// Area.jsx — VM0047 v1.1 AREA-BASED workflow.
//
// The atomic record is a fixed-radius SAMPLING PLOT inside a stratum.
// Field flow:
//   1. AreaPlotBrief    visit summary, task list, inventory hero
//   2. PlotLocateTask   walk to designed plot centre, drop pin
//   3. PlotInventory    every stem inside the plot — species, DBH, height
//   4. PlotObsTask      cover %, regen, disturbance, soil
//   5. PlotPhotosTask   4 cardinals + plot centre, optional species closeups
//   6. PlotReviewTask   readiness scorecard, sign locally, submit

// ─────────────────────────────────────────────────────────
// AREA PLOT BRIEF
// ─────────────────────────────────────────────────────────
function AreaPlotBrief({ visit, data, stems, onTask, onInventory, showMethodologyTags }) {
  const [setupOpen, setSetupOpen] = React.useState(false);

  const liveStems = stems.filter(s => s.status !== 'dead');
  const stemCount = liveStems.length;
  // Basal area (m²) per plot = sum(π*(dbh/2)²)/10000
  const ba = liveStems.reduce((s,t) => s + Math.PI * Math.pow((t.dbh||0)/2, 2), 0) / 10000;
  // Trees-per-hectare extrapolation
  const tph = visit.plotAreaM2 ? Math.round(stemCount / visit.plotAreaM2 * 10000) : 0;

  const speciesCount = new Set(liveStems.map(s=>s.species)).size;

  const isLocateDone  = !!data.plotLocated;
  const isInvDone     = stemCount > 0 && !!data.inventoryConfirmed;
  const isObsDone     = !!data.obsConfirmed;
  const isPhotosDone  = !!data.cardinalsConfirmed;

  const tasks = [
    { id:'plotlocate',  icon:'pin',   title:'Walk to plot centre',  sub:'Designed coords · drop pin within 5 m',         done:isLocateDone,  mtag:'M3 §9.1' },
    { id:'plotinventory',icon:'stems',title:'Plot inventory',       sub:stemCount>0 ? `${stemCount} stems · ${speciesCount} species` : 'Tree-by-tree inside the plot · DBH · height', done:isInvDone, mtag:'M3 §10.2' },
    { id:'plotobs',     icon:'eye',   title:'Plot observations',    sub:'Cover · regen · disturbance · soil',            done:isObsDone,     mtag:'M3 §10.4' },
    { id:'plotphotos',  icon:'cam',   title:'Cardinal photos',      sub:'N · E · S · W from plot centre · centre shot',  done:isPhotosDone,  mtag:'M3 §11.1' },
  ];
  const doneCount = tasks.filter(t=>t.done).length;
  const allDone = doneCount === tasks.length && stemCount > 0;

  return (
    <div style={{padding:'14px 16px 24px',display:'flex',flexDirection:'column',gap:12}}>
      {/* Plot header — stratum + designed coords */}
      <div style={{background:'#fff',border:'1px solid #E5E7EB',borderRadius:12,padding:'12px 14px'}}>
        <div style={{display:'flex',justifyContent:'space-between',alignItems:'baseline',gap:10}}>
          <div style={{minWidth:0,flex:1}}>
            <div style={{fontSize:10,fontWeight:800,letterSpacing:'0.1em',color:'#059669',fontFamily:"'JetBrains Mono', monospace"}}>{visit.id} · AREA · {visit.type.toUpperCase()}</div>
            <div style={{fontSize:17,fontWeight:900,letterSpacing:'-0.01em',color:'#022C28',marginTop:2}}>Plot {visit.id.replace('PLT-','')}</div>
            <div style={{fontSize:12,color:'#6B7280',marginTop:1}}>{visit.village}</div>
          </div>
          <div style={{textAlign:'right',flexShrink:0}}>
            <div style={{fontSize:10,fontWeight:800,letterSpacing:'0.06em',color:'#6B7280'}}>STRATUM {visit.stratum}</div>
            <div style={{fontSize:13,fontWeight:800,color:'#022C28',marginTop:1,fontFamily:"'JetBrains Mono', monospace"}}>{visit.stratumAreaHa} ha</div>
            <div style={{fontSize:10,color:'#6B7280',fontFamily:"'JetBrains Mono', monospace",marginTop:1}}>{visit.project.split('·')[1]?.trim()}</div>
          </div>
        </div>
        <div style={{display:'flex',gap:6,marginTop:10,paddingTop:10,borderTop:'1px solid #F3F4F6'}}>
          {[{l:'PLOT SHAPE',v:visit.plotShape},{l:'RADIUS',v:`${visit.plotRadiusM} m`},{l:'PLOT AREA',v:`${visit.plotAreaM2} m²`}].map((s,i)=>(
            <div key={i} style={{flex:1}}>
              <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.08em',color:'#9CA3AF'}}>{s.l}</div>
              <div style={{fontSize:12.5,fontWeight:800,color:'#022C28',marginTop:3,letterSpacing:'-0.01em'}}>{s.v}</div>
            </div>
          ))}
        </div>
        <div style={{marginTop:10,paddingTop:10,borderTop:'1px solid #F3F4F6',display:'flex',justifyContent:'space-between',alignItems:'center'}}>
          <div>
            <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.08em',color:'#9CA3AF'}}>STRATUM</div>
            <div style={{fontSize:12.5,fontWeight:800,color:'#022C28',marginTop:2,letterSpacing:'-0.01em'}}>{visit.stratumName}</div>
          </div>
          <div style={{textAlign:'right'}}>
            <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.08em',color:'#9CA3AF'}}>DESIGNED CENTRE</div>
            <div style={{fontSize:11,fontWeight:700,color:'#022C28',marginTop:2,fontFamily:"'JetBrains Mono', monospace"}}>0.1721, 34.0218</div>
          </div>
        </div>
      </div>

      {/* INVENTORY HERO */}
      <div style={{background:'#022C28',color:'#fff',borderRadius:14,padding:'16px',display:'flex',flexDirection:'column',gap:14,position:'relative',overflow:'hidden'}}>
        <div style={{position:'absolute',inset:0,background:'radial-gradient(ellipse 70% 50% at 80% 0%, rgba(43,196,138,0.16), transparent 70%)',pointerEvents:'none'}}/>
        <div style={{position:'relative',display:'flex',justifyContent:'space-between',alignItems:'flex-start',gap:10}}>
          <div style={{flex:1,minWidth:0}}>
            <div style={{fontSize:10,fontWeight:800,letterSpacing:'0.1em',color:'#2BC48A',fontFamily:"'JetBrains Mono', monospace"}}>PLOT INVENTORY · STEMS</div>
            <div style={{display:'flex',alignItems:'baseline',gap:6,marginTop:6}}>
              <div style={{fontSize:38,fontWeight:900,color:'#fff',letterSpacing:'-0.03em',lineHeight:1}}>{stemCount}</div>
              <div style={{fontSize:14,color:'rgba(255,255,255,0.55)',fontWeight:700,fontFamily:"'JetBrains Mono', monospace"}}>{stemCount===0?'· not started':'live stems'}</div>
            </div>
            <div style={{fontSize:12,color:'rgba(255,255,255,0.7)',marginTop:2}}>
              {stemCount===0 ? `Stand at centre and tap each tree inside ${visit.plotRadiusM} m` : `${speciesCount} species · ${(stems.length-liveStems.length)>0 ? `${stems.length-liveStems.length} dead/snag` : 'all live'}`}
            </div>
          </div>
          <div style={{textAlign:'right',background:'rgba(255,255,255,0.06)',padding:'10px 12px',borderRadius:10,minWidth:108}}>
            <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.08em',color:'rgba(255,255,255,0.55)',fontFamily:"'JetBrains Mono', monospace"}}>EXTRAPOLATED</div>
            <div style={{display:'flex',alignItems:'baseline',gap:3,marginTop:2,justifyContent:'flex-end'}}>
              <span style={{fontSize:22,fontWeight:900,color:'#F4C300',letterSpacing:'-0.02em',lineHeight:1}}>{tph || '—'}</span>
              <span style={{fontSize:10,color:'rgba(255,255,255,0.55)',fontWeight:700}}>/ha</span>
            </div>
            <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.06em',color:'rgba(255,255,255,0.45)',marginTop:3,fontFamily:"'JetBrains Mono', monospace"}}>BA · {ba.toFixed(3)} M²</div>
          </div>
        </div>

        {/* Stem dots preview */}
        {stemCount > 0 && (
          <div style={{display:'flex',gap:4,overflowX:'auto',scrollbarWidth:'none'}}>
            {liveStems.slice(0,10).map(s => {
              const sp = speciesById(s.species);
              return (
                <div key={s.id} style={{flexShrink:0,background:'rgba(43,196,138,0.12)',border:'1px solid rgba(43,196,138,0.28)',borderRadius:6,padding:'4px 7px',fontSize:9,color:'#2BC48A',fontFamily:"'JetBrains Mono', monospace",fontWeight:800,letterSpacing:'0.04em',whiteSpace:'nowrap'}}>
                  {s.id} · {sp?.common.split(' ')[0]} · {s.dbh}cm
                </div>
              );
            })}
            {stemCount > 10 && <div style={{flexShrink:0,padding:'4px 7px',fontSize:9,color:'rgba(255,255,255,0.55)',fontFamily:"'JetBrains Mono', monospace",fontWeight:700}}>+{stemCount-10} more</div>}
          </div>
        )}

        <button onClick={onInventory} disabled={!isLocateDone} style={{padding:'14px',background: isLocateDone ? '#F4C300' : 'rgba(255,255,255,0.1)',color: isLocateDone ? '#022C28' : 'rgba(255,255,255,0.55)',border:'none',borderRadius:12,fontWeight:900,fontSize:15,cursor: isLocateDone ? 'pointer' : 'not-allowed',fontFamily:'inherit',letterSpacing:'-0.01em',display:'flex',alignItems:'center',justifyContent:'center',gap:8,boxShadow: isLocateDone ? '0 8px 24px rgba(244,195,0,0.25)' : 'none'}}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10" strokeDasharray="3 3"/><circle cx="12" cy="12" r="1.5" fill="currentColor"/></svg>
          {!isLocateDone ? 'Locate plot centre first' : stemCount===0 ? 'Start plot inventory' : 'Continue inventory'}
        </button>
      </div>

      {/* Tasks (always shown — only 4) */}
      <button onClick={()=>setSetupOpen(o=>!o)} style={{background:'#fff',border:'1px solid #E5E7EB',borderRadius:12,padding:'12px 14px',display:'flex',alignItems:'center',gap:12,cursor:'pointer',fontFamily:'inherit',textAlign:'left'}}>
        <div style={{width:34,height:34,borderRadius:8,background: allDone?'#ECFDF5':'#FFF8E0',color: allDone?'#059669':'#B8960A',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
          {allDone
            ? <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
            : <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>}
        </div>
        <div style={{flex:1,minWidth:0}}>
          <div style={{fontSize:14,fontWeight:900,color:'#022C28',letterSpacing:'-0.01em'}}>Plot tasks{allDone?' · complete':''}</div>
          <div style={{fontSize:11,color:'#6B7280',marginTop:1}}>{doneCount} of {tasks.length} complete · locate, inventory, observe, photograph</div>
        </div>
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#9CA3AF" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{flexShrink:0,transform: setupOpen?'rotate(90deg)':'none',transition:'transform .2s'}}><polyline points="9 18 15 12 9 6"/></svg>
      </button>
      {setupOpen && (
        <div style={{display:'flex',flexDirection:'column',gap:8,marginTop:-4}}>
          {tasks.map(tk => <TaskTile key={tk.id} t={{...tk, critical:true}} onOpen={()=>onTask(tk.id)} showMtag={showMethodologyTags}/>)}
        </div>
      )}

      <button onClick={()=>onTask('plotreview')}
        style={{marginTop:4,padding:'14px',background: allDone ? '#F4C300':'#022C28',color: allDone ? '#022C28':'#fff',border:'none',borderRadius:12,fontWeight:900,fontSize:15,cursor: allDone ? 'pointer':'not-allowed',fontFamily:'inherit',letterSpacing:'-0.01em',opacity: allDone ? 1 : 0.55}}
        disabled={!allDone}>
        {allDone ? `Submit plot · ${stemCount} stems ✓` : `Submit · ${tasks.length-doneCount} task${tasks.length-doneCount>1?'s':''} left`}
      </button>
    </div>
  );
}

// ─────────────────────────────────────────────────────────
// PLOT LOCATE — walk to designed center
// ─────────────────────────────────────────────────────────
function PlotLocateTask({ visit, data, update, onDone, ai }) {
  const [distance, setDistance] = React.useState(data.distanceToCentre ?? 18.2);
  const [walking, setWalking] = React.useState(false);

  const onSite = distance <= 5;
  const close = distance <= 12 && !onSite;
  const acc = onSite ? 3.4 : close ? 4.6 : 6.2;

  const startWalk = () => {
    setWalking(true);
    let d = distance;
    const iv = setInterval(()=>{
      d = Math.max(2.4, d - 1.6 - Math.random()*0.4);
      setDistance(parseFloat(d.toFixed(1)));
      if (d <= 2.5) { clearInterval(iv); setWalking(false); }
    }, 280);
  };

  const confirm = () => {
    update({ plotLocated:true, plotCentreLat:'0.17213', plotCentreLon:'34.02181', plotCentreAcc:acc, distanceToCentre:distance });
    onDone();
  };

  return (
    <TaskShell ctaLabel={onSite ? 'Confirm plot centre' : `Walk closer · ${distance.toFixed(1)} m to go`} onCta={confirm} disabled={!onSite}>
      {/* Map */}
      <div style={{position:'relative',height:240,borderRadius:12,overflow:'hidden',background:'linear-gradient(135deg,#1a3d39 0%,#022C28 100%)'}}>
        <svg width="100%" height="100%" viewBox="0 0 360 240" style={{position:'absolute',inset:0}} preserveAspectRatio="xMidYMid slice">
          <defs><pattern id="locgrid" width="22" height="22" patternUnits="userSpaceOnUse"><path d="M 22 0 L 0 0 0 22" fill="none" stroke="rgba(255,255,255,0.05)" strokeWidth="0.5"/></pattern></defs>
          <rect width="360" height="240" fill="url(#locgrid)"/>
          {/* Stratum patch */}
          <path d="M40,40 L320,30 L340,210 L60,220 Z" fill="rgba(43,196,138,0.06)" stroke="rgba(43,196,138,0.25)" strokeWidth="1" strokeDasharray="4 4"/>
          <text x="50" y="56" fontSize="9" fill="rgba(43,196,138,0.7)" fontFamily="'JetBrains Mono', monospace">STRATUM {visit.stratum}</text>
          {/* Designed plot circle (target) */}
          <g transform="translate(220,118)">
            <circle r="46" fill="rgba(244,195,0,0.06)" stroke="rgba(244,195,0,0.5)" strokeWidth="1.5" strokeDasharray="4 3"/>
            <circle r="3" fill="#F4C300" stroke="#022C28" strokeWidth="1"/>
            <text x="0" y="-52" textAnchor="middle" fontSize="9" fill="#F4C300" fontFamily="'JetBrains Mono', monospace" fontWeight="800">PLOT {visit.id.replace('PLT-','')}</text>
            <text x="0" y="20" textAnchor="middle" fontSize="8" fill="rgba(244,195,0,0.65)" fontFamily="'JetBrains Mono', monospace">{visit.plotRadiusM} m</text>
          </g>
          {/* Agent position */}
          {(() => {
            // Pose agent based on distance — closer to centre as distance shrinks
            const ax = 220 - distance * 4.4;
            const ay = 118 + distance * 2.4;
            return (
              <>
                <line x1={ax} y1={ay} x2="220" y2="118" stroke="rgba(43,196,138,0.5)" strokeWidth="1" strokeDasharray="3 3"/>
                <g transform={`translate(${ax},${ay})`} style={{animation:'gpsPulse 1.6s infinite'}}>
                  <circle r="20" fill="#2BC48A" opacity="0.15"/>
                  <circle r="11" fill="#2BC48A" opacity="0.35"/>
                  <circle r="6" fill="#2BC48A" stroke="#fff" strokeWidth="2"/>
                </g>
              </>
            );
          })()}
        </svg>
        <div style={{position:'absolute',top:10,left:12,background:'rgba(2,28,24,0.7)',padding:'5px 9px',borderRadius:6,fontSize:9,fontWeight:800,letterSpacing:'0.08em',color:'#F4C300',fontFamily:"'JetBrains Mono', monospace"}}>SATELLITE · CACHED · MAY 11</div>
        <button onClick={startWalk} disabled={walking || onSite} style={{position:'absolute',bottom:10,right:10,background: walking ? 'rgba(43,196,138,0.9)' : onSite ? 'rgba(43,196,138,0.4)' : '#F4C300',color: walking ? '#022C28' : onSite ? '#022C28' : '#022C28',border:'none',padding:'8px 14px',borderRadius:8,fontWeight:900,fontSize:12,cursor: walking||onSite ?'not-allowed':'pointer',fontFamily:'inherit',letterSpacing:'-0.01em'}}>
          {walking ? 'Walking…' : onSite ? '✓ At centre' : 'Simulate walk'}
        </button>
      </div>

      {/* Distance card */}
      <div style={{background:'#022C28',color:'#fff',borderRadius:12,padding:'14px 16px'}}>
        <div style={{display:'flex',justifyContent:'space-between',alignItems:'flex-start',gap:12}}>
          <div>
            <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.1em',color:'#F4C300',fontFamily:"'JetBrains Mono', monospace"}}>DISTANCE TO DESIGNED CENTRE</div>
            <div style={{fontSize:30,fontWeight:900,color: onSite?'#2BC48A':close?'#F4C300':'#fff',letterSpacing:'-0.02em',marginTop:6,fontFamily:"'JetBrains Mono', monospace",lineHeight:1}}>{distance.toFixed(1)}<span style={{fontSize:14,opacity:0.6,fontWeight:700,marginLeft:4}}>m</span></div>
            <div style={{fontSize:11,color:'rgba(255,255,255,0.7)',marginTop:4}}>
              {onSite ? 'You are within the 5 m tolerance · confirm' : close ? 'Almost there — keep walking' : 'Designed centre is ahead'}
            </div>
          </div>
          <div style={{textAlign:'right'}}>
            <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.08em',color:'rgba(255,255,255,0.55)',fontFamily:"'JetBrains Mono', monospace"}}>GPS ACCURACY</div>
            <div style={{fontSize:18,fontWeight:900,color: acc<=4?'#2BC48A':acc<=6?'#F4C300':'#DC2626',marginTop:2,fontFamily:"'JetBrains Mono', monospace",letterSpacing:'-0.02em'}}>±{acc.toFixed(1)} m</div>
            <div style={{fontSize:9,color:'rgba(255,255,255,0.55)',fontFamily:"'JetBrains Mono', monospace",fontWeight:700,marginTop:1}}>{acc<=4?'EXCELLENT':acc<=6?'OK':'POOR'}</div>
          </div>
        </div>
      </div>

      {/* Designed coords reference */}
      <Field label="Designed plot centre" hint="From project sampling design · do not edit on tablet">
        <div style={{display:'flex',justifyContent:'space-between',fontSize:13,padding:'4px 0'}}>
          <span style={{fontFamily:"'JetBrains Mono', monospace",fontWeight:800,color:'#022C28'}}>0.17213 N, 34.02181 E</span>
          <span style={{fontSize:11,color:'#6B7280',fontFamily:"'JetBrains Mono', monospace"}}>WGS84 · alt 1,212 m</span>
        </div>
      </Field>

      {/* AI tip */}
      {ai && <div style={{background:'#EFF6FF',border:'1px solid #BFDBFE',borderRadius:10,padding:'12px 14px',display:'flex',gap:10,alignItems:'flex-start'}}>
        <div style={{width:24,height:24,borderRadius:6,background:'#0077B6',color:'#fff',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0,marginTop:1}}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4"/></svg>
        </div>
        <div style={{fontSize:12,color:'#1E40AF',lineHeight:1.45}}>If GPS reading drifts &gt;8 m after standing still 30 s, mark plot as <b>offset</b> at review. Verifier will see both designed and captured centres.</div>
      </div>}

      <Field label="If the designed centre is unreachable" hint="Trees, water, fence. Leave blank if you reached it.">
        <ChipPicker value={data.offsetReason || ''} onChange={(v)=>update({offsetReason:v})} options={[['','None'],['canopy','Canopy gap'],['water','In water'],['fence','Fenced'],['steep','Too steep'],['safety','Safety']]}/>
      </Field>
    </TaskShell>
  );
}

// ─────────────────────────────────────────────────────────
// PLOT INVENTORY — stem-by-stem inside the plot
// ─────────────────────────────────────────────────────────
function PlotInventory({ plot, stems, recentSpecies, onSaveStem, onExit }) {
  const [sheetOpen, setSheetOpen] = React.useState(false);
  const [pickerOpen, setPickerOpen] = React.useState(false);
  const [draft, setDraft] = React.useState(null);
  const [savedTick, setSavedTick] = React.useState(false);

  const startCapture = () => {
    setSheetOpen(true);
    // Random position within plot radius
    const r = Math.random() * plot.plotRadiusM * 0.95;
    const theta = Math.random() * 360;
    const num = (stems.length + 1).toString().padStart(2,'0');
    setDraft({
      id: `ST-${num}`,
      r: parseFloat(r.toFixed(1)),
      theta: Math.round(theta),
      speciesId: recentSpecies[0] || 'sp_grevillea',
      dbh: '',
      height: '',
      status: 'live',
    });
  };

  const save = (andContinue) => {
    if (!draft) return;
    if (!draft.dbh) return;
    const newStem = {
      id: draft.id,
      r: parseFloat(draft.r),
      theta: parseFloat(draft.theta),
      species: draft.speciesId,
      dbh: parseFloat(draft.dbh),
      height: parseFloat(draft.height) || null,
      status: draft.status,
    };
    onSaveStem(newStem, draft.speciesId);
    setSavedTick(true);
    setTimeout(()=>setSavedTick(false), 900);
    if (andContinue) {
      setTimeout(()=>{
        const r = Math.random() * plot.plotRadiusM * 0.95;
        const theta = Math.random() * 360;
        const num = (stems.length + 2).toString().padStart(2,'0');
        setDraft({
          id: `ST-${num}`,
          r: parseFloat(r.toFixed(1)),
          theta: Math.round(theta),
          speciesId: draft.speciesId,
          dbh: '',
          height: '',
          status: 'live',
        });
      }, 280);
    } else {
      setSheetOpen(false);
      setDraft(null);
    }
  };

  return (
    <div style={{position:'relative',height:'100%',display:'flex',flexDirection:'column',background:'#0e1f15',overflow:'hidden'}}>
      <PlotMap plot={plot} stems={stems} highlightLatest={savedTick && stems.length>0 ? stems[stems.length-1] : null}/>

      {/* Top chip */}
      <div style={{position:'absolute',top:12,left:12,right:12,display:'flex',gap:8,zIndex:5}}>
        <div style={{flex:1,background:'rgba(2,28,24,0.82)',border:'1px solid rgba(255,255,255,0.08)',backdropFilter:'blur(10px)',WebkitBackdropFilter:'blur(10px)',borderRadius:12,padding:'10px 12px',display:'flex',alignItems:'center',gap:12,color:'#fff'}}>
          <div>
            <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.1em',color:'rgba(255,255,255,0.55)',fontFamily:"'JetBrains Mono', monospace"}}>STEMS</div>
            <div style={{fontSize:18,fontWeight:900,color:'#2BC48A',letterSpacing:'-0.02em',marginTop:1}}>{stems.length}</div>
          </div>
          <div style={{width:1,height:30,background:'rgba(255,255,255,0.1)'}}/>
          <div style={{flex:1}}>
            <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.08em',color:'rgba(255,255,255,0.55)',fontFamily:"'JetBrains Mono', monospace"}}>PLOT {plot.id.replace('PLT-','')}</div>
            <div style={{fontSize:13,fontWeight:800,color:'#F4C300',marginTop:1,fontFamily:"'JetBrains Mono', monospace",letterSpacing:'-0.01em'}}>r ≤ {plot.plotRadiusM} m · circular</div>
          </div>
        </div>
        <button onClick={onExit} style={{background:'rgba(2,28,24,0.8)',border:'1px solid rgba(255,255,255,0.1)',color:'#fff',padding:'8px 12px',borderRadius:10,fontSize:11,fontWeight:800,letterSpacing:'0.06em',cursor:'pointer',fontFamily:'inherit',whiteSpace:'nowrap',backdropFilter:'blur(8px)',WebkitBackdropFilter:'blur(8px)'}}>
          Done
        </button>
      </div>

      {/* Saved toast */}
      {savedTick && <div style={{position:'absolute',top:'48%',left:'50%',transform:'translate(-50%,-50%)',background:'rgba(43,196,138,0.95)',color:'#022C28',padding:'10px 20px',borderRadius:999,fontWeight:900,fontSize:14,zIndex:6,letterSpacing:'-0.01em',boxShadow:'0 10px 30px rgba(0,0,0,0.3)',animation:'pop .3s ease-out'}}>
        ✓ Saved · {stems.length} stems
      </div>}

      {/* Idle CTA */}
      {!sheetOpen && (
        <div style={{position:'absolute',left:18,right:18,bottom:24,zIndex:5}}>
          <button onClick={startCapture} style={{width:'100%',padding:'18px',background:'#F4C300',color:'#022C28',border:'none',borderRadius:14,fontWeight:900,fontSize:16,cursor:'pointer',fontFamily:'inherit',letterSpacing:'-0.01em',display:'flex',alignItems:'center',justifyContent:'center',gap:10,boxShadow:'0 12px 40px rgba(244,195,0,0.35)'}}>
            <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
            I'm at the next stem
          </button>
          <div style={{textAlign:'center',marginTop:8,fontSize:11,color:'rgba(255,255,255,0.55)',fontFamily:"'JetBrains Mono', monospace",letterSpacing:'0.04em'}}>
            DBH ≥ 5 cm only · clockwise N → E → S → W is good practice
          </div>
        </div>
      )}

      {/* Capture sheet */}
      {sheetOpen && draft && (
        <StemSheet
          draft={draft} setDraft={setDraft}
          plotRadius={plot.plotRadiusM}
          onPickSpecies={()=>setPickerOpen(true)}
          onCancel={()=>{ setSheetOpen(false); setDraft(null); }}
          onSaveContinue={()=>save(true)}
          onSaveDone={()=>save(false)}
        />
      )}

      <SpeciesPicker
        open={pickerOpen}
        onClose={()=>setPickerOpen(false)}
        value={draft ? [draft.speciesId] : []}
        dominant={draft?.speciesId}
        onChange={(arr)=>setDraft(d=>({...d, speciesId: arr[arr.length-1] || d.speciesId}))}
        onDominantChange={(id)=>setDraft(d=> id ? ({...d, speciesId:id}) : d)}
        standKind="Tree"
      />

      <style>{`@keyframes pop { 0%{transform:translate(-50%,-50%) scale(.7); opacity:0} 60%{transform:translate(-50%,-50%) scale(1.08); opacity:1} 100%{transform:translate(-50%,-50%) scale(1); opacity:1} }
      @keyframes gpsPulse { 0%,100%{opacity:.55} 50%{opacity:1} }`}</style>
    </div>
  );
}

// Plot map: agent at centre, concentric rings, stems plotted from polar coords
function PlotMap({ plot, stems, highlightLatest }) {
  const cx = 180, cy = 160;
  // Pixels per metre — fit plotRadius into ~120 px
  const scale = 110 / plot.plotRadiusM;

  const polarToXY = (r, theta) => {
    const rad = (theta - 90) * Math.PI / 180;
    return [cx + r * scale * Math.cos(rad), cy + r * scale * Math.sin(rad)];
  };

  return (
    <div style={{position:'absolute',inset:0,background:'radial-gradient(ellipse at center, #1a3d39 0%, #0e1f15 80%)'}}>
      <svg width="100%" height="100%" viewBox="0 0 360 320" preserveAspectRatio="xMidYMid slice">
        {/* Concentric rings */}
        {[1, plot.plotRadiusM*0.33, plot.plotRadiusM*0.66, plot.plotRadiusM].map((r,i)=>(
          <circle key={i} cx={cx} cy={cy} r={r*scale}
            fill={i===3?'rgba(244,195,0,0.04)':'none'}
            stroke="rgba(244,195,0,0.25)" strokeWidth={i===3?1.5:1}
            strokeDasharray={i===3?'5 3':'2 4'}/>
        ))}
        {/* Cardinal labels */}
        <text x={cx} y={cy - plot.plotRadiusM*scale - 8} textAnchor="middle" fontSize="11" fill="rgba(244,195,0,0.7)" fontFamily="'JetBrains Mono', monospace" fontWeight="800">N</text>
        <text x={cx + plot.plotRadiusM*scale + 12} y={cy + 4} textAnchor="middle" fontSize="11" fill="rgba(244,195,0,0.7)" fontFamily="'JetBrains Mono', monospace" fontWeight="800">E</text>
        <text x={cx} y={cy + plot.plotRadiusM*scale + 16} textAnchor="middle" fontSize="11" fill="rgba(244,195,0,0.7)" fontFamily="'JetBrains Mono', monospace" fontWeight="800">S</text>
        <text x={cx - plot.plotRadiusM*scale - 12} y={cy + 4} textAnchor="middle" fontSize="11" fill="rgba(244,195,0,0.7)" fontFamily="'JetBrains Mono', monospace" fontWeight="800">W</text>
        {/* Ring labels */}
        <text x={cx + 3} y={cy - plot.plotRadiusM*0.33*scale - 4} fontSize="8" fill="rgba(244,195,0,0.5)" fontFamily="'JetBrains Mono', monospace">{(plot.plotRadiusM*0.33).toFixed(0)}m</text>
        <text x={cx + 3} y={cy - plot.plotRadiusM*scale + 4} fontSize="8" fill="rgba(244,195,0,0.5)" fontFamily="'JetBrains Mono', monospace">{plot.plotRadiusM}m</text>

        {/* Stems */}
        {stems.map(s => {
          const [x,y] = polarToXY(s.r, s.theta);
          const isLatest = highlightLatest && s.id === highlightLatest.id;
          const isDead = s.status === 'dead';
          const sizeRadius = Math.max(2.5, Math.min(8, (s.dbh||10)/4));
          return (
            <g key={s.id} transform={`translate(${x},${y})`}>
              {isLatest && <circle r={sizeRadius+8} fill="#2BC48A" opacity="0.4"/>}
              <circle r={sizeRadius} fill={isDead?'#6B7280':'#2BC48A'} stroke="rgba(2,28,24,0.7)" strokeWidth="1" opacity={isDead?0.7:1}/>
            </g>
          );
        })}

        {/* Agent (centre) */}
        <g transform={`translate(${cx},${cy})`} style={{animation:'gpsPulse 1.6s infinite'}}>
          <circle r="14" fill="#F4C300" opacity="0.15"/>
          <circle r="8" fill="#F4C300" opacity="0.4"/>
          <circle r="4" fill="#F4C300" stroke="#022C28" strokeWidth="1.5"/>
        </g>

        {/* Compass */}
        <g transform="translate(38,52)">
          <circle r="22" fill="rgba(2,28,24,0.6)" stroke="rgba(244,195,0,0.4)" strokeWidth="1"/>
          <path d="M0,-14 L4,4 L0,1 L-4,4 Z" fill="#F4C300"/>
          <path d="M0,14 L4,-4 L0,-1 L-4,-4 Z" fill="rgba(255,255,255,0.5)"/>
          <text x="0" y="-26" textAnchor="middle" fontSize="9" fill="#F4C300" fontFamily="'JetBrains Mono', monospace" fontWeight="800">N</text>
        </g>
      </svg>
    </div>
  );
}

function StemSheet({ draft, setDraft, plotRadius, onPickSpecies, onCancel, onSaveContinue, onSaveDone }) {
  const species = speciesById(draft.speciesId);
  const inPlot = draft.r <= plotRadius;
  const canSave = !!draft.dbh && parseFloat(draft.dbh) >= 5 && inPlot;
  const dbhNum = parseFloat(draft.dbh) || 0;

  // Quick-input chips for DBH
  const dbhPresets = [8, 12, 16, 20, 28];
  // Tape-around-trunk mode for DBH
  const [dbhMode, setDbhMode] = React.useState(draft.dbhMethod || 'across');
  const [tapeIn, setTapeIn] = React.useState(draft.tapeInput || '');
  const setDbh = (v) => setDraft(d => ({ ...d, dbh: v, dbhMethod:'across' }));
  const setTape = (v) => {
    setTapeIn(v);
    const c = parseFloat(v);
    const dbh = isNaN(c) ? '' : (c / Math.PI).toFixed(1);
    setDraft(d => ({ ...d, dbh, dbhMethod:'around', tapeInput:v }));
  };
  const switchMode = (m) => { setDbhMode(m); setDraft(d=>({ ...d, dbhMethod:m })); };
  // Quadrant ("N", "NE", "E"…) from theta
  const quadrant = (() => {
    const t = draft.theta % 360;
    if (t < 22 || t >= 338) return 'N';
    if (t < 67)   return 'NE';
    if (t < 112)  return 'E';
    if (t < 157)  return 'SE';
    if (t < 202)  return 'S';
    if (t < 247)  return 'SW';
    if (t < 292)  return 'W';
    return 'NW';
  })();

  return (
    <div style={{position:'absolute',left:0,right:0,bottom:0,background:'#fff',borderTopLeftRadius:18,borderTopRightRadius:18,boxShadow:'0 -10px 40px rgba(0,0,0,0.45)',display:'flex',flexDirection:'column',zIndex:10,overflow:'hidden',maxHeight:'78%',animation:'sheetIn .25s ease-out'}}>
      <div style={{padding:'10px 0 4px',display:'flex',justifyContent:'center'}}>
        <div style={{width:42,height:4,borderRadius:2,background:'#D1D5DB'}}/>
      </div>
      <div style={{flex:1, overflowY:'auto', padding:'4px 18px 14px'}}>
        {/* Header: stem ID + position */}
        <div style={{display:'grid',gridTemplateColumns:'auto 1fr',gap:10,alignItems:'stretch',marginBottom:12}}>
          <div style={{background:'#022C28',color:'#fff',borderRadius:12,padding:'10px 12px',display:'flex',flexDirection:'column',justifyContent:'center'}}>
            <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.1em',color:'#2BC48A',fontFamily:"'JetBrains Mono', monospace"}}>STEM</div>
            <div style={{fontSize:16,fontWeight:900,fontFamily:"'JetBrains Mono', monospace",marginTop:2,letterSpacing:'-0.01em'}}>{draft.id}</div>
          </div>
          <div style={{background:'#fff',border:`1px solid ${inPlot?'#D1FAE5':'#FCA5A5'}`,borderRadius:12,padding:'10px 12px'}}>
            <div style={{display:'flex',justifyContent:'space-between',alignItems:'center'}}>
              <div style={{fontSize:9,fontWeight:800,letterSpacing:'0.08em',color: inPlot?'#059669':'#DC2626',fontFamily:"'JetBrains Mono', monospace"}}>
                POSITION · {quadrant}
              </div>
              <div style={{fontSize:9,fontWeight:700,color: inPlot?'#059669':'#DC2626',letterSpacing:'0.04em'}}>{inPlot?'INSIDE PLOT':'OUTSIDE — MOVE'}</div>
            </div>
            <div style={{fontSize:13,fontWeight:800,color:'#022C28',marginTop:4,fontFamily:"'JetBrains Mono', monospace",letterSpacing:'-0.01em'}}>
              {draft.r.toFixed(1)} m · bearing {draft.theta}°
            </div>
          </div>
        </div>

        {/* DBH (primary measurement) */}
        <div style={{marginBottom:14,background:'#fff',border:'1px solid #E5E7EB',borderRadius:12,padding:'14px 16px'}}>
          <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:8}}>
            <div style={{fontSize:11,fontWeight:800,letterSpacing:'0.08em',textTransform:'uppercase',color:'#6B7280'}}>
              {dbhMode==='across' ? 'DBH at 1.3 m' : 'Circumference at 1.3 m'}
            </div>
            <div style={{display:'flex',gap:2,background:'#F3F4F6',borderRadius:6,padding:2}}>
              {[['across','Across'],['around','Tape around']].map(([v,l])=>(
                <button key={v} onClick={()=>switchMode(v)} style={{padding:'4px 9px',background: dbhMode===v?'#022C28':'transparent',color: dbhMode===v?'#fff':'#6B7280',border:'none',borderRadius:4,fontSize:10,fontWeight:800,letterSpacing:'0.04em',cursor:'pointer',fontFamily:'inherit'}}>{l}</button>
              ))}
            </div>
          </div>
          {dbhMode === 'across' ? (
            <div style={{display:'flex',gap:10,alignItems:'flex-end'}}>
              <input value={draft.dbh} onChange={(e)=>setDbh(e.target.value)} inputMode="decimal" placeholder="—" style={{flex:1,padding:'8px 0',background:'transparent',border:'none',borderBottom:'2px solid #022C28',outline:'none',fontSize:32,fontWeight:900,color:'#022C28',fontFamily:"'JetBrains Mono', monospace",letterSpacing:'-0.03em'}}/>
              <div style={{fontSize:14,fontWeight:700,color:'#6B7280',paddingBottom:10}}>cm</div>
            </div>
          ) : (
            <>
              <div style={{display:'flex',gap:10,alignItems:'flex-end'}}>
                <input value={tapeIn} onChange={(e)=>setTape(e.target.value)} inputMode="decimal" placeholder="—" style={{flex:1,padding:'8px 0',background:'transparent',border:'none',borderBottom:'2px solid #022C28',outline:'none',fontSize:32,fontWeight:900,color:'#022C28',fontFamily:"'JetBrains Mono', monospace",letterSpacing:'-0.03em'}}/>
                <div style={{fontSize:14,fontWeight:700,color:'#6B7280',paddingBottom:10}}>cm around</div>
              </div>
              {draft.dbh && <div style={{marginTop:6,fontSize:12,fontWeight:700,color:'#059669',fontFamily:"'JetBrains Mono', monospace"}}>= {draft.dbh} cm DBH (auto)</div>}
            </>
          )}
          {dbhNum>0 && dbhNum<5 && <div style={{marginTop:6,fontSize:10,fontWeight:800,letterSpacing:'0.06em',color:'#DC2626'}}>BELOW 5 CM — RECORD AS REGEN COUNT INSTEAD</div>}
          {dbhMode === 'across' && (
            <div style={{display:'flex',gap:5,marginTop:10}}>
              {dbhPresets.map(d => (
                <button key={d} onClick={()=>setDbh(String(d))} style={{flex:1,padding:'8px 4px',background: String(d)===draft.dbh?'#022C28':'#F9FAFB',color: String(d)===draft.dbh?'#fff':'#022C28',border:`1.5px solid ${String(d)===draft.dbh?'#022C28':'#E5E7EB'}`,borderRadius:8,fontWeight:800,fontSize:13,cursor:'pointer',fontFamily:"'JetBrains Mono', monospace"}}>{d}</button>
              ))}
            </div>
          )}
        </div>

        {/* Species */}
        <div style={{marginBottom:12}}>
          <div style={{fontSize:11,fontWeight:800,letterSpacing:'0.08em',textTransform:'uppercase',color:'#6B7280',marginBottom:6}}>Species</div>
          <button onClick={onPickSpecies} style={{width:'100%',padding:'12px 14px',background:'#F9FAFB',border:'1.5px solid #E5E7EB',borderRadius:10,textAlign:'left',display:'flex',alignItems:'center',gap:10,cursor:'pointer',fontFamily:'inherit'}}>
            <div style={{width:36,height:36,borderRadius:8,background:'#E6FBF3',color:'#059669',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M11 20A7 7 0 0 1 4 13 7 7 0 0 1 11 6h9v3a11 11 0 0 1-9 11z"/><path d="M2 22c0-7 5-12 12-12"/></svg>
            </div>
            <div style={{flex:1,minWidth:0}}>
              <div style={{fontSize:14,fontWeight:800,color:'#022C28',letterSpacing:'-0.01em',display:'flex',alignItems:'center',gap:6}}>
                {species?.common || 'Pick species'}
                {species?.shortlist && <span style={{fontSize:9,fontWeight:800,letterSpacing:'0.06em',padding:'1px 5px',borderRadius:3,background:'#FFF8E0',color:'#B8960A'}}>PROJECT</span>}
              </div>
              <div style={{fontSize:11,color:'#6B7280',fontStyle:'italic',marginTop:1}}>{species?.sci}</div>
            </div>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#6B7280" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 18 15 12 9 6"/></svg>
          </button>
        </div>

        {/* Status + Height */}
        <div style={{display:'flex',gap:8,marginBottom:12}}>
          <div style={{flex:1,background:'#fff',border:'1px solid #E5E7EB',borderRadius:10,padding:'10px 12px'}}>
            <div style={{fontSize:10,fontWeight:800,letterSpacing:'0.08em',color:'#6B7280'}}>STATUS</div>
            <div style={{display:'flex',gap:4,marginTop:6}}>
              {[['live','Live'],['dead','Dead'],['snag','Snag']].map(([v,l])=>(
                <button key={v} onClick={()=>setDraft(d=>({...d, status:v}))} style={{flex:1,padding:'7px 4px',background: draft.status===v?'#022C28':'#fff',color: draft.status===v?'#fff':'#022C28',border:`1.5px solid ${draft.status===v?'#022C28':'#E5E7EB'}`,borderRadius:6,fontWeight:800,fontSize:11,cursor:'pointer',fontFamily:'inherit'}}>{l}</button>
              ))}
            </div>
          </div>
          <div style={{flex:1,background:'#fff',border:'1px solid #E5E7EB',borderRadius:10,padding:'10px 12px'}}>
            <div style={{fontSize:10,fontWeight:800,letterSpacing:'0.08em',color:'#6B7280'}}>HEIGHT (M)</div>
            <input value={draft.height} onChange={(e)=>setDraft(d=>({...d, height: e.target.value}))} inputMode="decimal" placeholder="opt." style={{width:'100%',background:'transparent',border:'none',outline:'none',fontSize:20,fontWeight:900,color:'#022C28',marginTop:2,fontFamily:"'JetBrains Mono', monospace",padding:0,letterSpacing:'-0.02em'}}/>
          </div>
        </div>
      </div>

      <div style={{padding:'10px 14px 14px',borderTop:'1px solid #E5E7EB',background:'#fff',display:'flex',gap:8}}>
        <button onClick={onCancel} style={{padding:'14px',background:'#fff',color:'#022C28',border:'1.5px solid #E5E7EB',borderRadius:10,fontWeight:800,fontSize:13,cursor:'pointer',fontFamily:'inherit',minWidth:80}}>
          Discard
        </button>
        <button onClick={onSaveDone} disabled={!canSave} style={{flex:1,padding:'14px',background:'#fff',color: canSave?'#022C28':'#9CA3AF',border:`1.5px solid ${canSave?'#022C28':'#E5E7EB'}`,borderRadius:10,fontWeight:800,fontSize:13,cursor: canSave?'pointer':'not-allowed',fontFamily:'inherit'}}>
          Save · stop
        </button>
        <button onClick={onSaveContinue} disabled={!canSave} style={{flex:1.4,padding:'14px',background: canSave?'#F4C300':'#E5E7EB',color: canSave?'#022C28':'#9CA3AF',border:'none',borderRadius:10,fontWeight:900,fontSize:14,cursor: canSave?'pointer':'not-allowed',fontFamily:'inherit',letterSpacing:'-0.01em'}}>
          Save · next →
        </button>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────
// PLOT OBSERVATIONS — cover, regen, disturbance, soil
// ─────────────────────────────────────────────────────────
function PlotObsTask({ visit, data, update, onDone }) {
  const [cover, setCover] = React.useState(data.canopyCover || '40-70');
  const [regen, setRegen] = React.useState(data.regenCount || '');
  const [disturb, setDisturb] = React.useState(data.disturbance || 'none');
  const [disturbNote, setDisturbNote] = React.useState(data.disturbanceNote || '');
  const [soil, setSoil] = React.useState(data.soilDepth || 'moderate');
  const [litter, setLitter] = React.useState(data.litterDepth || 'thin');

  const canSave = !!cover && regen !== '';
  const save = () => {
    update({ obsConfirmed:true, canopyCover:cover, regenCount:parseInt(regen)||0, disturbance:disturb, disturbanceNote:disturbNote, soilDepth:soil, litterDepth:litter });
    onDone();
  };

  return (
    <TaskShell ctaLabel="Save observations" onCta={save} disabled={!canSave}>
      <div style={{padding:'14px 16px',background:'#022C28',color:'#fff',borderRadius:12}}>
        <div style={{fontSize:10,fontWeight:800,letterSpacing:'0.1em',color:'#F4C300',fontFamily:"'JetBrains Mono', monospace"}}>PLOT {visit.id.replace('PLT-','')} · OBSERVATIONS</div>
        <div style={{fontSize:13,marginTop:6,color:'rgba(255,255,255,0.8)',lineHeight:1.45}}>Stand at plot centre. Look around the full 360°. These observations scale up via remote sensing.</div>
      </div>

      {/* Canopy cover */}
      <Field label="Canopy cover" hint="Estimate the % of plot covered by tree crowns from above">
        <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:8}}>
          {COVER_CLASSES.map(c => {
            const sel = cover === c.value;
            return (
              <button key={c.value} onClick={()=>setCover(c.value)} style={{padding:'12px',background: sel?'#022C28':'#fff',color: sel?'#fff':'#022C28',border:`1.5px solid ${sel?'#022C28':'#E5E7EB'}`,borderRadius:10,textAlign:'left',cursor:'pointer',fontFamily:'inherit'}}>
                <div style={{fontSize:15,fontWeight:900,letterSpacing:'-0.01em'}}>{c.label}</div>
                <div style={{fontSize:11,color: sel?'rgba(255,255,255,0.7)':'#6B7280',marginTop:3,lineHeight:1.3}}>{c.hint}</div>
              </button>
            );
          })}
        </div>
      </Field>

      {/* Regen count */}
      <Field label="Regeneration count" hint="Count saplings < 1.3 m or DBH < 5 cm inside the plot · estimate is OK">
        <div style={{display:'flex',alignItems:'center',gap:10}}>
          <button onClick={()=>setRegen(r=>String(Math.max(0,(parseInt(r)||0)-1)))} style={{padding:'12px 18px',background:'#F3F4F6',color:'#022C28',border:'none',borderRadius:10,fontWeight:900,fontSize:18,cursor:'pointer',fontFamily:'inherit'}}>−</button>
          <input value={regen} onChange={(e)=>setRegen(e.target.value)} inputMode="numeric" placeholder="0" style={{flex:1,padding:'12px 14px',background:'#F9FAFB',border:'1.5px solid #E5E7EB',borderRadius:10,fontSize:22,fontWeight:900,color:'#022C28',outline:'none',textAlign:'center',fontFamily:"'JetBrains Mono', monospace",letterSpacing:'-0.02em',boxSizing:'border-box'}}/>
          <button onClick={()=>setRegen(r=>String((parseInt(r)||0)+1))} style={{padding:'12px 18px',background:'#F3F4F6',color:'#022C28',border:'none',borderRadius:10,fontWeight:900,fontSize:18,cursor:'pointer',fontFamily:'inherit'}}>+</button>
        </div>
        <div style={{display:'flex',gap:5,marginTop:8}}>
          {[5,10,20,40].map(n => (
            <button key={n} onClick={()=>setRegen(String(n))} style={{flex:1,padding:'6px',background:'#fff',color:'#022C28',border:'1.5px dashed #D1D5DB',borderRadius:6,fontWeight:800,fontSize:12,cursor:'pointer',fontFamily:"'JetBrains Mono', monospace"}}>~{n}</button>
          ))}
        </div>
      </Field>

      {/* Disturbance */}
      <Field label="Disturbance signs">
        <ListPickerInline value={disturb} options={DISTURBANCE_TYPES} onChange={setDisturb}/>
        {disturb !== 'none' && (
          <input value={disturbNote} onChange={(e)=>setDisturbNote(e.target.value)} placeholder="What did you see? (one line)" style={{marginTop:10,width:'100%',padding:'10px 12px',background:'#F9FAFB',border:'1.5px solid #E5E7EB',borderRadius:10,fontSize:13,fontWeight:600,color:'#022C28',outline:'none',boxSizing:'border-box',fontFamily:'inherit'}}/>
        )}
      </Field>

      {/* Soil + litter */}
      <Field label="Soil depth (probe at centre)">
        <ChipPicker value={soil} onChange={setSoil} options={[['shallow','Shallow · <15 cm'],['moderate','Moderate · 15–40 cm'],['deep','Deep · >40 cm']]}/>
      </Field>
      <Field label="Litter / organic layer">
        <ChipPicker value={litter} onChange={setLitter} options={[['none','None'],['thin','Thin · <2 cm'],['thick','Thick · >2 cm']]}/>
      </Field>
    </TaskShell>
  );
}

function ListPickerInline({ value, options, onChange }) {
  return (
    <div style={{display:'flex',flexDirection:'column',gap:6}}>
      {options.map(opt => {
        const sel = value === opt.value;
        return (
          <button key={opt.value} onClick={()=>onChange(opt.value)} style={{padding:'10px 12px',background: sel?'#022C28':'#fff',color: sel?'#fff':'#022C28',border:`1.5px solid ${sel?'#022C28':'#E5E7EB'}`,borderRadius:10,textAlign:'left',display:'flex',alignItems:'center',gap:10,cursor:'pointer',fontFamily:'inherit'}}>
            <div style={{width:18,height:18,borderRadius:'50%',border:`2px solid ${sel?'#F4C300':'#D1D5DB'}`,display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
              {sel && <div style={{width:8,height:8,borderRadius:'50%',background:'#F4C300'}}/>}
            </div>
            <div style={{fontSize:13,fontWeight:700}}>{opt.label}</div>
          </button>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────
// PLOT PHOTOS — shutter capture, cardinals + centre
// ─────────────────────────────────────────────────────────
function PlotPhotosTask({ visit, data, update, onDone, ai }) {
  const [shots, setShots] = React.useState(data.cardinalPhotos || {});
  const cardinals = [
    { id:'N',        label:'Facing North',   sub:'From plot centre, looking due North',  critical:true,  bearing:0,   shortLabel:'N', thumb:'N', hudLabel:'BEARING 0° N' },
    { id:'E',        label:'Facing East',    sub:'From plot centre, looking due East',   critical:true,  bearing:90,  shortLabel:'E', thumb:'E', hudLabel:'BEARING 90° E' },
    { id:'S',        label:'Facing South',   sub:'From plot centre, looking due South',  critical:true,  bearing:180, shortLabel:'S', thumb:'S', hudLabel:'BEARING 180° S' },
    { id:'W',        label:'Facing West',    sub:'From plot centre, looking due West',   critical:true,  bearing:270, shortLabel:'W', thumb:'W', hudLabel:'BEARING 270° W' },
    { id:'centre',   label:'Plot centre',    sub:'Look down · marker pin in shot',       critical:true,                shortLabel:'Centre', thumb:'•' },
    { id:'panorama', label:'Plot panorama',  sub:'Optional · sweep around if helpful',   critical:false,               shortLabel:'Pano',   thumb:'∞' },
  ];
  return (
    <ShutterPhotosBoard
      slots={cardinals}
      value={shots}
      onChange={setShots}
      onCancel={onDone}
      onDone={()=>{ update({ cardinalsConfirmed:true, cardinalPhotos:shots }); onDone(); }}
      renderScene={(active) => <PlotPhotoScene active={active}/>}
      ai={ai}
    />
  );
}

// Bearing-aware scene for cardinal photos
function PlotPhotoScene({ active }) {
  // Different stylised view per bearing
  const palettes = {
    0:   { sky:'#2c3a26', ground:'#0e1f15', trees:[[60,400],[140,420],[230,400],[310,410]] },
    90:  { sky:'#3a3220', ground:'#1a1410', trees:[[40,420],[120,410],[220,425],[300,415]] },
    180: { sky:'#1c2826', ground:'#0a1810', trees:[[80,430],[170,420],[270,425]] },
    270: { sky:'#352c1c', ground:'#1a140a', trees:[[50,410],[150,425],[250,415],[330,420]] },
  };
  const p = palettes[active.bearing] || palettes[0];
  return (
    <svg width="100%" height="100%" viewBox="0 0 360 600" preserveAspectRatio="xMidYMid slice" style={{position:'absolute',inset:0}}>
      <rect width="360" height="280" fill={p.sky}/>
      <rect y="280" width="360" height="320" fill={p.ground}/>
      {p.trees.map(([x,y],i)=>(
        <g key={i}>
          <rect x={x-3} y={y} width="6" height="120" fill="#3a2818"/>
          <ellipse cx={x} cy={y-30} rx="38" ry="48" fill="rgba(43,196,138,0.55)"/>
          <ellipse cx={x-14} cy={y-52} rx="26" ry="32" fill="rgba(43,196,138,0.4)"/>
        </g>
      ))}
      {/* horizon */}
      <path d="M0 360 Q 180 350 360 358" stroke="rgba(255,255,255,0.05)" strokeWidth="1" fill="none"/>
      {/* Compass needle overlay if bearing-specific */}
      {active.bearing != null && (
        <g transform="translate(310,80)">
          <circle r="28" fill="rgba(2,28,24,0.7)" stroke="rgba(244,195,0,0.5)" strokeWidth="1.5"/>
          <g transform={`rotate(${active.bearing})`}>
            <path d="M0,-18 L5,5 L0,2 L-5,5 Z" fill="#F4C300"/>
            <path d="M0,18 L5,-5 L0,-2 L-5,-5 Z" fill="rgba(255,255,255,0.5)"/>
          </g>
          <text x="0" y="-32" textAnchor="middle" fontSize="11" fill="#F4C300" fontFamily="'JetBrains Mono', monospace" fontWeight="900">{active.shortLabel}</text>
        </g>
      )}
    </svg>
  );
}

// ─────────────────────────────────────────────────────────
// PLOT REVIEW — readiness, sign, submit
// ─────────────────────────────────────────────────────────
function PlotReviewTask({ visit, data, stems, onSubmit }) {
  const stemCount = stems.length;
  const speciesCount = new Set(stems.map(s=>s.species)).size;
  const items = [
    { ok:!!data.plotLocated,        label:'Plot centre confirmed',  val: data.plotLocated ? `0.17213, 34.02181 · ±${data.plotCentreAcc?.toFixed?.(1) || '3.4'} m` : 'Missing' },
    { ok: stemCount > 0 && !!data.inventoryConfirmed, label:'Plot inventory',         val: stemCount>0 ? `${stemCount} stems · ${speciesCount} species` : 'Not started' },
    { ok:!!data.obsConfirmed,       label:'Observations',           val: data.obsConfirmed ? `${data.canopyCover}% cover · ${data.regenCount} regen · ${data.disturbance}` : 'Missing' },
    { ok:!!data.cardinalsConfirmed, label:'Cardinal photos',        val: data.cardinalsConfirmed ? `${Object.values(data.cardinalPhotos||{}).filter(Boolean).length} photos` : 'Missing' },
  ];
  const allGood = items.every(i => i.ok);

  return (
    <TaskShell ctaLabel={allGood ? 'Submit plot · sign locally' : `Fix ${items.filter(i=>!i.ok).length} task${items.filter(i=>!i.ok).length>1?'s':''}`} onCta={allGood?onSubmit:()=>{}} disabled={!allGood} hint={allGood ? 'Hashed and signed on this device. Syncs on Wi‑Fi. Anchors to Hedera.' : 'Open the brief to finish remaining tasks.'}>
      {/* Readiness ring */}
      <div style={{background:'#022C28',color:'#fff',borderRadius:14,padding:'18px',display:'flex',alignItems:'center',gap:16}}>
        <div style={{position:'relative',width:72,height:72,flexShrink:0}}>
          <svg width="72" height="72" viewBox="0 0 72 72">
            <circle cx="36" cy="36" r="30" fill="none" stroke="rgba(255,255,255,0.12)" strokeWidth="6"/>
            <circle cx="36" cy="36" r="30" fill="none" stroke={allGood?'#2BC48A':'#F4C300'} strokeWidth="6" strokeDasharray={`${(items.filter(i=>i.ok).length/items.length)*188.5} 188.5`} strokeLinecap="round" transform="rotate(-90 36 36)"/>
          </svg>
          <div style={{position:'absolute',inset:0,display:'flex',alignItems:'center',justifyContent:'center',fontSize:18,fontWeight:900,color:allGood?'#2BC48A':'#F4C300',letterSpacing:'-0.02em'}}>{Math.round((items.filter(i=>i.ok).length/items.length)*100)}%</div>
        </div>
        <div style={{flex:1,minWidth:0}}>
          <div style={{fontSize:10,fontWeight:800,letterSpacing:'0.1em',color:'#F4C300',fontFamily:"'JetBrains Mono', monospace"}}>READINESS · {visit.id}</div>
          <div style={{fontSize:16,fontWeight:900,letterSpacing:'-0.01em',marginTop:3,lineHeight:1.25}}>{allGood ? 'Plot ready to submit' : 'Almost there'}</div>
          <div style={{fontSize:12,color:'rgba(255,255,255,0.7)',marginTop:3}}>{allGood ? 'Plot data joins the stratum estimate.' : `${items.filter(i=>!i.ok).length} required task${items.filter(i=>!i.ok).length>1?'s':''} open.`}</div>
        </div>
      </div>

      {/* Plot summary cards */}
      <div style={{display:'grid',gridTemplateColumns:'1fr 1fr 1fr',gap:8}}>
        <KPI label="Stems" value={stemCount} color="#022C28"/>
        <KPI label="Species" value={speciesCount} color="#059669"/>
        <KPI label="Mean DBH" value={stemCount ? (stems.reduce((s,t)=>s+(t.dbh||0),0)/stemCount).toFixed(1) : '—'} color="#022C28"/>
      </div>

      {/* Task readiness list */}
      <div style={{background:'#fff',border:'1px solid #E5E7EB',borderRadius:12,overflow:'hidden'}}>
        {items.map((it,i)=>(
          <div key={i} style={{display:'flex',gap:10,padding:'12px 14px',borderBottom: i<items.length-1?'1px solid #F3F4F6':'none',alignItems:'center'}}>
            <div style={{width:24,height:24,borderRadius:'50%',background: it.ok?'#059669':'#DC2626',color:'#fff',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
              {it.ok ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
                     : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3"><line x1="6" y1="6" x2="18" y2="18"/><line x1="6" y1="18" x2="18" y2="6"/></svg>}
            </div>
            <div style={{flex:1,minWidth:0}}>
              <div style={{fontSize:13,fontWeight:800,color:'#022C28'}}>{it.label}</div>
              <div style={{fontSize:11,color:'#6B7280',marginTop:2}}>{it.val}</div>
            </div>
          </div>
        ))}
      </div>

      {/* Transparency footer */}
      <div style={{background:'#F5F0FF',border:'1px solid #DDD6FE',borderRadius:10,padding:'12px 14px'}}>
        <div style={{fontSize:10,fontWeight:800,letterSpacing:'0.08em',color:'#5B21B6',fontFamily:"'JetBrains Mono', monospace"}}>TRANSPARENCY · SIGNED LOCALLY</div>
        <div style={{display:'flex',justifyContent:'space-between',fontSize:11,color:'#5B21B6',marginTop:6,fontFamily:"'JetBrains Mono', monospace"}}><span>Agent</span><span>0042 · Mary Wanjiru</span></div>
        <div style={{display:'flex',justifyContent:'space-between',fontSize:11,color:'#5B21B6',marginTop:2,fontFamily:"'JetBrains Mono', monospace"}}><span>Plot</span><span>{visit.id} · stratum {visit.stratum}</span></div>
        <div style={{display:'flex',justifyContent:'space-between',fontSize:11,color:'#5B21B6',marginTop:2,fontFamily:"'JetBrains Mono', monospace"}}><span>SHA-256</span><span>4a7e…91c2</span></div>
        <div style={{display:'flex',justifyContent:'space-between',fontSize:11,color:'#5B21B6',marginTop:2,fontFamily:"'JetBrains Mono', monospace"}}><span>Hedera</span><span>queued · anchors on sync</span></div>
      </div>

      {/* What we send to verifiers — Verra payload preview (area variant) */}
      <PlotVerraPayloadPreview visit={visit} data={data} stems={stems}/>
    </TaskShell>
  );
}

function PlotVerraPayloadPreview({ visit, data, stems }) {
  const live = stems.filter(s => s.status !== 'dead');
  const ba = live.reduce((s,t) => s + Math.PI * Math.pow((t.dbh||0)/2, 2), 0) / 10000;
  const tph = visit.plotAreaM2 ? Math.round(live.length / visit.plotAreaM2 * 10000) : 0;
  const speciesCount = new Set(live.map(s => s.species)).size;
  const meanDbh = live.length ? (live.reduce((s,t)=>s+(t.dbh||0),0)/live.length).toFixed(1) : '—';
  const photoCount = Object.values(data.cardinalPhotos || {}).filter(Boolean).length;

  return (
    <div style={{background:'#fff',border:'1.5px solid #022C28',borderRadius:12,overflow:'hidden'}}>
      <div style={{padding:'12px 14px',background:'#022C28',color:'#fff',display:'flex',alignItems:'center',gap:10}}>
        <div style={{width:26,height:26,borderRadius:6,background:'#F4C300',color:'#022C28',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
          <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
        </div>
        <div style={{flex:1,minWidth:0}}>
          <div style={{fontSize:10,fontWeight:800,letterSpacing:'0.1em',color:'#F4C300',fontFamily:"'JetBrains Mono', monospace"}}>WHAT WE SEND TO VERIFIERS</div>
          <div style={{fontSize:13,fontWeight:800,letterSpacing:'-0.01em',marginTop:1}}>Verra VM0047 v1.1 · plot inventory package</div>
        </div>
      </div>
      <div style={{padding:'4px 0'}}>
        {[
          { l:'Plot',           v:`${visit.id} · ${visit.plotShape} · r ${visit.plotRadiusM} m` },
          { l:'Project',        v:visit.project },
          { l:'Stratum',        v:`${visit.stratum} · ${visit.stratumName} · ${visit.stratumAreaHa} ha` },
          { l:'Stems inventoried', v:`${live.length} live`, bold:true },
          { l:'Species',        v:`${speciesCount} unique` },
          { l:'Mean DBH',       v:`${meanDbh} cm` },
          { l:'Basal area',     v:`${ba.toFixed(3)} m²` },
          { l:'Extrapolated TPH', v:`${tph.toLocaleString()} stems/ha` },
          { l:'Photos attached',v:`${photoCount} cardinals` },
          { l:'GPS quality',    v:`±${data.plotCentreAcc?.toFixed?.(1) || '3.4'} m · WGS84` },
          { l:'Signed',         v:'SHA-256 locally · Hedera on sync' },
        ].map((row,i,a) => (
          <div key={i} style={{padding:'9px 14px',borderBottom: i<a.length-1 ? '1px solid #F3F4F6' : 'none',display:'flex',justifyContent:'space-between',alignItems:'flex-start',gap:10}}>
            <div style={{fontSize:11,fontWeight:700,color:'#6B7280',flexShrink:0,minWidth:110}}>{row.l}</div>
            <div style={{textAlign:'right',minWidth:0,flex:1,fontSize:12.5,fontWeight: row.bold?900:700,color:'#022C28',letterSpacing:'-0.01em',wordBreak:'break-word',fontFamily: row.bold ? "'JetBrains Mono', monospace" : 'inherit'}}>{row.v}</div>
          </div>
        ))}
      </div>
      <div style={{padding:'10px 14px',background:'#F6F8F7',fontSize:11,color:'#6B7280',lineHeight:1.5}}>
        This is exactly what the verifier (VVB) and Verra receive for this plot after sync. Plot data scales up to the stratum estimate via remote sensing.
      </div>
    </div>
  );
}

Object.assign(window, {
  AreaPlotBrief, PlotLocateTask, PlotInventory, PlotObsTask, PlotPhotosTask, PlotReviewTask
});
