/* Me2You - Marketplace screens: Home, Browse, PDP, Cart, Checkout, Success, Orders, Dispute */
/* global React, Icon, StatusTag, Field, OrderStepper, Price, CondTag, PageTransition, EmptyState,
 btnPrimary, btnGhost, btnDanger, btnSmall, panelStyle, PRODUCTS, CATEGORIES, SAMPLE_ORDERS */

const { useState, useEffect, useRef, useMemo } = React;

/* --- Hero --- */
function MarketplaceHero({ onBrowse, onSell }) {
 return (
 <section style={{
 background:'var(--brand-orange-50)',borderRadius:'var(--radius-xl)',
 padding:'48px 48px 44px',display:'grid',gridTemplateColumns:'1fr auto',
 gap:32,alignItems:'center',overflow:'hidden',position:'relative'
 }}>
 <div>
 <span style={{display:'inline-flex',alignItems:'center',gap:8,
 background:'rgba(255,255,255,.7)',padding:'6px 14px',borderRadius:999,
 fontFamily:'var(--font-body)',fontWeight:700,fontSize:12,
 color:'var(--brand-orange-700)',letterSpacing:'.04em',textTransform:'uppercase'}}>Made in SA - POPIA-safe</span>
 <h1 style={{fontFamily:'var(--font-display)',fontWeight:700,
 fontSize:'clamp(32px,4.5vw,48px)',lineHeight:1.05,letterSpacing:'-0.02em',
 margin:'16px 0 12px',color:'var(--ink-900)'}}>
 Sell to your<br/>neighbours, safely.
 </h1>
 <p style={{fontFamily:'var(--font-body)',fontSize:17,lineHeight:1.55,
 color:'var(--ink-700)',maxWidth:460,margin:'0 0 24px'}}>
 We hold your buyer's payment until they confirm receipt. No fake proof of payment, no cash meet-ups, no fuss.
 </p>
 <div style={{display:'flex',gap:12,flexWrap:'wrap'}}>
 <button onClick={onSell} style={btnPrimary}>List your first item</button>
 <button onClick={onBrowse} style={btnGhost}>Browse marketplace</button>
 </div>
 </div>
 <img src="assets/icon-peace-mono.png" alt="" style={{width:180,height:180,opacity:.12}}/>
 </section>
 );
}

/* --- Category Rail --- */
function CategoryRail({ active, onPick }) {
 return (
 <div style={{display:'flex',gap:8,flexWrap:'wrap',padding:'4px 0'}}>
 {CATEGORIES.map(c => (
 <button key={c.slug} onClick={() => onPick(c.slug)} style={{
 padding:'10px 18px',borderRadius:'var(--radius-pill)',
 fontFamily:'var(--font-body)',fontWeight:600,fontSize:14,cursor:'pointer',
 background: active === c.slug ? 'var(--ink-900)' : 'var(--paper)',
 color: active === c.slug ? 'white' : 'var(--ink-900)',
 border: '1.5px solid ' + (active === c.slug ? 'var(--ink-900)' : 'var(--ink-200)'),
 transition:'all .15s ease'
 }}>{c.name}</button>
 ))}
 </div>
 );
}

/* --- Product Card --- */
function ProductCard({ product, onClick, onAddToCart }) {
 const [hovered, setHovered] = useState(false);
 const [liked, setLiked] = useState(false);
 return (
 <article onClick={onClick}
 onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)}
 style={{
 background:'var(--paper)',borderRadius:'var(--radius-lg)',
 border:'1px solid var(--ink-200)',
 boxShadow: hovered ? 'var(--shadow-md)' : 'var(--shadow-sm)',
 padding:10,cursor:'pointer',
 transition:'all .2s cubic-bezier(.2,.7,.3,1)',
 transform: hovered ? 'translateY(-3px)' : 'none',
 display:'flex',flexDirection:'column',position:'relative'
 }}>
 <div style={{position:'absolute',top:18,right:18,zIndex:2}}>
 <button onClick={e => { e.stopPropagation(); setLiked(!liked); }}
 style={{width:32,height:32,borderRadius:'50%',border:'none',cursor:'pointer',
 background:'rgba(255,255,255,.85)',backdropFilter:'blur(8px)',
 display:'flex',alignItems:'center',justifyContent:'center',
 color: liked ? 'var(--danger)' : 'var(--ink-400)',transition:'color .15s'}}>
 <Icon name="heart" size={16} stroke={2} fill={liked ? 'currentColor' : 'none'}/>
 </button>
 </div>
 <div style={{aspectRatio:'1',borderRadius:14,overflow:'hidden',position:'relative',
 backgroundImage: 'url(assets/me2you.jpg)', backgroundSize: 'cover', backgroundPosition: 'center'}}>
 <div style={{position:'absolute',bottom:8,left:8,
 background:'rgba(255,255,255,.92)',backdropFilter:'blur(8px)',
 padding:'4px 10px',borderRadius:999,fontSize:11,fontWeight:700,
 fontFamily:'var(--font-body)',color:'var(--ink-700)',
 display:'inline-flex',alignItems:'center',gap:4}}>
 <span style={{fontSize:14}}>{product.emoji}</span>
 {product.title.split(' ').slice(0,2).join(' ')}
 </div>
 </div>
 <div style={{padding:'12px 4px 4px'}}>
 <CondTag condition={product.condition}/>
 <h3 style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:15,
 margin:'8px 0 4px',lineHeight:1.25,color:'var(--ink-900)'}}>{product.title}</h3>
 <div style={{fontFamily:'var(--font-body)',fontSize:12,color:'var(--ink-500)',marginBottom:8,
 display:'flex',alignItems:'center',gap:4}}>
 <Icon name="map-pin" size={11} stroke={2.4}/> {product.location} - {product.seller}
 </div>
 <div style={{display:'flex',justifyContent:'space-between',alignItems:'center'}}>
 <Price amount={product.price}/>
 <div style={{fontSize:11,color:'var(--ink-400)',fontFamily:'var(--font-body)'}}><span style={{color:'var(--brand-orange)'}}>★</span> {product.rating}
 </div>
 </div>
 </div>
 </article>
 );
}

/* --- Product Grid --- */
function ProductGrid({ products, onSelect, onAddToCart }) {
 return (
 <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill, minmax(220px, 1fr))',gap:16}}>
 {products.map(p => <ProductCard key={p.id} product={p} onClick={() => onSelect(p)} onAddToCart={onAddToCart}/>)}
 </div>
 );
}

/* --- Search bar --- */
function SearchBar({ value, onChange, onClear }) {
 return (
 <div style={{position:'relative',maxWidth:600,width:'100%'}}>
 <div style={{position:'absolute',left:14,top:'50%',transform:'translateY(-50%)',color:'var(--ink-400)'}}>
 <Icon name="search" size={18}/>
 </div>
 <input value={value} onChange={e => onChange(e.target.value)}
 placeholder="Search listings, e.g. 'Hisense TV'"
 style={{width:'100%',padding:'12px 40px 12px 42px',border:'1.5px solid var(--ink-200)',
 borderRadius:'var(--radius-pill)',background:'var(--ink-50)',
 fontFamily:'var(--font-body)',fontSize:14,boxSizing:'border-box',
 transition:'border-color .15s'}}/>
 {value && (
 <button onClick={onClear} style={{position:'absolute',right:14,top:'50%',transform:'translateY(-50%)',
 background:'none',border:'none',cursor:'pointer',color:'var(--ink-400)'}}>
 <Icon name="x" size={16}/>
 </button>
 )}
 </div>
 );
}

