// ──────────────────────────── Catalogo articoli ────────────────────────────

const { useState: useStateC, useMemo: useMemoC, useEffect: useEffectC, useRef: useRefC } = React;

// ─── Color swatch (cerchio pieno con bordo, usa COLOR_HEX) ───
const ColorDot = ({ name, size = 16, ringed = false }) => {
  const hex = COLOR_HEX[name] || 'var(--text-tertiary)';
  const light = ['#F5F1E8','#EDE3D1','#C9B89A'].includes(hex);
  return (
    <span
      title={name}
      className="inline-block rounded-full border align-middle"
      style={{
        width: size, height: size, background: hex,
        borderColor: light ? '#D6CFC1' : 'rgba(0,0,0,0.18)',
        boxShadow: ringed ? '0 0 0 2px var(--accent-blue)' : 'none',
      }}
    />
  );
};

// ─── Riepilogo stock totale di un articolo nello store corrente ───
const totalStock = (article, storeId = STORE.id) => {
  const ss = article.stock[storeId] || {};
  let total = 0;
  for (const c of article.colors) for (const s of article.sizes) total += (ss[c]?.[s] ?? 0);
  return total;
};

const stockBadge = (n) => {
  if (n === 0) return <Pill tone="neg">Esaurito</Pill>;
  if (n <= 5)  return <Pill tone="warn">Scorta bassa · {n}</Pill>;
  return <Pill tone="pos">In stock · {n}</Pill>;
};

// ─── Channel pill (mostra dot colorati per canali) ───
const ChannelPill = ({ ch }) => {
  const labels = [];
  if (ch.negozio) labels.push('Negozio');
  if (ch.ecommerce) labels.push('E-commerce');
  if (ch.marketplace) labels.push('Marketplace');
  if (labels.length === 0) return <Pill tone="neutral">Non pubblicato</Pill>;
  return (
    <span className="inline-flex items-center gap-1.5 text-[12px] text-muted">
      <span className="flex items-center -space-x-1">
        {ch.negozio    && <span className="w-2 h-2 rounded-full bg-[var(--text-secondary)] ring-2 ring-surface"></span>}
        {ch.ecommerce  && <span className="w-2 h-2 rounded-full bg-[var(--accent-blue)] ring-2 ring-surface"></span>}
        {ch.marketplace&& <span className="w-2 h-2 rounded-full bg-pos ring-2 ring-surface"></span>}
      </span>
      <span>{labels.join(' · ')}</span>
    </span>
  );
};

// ─── CSV parser (rispetta campi quotati) ───
const parseCSVLineCat = (line) => {
  const result = [];
  let cur = '';
  let inQ = false;
  for (let i = 0; i < line.length; i++) {
    const ch = line[i];
    if (ch === '"') { inQ = !inQ; }
    else if (ch === ',' && !inQ) { result.push(cur); cur = ''; }
    else { cur += ch; }
  }
  result.push(cur);
  return result;
};

