/* importflow.jsx — the three import screens.
   UploadScreen (§5.3) · PreviewScreen (§5.4, the consent gate) · RunDetailScreen (§5.5).
   Exported to window. */

var { Button, Eyebrow } = window.WiggleverseDesignSystem_94cd80 || {};

const { useState: _ifState, useEffect: _ifEffect, useRef: _ifRef } = React;

/* ============================ small shared bits ============================ */

function ScreenHeader({ eyebrow, title, onBack, backLabel = 'Products', right }) {
  return (
    <div style={{ marginBottom: '1.6rem' }}>
      <button onClick={onBack} style={{
        display: 'inline-flex', alignItems: 'center', gap: '.35em', font: 'inherit',
        fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: '.85rem',
        color: 'var(--wv-violet)', background: 'transparent', border: 'none', cursor: 'pointer',
        padding: 0, marginBottom: '.9rem',
      }}>
        <Icon name="arrowLeft" size={15} /> Back to {backLabel}
      </button>
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: '1rem', flexWrap: 'wrap' }}>
        <div style={{ minWidth: 0 }}>
          {eyebrow && <Eyebrow onLight>{eyebrow}</Eyebrow>}
          <h1 style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: '1.9rem', letterSpacing: '-0.015em', color: 'var(--text-on-light)', margin: '.35rem 0 0', overflowWrap: 'anywhere' }}>{title}</h1>
        </div>
        {right}
      </div>
    </div>
  );
}

/* ================================ UPLOAD ================================== */

const SAMPLE_FILES = [
  { key: 'canonical', name: 'spring-2026-pricing.csv', size: '48 rows · 11 KB', desc: 'Canonical format — a seasonal repricing with new arrivals, updates, and a few bad rows.', icon: 'file' },
  { key: 'shopify', name: 'shopify-store-export.csv', size: '1,894 rows · 2.1 MB', desc: 'An unmodified Shopify product export — auto-detected and mapped to canonical.', icon: 'file' },
  { key: 'roundtrip', name: 'wander-wool-catalog-export.csv', size: '1,620 rows · 1.7 MB', desc: 'Your own export, re-imported — the lossless round-trip (nothing to change).', icon: 'refresh' },
];
const REJECT_FILE = { key: 'reject', name: 'orders-q1.csv', size: '900 rows · 240 KB', desc: 'A file that is not a product catalog — to see an honest whole-file rejection.', icon: 'alert' };

