/* ============ TollTab — terminal reskin of TollCalc =============
   Source: profit-calc-clean-source.html lines 1644-2354. Math + field semantics preserved. */

function TollTab(){
  /* ----- state (defaults match source) ----- */
  const [extractionType,setExtractionType]=useState('hash_rosin');
  const [model,setModel]=useState('toll');
  const [skuName,setSkuName]=useState('Papaya #4');

  const [ffLbs,setFfLbs]=useState(100);
  const [ffCostPerLb,setFfCostPerLb]=useState(75);
  const [trimLbs,setTrimLbs]=useState(0);
  const [trimCostPerLb,setTrimCostPerLb]=useState(35);

  const [washFeePerG,setWashFeePerG]=useState(0.02);
  const [washFeeUnit,setWashFeeUnit]=useState('gram');
  const [pressFeePerG,setPressFeePerG]=useState(2.00);
  const [pressFeeBasis,setPressFeeBasis]=useState('hash_input');
  const [extractionFeePerG,setExtractionFeePerG]=useState(0.015);
  const [extractionFeeUnit,setExtractionFeeUnit]=useState('gram');

  const [hasRefinement,setHasRefinement]=useState(false);
  const [refinementLabel,setRefinementLabel]=useState('Diamond Separation');
  const [refinementFeePerG,setRefinementFeePerG]=useState(1.50);
  const [refinementYieldPct,setRefinementYieldPct]=useState(50);

  const [splitYou,setSplitYou]=useState(70);
  const [splitExtractor,setSplitExtractor]=useState(30);

  const [hashYieldPct,setHashYieldPct]=useState(6);
  const [rosinYieldFromHash,setRosinYieldFromHash]=useState(80);
  const [distillateYieldPct,setDistillateYieldPct]=useState(12);
  const [liveResinYieldPct,setLiveResinYieldPct]=useState(8);
  const [secondPressYield,setSecondPressYield]=useState(0);
  const [t2RosinPressYield,setT2RosinPressYield]=useState(75);
  const [penRosinPressYield,setPenRosinPressYield]=useState(70);
  const [foodRosinPressYield,setFoodRosinPressYield]=useState(65);

  const [microns,setMicrons]=useState([
    {size:'25-45u',pct:5,label:'25-45u (contaminant / 1-2 star)',custom:false,dest:'food'},
    {size:'45-70u',pct:10,label:'45-70u (immature / 1-3 star — press only)',custom:false,dest:'t2'},
    {size:'73u',pct:15,label:'73u (4 star — dabbable)',custom:false,dest:'t1'},
    {size:'90u',pct:25,label:'90u (5 star — full melt)',custom:false,dest:'t1'},
    {size:'120u',pct:30,label:'120u (6 star — full melt)',custom:false,dest:'t1'},
    {size:'160u',pct:10,label:'160u (half melt — food grade)',custom:false,dest:'food'},
    {size:'220u',pct:5,label:'220u+ (wash / food grade)',custom:false,dest:'food'},
  ]);

  /* prices */
  const [hashPriceG,setHashPriceG]=useState(35);
  const [hashLowPriceG,setHashLowPriceG]=useState(8);
  const [hashFoodPriceG,setHashFoodPriceG]=useState(4);
  const [rosinPriceG,setRosinPriceG]=useState(25);
  const [t2RosinPriceG,setT2RosinPriceG]=useState(12);
  const [penRosinPriceG,setPenRosinPriceG]=useState(8);
  const [foodRosinPriceG,setFoodRosinPriceG]=useState(3);
  const [distillatePriceG,setDistillatePriceG]=useState(4.5);
  const [liveResinPriceG,setLiveResinPriceG]=useState(10);
  const [diamondPriceG,setDiamondPriceG]=useState(18);

  /* derived */
  const isHash=extractionType==='hash_only'||extractionType==='hash_rosin';
  const isRosin=extractionType==='hash_rosin';
  const isDistillate=extractionType==='distillate';
  const isLiveResin=extractionType==='live_resin';

  const safe=n=>Number.isFinite(+n)?+n:0;
  const safeFfLbs=Math.max(0,safe(ffLbs));
  const safeTrimLbs=Math.max(0,safe(trimLbs));
  const safeWashFeePerG=Math.max(0,safe(washFeePerG));
  const safePressFeePerG=Math.max(0,safe(pressFeePerG));
  const safeExtractionFeePerG=Math.max(0,safe(extractionFeePerG));
  const safeRefinementFeePerG=Math.max(0,safe(refinementFeePerG));
  const safeRefinementYieldPct=Math.max(0,Math.min(100,safe(refinementYieldPct)));
  const safeSplitYou=Math.max(0,Math.min(100,safe(splitYou)));
  const safeSplitExtractor=Math.max(0,Math.min(100,safe(splitExtractor)));
  const splitTotalPct=safeSplitYou+safeSplitExtractor;
  const safeHashYieldPct=Math.max(0,Math.min(100,safe(hashYieldPct)));
  const safeRosinYieldFromHash=Math.max(0,Math.min(100,safe(rosinYieldFromHash)));
  const safeT2RosinPressYield=Math.max(0,Math.min(100,safe(t2RosinPressYield)));
  const safePenRosinPressYield=Math.max(0,Math.min(100,safe(penRosinPressYield)));
  const safeFoodRosinPressYield=Math.max(0,Math.min(100,safe(foodRosinPressYield)));
  const safeSecondPressYield=Math.max(0,Math.min(100,safe(secondPressYield)));
  const safeDistillateYieldPct=Math.max(0,Math.min(100,safe(distillateYieldPct)));
  const safeLiveResinYieldPct=Math.max(0,Math.min(100,safe(liveResinYieldPct)));
  const safeHashPriceG=nonNegative(hashPriceG);
  const safeHashLowPriceG=nonNegative(hashLowPriceG);
  const safeHashFoodPriceG=nonNegative(hashFoodPriceG);
  const safeRosinPriceG=nonNegative(rosinPriceG);
  const safeT2RosinPriceG=nonNegative(t2RosinPriceG);
  const safePenRosinPriceG=nonNegative(penRosinPriceG);
  const safeFoodRosinPriceG=nonNegative(foodRosinPriceG);
  const safeDistillatePriceG=nonNegative(distillatePriceG);
  const safeLiveResinPriceG=nonNegative(liveResinPriceG);
  const safeDiamondPriceG=nonNegative(diamondPriceG);

  const totalInputLbs=safeFfLbs+safeTrimLbs;
  const totalInputGrams=totalInputLbs*GRAMS_PER_LB;
  const materialCost=safeFfLbs*nonNegative(ffCostPerLb)+safeTrimLbs*nonNegative(trimCostPerLb);

  const rawMicronTotalPct=microns.reduce((s,m)=>s+(+m.pct||0),0);
  const normalizedPctAt=i=>rawMicronTotalPct>0?((+microns[i].pct||0)/rawMicronTotalPct)*100:0;

  const totalHashGrams=isHash?totalInputGrams*(safeHashYieldPct/100):0;
  const yourPct=model==='split'?(splitTotalPct>0?safeSplitYou/splitTotalPct:0):1;

  /* micron breakdown (normalized) */
  let premiumGradeGrams=0,lowGradeGrams=0,foodGradeGrams=0;
  let hashToKeepAsHash=0,hashToDabRosin=0,hashToT2Rosin=0,hashToPenRosin=0,hashToFoodRosin=0;
  microns.forEach((m,i)=>{
    const g=totalHashGrams*(normalizedPctAt(i)/100);
    const n=parseInt(m.size);
    if(!isNaN(n)&&n>=73&&n<120)premiumGradeGrams+=g;
    else if(!isNaN(n)&&n<=70&&!m.custom)lowGradeGrams+=g;
    else if(!isNaN(n)&&n>=120&&!m.custom)foodGradeGrams+=g;
    const dest=m.dest||'t1';
    if(dest==='hash')hashToKeepAsHash+=g;
    else if(dest==='t1')hashToDabRosin+=g;
    else if(dest==='t2')hashToT2Rosin+=g;
    else if(dest==='pen')hashToPenRosin+=g;
    else if(dest==='food')hashToFoodRosin+=g;
  });
  const premiumGradePct=totalHashGrams>0?(premiumGradeGrams/totalHashGrams)*100:0;
  const lowGradePct=totalHashGrams>0?(lowGradeGrams/totalHashGrams)*100:0;
  const foodGradePct=totalHashGrams>0?(foodGradeGrams/totalHashGrams)*100:0;

  /* rosin yields */
  const dabRosinGrams=isRosin?hashToDabRosin*(safeRosinYieldFromHash/100):0;
  const secondPressInputGrams=isRosin?Math.max(0,hashToDabRosin-dabRosinGrams):0;
  const secondPressGrams=isRosin?secondPressInputGrams*(safeSecondPressYield/100):0;
  const t2RosinGrams=isRosin?hashToT2Rosin*(safeT2RosinPressYield/100)+secondPressGrams:0;
  const penRosinGrams=isRosin?hashToPenRosin*(safePenRosinPressYield/100):0;
  const foodRosinGrams=isRosin?hashToFoodRosin*(safeFoodRosinPressYield/100):0;
  const totalRosinGrams=dabRosinGrams+t2RosinGrams+penRosinGrams+foodRosinGrams;
  const hashSentToPressGrams=hashToDabRosin+hashToT2Rosin+hashToPenRosin+hashToFoodRosin;

  /* extract yields */
  const totalDistillateGrams=isDistillate?totalInputGrams*(safeDistillateYieldPct/100):0;
  const totalLiveResinGrams=isLiveResin?totalInputGrams*(safeLiveResinYieldPct/100):0;

  /* your share */
  const yourHashGrams=(extractionType==='hash_only'?totalHashGrams:hashToKeepAsHash)*yourPct;
  const yourPremiumHash=extractionType==='hash_only'?(totalHashGrams*(premiumGradePct/100))*yourPct:0;
  const yourLowGradeHash=extractionType==='hash_only'?(totalHashGrams*(lowGradePct/100))*yourPct:0;
  const yourFoodGradeHash=extractionType==='hash_only'?(totalHashGrams*(foodGradePct/100))*yourPct:0;
  const yourDabRosinGrams=dabRosinGrams*yourPct;
  const yourT2RosinGrams=t2RosinGrams*yourPct;
  const yourPenRosinGrams=penRosinGrams*yourPct;
  const yourFoodRosinGrams=foodRosinGrams*yourPct;
  const yourDistillateGrams=totalDistillateGrams*yourPct;
  const yourLiveResinGrams=totalLiveResinGrams*yourPct;

  /* values */
  const hashValue=yourHashGrams*safeHashPriceG;
  const hashLowValue=yourLowGradeHash*safeHashLowPriceG;
  const hashFoodValue=yourFoodGradeHash*safeHashFoodPriceG;
  const dabRosinValue=yourDabRosinGrams*safeRosinPriceG;
  const t2RosinValue=yourT2RosinGrams*safeT2RosinPriceG;
  const penRosinValue=yourPenRosinGrams*safePenRosinPriceG;
  const foodRosinValue=yourFoodRosinGrams*safeFoodRosinPriceG;
  const baseDistillateValue=yourDistillateGrams*safeDistillatePriceG;
  const baseLiveResinValue=yourLiveResinGrams*safeLiveResinPriceG;
  const refinedOutputGrams=(isDistillate||isLiveResin)&&hasRefinement?(isDistillate?yourDistillateGrams:yourLiveResinGrams)*(safeRefinementYieldPct/100):0;
  const diamondValue=refinedOutputGrams*safeDiamondPriceG;
  const distillateValue=isDistillate?(hasRefinement?0:baseDistillateValue):0;
  const liveResinValue=isLiveResin?(hasRefinement?0:baseLiveResinValue):0;
  const totalOutputValue=extractionType==='hash_only'?
    (yourPremiumHash*safeHashPriceG)+hashFoodValue+hashLowValue:
    hashValue+dabRosinValue+t2RosinValue+penRosinValue+foodRosinValue+distillateValue+liveResinValue+(hasRefinement?diamondValue:0);

  /* costs */
  const washCost=model==='toll'&&isHash?(washFeeUnit==='gram'?totalInputGrams*safeWashFeePerG:totalInputLbs*safeWashFeePerG):0;
  const pressFeeBaseGrams=pressFeeBasis==='hash_input'?hashSentToPressGrams:totalRosinGrams;
  const pressCost=model==='toll'&&isRosin?pressFeeBaseGrams*safePressFeePerG:0;
  const extractionCost=model==='toll'&&(isDistillate||isLiveResin)?(extractionFeeUnit==='gram'?totalInputGrams*safeExtractionFeePerG:totalInputLbs*safeExtractionFeePerG):0;
  const refinementCost=model==='toll'&&hasRefinement&&(isDistillate||isLiveResin)?((isDistillate?totalDistillateGrams:totalLiveResinGrams)*safeRefinementFeePerG):0;
  const tollCost=washCost+pressCost+extractionCost+refinementCost;
  const totalCost=materialCost+tollCost;
  const netProfit=totalOutputValue-totalCost;
  const roi=totalCost>0?((netProfit/totalCost)*100):0;

  /* helpers */
  const addCustomMicron=()=>setMicrons([...microns,{size:'custom',pct:0,label:'custom blend',custom:true,dest:'t1'}]);
  const removeMicron=i=>setMicrons(microns.filter((_,idx)=>idx!==i));
  const destOptions=[
    {v:'hash',l:'keep as hash'},
    {v:'t1',l:'t1 rosin (dab)'},
    {v:'t2',l:'t2 rosin'},
    {v:'pen',l:'pen-grade rosin'},
    {v:'food',l:'food-grade rosin'},
  ];
  const destLabel=v=>({hash:'hash',t1:'t1',t2:'t2',pen:'pen',food:'food'})[v]||v;
  const micronSizesFor=dest=>microns.filter(m=>(m.dest||'t1')===dest&&Number(m.pct)>0).map(m=>m.label||m.size).join(', ');

  /* export */
  const exportCSV=()=>{
    const rows=[];
    const totalHashOut=hashToKeepAsHash+hashToDabRosin+hashToT2Rosin+hashToPenRosin+hashToFoodRosin;
    const hashCostG=extractionType==='hash_only'?(yourHashGrams>0?totalCost/yourHashGrams:0):(yourHashGrams>0?totalCost*(hashToKeepAsHash/Math.max(totalHashOut,1))/yourHashGrams:0);
    const push=(p,g,pg,v,cg)=>{if(g>0)rows.push([p,g.toFixed(1),pg.toFixed(2),v.toFixed(2),cg.toFixed(2)])};
    if(extractionType==='hash_only'){push('full melt 73-120u',yourPremiumHash,safeHashPriceG,yourPremiumHash*safeHashPriceG,hashCostG);push('low grade <=70u',yourLowGradeHash,safeHashLowPriceG,hashLowValue,hashCostG);push('food grade 120u+',yourFoodGradeHash,safeHashFoodPriceG,hashFoodValue,hashCostG);}
    if(isRosin){
      push('hash (bubble)',yourHashGrams,safeHashPriceG,hashValue,hashCostG);
      push('t1 rosin',yourDabRosinGrams,safeRosinPriceG,dabRosinValue,yourDabRosinGrams>0?totalCost*(hashToDabRosin/Math.max(totalHashOut,1))/yourDabRosinGrams:0);
      push('t2 rosin',yourT2RosinGrams,safeT2RosinPriceG,t2RosinValue,yourT2RosinGrams>0?totalCost*(hashToT2Rosin/Math.max(totalHashOut,1))/yourT2RosinGrams:0);
      push('pen rosin',yourPenRosinGrams,safePenRosinPriceG,penRosinValue,yourPenRosinGrams>0?totalCost*(hashToPenRosin/Math.max(totalHashOut,1))/yourPenRosinGrams:0);
      push('food rosin',yourFoodRosinGrams,safeFoodRosinPriceG,foodRosinValue,yourFoodRosinGrams>0?totalCost*(hashToFoodRosin/Math.max(totalHashOut,1))/yourFoodRosinGrams:0);
    }
    if(isDistillate&&!hasRefinement)push('distillate',yourDistillateGrams,safeDistillatePriceG,distillateValue,yourDistillateGrams>0?totalCost/yourDistillateGrams:0);
    if(isLiveResin&&!hasRefinement)push('live resin',yourLiveResinGrams,safeLiveResinPriceG,liveResinValue,yourLiveResinGrams>0?totalCost/yourLiveResinGrams:0);
    if((isDistillate||isLiveResin)&&hasRefinement&&refinedOutputGrams>0)push(refinementLabel.toLowerCase(),refinedOutputGrams,safeDiamondPriceG,diamondValue,totalCost/refinedOutputGrams);
    const cols=['product','grams','value_per_g','total_value','cost_per_g'];
    let csv=cols.join(',')+'\n'+rows.map(r=>r.join(',')).join('\n');
    csv+=`\n\nsummary\ntotal_investment,${totalCost.toFixed(2)}\ntotal_output_value,${totalOutputValue.toFixed(2)}\nnet_profit,${netProfit.toFixed(2)}\nroi,${roi.toFixed(1)}%`;
    const blob=new Blob([csv],{type:'text/csv'});const url=URL.createObjectURL(blob);const a=document.createElement('a');
    a.href=url;a.download=`toll_${skuName.replace(/\s+/g,'_').toLowerCase()}.csv`;a.click();URL.revokeObjectURL(url);
  };

  const extractorPct=model==='split'?(splitTotalPct>0?safeSplitExtractor/splitTotalPct:0):0;
  const hasAnyInput=totalInputLbs>0;

  return(<div className="calc-page">
    <div className="readme">
      <p><strong style={{color:'var(--text)'}}>toll_calc.run</strong> — bulk processing economics. buy fresh frozen or trim, send it to an extractor, model the output. select extraction type, then choose toll-fee or split model. every downstream field reacts to your choice.</p>
    </div>

    <Section idx={1} title="extraction + model" active>
      <p className="section-desc">what are you running, and how are you paying for it. toll = pay a processing fee, keep 100% of output. split = extractor keeps a percentage.</p>

      <div className="sub-head"><span className="mark">//</span><span className="title">extraction_type</span></div>
      <Seg options={[
        {value:'hash_only',label:'hash_only'},
        {value:'hash_rosin',label:'hash_+_rosin'},
        {value:'distillate',label:'distillate'},
        {value:'live_resin',label:'live_resin'},
      ]} value={extractionType} onChange={setExtractionType}/>
      <p className="section-desc" style={{marginTop:8,marginBottom:16,fontSize:12}}>
        {extractionType==='hash_only'&&'fresh frozen → ice water hash (bubble). separate into micron grades for sale.'}
        {extractionType==='hash_rosin'&&'fresh frozen → hash → rosin press. allocate to dab / t2 / pen / food grades.'}
        {extractionType==='distillate'&&'trim or fresh frozen → hydrocarbon or ethanol extraction → distillate. high yield, lower $/g.'}
        {extractionType==='live_resin'&&'fresh frozen → live resin via bho/pho. preserves terpene profile.'}
      </p>

      <div className="sub-head"><span className="mark">//</span><span className="title">processing_model</span></div>
      <Seg options={[
        {value:'toll',label:'toll_processing'},
        {value:'split',label:'split_with_extractor'},
      ]} value={model} onChange={setModel}/>

      {model==='toll'&&isHash&&<div style={{marginTop:14}} className="g4">
        <div>
          <Field label={`wash_fee_per_${washFeeUnit==='gram'?'gram':'lb'}`} prefix="$" value={washFeePerG} onChange={setWashFeePerG} step={washFeeUnit==='gram'?0.005:1}/>
          <div style={{marginTop:6}}><Seg size="sm" options={[{value:'gram',label:'per_gram'},{value:'lb',label:'per_lb'}]} value={washFeeUnit} onChange={u=>{if(u!==washFeeUnit){setWashFeeUnit(u);setWashFeePerG(u==='lb'?+(washFeePerG*GRAMS_PER_LB).toFixed(2):+(washFeePerG/GRAMS_PER_LB).toFixed(4));}}}/></div>
        </div>
        {isRosin&&<div>
          <Field label={`press_fee_per_gram (${pressFeeBasis==='hash_input'?'hash_input':'rosin_output'})`} prefix="$" value={pressFeePerG} onChange={setPressFeePerG} step={0.05}/>
          <div style={{marginTop:6}}><Seg size="sm" options={[{value:'hash_input',label:'hash_grams'},{value:'rosin_output',label:'rosin_grams'}]} value={pressFeeBasis} onChange={setPressFeeBasis}/></div>
        </div>}
        <Stat label="you_keep" value="100%" sub="all output is yours, you pay fees"/>
        <Stat label="total_toll_cost" value={fmtK(washCost+pressCost)} sub={`${fmtK(washCost)} wash${isRosin?` + ${fmtK(pressCost)} press`:''}`} tone="warn"/>
      </div>}

      {model==='toll'&&(isDistillate||isLiveResin)&&<div style={{marginTop:14}}>
        <div className="g4">
          <div>
            <Field label={`extraction_fee_per_${extractionFeeUnit==='gram'?'gram':'lb'}`} prefix="$" value={extractionFeePerG} onChange={setExtractionFeePerG} step={extractionFeeUnit==='gram'?0.005:1}/>
            <div style={{marginTop:6}}><Seg size="sm" options={[{value:'gram',label:'per_gram'},{value:'lb',label:'per_lb'}]} value={extractionFeeUnit} onChange={u=>{if(u!==extractionFeeUnit){setExtractionFeeUnit(u);setExtractionFeePerG(u==='lb'?+(extractionFeePerG*GRAMS_PER_LB).toFixed(2):+(extractionFeePerG/GRAMS_PER_LB).toFixed(4));}}}/></div>
          </div>
          <Stat label="extraction_cost" value={fmtK(extractionCost)} sub={extractionFeeUnit==='gram'?`${totalInputGrams.toFixed(0)}g × ${fmt(safeExtractionFeePerG)}/g`:`${totalInputLbs}lb × ${fmt(safeExtractionFeePerG)}/lb`} tone="warn"/>
          <Stat label="you_keep" value="100%" sub="you pay fees"/>
        </div>
        <div style={{marginTop:14}}>
          <div className="sub-head"><span className="mark">//</span><span className="title">refinement_step</span><span className="note">— optional: diamonds, thca iso, sauce sep</span></div>
          <Seg options={[{value:false,label:'no_refinement'},{value:true,label:'add_refinement'}]} value={hasRefinement} onChange={setHasRefinement}/>
          {hasRefinement&&<div className="g4" style={{marginTop:12}}>
            <Field label="refinement_type" type="text" value={refinementLabel} onChange={setRefinementLabel}/>
            <Field label="refinement_fee_per_g (output)" prefix="$" value={refinementFeePerG} onChange={setRefinementFeePerG} step={0.25}/>
            <Field label="refinement_yield_pct" value={refinementYieldPct} onChange={setRefinementYieldPct} suffix="%"/>
            <Stat label="refined_output" value={`${((isDistillate?totalDistillateGrams:totalLiveResinGrams)*(safeRefinementYieldPct/100)).toFixed(0)}g`} sub={`${safeRefinementYieldPct}% of ${(isDistillate?totalDistillateGrams:totalLiveResinGrams).toFixed(0)}g`}/>
          </div>}
        </div>
      </div>}

      {model==='split'&&<div className="g4" style={{marginTop:14}}>
        <Field label="your_split" value={splitYou} onChange={v=>{setSplitYou(v);setSplitExtractor(100-v);}} suffix="%"/>
        <Field label="extractor_split" value={splitExtractor} onChange={v=>{setSplitExtractor(v);setSplitYou(100-v);}} suffix="%"/>
        <Stat label="industry_standard" value="70 / 30" sub="70% you, 30% extractor"/>
        <Stat label="you_keep" value={`${(yourPct*100).toFixed(0)}%`} sub="of all output"/>
      </div>}
    </Section>

    <Section idx={2} title="input material" active>
      <p className="section-desc">what goes in. cost × quantity = your material investment. fresh frozen and trim can mix.</p>
      <div className="g2" style={{marginBottom:12}}>
        <Field label="strain_/_run_name" type="text" value={skuName} onChange={setSkuName}/>
        <Stat label="total_input" value={`${totalInputLbs} lbs`} sub={`${(totalInputGrams/1000).toFixed(1)} kg`}/>
      </div>
      <div className="g4">
        <Field label="fresh_frozen_lbs" value={ffLbs} onChange={setFfLbs} suffix="lbs"/>
        <Field label="ff_cost_per_lb" prefix="$" value={ffCostPerLb} onChange={setFfCostPerLb}/>
        <Field label="trim_lbs" value={trimLbs} onChange={setTrimLbs} suffix="lbs"/>
        <Field label="trim_cost_per_lb" prefix="$" value={trimCostPerLb} onChange={setTrimCostPerLb}/>
      </div>
      <div className="g4" style={{marginTop:12}}>
        <Stat label="material_cost" value={fmtK(materialCost)} sub={`${safeFfLbs>0?safeFfLbs+'lb ff':''}${safeFfLbs>0&&safeTrimLbs>0?' + ':''}${safeTrimLbs>0?safeTrimLbs+'lb trim':''}`}/>
        {model==='toll'&&isHash&&<Stat label="wash_fee" value={fmtK(washCost)} sub={washFeeUnit==='gram'?`${totalInputGrams.toFixed(0)}g × ${fmt(safeWashFeePerG)}/g`:`${totalInputLbs}lb × ${fmt(safeWashFeePerG)}/lb`} tone="warn"/>}
        {model==='toll'&&isRosin&&<Stat label="press_fee" value={fmtK(pressCost)} sub={pressFeeBasis==='hash_input'?`${hashSentToPressGrams.toFixed(0)}g × ${fmt(safePressFeePerG)}/g`:`${totalRosinGrams.toFixed(0)}g × ${fmt(safePressFeePerG)}/g`} tone="warn"/>}
        {model==='toll'&&(isDistillate||isLiveResin)&&<Stat label="extraction_fee" value={fmtK(extractionCost)} sub={extractionFeeUnit==='gram'?`${totalInputGrams.toFixed(0)}g × ${fmt(safeExtractionFeePerG)}/g`:`${totalInputLbs}lb × ${fmt(safeExtractionFeePerG)}/lb`} tone="warn"/>}
        {model==='toll'&&hasRefinement&&refinementCost>0&&<Stat label={`${refinementLabel.toLowerCase()}_fee`} value={fmtK(refinementCost)} tone="warn"/>}
        <Stat label="total_investment" value={fmtK(totalCost)} sub={`material${tollCost>0?' + toll fees':''}`} tone="neg"/>
      </div>
    </Section>

    <Section idx={3} title="yields" active>
      {isHash&&<>
        <p className="section-desc">fresh frozen → ice water hash. quality runs 4-8% (6% is a solid benchmark).{isRosin?' hash presses at 70-85% into rosin — 80% typical.':''}</p>
        <div className="g3">
          <Field label="hash_yield_from_input" value={hashYieldPct} onChange={setHashYieldPct} suffix="%" step={0.5}/>
          {isRosin&&<Field label="t1_rosin_press_yield" value={rosinYieldFromHash} onChange={setRosinYieldFromHash} suffix="%"/>}
          <Stat label="total_hash_output" value={`${totalHashGrams.toFixed(0)}g`} sub={`${(totalHashGrams/28.35).toFixed(1)}oz from ${totalInputLbs}lb`}/>
        </div>
        {isRosin&&<div className="g3" style={{marginTop:10}}>
          <Field label="t2_press_yield" value={t2RosinPressYield} onChange={setT2RosinPressYield} suffix="%"/>
          <Field label="pen_grade_press_yield" value={penRosinPressYield} onChange={setPenRosinPressYield} suffix="%"/>
          <Field label="food_grade_press_yield" value={foodRosinPressYield} onChange={setFoodRosinPressYield} suffix="%"/>
        </div>}

        {/* ---- micron breakdown ---- */}
        <div style={{marginTop:18}}>
          <div className="sub-head"><span className="mark">//</span><span className="title">micron_size_breakdown</span><span className="note">— auto-normalized to 100%</span></div>

          <div className="micron-tier tier-premium">
            <div className="tier-head">
              <span className="tier-tag">full_melt</span>
              <span className="tier-range">73-120u — dabbable premium hash (5-6 star)</span>
            </div>
            <div className="g2">
              {microns.map((m,i)=>{const n=parseInt(m.size);if(isNaN(n)||n<73||n>=120||m.custom)return null;return(
                <div key={i} className="micron-row">
                  <div style={{flex:1}}><Field label={m.label} value={m.pct} onChange={v=>{const nm=[...microns];nm[i]={...m,pct:v};setMicrons(nm);}} suffix="%"/></div>
                  <div className="micron-gram">{(totalHashGrams*(normalizedPctAt(i)/100)).toFixed(0)}g</div>
                </div>);})}
            </div>
            <div className="tier-total"><span>full melt total</span><span>{premiumGradeGrams.toFixed(0)}g <span className="dim">({premiumGradePct.toFixed(0)}%)</span></span></div>
          </div>

          <div className="micron-tier tier-low">
            <div className="tier-head">
              <span className="tier-tag tier-tag-low">low_grade</span>
              <span className="tier-range">≤70u — immature / contaminant — press or edibles only</span>
            </div>
            <div className="g2">
              {microns.map((m,i)=>{const n=parseInt(m.size);if(isNaN(n)||n>70||m.custom)return null;return(
                <div key={i} className="micron-row">
                  <div style={{flex:1}}><Field label={m.label} value={m.pct} onChange={v=>{const nm=[...microns];nm[i]={...m,pct:v};setMicrons(nm);}} suffix="%"/></div>
                  <div className="micron-gram neg">{(totalHashGrams*(normalizedPctAt(i)/100)).toFixed(0)}g</div>
                </div>);})}
            </div>
            <div className="tier-total neg"><span>low grade total</span><span>{lowGradeGrams.toFixed(0)}g <span className="dim">({lowGradePct.toFixed(0)}%)</span></span></div>
          </div>

          <div className="micron-tier tier-food">
            <div className="tier-head">
              <span className="tier-tag tier-tag-food">food_grade</span>
              <span className="tier-range">120u+ — half melt / wash — edibles &amp; topicals</span>
            </div>
            <div className="g2">
              {microns.map((m,i)=>{const n=parseInt(m.size);if(isNaN(n)||n<120||m.custom)return null;return(
                <div key={i} className="micron-row">
                  <div style={{flex:1}}><Field label={m.label} value={m.pct} onChange={v=>{const nm=[...microns];nm[i]={...m,pct:v};setMicrons(nm);}} suffix="%"/></div>
                  <div className="micron-gram warn">{(totalHashGrams*(normalizedPctAt(i)/100)).toFixed(0)}g</div>
                </div>);})}
            </div>
            <div className="tier-total warn"><span>food grade total</span><span>{foodGradeGrams.toFixed(0)}g <span className="dim">({foodGradePct.toFixed(0)}%)</span></span></div>
          </div>

          {microns.some(m=>m.custom)&&<div className="micron-tier tier-custom">
            <div className="tier-head"><span className="tier-tag tier-tag-custom">custom</span></div>
            {microns.map((m,i)=>{if(!m.custom)return null;return(
              <div key={i} className="micron-row-custom">
                <div style={{flex:1}}><Field label="range_label" type="text" value={m.label} onChange={v=>{const nm=[...microns];nm[i]={...m,label:v};setMicrons(nm);}}/></div>
                <div style={{width:120}}><Field label="pct" value={m.pct} onChange={v=>{const nm=[...microns];nm[i]={...m,pct:v};setMicrons(nm);}} suffix="%"/></div>
                <div className="micron-gram">{(totalHashGrams*(normalizedPctAt(i)/100)).toFixed(0)}g</div>
                <button className="chip-btn chip-x" onClick={()=>removeMicron(i)}>×</button>
              </div>);})}
          </div>}

          <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginTop:10}}>
            <button className="chip-btn" onClick={addCustomMicron}>+ custom micron blend</button>
            {Math.abs(rawMicronTotalPct-100)>0.5?
              <span className="warn" style={{fontSize:12}}>input total: {rawMicronTotalPct.toFixed(0)}% — auto-normalized to 100%</span>:
              <span className="pos" style={{fontSize:12}}>[✓] 100%</span>}
          </div>
        </div>

        {isRosin&&<div style={{marginTop:18}}>
          <div className="sub-head"><span className="mark">//</span><span className="title">micron_to_rosin_assignment</span><span className="note">— route each tier to a rosin grade</span></div>
          <div className="assign-list">
            {microns.filter(m=>Number(m.pct)>0).map(m=>{const i=microns.indexOf(m);return(
              <div key={i} className="assign-row">
                <span className="assign-label">{m.label||m.size}</span>
                <span className="assign-gram">{(totalHashGrams*(normalizedPctAt(i)/100)).toFixed(0)}g</span>
                <span className="arrow">→</span>
                <select className="assign-sel" value={m.dest||'t1'} onChange={e=>{const nm=[...microns];nm[i]={...m,dest:e.target.value};setMicrons(nm);}}>
                  {destOptions.map(o=><option key={o.v} value={o.v}>{o.l}</option>)}
                </select>
              </div>);})}
          </div>
          <div className="g2" style={{marginTop:12}}>
            <Field label="2nd_press_yield (t1 pucks → t2)" value={secondPressYield} onChange={setSecondPressYield} suffix="%"/>
            <div style={{fontSize:12,color:'var(--text2)',paddingTop:22}}>{secondPressGrams>0?`+${secondPressGrams.toFixed(0)}g added to t2 from re-pressing t1 pucks`:'set > 0% to re-press t1 pucks into t2'}</div>
          </div>
        </div>}
      </>}

      {isDistillate&&<>
        <p className="section-desc">trim or fresh frozen → hydrocarbon or ethanol → distillate. typical yield: 8-15% trim, 10-18% ff.</p>
        <div className="g3">
          <Field label="distillate_yield" value={distillateYieldPct} onChange={setDistillateYieldPct} suffix="%" step={0.5}/>
          <Stat label="total_distillate_output" value={`${totalDistillateGrams.toFixed(0)}g`} sub={`${(totalDistillateGrams/28.35).toFixed(1)}oz from ${totalInputLbs}lb`}/>
          <Stat label="distillate_per_lb" value={`${(totalInputLbs>0?totalDistillateGrams/totalInputLbs:0).toFixed(1)}g/lb`} sub="avg yield"/>
        </div>
      </>}

      {isLiveResin&&<>
        <p className="section-desc">fresh frozen → live resin via bho/pho. preserves terpene profile. typical yield: 10-20%.</p>
        <div className="g3">
          <Field label="live_resin_yield" value={liveResinYieldPct} onChange={setLiveResinYieldPct} suffix="%" step={0.5}/>
          <Stat label="total_live_resin_output" value={`${totalLiveResinGrams.toFixed(0)}g`} sub={`${(totalLiveResinGrams/28.35).toFixed(1)}oz from ${totalInputLbs}lb`}/>
          <Stat label="live_resin_per_lb" value={`${(totalInputLbs>0?totalLiveResinGrams/totalInputLbs:0).toFixed(1)}g/lb`} sub="avg yield"/>
        </div>
      </>}
    </Section>

    <Section idx={4} title={`your_output${model==='split'?` — ${(yourPct*100).toFixed(0)}% split`:''}`} active>
      <p className="section-desc">what you keep after the processing model resolves.</p>
      <div className="g4">
        {extractionType==='hash_only'&&yourPremiumHash>0&&<Stat label="full_melt (73-120u)" value={`${yourPremiumHash.toFixed(0)}g`} sub={`${premiumGradePct.toFixed(0)}% — dabbable`} tone="pos"/>}
        {extractionType==='hash_only'&&yourLowGradeHash>0&&<Stat label="low_grade (≤70u)" value={`${yourLowGradeHash.toFixed(0)}g`} sub={`${lowGradePct.toFixed(0)}% — press/edibles`} tone="neg"/>}
        {extractionType==='hash_only'&&yourFoodGradeHash>0&&<Stat label="food_grade (120u+)" value={`${yourFoodGradeHash.toFixed(0)}g`} sub={`${foodGradePct.toFixed(0)}% — half melt / wash`} tone="warn"/>}
        {isRosin&&yourHashGrams>0&&<Stat label="hash (bubble)" value={`${yourHashGrams.toFixed(0)}g`} sub={micronSizesFor('hash')||'kept as hash'}/>}
        {isRosin&&yourDabRosinGrams>0&&<Stat label="t1_rosin (dab)" value={`${yourDabRosinGrams.toFixed(0)}g`} sub={`${safeRosinYieldFromHash}% press`} tone="pos"/>}
        {isRosin&&yourT2RosinGrams>0&&<Stat label="t2_rosin" value={`${yourT2RosinGrams.toFixed(0)}g`} sub={`${safeT2RosinPressYield}%${secondPressGrams>0?` + ${secondPressGrams.toFixed(0)}g 2nd press`:''}`}/>}
        {isRosin&&yourPenRosinGrams>0&&<Stat label="pen_rosin" value={`${yourPenRosinGrams.toFixed(0)}g`} sub={`${safePenRosinPressYield}% press`}/>}
        {isRosin&&yourFoodRosinGrams>0&&<Stat label="food_rosin" value={`${yourFoodRosinGrams.toFixed(0)}g`} sub={`${safeFoodRosinPressYield}% press`}/>}
        {isDistillate&&yourDistillateGrams>0&&<Stat label={hasRefinement?'base_distillate':'distillate'} value={`${yourDistillateGrams.toFixed(0)}g`} sub={`${safeDistillateYieldPct}% yield${hasRefinement?' pre-refinement':''}`}/>}
        {isLiveResin&&yourLiveResinGrams>0&&<Stat label={hasRefinement?'base_live_resin':'live_resin'} value={`${yourLiveResinGrams.toFixed(0)}g`} sub={`${safeLiveResinYieldPct}% yield${hasRefinement?' pre-refinement':''}`}/>}
        {(isDistillate||isLiveResin)&&hasRefinement&&refinedOutputGrams>0&&<Stat label={refinementLabel.toLowerCase()} value={`${refinedOutputGrams.toFixed(0)}g`} sub={`${safeRefinementYieldPct}% of base`} tone="pos"/>}
      </div>
      {model==='split'&&<p className="section-desc" style={{marginTop:12}}>extractor keeps ({(extractorPct*100).toFixed(0)}%):
        {isHash&&hashToKeepAsHash>0&&` ${(hashToKeepAsHash*extractorPct).toFixed(0)}g hash,`}
        {isRosin&&dabRosinGrams>0&&` ${(dabRosinGrams*extractorPct).toFixed(0)}g t1,`}
        {isRosin&&t2RosinGrams>0&&` ${(t2RosinGrams*extractorPct).toFixed(0)}g t2,`}
        {isRosin&&penRosinGrams>0&&` ${(penRosinGrams*extractorPct).toFixed(0)}g pen,`}
        {isRosin&&foodRosinGrams>0&&` ${(foodRosinGrams*extractorPct).toFixed(0)}g food,`}
        {isDistillate&&` ${(totalDistillateGrams*extractorPct).toFixed(0)}g distillate,`}
        {isLiveResin&&` ${(totalLiveResinGrams*extractorPct).toFixed(0)}g live resin`}
      </p>}
    </Section>

    <Section idx={5} title="market_valuation" active>
      <p className="section-desc">set per-gram value for each output. use these as inputs in the vapes / hash-rosin finished-good calculators.</p>
      <div className="g4">
        {extractionType==='hash_only'&&<Field label="full_melt $/g (73-120u)" prefix="$" value={hashPriceG} onChange={setHashPriceG}/>}
        {extractionType==='hash_only'&&<Field label="low_grade $/g (≤70u)" prefix="$" value={hashLowPriceG} onChange={setHashLowPriceG}/>}
        {extractionType==='hash_only'&&<Field label="food_grade $/g (120u+)" prefix="$" value={hashFoodPriceG} onChange={setHashFoodPriceG}/>}
        {isRosin&&hashToKeepAsHash>0&&<Field label="hash $/g" prefix="$" value={hashPriceG} onChange={setHashPriceG}/>}
        {isRosin&&hashToDabRosin>0&&<Field label="t1_rosin $/g" prefix="$" value={rosinPriceG} onChange={setRosinPriceG}/>}
        {isRosin&&(hashToT2Rosin>0||secondPressGrams>0)&&<Field label="t2_rosin $/g" prefix="$" value={t2RosinPriceG} onChange={setT2RosinPriceG}/>}
        {isRosin&&hashToPenRosin>0&&<Field label="pen_rosin $/g" prefix="$" value={penRosinPriceG} onChange={setPenRosinPriceG}/>}
        {isRosin&&hashToFoodRosin>0&&<Field label="food_rosin $/g" prefix="$" value={foodRosinPriceG} onChange={setFoodRosinPriceG}/>}
        {isDistillate&&!hasRefinement&&<Field label="distillate $/g" prefix="$" value={distillatePriceG} onChange={setDistillatePriceG}/>}
        {isLiveResin&&!hasRefinement&&<Field label="live_resin $/g" prefix="$" value={liveResinPriceG} onChange={setLiveResinPriceG}/>}
        {(isDistillate||isLiveResin)&&hasRefinement&&<Field label={`${refinementLabel.toLowerCase()} $/g`} prefix="$" value={diamondPriceG} onChange={setDiamondPriceG}/>}
      </div>
    </Section>

    <Section idx={6} title="p_and_l" active done={hasAnyInput}>
      <p className="section-desc">output value minus everything you paid to make it.</p>
      <Waterfall
        caption="profit waterfall"
        lines={[
          {label:`output_value${model==='split'?` (${(yourPct*100).toFixed(0)}% split)`:''}`,value:totalOutputValue,tone:'pos'},
          {label:`material_cost`,value:-materialCost,tone:'neg'},
          ...(model==='toll'&&isHash&&washCost>0?[{label:'wash_fee',value:-washCost,tone:'neg'}]:[]),
          ...(model==='toll'&&isRosin&&pressCost>0?[{label:'press_fee',value:-pressCost,tone:'neg'}]:[]),
          ...(model==='toll'&&(isDistillate||isLiveResin)&&extractionCost>0?[{label:'extraction_fee',value:-extractionCost,tone:'neg'}]:[]),
          ...(model==='toll'&&hasRefinement&&refinementCost>0?[{label:`${refinementLabel.toLowerCase()}_fee`,value:-refinementCost,tone:'neg'}]:[]),
        ]}
        total={netProfit}
        totalLabel="net_profit"
      />
      <div className="g4" style={{marginTop:14}}>
        <Stat label="total_investment" value={fmtK(totalCost)} tone="neg"/>
        <Stat label="total_output_value" value={fmtK(totalOutputValue)}/>
        <Stat label="net_profit" value={fmtK(netProfit)} tone={netProfit>0?'pos':'neg'}/>
        <Stat label="roi" value={`${roi.toFixed(0)}%`} sub="return on investment" tone={roi>20?'pos':roi>0?'warn':'neg'}/>
      </div>
    </Section>

    <Section idx={7} title="cost_per_gram_of_output" active>
      <p className="section-desc">your effective input cost per gram for each product — use in the vapes / prerolls calculators when modeling finished-goods margin.</p>
      <div className="g4">
        {extractionType==='hash_only'&&yourPremiumHash>0&&<Stat label="full_melt $/g" value={fmt(totalCost*(premiumGradePct/100)/yourPremiumHash)} sub="effective input cost" tone="pos"/>}
        {extractionType==='hash_only'&&yourLowGradeHash>0&&<Stat label="low_grade $/g" value={fmt(totalCost*(lowGradePct/100)/yourLowGradeHash)} sub="effective input cost" tone="warn"/>}
        {extractionType==='hash_only'&&yourFoodGradeHash>0&&<Stat label="food_grade $/g" value={fmt(totalCost*(foodGradePct/100)/yourFoodGradeHash)} sub="effective input cost" tone="warn"/>}
        {isRosin&&yourHashGrams>0&&<Stat label="hash $/g" value={fmt(totalCost*(hashToKeepAsHash/Math.max(hashToKeepAsHash+hashToDabRosin+hashToT2Rosin+hashToPenRosin+hashToFoodRosin,1))/yourHashGrams)} sub="effective input cost" tone="pos"/>}
        {isRosin&&yourDabRosinGrams>0&&<Stat label="t1_rosin $/g" value={fmt(totalCost*(hashToDabRosin/Math.max(hashToKeepAsHash+hashToDabRosin+hashToT2Rosin+hashToPenRosin+hashToFoodRosin,1))/yourDabRosinGrams)} tone="pos"/>}
        {isRosin&&yourT2RosinGrams>0&&<Stat label="t2_rosin $/g" value={fmt(totalCost*(hashToT2Rosin/Math.max(hashToKeepAsHash+hashToDabRosin+hashToT2Rosin+hashToPenRosin+hashToFoodRosin,1))/yourT2RosinGrams)} tone="pos"/>}
        {isRosin&&yourPenRosinGrams>0&&<Stat label="pen_rosin $/g" value={fmt(totalCost*(hashToPenRosin/Math.max(hashToKeepAsHash+hashToDabRosin+hashToT2Rosin+hashToPenRosin+hashToFoodRosin,1))/yourPenRosinGrams)} tone="pos"/>}
        {isRosin&&yourFoodRosinGrams>0&&<Stat label="food_rosin $/g" value={fmt(totalCost*(hashToFoodRosin/Math.max(hashToKeepAsHash+hashToDabRosin+hashToT2Rosin+hashToPenRosin+hashToFoodRosin,1))/yourFoodRosinGrams)} tone="pos"/>}
        {isDistillate&&yourDistillateGrams>0&&!hasRefinement&&<Stat label="distillate $/g" value={fmt(totalCost/yourDistillateGrams)} tone="pos"/>}
        {isLiveResin&&yourLiveResinGrams>0&&!hasRefinement&&<Stat label="live_resin $/g" value={fmt(totalCost/yourLiveResinGrams)} tone="pos"/>}
        {(isDistillate||isLiveResin)&&hasRefinement&&refinedOutputGrams>0&&<Stat label={`${refinementLabel.toLowerCase()} $/g`} value={fmt(totalCost/refinedOutputGrams)} sub="effective refined cost" tone="pos"/>}
      </div>
      <div style={{textAlign:'center',marginTop:18}}>
        <button className="chip-btn chip-btn-cta" onClick={exportCSV}>export toll processing csv ↓</button>
      </div>
    </Section>
  </div>);
}

Object.assign(window,{TollTab});
