// UI primitives — icons, buttons, badges, inputs, modals, cards, shared widgets

// ─── ICONS ──────────────────────────────────────────────────
// Minimal inline Lucide-style SVGs. 1.75 stroke, rounded caps.
const Icon = ({ name, size=18, className='', style={}, ...props }) => {
  const p = { width:size, height:size, viewBox:'0 0 24 24', fill:'none',
    stroke:'currentColor', strokeWidth:1.75, strokeLinecap:'round', strokeLinejoin:'round',
    className, style, ...props };
  const PATHS = {
    search:<><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></>,
    heart:<path d="M12 20s-7-4.5-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.5-7 10-7 10Z"/>,
    'heart-fill':<path d="M12 20s-7-4.5-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.5-7 10-7 10Z" fill="currentColor"/>,
    star:<path d="m12 3 2.6 5.8 6.4.7-4.8 4.3 1.4 6.3L12 17l-5.6 3.1 1.4-6.3L3 9.5l6.4-.7Z" fill="currentColor"/>,
    chevron:<path d="m9 6 6 6-6 6"/>,
    'chevron-d':<path d="m6 9 6 6 6-6"/>,
    'chevron-u':<path d="m6 15 6-6 6 6"/>,
    'chevron-l':<path d="m15 6-6 6 6 6"/>,
    close:<><path d="M6 6 18 18"/><path d="M6 18 18 6"/></>,
    menu:<><path d="M4 7h16"/><path d="M4 12h16"/><path d="M4 17h10"/></>,
    plus:<><path d="M12 5v14"/><path d="M5 12h14"/></>,
    minus:<path d="M5 12h14"/>,
    check:<path d="M4 12l5 5L20 6"/>,
    x:<><path d="M6 6 18 18"/><path d="M6 18 18 6"/></>,
    calendar:<><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 10h18"/><path d="M8 3v4"/><path d="M16 3v4"/></>,
    clock:<><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>,
    pin:<><path d="M12 21s-7-7-7-12a7 7 0 0 1 14 0c0 5-7 12-7 12Z"/><circle cx="12" cy="9" r="2.5"/></>,
    users:<><circle cx="9" cy="8" r="3.5"/><path d="M3 20c0-3 3-5 6-5s6 2 6 5"/><path d="M17 11a3 3 0 0 0 0-6"/><path d="M20 20c0-2-1.5-4-4-4.5"/></>,
    user:<><circle cx="12" cy="9" r="3.5"/><path d="M5 20c0-3.5 3-6 7-6s7 2.5 7 6"/></>,
    message:<path d="M21 12a7 7 0 0 1-10 6l-5 1 1-5a7 7 0 1 1 14-2Z"/>,
    share:<><circle cx="18" cy="5" r="2.5"/><circle cx="6" cy="12" r="2.5"/><circle cx="18" cy="19" r="2.5"/><path d="m8 11 8-5"/><path d="m8 13 8 5"/></>,
    globe:<><circle cx="12" cy="12" r="9"/><path d="M3 12h18"/><path d="M12 3c3 3 3 15 0 18"/><path d="M12 3c-3 3-3 15 0 18"/></>,
    sun:<><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m5 5 1.4 1.4"/><path d="m17.6 17.6 1.4 1.4"/><path d="m5 19 1.4-1.4"/><path d="m17.6 6.4 1.4-1.4"/></>,
    arrow:<><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></>,
    'arrow-l':<><path d="M19 12H5"/><path d="m11 6-6 6 6 6"/></>,
    map:<><path d="M9 3 3 5v16l6-2 6 2 6-2V3l-6 2Z"/><path d="M9 3v16"/><path d="M15 5v16"/></>,
    filter:<><path d="M3 5h18l-7 8v6l-4 2v-8Z"/></>,
    grid:<><rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/></>,
    list:<><path d="M8 6h12"/><path d="M8 12h12"/><path d="M8 18h12"/><circle cx="4" cy="6" r="1" fill="currentColor"/><circle cx="4" cy="12" r="1" fill="currentColor"/><circle cx="4" cy="18" r="1" fill="currentColor"/></>,
    settings:<><circle cx="12" cy="12" r="3"/><path d="M19 12c0-1-.1-2-.3-2.9l1.8-1.4-2-3.4-2.1.9a7 7 0 0 0-2.4-1.4L14.6 2h-4l-.4 1.8c-.9.3-1.7.8-2.4 1.4l-2.1-.9-2 3.4 1.8 1.4c-.2 1-.2 1.9 0 2.9l-1.8 1.4 2 3.4 2.1-.9c.7.6 1.5 1.1 2.4 1.4L10.6 22h4l.4-1.8c.9-.3 1.7-.8 2.4-1.4l2.1.9 2-3.4-1.8-1.4c.2-.9.3-1.9.3-2.9Z"/></>,
    bell:<><path d="M6 10a6 6 0 0 1 12 0c0 5 2 6 2 6H4s2-1 2-6Z"/><path d="M10 20a2 2 0 0 0 4 0"/></>,
    'more':<><circle cx="6"  cy="12" r="1.5" fill="currentColor"/><circle cx="12" cy="12" r="1.5" fill="currentColor"/><circle cx="18" cy="12" r="1.5" fill="currentColor"/></>,
    'more-v':<><circle cx="12" cy="6"  r="1.5" fill="currentColor"/><circle cx="12" cy="12" r="1.5" fill="currentColor"/><circle cx="12" cy="18" r="1.5" fill="currentColor"/></>,
    edit:<><path d="M4 20h4l10-10-4-4L4 16Z"/><path d="m14 6 4 4"/></>,
    trash:<><path d="M4 7h16"/><path d="M9 7V4h6v3"/><path d="M6 7v13a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V7"/></>,
    eye:<><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/></>,
    upload:<><path d="M12 16V4"/><path d="m6 10 6-6 6 6"/><path d="M4 20h16"/></>,
    download:<><path d="M12 4v12"/><path d="m6 10 6 6 6-6"/><path d="M4 20h16"/></>,
    sailboat:<><path d="M4 20h16"/><path d="M12 4v12"/><path d="M12 6l8 10H5Z"/></>,
    mountain:<path d="M3 20 9 9l4 6 2-3 6 8Z"/>,
    wind:<><path d="M4 10h11a3 3 0 1 0-3-3"/><path d="M3 14h14a3 3 0 1 1-3 3"/></>,
    camera:<><rect x="3" y="7" width="18" height="13" rx="2"/><circle cx="12" cy="13.5" r="3.5"/><path d="M9 7l2-3h2l2 3"/></>,
    utensils:<><path d="M5 3v8a2 2 0 0 0 4 0V3"/><path d="M7 11v10"/><path d="M17 3c-1.5 1-2 3-2 5v3h3V3"/><path d="M18 11v10"/></>,
    landmark:<><path d="M3 20h18"/><path d="M5 20V9"/><path d="M9 20V9"/><path d="M15 20V9"/><path d="M19 20V9"/><path d="M2 9h20L12 3Z"/></>,
    anchor:<><circle cx="12" cy="5" r="2"/><path d="M12 7v14"/><path d="M5 16a7 7 0 0 0 14 0"/><path d="M8 11h8"/></>,
    palette:<><path d="M12 3a9 9 0 0 0 0 18c1 0 1.5-.7 1.5-1.5 0-1.5-1-1.5-1-2.5 0-1 .7-1.5 2-1.5h1.5a5 5 0 0 0 5-5A9 9 0 0 0 12 3Z"/><circle cx="7" cy="10" r="1" fill="currentColor"/><circle cx="12" cy="7" r="1" fill="currentColor"/><circle cx="17" cy="10" r="1" fill="currentColor"/></>,
    'chef-hat':<path d="M6 14c-2 0-3-1.5-3-3.5S4.5 7 6.5 7C7 4.5 9.5 3 12 3s5 1.5 5.5 4C19.5 7 21 8.5 21 10.5S20 14 18 14v4a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2Z"/>,
    flower:<><circle cx="12" cy="12" r="2"/><path d="M12 10V4"/><path d="M12 14v6"/><path d="M10 12H4"/><path d="M14 12h6"/><path d="m7 7 3.5 3.5"/><path d="m13.5 13.5 3.5 3.5"/><path d="m7 17 3.5-3.5"/><path d="m13.5 10.5 17 7"/></>,
    truck:<><path d="M3 16V6h11v10"/><path d="M14 9h4l3 3v4h-7"/><circle cx="7" cy="18" r="2"/><circle cx="17" cy="18" r="2"/></>,
    logout:<><path d="M10 20H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h5"/><path d="m15 8 4 4-4 4"/><path d="M19 12H9"/></>,
    dashboard:<><rect x="3" y="3" width="7" height="10" rx="1.5"/><rect x="14" y="3" width="7" height="6" rx="1.5"/><rect x="3" y="16" width="7" height="5" rx="1.5"/><rect x="14" y="12" width="7" height="9" rx="1.5"/></>,
    trending:<><path d="m3 17 6-6 4 4 8-8"/><path d="M14 7h7v7"/></>,
    money:<><rect x="3" y="6" width="18" height="12" rx="2"/><circle cx="12" cy="12" r="2.5"/><path d="M6 9v6"/><path d="M18 9v6"/></>,
    package:<><path d="M21 8 12 3 3 8l9 5Z"/><path d="M21 8v8l-9 5-9-5V8"/><path d="m12 13 9-5"/></>,
    book:<><path d="M4 4h10a4 4 0 0 1 4 4v12H8a4 4 0 0 1-4-4Z"/><path d="M4 16a4 4 0 0 1 4-4h10"/></>,
    tag:<><path d="M13 3H4v9l10 10 9-9Z"/><circle cx="8.5" cy="7.5" r="1.25" fill="currentColor"/></>,
    folder:<path d="M3 6a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"/>,
    database:<><ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v14c0 1.5 3.5 3 8 3s8-1.5 8-3V5"/><path d="M4 12c0 1.5 3.5 3 8 3s8-1.5 8-3"/></>,
    shield:<path d="m12 3 8 3v5c0 5-3.5 9-8 10-4.5-1-8-5-8-10V6Z"/>,
    inbox:<><path d="M3 13h5l1 3h6l1-3h5"/><path d="M5 13 7 4h10l2 9v7H5Z"/></>,
    'file-text':<><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9Z"/><path d="M14 3v6h6"/><path d="M8 13h8"/><path d="M8 17h5"/></>,
    key:<><circle cx="7" cy="15" r="3"/><path d="m9.5 12.5 10-10"/><path d="m14 7 3 3"/><path d="m17 5 3 3"/></>,
    external:<><path d="M10 4h-4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4"/><path d="M14 4h6v6"/><path d="m10 14 10-10"/></>,
  };
  return <svg {...p}>{PATHS[name] || PATHS.settings}</svg>;
};


