// Scene components for the B2B scroll page (For Owners).
// Each scene renders the phone screen state plus optional desktop overlay.

// Step copy is generated from the active service so every label references their trade.
function buildOwnerSteps(cfg) {
  const trade = cfg.name;
  const mode = cfg.measureMode || 'satellite';
  const measureStep = (function() {
    if (mode === 'records') {
      return { id:'satellite', eyebrow:'02 · Pull records', title:<>Pulled <span className="serif-it" style={{color:'var(--lilac-600)'}}>before</span><br/>they call.</>, body:`County records, MLS, prior permits — pre-loaded for every ${trade.toLowerCase()} lead. ${cfg.atlas.label}: ${cfg.atlas.value}. Your estimator opens with context, not questions.` };
    }
    if (mode === 'dispatch') {
      return { id:'satellite', eyebrow:'02 · Closest crew', title:<>Live <span className="serif-it" style={{color:'var(--lilac-600)'}}>radar</span>.<br/>Fastest route.</>, body:`Emergency intake fires the dispatch board. Crews, trucks, and traffic on one screen. Closest qualified tech is routed before the homeowner hangs up.` };
    }
    if (mode === 'photos') {
      return { id:'satellite', eyebrow:'02 · From their photos', title:<>Their phone.<br/>Your <span className="serif-it" style={{color:'var(--lilac-600)'}}>scope.</span></>, body:`Customer texts photos before the truck rolls. The system tags every item on the list and produces a scope sheet your tech can quote without a site visit.` };
    }
    if (mode === 'claim') {
      return { id:'satellite', eyebrow:'02 · Claim + weather', title:<>The claim<br/><span className="serif-it" style={{color:'var(--lilac-600)'}}>cross-checked.</span></>, body:`Carrier data, claim status, and the weather event that caused the loss — loaded automatically. You walk in knowing what they're entitled to and what the adjuster will fight.` };
    }
    return { id:'satellite', eyebrow:'02 · Measure', title:<>From <span className="serif-it" style={{color:'var(--lilac-600)'}}>space</span>,<br/>in seconds.</>, body:`The system pulls fresh satellite imagery and measures ${cfg.atlas.label.toLowerCase()} for ${trade} jobs. ${cfg.atlas.value} captured before your truck leaves the lot.` };
  })();
  return [
    { id:'configured', eyebrow:'01 · Configured', title:<>Engine set for<br/><span className="serif-it" style={{color:'var(--lilac-600)'}}>{trade}.</span></>, body:`Pricing rules, custom fields, AR tags, and lead qualifiers just repointed to ${trade}. Same engine — your shape.` },
    measureStep,
    { id:'ar', eyebrow:'03 · Walk it', title:<>Or let the<br/>homeowner do it.</>, body:`Send a link. They walk the property with their phone — AR snaps lines, tags ${trade.toLowerCase()} features, and the engine prices everything as they move.` },
    { id:'fields', eyebrow:'04 · Your form', title:<>Your fields.<br/>Your <span className="serif-it" style={{color:'var(--lilac-600)'}}>pricing.</span></>, body:`These are the fields ${trade} estimators actually care about. Drag, drop, set rules. Margins stay yours.` },
    { id:'qualify', eyebrow:'05 · Sort leads', title:<>Leads come<br/>pre-qualified.</>, body:`The chat runs the intake with questions that matter for ${trade.toLowerCase()}. Budget, timeline, decision maker, urgency. A live score climbs cold to ready-to-buy.` },
    { id:'estimate', eyebrow:'06 · Send it', title:<>Sixty seconds<br/>to <span className="serif-it" style={{color:'var(--lilac-600)'}}>signed.</span></>, body:`Line items, materials, labor, tax, deposit — priced against live ${trade.toLowerCase()} data. A signature line and a Stripe button. Your competition is still driving to the property.` },
    { id:'stack', eyebrow:'07 · Plug in', title:<>Sits on top<br/>of your stack.</>, body:`It doesn't replace your tools — it runs them. Each ${trade} quote flows into your CRM, the calendar books the install, dispatch hands it to a crew, payroll closes the loop.` },
  ];
}

/* ============== INDUSTRY SCENE ============== */
const OWNER_INDUSTRIES = [
  { id:'roofing', name:'Roofing' },
  { id:'hvac', name:'HVAC' },
  { id:'solar', name:'Solar' },
  { id:'plumbing', name:'Plumbing' },
  { id:'electrical', name:'Electrical' },
  { id:'pool', name:'Pool' },
  { id:'tree', name:'Tree' },
  { id:'paint', name:'Paint' },
  { id:'fence', name:'Fence' },
  { id:'concrete', name:'Concrete' },
  { id:'pest', name:'Pest' },
  { id:'landscape', name:'Landscape' },
];