/* --- Lay-bye panel: reserve with deposit --- */
function LaybyePanel({ product, onReserve }) {
 const [agreed, setAgreed] = useState(false);
 const [reserved, setReserved] = useState(false);
 const [ackAt, setAckAt] = useState(null);
 // Split the price into a deposit plus 3 weekly instalments (4 payments total)
 const instalments = 4;
 const each = Math.floor((product.price / instalments) * 100) / 100;
 const last = Math.round((product.price - each * (instalments - 1)) * 100) / 100;
 const schedule = [
 { label:'Deposit today', amount: each },
 { label:'Instalment 2 - in 1 week', amount: each },
 { label:'Instalment 3 - in 2 weeks', amount: each },
 { label:'Instalment 4 - in 3 weeks', amount: last },
 ];

 const toggleAck = () => {
 setAgreed(prev => {
 const next = !prev;
 setAckAt(next ? new Date().toLocaleString('en-ZA', { dateStyle:'medium', timeStyle:'short' }) : null);
 return next;
 });
 };

 if (reserved) {
 return (
 <div style={{...panelStyle,background:'var(--success-100)',borderColor:'var(--success)',marginTop:0}}>
 <div style={{display:'flex',alignItems:'center',gap:12}}>
 <div style={{width:44,height:44,borderRadius:999,background:'var(--success)',color:'white',
 display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
 <Icon name="check" size={22} stroke={2.5}/>
 </div>
 <div>
 <strong style={{fontSize:16,fontFamily:'var(--font-display)'}}>Item reserved on lay-bye</strong>
 <div style={{fontSize:13,color:'var(--ink-700)',marginTop:2}}>
 Deposit of R {each.toLocaleString('en-ZA')} taken. We hold the item for you. It ships once paid in full.
 </div>
 </div>
 </div>
 </div>
 );
 }

 return (
 <div style={{...panelStyle,marginTop:0,background:'var(--brand-orange-50)',borderColor:'var(--brand-orange-100)'}}>
 <h3 style={{margin:'0 0 4px',fontSize:16,fontFamily:'var(--font-display)'}}>Reserve on lay-bye</h3>
 <p style={{margin:'0 0 14px',fontSize:13,color:'var(--ink-700)'}}>
 Pay a deposit today, then weekly instalments. The item ships once it is paid in full.
 </p>
 <div style={{background:'var(--paper)',borderRadius:'var(--radius-md)',padding:'4px 14px',marginBottom:14}}>
 {schedule.map((s,i) => (
 <div key={i} style={{display:'flex',justifyContent:'space-between',alignItems:'center',
 padding:'10px 0',borderBottom: i < schedule.length-1 ? '1px solid var(--ink-100)' : 'none',
 fontFamily:'var(--font-body)',fontSize:14}}>
 <span style={{color: i === 0 ? 'var(--ink-900)' : 'var(--ink-700)',fontWeight: i === 0 ? 700 : 400}}>{s.label}</span>
 <span style={{fontFamily:'var(--font-display)',fontWeight:700}}>R {s.amount.toLocaleString('en-ZA')}</span>
 </div>
 ))}
 </div>
 <label style={{display:'flex',alignItems:'flex-start',gap:10,marginBottom:14,cursor:'pointer',
 fontFamily:'var(--font-body)',fontSize:13,color:'var(--ink-700)',lineHeight:1.45}}>
 <input type="checkbox" checked={agreed} onChange={toggleAck}
 style={{accentColor:'var(--brand-orange)',marginTop:2,width:18,height:18,flexShrink:0}}/>
 <span>
 I understand that if I miss instalments my deposit may be forfeited under the lay-bye terms, and the item is only released once paid in full.
 {ackAt && <span style={{display:'block',marginTop:4,fontFamily:'var(--font-mono)',fontSize:11,color:'var(--ink-500)'}}>Acknowledged {ackAt}</span>}
 </span>
 </label>
 <button onClick={() => { setReserved(true); if (onReserve) onReserve(); }} disabled={!agreed}
 style={{...btnPrimary,width:'100%',justifyContent:'center',padding:'14px',
 opacity: agreed ? 1 : 0.5,cursor: agreed ? 'pointer' : 'not-allowed'}}>
 <Icon name="shield-check" size={18}/> Start lay-bye - pay deposit R {each.toLocaleString('en-ZA')}
 </button>
 </div>
 );
}

/* --- Auction / Bid panel: countdown, current bid, place bid --- */
function AuctionPanel({ product }) {
 const a = product.auction;
 const [remaining, setRemaining] = useState(a ? a.endsInMs : 0);
 const [currentBid, setCurrentBid] = useState(a ? a.currentBid : 0);
 const [bids, setBids] = useState(a ? a.bids : 0);
 const [won, setWon] = useState(false);
 const minNext = currentBid + (a ? a.minIncrement : 50);
 const [bidValue, setBidValue] = useState(minNext);
 const [error, setError] = useState('');

 useEffect(() => {
 if (won || remaining <= 0) return;
 const t = setInterval(() => setRemaining(r => Math.max(0, r - 1000)), 1000);
 return () => clearInterval(t);
 }, [won, remaining]);

 const ended = remaining <= 0;

 const fmt = (ms) => {
 const total = Math.floor(ms / 1000);
 const h = String(Math.floor(total / 3600)).padStart(2,'0');
 const m = String(Math.floor((total % 3600) / 60)).padStart(2,'0');
 const s = String(total % 60).padStart(2,'0');
 return `${h}:${m}:${s}`;
 };

 const placeBid = () => {
 const v = Number(bidValue);
 if (!v || v < minNext) { setError(`Your bid must be at least R ${minNext.toLocaleString('en-ZA')}.`); return; }
 setError('');
 setCurrentBid(v);
 setBids(b => b + 1);
 setBidValue(v + (a ? a.minIncrement : 50));
 // Simulate the auction closing in your favour shortly after you take the lead
 setRemaining(4000);
 setTimeout(() => setWon(true), 4200);
 };

 if (won) {
 return (
 <div style={{...panelStyle,marginTop:0,background:'var(--success-100)',borderColor:'var(--success)'}}>
 <div style={{display:'flex',alignItems:'center',gap:12}}>
 <div style={{width:44,height:44,borderRadius:999,background:'var(--success)',color:'white',
 display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
 <Icon name="gavel" size={22}/>
 </div>
 <div>
 <strong style={{fontSize:16,fontFamily:'var(--font-display)'}}>You won the auction</strong>
 <div style={{fontSize:13,color:'var(--ink-700)',marginTop:2}}>
 Winning bid R {currentBid.toLocaleString('en-ZA')}. This pays through escrow. Funds release on confirmed receipt.
 </div>
 </div>
 </div>
 </div>
 );
 }

 return (
 <div style={{...panelStyle,marginTop:0,background:'var(--brand-plum-100, #ECE6F2)',borderColor:'var(--ink-200)'}}>
 <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:14}}>
 <h3 style={{margin:0,fontSize:16,fontFamily:'var(--font-display)'}}>Live auction</h3>
 <span style={{display:'inline-flex',alignItems:'center',gap:6,padding:'6px 12px',borderRadius:999,
 background: ended ? 'var(--ink-200)' : 'var(--ink-900)',color: ended ? 'var(--ink-700)' : 'white',
 fontFamily:'var(--font-mono)',fontWeight:700,fontSize:14}}>
 <Icon name="clock" size={14}/> {ended ? 'Ended' : fmt(remaining)}
 </span>
 </div>
 <div style={{background:'var(--paper)',borderRadius:'var(--radius-md)',padding:14,marginBottom:14}}>
 <div style={{display:'flex',justifyContent:'space-between',alignItems:'baseline',marginBottom:4}}>
 <span style={{fontSize:13,color:'var(--ink-500)'}}>Current bid</span>
 <span style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:24}}>R {currentBid.toLocaleString('en-ZA')}</span>
 </div>
 <div style={{fontSize:12,color:'var(--ink-500)'}}>{bids} bids - top bidder {a ? a.topBidder : ''}</div>
 </div>
 {ended ? (
 <div style={{background:'var(--ink-100)',borderRadius:'var(--radius-md)',padding:14,fontSize:13,color:'var(--ink-700)',textAlign:'center'}}>
 This auction has closed. The highest bidder pays through escrow.
 </div>
 ) : (
 <>
 <label style={{display:'block',fontFamily:'var(--font-body)',fontWeight:700,fontSize:13,color:'var(--ink-700)',marginBottom:6}}>
 Your bid (R) - minimum R {minNext.toLocaleString('en-ZA')}
 </label>
 <div style={{display:'flex',gap:8}}>
 <input type="number" value={bidValue} min={minNext} onChange={e => setBidValue(e.target.value)}
 style={{flex:1,padding:'13px 14px',border:'1.5px solid var(--ink-200)',borderRadius:'var(--radius-sm)',
 fontFamily:'var(--font-body)',fontSize:15,boxSizing:'border-box',background:'var(--paper)'}}/>
 <button onClick={placeBid} style={{...btnPrimary,padding:'12px 18px'}}>
 <Icon name="gavel" size={18}/> Place bid
 </button>
 </div>
 {error && <div style={{fontFamily:'var(--font-body)',fontSize:12,color:'var(--danger)',fontWeight:600,marginTop:8}}>{error}</div>}
 </>
 )}
 <div style={{background:'var(--success-100)',borderRadius:'var(--radius-md)',padding:'10px 14px',marginTop:14,
 fontSize:12,color:'var(--status-paid-fg)',display:'flex',gap:8,alignItems:'start'}}>
 <Icon name="shield-check" size={16} stroke={2}/>
 <span>Winning bid pays through escrow. Funds released on confirmed receipt.</span>
 </div>
 </div>
 );
}

