// Proposal Builder — context form + multi-technique assembled, printable proposal document
const PROPOSAL_CTX_KEY = 'proposalContext_v1';
const PROPOSAL_CART_KEY = 'proposalCart_v1';

function loadCtx() {
  try { return JSON.parse(localStorage.getItem(PROPOSAL_CTX_KEY)) || {}; } catch { return {}; }
}
function loadCart() {
  try { return JSON.parse(localStorage.getItem(PROPOSAL_CART_KEY)) || []; } catch { return []; }
}

const CTX_DEFAULTS = {
  clientName: '', preparedBy: '', productName: '', indication: '',
  audience: '', sampleSize: '', currency: '£', objectives: '',
};

// Hook to manage proposal cart + context globally
function useProposal() {
  const [cart, setCart] = React.useState(loadCart);
  const [ctx, setCtx] = React.useState(() => ({ ...CTX_DEFAULTS, ...loadCtx() }));

  React.useEffect(() => { localStorage.setItem(PROPOSAL_CART_KEY, JSON.stringify(cart)); }, [cart]);
  React.useEffect(() => { localStorage.setItem(PROPOSAL_CTX_KEY, JSON.stringify(ctx)); }, [ctx]);

  const inCart = id => cart.includes(id);
  const toggleCart = id => setCart(c => c.includes(id) ? c.filter(x => x !== id) : [...c, id]);
  const removeFromCart = id => setCart(c => c.filter(x => x !== id));
  const clearCart = () => setCart([]);
  const setCtxField = (k, v) => setCtx(c => ({ ...c, [k]: v }));

  return { cart, inCart, toggleCart, removeFromCart, clearCart, ctx, setCtx, setCtxField };
}

// Compute combined timeline (phases run partly sequentially; we estimate calendar weeks
// as the longest single study plus a fraction of the others when run in parallel)
function combinedTimeline(techniques) {
  if (!techniques.length) return { total: 0, perStudy: [] };
  const totals = techniques.map(t => {
    const ex = window.PROPOSAL_EXTRAS[t.id];
    const wk = ex ? ex.timeline.reduce((s, p) => s + p.weeks, 0) : 6;
    return { id: t.id, name: t.name, weeks: wk };
  });
  const longest = Math.max(...totals.map(t => t.weeks));
  const rest = totals.reduce((s, t) => s + t.weeks, 0) - longest;
  // parallelised estimate: longest + 35% of the rest
  const total = Math.round((longest + rest * 0.35) * 10) / 10;
  return { total, perStudy: totals };
}