function SceneConfigured({ progress, config, onSwitch }) {
  // Show the configured trade as a confirmation tile + a list of related trades that share the engine.
  // Pulses through the configuration steps (form, pricing, agents, AR map).
  const cfg = config || { name:'No trade picked', catLabel:'Pick one', fields:[], arTags:[], qualifyChecks:[], atlas:{ label:'—' } };
  const items = [
    { label:'Custom fields', value:`${(cfg.fields||[]).length} fields`, done: progress > 0.05 },
    { label:'Pricing rules', value: config ? 'Loaded' : 'Waiting',       done: progress > 0.20 },
    { label:'AR feature map',value:`${(cfg.arTags||[]).length} tags`,    done: progress > 0.40 },
    { label:'Qualifier chat',value:`${(cfg.qualifyChecks||[]).length} checks`, done: progress > 0.60 },
    { label:'Satellite target',  value: cfg.atlas?.label || '—',              done: progress > 0.80 },
  ];
  return (
    <div>
      <div style={{ fontSize:10, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.14em', textTransform:'uppercase' }}>Estimator · trade configured</div>
      <div style={{ marginTop:6, padding:'14px 14px', borderRadius:14, background:'var(--ink)', color:'#fff', position:'relative', overflow:'hidden' }}>
        <div style={{ position:'absolute', top:-30, right:-30, width:140, height:140, borderRadius:'50%', background:'var(--chart-300)', opacity:.15, filter:'blur(20px)' }}/>
        <div style={{ position:'relative' }}>
          <div style={{ fontSize:9, fontWeight:700, letterSpacing:'0.14em', color:'var(--chart-300)' }}>{(cfg.catLabel||'').toUpperCase()}</div>
          <div className="display" style={{ fontSize:24, fontWeight:600, letterSpacing:'-0.025em', lineHeight:1.05, marginTop:3 }}>{cfg.name}</div>
          <div style={{ fontSize:10.5, color:'rgba(255,255,255,0.6)', marginTop:4 }}>Engine repointed · ready to estimate</div>
          {onSwitch && (
            <button onClick={onSwitch} style={{ marginTop:10, background:'rgba(255,255,255,0.08)', border:'1px solid rgba(255,255,255,0.18)', color:'#fff', padding:'5px 11px', borderRadius:99, fontSize:10, fontFamily:'var(--font-body)', fontWeight:600, cursor:'pointer' }}>Switch trade →</button>
          )}
        </div>
      </div>
      <div style={{ marginTop:12, display:'flex', flexDirection:'column', gap:5 }}>
        {items.map((it, i) => (
          <div key={i} style={{ display:'flex', alignItems:'center', gap:9, padding:'8px 10px', background: it.done ? 'var(--chart-100)' : 'var(--paper-3)', borderRadius:9, transition:'all 0.3s' }}>
            <span style={{ width:16, height:16, borderRadius:99, background: it.done? 'var(--chart-300)' : 'var(--mute-3)', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
              {it.done && <IconCheck size={10} stroke="var(--ink)" sw={2.5}/>}
            </span>
            <span style={{ flex:1, fontSize:11.5, fontWeight:600, color: it.done? 'var(--ink)' : 'var(--mute-2)' }}>{it.label}</span>
            <span style={{ fontSize:10, fontFamily:'var(--font-mono)', color:'var(--mute-1)' }}>{it.value}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

function IndustryGlyph({ id, size=20 }) {
  const c = 'currentColor';
  const w = size, h = size;
  const paths = {
    roofing:    <><path d="M2 12 12 3l10 9"/><path d="M5 11v9h14v-9"/></>,
    hvac:       <><circle cx="12" cy="12" r="3"/><path d="M12 3v6M12 15v6M3 12h6M15 12h6"/></>,
    solar:      <><rect x="3" y="7" width="18" height="11" rx="1"/><path d="M3 11h18M9 7v11M15 7v11"/></>,
    plumbing:   <><path d="M5 4v5a3 3 0 0 0 3 3h4a3 3 0 0 1 3 3v5"/><path d="M3 4h4M19 7l2-2-3-3-2 2z"/></>,
    electrical: <path d="M13 2 4 14h7l-1 8 10-12h-7z"/>,
    pool:       <><path d="M3 18c2 0 2-2 4-2s2 2 4 2 2-2 4-2 2 2 4 2"/><path d="M7 14V5a2 2 0 0 1 4 0M13 14V5a2 2 0 0 1 4 0"/></>,
    tree:       <><path d="M12 3a5 5 0 0 1 5 7 4 4 0 0 1-3 7h-4a4 4 0 0 1-3-7 5 5 0 0 1 5-7z"/><path d="M12 17v5"/></>,
    paint:      <><path d="M4 5h13v5H4z"/><path d="M10 10v4a2 2 0 0 0 2 2h2v4h-3v-4"/></>,
    fence:      <><path d="M3 21V8l3-3 3 3v13M9 21V8l3-3 3 3v13M15 21V8l3-3 3 3v13"/><path d="M3 13h18M3 17h18"/></>,
    concrete:   <><rect x="3" y="10" width="18" height="8" rx="1"/><path d="M6 18v3M18 18v3M5 14h2M11 14h2M17 14h2"/></>,
    pest:       <><ellipse cx="12" cy="14" rx="5" ry="6"/><path d="M9 9 7 6M15 9l2-3M7 14H4M17 14h3"/></>,
    landscape:  <><path d="M3 20h18"/><path d="M6 20c0-3 2-5 5-5M13 20c0-2 2-4 5-4"/><circle cx="11" cy="9" r="3"/></>,
  };
  return (
    <svg width={w} height={h} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      {paths[id] || paths.roofing}
    </svg>
  );
}

/* ============== MEASURE SCENE — dispatches by measureMode ============== */
function SceneSatellite({ progress, config }) {
  const mode = (config && config.measureMode) || 'satellite';
  if (mode === 'records')  return <SceneRecords  progress={progress} config={config}/>;
  if (mode === 'dispatch') return <SceneDispatch progress={progress} config={config}/>;
  if (mode === 'photos')   return <ScenePhotos   progress={progress} config={config}/>;
  if (mode === 'claim')    return <SceneClaim    progress={progress} config={config}/>;
  return <SceneSatelliteCore progress={progress} config={config}/>;
}

/* ============== ACTUAL SATELLITE (default) ============== */
function SceneSatelliteCore({ progress, config }) {
  const atlas = (config && config.atlas) || { label:'Roof', value:'2,418 sq ft', detail:'6/12 pitch' };
  const detailParts = (atlas.detail || '').split(' · ');
  // 0..0.4 = zoom in from earth, 0.4..1 = draw the roof outline
  const zoom = Math.min(1, progress / 0.5);
  const draw = Math.min(1, Math.max(0, (progress - 0.35) / 0.5));
  return (
    <div>
      <div style={{ fontSize:10, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.14em', textTransform:'uppercase' }}>Satellite · {atlas.label.toLowerCase()}</div>
      <div className="display" style={{ fontSize:20, fontWeight:600, letterSpacing:'-0.03em', marginTop:4 }}>1421 Pine St</div>
      <div style={{ position:'relative', marginTop:12, borderRadius:18, overflow:'hidden', height:240,
        background:'linear-gradient(180deg, #0a0d12 0%, #1a2030 100%)' }}>
        {/* earth curve */}
        <div style={{ position:'absolute', inset:0, transition:'transform 0.6s', transform:`scale(${1 + zoom * 6}) translateY(${zoom * 30}%)` }}>
          <svg viewBox="0 0 280 240" width="100%" height="100%" preserveAspectRatio="xMidYMid slice">
            <defs>
              <radialGradient id="earth" cx="50%" cy="40%" r="70%">
                <stop offset="0%" stopColor="#5b8c5a"/>
                <stop offset="60%" stopColor="#2d5a47"/>
                <stop offset="100%" stopColor="#0a1a18"/>
              </radialGradient>
            </defs>
            <circle cx="140" cy="220" r="200" fill="url(#earth)"/>
            <ellipse cx="80" cy="160" rx="22" ry="8" fill="#7a9d6f" opacity=".6"/>
            <ellipse cx="150" cy="190" rx="30" ry="10" fill="#8aae7f" opacity=".5"/>
            <ellipse cx="220" cy="140" rx="18" ry="6" fill="#7a9d6f" opacity=".6"/>
          </svg>
        </div>
        {/* satellite */}
        {zoom < 0.6 && (
          <div style={{ position:'absolute', top: 30 - zoom*40, right: 30 + zoom*30, opacity: 1 - zoom*1.5 }}>
            <svg width="44" height="22" viewBox="0 0 60 30" fill="none">
              <rect x="22" y="11" width="16" height="8" rx="1" fill="#c0c4cc"/>
              <rect x="2" y="7" width="18" height="16" rx="1" fill="var(--chart-300)" stroke="#fff" strokeOpacity=".4"/>
              <rect x="40" y="7" width="18" height="16" rx="1" fill="var(--chart-300)" stroke="#fff" strokeOpacity=".4"/>
              <path d="M22 7v-4M38 23v4" stroke="#fff" strokeOpacity=".5"/>
            </svg>
          </div>
        )}
        {/* roof outline appears */}
        {zoom > 0.5 && (
          <svg viewBox="0 0 280 240" style={{ position:'absolute', inset:0, width:'100%', height:'100%' }}>
            <polygon points="60,90 140,50 220,90 220,170 60,170"
              fill="rgba(196,240,0,0.08)"
              stroke="var(--chart-300)" strokeWidth="2"
              strokeDasharray="600"
              strokeDashoffset={600 - draw * 600}
              style={{ filter:'drop-shadow(0 0 8px rgba(196,240,0,.5))' }}/>
            <line x1="140" y1="50" x2="140" y2="170" stroke="var(--chart-300)" strokeWidth="1" strokeDasharray="3 3" opacity={draw}/>
            {/* corner dots */}
            {[[60,90],[140,50],[220,90],[220,170],[60,170]].map(([x,y],i)=>(
              <circle key={i} cx={x} cy={y} r="3" fill="var(--chart-300)" opacity={draw > i*0.18 ? 1 : 0}/>
            ))}
          </svg>
        )}
        {/* measurement chips */}
        {draw > 0.5 && (
          <>
            <div style={{ position:'absolute', top: 60, left: 90, background:'var(--ink)', color:'var(--chart-300)', padding:'3px 8px', borderRadius:6, fontSize:10, fontWeight:700, fontFamily:'var(--font-mono)', opacity: Math.min(1, (draw-0.5)*4) }}>{atlas.value}</div>
            {detailParts[0] && (
              <div style={{ position:'absolute', top: 130, right: 26, background:'var(--ink)', color:'#fff', padding:'3px 8px', borderRadius:6, fontSize:10, fontWeight:600, opacity: Math.min(1, (draw-0.6)*4) }}>{detailParts[0]}</div>
            )}
            {detailParts[1] && (
              <div style={{ position:'absolute', bottom: 16, left: 86, background:'var(--ink)', color:'#fff', padding:'3px 8px', borderRadius:6, fontSize:10, fontWeight:600, opacity: Math.min(1, (draw-0.7)*4) }}>{detailParts[1]}</div>
            )}
          </>
        )}
        {/* AI badge */}
        <div style={{ position:'absolute', top:12, left:12, background:'rgba(12,14,16,0.7)', backdropFilter:'blur(8px)', color:'#fff', padding:'5px 10px', borderRadius:99, fontSize:10, fontWeight:600, letterSpacing:'0.06em', display:'flex', alignItems:'center', gap:6 }}>
          <span style={{ width:6, height:6, borderRadius:99, background:'var(--chart-300)' }} className="pulse-soft"/>LIVE
        </div>
      </div>
      <div style={{ marginTop:10, display:'grid', gridTemplateColumns:'1fr 1fr', gap:6 }}>
        {[[atlas.label, atlas.value],['Detail', atlas.detail || '—']].map(([l,v],i)=>(
          <div key={i} style={{ background:'var(--paper-3)', borderRadius:10, padding:'8px 10px' }}>
            <div style={{ fontSize:9, color:'var(--mute-1)', letterSpacing:'0.1em', textTransform:'uppercase' }}>{l}</div>
            <div style={{ fontFamily:'var(--font-display)', fontSize:15, fontWeight:600, marginTop:1 }}>{v}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ============== RECORDS — property records lookup (cleaning, remodel, inspect, specialty) ============== */
function SceneRecords({ progress, config }) {
  const p = Math.min(1, Math.max(0, progress * 1.15));
  // Cards stream in as the AI pulls data sources
  const sources = [
    { src:'County records',  label:'Year built',   value:'1968',           done: p > 0.10 },
    { src:'MLS · last sale', label:'Sq ft · beds', value:'2,400 · 4/2.5',  done: p > 0.25 },
    { src:'Permit DB',       label:'Last permit',  value:'HVAC · 2018',    done: p > 0.45 },
    { src:'AVM',             label:'Property value',value:'$680k',         done: p > 0.65 },
    { src:'Tax assessor',    label:'Lot · zone',   value:'7,840 sf · R-1', done: p > 0.85 },
  ];
  return (
    <div>
      <div style={{ fontSize:10, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.14em', textTransform:'uppercase' }}>Records · property lookup</div>
      <div className="display" style={{ fontSize:20, fontWeight:600, letterSpacing:'-0.03em', marginTop:4 }}>1421 Pine St</div>
      {/* Animated streaming visual */}
      <div style={{ position:'relative', marginTop:12, borderRadius:14, overflow:'hidden', height:160, background:'linear-gradient(180deg, var(--lilac-50) 0%, #fff 100%)', border:'1px solid var(--line-2)' }}>
        {/* center "address" node */}
        <div style={{ position:'absolute', left:'50%', top:'50%', transform:'translate(-50%,-50%)', zIndex:5 }}>
          <div style={{ width:60, height:60, borderRadius:14, background:'var(--ink)', color:'var(--chart-300)', display:'flex', alignItems:'center', justifyContent:'center', boxShadow:'0 0 0 5px rgba(196,240,0,0.18)' }}>
            <IconHome size={26} stroke="var(--chart-300)" sw={2}/>
          </div>
        </div>
        {/* Streaming lines from outside in */}
        <svg viewBox="0 0 280 160" style={{ position:'absolute', inset:0, width:'100%', height:'100%' }}>
          {[
            { x:30, y:30 }, { x:250, y:30 }, { x:20, y:80 }, { x:260, y:80 }, { x:60, y:140 }, { x:220, y:140 },
          ].map((pt, i) => (
            <line key={i} x1={pt.x} y1={pt.y} x2="140" y2="80"
              stroke="var(--lilac-400)" strokeWidth="1.3"
              strokeDasharray="120"
              strokeDashoffset={120 - Math.min(1, Math.max(0, p * 1.4 - i*0.12)) * 120}
              style={{ transition:'stroke-dashoffset 0.4s' }}/>
          ))}
        </svg>
        {/* Source label chips */}
        {[
          { left:'8%',  top:'18%', label:'COUNTY',  i:0 },
          { left:'78%', top:'18%', label:'MLS',     i:1 },
          { left:'4%',  top:'48%', label:'PERMITS', i:2 },
          { left:'82%', top:'48%', label:'AVM',     i:3 },
          { left:'18%', top:'82%', label:'TAX',     i:4 },
          { left:'70%', top:'82%', label:'NOAA',    i:5 },
        ].map((c, i) => (
          <div key={i} style={{ position:'absolute', left:c.left, top:c.top, transform:'translate(-50%,-50%)',
            background:'#fff', border:'1px solid var(--lilac-200)', padding:'2px 6px', borderRadius:5,
            fontSize:8.5, fontWeight:700, fontFamily:'var(--font-mono)', color:'var(--lilac-700)', letterSpacing:'0.05em',
            opacity: p > c.i * 0.12 ? 1 : 0.3, transition:'opacity 0.4s' }}>{c.label}</div>
        ))}
        <div style={{ position:'absolute', top:10, left:12, fontSize:9, color:'var(--lilac-700)', fontWeight:600, letterSpacing:'0.1em', textTransform:'uppercase', display:'flex', alignItems:'center', gap:6 }}>
          <span style={{ width:5, height:5, borderRadius:99, background:'var(--lilac-500)' }} className="pulse-soft"/>{Math.round(p*100)}% loaded
        </div>
      </div>
      {/* Records list */}
      <div style={{ marginTop:10, display:'flex', flexDirection:'column', gap:4 }}>
        {sources.map((s, i) => (
          <div key={i} style={{ display:'flex', alignItems:'center', gap:9, padding:'7px 10px', background: s.done ? 'var(--paper-3)' : '#fff', borderRadius:8, border:'1px solid var(--line-2)', transition:'background 0.3s' }}>
            <span style={{ width:14, height:14, borderRadius:99, background: s.done? 'var(--chart-300)' : 'var(--paper-3)', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
              {s.done && <IconCheck size={9} stroke="var(--ink)" sw={2.5}/>}
            </span>
            <span style={{ fontSize:9, fontFamily:'var(--font-mono)', color:'var(--mute-2)', letterSpacing:'0.06em', minWidth:60 }}>{s.src}</span>
            <span style={{ flex:1, fontSize:11, color: s.done? 'var(--mute-1)' : 'var(--mute-2)' }}>{s.label}</span>
            <span style={{ fontSize:11, fontWeight:600, color: s.done? 'var(--ink)' : 'var(--mute-2)' }}>{s.value}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ============== DISPATCH — emergency live crew radar ============== */
function SceneDispatch({ progress, config }) {
  const p = Math.min(1, Math.max(0, progress * 1.1));
  const eta = Math.max(8, Math.round(38 - p * 30));
  const crews = [
    { x:'30%', y:'30%', name:'Marcus R.', eta:'8 min',  van:'V-04', sel:true,  show: p > 0.10 },
    { x:'72%', y:'24%', name:'Jenna L.',  eta:'19 min', van:'V-11', sel:false, show: p > 0.25 },
    { x:'22%', y:'72%', name:'Drew P.',   eta:'24 min', van:'V-08', sel:false, show: p > 0.40 },
    { x:'78%', y:'68%', name:'Sam K.',    eta:'31 min', van:'V-02', sel:false, show: p > 0.55 },
  ];
  return (
    <div>
      <div style={{ fontSize:10, fontWeight:600, color:'#ff3b30', letterSpacing:'0.14em', textTransform:'uppercase', display:'flex', alignItems:'center', gap:6 }}>
        <span style={{ width:6, height:6, borderRadius:99, background:'#ff3b30' }} className="pulse-soft"/>Emergency dispatch
      </div>
      <div className="display" style={{ fontSize:20, fontWeight:600, letterSpacing:'-0.03em', marginTop:4 }}>1421 Pine St</div>
      <div style={{ position:'relative', marginTop:12, borderRadius:14, overflow:'hidden', height:220, background:'linear-gradient(180deg, #0a0d12 0%, #1a1f2c 100%)' }}>
        {/* Map grid */}
        <svg viewBox="0 0 280 220" style={{ position:'absolute', inset:0, width:'100%', height:'100%' }}>
          <g stroke="rgba(255,255,255,0.06)" strokeWidth="1">
            {Array.from({length: 8}).map((_,i) => <line key={'h'+i} x1="0" y1={i*30} x2="280" y2={i*30}/>)}
            {Array.from({length: 10}).map((_,i) => <line key={'v'+i} x1={i*30} y1="0" x2={i*30} y2="220"/>)}
          </g>
          {/* Streets — slightly brighter */}
          <g stroke="rgba(255,255,255,0.12)" strokeWidth="6" strokeLinecap="round">
            <path d="M-20 70 L300 50"/>
            <path d="M-20 150 L300 130"/>
            <path d="M80 -20 L100 240"/>
            <path d="M200 -20 L220 240"/>
          </g>
          {/* Radar pulse */}
          <circle cx="140" cy="110" r={20 + p * 90} fill="none" stroke="var(--chart-300)" strokeWidth="1" opacity={Math.max(0, 0.5 - p*0.5)}/>
          <circle cx="140" cy="110" r={40 + p * 60} fill="none" stroke="var(--chart-300)" strokeWidth="1" opacity={Math.max(0, 0.3 - p*0.3)}/>
          {/* Route line to selected crew */}
          {crews[0].show && (
            <path d={`M ${crews[0].x.replace('%','')*2.8} ${crews[0].y.replace('%','')*2.2} Q 100 80 140 110`}
              stroke="var(--chart-300)" strokeWidth="2.5" fill="none" strokeLinecap="round"
              strokeDasharray="200" strokeDashoffset={(1 - Math.min(1, p*1.5))*200}
              style={{ filter:'drop-shadow(0 0 6px rgba(196,240,0,0.6))' }}/>
          )}
        </svg>
        {/* Destination */}
        <div style={{ position:'absolute', left:'50%', top:'50%', transform:'translate(-50%,-50%)', zIndex:5 }}>
          <div style={{ position:'relative' }}>
            <div style={{ width:32, height:32, borderRadius:'50%', background:'#ff3b30', display:'flex', alignItems:'center', justifyContent:'center', boxShadow:'0 0 0 4px rgba(255,59,48,0.25)' }}>
              <IconHome size={16} stroke="#fff" sw={2.2}/>
            </div>
            <div style={{ position:'absolute', top:36, left:'50%', transform:'translateX(-50%)', whiteSpace:'nowrap', background:'rgba(255,59,48,0.18)', color:'#ff8a78', padding:'2px 7px', borderRadius:5, fontSize:9, fontWeight:700, letterSpacing:'0.08em', fontFamily:'var(--font-mono)' }}>EMERGENCY</div>
          </div>
        </div>
        {/* Crew pins */}
        {crews.map((c, i) => c.show && (
          <div key={i} style={{ position:'absolute', left:c.x, top:c.y, transform:'translate(-50%,-50%)' }}>
            <div style={{ background: c.sel ? 'var(--chart-300)' : 'rgba(255,255,255,0.95)', color:'var(--ink)', padding:'3px 8px', borderRadius:6, fontSize:9.5, fontWeight:700, fontFamily:'var(--font-display)', boxShadow: c.sel ? '0 4px 12px rgba(196,240,0,0.4)' : '0 2px 6px rgba(0,0,0,0.3)', display:'flex', alignItems:'center', gap:5, transition:'all 0.3s', transform: c.sel ? 'scale(1.1)' : 'scale(1)' }}>
              {c.sel && <span style={{ width:5, height:5, borderRadius:99, background:'var(--ink)' }} className="pulse-soft"/>}
              {c.eta}
            </div>
            <div style={{ marginTop:2, fontSize:8, fontFamily:'var(--font-mono)', color: c.sel ? 'var(--chart-300)' : 'rgba(255,255,255,0.45)', textAlign:'center' }}>{c.van}</div>
          </div>
        ))}
      </div>
      {/* Closest crew detail */}
      <div style={{ marginTop:10, padding:'10px 12px', background:'var(--ink)', borderRadius:12, color:'#fff', display:'flex', alignItems:'center', gap:10 }}>
        <Avatar name="MR" size={32} hue={140}/>
        <div style={{ flex:1 }}>
          <div style={{ fontSize:12.5, fontWeight:600, fontFamily:'var(--font-display)' }}>Marcus R. · routed</div>
          <div style={{ fontSize:10, color:'rgba(255,255,255,0.55)', marginTop:1 }}>White van · ★ 4.94 · plumbing certified</div>
        </div>
        <div style={{ display:'flex', flexDirection:'column', alignItems:'flex-end' }}>
          <div className="display" style={{ fontSize:22, fontWeight:600, color:'var(--chart-300)', lineHeight:1 }}>{eta} min</div>
          <div style={{ fontSize:9, color:'rgba(255,255,255,0.45)', fontFamily:'var(--font-mono)' }}>ETA</div>
        </div>
      </div>
    </div>
  );
}

/* ============== PHOTOS — customer-uploaded photo intake (handyman) ============== */
function ScenePhotos({ progress, config }) {
  const photos = [
    { id:1, label:'Mount TV · 65"',          tag:'+$140' },
    { id:2, label:'Install 4 shelves',       tag:'+$220' },
    { id:3, label:'Sticky door · plane',     tag:'+$80'  },
    { id:4, label:'Toilet · running fill',   tag:'+$110' },
  ];
  const visible = Math.min(photos.length, Math.max(1, Math.ceil(progress * photos.length * 1.3)));
  return (
    <div>
      <div style={{ fontSize:10, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.14em', textTransform:'uppercase' }}>Photos · customer upload</div>
      <div className="display" style={{ fontSize:20, fontWeight:600, letterSpacing:'-0.03em', marginTop:4 }}>Joel's task list</div>
      <div style={{ marginTop:12, display:'grid', gridTemplateColumns:'1fr 1fr', gap:6 }}>
        {photos.map((ph, i) => {
          const shown = i < visible;
          return (
            <div key={ph.id} style={{ position:'relative', height:104, borderRadius:11, overflow:'hidden',
              background: i % 2 === 0 ? 'linear-gradient(135deg, #b8c5d0, #7a8a98)' : 'linear-gradient(135deg, #c9b896, #8a7656)',
              opacity: shown ? 1 : 0.18, transition:'opacity 0.4s', border: shown ? '1.5px solid var(--chart-300)' : '1.5px solid transparent' }}>
              {/* fake photo content */}
              <svg viewBox="0 0 100 100" style={{ width:'100%', height:'100%', position:'absolute', inset:0 }}>
                {i === 0 && <rect x="20" y="20" width="60" height="40" fill="rgba(12,14,16,0.5)" rx="2"/>}
                {i === 1 && [0,1,2,3].map(s => <rect key={s} x="15" y={20 + s*15} width="70" height="3" fill="rgba(12,14,16,0.5)"/>)}
                {i === 2 && <rect x="35" y="20" width="30" height="60" fill="rgba(12,14,16,0.5)" rx="2"/>}
                {i === 3 && <><ellipse cx="50" cy="55" rx="18" ry="22" fill="rgba(255,255,255,0.6)"/><rect x="42" y="33" width="16" height="6" fill="rgba(255,255,255,0.6)"/></>}
              </svg>
              {/* Detection bounding box */}
              {shown && (
                <svg viewBox="0 0 100 100" style={{ width:'100%', height:'100%', position:'absolute', inset:0 }}>
                  <rect x="14" y="14" width="72" height="72" fill="none" stroke="var(--chart-300)" strokeWidth="1.2" strokeDasharray="3 3"/>
                </svg>
              )}
              {/* Label */}
              {shown && (
                <div style={{ position:'absolute', bottom:6, left:6, right:6, display:'flex', justifyContent:'space-between', alignItems:'flex-end', gap:4 }}>
                  <span style={{ background:'rgba(12,14,16,0.85)', color:'#fff', padding:'3px 6px', borderRadius:4, fontSize:9, fontWeight:600, maxWidth:80, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{ph.label}</span>
                  <span style={{ background:'var(--chart-300)', color:'var(--ink)', padding:'3px 6px', borderRadius:4, fontSize:9, fontWeight:700, fontFamily:'var(--font-mono)' }}>{ph.tag}</span>
                </div>
              )}
              {/* Photo num */}
              <div style={{ position:'absolute', top:6, left:6, background:'rgba(255,255,255,0.85)', color:'var(--ink)', padding:'2px 6px', borderRadius:4, fontSize:9, fontWeight:700, fontFamily:'var(--font-mono)' }}>#{ph.id}</div>
            </div>
          );
        })}
      </div>
      <div style={{ marginTop:10, padding:'9px 12px', background:'var(--ink)', borderRadius:11, color:'#fff', display:'flex', alignItems:'center', gap:8 }}>
        <span style={{ width:6, height:6, borderRadius:99, background:'var(--chart-300)' }} className="pulse-soft"/>
        <span style={{ flex:1, fontSize:11 }}>AI detected <strong style={{ color:'var(--chart-300)' }}>{visible}</strong> tasks · scope sheet ready</span>
        <IconArrow size={12} stroke="var(--chart-300)"/>
      </div>
    </div>
  );
}

/* ============== CLAIM — insurance + weather data cross-check (restoration) ============== */
function SceneClaim({ progress, config }) {
  const p = Math.min(1, Math.max(0, progress * 1.15));
  const rows = [
    { src:'Insurance carrier', value:'State Farm', detail:'Auto + dwelling', done: p > 0.10 },
    { src:'Claim number',      value:'SF-4218-A',  detail:'Filed 11:43 PM',  done: p > 0.30 },
    { src:'Deductible',        value:'$2,500',     detail:'Met YTD',         done: p > 0.50 },
    { src:'Weather event',     value:'Hailstorm',  detail:'Apr 12 · 1.75"', done: p > 0.70 },
    { src:'Xactimate range',   value:'$8.4–11.2k', detail:'Carrier avg',     done: p > 0.90 },
  ];
  return (
    <div>
      <div style={{ fontSize:10, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.14em', textTransform:'uppercase' }}>Claim · cross-check</div>
      <div className="display" style={{ fontSize:20, fontWeight:600, letterSpacing:'-0.03em', marginTop:4 }}>SF-4218-A · Rachel L.</div>
      {/* Visual */}
      <div style={{ position:'relative', marginTop:12, borderRadius:14, overflow:'hidden', height:110, background:'linear-gradient(180deg, var(--ink) 0%, #1a2030 100%)', padding:'14px 16px', color:'#fff' }}>
        <div style={{ display:'flex', justifyContent:'space-between', alignItems:'flex-start' }}>
          <div>
            <div style={{ fontSize:9, color:'var(--chart-300)', fontWeight:700, letterSpacing:'0.14em' }}>CARRIER MATCH</div>
            <div style={{ marginTop:6, display:'flex', alignItems:'center', gap:6 }}>
              <div style={{ width:28, height:28, borderRadius:7, background:'var(--chart-300)', display:'flex', alignItems:'center', justifyContent:'center', color:'var(--ink)', fontFamily:'var(--font-display)', fontWeight:800, fontSize:12 }}>SF</div>
              <div>
                <div style={{ fontFamily:'var(--font-display)', fontWeight:600, fontSize:13 }}>State Farm</div>
                <div style={{ fontSize:9, color:'rgba(255,255,255,0.55)' }}>Preferred contractor</div>
              </div>
            </div>
          </div>
          <div style={{ textAlign:'right' }}>
            <div style={{ fontSize:9, color:'rgba(255,255,255,0.5)', fontWeight:700, letterSpacing:'0.14em' }}>HAILSTORM · APR 12</div>
            <div style={{ marginTop:6, fontFamily:'var(--font-display)', fontSize:13, fontWeight:600 }}>1.75" stones</div>
            <div style={{ fontSize:9, color:'rgba(255,255,255,0.55)' }}>NOAA confirmed</div>
          </div>
        </div>
        {/* Animated link line */}
        <svg viewBox="0 0 280 30" style={{ position:'absolute', bottom:8, left:0, right:0, width:'100%', height:14 }}>
          <line x1="20" y1="7" x2="260" y2="7" stroke="var(--chart-300)" strokeWidth="1.5"
            strokeDasharray="240" strokeDashoffset={(1-p)*240}/>
          <circle cx="20" cy="7" r="3" fill="var(--chart-300)"/>
          <circle cx="260" cy="7" r="3" fill="var(--chart-300)"/>
        </svg>
      </div>
      {/* Records */}
      <div style={{ marginTop:8, display:'flex', flexDirection:'column', gap:4 }}>
        {rows.map((r, i) => (
          <div key={i} style={{ display:'flex', alignItems:'center', gap:9, padding:'7px 10px', background: r.done ? 'var(--paper-3)' : '#fff', borderRadius:8, border:'1px solid var(--line-2)', transition:'background 0.3s' }}>
            <span style={{ width:14, height:14, borderRadius:99, background: r.done? 'var(--chart-300)' : 'var(--paper-3)', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
              {r.done && <IconCheck size={9} stroke="var(--ink)" sw={2.5}/>}
            </span>
            <span style={{ fontSize:9.5, fontFamily:'var(--font-mono)', color:'var(--mute-2)', letterSpacing:'0.04em', minWidth:88 }}>{r.src}</span>
            <span style={{ flex:1, fontSize:11.5, fontWeight:600, color: r.done? 'var(--ink)' : 'var(--mute-2)' }}>{r.value}</span>
            <span style={{ fontSize:10, color:'var(--mute-1)' }}>{r.detail}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ============== AR SCENE ============== */
function SceneAR({ progress, config }) {
  const tags = (config && config.arTags) || [
    { x:'30%', y:'38%', label:'Front door · 36"' },
    { x:'70%', y:'30%', label:'Window · 48"×60"' },
    { x:'55%', y:'58%', label:'Siding · vinyl' },
    { x:'25%', y:'72%', label:'Step · concrete' },
  ];
  const visible = Math.min(tags.length, Math.floor(progress * tags.length * 1.5));
  return (
    <div>
      <div style={{ fontSize:10, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.14em', textTransform:'uppercase', display:'flex', alignItems:'center', gap:6 }}>
        <span style={{ width:6, height:6, borderRadius:99, background:'#ff3b30' }} className="pulse-soft"/>AR · live walkthrough
      </div>
      <div className="display" style={{ fontSize:18, fontWeight:600, letterSpacing:'-0.03em', marginTop:4 }}>Homeowner is scanning…</div>
      <div style={{ position:'relative', marginTop:12, borderRadius:18, overflow:'hidden', height:280,
        background:'linear-gradient(180deg, #d9e8f0 0%, #b8cad6 60%, #94a3b0 100%)' }}>
        {/* sky */}
        <div style={{ position:'absolute', top:0, left:0, right:0, height:'40%', background:'linear-gradient(180deg, #c5d8e3 0%, #e0e8ec 100%)' }}/>
        {/* house silhouette */}
        <svg viewBox="0 0 280 280" style={{ position:'absolute', inset:0, width:'100%', height:'100%' }}>
          <polygon points="40,120 140,60 240,120 240,260 40,260" fill="#e8e3d8"/>
          <polygon points="40,120 140,60 240,120" fill="#7a8290"/>
          <rect x="60" y="160" width="40" height="50" fill="#6a7280"/>
          <rect x="180" y="160" width="40" height="50" fill="#6a7280"/>
          <rect x="118" y="170" width="44" height="80" fill="#3a4250"/>
          <rect x="120" y="172" width="40" height="76" fill="#5a6270"/>
          {/* lawn */}
          <rect x="0" y="240" width="280" height="40" fill="#7a8c5a"/>
        </svg>
        {/* AR mesh overlay */}
        <svg viewBox="0 0 280 280" style={{ position:'absolute', inset:0, width:'100%', height:'100%' }}>
          {Array.from({length: 8}).map((_,i)=>(
            <line key={'h'+i} x1="0" y1={i*40} x2="280" y2={i*40} stroke="var(--chart-300)" strokeWidth=".5" opacity=".25"/>
          ))}
          {Array.from({length: 8}).map((_,i)=>(
            <line key={'v'+i} x1={i*40} y1="0" x2={i*40} y2="280" stroke="var(--chart-300)" strokeWidth=".5" opacity=".25"/>
          ))}
          {/* feature outlines */}
          <rect x="118" y="170" width="44" height="80" fill="none" stroke="var(--chart-300)" strokeWidth="1.5" strokeDasharray="3 3" opacity={visible > 0 ? 1 : 0}/>
          <rect x="60" y="160" width="40" height="50" fill="none" stroke="var(--chart-300)" strokeWidth="1.5" strokeDasharray="3 3" opacity={visible > 1 ? 1 : 0}/>
          <rect x="40" y="120" width="200" height="140" fill="none" stroke="var(--chart-300)" strokeWidth="1" strokeDasharray="2 4" opacity={visible > 2 ? 0.5 : 0}/>
        </svg>
        {/* labels */}
        {tags.slice(0, visible).map((t,i)=>(
          <div key={i} style={{ position:'absolute', top:t.y, left:t.x, transform:'translate(-50%,-50%)' }}>
            <div style={{ width:8, height:8, borderRadius:99, background:'var(--chart-300)', boxShadow:'0 0 0 4px rgba(196,240,0,0.25)' }}/>
            <div style={{ position:'absolute', top:-4, left:14, background:'var(--ink)', color:'#fff', padding:'3px 7px', borderRadius:6, fontSize:9.5, fontWeight:600, whiteSpace:'nowrap' }}>{t.label}</div>
          </div>
        ))}
        {/* phone-in-phone reticle */}
        <div style={{ position:'absolute', top:14, left:14, background:'rgba(12,14,16,0.7)', backdropFilter:'blur(8px)', color:'#fff', padding:'5px 10px', borderRadius:99, fontSize:10, fontWeight:600, display:'flex', alignItems:'center', gap:6 }}>
          <IconCamera size={11} stroke="#fff" sw={2}/> Scanning · {Math.round(progress*100)}%
        </div>
        <div style={{ position:'absolute', bottom:14, right:14, background:'var(--chart-300)', color:'var(--ink)', padding:'4px 9px', borderRadius:99, fontSize:10, fontWeight:700, letterSpacing:'0.04em' }}>+${visible*240}</div>
      </div>
      <div style={{ marginTop:10, fontSize:11, color:'var(--mute-1)', display:'flex', alignItems:'center', gap:6 }}>
        <span style={{ width:6, height:6, borderRadius:99, background:'var(--success)' }}/>
        <span><strong style={{ color:'var(--ink)' }}>{visible}</strong> features tagged · {Math.max(0, 12 - visible*2)} pts to go</span>
      </div>
    </div>
  );
}

/* ============== FIELDS SCENE — drag-and-drop estimate builder ============== */
const FIELD_CATALOG = [
  { id:'pitch', name:'Roof pitch', kind:'select' },
  { id:'sqft', name:'Square footage', kind:'number' },
  { id:'material', name:'Material', kind:'select' },
  { id:'layers', name:'Layers', kind:'number' },
  { id:'decking', name:'Decking', kind:'toggle' },
  { id:'tier', name:'Tier', kind:'select' },
];

function SceneFields({ progress, config, placedIds, onDrop, onRemove }) {
  const catalog = (config && config.fields) || FIELD_CATALOG;
  // If controlled (placedIds/onDrop provided), use that. Otherwise drive by scroll progress.
  const placed = placedIds || catalog.slice(0, Math.min(catalog.length, Math.floor(progress * catalog.length * 1.4))).map(f=>f.id);
  const available = catalog.filter(f => !placed.includes(f.id));
  return (
    <div>
      <div style={{ fontSize:10, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.14em', textTransform:'uppercase' }}>Estimator · {(config && config.name) ? config.name.toLowerCase() : 'roofing'} template</div>
      <div className="display" style={{ fontSize:18, fontWeight:600, letterSpacing:'-0.03em', marginTop:4 }}>Build your form</div>
      <div style={{ marginTop:12, display:'flex', flexDirection:'column', gap:6 }}>
        <div style={{ fontSize:9, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.1em', textTransform:'uppercase' }}>Available fields</div>
        <div style={{ display:'flex', flexWrap:'wrap', gap:5, minHeight:30 }}>
          {available.length === 0 && <span style={{ fontSize:11, color:'var(--mute-2)' }}>All placed.</span>}
          {available.map(f => (
            <div key={f.id}
              draggable={!!onDrop}
              onDragStart={onDrop ? (e) => e.dataTransfer.setData('text/plain', f.id) : undefined}
              style={{ background:'var(--lilac-100)', color:'var(--lilac-800)', padding:'5px 9px', borderRadius:8, fontSize:10.5, fontWeight:600, display:'flex', alignItems:'center', gap:5, cursor: onDrop ? 'grab' : 'default' }}>
              <span style={{ fontFamily:'var(--font-mono)', fontSize:9, opacity:.6 }}>⋮⋮</span>{f.name}
            </div>
          ))}
        </div>
        <div style={{ fontSize:9, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.1em', textTransform:'uppercase', marginTop:6 }}>Your estimate form</div>
        <div
          onDragOver={onDrop ? (e)=>{ e.preventDefault(); } : undefined}
          onDrop={onDrop ? (e)=>{ e.preventDefault(); const id = e.dataTransfer.getData('text/plain'); if(id) onDrop(id); } : undefined}
          style={{ background:'var(--paper-3)', borderRadius:12, padding:10, minHeight:170, display:'flex', flexDirection:'column', gap:5,
            border:'1.5px dashed var(--mute-3)' }}>
          {placed.length === 0 && <div style={{ color:'var(--mute-2)', fontSize:11, padding:8, textAlign:'center' }}>Drop fields here</div>}
          {placed.map((id, i) => {
            const f = catalog.find(x=>x.id===id) || {};
            return (
              <div key={id} style={{ background:'#fff', borderRadius:8, padding:'7px 9px', display:'flex', alignItems:'center', gap:8, fontSize:11, transition:'all 0.25s' }}>
                <span style={{ fontFamily:'var(--font-mono)', fontSize:9, color:'var(--mute-2)' }}>0{i+1}</span>
                <span style={{ fontWeight:600, flex:1 }}>{f.name}</span>
                <span style={{ fontSize:9, color:'var(--mute-2)', background:'var(--paper-3)', padding:'2px 6px', borderRadius:99 }}>{f.kind}</span>
                {onRemove && <span onClick={()=>onRemove(id)} style={{ cursor:'pointer', color:'var(--mute-2)', fontSize:13 }}>×</span>}
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

/* ============== QUALIFY SCENE — chat + score ============== */
function SceneQualify({ progress, config }) {
  const msgs = (config && config.qualifyChat) || [
    { who:'bot', text:'Hey! Got a sec to help me line this up?' },
    { who:'them', text:'Sure.' },
    { who:'bot', text:'Budget range you\'re thinking?' },
    { who:'them', text:'15–22k. Insurance is covering most.' },
    { who:'bot', text:'Timeline — this month, next?' },
    { who:'them', text:'ASAP. Storm hit Tuesday.' },
    { who:'bot', text:'Are you the homeowner?' },
    { who:'them', text:'Yes. My wife and I both decide.' },
  ];
  const checks = (config && config.qualifyChecks) || [
    ['Budget','$15–22k',4],['Timeline','ASAP',6],['Decider','Confirmed',8],['Insurance','Yes',4]
  ];
  const customerLabel = (config && config.cat === 'commercial') ? 'Facility lead' : 'Vince at Pine St';
  const visible = Math.min(msgs.length, Math.max(2, Math.ceil(progress * msgs.length * 1.3)));
  // score climbs with messages
  const score = Math.min(100, Math.round(visible / msgs.length * 100));
  const tier = score < 30 ? 'COLD' : score < 55 ? 'WARM' : score < 85 ? 'HOT' : 'READY';
  const tierColor = score < 30 ? '#8a8f97' : score < 55 ? '#f5a524' : score < 85 ? '#ff7a3d' : 'var(--chart-300)';
  const tierFg = score < 30 ? '#fff' : score < 55 ? '#5c3a05' : score < 85 ? '#fff' : 'var(--ink)';
  return (
    <div style={{ display:'flex', flexDirection:'column', height:'100%' }}>
      <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between' }}>
        <div>
          <div style={{ fontSize:10, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.14em', textTransform:'uppercase' }}>Lead intake</div>
          <div className="display" style={{ fontSize:18, fontWeight:600, letterSpacing:'-0.03em', marginTop:2 }}>{customerLabel}</div>
        </div>
        <div style={{ background: tierColor, color: tierFg, padding:'4px 10px', borderRadius:99, fontSize:10, fontWeight:800, letterSpacing:'0.08em' }}>{tier}</div>
      </div>
      {/* score bar */}
      <div style={{ marginTop:10, background:'var(--paper-3)', borderRadius:99, height:8, overflow:'hidden', position:'relative' }}>
        <div style={{ position:'absolute', inset:0, width:`${score}%`, background:`linear-gradient(90deg, var(--lilac-300), var(--chart-300))`, borderRadius:99, transition:'width 0.4s' }}/>
      </div>
      <div style={{ display:'flex', justifyContent:'space-between', fontSize:9, color:'var(--mute-2)', marginTop:3, fontFamily:'var(--font-mono)' }}>
        <span>0</span><span>cold</span><span>warm</span><span>hot</span><span>100</span>
      </div>
      <div style={{ flex:1, marginTop:10, display:'flex', flexDirection:'column', gap:5, overflow:'hidden' }}>
        {msgs.slice(0, visible).map((m, i) => (
          <div key={i} style={{ display:'flex', justifyContent: m.who==='them'? 'flex-end':'flex-start' }}>
            <div style={{ maxWidth:'78%', padding:'7px 11px', borderRadius: m.who==='them'? '14px 14px 4px 14px' : '14px 14px 14px 4px',
              background: m.who==='them'? 'var(--ink)' : 'var(--lilac-100)',
              color: m.who==='them'? '#fff' : 'var(--lilac-900)', fontSize:11.5, lineHeight:1.4 }}>{m.text}</div>
          </div>
        ))}
        {visible < msgs.length && (
          <div style={{ alignSelf:'flex-start', padding:'5px 11px', background:'var(--lilac-100)', borderRadius:99, fontSize:11, color:'var(--lilac-700)' }}>· · ·</div>
        )}
      </div>
      {/* qualifier checkboxes */}
      <div style={{ marginTop:8, padding:'8px 10px', background:'var(--paper-3)', borderRadius:10, display:'grid', gridTemplateColumns:'1fr 1fr', gap:5, fontSize:10 }}>
        {checks.map((c,i) => {
          const [l, v, threshold] = c;
          const done = visible >= threshold;
          return (
            <div key={i} style={{ display:'flex', alignItems:'center', gap:6, opacity: done ? 1 : 0.45 }}>
              <span style={{ width:14, height:14, borderRadius:99, background: done? 'var(--chart-300)' : 'var(--mute-3)', display:'flex', alignItems:'center', justifyContent:'center' }}>
                {done && <IconCheck size={10} stroke="var(--ink)" sw={2.5}/>}
              </span>
              <span style={{ color:'var(--mute-1)' }}>{l}:</span>
              <span style={{ fontWeight:600, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{v}</span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ============== ESTIMATE SCENE — line items, total, deposit ============== */
function SceneEstimate({ progress, config }) {
  const lines = (config && config.lines) || [
    ['Tear-off (2 layers)', '$2,800'],
    ['GAF Timberline HDZ', '$5,940'],
    ['Underlayment + ice', '$1,180'],
    ['Decking repair (est)', '$640'],
    ['Labor · 3-man crew', '$4,100'],
    ['Permit + dump', '$485'],
  ];
  const subtotal = (config && config.subtotal) || 15145;
  const tax = (config && (config.tax === 0 || config.tax)) ? config.tax : 1250;
  const targetTotal = (config && config.total) || 16395;
  const deposit = (config && config.deposit) || 4099;
  const visible = Math.min(lines.length, Math.floor(progress * lines.length * 1.5));
  const total = visible >= lines.length ? targetTotal : Math.round(progress * targetTotal);
  return (
    <div>
      <div style={{ fontSize:10, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.14em', textTransform:'uppercase' }}>Quote · 1421 Pine St</div>
      <div style={{ display:'flex', alignItems:'baseline', justifyContent:'space-between', marginTop:4 }}>
        <div className="display" style={{ fontSize:30, fontWeight:600, letterSpacing:'-0.04em', lineHeight:1 }}>${total.toLocaleString()}</div>
        <div style={{ display:'flex', gap:5 }}>
          <span style={{ background:'var(--chart-300)', color:'var(--ink)', fontSize:9, fontWeight:700, padding:'3px 7px', borderRadius:99, letterSpacing:'0.06em' }}>SENT · 58s</span>
        </div>
      </div><div style={{ marginTop:10, background:'var(--paper-3)', borderRadius:12, padding:'8px 11px' }}>
        {lines.slice(0, visible).map(([l,v],i)=>(
          <div key={i} style={{ display:'flex', justifyContent:'space-between', padding:'4px 0', fontSize:11.5, borderTop:i>0?'1px solid rgba(12,14,16,0.05)':'0' }}>
            <span style={{ color:'var(--mute-1)' }}>{l}</span>
            <span style={{ fontFamily:'var(--font-mono)', fontWeight:600 }}>{v}</span>
          </div>
        ))}
        {visible >= lines.length && (
          <>
            <div style={{ display:'flex', justifyContent:'space-between', padding:'4px 0', fontSize:11, color:'var(--mute-1)', borderTop:'1px dashed var(--line)', marginTop:4 }}>
              <span>Subtotal</span><span style={{ fontFamily:'var(--font-mono)' }}>${subtotal.toLocaleString()}</span>
            </div>
            {tax > 0 && (
              <div style={{ display:'flex', justifyContent:'space-between', padding:'2px 0', fontSize:11, color:'var(--mute-1)' }}>
                <span>Tax</span><span style={{ fontFamily:'var(--font-mono)' }}>${tax.toLocaleString()}</span>
              </div>
            )}
            <div style={{ display:'flex', justifyContent:'space-between', padding:'2px 0', fontSize:11, color:'var(--mute-1)' }}>
              <span>Margin built in</span><span style={{ fontFamily:'var(--font-mono)' }}>32%</span>
            </div>
          </>
        )}
      </div>
      {visible >= lines.length && deposit > 0 && (
          <>
            <div style={{ marginTop:10, padding:'10px 11px', background:'var(--ink)', borderRadius:12, color:'#fff' }}>
              <div style={{ fontSize:9, color:'rgba(255,255,255,.5)', letterSpacing:'0.12em', textTransform:'uppercase' }}>Deposit (25%)</div>
              <div style={{ display:'flex', alignItems:'center', justifyContent:'space-between', marginTop:2 }}>
                <div className="display" style={{ fontSize:18, fontWeight:600, color:'var(--chart-300)' }}>${deposit.toLocaleString()}</div>
                <button style={{ background:'var(--chart-300)', color:'var(--ink)', border:0, padding:'7px 14px', borderRadius:99, fontWeight:700, fontSize:11, fontFamily:'var(--font-body)' }}>Pay & sign</button>
              </div>
            </div>
            <div style={{ marginTop:6, fontSize:10, color:'var(--mute-1)', display:'flex', alignItems:'center', gap:6 }}>
              <IconCheck size={11} stroke="var(--success)" sw={2.5}/> Signed by Vince R. · 11:42 AM
            </div>
          </>
        )}
    </div>
  );
}

/* ============== STACK SCENE — connected systems ============== */
function SceneStack({ progress, config }) {
  const flow = Math.min(1, progress * 1.2);
  const trade = (config && config.name) || 'Electrical';
  const total = (config && config.total) ? '$' + Math.round(config.total * 0.25).toLocaleString() : '$4,099';

  const systems = [
    { id:'crm',  label:'CRM',      sub:'Customer record',   t:0.20 },
    { id:'cal',  label:'Calendar', sub:'Install · Apr 18',  t:0.42 },
    { id:'disp', label:'Dispatch', sub:'Crew assigned',     t:0.62 },
    { id:'pay',  label:'Payroll',  sub:'Commission logged', t:0.82 },
  ];
  const synced = systems.filter(s => flow >= s.t).length;

  const Cell = ({ s, borderRight, borderBottom }) => {
    const active = flow >= s.t;
    return (
      <div style={{
        padding:'11px 13px',
        background: active ? 'rgba(196,240,0,0.04)' : 'rgba(255,255,255,0.02)',
        borderRight: borderRight ? '1px solid rgba(255,255,255,0.07)' : 'none',
        borderBottom: borderBottom ? '1px solid rgba(255,255,255,0.07)' : 'none',
        transition:'background 0.5s',
      }}>
        <div style={{ fontSize:10.5, fontWeight:700, color: active ? '#fff' : 'rgba(255,255,255,0.28)', letterSpacing:'-0.01em', transition:'color 0.4s' }}>{s.label}</div>
        <div style={{ fontSize:8.5, color:'rgba(255,255,255,0.38)', marginTop:2, lineHeight:1.3 }}>{s.sub}</div>
        <div style={{ marginTop:6, height:14, display:'flex', alignItems:'center' }}>
          {active ? (
            <div style={{ display:'flex', alignItems:'center', gap:4 }}>
              <span style={{ width:5, height:5, borderRadius:99, background:'var(--chart-300)', flexShrink:0 }} className="pulse-soft"/>
              <span style={{ fontSize:8, fontWeight:700, color:'var(--chart-300)', letterSpacing:'0.12em', fontFamily:'var(--font-mono)' }}>SYNCED</span>
            </div>
          ) : (
            <div style={{ width:32, height:2, borderRadius:99, background:'rgba(255,255,255,0.08)' }}/>
          )}
        </div>
      </div>
    );
  };

  return (
    <div>
      <div style={{ fontSize:10, fontWeight:600, color:'var(--mute-1)', letterSpacing:'0.14em', textTransform:'uppercase' }}>Orchestration</div>
      <div className="display" style={{ fontSize:18, fontWeight:600, letterSpacing:'-0.03em', marginTop:4 }}>Quote → installed</div>

      <div style={{ marginTop:12, borderRadius:16, overflow:'hidden', background:'#0c0f15', border:'1px solid rgba(255,255,255,0.07)' }}>
        {/* Top row */}
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr' }}>
          <Cell s={systems[0]} borderRight borderBottom/>
          <Cell s={systems[1]} borderBottom/>
        </div>

        {/* Center hub */}
        <div style={{ padding:'16px 14px', borderBottom:'1px solid rgba(255,255,255,0.07)', background:'rgba(255,255,255,0.015)', display:'flex', alignItems:'center', gap:12, position:'relative', overflow:'hidden' }}>
          {/* glow */}
          <div style={{ position:'absolute', top:'-30px', left:'30px', width:140, height:140, borderRadius:'50%', background:'radial-gradient(circle, rgba(196,240,0,0.18) 0%, transparent 60%)', pointerEvents:'none' }}/>
          <div style={{ width:48, height:48, borderRadius:13, background:'var(--chart-300)', display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0, boxShadow:'0 0 0 5px rgba(196,240,0,0.12), 0 0 24px rgba(196,240,0,0.4)', position:'relative' }}>
            <IconReceipt size={24} stroke="var(--ink)" sw={2}/>
          </div>
          <div style={{ position:'relative', minWidth:0 }}>
            <div style={{ fontSize:8.5, fontFamily:'var(--font-mono)', color:'var(--chart-300)', fontWeight:700, letterSpacing:'0.12em' }}>QUOTE #4218</div>
            <div style={{ fontFamily:'var(--font-display)', fontSize:14, fontWeight:700, color:'#fff', marginTop:2, letterSpacing:'-0.025em' }}>1421 Pine St</div>
            <div style={{ fontSize:9, color:'rgba(255,255,255,0.42)', marginTop:2, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>{trade} · {total} deposit paid</div>
          </div>
          {/* progress dots */}
          <div style={{ position:'absolute', right:14, top:'50%', transform:'translateY(-50%)', display:'flex', flexDirection:'column', gap:4 }}>
            {[0,1,2,3].map(i => (
              <div key={i} style={{ width:4, height:4, borderRadius:99, background:'var(--chart-300)', opacity: synced > i ? 1 : 0.12, transition:'opacity 0.35s', boxShadow: synced > i ? '0 0 6px rgba(196,240,0,0.6)' : 'none' }}/>
            ))}
          </div>
        </div>

        {/* Bottom row */}
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr' }}>
          <Cell s={systems[2]} borderRight/>
          <Cell s={systems[3]}/>
        </div>
      </div>

      {/* Status bar */}
      <div style={{ marginTop:8, display:'flex', justifyContent:'space-between', alignItems:'center', padding:'9px 12px', background:'var(--paper-3)', borderRadius:10 }}>
        <div style={{ display:'flex', alignItems:'center', gap:7 }}>
          <span style={{ fontFamily:'var(--font-mono)', fontSize:14, fontWeight:700, color:'var(--ink)', lineHeight:1 }}>{synced}</span>
          <span style={{ fontSize:11, color:'var(--mute-1)' }}>/ 4 systems synced</span>
        </div>
        <span style={{ fontSize:10, fontFamily:'var(--font-mono)', color:'var(--mute-2)', background:'#fff', border:'1px solid var(--line)', padding:'3px 8px', borderRadius:6 }}>2.4s</span>
      </div>
    </div>
  );
}

Object.assign(window, {
  OWNER_INDUSTRIES, buildOwnerSteps,
  SceneConfigured, SceneSatellite, SceneAR, SceneFields, SceneQualify, SceneEstimate, SceneStack,
  IndustryGlyph,
});