/* --- PDP --- */
function ProductDetail({ product, onBack, onAddToCart, onSwap, onWatch, watched }) {
 if (!product) return null;
 const [activeImg, setActiveImg] = useState(0);
 const [showShare, setShowShare] = useState(false);
 const [payMode, setPayMode] = useState('buy');
 const hasTabs = product.laybye || product.auction;
 // Simulate multiple images by using same emoji with different bg tints
 const images = [
 product.bg,
 `linear-gradient(135deg, var(--ink-100), var(--brand-orange-50))`,
 `linear-gradient(135deg, var(--brand-orange-100), var(--ink-50))`,
 product.bg,
 ];
 const reviews = [
 { buyer:'Thandi K.', stars:5, comment:'Exactly as described. Fast delivery!', date:'2 days ago' },
 { buyer:'James R.', stars:5, comment:'Great seller, very responsive on WhatsApp.', date:'1 week ago' },
 { buyer:'Siya N.', stars:4, comment:'Good condition, minor scratch not in photos but ok.', date:'2 weeks ago' },
 ];
 const moreFromSeller = PRODUCTS.filter(p => p.seller === product.seller && p.id !== product.id).slice(0,3);

 return (
 <div>
 <button onClick={onBack} style={{...btnSmall,border:'none',color:'var(--ink-500)',padding:'8px 0',marginBottom:12}}>
 <Icon name="arrow-left" size={16}/> Back to listings
 </button>
 {product.sellerOnVacation && (
 <div style={{...panelStyle,background:'var(--warning-100)',borderColor:'var(--warning)',display:'flex',gap:10,alignItems:'start'}}>
 <Icon name="umbrella" size={18} stroke={2}/>
 <div style={{fontSize:13,color:'var(--ink-700)'}}>
 <strong style={{display:'block',fontFamily:'var(--font-display)',fontSize:14}}>Shop on a short break</strong>
 {product.seller} is away until <strong>{product.vacationUntil}</strong>. You can save this listing and watch it for updates. Buy now is paused.
 </div>
 </div>
 )}
 <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:32}}>
 {/* Image gallery */}
 <div>
 <div style={{aspectRatio:'1',borderRadius:'var(--radius-lg)',
 backgroundImage:'url(assets/me2you.jpg)',backgroundSize:'cover',backgroundPosition:'center',
 border:'1px solid var(--ink-200)',position:'relative',overflow:'hidden'}}>
 <div style={{position:'absolute',top:16,left:16,
 background:'rgba(255,255,255,.92)',backdropFilter:'blur(8px)',
 padding:'6px 14px',borderRadius:999,fontSize:13,fontWeight:700,
 fontFamily:'var(--font-body)',color:'var(--ink-700)',
 display:'inline-flex',alignItems:'center',gap:6}}>
 <span style={{fontSize:18}}>{product.emoji}</span> {product.title.split(' ').slice(0,3).join(' ')}
 </div>
 <button onClick={() => setActiveImg(i => (i - 1 + images.length) % images.length)}
 style={{position:'absolute',left:12,top:'50%',transform:'translateY(-50%)',
 width:40,height:40,borderRadius:999,background:'rgba(255,255,255,.9)',backdropFilter:'blur(8px)',
 border:'none',cursor:'pointer',display:'flex',alignItems:'center',justifyContent:'center'}}>
 <Icon name="arrow-left" size={18}/>
 </button>
 <button onClick={() => setActiveImg(i => (i + 1) % images.length)}
 style={{position:'absolute',right:12,top:'50%',transform:'translateY(-50%)',
 width:40,height:40,borderRadius:999,background:'rgba(255,255,255,.9)',backdropFilter:'blur(8px)',
 border:'none',cursor:'pointer',display:'flex',alignItems:'center',justifyContent:'center'}}>
 <Icon name="arrow-right" size={18}/>
 </button>
 <div style={{position:'absolute',bottom:16,left:'50%',transform:'translateX(-50%)',
 background:'rgba(0,0,0,.5)',color:'white',padding:'4px 10px',borderRadius:999,
 fontFamily:'var(--font-mono)',fontSize:11,fontWeight:600}}>
 {activeImg+1} / {images.length}
 </div>
 </div>
 <div style={{display:'flex',gap:8,marginTop:12}}>
 {images.map((bg,i) => (
 <button key={i} onClick={() => setActiveImg(i)}
 style={{width:64,height:64,borderRadius:10,backgroundImage:'url(assets/me2you.jpg)',backgroundSize:'cover',backgroundPosition:'center',
 border: activeImg === i ? '2px solid var(--brand-orange)' : '1px solid var(--ink-200)',
 cursor:'pointer',transition:'all .15s',flexShrink:0}}/>
 ))}
 </div>
 </div>

 <div>
 <CondTag condition={product.condition}/>
 <h1 style={{margin:'12px 0 8px'}}>{product.title}</h1>
 <div style={{fontFamily:'var(--font-body)',color:'var(--ink-500)',fontSize:14,marginBottom:16,
 display:'flex',alignItems:'center',gap:6,flexWrap:'wrap'}}>
 <Icon name="map-pin" size={14}/> {product.location}
 <span> - </span>
 <span> {product.rating} ({product.reviews} reviews)</span>
 </div>
 <div style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:42,marginBottom:24,color:'var(--ink-900)'}}>
 <span style={{fontWeight:600,opacity:.65,fontSize:24}}>R </span>{product.price.toLocaleString('en-ZA')}
 </div>
 <div style={{background:'var(--success-100)',padding:'12px 16px',borderRadius:'var(--radius-md)',
 display:'flex',alignItems:'center',gap:10,marginBottom:16}}>
 <Icon name="shield-check" size={20} stroke={2}/>
 <span style={{fontFamily:'var(--font-body)',fontSize:14,color:'var(--status-paid-fg)',fontWeight:600}}>
 Paid through Me2You - your money is safe until you confirm receipt.
 </span>
 </div>
 <p style={{fontFamily:'var(--font-body)',fontSize:15,color:'var(--ink-700)',lineHeight:1.55}}>
 Excellent condition, used for about a year. Original packaging included. Pickup or courier - your choice.
 </p>
 {/* Pay-mode tabs: Buy / Lay-bye / Bid (only for eligible listings) */}
 {hasTabs && (
 <div style={{display:'flex',gap:2,padding:4,background:'var(--ink-100)',borderRadius:999,marginBottom:16,width:'fit-content'}}>
 {[
 { key:'buy', label:'Buy now' },
 product.laybye && { key:'laybye', label:'Lay-bye' },
 product.auction && { key:'bid', label:'Bid' },
 ].filter(Boolean).map(t => (
 <button key={t.key} onClick={() => setPayMode(t.key)} style={{
 padding:'8px 18px',borderRadius:999,border:'none',cursor:'pointer',minHeight:36,
 fontFamily:'var(--font-body)',fontWeight:600,fontSize:14,
 background: payMode === t.key ? 'var(--paper)' : 'transparent',
 color: payMode === t.key ? 'var(--ink-900)' : 'var(--ink-500)',
 boxShadow: payMode === t.key ? 'var(--shadow-xs)' : 'none',transition:'all .15s'
 }}>{t.label}</button>
 ))}
 </div>
 )}

 {hasTabs && payMode === 'laybye' && <LaybyePanel product={product}/>}
 {hasTabs && payMode === 'bid' && <AuctionPanel product={product}/>}

 {(!hasTabs || payMode === 'buy') && (
 <div style={{display:'flex',gap:12,marginTop:24,flexWrap:'wrap'}}>
 <button onClick={() => onAddToCart(product)} disabled={product.sellerOnVacation}
 style={{...btnPrimary,opacity: product.sellerOnVacation ? 0.55 : 1,cursor: product.sellerOnVacation ? 'not-allowed' : 'pointer'}}>
 <Icon name="shopping-bag" size={18}/> {product.sellerOnVacation ? 'Buy now - paused' : 'Add to cart'}
 </button>
 <button onClick={() => onWatch && onWatch(product.id)} style={{...btnGhost,color: watched ? 'var(--brand-orange-700)' : 'var(--ink-900)',
 borderColor: watched ? 'var(--brand-orange)' : 'var(--ink-300)'}}>
 <Icon name="eye" size={18} fill={watched ? 'currentColor' : 'none'}/> {watched ? 'Watching' : 'Watch'}
 </button>
 <button onClick={() => onSwap && onSwap(product)} style={btnGhost}>
 <Icon name="arrow-left-right" size={18}/> Propose a swap
 </button>
 <button onClick={() => setShowShare(!showShare)} style={{...btnGhost,position:'relative'}}>
 <Icon name="share-2" size={18}/> Share
 </button>
 {showShare && (
 <div style={{position:'absolute',marginTop:48,...panelStyle,padding:8,zIndex:5,minWidth:200,
 boxShadow:'var(--shadow-lg)',animation:'pop .2s ease'}}>
 {[
 { label:'WhatsApp', icon:'message-circle', color:'#25D366' },
 { label:'Copy link', icon:'tag', color:'var(--ink-700)' },
 { label:'SMS', icon:'phone', color:'var(--info)' },
 ].map(opt => (
 <button key={opt.label} style={{display:'flex',alignItems:'center',gap:10,padding:'10px 12px',width:'100%',
 background:'none',border:'none',cursor:'pointer',borderRadius:8,
 fontFamily:'var(--font-body)',fontSize:14,fontWeight:600,color:'var(--ink-700)',textAlign:'left'}}
 onMouseEnter={e => e.currentTarget.style.background='var(--ink-50)'}
 onMouseLeave={e => e.currentTarget.style.background='none'}>
 <Icon name={opt.icon} size={18} stroke={2}/> {opt.label}
 </button>
 ))}
 </div>
 )}
 </div>
 )}

 {/* Seller card */}
 <div style={{...panelStyle,marginTop:24,display:'flex',alignItems:'center',gap:12}}>
 <div style={{width:48,height:48,borderRadius:999,background:'var(--brand-orange-100)',
 display:'flex',alignItems:'center',justifyContent:'center',fontFamily:'var(--font-display)',
 fontWeight:700,fontSize:18,color:'var(--brand-orange-700)'}}>
 {product.seller.charAt(0)}
 </div>
 <div style={{flex:1}}>
 <div style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:15}}>{product.seller}</div>
 <div style={{fontSize:12,color:'var(--ink-500)'}}><span style={{color:'var(--brand-orange)'}}>★</span> {product.rating} - Joined Mar 2025</div>
 </div>
 <button style={{...btnSmall,fontSize:12}}>View profile</button>
 </div>
 </div>
 </div>

 {/* Reviews */}
 <section style={{marginTop:48}}>
 <div style={{display:'flex',justifyContent:'space-between',alignItems:'baseline',marginBottom:16}}>
 <h2>Reviews ({product.reviews})</h2>
 <span style={{fontSize:14,color:'var(--ink-500)'}}><span style={{color:'var(--brand-orange)'}}>★</span> {product.rating} average</span>
 </div>
 <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(260px,1fr))',gap:12}}>
 {reviews.map((r,i) => (
 <div key={i} style={{...panelStyle,marginBottom:0}}>
 <div style={{display:'flex',justifyContent:'space-between',alignItems:'baseline',marginBottom:6}}>
 <strong style={{fontSize:14}}>{r.buyer}</strong>
 <span style={{color:'var(--brand-orange)',fontSize:13,display:'inline-flex',gap:2}}>
                  {[1,2,3,4,5].map(n => <Icon key={n} name="star" size={12} fill={n <= r.stars ? 'currentColor' : 'none'}/>)}
                </span>
 </div>
 <p style={{fontSize:13,color:'var(--ink-700)',margin:0,lineHeight:1.5}}>{r.comment}</p>
 <div style={{fontSize:11,color:'var(--ink-400)',marginTop:6}}>{r.date}</div>
 </div>
 ))}
 </div>
 </section>

 {/* More from this seller */}
 {moreFromSeller.length > 0 && (
 <section style={{marginTop:48}}>
 <h2 style={{marginBottom:16}}>More from {product.seller}</h2>
 <div style={{display:'grid',gridTemplateColumns:'repeat(auto-fill,minmax(220px,1fr))',gap:16}}>
 {moreFromSeller.map(p => <ProductCard key={p.id} product={p} onClick={() => {}}/>)}
 </div>
 </section>
 )}
 </div>
 );
}