function ProposalBuilder({ allTechniques, proposal, onOpenTechnique }) {
  const { cart, removeFromCart, clearCart, ctx, setCtxField } = proposal;
  const [view, setView] = React.useState('setup'); // setup | document
  const selected = cart.map(id => allTechniques.find(t => t.id === id)).filter(Boolean);
  const docRef = React.useRef(null);
  const infoRef = React.useRef(null);
  const wrapRef = React.useRef(null);
  const [scale, setScale] = React.useState(1);
  const [wrapH, setWrapH] = React.useState(0);
  const [exporting, setExporting] = React.useState(false);
  const INFO_W = 1100;

  // Fit the fixed-width infographic into the available modal width
  React.useEffect(() => {
    const fit = () => {
      if (!wrapRef.current || !infoRef.current) return;
      const avail = wrapRef.current.clientWidth;
      const s = Math.min(1, avail / INFO_W);
      setScale(s);
      setWrapH(infoRef.current.scrollHeight * s);
    };
    fit();
    const t1 = setTimeout(fit, 250);
    const t2 = setTimeout(fit, 800);
    let ro;
    if (window.ResizeObserver && wrapRef.current) { ro = new ResizeObserver(fit); ro.observe(wrapRef.current); }
    window.addEventListener('resize', fit);
    return () => { clearTimeout(t1); clearTimeout(t2); if (ro) ro.disconnect(); window.removeEventListener('resize', fit); };
  }, [view, cart.join(','), JSON.stringify(ctx)]);

  const fill = txt => window.fillProposalTokens(txt, ctx);
  const tl = combinedTimeline(selected);

  const today = new Date().toLocaleDateString('en-GB', { day:'numeric', month:'long', year:'numeric' });

  // Combined, de-duplicated deliverables / assumptions / risks
  const dedupe = arr => [...new Set(arr)];
  const allDeliverables = dedupe(selected.flatMap(t => t.proposal.deliverables || []));
  const allAssumptions = dedupe(selected.flatMap(t => t.proposal.assumptions || []));
  const allRisks = dedupe(selected.flatMap(t => t.proposal.risks || []));

  const buildPlainText = () => {
    const L = [];
    L.push('RESEARCH PROPOSAL');
    if (ctx.clientName) L.push(`Prepared for: ${ctx.clientName}`);
    if (ctx.preparedBy) L.push(`Prepared by: ${ctx.preparedBy}`);
    L.push(`Date: ${today}`);
    L.push('');
    L.push('1. BACKGROUND & OBJECTIVES');
    L.push(fill(backgroundText()));
    if (ctx.objectives) { L.push(''); L.push('Specific objectives:'); L.push(ctx.objectives); }
    L.push('');
    L.push('2. RECOMMENDED APPROACH');
    L.push(approachIntro());
    selected.forEach((t, i) => {
      L.push('');
      L.push(`2.${i+1} ${t.name}`);
      L.push(fill(t.proposal.s150));
      L.push('');
      L.push(`Scope of work: ${fill(t.proposal.scopeOfWork)}`);
      const ex = window.PROPOSAL_EXTRAS[t.id];
      if (ex) {
        L.push(`Recommended sample: n=${ex.sampleSize.recommended} (minimum n=${ex.sampleSize.min}). ${ex.sampleSize.note}`);
        L.push(`Indicative duration: ~${ex.timeline.reduce((s,p)=>s+p.weeks,0)} weeks. ${ex.fieldwork}`);
      }
    });
    L.push('');
    L.push('3. TIMELINE');
    L.push(`Estimated total programme duration: approximately ${tl.total} weeks (methods partially parallelised).`);
    L.push('');
    L.push('4. DELIVERABLES');
    allDeliverables.forEach(d => L.push(`• ${d}`));
    L.push('');
    L.push('5. SAMPLE & AUDIENCE');
    L.push(`Audience: ${ctx.audience || 'as agreed with client'}.`);
    if (ctx.sampleSize) L.push(`Target sample: n=${ctx.sampleSize}.`);
    L.push('');
    L.push('6. ASSUMPTIONS');
    allAssumptions.forEach(a => L.push(`• ${a}`));
    L.push('');
    L.push('7. RISKS & DEPENDENCIES');
    allRisks.forEach(r => L.push(`• ${r}`));
    return L.join('\n');
  };

  const backgroundText = () => {
    const c = ctx.clientName || 'the client';
    const p = ctx.productName || 'the asset';
    const ind = ctx.indication ? ` in ${ctx.indication}` : '';
    return `${c} is seeking robust market research evidence to support decision-making for ${p}${ind}. This proposal sets out a recommended analytical approach designed to answer the key business questions with rigour and to deliver clear, actionable guidance for commercial and medical strategy.`;
  };

  const approachIntro = () => {
    if (selected.length === 1) return `We recommend a focused study using the following methodology:`;
    return `We recommend an integrated programme combining ${selected.length} complementary techniques. Together these methods address the research objectives from multiple angles, ensuring findings are both robust and directly actionable:`;
  };

  const printDoc = () => {
    document.body.classList.add('printing-proposal');
    window.print();
    setTimeout(() => document.body.classList.remove('printing-proposal'), 500);
  };

  // ---- SETUP VIEW ----
  if (view === 'setup') {
    return (
      <div>
        <div style={{ display:'flex', gap:6, marginBottom:20, background:COLORS.slate[100], padding:4, borderRadius:10 }}>
          <button onClick={()=>setView('setup')} style={tabBtn(true)}>1 · Set up</button>
          <button onClick={()=> selected.length && setView('document')} style={tabBtn(false, selected.length===0)}>2 · Review document</button>
        </div>

        {/* Selected methods */}
        <SectionLabel>Selected Techniques ({selected.length})</SectionLabel>
        {selected.length === 0 ? (
          <div style={{ padding:'24px', textAlign:'center', background:COLORS.slate[50],
            borderRadius:12, border:`1px dashed ${COLORS.slate[300]}`, marginBottom:20 }}>
            <div style={{ fontSize:13, color:COLORS.slate[500], marginBottom:6 }}>No techniques added yet.</div>
            <div style={{ fontSize:12, color:COLORS.slate[400] }}>Open any technique's <strong>Proposal</strong> tab and click <strong>"+ Add to Proposal"</strong>, or add below.</div>
          </div>
        ) : (
          <div style={{ display:'flex', flexDirection:'column', gap:8, marginBottom:16 }}>
            {selected.map(t => {
              const ex = window.PROPOSAL_EXTRAS[t.id];
              return (
                <div key={t.id} style={{ display:'flex', alignItems:'center', gap:12, padding:'10px 14px',
                  borderRadius:10, border:`1px solid ${COLORS.slate[200]}`, background:COLORS.slate[100] }}>
                  <div style={{ width:34, height:34, borderRadius:8, background:`${t.color}18`, color:t.color,
                    display:'flex', alignItems:'center', justifyContent:'center', fontSize:16, flexShrink:0 }}>{t.icon}</div>
                  <div style={{ flex:1, minWidth:0 }}>
                    <div style={{ fontWeight:700, fontSize:13, color:COLORS.slate[800] }}>{t.name}</div>
                    {ex && <div style={{ fontSize:11, color:COLORS.slate[500] }}>n={ex.sampleSize.recommended} · ~{ex.timeline.reduce((s,p)=>s+p.weeks,0)} wks · {ex.effort} effort</div>}
                  </div>
                  <button onClick={()=>removeFromCart(t.id)} title="Remove"
                    style={{ border:'none', background:COLORS.slate[100], borderRadius:7, width:28, height:28,
                      cursor:'pointer', color:COLORS.slate[500], fontSize:15 }}>×</button>
                </div>
              );
            })}
          </div>
        )}

        {/* Quick-add */}
        <div style={{ marginBottom:24 }}>
          <SectionLabel>Quick add</SectionLabel>
          <div style={{ display:'flex', flexWrap:'wrap', gap:6 }}>
            {allTechniques.filter(t => !cart.includes(t.id)).map(t => (
              <button key={t.id} onClick={()=>proposal.toggleCart(t.id)}
                style={{ padding:'6px 12px', borderRadius:999, border:`1px solid ${t.color}40`,
                  background:`${t.color}0D`, color:t.color, fontSize:12, fontWeight:600, cursor:'pointer',
                  display:'flex', alignItems:'center', gap:5 }}>
                <span>{t.icon}</span> + {t.shortName}
              </button>
            ))}
            {allTechniques.filter(t => !cart.includes(t.id)).length === 0 &&
              <span style={{ fontSize:12, color:COLORS.slate[400] }}>All techniques added.</span>}
          </div>
        </div>

        <Divider />

        {/* Context form */}
        <SectionLabel>Project Context</SectionLabel>
        <div style={{ fontSize:12, color:COLORS.slate[500], marginBottom:14 }}>
          These details auto-fill into the proposal text and document header. All optional — leave blank to use generic placeholders.
        </div>
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:12 }}>
          <Field label="Client / Company" value={ctx.clientName} onChange={v=>setCtxField('clientName',v)} placeholder="e.g. Northwind Pharma" />
          <Field label="Prepared by" value={ctx.preparedBy} onChange={v=>setCtxField('preparedBy',v)} placeholder="e.g. Insights & Analytics Team" />
          <Field label="Product / Asset name" value={ctx.productName} onChange={v=>setCtxField('productName',v)} placeholder="e.g. NW-204" />
          <Field label="Indication / Therapy area" value={ctx.indication} onChange={v=>setCtxField('indication',v)} placeholder="e.g. severe asthma" />
          <Field label="Audience" value={ctx.audience} onChange={v=>setCtxField('audience',v)} placeholder="e.g. UK & DE pulmonologists" />
          <div style={{ display:'flex', gap:8 }}>
            <div style={{ width:70 }}>
              <FieldLabel>Currency</FieldLabel>
              <select value={ctx.currency} onChange={e=>setCtxField('currency',e.target.value)}
                style={{ width:'100%', padding:'8px 8px', borderRadius:8, border:`1px solid ${COLORS.slate[200]}`,
                  fontSize:13, background:COLORS.slate[100], color:COLORS.slate[700], cursor:'pointer' }}>
                <option>£</option><option>$</option><option>€</option>
              </select>
            </div>
            <div style={{ flex:1 }}>
              <Field label="Target sample (n)" value={ctx.sampleSize} onChange={v=>setCtxField('sampleSize',v)} placeholder="e.g. 220" />
            </div>
          </div>
        </div>
        <div style={{ marginTop:12 }}>
          <FieldLabel>Specific objectives (optional)</FieldLabel>
          <textarea value={ctx.objectives} onChange={e=>setCtxField('objectives',e.target.value)}
            placeholder="e.g. Define the optimal target product profile and quantify willingness to trade efficacy for tolerability."
            rows={3} style={{ width:'100%', padding:'10px 12px', borderRadius:8, border:`1px solid ${COLORS.slate[200]}`,
              fontSize:13, fontFamily:'inherit', resize:'vertical', boxSizing:'border-box', color:COLORS.slate[700] }} />
        </div>

        <div style={{ display:'flex', justifyContent:'space-between', marginTop:24, alignItems:'center' }}>
          {selected.length > 0
            ? <button onClick={clearCart} style={{ fontSize:12, color:COLORS.rose[600], background:'none',
                border:'none', cursor:'pointer', fontWeight:600 }}>Clear all techniques</button>
            : <span />}
          <button onClick={()=> selected.length && setView('document')} disabled={selected.length===0}
            style={{ padding:'10px 22px', borderRadius:10, border:'none',
              background: selected.length ? COLORS.indigo[600] : COLORS.slate[200],
              color:'white', fontSize:13.5, fontWeight:700, cursor: selected.length ? 'pointer':'not-allowed' }}>
            Build Proposal Document →
          </button>
        </div>
      </div>
    );
  }

  // ---- DOCUMENT VIEW (infographic) ----
  const PE = window.PROPOSAL_EXTRAS;
  const programmeTitle = (ctx.productName ? `${ctx.productName} — ` : '') +
    (selected.length === 1 ? `${selected[0].name} Study` : 'Integrated Research Programme');
  const maxWeeks = Math.max(...selected.map(t => { const ex = PE[t.id]; return ex ? ex.timeline.reduce((s,p)=>s+p.weeks,0) : 6; }), 1);
  const tickStep = maxWeeks > 12 ? 2 : 1;
  const ticks = []; for (let w = 0; w <= Math.ceil(maxWeeks); w += tickStep) ticks.push(w);

  const metrics = [
    { icon:'◫', value: selected.length, label: selected.length === 1 ? 'Method' : 'Methods' },
    { icon:'◷', value: `~${tl.total}`, label: 'Weeks (est.)' },
    { icon:'◉', value: ctx.sampleSize ? `n=${ctx.sampleSize}` : 'Per method', label: 'Sample' },
    { icon:'✦', value: allDeliverables.length, label: 'Deliverables' },
  ];

  const slug = s => (s || 'research').toLowerCase().replace(/[^a-z0-9]+/g,'-').replace(/^-|-$/g,'');
  const exportImage = async () => {
    const node = infoRef.current;
    if (!node || !window.htmlToImage) { alert('Image export library not loaded.'); return; }
    setExporting(true);
    try {
      const dataUrl = await window.htmlToImage.toPng(node, {
        pixelRatio: 2, backgroundColor: '#ffffff', cacheBust: true,
        width: node.offsetWidth, height: node.offsetHeight,
        style: { transform: 'none', transformOrigin: 'top left', margin: '0' },
      });
      const a = document.createElement('a');
      a.download = `${slug(ctx.productName || ctx.clientName)}-proposal.png`;
      a.href = dataUrl; a.click();
    } catch (e) { console.error(e); alert('Export failed: ' + e.message); }
    setExporting(false);
  };

  const NAVY = '#1A1840';

  return (
    <div>
      <div style={{ display:'flex', gap:6, marginBottom:16, background:COLORS.slate[100], padding:4, borderRadius:10 }}>
        <button onClick={()=>setView('setup')} style={tabBtn(false)}>1 · Set up</button>
        <button onClick={()=>setView('document')} style={tabBtn(true)}>2 · Proposal slide</button>
      </div>

      {/* Action bar */}
      <div style={{ display:'flex', gap:8, marginBottom:14, justifyContent:'space-between', alignItems:'center', flexWrap:'wrap' }}>
        <span style={{ fontSize:11.5, color:COLORS.slate[400] }}>Exports as a high-resolution PNG (~2200px wide) — drop it straight into your deck or proposal.</span>
        <div style={{ display:'flex', gap:8 }}>
          <CopyBtn text={buildPlainText()} label="Copy text" />
          <button onClick={printDoc} style={{ padding:'6px 14px', borderRadius:8,
            border:`1px solid ${COLORS.slate[200]}`, background:COLORS.slate[100], color:COLORS.slate[600], fontSize:12, fontWeight:600,
            cursor:'pointer', display:'flex', alignItems:'center', gap:5 }}>⎙ Print / PDF</button>
          <button onClick={exportImage} disabled={exporting} style={{ padding:'6px 16px', borderRadius:8,
            border:'none', background: exporting ? COLORS.slate[400] : COLORS.indigo[600], color:'white', fontSize:12.5, fontWeight:700,
            cursor: exporting ? 'wait' : 'pointer', display:'flex', alignItems:'center', gap:6,
            boxShadow:`0 2px 8px ${COLORS.indigo[600]}40` }}>
            {exporting ? '⏳ Generating…' : '⬇ Download image'}
          </button>
        </div>
      </div>

      {/* Scaled preview wrapper */}
      <div ref={wrapRef} style={{ position:'relative', width:'100%', height: wrapH || 'auto', overflow:'hidden',
        borderRadius:12, border:`1px solid ${COLORS.slate[200]}`, background:COLORS.slate[100] }}>
        <div id="proposal-print-root" ref={infoRef} style={{
          position:'absolute', top:0, left:0, width:INFO_W, transform:`scale(${scale})`, transformOrigin:'top left',
          background:'white', fontFamily:"'Inter', sans-serif", color:COLORS.slate[700]
        }}>

          {/* HEADER BAND */}
          <div style={{ background:`linear-gradient(125deg, ${NAVY} 0%, #2A2660 70%, #322C72 100%)`,
            color:'white', padding:'40px 56px 30px', position:'relative', overflow:'hidden' }}>
            {/* decorative dots */}
            <div style={{ position:'absolute', top:-40, right:-30, width:200, height:200, borderRadius:999,
              background:'radial-gradient(circle, rgba(99,102,241,0.35), transparent 70%)' }} />
            <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:26, position:'relative' }}>
              <div style={{ display:'flex', alignItems:'center', gap:11 }}>
                <div style={{ width:36, height:36, borderRadius:9, background:COLORS.indigo[500],
                  display:'flex', alignItems:'center', justifyContent:'center', fontSize:18 }}>⚗</div>
                <div style={{ fontSize:11, fontWeight:700, letterSpacing:'0.22em', color:'rgba(255,255,255,0.75)' }}>RESEARCH PROPOSAL</div>
              </div>
              <div style={{ fontSize:12, color:'rgba(255,255,255,0.65)', border:'1px solid rgba(255,255,255,0.2)',
                borderRadius:999, padding:'5px 14px' }}>{today}</div>
            </div>
            <h1 style={{ margin:'0 0 14px', fontSize:34, fontWeight:800, lineHeight:1.15, letterSpacing:'-0.01em', position:'relative', maxWidth:760 }}>
              {programmeTitle}
            </h1>
            <div style={{ display:'flex', gap:'8px 22px', flexWrap:'wrap', fontSize:13, color:'rgba(255,255,255,0.7)', position:'relative' }}>
              {ctx.clientName && <span>Prepared for <strong style={{ color:'white' }}>{ctx.clientName}</strong></span>}
              {ctx.indication && <span>·&nbsp;&nbsp;{ctx.indication}</span>}
              {ctx.audience && <span>·&nbsp;&nbsp;{ctx.audience}</span>}
              {ctx.preparedBy && <span>·&nbsp;&nbsp;by {ctx.preparedBy}</span>}
            </div>
            {/* accent multi-colour rule */}
            <div style={{ display:'flex', height:5, borderRadius:999, overflow:'hidden', marginTop:24, position:'relative', maxWidth:420 }}>
              {selected.map(t => <div key={t.id} style={{ flex:1, background:t.color }} />)}
            </div>
          </div>

          {/* METRIC TILES */}
          <div style={{ padding:'0 56px' }}>
            <div style={{ display:'grid', gridTemplateColumns:'repeat(4,1fr)', background:'white',
              borderRadius:14, boxShadow:'0 10px 30px rgba(15,23,42,0.10)', border:`1px solid ${COLORS.slate[200]}`,
              marginTop:-26, position:'relative', overflow:'hidden' }}>
              {metrics.map((m,i) => (
                <div key={i} style={{ padding:'20px 22px', borderRight: i<3 ? `1px solid ${COLORS.slate[100]}` : 'none',
                  display:'flex', alignItems:'center', gap:14 }}>
                  <div style={{ width:42, height:42, borderRadius:11, background:COLORS.indigo[50], color:COLORS.indigo[600],
                    display:'flex', alignItems:'center', justifyContent:'center', fontSize:19, flexShrink:0 }}>{m.icon}</div>
                  <div>
                    <div style={{ fontSize:23, fontWeight:800, color:COLORS.slate[900], lineHeight:1 }}>{m.value}</div>
                    <div style={{ fontSize:11, color:COLORS.slate[500], fontWeight:600, marginTop:4, letterSpacing:'0.02em' }}>{m.label}</div>
                  </div>
                </div>
              ))}
            </div>
          </div>

          {/* BODY */}
          <div style={{ padding:'34px 56px 0' }}>
            {/* Objectives */}
            <InfoBlock n="01" title="Background & Objectives" color={COLORS.indigo[600]}>
              <p style={{ margin:'0 0 10px', fontSize:13.5, lineHeight:1.7 }}>{fill(backgroundText())}</p>
              {ctx.objectives && (
                <div style={{ background:COLORS.indigo[50], borderRadius:10, padding:'12px 16px', borderLeft:`3px solid ${COLORS.indigo[500]}` }}>
                  <div style={{ fontSize:10.5, fontWeight:700, letterSpacing:'0.08em', color:COLORS.indigo[700], marginBottom:5 }}>OBJECTIVES</div>
                  <div style={{ fontSize:13, lineHeight:1.65, whiteSpace:'pre-line', color:COLORS.slate[700] }}>{ctx.objectives}</div>
                </div>
              )}
            </InfoBlock>

            {/* Approach cards */}
            <InfoBlock n="02" title="Recommended Approach" color={COLORS.indigo[600]}>
              <p style={{ margin:'0 0 16px', fontSize:13, lineHeight:1.65, color:COLORS.slate[600] }}>{approachIntro()}</p>
              <div style={{ display:'grid', gridTemplateColumns: selected.length === 1 ? '1fr' : '1fr 1fr', gap:14 }}>
                {selected.map((t,i) => {
                  const ex = PE[t.id];
                  return (
                    <div key={t.id} style={{ border:`1px solid ${COLORS.slate[200]}`, borderRadius:13, overflow:'hidden',
                      background:'white', position:'relative' }}>
                      <div style={{ height:5, background:t.color }} />
                      <div style={{ padding:'16px 18px' }}>
                        <div style={{ position:'absolute', top:14, right:16, fontSize:30, fontWeight:800, color:`${t.color}1A`, lineHeight:1 }}>
                          {String(i+1).padStart(2,'0')}
                        </div>
                        <div style={{ display:'flex', alignItems:'center', gap:11, marginBottom:9 }}>
                          <div style={{ width:38, height:38, borderRadius:10, background:`${t.color}18`, color:t.color,
                            display:'flex', alignItems:'center', justifyContent:'center', fontSize:18, flexShrink:0 }}>{t.icon}</div>
                          <div>
                            <div style={{ fontWeight:800, fontSize:15, color:COLORS.slate[900] }}>{t.name}</div>
                            <div style={{ fontSize:11, color:t.color, fontWeight:600 }}>{t.family}</div>
                          </div>
                        </div>
                        <p style={{ margin:'0 0 12px', fontSize:12.5, lineHeight:1.6, color:COLORS.slate[600] }}>{fill(t.tagline)}.</p>
                        <div style={{ display:'flex', gap:8, flexWrap:'wrap' }}>
                          {ex && <FactPill label="Sample" value={`n=${ex.sampleSize.recommended}`} color={t.color} />}
                          {ex && <FactPill label="Duration" value={`~${ex.timeline.reduce((s,p)=>s+p.weeks,0)} wks`} color={t.color} />}
                          {(t.tags.outputTypes||[]).slice(0,1).map((o,k)=> <FactPill key={k} label="Output" value={o} color={t.color} />)}
                        </div>
                      </div>
                    </div>
                  );
                })}
              </div>
            </InfoBlock>

            {/* Gantt timeline */}
            <InfoBlock n="03" title="Programme Timeline" color={COLORS.indigo[600]}
              aside={<div style={{ textAlign:'right' }}>
                <div style={{ fontSize:26, fontWeight:800, color:COLORS.indigo[700], lineHeight:1 }}>~{tl.total} wks</div>
                <div style={{ fontSize:10.5, color:COLORS.slate[400], fontWeight:600 }}>TOTAL (PARALLELISED)</div>
              </div>}>
              {/* tick header */}
              <div style={{ display:'grid', gridTemplateColumns:'185px 1fr', alignItems:'end', marginBottom:8 }}>
                <div />
                <div style={{ position:'relative', height:16, borderBottom:`1px solid ${COLORS.slate[200]}` }}>
                  {ticks.map(w => (
                    <span key={w} style={{ position:'absolute', left:`${(w/maxWeeks)*100}%`, transform:'translateX(-50%)',
                      fontSize:10, color:COLORS.slate[400], fontWeight:600, bottom:2, whiteSpace:'nowrap' }}>{w===0?'Wk 0':w}</span>
                  ))}
                </div>
              </div>
              {/* rows */}
              {selected.map(t => {
                const ex = PE[t.id]; if (!ex) return null;
                const total = ex.timeline.reduce((s,p)=>s+p.weeks,0);
                return (
                  <div key={t.id} style={{ display:'grid', gridTemplateColumns:'185px 1fr', alignItems:'center', marginBottom:9 }}>
                    <div style={{ paddingRight:14 }}>
                      <div style={{ fontSize:12.5, fontWeight:700, color:COLORS.slate[800], lineHeight:1.25 }}>{t.shortName}</div>
                      <div style={{ fontSize:10.5, color:COLORS.slate[400] }}>{total} weeks</div>
                    </div>
                    <div style={{ position:'relative', height:30, background:COLORS.slate[100], borderRadius:7 }}>
                      <div style={{ display:'flex', height:'100%', width:`${(total/maxWeeks)*100}%`, borderRadius:7, overflow:'hidden',
                        boxShadow:'0 1px 3px rgba(0,0,0,0.12)' }}>
                        {ex.timeline.map((p,j) => {
                          const frac = p.weeks/total;
                          return (
                            <div key={j} title={`${p.phase}: ${p.weeks} wk`}
                              style={{ width:`${frac*100}%`, background:shade(t.color,j),
                                borderRight: j<ex.timeline.length-1 ? '1px solid rgba(255,255,255,0.45)' : 'none',
                                display:'flex', alignItems:'center', justifyContent:'center',
                                fontSize:9.5, color:'white', fontWeight:600, overflow:'hidden', whiteSpace:'nowrap', padding:'0 3px' }}>
                              {frac > 0.17 ? p.phase.split(' ')[0] : ''}
                            </div>
                          );
                        })}
                      </div>
                    </div>
                  </div>
                );
              })}
              {/* phase legend (representative) */}
              {selected[0] && PE[selected[0].id] && (
                <div style={{ display:'flex', flexWrap:'wrap', gap:'5px 16px', marginTop:12, paddingTop:12,
                  borderTop:`1px solid ${COLORS.slate[100]}`, fontSize:10.5, color:COLORS.slate[500] }}>
                  {PE[selected[0].id].timeline.map((p,j) => (
                    <span key={j} style={{ display:'flex', alignItems:'center', gap:5 }}>
                      <span style={{ width:10, height:10, borderRadius:3, background:shade(selected[0].color,j) }} />{p.phase}
                    </span>
                  ))}
                </div>
              )}
            </InfoBlock>

            {/* Deliverables */}
            <InfoBlock n="04" title="Deliverables" color={COLORS.green[600]}>
              <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr 1fr', gap:'10px 16px' }}>
                {allDeliverables.map((d,i) => (
                  <div key={i} style={{ display:'flex', gap:9, alignItems:'flex-start', fontSize:12.5, lineHeight:1.45 }}>
                    <span style={{ width:20, height:20, borderRadius:999, background:COLORS.green[600]+'18', color:COLORS.green[600],
                      display:'flex', alignItems:'center', justifyContent:'center', fontSize:11, flexShrink:0, fontWeight:800, marginTop:1 }}>✓</span>
                    <span style={{ color:COLORS.slate[700] }}>{d}</span>
                  </div>
                ))}
              </div>
            </InfoBlock>

            {/* Assumptions + Risks */}
            <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:16, marginBottom:8 }}>
              <div style={{ background:COLORS.slate[50], borderRadius:12, padding:'18px 20px', border:`1px solid ${COLORS.slate[200]}` }}>
                <div style={{ fontSize:11, fontWeight:800, letterSpacing:'0.08em', color:COLORS.slate[600], marginBottom:10 }}>ASSUMPTIONS</div>
                {allAssumptions.map((a,i) => (
                  <div key={i} style={{ display:'flex', gap:8, fontSize:11.5, lineHeight:1.5, color:COLORS.slate[600], marginBottom:7 }}>
                    <span style={{ color:COLORS.slate[400], flexShrink:0 }}>•</span>{a}
                  </div>
                ))}
              </div>
              <div style={{ background:'#FFF7ED', borderRadius:12, padding:'18px 20px', border:'1px solid #FED7AA' }}>
                <div style={{ fontSize:11, fontWeight:800, letterSpacing:'0.08em', color:COLORS.amber[600], marginBottom:10 }}>RISKS &amp; DEPENDENCIES</div>
                {allRisks.map((r,i) => (
                  <div key={i} style={{ display:'flex', gap:8, fontSize:11.5, lineHeight:1.5, color:COLORS.slate[600], marginBottom:7 }}>
                    <span style={{ color:COLORS.amber[500], flexShrink:0 }}>⚠</span>{r}
                  </div>
                ))}
              </div>
            </div>
          </div>

          {/* FOOTER */}
          <div style={{ background:COLORS.slate[50], borderTop:`1px solid ${COLORS.slate[200]}`,
            padding:'16px 56px', display:'flex', justifyContent:'space-between', alignItems:'center', marginTop:18 }}>
            <div style={{ display:'flex', alignItems:'center', gap:8, fontSize:11, color:COLORS.slate[400], fontWeight:600 }}>
              <span style={{ width:20, height:20, borderRadius:5, background:NAVY, color:'white',
                display:'flex', alignItems:'center', justifyContent:'center', fontSize:11 }}>⚗</span>
              Analytical Technique Library
            </div>
            <div style={{ fontSize:10, color:COLORS.slate[400] }}>Indicative figures — confirmed at kick-off. Sample illustrative data.</div>
          </div>
        </div>
      </div>
    </div>
  );
}