function UploadScreen({ onBack, onValidated, toast }) {
  const [phase, setPhase] = _ifState('idle'); // idle | validating | rejected
  const [progress, setProgress] = _ifState({ done: 0, total: 0, file: '' });
  const [dragOver, setDragOver] = _ifState(false);
  const timer = _ifRef(null);
  const fileInput = _ifRef(null);

  _ifEffect(() => () => clearInterval(timer.current), []);

  const start = (file) => {
    if (file.key === 'reject') {
      setPhase('rejected');
      return;
    }
    const total = file.rows;
    setProgress({ done: 0, total, file: file.name });
    setPhase('validating');
    clearInterval(timer.current);
    const step = Math.max(1, Math.round(total / 22));
    timer.current = setInterval(() => {
      setProgress((p) => {
        const done = Math.min(total, p.done + step);
        if (done >= total) {
          clearInterval(timer.current);
          setTimeout(() => onValidated(file.key), 320);
        }
        return { ...p, done };
      });
    }, 70);
  };

  const ROWS = { canonical: 48, shopify: 1894, roundtrip: 1620 };
  const pick = (key, name) => start({ key, name, rows: ROWS[key] });

  const onDrop = (e) => {
    e.preventDefault(); setDragOver(false);
    pick('canonical', 'spring-2026-pricing.csv');
    toast('Reading dropped file…');
  };

  return (
    <div>
      <ScreenHeader eyebrow="Import" title="Import products" onBack={onBack} />

      {phase === 'validating' ? (
        <Card style={{ padding: '2.4rem 2rem' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: '.6rem', marginBottom: '1rem' }}>
            <Spinner size={20} />
            <span style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: '1.1rem', color: 'var(--text-on-light)' }}>Validating…</span>
          </div>
          <div style={{ fontSize: '.92rem', color: 'var(--text-on-light-soft)', marginBottom: '.7rem' }}>
            {progress.file} — {progress.done.toLocaleString()} of {progress.total.toLocaleString()} rows
          </div>
          <ProgressBar value={progress.done} max={progress.total} />
          <div style={{ marginTop: '1.4rem', display: 'flex', alignItems: 'center', gap: '.6rem' }}>
            <Button variant="ghost" onLight onClick={() => { clearInterval(timer.current); setPhase('idle'); }}>Cancel</Button>
            <span style={{ fontSize: '.85rem', color: 'var(--text-on-light-soft)' }}>Canceling is free — nothing has been written.</span>
          </div>
        </Card>
      ) : (
        <>
          {/* drop zone */}
          <div
            onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
            onDragLeave={() => setDragOver(false)}
            onDrop={onDrop}
            onClick={() => fileInput.current && fileInput.current.click()}
            style={{
              border: `2px dashed ${dragOver ? 'var(--wv-violet)' : 'var(--paper-line-strong)'}`,
              background: dragOver ? 'var(--violet-tint)' : 'var(--surface-card-light)',
              borderRadius: '16px', padding: '2.6rem 2rem', textAlign: 'center', cursor: 'pointer',
              transition: 'border-color var(--dur-fast), background var(--dur-fast)',
            }}>
            <input ref={fileInput} type="file" accept=".csv" style={{ display: 'none' }}
              onChange={() => { pick('canonical', 'spring-2026-pricing.csv'); }} />
            <div style={{ width: 54, height: 54, margin: '0 auto 1rem', borderRadius: 14, background: 'var(--violet-tint)', display: 'grid', placeItems: 'center' }}>
              <Icon name="upload" size={26} style={{ color: 'var(--wv-violet)' }} />
            </div>
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: '1.15rem', color: 'var(--text-on-light)' }}>Drop a CSV here, or click to choose</div>
            <div style={{ fontSize: '.92rem', color: 'var(--text-on-light-soft)', marginTop: '.4rem' }}>CSV, up to 5,000 rows · 10 MB. Selecting a file starts validation right away.</div>
            <div style={{ fontSize: '.9rem', color: 'var(--text-on-light-soft)', marginTop: '1.1rem', borderTop: '1px solid var(--paper-line)', paddingTop: '1.1rem', maxWidth: 460, margin: '1.1rem auto 0' }}>
              Works with the <strong style={{ color: 'var(--text-on-light)' }}>canonical format</strong> or a <strong style={{ color: 'var(--text-on-light)' }}>Shopify product export</strong> — we detect which.
            </div>
            <div style={{ display: 'flex', gap: '1.4rem', justifyContent: 'center', marginTop: '.9rem' }} onClick={(e) => e.stopPropagation()}>
              <a onClick={(e) => { e.preventDefault(); IE_downloadText('wander-wool-sample.csv', IE_SAMPLE_CSV); toast('Sample CSV downloaded', 'success'); }} href="#" style={linkStyle}><Icon name="download" size={14} /> Sample CSV</a>
              <a onClick={(e) => e.preventDefault()} href="#" style={linkStyle}><Icon name="link" size={14} /> Column reference</a>
            </div>
          </div>

          {/* file-level rejection */}
          {phase === 'rejected' && (
            <div style={{ display: 'flex', alignItems: 'flex-start', gap: '.7rem', marginTop: '1.2rem', padding: '1rem 1.2rem', borderRadius: '12px', background: 'var(--st-error-tint)', border: '1px solid var(--st-error-line)' }}>
              <Icon name="alert" size={19} style={{ color: 'var(--st-error)', marginTop: '.1rem' }} />
              <div>
                <div style={{ fontWeight: 600, color: 'var(--text-on-light)' }}>This file can't be imported as a catalog.</div>
                <div style={{ fontSize: '.92rem', color: 'var(--text-on-light-soft)', marginTop: '.2rem' }}>It's missing the required column <code style={codeStyle}>Title</code> and matches no known dialect. Nothing was imported and no import run was recorded. Fix the file and try again.</div>
              </div>
            </div>
          )}

          {/* sample files */}
          <div style={{ marginTop: '2rem' }}>
            <div style={{ fontSize: '.78rem', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '.08em', color: 'var(--text-on-light-soft)', marginBottom: '.8rem' }}>Or try a sample file</div>
            <div style={{ display: 'grid', gap: '.7rem' }}>
              {[...SAMPLE_FILES, REJECT_FILE].map((f) => (
                <button key={f.key} onClick={() => start({ ...f, rows: ROWS[f.key] })} className="ie-samplefile" style={{
                  display: 'flex', alignItems: 'center', gap: '1rem', width: '100%', textAlign: 'left',
                  background: 'var(--surface-card-light)', border: '1px solid var(--paper-line)',
                  borderRadius: '12px', padding: '.9rem 1.1rem', cursor: 'pointer', font: 'inherit',
                  transition: 'border-color var(--dur-fast), transform var(--dur-fast)',
                }}>
                  <span style={{ width: 38, height: 38, flexShrink: 0, borderRadius: 10, background: f.key === 'reject' ? 'var(--st-error-tint)' : 'var(--violet-tint)', display: 'grid', placeItems: 'center' }}>
                    <Icon name={f.icon} size={18} style={{ color: f.key === 'reject' ? 'var(--st-error)' : 'var(--wv-violet)' }} />
                  </span>
                  <span style={{ flex: 1, minWidth: 0 }}>
                    <span style={{ display: 'flex', alignItems: 'baseline', gap: '.6rem', minWidth: 0 }}>
                      <span style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: '.96rem', color: 'var(--text-on-light)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{f.name}</span>
                      <span style={{ fontSize: '.78rem', color: 'var(--text-on-light-soft)', whiteSpace: 'nowrap', flexShrink: 0 }}>{f.size}</span>
                    </span>
                    <span style={{ display: 'block', fontSize: '.88rem', color: 'var(--text-on-light-soft)', marginTop: '.15rem' }}>{f.desc}</span>
                  </span>
                  <Icon name="arrowRight" size={16} style={{ color: 'var(--wv-violet)' }} />
                </button>
              ))}
            </div>
          </div>
        </>
      )}
    </div>
  );
}