/* --- Cart --- */
function CartView({ cart, onUpdateQty, onRemove, onCheckout, onBrowse }) {
 if (cart.length === 0) return (
 <EmptyState icon="shopping-bag" title="Your cart's empty" subtitle="Pop something nice in here." action="Browse listings" onAction={onBrowse}/>
 );
 const subtotal = cart.reduce((s,i) => s + i.product.price * i.qty, 0);
 const delivery = 60;
 return (
 <div style={{maxWidth:720,margin:'0 auto'}}>
 <h1 style={{marginBottom:24}}>Your cart</h1>
 <div style={{...panelStyle,padding:0,overflow:'hidden'}}>
 {cart.map(i => (
 <div key={i.product.id} style={{display:'grid',gridTemplateColumns:'72px 1fr auto auto',gap:16,
 padding:16,borderBottom:'1px solid var(--ink-100)',alignItems:'center'}}>
 <div style={{width:72,height:72,borderRadius:12,backgroundImage:'url(assets/me2you.jpg)',backgroundSize:'cover',backgroundPosition:'center',flexShrink:0}}/>
 <div>
 <div style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:15}}>{i.product.title}</div>
 <div style={{fontFamily:'var(--font-body)',fontSize:12,color:'var(--ink-500)'}}>From {i.product.seller}, {i.product.location}</div>
 </div>
 <div style={{display:'flex',alignItems:'center',gap:8}}>
 <button onClick={() => onUpdateQty(i.product.id, -1)} style={{width:28,height:28,borderRadius:8,border:'1px solid var(--ink-200)',background:'var(--paper)',cursor:'pointer',display:'flex',alignItems:'center',justifyContent:'center'}}>
 <Icon name="minus" size={14}/>
 </button>
 <span style={{fontFamily:'var(--font-mono)',fontSize:14,minWidth:20,textAlign:'center'}}>{i.qty}</span>
 <button onClick={() => onUpdateQty(i.product.id, 1)} style={{width:28,height:28,borderRadius:8,border:'1px solid var(--ink-200)',background:'var(--paper)',cursor:'pointer',display:'flex',alignItems:'center',justifyContent:'center'}}>
 <Icon name="plus" size={14}/>
 </button>
 </div>
 <div style={{textAlign:'right'}}>
 <Price amount={i.product.price * i.qty}/>
 <button onClick={() => onRemove(i.product.id)} style={{display:'block',marginTop:4,background:'none',border:'none',cursor:'pointer',color:'var(--danger)',fontSize:12,fontWeight:600,fontFamily:'var(--font-body)'}}>Remove</button>
 </div>
 </div>
 ))}
 </div>
 <div style={{...panelStyle,marginTop:16}}>
 <SummaryRow label="Subtotal" value={`R ${subtotal.toLocaleString('en-ZA')}`}/>
 <SummaryRow label="Standard delivery" value={`R ${delivery}`}/>
 <div style={{display:'flex',justifyContent:'space-between',fontFamily:'var(--font-body)',fontSize:18,fontWeight:700,paddingTop:12,borderTop:'1px solid var(--ink-200)',marginTop:8}}>
 <span>Total</span><span>R {(subtotal + delivery).toLocaleString('en-ZA')}</span>
 </div>
 <button onClick={onCheckout} style={{...btnPrimary,width:'100%',marginTop:16,padding:'16px',justifyContent:'center'}}>
 <Icon name="shield-check" size={18}/> Proceed to safe checkout
 </button>
 </div>
 </div>
 );
}

function SummaryRow({ label, value }) {
 return (
 <div style={{display:'flex',justifyContent:'space-between',fontFamily:'var(--font-body)',fontSize:14,padding:'8px 0',color:'var(--ink-700)'}}>
 <span>{label}</span><span>{value}</span>
 </div>
 );
}