// ─── LOGO ──────────────────────────────────────────────────
const Logo = ({ size=44, style={} }) =>
  <img src="assets/logo.png" alt="Vagoonya" width={size} height={size}
    style={{display:'block', objectFit:'contain', flexShrink:0, ...style}}/>;

// ─── BUTTONS ──────────────────────────────────────────────────
const Btn = ({ variant='primary', size='md', icon, iconRight, children, className='', ...p }) =>
  <button className={`btn btn-${variant} ${size==='sm'?'btn-sm':size==='lg'?'btn-lg':''} ${className}`} {...p}>
    {icon && <Icon name={icon} size={size==='sm'?14:16} />}
    {children}
    {iconRight && <Icon name={iconRight} size={size==='sm'?14:16} />}
  </button>;

// ─── BADGES / PILLS ───────────────────────────────────────────
const Pill = ({ tone='neutral', children, className='', icon }) =>
  <span className={`pill ${tone!=='neutral'?tone:''} ${className}`}>
    {icon && <Icon name={icon} size={11} />}
    {children}
  </span>;

const StatusPill = ({ status }) =>
  <Pill tone={window.STATUS_TONE[status] || 'neutral'}>{window.STATUS_TR[status] || status}</Pill>;

// ─── STARS ────────────────────────────────────────────────────
const Stars = ({ value, size=13, showValue=false, count }) => {
  const filled = Math.round(value);
  return <span style={{display:'inline-flex', alignItems:'center', gap:4, fontSize:13, fontWeight:600}}>
    <span className="star" style={{fontSize:size}}>
      {[1,2,3,4,5].map(i => <Icon key={i} name="star" size={size} style={{color: i<=filled ? 'var(--color-warn-deep)' : 'var(--color-line-strong)'}}/>)}
    </span>
    {showValue && <span className="tnum" style={{color:'var(--color-ink)'}}>{value.toFixed(1)}</span>}
    {count != null && <span className="tnum" style={{color:'var(--color-ink-dim)', fontWeight:500}}>({count})</span>}
  </span>;
};