/* ================================ PREVIEW ================================= */

function FieldRow({ label, value, note }) {
  return (
    <div style={{ display: 'flex', gap: '1rem', padding: '.4rem 0', borderBottom: '1px solid var(--paper-line)' }}>
      <div style={{ width: 130, flexShrink: 0, fontSize: '.82rem', color: 'var(--text-on-light-soft)', fontWeight: 500 }}>{label}</div>
      <div style={{ flex: 1, fontSize: '.9rem', color: 'var(--text-on-light)' }}>
        {value}
        {note && <span style={{ display: 'block', fontSize: '.78rem', color: 'var(--st-update)', marginTop: '.2rem' }}>⚠ {note}</span>}
      </div>
    </div>
  );
}

function RecordDetail({ rec }) {
  const d = rec.detail || {};
  if (rec.kind === 'add') {
    return (
      <div style={{ padding: '.4rem 0 .2rem' }}>
        <div style={{ fontSize: '.78rem', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '.06em', color: 'var(--st-add)', marginBottom: '.5rem' }}>New product — fields to be set</div>
        <div style={{ marginBottom: '1rem' }}>
          {d.product.map((row, i) => <FieldRow key={i} label={row[0]} value={row[1]} note={row[2]} />)}
        </div>
        <div style={{ display: 'flex', gap: '1.4rem', flexWrap: 'wrap' }}>
          <div style={{ flex: '1 1 280px' }}>
            <div style={{ fontSize: '.78rem', fontWeight: 600, color: 'var(--text-on-light-soft)', marginBottom: '.4rem' }}>Variants ({rec.variants}) · sample</div>
            <div style={{ display: 'grid', gap: '.3rem' }}>
              {d.variantsPreview.map((v, i) => (
                <div key={i} style={{ display: 'flex', alignItems: 'center', gap: '.6rem', fontSize: '.86rem', color: 'var(--text-on-light)' }}>
                  <span style={{ minWidth: 130, fontWeight: 500 }}>{v[0]}</span>
                  <span style={{ color: 'var(--text-on-light-soft)', flex: 1 }}>{v[1]}</span>
                  <span style={{ fontWeight: 600 }}>{v[2]}</span>
                </div>
              ))}
              {rec.variants > d.variantsPreview.length && <div style={{ fontSize: '.82rem', color: 'var(--text-on-light-soft)' }}>+ {rec.variants - d.variantsPreview.length} more variants</div>}
            </div>
          </div>
          <div style={{ flex: '0 0 auto', display: 'flex', alignItems: 'center', gap: '.45em', color: 'var(--text-on-light-soft)', fontSize: '.86rem' }}>
            <Icon name="image" size={15} /> {d.images} image{d.images === 1 ? '' : 's'} to fetch
          </div>
        </div>
      </div>
    );
  }
  if (rec.kind === 'update') {
    return (
      <div style={{ padding: '.4rem 0 .2rem' }}>
        <div style={{ fontSize: '.78rem', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '.06em', color: 'var(--st-update)', marginBottom: '.5rem' }}>Changes — before → after</div>
        <div style={{ display: 'grid', gap: '.1rem' }}>
          {d.changes.map((c, i) => (
            <div key={i} style={{ display: 'flex', gap: '1rem', padding: '.55rem 0', borderBottom: '1px solid var(--paper-line)', alignItems: 'baseline', opacity: c.noop ? .6 : 1 }}>
              <div style={{ width: 170, flexShrink: 0 }}>
                <div style={{ fontSize: '.88rem', fontWeight: 600, color: 'var(--text-on-light)' }}>{c.field}</div>
                <div style={{ fontSize: '.76rem', color: 'var(--text-on-light-soft)' }}>{c.scope}</div>
              </div>
              <div style={{ flex: 1 }}><DiffPair before={c.before} after={c.after} noop={c.noop} /></div>
            </div>
          ))}
        </div>
      </div>
    );
  }
  if (rec.kind === 'error') {
    return (
      <div style={{ padding: '.5rem 0 .2rem' }}>
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: '.6rem', padding: '.8rem 1rem', borderRadius: 10, background: 'var(--st-error-tint)', border: '1px solid var(--st-error-line)' }}>
          <Icon name="alert" size={17} style={{ color: 'var(--st-error)', marginTop: '.1rem' }} />
          <div style={{ fontSize: '.9rem', color: 'var(--text-on-light)' }}>
            <span style={{ fontWeight: 600 }}>Row {rec.line} · {rec.column}</span>
            <div style={{ color: 'var(--text-on-light-soft)', marginTop: '.2rem' }}>{rec.message}</div>
            <div style={{ marginTop: '.4rem', fontSize: '.82rem', color: 'var(--text-on-light-soft)' }}>This product will not be imported. Correct the row and re-import — the valid products still go through.</div>
          </div>
        </div>
      </div>
    );
  }
  return <div style={{ padding: '.6rem 0', fontSize: '.88rem', color: 'var(--text-on-light-soft)' }}>This product matches your catalog exactly — nothing to change.</div>;
}