/* --- Checkout --- */
function CheckoutView({ cart, onSuccess }) {
 const [delivery, setDelivery] = useState('pickup');
 const [tip, setTip] = useState(10);
 const [radius, setRadius] = useState(8);
 const subtotal = cart.reduce((s,i) => s + i.product.price * i.qty, 0);

 // Distance-based pricing for door-to-door driver
 const calcDoorPrice = (km) => {
 const base = 25;
 const perKm = 5;
 const surge = km > 20 ? Math.ceil((km - 20) / 5) * 10 : 0;
 return base + Math.round(km * perKm) + surge;
 };
 const doorPrice = calcDoorPrice(radius);
 const pickupPrice = 30;
 const deliveryCost = delivery === 'door' ? doorPrice : delivery === 'pickup' ? pickupPrice : 0;
 const total = subtotal + deliveryCost + tip;

 return (
 <div style={{maxWidth:720,margin:'0 auto'}}>
 <h1 style={{marginBottom:8}}>Checkout</h1>
 <p style={{color:'var(--ink-500)',marginBottom:24,fontSize:14}}>Shipping, delivery and payment</p>

 <div style={panelStyle}>
 <h3 style={{margin:'0 0 16px',fontSize:18}}>Where should we send it?</h3>
 <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
 <Field label="Full name" value="Nomsa Mthembu" icon="user-round"/>
 <Field label="Phone" value="071 234 5678" icon="phone"/>
 <Field label="Street address" value="42 Vilakazi St" full icon="map-pin"/>
 <Field label="City" value="Soweto"/>
 <Field label="Province" value="Gauteng"/>
 </div>
 </div>

 <div style={panelStyle}>
 <h3 style={{margin:'0 0 12px',fontSize:18}}>How do you want it?</h3>
 {[
 { key:'pickup', icon:'map-pin', title:'Pickup point', desc:`Collect from your nearest PEP / Pargo / Paxi. R ${pickupPrice}.`, price: pickupPrice },
 { key:'door', icon:'truck', title:'Driver to your door', desc:`Distance-based. Currently R ${doorPrice} for ${radius} km.`, price: doorPrice },
 { key:'self', icon:'user-round', title:'Self-collect with OTP', desc:'Meet seller, inspect, release with 6-digit code. Free.', price: 0 },
 ].map(opt => (
 <div key={opt.key} onClick={() => setDelivery(opt.key)} style={{
 display:'flex',gap:12,padding:14,borderRadius:'var(--radius-md)',cursor:'pointer',
 border: '1.5px solid ' + (delivery === opt.key ? 'var(--brand-orange)' : 'var(--ink-200)'),
 background: delivery === opt.key ? 'var(--brand-orange-50)' : 'transparent',marginBottom:8,
 transition:'all .15s ease'
 }}>
 <div style={{width:40,height:40,borderRadius:10,background:'var(--paper)',
 display:'flex',alignItems:'center',justifyContent:'center',
 color:'var(--brand-orange-700)',border:'1px solid var(--ink-200)'}}>
 <Icon name={opt.icon} size={20}/>
 </div>
 <div style={{flex:1}}>
 <div style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:14}}>{opt.title}</div>
 <div style={{fontFamily:'var(--font-body)',fontSize:12,color:'var(--ink-500)',marginTop:2}}>{opt.desc}</div>
 </div>
 <div style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:15,minWidth:50,textAlign:'right'}}>{opt.price === 0 ? 'Free' : `R ${opt.price}`}</div>
 </div>
 ))}

 {delivery === 'door' && (
 <div style={{marginTop:12,padding:16,background:'var(--brand-orange-50)',borderRadius:'var(--radius-md)',border:'1px solid var(--brand-orange-100)'}}>
 <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:8}}>
 <strong style={{fontSize:13,fontFamily:'var(--font-body)',color:'var(--brand-orange-700)'}}>Distance from seller</strong>
 <span style={{fontFamily:'var(--font-mono)',fontWeight:700,fontSize:14}}>{radius} km</span>
 </div>
 <input type="range" min={2} max={40} step={1} value={radius} onChange={e => setRadius(+e.target.value)}
 style={{width:'100%',accentColor:'var(--brand-orange)'}}/>
 <div style={{display:'flex',justifyContent:'space-between',fontSize:11,color:'var(--ink-500)',marginTop:4}}>
 <span>2 km - R {calcDoorPrice(2)}</span>
 <span>20 km - R {calcDoorPrice(20)}</span>
 <span>40 km - R {calcDoorPrice(40)}</span>
 </div>
 <div style={{marginTop:10,padding:10,background:'var(--paper)',borderRadius:8,fontSize:12,color:'var(--ink-700)',display:'flex',gap:8,alignItems:'start'}}>
 <Icon name="truck" size={14} stroke={2}/>
 <div>
 <strong>R 25 base + R 5/km</strong>{radius > 20 ? <span style={{color:'var(--brand-orange-700)'}}> + R {Math.ceil((radius - 20)/5)*10} long-distance surcharge</span> : ''}.
 100% of the delivery fee goes to your driver.
 </div>
 </div>
 </div>
 )}
 </div>

 <div style={panelStyle}>
 <h3 style={{margin:'0 0 12px',fontSize:18}}>Tip your driver <span style={{fontSize:13,fontWeight:400,color:'var(--ink-500)'}}>(optional, 100% to driver)</span></h3>
 <div style={{display:'flex',gap:8}}>
 {[0,5,10,20].map(t => (
 <button key={t} onClick={() => setTip(t)} style={{
 padding:'10px 18px',borderRadius:'var(--radius-pill)',cursor:'pointer',
 fontFamily:'var(--font-body)',fontWeight:600,fontSize:14,
 background: tip===t ? 'var(--ink-900)' : 'var(--paper)',
 color: tip===t ? 'white' : 'var(--ink-900)',
 border: '1.5px solid ' + (tip===t ? 'var(--ink-900)' : 'var(--ink-200)'),
 }}>{t === 0 ? 'No tip' : `R ${t}`}</button>
 ))}
 </div>
 </div>

 <div style={panelStyle}>
 <h3 style={{margin:'0 0 4px',fontSize:18}}>Pay safely with PayFast</h3>
 <p style={{margin:'0 0 16px',color:'var(--ink-500)',fontSize:13}}>EFT, card, or mobile. We hold your money until you confirm receipt.</p>
 <Field label="Card number" value="4242 4242 4242 4242" full icon="wallet"/>
 <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12,marginTop:12}}>
 <Field label="Expiry" value="08 / 28"/>
 <Field label="CVV" value="123" type="password"/>
 </div>
 </div>

 <div style={{...panelStyle,padding:16,background:'var(--ink-50)'}}>
 <div style={{display:'flex',justifyContent:'space-between',fontSize:13,marginBottom:6}}>
 <span style={{color:'var(--ink-500)'}}>Subtotal</span><span>R {subtotal.toLocaleString('en-ZA')}</span>
 </div>
 <div style={{display:'flex',justifyContent:'space-between',fontSize:13,marginBottom:6}}>
 <span style={{color:'var(--ink-500)'}}>Delivery ({delivery === 'door' ? `${radius} km` : delivery})</span><span>R {deliveryCost}</span>
 </div>
 {tip > 0 && <div style={{display:'flex',justifyContent:'space-between',fontSize:13,marginBottom:6}}>
 <span style={{color:'var(--ink-500)'}}>Driver tip</span><span>R {tip}</span>
 </div>}
 <div style={{display:'flex',justifyContent:'space-between',fontSize:16,fontWeight:700,paddingTop:8,borderTop:'1px solid var(--ink-200)',marginTop:6}}>
 <span>Total</span><span>R {total.toLocaleString('en-ZA')}</span>
 </div>
 </div>

 <button onClick={() => onSuccess(delivery)} style={{...btnPrimary,width:'100%',padding:'16px',fontSize:16,justifyContent:'center'}}>
 <Icon name="shield-check" size={20}/> Pay R {total.toLocaleString('en-ZA')} safely
 </button>
 </div>
 );
}

/* --- Order Success --- */
function OrderSuccess({ onContinue, onConfirmCollect }) {
 return (
 <div style={{maxWidth:720,margin:'0 auto',textAlign:'center'}}>
 <div style={{width:80,height:80,borderRadius:999,background:'var(--success-100)',
 color:'var(--success)',display:'inline-flex',alignItems:'center',justifyContent:'center',marginBottom:24,
 animation:'pop .4s cubic-bezier(.2,.7,.3,1)'}}>
 <Icon name="check" size={40} stroke={2.5}/>
 </div>
 <h1>You're paid up.</h1>
 <p style={{color:'var(--ink-500)',fontSize:17,maxWidth:480,margin:'12px auto 24px'}}>
 We've let the seller know. They have 3 days to dispatch your order.
 </p>
 <div style={{...panelStyle,textAlign:'left'}}>
 <div style={{display:'flex',justifyContent:'space-between',marginBottom:16}}>
 <div>
 <div style={{fontFamily:'var(--font-mono)',fontSize:11,color:'var(--ink-500)',textTransform:'uppercase',letterSpacing:'.08em'}}>Order reference</div>
 <div style={{fontFamily:'var(--font-mono)',fontSize:16,fontWeight:600,marginTop:4}}>M2Y-2026-00248</div>
 </div>
 <StatusTag status="Paid"/>
 </div>
 <OrderStepper current="Paid"/>
 </div>
 <div style={{display:'flex',gap:12,justifyContent:'center',marginTop:24,flexWrap:'wrap'}}>
 {onConfirmCollect && (
 <button onClick={onConfirmCollect} style={btnPrimary}>
 <Icon name="lock" size={18}/> Confirm collection with OTP
 </button>
 )}
 <button onClick={onContinue} style={btnGhost}>Continue shopping</button>
 </div>
 </div>
 );
}

/* --- Orders List --- */
function OrdersList({ orders, onTrack }) {
 return (
 <div style={{maxWidth:800,margin:'0 auto'}}>
 <h1 style={{marginBottom:24}}>Your orders</h1>
 {orders.map(o => (
 <div key={o.id} onClick={() => onTrack && onTrack(o)}
 style={{...panelStyle,display:'grid',gridTemplateColumns:'60px 1fr auto',gap:16,alignItems:'center',cursor:'pointer',transition:'box-shadow .15s'}}
 onMouseEnter={e => e.currentTarget.style.boxShadow='var(--shadow-md)'}
 onMouseLeave={e => e.currentTarget.style.boxShadow='none'}>
 <div style={{width:60,height:60,borderRadius:12,backgroundImage:'url(assets/me2you.jpg)',backgroundSize:'cover',backgroundPosition:'center'}}/>
 <div>
 <div style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:15}}>{o.product.title}</div>
 <div style={{fontFamily:'var(--font-mono)',fontSize:11,color:'var(--ink-500)',marginTop:2}}>{o.id} - {o.date}</div>
 </div>
 <div style={{textAlign:'right'}}>
 <StatusTag status={o.status}/>
 <div style={{marginTop:6}}><Price amount={o.total} size="sm"/></div>
 </div>
 </div>
 ))}
 </div>
 );
}