// ─── INPUTS ───────────────────────────────────────────────────
const Field = ({ label, hint, error, children, style }) =>
  <div style={{display:'flex', flexDirection:'column', ...style}}>
    {label && <label className="field-label">{label}</label>}
    {children}
    {error ? <span className="field-hint" style={{color:'var(--color-danger-deep)'}}>{error}</span>
      : hint && <span className="field-hint">{hint}</span>}
  </div>;

const Input = (p) => <input className="input" {...p} />;
const TextArea = (p) => <textarea className="input" {...p} />;
const Select = ({ options, value, onChange, placeholder, style }) =>
  <select className="input" value={value||''} onChange={e=>onChange&&onChange(e.target.value)} style={style}>
    {placeholder && <option value="">{placeholder}</option>}
    {(options||[]).map(o => typeof o === 'string'
      ? <option key={o} value={o}>{o}</option>
      : <option key={o.value} value={o.value}>{o.label}</option>)}
  </select>;

// ─── SEGMENTED ────────────────────────────────────────────────
const Segmented = ({ options, value, onChange, size='md' }) => {
  const pad = size==='sm' ? '6px 12px' : '8px 16px';
  return <div style={{display:'inline-flex', background:'var(--color-surface-sunken)', borderRadius:'var(--r-md)', padding:3, gap:2}}>
    {options.map(o => {
      const v = typeof o === 'string' ? o : o.value;
      const lbl = typeof o === 'string' ? o : o.label;
      const active = v === value;
      return <button key={v} onClick={()=>onChange&&onChange(v)}
        style={{padding:pad, borderRadius:'calc(var(--r-md) - 3px)', border:0,
          background: active ? 'var(--color-surface-raised)':'transparent',
          color: active ? 'var(--color-ink-strong)':'var(--color-ink-dim)',
          boxShadow: active ? 'var(--sh-soft)':'none',
          fontSize:13, fontWeight:600, cursor:'default'}}>{lbl}</button>;
    })}
  </div>;
};