function PreviewRow({ rec, expanded, onToggle }) {
  return (
    <div style={{ borderBottom: '1px solid var(--paper-line)' }}>
      <button onClick={onToggle} className="ie-prow" style={{
        display: 'flex', alignItems: 'center', gap: '1rem', width: '100%', textAlign: 'left',
        padding: '.85rem 1.2rem', background: expanded ? 'var(--violet-tint)' : 'transparent',
        border: 'none', cursor: 'pointer', font: 'inherit', transition: 'background var(--dur-fast)',
      }}>
        <Icon name="chevron" size={15} style={{ color: 'var(--text-on-light-soft)', transform: expanded ? 'rotate(90deg)' : 'none', transition: 'transform var(--dur-fast)' }} />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: '.96rem', color: 'var(--text-on-light)' }}>{rec.title}</div>
          <div style={{ fontSize: '.8rem', color: 'var(--text-on-light-soft)', fontFamily: 'var(--font-body)' }}>{rec.handle}</div>
        </div>
        <span style={{ fontSize: '.82rem', color: 'var(--text-on-light-soft)', whiteSpace: 'nowrap' }}>{rec.variants} variant{rec.variants === 1 ? '' : 's'}</span>
        <KindBadge kind={rec.kind} />
      </button>
      {expanded && <div style={{ padding: '0 1.2rem 1.1rem 2.4rem' }}><RecordDetail rec={rec} /></div>}
    </div>
  );
}