/* --- Dispute Form --- */
function DisputeForm({ onBack }) {
 const [submitted, setSubmitted] = useState(false);
 const [reason, setReason] = useState('');
 const [chatInput, setChatInput] = useState('');
 const [messages, setMessages] = useState([
 { from:'admin', name:'Marco (Admin)', text:"Hi, we've received your dispute. Can you share photos of the issue?", time:'just now' },
 ]);

 const send = () => {
 if (!chatInput.trim()) return;
 setMessages(prev => [...prev, { from:'me', name:'You', text:chatInput, time:'now' }]);
 setChatInput('');
 // Simulate admin response
 setTimeout(() => {
 setMessages(prev => [...prev, { from:'admin', name:'Marco (Admin)', text:"Thanks. We'll review and respond within 24 hours.", time:'now' }]);
 }, 1500);
 };

 if (submitted) {
 return (
 <div style={{maxWidth:680,margin:'0 auto'}}>
 <button onClick={onBack} style={{...btnSmall,border:'none',color:'var(--ink-500)',padding:'8px 0',marginBottom:12}}>
 <Icon name="arrow-left" size={16}/> Back to orders
 </button>
 <div style={{...panelStyle,padding:24,background:'var(--success-100)',borderColor:'var(--success)'}}>
 <div style={{display:'flex',alignItems:'center',gap:12}}>
 <div style={{width:48,height:48,borderRadius:999,background:'var(--success)',
 color:'white',display:'flex',alignItems:'center',justifyContent:'center',flexShrink:0}}>
 <Icon name="check" size={22} stroke={2.5}/>
 </div>
 <div>
 <h2 style={{margin:'0 0 4px',fontSize:20}}>Dispute opened</h2>
 <div style={{fontSize:13,color:'var(--ink-700)'}}>
 Case <span style={{fontFamily:'var(--font-mono)',fontWeight:700}}>DSP-2026-0142</span> - Funds frozen in escrow
 </div>
 </div>
 </div>
 </div>

 <div style={panelStyle}>
 <h3 style={{fontSize:16,margin:'0 0 12px'}}>What happens next</h3>
 <div style={{display:'flex',flexDirection:'column',gap:10,fontSize:14}}>
 {[
 { icon:'shield-check', text:'Escrow funds are frozen until resolved', done:true },
 { icon:'message-circle', text:'Admin contacts both parties within 24 hours', done:false },
 { icon:'check-circle', text:'Resolution: refund, release, or partial', done:false },
 ].map((step,i) => (
 <div key={i} style={{display:'flex',alignItems:'center',gap:10,color: step.done ? 'var(--ink-900)' : 'var(--ink-500)'}}>
 <div style={{width:28,height:28,borderRadius:999,flexShrink:0,
 background: step.done ? 'var(--success-100)' : 'var(--ink-100)',
 color: step.done ? 'var(--success)' : 'var(--ink-400)',
 display:'flex',alignItems:'center',justifyContent:'center'}}>
 <Icon name={step.icon} size={14}/>
 </div>
 {step.text}
 </div>
 ))}
 </div>
 </div>

 {/* Live admin chat */}
 <div style={{...panelStyle,padding:0,overflow:'hidden'}}>
 <div style={{padding:'12px 16px',borderBottom:'1px solid var(--ink-100)',display:'flex',alignItems:'center',gap:10,background:'var(--ink-50)'}}>
 <div style={{width:32,height:32,borderRadius:999,background:'var(--brand-plum-100)',
 display:'flex',alignItems:'center',justifyContent:'center',color:'var(--brand-plum)'}}>
 <Icon name="shield-check" size={16}/>
 </div>
 <div>
 <strong style={{fontSize:13}}>Me2You Support</strong>
 <div style={{fontSize:11,color:'var(--success)',display:'flex',alignItems:'center',gap:4}}>
 <span style={{width:6,height:6,borderRadius:999,background:'var(--success)'}}/> Usually replies in 2 hours
 </div>
 </div>
 </div>
 <div style={{padding:16,maxHeight:280,overflow:'auto',display:'flex',flexDirection:'column',gap:8}}>
 {messages.map((m,i) => (
 <div key={i} style={{display:'flex',justifyContent: m.from === 'me' ? 'flex-end' : 'flex-start'}}>
 <div style={{maxWidth:'75%'}}>
 <div style={{fontSize:11,color:'var(--ink-500)',marginBottom:2,
 textAlign: m.from === 'me' ? 'right' : 'left'}}>{m.name}</div>
 <div style={{padding:'10px 14px',
 borderRadius: m.from === 'me' ? '16px 16px 4px 16px' : '16px 16px 16px 4px',
 background: m.from === 'me' ? 'var(--brand-orange)' : 'var(--ink-100)',
 color: m.from === 'me' ? 'white' : 'var(--ink-900)',
 fontSize:14,lineHeight:1.4}}>{m.text}</div>
 </div>
 </div>
 ))}
 </div>
 <div style={{padding:12,borderTop:'1px solid var(--ink-100)',display:'flex',gap:8}}>
 <input value={chatInput} onChange={e => setChatInput(e.target.value)}
 onKeyDown={e => e.key === 'Enter' && send()}
 placeholder="Message support..."
 style={{flex:1,padding:'10px 14px',border:'1.5px solid var(--ink-200)',borderRadius:'var(--radius-pill)',
 fontFamily:'var(--font-body)',fontSize:14}}/>
 <button onClick={send} style={{...btnPrimary,padding:'10px 14px'}}>
 <Icon name="arrow-right" size={16}/>
 </button>
 </div>
 </div>

 <div style={{...panelStyle,background:'var(--info-100)',borderColor:'var(--info)'}}>
 <div style={{display:'flex',gap:10,alignItems:'start'}}>
 <Icon name="phone" size={18}/>
 <div>
 <strong style={{fontSize:14,display:'block'}}>Need urgent help?</strong>
 <div style={{fontSize:13,color:'var(--ink-700)',marginTop:2}}>
 Call us on <strong>0860 ME 2 YOU</strong> - WhatsApp <strong>+27 71 234 5678</strong> - Mon-Fri 8am-6pm
 </div>
 </div>
 </div>
 </div>
 </div>
 );
 }

 return (
 <div style={{maxWidth:680,margin:'0 auto'}}>
 <button onClick={onBack} style={{...btnSmall,border:'none',color:'var(--ink-500)',padding:'8px 0',marginBottom:12}}>
 <Icon name="arrow-left" size={16}/> Back to orders
 </button>
 <h1 style={{marginBottom:8}}>Something not right?</h1>
 <p style={{color:'var(--ink-500)',marginBottom:24}}>We've got you. Tell us what happened and our team will be in touch within 24 hours.</p>

 <div style={panelStyle}>
 <h3 style={{fontSize:16,margin:'0 0 12px'}}>Order details</h3>
 <Field label="Order reference" value="M2Y-2026-00248" full/>
 <div style={{marginTop:12}}>
 <label style={{display:'block',fontFamily:'var(--font-body)',fontWeight:700,fontSize:13,color:'var(--ink-700)',marginBottom:8}}>
 What went wrong?
 </label>
 <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:8,marginBottom:12}}>
 {[
 {key:'not-received', label:'Never arrived', icon:'package'},
 {key:'damaged', label:'Arrived damaged', icon:'triangle-alert'},
 {key:'wrong-item', label:'Wrong item', icon:'x'},
 {key:'fake', label:'Not as described', icon:'eye'},
 ].map(r => (
 <button key={r.key} onClick={() => setReason(r.key)} style={{
 padding:'12px',borderRadius:'var(--radius-md)',cursor:'pointer',
 border: reason===r.key ? '2px solid var(--danger)' : '1.5px solid var(--ink-200)',
 background: reason===r.key ? 'var(--danger-100)' : 'var(--paper)',
 display:'flex',alignItems:'center',gap:8,
 fontFamily:'var(--font-body)',fontWeight:600,fontSize:13,
 color: reason===r.key ? 'var(--danger)' : 'var(--ink-700)',textAlign:'left'
 }}>
 <Icon name={r.icon} size={16}/> {r.label}
 </button>
 ))}
 </div>
 <textarea rows={4} placeholder="Describe what happened - be as specific as possible..."
 style={{width:'100%',padding:14,border:'1.5px solid var(--ink-200)',borderRadius:'var(--radius-sm)',
 fontFamily:'var(--font-body)',fontSize:15,boxSizing:'border-box',resize:'vertical'}}/>
 </div>
 </div>

 <div style={panelStyle}>
 <h3 style={{fontSize:16,margin:'0 0 12px'}}>Upload evidence</h3>
 <p style={{fontSize:13,color:'var(--ink-500)',margin:'0 0 12px'}}>Photos or screenshots help us resolve disputes faster.</p>
 <div style={{border:'1.5px dashed var(--ink-300)',borderRadius:'var(--radius-md)',padding:32,textAlign:'center',color:'var(--ink-400)',cursor:'pointer'}}>
 <Icon name="image" size={28}/>
 <div style={{fontSize:13,marginTop:8,fontWeight:600}}>Tap to upload photos or video</div>
 <div style={{fontSize:11,marginTop:4}}>JPG - PNG - MP4 - up to 5 files</div>
 </div>
 </div>

 <div style={panelStyle}>
 <h3 style={{fontSize:16,margin:'0 0 12px'}}>Your contact details</h3>
 <p style={{fontSize:13,color:'var(--ink-500)',margin:'0 0 12px'}}>
 We'll reach you on these to resolve your case.
 </p>
 <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
 <Field label="Email" value="nomsa@email.co.za" icon="user-round"/>
 <Field label="Phone / WhatsApp" value="071 234 5678" icon="phone"/>
 </div>
 <label style={{display:'flex',alignItems:'center',gap:8,marginTop:12,fontSize:13,cursor:'pointer'}}>
 <input type="checkbox" defaultChecked style={{accentColor:'var(--brand-orange)'}}/>
 Allow Me2You support to contact me via WhatsApp
 </label>
 </div>

 <div style={{...panelStyle,background:'var(--warning-100)',borderColor:'var(--warning)'}}>
 <div style={{display:'flex',gap:10,alignItems:'start'}}>
 <Icon name="shield-check" size={18}/>
 <div style={{fontSize:13,color:'var(--ink-700)'}}>
 <strong>Your money is safe.</strong> Filing a dispute freezes the escrow funds. They won't be released to the seller until your case is resolved - typically within 48 hours.
 </div>
 </div>
 </div>

 <button onClick={() => setSubmitted(true)} disabled={!reason}
 style={{...btnDanger,width:'100%',justifyContent:'center',padding:'14px',
 opacity: reason ? 1 : 0.5,cursor: reason ? 'pointer' : 'not-allowed'}}>
 <Icon name="triangle-alert" size={18}/> Open dispute
 </button>
 </div>
 );
}