// ─── CHIP ─────────────────────────────────────────────────────
const Chip = ({ active, children, onClick, icon }) =>
  <button onClick={onClick} style={{
    display:'inline-flex', alignItems:'center', gap:6, padding:'7px 14px', borderRadius:'var(--r-pill)',
    border: `1px solid ${active ? 'var(--color-ink-strong)' : 'var(--color-line-strong)'}`,
    background: active ? 'var(--color-ink-strong)' : 'var(--color-surface-raised)',
    color: active ? 'var(--color-on-dark)' : 'var(--color-ink)',
    fontSize:13, fontWeight:600, cursor:'default', transition:'all .15s'}}>
    {icon && <Icon name={icon} size={13}/>}
    {children}
  </button>;

// ─── AVATAR ───────────────────────────────────────────────────
const Avatar = ({ src, name, size=36, style }) =>
  <div style={{width:size, height:size, borderRadius:'50%', overflow:'hidden',
    background:'var(--color-surface-sunken)', display:'inline-flex', alignItems:'center',
    justifyContent:'center', flexShrink:0, fontSize:size*0.4, fontWeight:600, color:'var(--color-ink-dim)', ...style}}>
    {src ? <img src={src} alt={name||''} style={{width:'100%', height:'100%', objectFit:'cover'}}/>
         : (name||'?').split(' ').map(s=>s[0]).join('').slice(0,2).toUpperCase()}
  </div>;