function ErrorTable({ errors }) {
  return (
    <Card pad="0" style={{ overflow: 'hidden' }}>
      <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '.88rem' }}>
        <thead>
          <tr style={{ textAlign: 'left', color: 'var(--text-on-light-soft)', fontSize: '.72rem', textTransform: 'uppercase', letterSpacing: '.06em' }}>
            <th style={{ padding: '.75rem 1.2rem', fontWeight: 600, width: 70 }}>Line</th>
            <th style={{ padding: '.75rem 1.2rem', fontWeight: 600, width: 150 }}>Column</th>
            <th style={{ padding: '.75rem 1.2rem', fontWeight: 600 }}>What's wrong</th>
          </tr>
        </thead>
        <tbody>
          {errors.map((e, i) => (
            <tr key={i} style={{ borderTop: '1px solid var(--paper-line)' }}>
              <td style={{ padding: '.8rem 1.2rem', fontVariantNumeric: 'tabular-nums', color: 'var(--st-error)', fontWeight: 600 }}>{e.line}</td>
              <td style={{ padding: '.8rem 1.2rem' }}><code style={codeStyle}>{e.column}</code></td>
              <td style={{ padding: '.8rem 1.2rem', color: 'var(--text-on-light)' }}>
                <span style={{ fontWeight: 600 }}>{e.title}</span> — {e.message}
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </Card>
  );
}

function PreviewScreen({ scenario, onCancel, onConfirm }) {
  const order = ['add', 'update', 'unchanged', 'error'];
  const firstActive = order.find((k) => scenario.summary[k] > 0) || 'unchanged';
  const [active, setActive] = _ifState(firstActive);
  const [expanded, setExpanded] = _ifState(() => new Set());
  const [warnOpen, setWarnOpen] = _ifState(true);

  const toggle = (h) => setExpanded((s) => { const n = new Set(s); n.has(h) ? n.delete(h) : n.add(h); return n; });

  const applyCount = scenario.summary.add + scenario.summary.update;
  const records = scenario.records[active] || [];
  const extra = (scenario.extra && scenario.extra[active]) || 0;

  return (
    <div style={{ paddingBottom: 90 }}>
      <ScreenHeader
        eyebrow="Import preview"
        title={scenario.file}
        onBack={onCancel}
        right={
          <div style={{ textAlign: 'right' }}>
            <div style={{ display: 'inline-flex', alignItems: 'center', gap: '.45em', padding: '.4rem .85rem', borderRadius: 999, background: scenario.dialectKind === 'shopify' ? 'var(--st-update-tint)' : 'var(--violet-tint)', border: `1px solid ${scenario.dialectKind === 'shopify' ? 'var(--st-update-line)' : 'var(--violet-line)'}` }}>
              <Icon name={scenario.dialectKind === 'shopify' ? 'refresh' : 'check'} size={14} style={{ color: scenario.dialectKind === 'shopify' ? 'var(--st-update)' : 'var(--wv-violet)' }} />
              <span style={{ fontSize: '.84rem', fontWeight: 600, color: 'var(--text-on-light)' }}>Recognized: {scenario.dialect}</span>
            </div>
          </div>
        }
      />

      {/* nothing-written reassurance */}
      <div style={{ display: 'flex', alignItems: 'center', gap: '.5em', fontSize: '.86rem', color: 'var(--text-on-light-soft)', marginBottom: '1.3rem', marginTop: '-.6rem' }}>
        <Icon name="check" size={14} style={{ color: 'var(--st-add)' }} /> Nothing has been written to your catalog yet. This is a preview.
      </div>

      {/* warnings band */}
      {scenario.unknownColumns.length > 0 && (
        <div style={{ marginBottom: '1.3rem', borderRadius: '12px', background: 'var(--st-update-tint)', border: '1px solid var(--st-update-line)', overflow: 'hidden' }}>
          <button onClick={() => setWarnOpen((o) => !o)} style={{ display: 'flex', alignItems: 'center', gap: '.6rem', width: '100%', padding: '.8rem 1.1rem', background: 'transparent', border: 'none', cursor: 'pointer', font: 'inherit', textAlign: 'left' }}>
            <Icon name="alert" size={17} style={{ color: 'var(--st-update)' }} />
            <span style={{ flex: 1, fontSize: '.92rem', color: 'var(--text-on-light)' }}>
              <strong style={{ fontWeight: 600 }}>{scenario.unknownColumns.length} columns won't be imported.</strong>
              <span style={{ color: 'var(--text-on-light-soft)' }}> They're recognized but have no home in your catalog — warned, never silently dropped.</span>
            </span>
            <Icon name="chevronDown" size={15} style={{ color: 'var(--text-on-light-soft)', transform: warnOpen ? 'none' : 'rotate(-90deg)', transition: 'transform var(--dur-fast)' }} />
          </button>
          {warnOpen && (
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: '.4rem', padding: '0 1.1rem 1rem 2.7rem' }}>
              {scenario.unknownColumns.map((c) => (
                <span key={c} style={{ fontSize: '.8rem', color: 'var(--text-on-light-soft)', background: 'var(--surface-card-light)', border: '1px solid var(--paper-line-strong)', borderRadius: 999, padding: '.18rem .6rem', fontFamily: 'var(--font-body)', whiteSpace: 'nowrap' }}>{c}</span>
              ))}
            </div>
          )}
        </div>
      )}

      {/* summary tiles */}
      <div style={{ display: 'flex', gap: '.8rem', marginBottom: '1.6rem', flexWrap: 'wrap' }}>
        <StatTile n={scenario.summary.add} label="To add" kind="add" active={active === 'add'} onClick={() => setActive('add')} disabled={scenario.summary.add === 0} />
        <StatTile n={scenario.summary.update} label="To update" kind="update" active={active === 'update'} onClick={() => setActive('update')} disabled={scenario.summary.update === 0} />
        <StatTile n={scenario.summary.unchanged} label="Unchanged" kind="unchanged" active={active === 'unchanged'} onClick={() => setActive('unchanged')} disabled={scenario.summary.unchanged === 0} />
        <StatTile n={scenario.summary.error} label="In error" kind="error" active={active === 'error'} onClick={() => setActive('error')} disabled={scenario.summary.error === 0} />
      </div>

      {/* detail list / error table */}
      <div style={{ display: 'flex', alignItems: 'center', gap: '.5rem', marginBottom: '.7rem' }}>
        <KindBadge kind={active} size="sm" />
        <span style={{ fontSize: '.86rem', color: 'var(--text-on-light-soft)' }}>
          {active === 'error' ? 'These rows are reported, not applied.' : active === 'unchanged' ? 'Re-supplied rows that already match your catalog.' : 'Expand any product to see exactly what will happen.'}
        </span>
      </div>

      {active === 'error'
        ? <ErrorTable errors={records} />
        : (
          <Card pad="0" style={{ overflow: 'hidden' }}>
            {records.length === 0
              ? <div style={{ padding: '1.6rem', textAlign: 'center', color: 'var(--text-on-light-soft)', fontSize: '.9rem' }}>Nothing in this group.</div>
              : records.map((rec) => <PreviewRow key={rec.handle} rec={rec} expanded={expanded.has(rec.handle)} onToggle={() => toggle(rec.handle)} />)}
            {extra > 0 && (
              <div style={{ padding: '.85rem 1.2rem', fontSize: '.86rem', color: 'var(--text-on-light-soft)', borderTop: '1px solid var(--paper-line)', textAlign: 'center' }}>
                + {extra.toLocaleString()} more {active} {extra === 1 ? 'product' : 'products'} in this file
              </div>
            )}
          </Card>
        )}

      {/* sticky footer */}
      <div style={{
        position: 'sticky', bottom: 0, marginTop: '1.6rem', marginLeft: -8, marginRight: -8,
        padding: '1rem 1.2rem', borderRadius: '14px',
        background: 'rgba(255,255,255,.9)', backdropFilter: 'blur(8px)',
        border: '1px solid var(--paper-line-strong)', boxShadow: '0 -6px 20px rgba(14,18,48,.06)',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '1rem', flexWrap: 'wrap',
      }}>
        <div style={{ fontSize: '.9rem', color: 'var(--text-on-light-soft)' }}>
          {scenario.noop
            ? <span style={{ display: 'inline-flex', alignItems: 'center', gap: '.4em' }}><Icon name="check" size={15} style={{ color: 'var(--st-add)' }} /> Nothing to change — your catalog already matches this file.</span>
            : <span><strong style={{ color: 'var(--text-on-light)', fontWeight: 600 }}>{applyCount.toLocaleString()} products</strong> will be added or updated{scenario.summary.error ? <span>, <strong style={{ color: 'var(--st-error)' }}>{scenario.summary.error} rows</strong> left in error</span> : ''}.</span>}
        </div>
        <div style={{ display: 'flex', gap: '.7rem' }}>
          <Button variant="ghost" onLight onClick={onCancel}>Cancel</Button>
          <Button variant="primary" disabled={scenario.noop || applyCount === 0} onClick={() => onConfirm(scenario)}>
            <Icon name="check" size={16} /> Import {applyCount.toLocaleString()} products
          </Button>
        </div>
      </div>
    </div>
  );
}