/* --- Swap offer flow: pick your item, side-by-side, message, send, seller decision --- */
function SwapOfferFlow({ product, onBack }) {
 if (!product) return null;
 const mine = (window.BUYER_LISTINGS || []);
 const [step, setStep] = useState('compose'); // compose | sent | decision
 const [offerId, setOfferId] = useState(mine[0] ? mine[0].id : null);
 const [topUp, setTopUp] = useState('');
 const [note, setNote] = useState('');
 const offer = mine.find(m => m.id === offerId) || mine[0];

 const tile = (item, label) => (
 <div style={{textAlign:'center'}}>
 <div style={{aspectRatio:1,borderRadius:12,backgroundImage:'url(assets/me2you.jpg)',backgroundSize:'cover',backgroundPosition:'center',marginBottom:6}}/>
 <div style={{fontSize:11,color:'var(--ink-500)',fontFamily:'var(--font-body)'}}>{label}</div>
 <div style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:13}}>{item ? item.title : ''}</div>
 <div style={{fontSize:12,color:'var(--ink-700)'}}>R {item ? item.price.toLocaleString('en-ZA') : 0}</div>
 </div>
 );

 const sideBySide = (theirs, yours, theirLabel, yourLabel) => (
 <div style={{...panelStyle,marginBottom:16,display:'grid',gridTemplateColumns:'1fr auto 1fr',gap:12,alignItems:'center'}}>
 {tile(theirs, theirLabel)}
 <div style={{color:'var(--brand-orange)'}}><Icon name="arrow-left-right" size={26}/></div>
 {tile(yours, yourLabel)}
 </div>
 );

 if (step === 'sent') {
 return (
 <div style={{maxWidth:560,margin:'0 auto'}}>
 <button onClick={onBack} style={{...btnSmall,border:'none',color:'var(--ink-500)',padding:'8px 0',marginBottom:12}}>
 <Icon name="arrow-left" size={16}/> Back to listing
 </button>
 <h1 style={{marginBottom:8}}>Swap offer sent</h1>
 <p style={{color:'var(--ink-500)',marginBottom:20,fontSize:14}}>We let {product.seller} know. You will get a message when they respond.</p>
 {sideBySide(offer, product, 'You offer', 'You want')}
 {Number(topUp) > 0 && (
 <div style={{...panelStyle,display:'flex',justifyContent:'space-between',alignItems:'center',marginBottom:16}}>
 <span style={{fontSize:13,color:'var(--ink-700)'}}>Cash top-up (you pay, held in escrow)</span>
 <strong style={{fontFamily:'var(--font-display)'}}>R {Number(topUp).toLocaleString('en-ZA')}</strong>
 </div>
 )}
 {note && <div style={{...panelStyle,fontSize:13,color:'var(--ink-700)',marginBottom:16}}><strong>Your message: </strong>{note}</div>}
 <button onClick={() => setStep('decision')} style={{...btnGhost,width:'100%',justifyContent:'center'}}>
 <Icon name="eye" size={16}/> Preview what the seller sees
 </button>
 </div>
 );
 }

 if (step === 'decision') {
 return <SellerSwapDecision theirs={offer} yours={product} topUp={Number(topUp) || 0} onBack={onBack}/>;
 }

 return (
 <div style={{maxWidth:560,margin:'0 auto'}}>
 <button onClick={onBack} style={{...btnSmall,border:'none',color:'var(--ink-500)',padding:'8px 0',marginBottom:12}}>
 <Icon name="arrow-left" size={16}/> Back to listing
 </button>
 <h1 style={{marginBottom:8}}>Propose a swap</h1>
 <p style={{color:'var(--ink-500)',marginBottom:20,fontSize:14}}>
 Offer one of your own listings for {product.seller}'s item. Add cash to balance the deal if needed.
 </p>

 <div style={{...panelStyle,display:'grid',gridTemplateColumns:'auto 1fr',gap:12,alignItems:'center',marginBottom:16}}>
 <div style={{width:48,height:48,borderRadius:12,backgroundImage:'url(assets/me2you.jpg)',backgroundSize:'cover',backgroundPosition:'center'}}/>
 <div>
 <div style={{fontSize:11,color:'var(--ink-500)'}}>You want</div>
 <strong style={{fontFamily:'var(--font-display)',fontSize:15}}>{product.title}</strong>
 <div style={{fontSize:12,color:'var(--ink-500)'}}>{product.seller} - {product.location} - R {product.price.toLocaleString('en-ZA')}</div>
 </div>
 </div>

 <label style={{display:'block',fontFamily:'var(--font-body)',fontWeight:700,fontSize:13,color:'var(--ink-700)',marginBottom:8}}>
 From your listings, choose one to offer
 </label>
 <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:8,marginBottom:16}}>
 {mine.map(m => (
 <button key={m.id} onClick={() => setOfferId(m.id)} style={{
 textAlign:'left',padding:8,borderRadius:'var(--radius-md)',cursor:'pointer',background:'var(--paper)',
 border: offerId === m.id ? '2px solid var(--brand-orange)' : '1.5px solid var(--ink-200)'}}>
 <div style={{aspectRatio:'1.4',borderRadius:8,backgroundImage:'url(assets/me2you.jpg)',backgroundSize:'cover',backgroundPosition:'center',marginBottom:6}}/>
 <div style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:13}}>{m.title}</div>
 <div style={{fontSize:12,color:'var(--ink-700)'}}>R {m.price.toLocaleString('en-ZA')}</div>
 {offerId === m.id && <div style={{fontSize:11,color:'var(--brand-orange-700)',fontWeight:700,marginTop:2}}>Selected</div>}
 </button>
 ))}
 </div>

 <label style={{display:'block',fontFamily:'var(--font-body)',fontWeight:700,fontSize:13,color:'var(--ink-700)',marginBottom:8}}>
 Add cash to balance (optional, R)
 </label>
 <input type="number" value={topUp} onChange={e => setTopUp(e.target.value)} placeholder="e.g. 60"
 style={{width:'100%',padding:'13px 14px',border:'1.5px solid var(--ink-200)',borderRadius:'var(--radius-sm)',
 fontFamily:'var(--font-body)',fontSize:15,boxSizing:'border-box',background:'var(--paper)',marginBottom:16}}/>

 <label style={{display:'block',fontFamily:'var(--font-body)',fontWeight:700,fontSize:13,color:'var(--ink-700)',marginBottom:8}}>
 Message to {product.seller}
 </label>
 <textarea rows={3} value={note} onChange={e => setNote(e.target.value)}
 placeholder="Tell them about your item, condition, why you want to swap"
 style={{width:'100%',padding:14,border:'1.5px solid var(--ink-200)',borderRadius:'var(--radius-sm)',
 fontFamily:'var(--font-body)',fontSize:15,boxSizing:'border-box',resize:'vertical',marginBottom:16}}/>

 <div style={{...panelStyle,background:'var(--success-100)',borderColor:'var(--success)',fontSize:13,color:'var(--status-paid-fg)',display:'flex',gap:8,alignItems:'start'}}>
 <Icon name="shield-check" size={16} stroke={2}/>
 <span>Any cash top-up goes through escrow. Items are exchanged at the pickup desk.</span>
 </div>

 <button onClick={() => setStep('sent')} style={{...btnPrimary,width:'100%',justifyContent:'center',padding:'14px'}}>
 <Icon name="arrow-left-right" size={18}/> Send swap offer
 </button>
 </div>
 );
}