// ─── MODAL ────────────────────────────────────────────────────
const Modal = ({ open, onClose, title, children, footer, width=520 }) => {
  if (!open) return null;
  return <div onClick={onClose} style={{position:'fixed', inset:0, zIndex:9999,
    background:'rgba(31,18,9,.5)', backdropFilter:'blur(4px)', display:'flex', alignItems:'center',
    justifyContent:'center', padding:20}}>
    <div onClick={e=>e.stopPropagation()} className="card fade-in" style={{
      width, maxWidth:'100%', maxHeight:'85vh', display:'flex', flexDirection:'column',
      borderRadius:'var(--r-lg)', boxShadow:'var(--sh-elevated)'}}>
      <div style={{padding:'18px 22px', borderBottom:'1px solid var(--color-line)',
        display:'flex', alignItems:'center', justifyContent:'space-between'}}>
        <h4 style={{fontSize:18}}>{title}</h4>
        <button onClick={onClose} style={{border:0, background:'transparent', padding:6, borderRadius:8, color:'var(--color-ink-dim)', cursor:'default'}}>
          <Icon name="close" size={18}/></button>
      </div>
      <div style={{padding:'22px', overflowY:'auto'}}>{children}</div>
      {footer && <div style={{padding:'14px 22px', borderTop:'1px solid var(--color-line)',
        display:'flex', justifyContent:'flex-end', gap:8, background:'var(--color-surface)'}}>{footer}</div>}
    </div>
  </div>;
};

// ─── TOAST ────────────────────────────────────────────────────
const useToasts = () => {
  const [list, setList] = React.useState([]);
  const push = (msg, tone='success') => {
    const id = Math.random();
    setList(l => [...l, {id, msg, tone}]);
    setTimeout(()=>setList(l => l.filter(t=>t.id!==id)), 4000);
  };
  const el = <div style={{position:'fixed', bottom:24, right:24, zIndex:9998, display:'flex', flexDirection:'column', gap:8}}>
    {list.map(t => <div key={t.id} className="card fade-in" style={{
      padding:'12px 16px', background:'var(--color-dark-800)', color:'var(--color-on-dark)',
      borderRadius:'var(--r-md)', border:0, fontSize:14, fontWeight:500, boxShadow:'var(--sh-elevated)',
      display:'flex', alignItems:'center', gap:10, minWidth:260}}>
      <Icon name={t.tone==='success'?'check':'bell'} size={16}
        style={{color: t.tone==='success' ? 'var(--color-success)' : t.tone==='danger' ? 'var(--color-danger)' : 'var(--color-info)'}}/>
      {t.msg}
    </div>)}
  </div>;
  return [push, el];
};

// ─── LISTING CARD ─────────────────────────────────────────────
const useFavorites = () => {
  const [favs, setFavs] = React.useState(() => {
    try { return JSON.parse(localStorage.getItem('vg-favs')||'{}'); } catch { return {}; }
  });
  const toggle = (id) => setFavs(f => {
    const n = {...f, [id]: !f[id]};
    localStorage.setItem('vg-favs', JSON.stringify(n));
    return n;
  });
  return [favs, toggle];
};