/* ============================== RUN DETAIL =============================== */

function RunDetailScreen({ run, scenario, images, onBack, live }) {
  // live: true → animate applying → fetching → complete. false → show final state.
  const [phase, setPhase] = _ifState(live ? 'applying' : 'done');
  const [fetched, setFetched] = _ifState(live ? 0 : images.fetched + images.problems.length);
  const timer = _ifRef(null);
  const total = images.total;

  _ifEffect(() => {
    if (!live) return;
    const t1 = setTimeout(() => setPhase('fetching'), 1100);
    return () => clearTimeout(t1);
  }, [live]);

  _ifEffect(() => {
    if (phase !== 'fetching') return;
    if (fetched >= total) { setPhase('done'); return; }
    const id = setTimeout(() => setFetched((f) => Math.min(total, f + 1)), 120);
    return () => clearTimeout(id);
  }, [phase, fetched, total]);

  const counts = run || { added: scenario.summary.add, updated: scenario.summary.update, errors: scenario.summary.error };
  const hasProblems = images.problems.length > 0 || counts.errors > 0;
  const statusLabel = phase === 'applying' ? 'Importing…' : phase === 'fetching' ? 'Fetching images…' : (hasProblems ? 'Complete · with problems' : 'Complete');
  const statusColor = phase === 'done' ? (hasProblems ? 'var(--st-update)' : 'var(--st-add)') : 'var(--wv-violet)';

  return (
    <div>
      <ScreenHeader
        eyebrow="Import run"
        title={scenario.file}
        onBack={onBack}
        right={
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: '.5em', fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: '.95rem', color: statusColor }}>
            {phase === 'done' ? <span style={{ width: 9, height: 9, borderRadius: 999, background: statusColor }} /> : <Spinner size={15} />}
            {statusLabel}
          </span>
        }
      />
      <div style={{ fontSize: '.88rem', color: 'var(--text-on-light-soft)', marginTop: '-.7rem', marginBottom: '1.4rem' }}>
        Imported {run ? run.rel : 'just now'} by {window.IEData.STOREFRONT.email} · {scenario.dialect}
      </div>

      {/* result summary */}
      <div style={{ display: 'flex', gap: '.8rem', marginBottom: '1.8rem', flexWrap: 'wrap' }}>
        <ResultTile n={counts.added} label="Products added" kind="add" />
        <ResultTile n={counts.updated} label="Products updated" kind="update" />
        <ResultTile n={counts.errors} label="Rows in error" kind="error" />
      </div>

      {/* images section */}
      <section style={{ marginBottom: '1.8rem' }}>
        <h2 style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: '1.2rem', color: 'var(--text-on-light)', margin: '0 0 .9rem' }}>Images</h2>
        <Card>
          {phase !== 'done' && phase === 'applying' ? (
            <div style={{ display: 'flex', alignItems: 'center', gap: '.6rem', color: 'var(--text-on-light-soft)', fontSize: '.92rem' }}>
              <Spinner size={16} /> Applying catalog rows — the image fetch begins once products commit.
            </div>
          ) : phase === 'fetching' ? (
            <div>
              <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '.7rem' }}>
                <span style={{ display: 'flex', alignItems: 'center', gap: '.5em', fontWeight: 600, color: 'var(--text-on-light)' }}><Spinner size={15} /> Fetching images</span>
                <span style={{ fontVariantNumeric: 'tabular-nums', color: 'var(--text-on-light-soft)', fontSize: '.9rem' }}>{fetched.toLocaleString()} of {total.toLocaleString()}</span>
              </div>
              <ProgressBar value={fetched} max={total} />
              <div style={{ fontSize: '.84rem', color: 'var(--text-on-light-soft)', marginTop: '.7rem' }}>Running in the background — your catalog is already live. You can leave this page and come back.</div>
            </div>
          ) : (
            <div>
              <div style={{ display: 'flex', gap: '1.4rem', flexWrap: 'wrap', marginBottom: images.problems.length ? '1.2rem' : 0 }}>
                <SummaryStat label="Fetched" n={images.fetched} color="var(--st-add)" glyph="check" />
                <SummaryStat label="Rejected" n={images.problems.filter((p) => p.outcome === 'rejected').length} color="var(--st-error)" glyph="x" />
                <SummaryStat label="Failed" n={images.problems.filter((p) => p.outcome === 'failed').length} color="var(--st-error)" glyph="alert" />
              </div>
              {images.problems.length > 0 ? (
                <div>
                  <div style={{ fontSize: '.82rem', fontWeight: 600, color: 'var(--text-on-light-soft)', marginBottom: '.5rem' }}>Only problems are listed — these products show a placeholder until you re-import a corrected URL.</div>
                  <div style={{ border: '1px solid var(--paper-line)', borderRadius: 10, overflow: 'hidden' }}>
                    {images.problems.map((p, i) => (
                      <div key={i} style={{ display: 'flex', gap: '1rem', padding: '.8rem 1rem', borderTop: i ? '1px solid var(--paper-line)' : 'none', alignItems: 'flex-start' }}>
                        <span style={{ marginTop: '.1rem' }}><KindBadge kind="error" size="sm" /></span>
                        <div style={{ flex: 1, minWidth: 0 }}>
                          <div style={{ fontSize: '.9rem', color: 'var(--text-on-light)', fontWeight: 600 }}>{p.handle} <span style={{ color: 'var(--text-on-light-soft)', fontWeight: 400 }}>· {p.variant}</span></div>
                          <div style={{ fontSize: '.8rem', color: 'var(--text-on-light-soft)', fontFamily: 'var(--font-body)', wordBreak: 'break-all', margin: '.1rem 0' }}>{p.url}</div>
                          <div style={{ fontSize: '.84rem', color: 'var(--st-error)' }}>{p.outcome === 'rejected' ? 'Rejected' : 'Failed'} — {p.reason}</div>
                        </div>
                      </div>
                    ))}
                  </div>
                </div>
              ) : <div style={{ fontSize: '.9rem', color: 'var(--st-add)' }}>All images fetched cleanly.</div>}
            </div>
          )}
        </Card>
      </section>

      {/* error table */}
      {scenario.records.error.length > 0 && (
        <section>
          <h2 style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: '1.2rem', color: 'var(--text-on-light)', margin: '0 0 .9rem' }}>Rows in error <span style={{ fontWeight: 500, color: 'var(--text-on-light-soft)', fontSize: '1rem' }}>· unapplied</span></h2>
          <ErrorTable errors={scenario.records.error} />
        </section>
      )}
    </div>
  );
}