/* --- Seller side: accept or decline a swap offer --- */
function SellerSwapDecision({ theirs, yours, topUp, onBack }) {
 const [outcome, setOutcome] = useState(null); // accepted | declined

 const tile = (item, label) => (
 <div style={{textAlign:'center'}}>
 <div style={{aspectRatio:1,borderRadius:12,backgroundImage:'url(assets/me2you.jpg)',backgroundSize:'cover',backgroundPosition:'center',marginBottom:6}}/>
 <div style={{fontSize:11,color:'var(--ink-500)'}}>{label}</div>
 <div style={{fontFamily:'var(--font-display)',fontWeight:700,fontSize:13}}>{item ? item.title : ''} - R {item ? item.price.toLocaleString('en-ZA') : 0}</div>
 </div>
 );

 return (
 <div style={{maxWidth:560,margin:'0 auto'}}>
 <button onClick={onBack} style={{...btnSmall,border:'none',color:'var(--ink-500)',padding:'8px 0',marginBottom:12}}>
 <Icon name="arrow-left" size={16}/> Back to listing
 </button>
 <h1 style={{marginBottom:8}}>Swap offer - #SW-118</h1>
 <div style={{...panelStyle,background:'var(--info-100)',borderColor:'var(--info)',fontSize:13,color:'var(--ink-700)'}}>
 A buyer sent you a swap offer 12 minutes ago.
 </div>
 <div style={{...panelStyle,display:'grid',gridTemplateColumns:'1fr auto 1fr',gap:12,alignItems:'center'}}>
 {tile(theirs, 'They offer')}
 <div style={{color:'var(--brand-orange)'}}><Icon name="arrow-left-right" size={26}/></div>
 {tile(yours, 'Your item')}
 </div>
 {topUp > 0 && (
 <div style={{...panelStyle,background:'var(--brand-orange-50)',borderColor:'var(--brand-orange-100)',display:'flex',justifyContent:'space-between',alignItems:'center'}}>
 <span style={{fontSize:13,color:'var(--ink-700)'}}>Cash top-up from buyer</span>
 <strong style={{fontFamily:'var(--font-display)'}}>R {topUp.toLocaleString('en-ZA')}</strong>
 </div>
 )}

 {outcome === 'accepted' ? (
 <div style={{...panelStyle,background:'var(--success-100)',borderColor:'var(--success)',display:'flex',gap:10,alignItems:'start'}}>
 <Icon name="check-circle" size={20} stroke={2}/>
 <div style={{fontSize:13,color:'var(--ink-700)'}}>
 <strong style={{display:'block',fontFamily:'var(--font-display)',fontSize:14}}>Swap accepted</strong>
 Both items are locked{topUp > 0 ? ` and escrow is open for the R ${topUp.toLocaleString('en-ZA')} top-up` : ''}. Arrange the exchange at a pickup desk.
 </div>
 </div>
 ) : outcome === 'declined' ? (
 <div style={{...panelStyle,background:'var(--danger-100)',borderColor:'var(--danger)',display:'flex',gap:10,alignItems:'start'}}>
 <Icon name="x" size={20} stroke={2}/>
 <div style={{fontSize:13,color:'var(--ink-700)'}}>
 <strong style={{display:'block',fontFamily:'var(--font-display)',fontSize:14}}>Swap declined</strong>
 We let the buyer know. Nothing was charged.
 </div>
 </div>
 ) : (
 <>
 <div style={{...panelStyle,background:'var(--success-100)',borderColor:'var(--success)',fontSize:13,color:'var(--status-paid-fg)'}}>
 Accepting locks both items{topUp > 0 ? ` and opens escrow for the R ${topUp.toLocaleString('en-ZA')} top-up` : ''}.
 </div>
 <div style={{display:'flex',gap:10}}>
 <button onClick={() => setOutcome('declined')} style={{...btnGhost,flex:1,justifyContent:'center'}}>
 <Icon name="x" size={16}/> Decline
 </button>
 <button onClick={() => setOutcome('accepted')} style={{...btnPrimary,flex:1,justifyContent:'center'}}>
 <Icon name="check" size={16}/> Accept swap
 </button>
 </div>
 </>
 )}
 </div>
 );
}

/* --- OTP self-collect confirm: 6-box code entry at handover --- */
function OTPCollectionConfirm({ onBack, onConfirmed }) {
 const [digits, setDigits] = useState(['','','','','','']);
 const [error, setError] = useState('');
 const [confirmed, setConfirmed] = useState(false);
 const refs = useRef([]);
 const EXPECTED = '482913';

 const setDigit = (i, v) => {
 const clean = v.replace(/[^0-9]/g, '').slice(-1);
 setError('');
 setDigits(prev => prev.map((d,idx) => idx === i ? clean : d));
 if (clean && i < 5 && refs.current[i+1]) refs.current[i+1].focus();
 };

 const onKey = (i, e) => {
 if (e.key === 'Backspace' && !digits[i] && i > 0 && refs.current[i-1]) refs.current[i-1].focus();
 };

 const confirm = () => {
 const code = digits.join('');
 if (code.length < 6) { setError('Enter all 6 digits from the buyer.'); return; }
 if (code !== EXPECTED) { setError('That code does not match. Ask the buyer to read it again from their order screen.'); return; }
 setConfirmed(true);
 if (onConfirmed) onConfirmed();
 };

 if (confirmed) {
 return (
 <div style={{maxWidth:520,margin:'0 auto',textAlign:'center'}}>
 <div style={{width:80,height:80,borderRadius:999,background:'var(--success-100)',color:'var(--success)',
 display:'inline-flex',alignItems:'center',justifyContent:'center',marginBottom:24,animation:'pop .4s cubic-bezier(.2,.7,.3,1)'}}>
 <Icon name="check" size={40} stroke={2.5}/>
 </div>
 <h1>Collection confirmed</h1>
 <p style={{color:'var(--ink-500)',fontSize:16,maxWidth:400,margin:'12px auto 24px'}}>
 The escrow funds have been released to the seller. Enjoy your item.
 </p>
 <button onClick={onBack} style={btnGhost}>Done</button>
 </div>
 );
 }

 return (
 <div style={{maxWidth:520,margin:'0 auto'}}>
 <button onClick={onBack} style={{...btnSmall,border:'none',color:'var(--ink-500)',padding:'8px 0',marginBottom:12}}>
 <Icon name="arrow-left" size={16}/> Back
 </button>
 <div style={{...panelStyle,textAlign:'center'}}>
 <div style={{width:56,height:56,borderRadius:999,background:'var(--brand-orange-50)',color:'var(--brand-orange-700)',
 display:'inline-flex',alignItems:'center',justifyContent:'center',marginBottom:16}}>
 <Icon name="lock" size={26}/>
 </div>
 <h1 style={{margin:'0 0 8px',fontSize:24}}>Confirm collection</h1>
 <p style={{color:'var(--ink-500)',fontSize:14,margin:'0 0 20px'}}>
 Inspect the item first. When you are happy, read the 6-digit code from your order screen to the seller, or enter it here to release payment.
 </p>
 <div style={{display:'flex',gap:8,justifyContent:'center',marginBottom:16}}>
 {digits.map((d,i) => (
 <input key={i} ref={el => refs.current[i] = el} value={d} inputMode="numeric" maxLength={1}
 onChange={e => setDigit(i, e.target.value)} onKeyDown={e => onKey(i, e)}
 aria-label={`Digit ${i+1}`}
 style={{width:44,height:54,textAlign:'center',fontFamily:'var(--font-mono)',fontWeight:700,fontSize:24,
 border: error ? '1.5px solid var(--danger)' : '1.5px solid var(--ink-200)',borderRadius:'var(--radius-sm)',
 background:'var(--paper)',color:'var(--ink-900)'}}/>
 ))}
 </div>
 {error && <div style={{fontFamily:'var(--font-body)',fontSize:13,color:'var(--danger)',fontWeight:600,marginBottom:12}}>{error}</div>}
 <div style={{background:'var(--ink-50)',borderRadius:'var(--radius-md)',padding:'10px 14px',fontSize:12,color:'var(--ink-500)',marginBottom:16}}>
 Demo code for testing: <strong style={{fontFamily:'var(--font-mono)',color:'var(--ink-700)'}}>482913</strong>
 </div>
 <button onClick={confirm} style={{...btnPrimary,width:'100%',justifyContent:'center',padding:'14px'}}>
 <Icon name="shield-check" size={18}/> Confirm collection - release payment
 </button>
 </div>
 </div>
 );
}

Object.assign(window, {
 MarketplaceHero, CategoryRail, ProductCard, ProductGrid, SearchBar,
 ProductDetail, CartView, CheckoutView, OrderSuccess, OrdersList, DisputeForm,
 LaybyePanel, AuctionPanel, SwapOfferFlow, SellerSwapDecision, OTPCollectionConfirm,
});