const ListingCard = ({ l, variant='standard', onClick, favs, toggleFav }) => {
  const onHeart = (e) => { e.stopPropagation(); toggleFav && toggleFav(l.id); };
  const fav = favs && favs[l.id];
  const heart = <button onClick={onHeart} className="no-print" style={{
      position:'absolute', top:12, right:12, width:36, height:36, borderRadius:'50%',
      border:0, background:'rgba(255,255,255,.9)', backdropFilter:'blur(6px)', cursor:'default',
      display:'flex', alignItems:'center', justifyContent:'center',
      color: fav ? 'var(--color-brand-500)' : 'var(--color-ink)',
      transition:'transform .2s', zIndex:2
    }}
    onMouseDown={e => { e.currentTarget.style.transform='scale(1.15)'; setTimeout(()=>{try{e.currentTarget.style.transform=''}catch{}}, 180); }}>
    <Icon name={fav ? 'heart-fill' : 'heart'} size={18}/>
  </button>;
  const catChip = <span style={{position:'absolute', top:12, left:12, zIndex:1,
    padding:'4px 10px', borderRadius:'var(--r-pill)', background:'rgba(255,255,255,.92)',
    fontSize:11, fontWeight:700, color:'var(--color-ink)', letterSpacing:'.01em'}}>{l.cat}</span>;

  if (variant === 'wide') {
    return <div onClick={onClick} className="card card-interactive" style={{display:'grid', gridTemplateColumns:'240px 1fr', overflow:'hidden'}}>
      <div style={{position:'relative', aspectRatio:'4/3'}}>
        {catChip}{heart}
        <img src={l.img} alt={l.title} style={{width:'100%', height:'100%', objectFit:'cover'}}/>
      </div>
      <div style={{padding:'16px 20px', display:'flex', flexDirection:'column', gap:8}}>
        <div style={{fontSize:17, fontWeight:700, lineHeight:1.3, color:'var(--color-ink-strong)'}}>{l.title}</div>
        <div style={{color:'var(--color-ink-dim)', fontSize:13}}>{l.dest} · {l.duration} · maks {l.maxGroup||12} kişi</div>
        <Stars value={l.rating} count={l.reviewCount} size={12}/>
        <div style={{marginTop:'auto', display:'flex', alignItems:'baseline', justifyContent:'space-between'}}>
          <div><span className="tnum" style={{fontSize:20, fontWeight:800}}>{l.price.toLocaleString('tr-TR')} ₺</span>
            <span style={{color:'var(--color-ink-dim)', fontSize:13, marginLeft:6}}>· kişi başı</span></div>
          <Icon name="chevron" size={16} style={{color:'var(--color-ink-dim)'}}/>
        </div>
      </div>
    </div>;
  }
  if (variant === 'minimal') {
    return <div onClick={onClick} style={{cursor:'default'}}>
      <div style={{position:'relative', aspectRatio:'4/5', borderRadius:'var(--r-lg)', overflow:'hidden', marginBottom:12}}>
        {heart}
        <img src={l.img} alt={l.title} style={{width:'100%', height:'100%', objectFit:'cover'}}/>
        <div style={{position:'absolute', bottom:14, left:14, right:14, color:'#fff'}}>
          <div style={{fontSize:11, fontWeight:700, letterSpacing:'.12em', textTransform:'uppercase', opacity:.9, marginBottom:4}}>{l.cat} · {l.dest}</div>
          <div style={{fontSize:20, fontWeight:700, lineHeight:1.2, textShadow:'0 2px 12px rgba(0,0,0,.4)'}}>{l.title}</div>
        </div>
      </div>
      <div style={{display:'flex', alignItems:'baseline', justifyContent:'space-between', padding:'0 2px'}}>
        <Stars value={l.rating} count={l.reviewCount} size={12}/>
        <span className="tnum" style={{fontSize:15, fontWeight:700}}>{l.price.toLocaleString('tr-TR')} ₺</span>
      </div>
    </div>;
  }
  // standard
  return <div onClick={onClick} className="card-interactive" style={{cursor:'default'}}>
    <div style={{position:'relative', aspectRatio:'3/2', borderRadius:'var(--r-lg)', overflow:'hidden', marginBottom:12}}>
      {catChip}{heart}
      <img src={l.img} alt={l.title} style={{width:'100%', height:'100%', objectFit:'cover'}}/>
    </div>
    <div style={{padding:'0 2px'}}>
      <h4 style={{fontSize:17, fontWeight:700, marginBottom:4, lineHeight:1.3,
        display:'-webkit-box', WebkitLineClamp:2, WebkitBoxOrient:'vertical', overflow:'hidden'}}>{l.title}</h4>
      <div style={{color:'var(--color-ink-dim)', fontSize:13, marginBottom:8}}>{l.dest} · {l.duration}</div>
      <div style={{display:'flex', alignItems:'center', justifyContent:'space-between'}}>
        <Stars value={l.rating} count={l.reviewCount} size={12}/>
        <div>
          {l.origPrice && <span className="tnum" style={{color:'var(--color-ink-low)', fontSize:13, textDecoration:'line-through', marginRight:6}}>{l.origPrice.toLocaleString('tr-TR')} ₺</span>}
          <span className="tnum" style={{fontSize:17, fontWeight:800}}>{l.price.toLocaleString('tr-TR')} ₺</span>
        </div>
      </div>
    </div>
  </div>;
};