// ─── Modale import articoli da CSV ───
const CatalogoImportModal = ({ onClose, onImport }) => {
  const [rows, setRows]         = useStateC([]);
  const [file, setFile]         = useStateC(null);
  const [dragging, setDragging] = useStateC(false);
  const fileRef                 = useRefC(null);

  const parseFile = (f) => {
    if (!f) return;
    setFile(f);
    const reader = new FileReader();
    reader.onload = (ev) => {
      const lines = ev.target.result
        .split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'));
      if (lines.length < 2) { setRows([]); return; }
      const headers = lines[0].split(',').map(h => h.trim().toLowerCase().replace(/\s+/g, ''));
      const parsed = lines.slice(1).map((line, i) => {
        const vals = parseCSVLineCat(line);
        const row = {};
        headers.forEach((h, idx) => { row[h] = (vals[idx] || '').trim(); });
        const nome  = row['nome'] || '';
        const sku   = row['sku']  || '';
        const pRaw  = (row['prezzovendita'] || row['prezzo'] || '').replace(',', '.');
        const price = parseFloat(pRaw);
        const valid = !!nome && !!sku && !isNaN(price) && price > 0;
        return {
          _i: i, nome, sku,
          prezzoVendita:   isNaN(price) ? 0 : price,
          cat:             row['categoria'] || 'Altro',
          season:          row['stagione']  || '',
          prezzoAcquisto:  parseFloat((row['prezzoacquisto'] || '0').replace(',', '.')) || 0,
          colors: (row['colori'] || '').split(',').map(c => c.trim()).filter(Boolean),
          sizes:  (row['taglie'] || '').split(',').map(s => s.trim()).filter(Boolean),
          valid,
          error: valid ? '' : (!nome ? 'Nome mancante' : !sku ? 'SKU mancante' : 'Prezzo non valido'),
        };
      });
      setRows(parsed);
    };
    reader.readAsText(f, 'UTF-8');
  };

  const downloadTemplate = () => {
    const csv = [
      '# Fac-simile importazione articoli Bone & Ink',
      '# Colonne obbligatorie: nome, sku, prezzovendita',
      '# Colonne opzionali: categoria, stagione, prezzoacquisto, colori, taglie',
      'nome,sku,prezzovendita,categoria,stagione,prezzoacquisto,colori,taglie',
      '"Cappotto lana cachemire",CA-0001,890,Capospalla,AI 2026,350,"Navy, Beige","S, M, L, XL"',
      '"Maglione trecce merino",MA-0002,320,Maglieria,AI 2026,120,"Bianco, Grigio","XS, S, M, L"',
    ].join('\n');
    const a = document.createElement('a');
    a.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv);
    a.download = 'fac-simile-articoli.csv';
    document.body.appendChild(a); a.click(); document.body.removeChild(a);
  };

  const validRows = rows.filter(r => r.valid);

  const doImport = () => {
    onImport(validRows.map(r => ({
      id: r.sku.toUpperCase(), name: r.nome, brand: 'Bone & Ink',
      cat: r.cat, season: r.season, status: 'Bozza',
      basePrice: r.prezzoVendita, purchasePrice: r.prezzoAcquisto,
      colors: r.colors.length ? r.colors : ['—'],
      sizes:  r.sizes.length  ? r.sizes  : ['TU'],
      description: '', composition: '', taxRate: 22, images: 0,
      stock:    Object.fromEntries(STORES.map(s => [s.id, {}])),
      prices:   Object.fromEntries(STORES.map(s => [s.id, r.prezzoVendita])),
      channels: { negozio: false, ecommerce: false, marketplace: false },
      _extra: true,
    })));
    onClose();
  };

  return (
    <div className="fixed inset-0 z-modal flex items-center justify-center" style={{ background: 'rgba(0,0,0,0.45)' }}>
      <div className="bg-surface rounded-2xl shadow-modal w-full max-w-[760px] mx-4 flex flex-col" style={{ maxHeight: '88vh' }}>
        {/* Header */}
        <div className="flex items-center justify-between px-6 py-4 border-b border-line">
          <div>
            <div className="text-[17px] font-semibold text-ink">Importa articoli da CSV</div>
            <div className="text-[12.5px] text-muted mt-0.5">Formato: CSV con virgola come separatore, UTF-8</div>
          </div>
          <button onClick={onClose} className="w-9 h-9 rounded-full flex items-center justify-center text-muted hover:bg-paper focus-ring">
            <I.X size={18}/>
          </button>
        </div>

        {/* Body */}
        <div className="flex-1 overflow-y-auto px-6 py-5 space-y-4">
          <div
            onDragOver={e => { e.preventDefault(); setDragging(true); }}
            onDragLeave={() => setDragging(false)}
            onDrop={e => { e.preventDefault(); setDragging(false); const f = e.dataTransfer.files[0]; if (f) parseFile(f); }}
            onClick={() => fileRef.current && fileRef.current.click()}
            className="rounded-xl p-8 text-center cursor-pointer transition-all duration-fast ease-standard"
            style={{
              border: `2px dashed ${dragging ? 'var(--accent-blue)' : 'var(--border-default)'}`,
              background: dragging ? 'var(--bg-selected)' : 'transparent',
            }}
          >
            <input ref={fileRef} type="file" accept=".csv" className="sr-only"
              onChange={e => parseFile(e.target.files[0])}/>
            <I.ArrowU size={28} className="mx-auto mb-3 text-muted"/>
            <div className="text-[15px] font-medium text-ink">
              {file ? file.name : 'Trascina il file qui o clicca per selezionare'}
            </div>
            <div className="text-[12.5px] text-muted mt-1">File .csv · max 500 righe</div>
          </div>

          <div className="flex justify-end">
            <button onClick={downloadTemplate}
              className="flex items-center gap-1.5 text-[13px] text-[var(--accent-blue)] hover:underline focus-ring rounded-md px-1 py-0.5">
              <I.ArrowD size={13}/>
              Scarica fac-simile CSV
            </button>
          </div>

          {rows.length > 0 && (
            <div>
              <div className="flex items-center justify-between mb-2">
                <span className="text-[12px] uppercase tracking-[0.08em] text-muted font-medium">
                  Anteprima — {rows.length} righe
                </span>
                <span className="text-[12.5px] text-muted">
                  <span className="text-pos font-medium">{validRows.length}</span> valide ·{' '}
                  <span className="text-neg font-medium">{rows.length - validRows.length}</span> errori
                </span>
              </div>
              <Card padded={false}>
                <div className="overflow-x-auto">
                  <table className="w-full text-[12.5px]">
                    <thead>
                      <tr className="hairline text-left text-muted uppercase text-[10.5px] tracking-[0.08em]">
                        <th className="px-4 py-2.5 font-medium">Nome</th>
                        <th className="px-4 py-2.5 font-medium">SKU</th>
                        <th className="px-4 py-2.5 font-medium text-right">Prezzo</th>
                        <th className="px-4 py-2.5 font-medium">Categoria</th>
                        <th className="px-4 py-2.5 font-medium">Stato</th>
                      </tr>
                    </thead>
                    <tbody>
                      {rows.map(r => (
                        <tr key={r._i} className={`border-b border-line2 last:border-0 ${r.valid ? '' : 'bg-[var(--danger-50)]'}`}>
                          <td className="px-4 py-3 text-ink">{r.nome || <span className="text-neg italic text-[12px]">mancante</span>}</td>
                          <td className="px-4 py-3 num text-muted">{r.sku  || <span className="text-neg italic text-[12px]">mancante</span>}</td>
                          <td className="px-4 py-3 num text-ink text-right">{r.prezzoVendita > 0 ? fmtEur(r.prezzoVendita) : <span className="text-neg italic text-[12px]">n/d</span>}</td>
                          <td className="px-4 py-3 text-muted">{r.cat}</td>
                          <td className="px-4 py-3">
                            {r.valid ? <Pill tone="pos">Valido</Pill> : <Pill tone="neg">{r.error}</Pill>}
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              </Card>
            </div>
          )}
        </div>

        {/* Footer */}
        <div className="flex items-center justify-between px-6 py-4 border-t border-line">
          <Btn variant="outline" size="md" onClick={onClose}>Annulla</Btn>
          <button onClick={doImport} disabled={validRows.length === 0}
            className="h-16 px-6 rounded-md bg-[var(--accent-blue)] text-[var(--text-inverse)] font-semibold text-[17px] flex items-center gap-3 hover:bg-[var(--accent-blue-hover)] disabled:opacity-30 disabled:cursor-not-allowed transition-all duration-fast ease-standard shadow-soft">
            <I.Check size={20}/>
            Importa {validRows.length > 0 ? `${validRows.length} ` : ''}articoli validi
          </button>
        </div>
      </div>
    </div>
  );
};

// ────────────────────────────── List view ──────────────────────────────
const CatalogoList = ({ onOpen, activeStoreId = STORE.id }) => {
  const [q, setQ] = useStateC('');
  const [cat, setCat] = useStateC('Tutti');
  const [season, setSeason] = useStateC('Tutte');
  const [status, setStatus] = useStateC('Tutti');
  const [avail, setAvail] = useStateC('Tutti'); // Tutti | In stock | Scorta bassa | Esauriti
  const [sort, setSort]                   = useStateC('name-asc');
  const [view, setView]                   = useStateC('table'); // table (lista) di default | grid
  const [extraArticles, setExtraArticles] = useStateC([]);
  const [showImportModal, setShowImportModal] = useStateC(false);
  const [newOpen, setNewOpen] = useStateC(false);

  const allArticles = useMemoC(() => [...ARTICLES, ...extraArticles], [extraArticles]);
  const categories  = useMemoC(() => ['Tutti', ...Array.from(new Set(allArticles.map(a => a.cat))).sort()], [allArticles]);
  const seasons     = useMemoC(() => ['Tutte', ...Array.from(new Set(allArticles.map(a => a.season))).sort()], [allArticles]);
  const statuses   = ['Tutti', 'Pubblicato', 'Bozza', 'Archiviato'];
  const availOpts  = ['Tutti', 'In stock', 'Scorta bassa', 'Esauriti'];

  const filtered = useMemoC(() => {
    const ql = q.trim().toLowerCase();
    let list = allArticles.filter(a => {
      if (ql && !(a.name.toLowerCase().includes(ql) || a.id.toLowerCase().includes(ql) || a.brand.toLowerCase().includes(ql))) return false;
      if (cat !== 'Tutti' && a.cat !== cat) return false;
      if (season !== 'Tutte' && a.season !== season) return false;
      if (status !== 'Tutti' && a.status !== status) return false;
      const total = totalStock(a, activeStoreId);
      if (avail === 'In stock'      && total <= 5)  return false;
      if (avail === 'Scorta bassa' && (total === 0 || total > 5)) return false;
      if (avail === 'Esauriti'     && total !== 0)  return false;
      return true;
    });
    list = [...list];
    list.sort((x, y) => {
      if (sort === 'name-asc')   return x.name.localeCompare(y.name);
      if (sort === 'name-desc')  return y.name.localeCompare(x.name);
      if (sort === 'price-asc')  return x.basePrice - y.basePrice;
      if (sort === 'price-desc') return y.basePrice - x.basePrice;
      if (sort === 'stock-desc') return totalStock(y, activeStoreId) - totalStock(x, activeStoreId);
      if (sort === 'stock-asc')  return totalStock(x, activeStoreId) - totalStock(y, activeStoreId);
      return 0;
    });
    return list;
  }, [q, cat, season, status, avail, sort, allArticles]);

  return (
    <>
      <Topbar
        eyebrow={`Catalogo articoli · ${STORES.find(s=>s.id===activeStoreId)?.name || STORE.name}`}
        title="Catalogo"
        right={<>
          <Btn variant="outline" size="md" leading={<I.ArrowD size={16}/>} onClick={() => {
            if (window.__csv) window.__csv(
              'catalogo-articoli.csv',
              ['Articolo','Codice','Brand','Categoria','Stagione','Colori','Stato','Prezzo','Disponibilità'],
              filtered.map(a => [a.name, a.id, a.brand, a.cat, a.season, a.colors.join(' / '), a.status, fmtEur(a.basePrice), totalStock(a, activeStoreId)])
            );
          }}>Esporta</Btn>
          <Btn variant="outline" size="md" leading={<I.ArrowU size={16}/>} onClick={() => setShowImportModal(true)}>Importa articoli</Btn>
          <Btn variant="ink" size="md" leading={<I.Plus size={16}/>} onClick={() => setNewOpen(true)}>Nuovo articolo</Btn>
        </>}
      />

      <div className="px-7 py-6 space-y-4 max-w-[1400px]">
        {/* Search + filters bar */}
        <div className="bg-surface rounded-2xl p-3.5 shadow-soft">
          <div className="flex flex-wrap items-center gap-2.5">
            <div className="relative flex-1 min-w-[260px]">
              <I.Search size={18} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-muted"/>
              <input
                value={q}
                onChange={(e)=>setQ(e.target.value)}
                placeholder="Cerca per nome, brand o codice articolo…"
                className="w-full h-11 pl-11 pr-4 rounded-md bg-sunken text-[14px] shadow-[inset_0_0_0_0.5px_var(--border-default)] focus:bg-surface focus:shadow-[var(--shadow-focus),inset_0_0_0_1px_var(--accent-blue)] transition-all duration-fast ease-standard"
              />
            </div>

            <FilterSelect label="Categoria" value={cat}    onChange={setCat}    options={categories}/>
            <FilterSelect label="Stagione"  value={season} onChange={setSeason} options={seasons}/>
            <FilterSelect label="Stato"     value={status} onChange={setStatus} options={statuses}/>
            <FilterSelect label="Disponibilità" value={avail} onChange={setAvail} options={availOpts}/>

            <div className="h-8 w-px bg-line mx-1"></div>

            <FilterSelect label="Ordina" value={sort} onChange={setSort} options={[
              { v:'name-asc',   l:'Nome A→Z' },
              { v:'name-desc',  l:'Nome Z→A' },
              { v:'price-desc', l:'Prezzo ↓' },
              { v:'price-asc',  l:'Prezzo ↑' },
              { v:'stock-desc', l:'Stock ↓' },
              { v:'stock-asc',  l:'Stock ↑' },
            ]}/>

            <div className="flex rounded-md border border-line bg-paper p-0.5 ml-auto">
              <button onClick={()=>setView('grid')}
                className={`w-9 h-9 rounded-sm flex items-center justify-center ${view==='grid' ? 'bg-[var(--bg-selected)] text-[var(--accent-blue)]' : 'text-muted hover:text-ink'}`}
                title="Vista griglia">
                <I.Dashboard size={16}/>
              </button>
              <button onClick={()=>setView('table')}
                className={`w-9 h-9 rounded-sm flex items-center justify-center ${view==='table' ? 'bg-[var(--bg-selected)] text-[var(--accent-blue)]' : 'text-muted hover:text-ink'}`}
                title="Vista tabella">
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18M3 12h18M3 18h18"/></svg>
              </button>
            </div>
          </div>
        </div>

        {/* Results summary */}
        <div className="flex items-center justify-between text-[13px] text-muted px-1">
          <span>
            <span className="num text-ink font-medium">{filtered.length}</span> articoli · {allArticles.length} totali
            {extraArticles.length > 0 && <span className="text-muted"> · <span className="num">{extraArticles.length}</span> importati</span>}
          </span>
          {(q || cat !== 'Tutti' || season !== 'Tutte' || status !== 'Tutti' || avail !== 'Tutti') && (
            <button
              onClick={()=>{setQ(''); setCat('Tutti'); setSeason('Tutte'); setStatus('Tutti'); setAvail('Tutti');}}
              className="text-ink hover:underline">Azzera filtri</button>
          )}
        </div>

        {/* Body */}
        {view === 'grid' ? (
          <div className="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
            {filtered.map(a => <ArticleCard key={a.id} article={a} onOpen={a._extra ? () => {} : onOpen} activeStoreId={activeStoreId}/>)}
          </div>
        ) : (
          <Card padded={false}>
            <table className="w-full text-[13.5px]">
              <thead>
                <tr className="text-left text-muted uppercase text-[11px] tracking-[0.08em] hairline">
                  <th className="px-5 py-3 font-medium">Articolo</th>
                  <th className="px-5 py-3 font-medium">Codice</th>
                  <th className="px-5 py-3 font-medium">Brand</th>
                  <th className="px-5 py-3 font-medium">Categoria</th>
                  <th className="px-5 py-3 font-medium">Stagione</th>
                  <th className="px-5 py-3 font-medium">Colori</th>
                  <th className="px-5 py-3 font-medium">Stato</th>
                  <th className="px-5 py-3 font-medium text-right">Prezzo</th>
                  <th className="px-5 py-3 font-medium text-right">Disponib.</th>
                </tr>
              </thead>
              <tbody>
                {filtered.map(a => {
                  const tot = totalStock(a, activeStoreId);
                  return (
                    <tr key={a.id} onClick={()=>{ if (!a._extra) onOpen(a.id); }} className="hover:bg-paper border-b border-line2 last:border-0 cursor-pointer">
                      <td className="px-5 py-3.5">
                        <div className="flex items-center gap-3">
                          <ProductThumb size={36}/>
                          <span className="font-medium text-ink">{a.name}</span>
                        </div>
                      </td>
                      <td className="px-5 py-3.5 num text-muted">{a.id}</td>
                      <td className="px-5 py-3.5 text-ink">{a.brand}</td>
                      <td className="px-5 py-3.5 text-ink">{a.cat}</td>
                      <td className="px-5 py-3.5 text-ink">{a.season}</td>
                      <td className="px-5 py-3.5">
                        <span className="flex items-center gap-1">
                          {a.colors.slice(0,4).map(c => <ColorDot key={c} name={c} size={14}/>)}
                          {a.colors.length > 4 && <span className="text-[11px] text-muted ml-1">+{a.colors.length-4}</span>}
                        </span>
                      </td>
                      <td className="px-5 py-3.5">
                        {a.status === 'Pubblicato' && <Pill tone="pos">Pubblicato</Pill>}
                        {a.status === 'Bozza'      && <Pill tone="warn">Bozza</Pill>}
                        {a.status === 'Archiviato' && <Pill tone="neutral">Archiviato</Pill>}
                      </td>
                      <td className="px-5 py-3.5 num text-ink text-right font-medium">{fmtEur(a.basePrice)}</td>
                      <td className="px-5 py-3.5 num text-right">
                        <span className={tot === 0 ? 'text-neg font-medium' : tot <= 5 ? 'text-warn font-medium' : 'text-ink'}>{tot}</span>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
            {filtered.length === 0 && (
              <div className="px-5 py-16 text-center text-muted text-[14px]">Nessun articolo corrisponde ai filtri.</div>
            )}
          </Card>
        )}

        {view === 'grid' && filtered.length === 0 && (
          <div className="bg-surface rounded-2xl p-12 text-center text-muted">Nessun articolo corrisponde ai filtri.</div>
        )}
      </div>

      {showImportModal && (
        <CatalogoImportModal
          onClose={() => setShowImportModal(false)}
          onImport={(newArts) => { if (window.__API__) { Promise.all(newArts.map(a => window.__API__.post('/api/articles', { article: a }).catch(()=>{}))).then(() => window.__BI_REFRESH__ && window.__BI_REFRESH__()); } else { setExtraArticles(prev => [...prev, ...newArts]); } }}
        />
      )}
      {newOpen && <CatalogoArticleForm article={null} onClose={() => setNewOpen(false)}/>}
    </>
  );
};

// ─── Filter dropdown nativo, stilizzato ───
const FilterSelect = ({ label, value, options, onChange }) => (
  <label className="inline-flex items-center gap-2 h-11 px-3 rounded-md border border-line bg-paper hover:border-strong transition-all duration-fast ease-standard cursor-pointer">
    <span className="text-[11.5px] uppercase tracking-[0.08em] text-muted font-medium">{label}</span>
    <select
      value={value}
      onChange={(e)=>onChange(e.target.value)}
      className="bg-transparent text-[13.5px] text-ink font-medium focus:outline-none cursor-pointer pr-1"
    >
      {options.map(o => {
        const v = typeof o === 'object' ? o.v : o;
        const l = typeof o === 'object' ? o.l : o;
        return <option key={v} value={v}>{l}</option>;
      })}
    </select>
  </label>
);

// ─── Article card (grid view) ───
const ArticleCard = ({ article, onOpen, activeStoreId = STORE.id }) => {
  const tot = totalStock(article, activeStoreId);
  return (
    <button
      onClick={()=>onOpen(article.id)}
      className="text-left bg-surface rounded-2xl overflow-hidden shadow-soft hover:shadow-lg hover:-translate-y-0.5 transition-all duration-fast ease-standard focus-ring"
    >
      <div className="aspect-[4/5] stripe-ph relative">
        <div className="absolute top-3 left-3">
          {article.status === 'Pubblicato' && <Pill tone="pos">Pubblicato</Pill>}
          {article.status === 'Bozza'      && <Pill tone="warn">Bozza</Pill>}
          {article.status === 'Archiviato' && <Pill tone="neutral">Archiviato</Pill>}
        </div>
        <div className="absolute top-3 right-3">
          {tot === 0 ? <Pill tone="neg">Esaurito</Pill> : tot <= 5 ? <Pill tone="warn">Scorta · {tot}</Pill> : null}
        </div>
        <div className="absolute bottom-3 right-3 num text-[10.5px] text-muted glass-thin px-1.5 py-0.5 rounded">
          {article.images} foto
        </div>
      </div>
      <div className="p-4">
        <div className="flex items-baseline justify-between gap-2">
          <span className="text-[11.5px] uppercase tracking-[0.06em] text-muted font-medium truncate">{article.brand}</span>
          <span className="num text-[10.5px] text-muted">{article.id}</span>
        </div>
        <h3 className="mt-0.5 text-[15px] font-medium text-ink leading-snug">{article.name}</h3>
        <div className="mt-2.5 flex items-center justify-between">
          <span className="flex items-center gap-1">
            {article.colors.slice(0,5).map(c => <ColorDot key={c} name={c} size={12}/>)}
            {article.colors.length > 5 && <span className="text-[11px] text-muted ml-1">+{article.colors.length-5}</span>}
          </span>
          <span className="num text-[15.5px] font-semibold text-ink">{fmtEur(article.basePrice)}</span>
        </div>
        <div className="mt-3 pt-3 border-t border-line2 flex items-center justify-between">
          <span className="text-[11.5px] text-muted">{article.cat} · {article.season}</span>
          <span className={`num text-[12px] font-medium ${tot === 0 ? 'text-neg' : tot <= 5 ? 'text-warn' : 'text-muted'}`}>
            {tot} disp.
          </span>
        </div>
      </div>
    </button>
  );
};

// ────────────────────────────── Detail view ──────────────────────────────
const CatalogoDetail = ({ articleId, onBack, activeStoreId = STORE.id }) => {
  const article = ARTICLES.find(a => a.id === articleId);
  const [activeImg, setActiveImg] = useStateC(0);
  const [storeView, setStoreView] = useStateC(activeStoreId === 'all' ? STORE.id : activeStoreId);
  const [channels, setChannels] = useStateC(article.channels);
  const [editOpen, setEditOpen] = useStateC(false);

  useEffectC(() => { setStoreView(activeStoreId === 'all' ? STORE.id : activeStoreId); }, [activeStoreId]);

  if (!article) return null;

  const matrixStock = article.stock[storeView] || {};
  const totHere = totalStock(article, storeView);

  return (
    <>
      <Topbar
        eyebrow={
          <span className="flex items-center gap-1.5">
            <button onClick={onBack} className="text-ink hover:underline">Catalogo</button>
            <I.ArrowR size={11} className="opacity-60"/>
            <span>{article.cat}</span>
          </span>
        }
        title={article.name}
        right={<>
          <Btn variant="outline" size="md" onClick={onBack} leading={<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M15 6l-6 6 6 6"/></svg>}>
            Torna al catalogo
          </Btn>
          <Btn variant="outline" size="md" leading={<I.Edit size={16}/>} onClick={() => setEditOpen(true)}>Modifica</Btn>
          <Btn variant="ink" size="md" leading={<I.ArrowU size={16}/>} onClick={() => { if (window.__API__) window.__API__.mutate('/api/articles/status', { id: article.id, status: 'Pubblicato' }).then(()=>{ if (window.__toast) window.__toast('Articolo pubblicato', 'success'); }).catch(()=>{}); }}>Pubblica</Btn>
        </>}
      />

      <div className="px-7 py-6 space-y-6 max-w-[1400px]">
        {/* Hero row: Gallery + Info */}
        <div className="grid grid-cols-[440px_1fr] gap-6">
          {/* Gallery */}
          <Card padded={false}>
            <div className="aspect-[4/5] stripe-ph relative">
              <div className="absolute bottom-3 left-3 num text-[10.5px] text-muted glass-thin px-2 py-1 rounded">
                {activeImg + 1} / {article.images}
              </div>
              <div className="absolute top-3 right-3 flex gap-1">
                {article.status === 'Pubblicato' && <Pill tone="pos">Pubblicato</Pill>}
                {article.status === 'Bozza'      && <Pill tone="warn">Bozza</Pill>}
                {article.status === 'Archiviato' && <Pill tone="neutral">Archiviato</Pill>}
              </div>
            </div>
            <div className="grid grid-cols-4 gap-2 p-3">
              {Array.from({ length: article.images }).map((_, i) => (
                <button
                  key={i}
                  onClick={()=>setActiveImg(i)}
                  className={`aspect-square stripe-ph rounded-sm border-2 transition-all duration-fast ease-standard
                    ${activeImg === i ? 'border-ink' : 'border-transparent hover:border-line'}`}
                  aria-label={`Immagine ${i+1}`}
                />
              ))}
            </div>
          </Card>

          {/* Info */}
          <div className="space-y-5">
            <div>
              <div className="flex items-baseline gap-3">
                <span className="text-[12px] uppercase tracking-[0.08em] text-muted font-medium">{article.brand}</span>
                <span className="num text-[12px] text-muted">{article.id}</span>
              </div>
              <h2 className="mt-1 text-[28px] font-semibold tracking-tight text-ink leading-tight">{article.name}</h2>
              <p className="mt-2 text-[14.5px] text-muted leading-relaxed max-w-[640px]">{article.description}</p>
            </div>

            <div className="grid grid-cols-4 gap-4 py-4 border-y border-line">
              <KeyVal label="Categoria" value={article.cat}/>
              <KeyVal label="Stagione"  value={article.season}/>
              <KeyVal label="IVA"       value={`${article.taxRate}%`}/>
              <KeyVal label="Prezzo base" value={fmtEur(article.basePrice)} mono/>
            </div>

            <KeyVal label="Composizione" value={article.composition}/>

            <div>
              <div className="text-[11.5px] uppercase tracking-[0.08em] text-muted font-medium mb-2">Disponibilità totale ({STORES.find(s=>s.id===storeView)?.name})</div>
              <div className="flex items-center gap-3">
                <span className="num text-[28px] font-semibold text-ink">{totHere}</span>
                <span className="text-[13px] text-muted">pezzi tra {article.colors.length} colori e {article.sizes.length} taglie</span>
                {totHere === 0 && <Pill tone="neg" className="ml-2">Esaurito</Pill>}
                {totHere > 0 && totHere <= 5 && <Pill tone="warn" className="ml-2">Scorta bassa</Pill>}
              </div>
            </div>
          </div>
        </div>

        {/* Matrice taglia × colore */}
        <Card
          title="Matrice varianti · taglia × colore"
          action={
            <div className="flex items-center gap-2">
              <FilterSelect
                label="Negozio"
                value={storeView}
                onChange={setStoreView}
                options={STORES.filter(s=>article.stock[s.id]).map(s => ({ v: s.id, l: s.name }))}
              />
            </div>
          }
        >
          <div className="overflow-x-auto -mx-5 px-5">
            <table className="border-separate border-spacing-0 text-[13.5px]">
              <thead>
                <tr>
                  <th className="sticky left-0 bg-surface text-left px-3 py-2.5 text-[11px] uppercase tracking-[0.08em] text-muted font-medium border-b border-line">Taglia</th>
                  {article.colors.map(c => (
                    <th key={c} className="px-2 py-2.5 border-b border-line min-w-[100px]">
                      <div className="flex items-center justify-center gap-2">
                        <ColorDot name={c} size={14}/>
                        <span className="text-[12.5px] text-ink font-medium">{c}</span>
                      </div>
                    </th>
                  ))}
                  <th className="px-3 py-2.5 border-b border-line text-[11px] uppercase tracking-[0.08em] text-muted font-medium text-right">Tot. riga</th>
                </tr>
              </thead>
              <tbody>
                {article.sizes.map(s => {
                  const rowTotal = article.colors.reduce((sum, c) => sum + (matrixStock[c]?.[s] ?? 0), 0);
                  return (
                    <tr key={s}>
                      <td className="sticky left-0 bg-surface px-3 py-2 border-b border-line2 num text-[14px] text-ink font-medium">Tg {s}</td>
                      {article.colors.map(c => {
                        const v = matrixStock[c]?.[s] ?? 0;
                        const tone = v === 0 ? 'bg-[var(--danger-50)] text-[var(--danger-700)]' : v <= 2 ? 'bg-[var(--warning-50)] text-[var(--warning-700)]' : v >= 6 ? 'bg-[var(--success-50)] text-[var(--success-700)]' : 'text-ink';
                        return (
                          <td key={c} className="border-b border-line2 px-1.5 py-1.5">
                            <div
                              onClick={() => { if (window.__toast) window.__toast(`${article.name} · ${c} Tg ${s} → registra il movimento in Magazzino`, 'info'); if (window.__nav) window.__nav('magazzino'); }}
                              className={`row-h min-h-[44px] flex items-center justify-center rounded-sm border border-line2 hover:border-strong cursor-pointer transition-all duration-fast ease-standard num text-[16px] font-medium ${tone}`}>
                              {v}
                            </div>
                          </td>
                        );
                      })}
                      <td className="border-b border-line2 px-3 py-2 num text-[14px] text-ink text-right font-semibold">{rowTotal}</td>
                    </tr>
                  );
                })}
                <tr>
                  <td className="sticky left-0 bg-paper px-3 py-2.5 text-[11px] uppercase tracking-[0.08em] text-muted font-medium">Tot. colonna</td>
                  {article.colors.map(c => {
                    const colTotal = article.sizes.reduce((sum, s) => sum + (matrixStock[c]?.[s] ?? 0), 0);
                    return (
                      <td key={c} className="px-2 py-2.5 num text-[14px] text-ink text-center font-semibold bg-paper">{colTotal}</td>
                    );
                  })}
                  <td className="px-3 py-2.5 num text-[16px] text-ink text-right font-semibold bg-paper">{totHere}</td>
                </tr>
              </tbody>
            </table>
          </div>
          <div className="mt-4 flex items-center gap-5 text-[12px] text-muted">
            <span className="inline-flex items-center gap-1.5"><span className="w-3 h-3 rounded bg-[var(--success-500)]"></span>≥ 6 pezzi</span>
            <span className="inline-flex items-center gap-1.5"><span className="w-3 h-3 rounded bg-[var(--warning-500)]"></span>1–2 pezzi · critico</span>
            <span className="inline-flex items-center gap-1.5"><span className="w-3 h-3 rounded bg-[var(--danger-50)]"></span>Esaurito</span>
            <span className="ml-auto">Tocca una cella per registrare un movimento manuale</span>
          </div>
        </Card>

        {/* Prezzi multi-store + Canali */}
        <div className="grid grid-cols-2 gap-6">
          <Card title="Listino multi-negozio">
            <table className="w-full text-[14px]">
              <thead>
                <tr className="text-left text-muted uppercase text-[11px] tracking-[0.08em] hairline">
                  <th className="py-2.5 font-medium">Negozio</th>
                  <th className="py-2.5 font-medium text-right">Listino</th>
                  <th className="py-2.5 font-medium text-right">Δ vs base</th>
                  <th className="py-2.5 font-medium text-right"></th>
                </tr>
              </thead>
              <tbody>
                {STORES.map(s => {
                  const p = article.prices[s.id];
                  if (p == null) return null;
                  const delta = p - article.basePrice;
                  return (
                    <tr key={s.id} className="border-b border-line2 last:border-0">
                      <td className="py-3 text-ink">{s.name}</td>
                      <td className="py-3 num text-ink text-right font-medium">{fmtEur(p)}</td>
                      <td className={`py-3 num text-right ${delta === 0 ? 'text-muted' : delta > 0 ? 'text-pos' : 'text-neg'}`}>
                        {delta === 0 ? '—' : (delta > 0 ? `+${fmtEur(delta)}` : `−${fmtEur(Math.abs(delta))}`)}
                      </td>
                      <td className="py-3 text-right">
                        <button onClick={() => setEditOpen(true)} className="text-[12.5px] text-ink hover:underline">Modifica</button>
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
            <div className="mt-3 text-[12px] text-muted">Prezzo base: <span className="num text-ink font-medium">{fmtEur(article.basePrice)}</span> · IVA inclusa</div>
          </Card>

          <Card title="Pubblicazione canali di vendita">
            <div className="space-y-3">
              {[
                { id: 'negozio',    label: 'Negozio fisico', sub: 'visibile in cassa e nei resi', icon: 'Store' },
                { id: 'ecommerce',  label: 'E-commerce',     sub: 'shop online del brand', icon: 'Globe' },
                { id: 'marketplace',label: 'Marketplace',    sub: 'Farfetch · pubblicazione varianti e prezzi', icon: 'Diamond' },
              ].map(c => {
                const Ico = I[c.icon];
                const on = channels[c.id];
                return (
                  <label key={c.id} className={`flex items-center gap-3.5 p-3.5 rounded-md border cursor-pointer transition-all duration-fast ease-standard
                    ${on ? 'bg-[var(--bg-selected)] shadow-[inset_0_0_0_1px_var(--accent-blue)]' : 'border-line bg-surface hover:border-strong'}`}>
                    <span className={`w-10 h-10 rounded-md flex items-center justify-center shrink-0
                      ${on ? 'bg-[var(--bg-selected)] text-[var(--accent-blue)]' : 'bg-line2 text-muted'}`}>
                      <Ico size={18}/>
                    </span>
                    <div className="flex-1 min-w-0">
                      <div className="text-[14.5px] font-medium text-ink">{c.label}</div>
                      <div className="text-[12px] text-muted mt-0.5">{c.sub}</div>
                    </div>
                    <Toggle on={on} onChange={(v)=>{ const next = {...channels, [c.id]: v}; setChannels(next); if (window.__API__) window.__API__.post('/api/articles/channels', { id: article.id, channels: next }).catch(()=>{}); }}/>
                  </label>
                );
              })}
            </div>
            <div className="mt-4 p-3.5 rounded-md bg-paper border border-line text-[12.5px] text-muted">
              <span className="text-ink font-medium">Suggerimento.</span> Modifiche ai canali vengono propagate alla pubblicazione successiva (entro 15 min).
            </div>
          </Card>
        </div>
      </div>
      {editOpen && <CatalogoArticleForm article={article} onClose={() => setEditOpen(false)}/>}
    </>
  );
};

// ─── Toggle component — dimensioni fisse inline (track 44×26, knob 20×20, padding 3px) ───
const Toggle = ({ on, onChange }) => (
  <button
    type="button"
    role="switch"
    aria-checked={!!on}
    onClick={() => onChange(!on)}
    className="focus-ring"
    style={{
      position: 'relative', flexShrink: 0, border: 'none', padding: 0, cursor: 'pointer',
      width: '44px', height: '26px', borderRadius: '13px',
      background: on ? 'var(--accent-blue)' : 'var(--border-strong)',
      transition: 'background 160ms cubic-bezier(0.32,0.72,0,1)',
    }}
  >
    <span style={{
      position: 'absolute',
      top: '3px',
      left: on ? '21px' : '3px',
      width: '20px', height: '20px', borderRadius: '50%',
      background: 'white',
      boxShadow: '0 1px 2px rgba(0,0,0,0.2)',
      transition: 'left 160ms cubic-bezier(0.32,0.72,0,1)',
    }} />
  </button>
);

// ─── Key/Value display ───
const KeyVal = ({ label, value, mono }) => (
  <div>
    <div className="text-[11px] uppercase tracking-[0.08em] text-muted font-medium">{label}</div>
    <div className={`mt-1 text-[14.5px] text-ink ${mono ? 'num font-medium' : ''}`}>{value}</div>
  </div>
);

// ─── Form crea/modifica articolo ───
const _catFLb = 'block text-[12px] font-semibold uppercase tracking-[0.04em] text-muted mb-1.5';
const _catFIn = 'w-full h-11 px-3 rounded-md border border-line bg-surface text-[14px] text-ink focus:border-strong focus:outline-none transition-all duration-fast ease-standard';

const CatalogoArticleForm = ({ article, onClose }) => {
  const isEdit = !!article;
  const [f, setF] = useStateC(() => ({
    id: article?.id || '',
    name: article?.name || '',
    brand: article?.brand || 'Bone & Ink',
    cat: article?.cat || '',
    season: article?.season || '',
    status: article?.status || 'Bozza',
    description: article?.description || '',
    composition: article?.composition || '',
    basePrice: article?.basePrice ?? 0,
    taxRate: article?.taxRate ?? 22,
    colors: (article?.colors || []).join(', '),
    sizes: (article?.sizes || []).join(', '),
    channels: { ...(article?.channels || { negozio: false, ecommerce: false, marketplace: false }) },
  }));
  const [saving, setSaving] = useStateC(false);
  const set = (k, v) => setF(prev => ({ ...prev, [k]: v }));

  const doSave = () => {
    const colors = f.colors.split(',').map(s => s.trim()).filter(Boolean);
    const sizes  = f.sizes.split(',').map(s => s.trim()).filter(Boolean);
    const id = (isEdit ? article.id : f.id).trim().toUpperCase();
    if (!id || !f.name.trim()) {
      if (window.__toast) window.__toast(!id ? 'Inserisci il codice / SKU' : 'Inserisci il nome articolo', 'error');
      return;
    }
    const price = parseFloat(f.basePrice) || 0;
    const body = {
      id, name: f.name.trim(), brand: f.brand.trim(), cat: f.cat.trim(), season: f.season.trim(),
      status: f.status, description: f.description, composition: f.composition,
      basePrice: price, taxRate: parseInt(f.taxRate) || 22,
      colors: colors.length ? colors : ['—'], sizes: sizes.length ? sizes : ['U'],
      channels: f.channels, images: article?.images || 0,
      // In modifica manteniamo i prezzi esistenti; in creazione = prezzo base per ogni negozio.
      prices: isEdit ? article.prices : Object.fromEntries((STORES || []).map(s => [s.id, price])),
      // NB: niente 'stock' nel payload → il backend preserva le giacenze (modifica)
      // o crea l'articolo senza giacenze (nuovo), senza sovrascrivere lo stock reale.
    };
    if (window.__API__) {
      setSaving(true);
      window.__API__.mutate('/api/articles', { article: body })
        .then(() => { setSaving(false); if (window.__toast) window.__toast(isEdit ? 'Articolo aggiornato' : 'Articolo creato', 'success'); onClose(); })
        .catch(() => { setSaving(false); /* l'errore mostra già un toast dal client */ });
    } else { onClose(); }
  };

  return (
    <Modal open={true} onClose={onClose} title={isEdit ? 'Modifica articolo' : 'Nuovo articolo'} width="max-w-[680px]"
      footer={
        <div className="flex items-center justify-between w-full">
          <Btn variant="outline" size="md" onClick={onClose}>Annulla</Btn>
          <button onClick={doSave} disabled={saving}
            className="h-12 px-6 rounded-md bg-[var(--accent-blue)] text-[var(--text-inverse)] font-semibold text-[15px] flex items-center gap-2 hover:bg-[var(--accent-blue-hover)] active:bg-[var(--accent-blue-active)] disabled:opacity-50 transition-all duration-fast ease-standard">
            <I.Check size={18}/> {isEdit ? 'Salva modifiche' : 'Crea articolo'}
          </button>
        </div>
      }>
      <div className="space-y-4">
        {!isEdit && (
          <div>
            <label className={_catFLb}>Codice / SKU</label>
            <input className={_catFIn} value={f.id} onChange={e => set('id', e.target.value)} placeholder="es. GI-1029"/>
          </div>
        )}
        <div>
          <label className={_catFLb}>Nome</label>
          <input className={_catFIn} value={f.name} onChange={e => set('name', e.target.value)}/>
        </div>
        <div className="grid grid-cols-2 gap-3">
          <div><label className={_catFLb}>Brand</label>
            <select className={_catFIn} value={f.brand} onChange={e => set('brand', e.target.value)}>
              <option value="">— scegli —</option>
              {(window.LISTS?.brand || []).map(x => <option key={x} value={x}>{x}</option>)}
              {f.brand && !(window.LISTS?.brand || []).includes(f.brand) && <option value={f.brand}>{f.brand}</option>}
            </select></div>
          <div><label className={_catFLb}>Categoria</label>
            <select className={_catFIn} value={f.cat} onChange={e => set('cat', e.target.value)}>
              <option value="">— scegli —</option>
              {(window.LISTS?.categorie || []).map(x => <option key={x} value={x}>{x}</option>)}
              {f.cat && !(window.LISTS?.categorie || []).includes(f.cat) && <option value={f.cat}>{f.cat}</option>}
            </select></div>
        </div>
        <div className="grid grid-cols-2 gap-3">
          <div><label className={_catFLb}>Stagione</label>
            <select className={_catFIn} value={f.season} onChange={e => set('season', e.target.value)}>
              <option value="">— scegli —</option>
              {(window.LISTS?.stagioni || []).map(x => <option key={x} value={x}>{x}</option>)}
              {f.season && !(window.LISTS?.stagioni || []).includes(f.season) && <option value={f.season}>{f.season}</option>}
            </select></div>
          <div>
            <label className={_catFLb}>Stato</label>
            <select className={_catFIn} value={f.status} onChange={e => set('status', e.target.value)}>
              <option>Bozza</option><option>Pubblicato</option><option>Archiviato</option>
            </select>
          </div>
        </div>
        <div className="grid grid-cols-2 gap-3">
          <div><label className={_catFLb}>Prezzo base €</label><input type="number" className={_catFIn} value={f.basePrice} onChange={e => set('basePrice', e.target.value)}/></div>
          <div><label className={_catFLb}>IVA %</label><input type="number" className={_catFIn} value={f.taxRate} onChange={e => set('taxRate', e.target.value)}/></div>
        </div>
        <div><label className={_catFLb}>Colori (separati da virgola)</label><input className={_catFIn} value={f.colors} onChange={e => set('colors', e.target.value)} placeholder="Navy, Nero, Bianco"/></div>
        <div><label className={_catFLb}>Taglie (separate da virgola)</label><input className={_catFIn} value={f.sizes} onChange={e => set('sizes', e.target.value)} placeholder="46, 48, 50"/></div>
        <div><label className={_catFLb}>Descrizione</label><textarea className={`${_catFIn} h-20 py-2 resize-none`} value={f.description} onChange={e => set('description', e.target.value)}/></div>
        <div><label className={_catFLb}>Composizione</label><input className={_catFIn} value={f.composition} onChange={e => set('composition', e.target.value)}/></div>
        <div>
          <label className={_catFLb}>Canali di vendita</label>
          <div className="flex gap-5 mt-1">
            {[['negozio', 'Negozio'], ['ecommerce', 'E-commerce'], ['marketplace', 'Marketplace']].map(([k, lbl]) => (
              <label key={k} className="flex items-center gap-2 text-[14px] text-ink cursor-pointer">
                <Toggle on={!!f.channels[k]} onChange={v => set('channels', { ...f.channels, [k]: v })}/> {lbl}
              </label>
            ))}
          </div>
        </div>
      </div>
    </Modal>
  );
};

// ─── Catalogo wrapper ───
const CatalogoView = ({ articleId, onOpen, onBack, activeStoreId = STORE.id }) => (
  articleId
    ? <CatalogoDetail articleId={articleId} onBack={onBack} activeStoreId={activeStoreId}/>
    : <CatalogoList onOpen={onOpen} activeStoreId={activeStoreId}/>
);

Object.assign(window, { CatalogoView, ColorDot, ChannelPill, FilterSelect, Toggle, KeyVal, totalStock, stockBadge });