function ResultTile({ n, label, kind }) {
  const m = KIND_META[kind];
  return (
    <div style={{ flex: '1 1 0', minWidth: 120, background: 'var(--surface-card-light)', border: '1px solid var(--paper-line)', borderRadius: 12, padding: '1rem 1.2rem' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: '.4em', marginBottom: '.3rem' }}>
        <span style={{ width: 7, height: 7, borderRadius: 999, background: `var(--st-${m.cssvar})` }} />
        <span style={{ fontSize: '.74rem', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '.06em', color: 'var(--text-on-light-soft)' }}>{label}</span>
      </div>
      <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: '1.8rem', color: kind === 'error' && n === 0 ? 'var(--text-on-light)' : `var(--st-${m.cssvar})` }}>{n.toLocaleString()}</div>
    </div>
  );
}

function SummaryStat({ label, n, color, glyph }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: '.55rem' }}>
      <span style={{ width: 30, height: 30, borderRadius: 8, background: color, opacity: .12, position: 'absolute' }} />
      <span style={{ width: 30, height: 30, borderRadius: 8, display: 'grid', placeItems: 'center', background: 'color-mix(in srgb, ' + color + ' 12%, transparent)' }}>
        <Icon name={glyph} size={16} style={{ color }} />
      </span>
      <span>
        <span style={{ display: 'block', fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: '1.2rem', color: 'var(--text-on-light)', lineHeight: 1 }}>{n.toLocaleString()}</span>
        <span style={{ fontSize: '.78rem', color: 'var(--text-on-light-soft)' }}>{label}</span>
      </span>
    </div>
  );
}

/* shared inline styles */
const ghostBtn = {
  fontFamily: 'var(--font-display)', fontWeight: 500, fontSize: '.92rem', color: 'var(--text-on-light)',
  background: 'transparent', border: '1.5px solid var(--paper-line-strong)', borderRadius: 999,
  padding: '.6rem 1.25rem', cursor: 'pointer',
};
const linkStyle = { display: 'inline-flex', alignItems: 'center', gap: '.35em', color: 'var(--wv-violet)', fontWeight: 500, fontSize: '.88rem', textDecoration: 'none' };
const codeStyle = { fontFamily: 'ui-monospace, Menlo, monospace', fontSize: '.84em', background: 'var(--violet-tint)', color: 'var(--wv-ink)', padding: '.08rem .35rem', borderRadius: 5 };

Object.assign(window, { UploadScreen, PreviewScreen, RunDetailScreen });