// ─── CHARTS ──────────────────────────────────────────────────
const genSpark = (fn, n=20) => Array.from({length:n}, (_,i) => Math.max(0, fn(i)));

const Sparkline = ({ values, width=100, height=28, color='var(--color-brand-500)' }) => {
  if (!values || !values.length) return null;
  const max = Math.max(...values), min = Math.min(...values);
  const range = max - min || 1;
  const pts = values.map((v,i) => {
    const x = (i / (values.length-1)) * width;
    const y = height - ((v - min) / range) * height;
    return `${x},${y}`;
  }).join(' ');
  return <svg width={width} height={height} style={{display:'inline-block'}}>
    <polyline points={pts} fill="none" stroke={color} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
  </svg>;
};

const BarChart = ({ data, height=160, color='var(--color-brand-500)' }) => {
  if (!data || !data.length) return null;
  const max = Math.max(...data);
  return <div style={{display:'flex', alignItems:'flex-end', gap:3, height, width:'100%'}}>
    {data.map((v,i) => <div key={i} style={{flex:1, height:`${(v/max)*100}%`, minHeight:2,
      background: `linear-gradient(180deg, ${color} 0%, color-mix(in oklch, ${color} 60%, transparent) 100%)`,
      borderRadius:'3px 3px 0 0', opacity: .6 + (i/data.length)*0.4}}/>)}
  </div>;
};

// ─── TABLE ──────────────────────────────────────────────────
const Table = ({ columns, rows }) => (
  <div className="card" style={{padding:0, overflow:'hidden'}}>
    <div style={{overflowX:'auto'}}>
      <table style={{width:'100%', borderCollapse:'collapse', fontSize:'var(--cell-fs, 14px)'}}>
        <thead>
          <tr style={{background:'var(--color-surface-muted)'}}>
            {columns.map((c,i) => <th key={i} style={{padding:'var(--row-py, 12px) var(--cell-px, 14px)',
              textAlign: c.align||'left', fontSize:11, fontWeight:700, color:'var(--color-ink-dim)',
              textTransform:'uppercase', letterSpacing:'.06em', width: c.width,
              borderBottom:'1px solid var(--color-line)'}}>{c.head}</th>)}
          </tr>
        </thead>
        <tbody>
          {rows.map((r,i) => <tr key={i} style={{borderBottom:'1px solid var(--color-line-soft)'}}>
            {columns.map((c,j) => <td key={j} style={{padding:'var(--row-py, 12px) var(--cell-px, 14px)',
              textAlign: c.align||'left', verticalAlign:'middle'}}>{r[c.key]}</td>)}
          </tr>)}
        </tbody>
      </table>
    </div>
  </div>
);

// ─── BREADCRUMBS ──────────────────────────────────────────────
const Breadcrumbs = ({ items = [], dark = false }) => (
  <nav aria-label="Breadcrumb" style={{display:'flex', alignItems:'center', gap:6, fontSize:13, flexWrap:'wrap'}}>
    {items.map((it, i) => {
      const last = i === items.length - 1;
      const color = dark ? (last ? '#fff' : 'rgba(255,255,255,.72)') : (last ? 'var(--color-ink-900)' : 'var(--color-ink-dim)');
      return (
        <React.Fragment key={i}>
          {it.onClick && !last
            ? <a onClick={it.onClick} style={{color, cursor:'pointer', textDecoration:'none'}}>{it.label}</a>
            : <span style={{color, fontWeight: last ? 600 : 400}}>{it.label}</span>}
          {!last && <span style={{color: dark ? 'rgba(255,255,255,.4)' : 'var(--color-ink-low)'}}>›</span>}
        </React.Fragment>
      );
    })}
  </nav>
);

Object.assign(window, { Icon, Logo, Btn, Pill, StatusPill, Stars, Field, Input, TextArea, Select,
  Segmented, Chip, Avatar, Modal, useToasts, ListingCard, useFavorites,
  Sparkline, BarChart, Table, genSpark, Breadcrumbs });