// --- small helpers ---
function tabBtn(active, disabled) {
  return {
    flex:1, padding:'8px 12px', borderRadius:7, border:'none',
    background: active ? 'white' : 'transparent',
    color: active ? COLORS.indigo[700] : disabled ? COLORS.slate[300] : COLORS.slate[500],
    fontSize:12.5, fontWeight: active ? 700 : 600,
    cursor: disabled ? 'not-allowed' : 'pointer',
    boxShadow: active ? '0 1px 3px rgba(0,0,0,0.1)' : 'none'
  };
}
function FieldLabel({ children }) {
  return <div style={{ fontSize:11, fontWeight:600, color:COLORS.slate[500], marginBottom:5 }}>{children}</div>;
}
function Field({ label, value, onChange, placeholder }) {
  return (
    <div>
      <FieldLabel>{label}</FieldLabel>
      <input value={value} onChange={e=>onChange(e.target.value)} placeholder={placeholder}
        style={{ width:'100%', padding:'8px 12px', borderRadius:8, border:`1px solid ${COLORS.slate[200]}`,
          fontSize:13, boxSizing:'border-box', color:COLORS.slate[800], outline:'none', fontFamily:'inherit' }} />
    </div>
  );
}
function DocSection({ n, title, children, last }) {
  return (
    <div style={{ marginBottom: last ? 0 : 24 }}>
      <h2 style={{ fontSize:14, fontWeight:800, color:COLORS.indigo[800], margin:'0 0 10px',
        display:'flex', alignItems:'center', gap:8 }}>
        <span style={{ width:22, height:22, borderRadius:6, background:COLORS.indigo[700], color:'white',
          display:'inline-flex', alignItems:'center', justifyContent:'center', fontSize:11 }}>{n}</span>
        {title}
      </h2>
      {children}
    </div>
  );
}
function DocChip({ label, value, wide }) {
  return (
    <div style={{ background:COLORS.slate[50], borderRadius:7, padding:'5px 10px',
      border:`1px solid ${COLORS.slate[200]}`, maxWidth: wide ? 360 : 'none' }}>
      <span style={{ fontSize:10, color:COLORS.slate[400], fontWeight:600 }}>{label}: </span>
      <span style={{ fontSize:11.5, color:COLORS.slate[700], fontWeight:600 }}>{value}</span>
    </div>
  );
}
// Infographic section block with numbered marker + optional aside
function InfoBlock({ n, title, color, aside, children }) {
  return (
    <div style={{ marginBottom:26 }}>
      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:14 }}>
        <div style={{ display:'flex', alignItems:'center', gap:12 }}>
          <span style={{ fontSize:13, fontWeight:800, color: color || COLORS.indigo[600],
            fontFamily:"'JetBrains Mono', monospace", letterSpacing:'0.05em' }}>{n}</span>
          <span style={{ width:6, height:6, borderRadius:999, background: color || COLORS.indigo[600] }} />
          <h2 style={{ margin:0, fontSize:17, fontWeight:800, color:COLORS.slate[900], letterSpacing:'-0.01em' }}>{title}</h2>
        </div>
        {aside}
      </div>
      {children}
    </div>
  );
}
// Small labelled fact pill used in approach cards
function FactPill({ label, value, color }) {
  return (
    <div style={{ display:'flex', alignItems:'baseline', gap:5, background:`${color}0D`,
      border:`1px solid ${color}26`, borderRadius:7, padding:'4px 9px' }}>
      <span style={{ fontSize:9.5, color:COLORS.slate[400], fontWeight:700, textTransform:'uppercase', letterSpacing:'0.04em' }}>{label}</span>
      <span style={{ fontSize:11.5, color:COLORS.slate[800], fontWeight:700 }}>{value}</span>
    </div>
  );
}
// darken a hex colour progressively for timeline phases
function shade(hex, step) {
  const f = parseInt(hex.slice(1), 16);
  let r = (f >> 16) & 255, g = (f >> 8) & 255, b = f & 255;
  const factor = 1 - Math.min(step * 0.11, 0.55);
  r = Math.round(r * factor); g = Math.round(g * factor); b = Math.round(b * factor);
  return `rgb(${r},${g},${b})`;
}

Object.assign(window, { useProposal, ProposalBuilder });
