// Pantalla MI LISTA — la más importante (Bubblegum)
// Input inteligente siempre visible abajo, swipe-borrar, edit inline

function ListScreen({ app, theme, openSheet }) {
  const c = theme.c;
  const t = app.t;
  const [editingId, setEditingId] = React.useState(null);
  const [draftName, setDraftName] = React.useState('');
  const [draftQty, setDraftQty]   = React.useState('');
  const [swipeId, setSwipeId]     = React.useState(null);
  const [hoverId, setHoverId]     = React.useState(null);
  const [catEditId, setCatEditId] = React.useState(null);
  const [hoverHeader, setHoverHeader] = React.useState(null);
  const [pressHeader, setPressHeader] = React.useState(null);
  const [hintId, setHintId]       = React.useState(null);

  const dragRef       = React.useRef({ id: null, dx: 0, locked: null, sx: 0, sy: 0, lastDel: false, lastBuy: false });
  const rowRefs       = React.useRef({});
  const revealRefs    = React.useRef({});
  const buyRevealRefs = React.useRef({});
  const pressTimer    = React.useRef(null);
  const hintTimers    = React.useRef([]);

  const MAX_DRAG = -160;
  const EDIT_OPEN_THRESHOLD = -50;
  const DELETE_THRESHOLD = -130;
  const COLOR_FLIP_AT = -100;
  const BUY_THRESHOLD = 110;
  const MAX_DRAG_RIGHT = 140;

  React.useEffect(() => () => {
    clearTimeout(pressTimer.current);
    hintTimers.current.forEach(clearTimeout);
  }, []);

  if (!app.list) return <NoListEmptyState app={app} theme={theme} />;

  const isDesktop = app.isDesktop;
  const density = app.density;
  const lang = app.lang;

  function sortItems(arr) {
    const a = [...arr];
    if (app.sortMode === 'name') {
      return a.sort((x, y) => (x.name || '').localeCompare(y.name || '', lang === 'es' ? 'es' : 'en', { sensitivity: 'base' }));
    }
    return a.sort((x, y) => (y.created_at || 0) - (x.created_at || 0));
  }
  function groupItems(arr) {
    const groups = new Map();
    for (const it of arr) {
      const k = it.category || 'otros';
      if (!groups.has(k)) groups.set(k, []);
      groups.get(k).push(it);
    }
    const order = Object.keys(CATEGORIES).filter(k => !CATEGORIES[k].alias && groups.has(k));
    for (const k of groups.keys()) if (!order.includes(k)) order.push(k);
    return order.map(k => ({ key: k, items: groups.get(k) }));
  }
  const ROW_PAD = density === 'compact' ? '10px 14px' : density === 'spacious' ? '20px 18px' : '14px 16px';
  const ROW_GAP = density === 'compact' ? 6 : density === 'spacious' ? 14 : 10;
  const FS_NAME = density === 'compact' ? 15 : density === 'spacious' ? 19 : 17;

  function startEdit(item) {
    setEditingId(item.id);
    setDraftName(item.name);
    setDraftQty(item.quantity == null || item.quantity === '' ? '' : String(item.quantity));
  }
  function commitEdit(id) {
    if (draftName.trim()) app.updateItem(id, { name: draftName.trim(), quantity: draftQty });
    setEditingId(null);
  }

  function vibe(p) { try { if (navigator.vibrate) navigator.vibrate(p); } catch (_) {} }
  function applyDx(id, dx) {
    const row    = rowRefs.current[id];
    const rev    = revealRefs.current[id];
    const buyRev = buyRevealRefs.current[id];
    if (row) row.style.transform = `translate3d(${dx}px,0,0)`;
    const isDel = dx <= COLOR_FLIP_AT;
    const isBuy = dx >= BUY_THRESHOLD;
    if (dragRef.current.id === id) {
      if (dragRef.current.lastDel !== isDel) {
        dragRef.current.lastDel = isDel;
        vibe(isDel ? 14 : 6);
      }
      if (dragRef.current.lastBuy !== isBuy) {
        dragRef.current.lastBuy = isBuy;
        if (isBuy) vibe(14);
      }
    }
    if (rev) {
      rev.style.opacity = dx < -10 ? '1' : '0';
      rev.style.background = isDel ? c.danger : c.accent;
      rev.style.color = isDel ? '#fff' : c.accentInk;
      const labels = rev.querySelectorAll('[data-rev-label]');
      for (let i = 0; i < labels.length; i++) {
        labels[i].style.display = labels[i].dataset.revLabel === (isDel ? 'delete' : 'edit') ? '' : 'none';
      }
      const icons = rev.querySelectorAll('[data-rev-icon]');
      for (let i = 0; i < icons.length; i++) {
        icons[i].style.display = icons[i].dataset.revIcon === (isDel ? 'trash' : 'edit') ? '' : 'none';
      }
    }
    if (buyRev) {
      buyRev.style.opacity = dx > 10 ? '1' : '0';
    }
  }
  function settleRow(id, target, ms = 220, after = null) {
    const row    = rowRefs.current[id];
    const rev    = revealRefs.current[id];
    const buyRev = buyRevealRefs.current[id];
    if (row) {
      row.style.transition = `transform ${ms}ms cubic-bezier(.2,.9,.3,1)`;
      row.style.transform  = `translate3d(${target}px,0,0)`;
    }
    if (rev)    rev.style.opacity    = target === 0 ? '0' : rev.style.opacity;
    if (buyRev) buyRev.style.opacity = target === 0 ? '0' : buyRev.style.opacity;
    setTimeout(() => {
      if (row) {
        row.style.transition = '';
        if (target === 0) row.style.transform = '';
      }
      if (after) after();
    }, ms);
  }
  function fireHint(id) {
    if (dragRef.current.locked === 'h') return;
    vibe(8);
    setHintId(id);
    setSwipeId(id);
    const row = rowRefs.current[id];
    const rev = revealRefs.current[id];
    const dur = 1100;
    if (row && row.animate) {
      row.animate([
        { transform: 'translate3d(0,0,0)', easing: 'cubic-bezier(.2,.9,.3,1)' },
        { transform: 'translate3d(-70px,0,0)', offset: 0.20, easing: 'cubic-bezier(.4,0,.6,1)' },
        { transform: 'translate3d(-140px,0,0)', offset: 0.50, easing: 'cubic-bezier(.4,0,.2,1)' },
        { transform: 'translate3d(0,0,0)', offset: 1 },
      ], { duration: dur });
    }
    if (rev && rev.animate) {
      rev.animate([
        { opacity: 0 },
        { opacity: 1, offset: 0.10 },
        { opacity: 1, offset: 0.88 },
        { opacity: 0, offset: 1 },
      ], { duration: dur });
    }
    const flipReveal = (mode) => {
      if (!rev) return;
      const isDel = mode === 'delete';
      rev.style.background = isDel ? c.danger : c.accent;
      rev.style.color = isDel ? '#fff' : c.accentInk;
      const labels = rev.querySelectorAll('[data-rev-label]');
      for (let i = 0; i < labels.length; i++) {
        labels[i].style.display = labels[i].dataset.revLabel === mode ? '' : 'none';
      }
      const icons = rev.querySelectorAll('[data-rev-icon]');
      for (let i = 0; i < icons.length; i++) {
        const want = mode === 'delete' ? 'trash' : 'edit';
        icons[i].style.display = icons[i].dataset.revIcon === want ? '' : 'none';
      }
    };
    const tFlipDel = setTimeout(() => { flipReveal('delete'); vibe(14); }, Math.round(dur * 0.34));
    const tFlipEdit = setTimeout(() => { flipReveal('edit'); vibe(6); }, Math.round(dur * 0.66));
    const tEnd = setTimeout(() => {
      setHintId(null); setSwipeId(null);
    }, dur + 30);
    hintTimers.current.push(tFlipDel, tFlipEdit, tEnd);
  }
  function onTouchStart(e, item) {
    if (isDesktop) return;
    if (hintId) return;
    if (editingId === item.id) return;
    dragRef.current = {
      id: item.id, dx: 0, locked: null,
      sx: e.touches[0].clientX, sy: e.touches[0].clientY,
      lastDel: false, lastBuy: false,
    };
    if (app.animations !== false) {
      clearTimeout(pressTimer.current);
      pressTimer.current = setTimeout(() => fireHint(item.id), 450);
    }
  }
  function onTouchMove(e) {
    if (isDesktop) return;
    if (hintId) return;
    const d = dragRef.current;
    if (!d.id) return;
    const dx = e.touches[0].clientX - d.sx;
    const dy = e.touches[0].clientY - d.sy;
    const adx = Math.abs(dx);
    const ady = Math.abs(dy);
    if (Math.max(adx, ady) > 6) clearTimeout(pressTimer.current);
    if (d.locked === null) {
      if (Math.max(adx, ady) < 8) return;
      d.locked = ady > adx ? 'v' : 'h';
      if (d.locked === 'h') {
        vibe(6);
        setSwipeId(d.id);
        const row = rowRefs.current[d.id];
        if (row) row.style.transition = 'none';
      }
    }
    if (d.locked !== 'h') return;
    const clamped = Math.max(Math.min(dx, MAX_DRAG_RIGHT), MAX_DRAG);
    d.dx = clamped;
    applyDx(d.id, clamped);
  }
  function onTouchEnd(item) {
    if (isDesktop) return;
    if (hintId) return;
    clearTimeout(pressTimer.current);
    const d = dragRef.current;
    if (!d.id || d.locked !== 'h') {
      dragRef.current = { id: null, dx: 0, locked: null, sx: 0, sy: 0, lastDel: false, lastBuy: false };
      return;
    }
    const id = d.id;
    const dx = d.dx;
    dragRef.current = { id: null, dx: 0, locked: null, sx: 0, sy: 0, lastDel: false, lastBuy: false };
    if (dx >= BUY_THRESHOLD) {
      vibe([14, 30, 14]);
      app.togglePurchased(id);
      settleRow(id, 0, 200, () => setSwipeId(null));
      return;
    }
    if (dx <= DELETE_THRESHOLD) {
      vibe([18, 40, 26]);
      const row = rowRefs.current[id];
      if (row) {
        row.style.transition = 'transform .22s ease-out, opacity .22s ease-out';
        row.style.transform  = 'translate3d(-100%,0,0)';
        row.style.opacity    = '0';
      }
      setTimeout(() => {
        app.deleteItem(id);
        setSwipeId(null);
      }, 220);
      return;
    }
    if (dx <= EDIT_OPEN_THRESHOLD) {
      vibe(14);
      startEdit(item);
      settleRow(id, 0, 200, () => setSwipeId(null));
      const rev = revealRefs.current[id];
      if (rev) rev.style.opacity = '0';
      return;
    }
    settleRow(id, 0, 200, () => setSwipeId(null));
    const rev    = revealRefs.current[id];
    const buyRev = buyRevealRefs.current[id];
    if (rev)    rev.style.opacity    = '0';
    if (buyRev) buyRev.style.opacity = '0';
  }

  function renderItem(item, idx) {
    const cat = CATEGORIES[item.category] || CATEGORIES.otros;
    const editing = editingId === item.id;
    const swiping = swipeId === item.id;

    const catColor = ({
      // Pastel por categoría (debe alinearse con los keys de CATEGORIES en
      // data.jsx). Los keys legacy se mantienen para items antiguos.
      frutaverdura:  '#5EEAD4', lacteos:       '#FEF3C7', panaderia:    '#FDBA74',
      carne:         '#F472B6', pescado:       '#7DD3FC', charcuteria:  '#FCA5A5',
      arrozpasta:    '#FCD34D', aceites:       '#FDE68A', conservas:    '#A78BFA',
      congelados:    '#93C5FD', preparados:    '#FB923C', cereales:     '#FCD9B4',
      aguarefrescos: '#C4B5FD', zumos:         '#FBA74D', cafe:         '#D6A77A',
      bodega:        '#7C2D12', dulces:        '#F0ABFC', aperitivos:   '#FDE047',
      postres:       '#FBCFE8', limpieza:      '#86EFAC', cuidadofacial:'#FCA5C0',
      cabello:       '#C7A8E0', maquillaje:    '#F9A8D4', parafarmacia: '#A7F3D0',
      bebe:          '#FECACA', mascotas:      '#FDBA74',
      // Aliases legacy
      frutas:        '#5EEAD4', despensa:      '#A78BFA', bebidas:      '#C4B5FD',
      higiene:       '#FBCFE8',
      otros:         '#E2DCF5',
    })[item.category] || c.accent;

    const baseBg = app.cardStyle === 'minimal' ? 'transparent' : c.bgCard;
    const hovered = isDesktop && hoverId === item.id;
    const bg = hovered ? c.bgAlt : baseBg;
    const border = `1px solid ${hovered ? c.accent : c.border}`;
    const shadow = app.cardStyle === 'minimal' ? 'none' : c.shadowSoft;

    return (
      <div key={item.id} style={{ position: 'relative', overflow: swiping ? 'hidden' : 'visible', borderRadius: theme.radius.lg }}>
        {!isDesktop && (
          <div
            ref={(el) => { if (el) revealRefs.current[item.id] = el; else delete revealRefs.current[item.id]; }}
            style={{
              position: 'absolute', inset: 0,
              background: c.accent,
              borderRadius: theme.radius.lg,
              display: 'flex', alignItems: 'center', justifyContent: 'flex-end',
              paddingRight: 22, gap: 8,
              color: c.accentInk,
              transition: 'background .12s ease, color .12s ease, opacity .15s ease',
              fontFamily: theme.fontDisplay, fontWeight: 700, fontSize: 13, letterSpacing: 0.5,
              opacity: 0,
              pointerEvents: 'none',
            }}
          >
            <span data-rev-label="edit">{t.edit}</span>
            <span data-rev-label="delete" style={{ display: 'none' }}>{t.delete}</span>
            <span data-rev-icon="edit" style={{ display: 'inline-flex' }}><Icon name="edit" size={22} stroke={2.5} /></span>
            <span data-rev-icon="trash" style={{ display: 'none' }}><Icon name="trash" size={22} stroke={2.5} /></span>
          </div>
        )}
        {!isDesktop && (
          <div
            ref={(el) => { if (el) buyRevealRefs.current[item.id] = el; else delete buyRevealRefs.current[item.id]; }}
            style={{
              position: 'absolute', inset: 0,
              background: c.success,
              borderRadius: theme.radius.lg,
              display: 'flex', alignItems: 'center', justifyContent: 'flex-start',
              paddingLeft: 22, gap: 8,
              color: '#fff',
              transition: 'opacity .15s ease',
              fontFamily: theme.fontDisplay, fontWeight: 700, fontSize: 13, letterSpacing: 0.5,
              opacity: 0,
              pointerEvents: 'none',
            }}
          >
            <Icon name={item.is_purchased ? 'undo' : 'check'} size={22} stroke={2.5} />
            <span>{item.is_purchased
              ? (lang === 'es' ? 'Pendiente' : 'Pending')
              : t.bought_one.charAt(0).toUpperCase() + t.bought_one.slice(1)}</span>
          </div>
        )}
        <div
          ref={(el) => { if (el) rowRefs.current[item.id] = el; else delete rowRefs.current[item.id]; }}
          onTouchStart={editing ? null : (e) => onTouchStart(e, item)}
          onTouchMove={editing ? null : onTouchMove}
          onTouchEnd={editing ? null : () => onTouchEnd(item)}
          onMouseEnter={isDesktop ? () => setHoverId(item.id) : null}
          onMouseLeave={isDesktop ? () => setHoverId(prev => prev === item.id ? null : prev) : null}
          style={{
            position: 'relative',
            display: 'flex', alignItems: 'center', gap: ROW_GAP,
            padding: ROW_PAD,
            background: bg,
            border, borderRadius: theme.radius.lg,
            boxShadow: shadow,
            fontFamily: theme.fontBody,
            touchAction: isDesktop ? 'auto' : 'pan-y',
            willChange: isDesktop ? 'auto' : 'transform',
          }}
        >
          <button type="button"
            onMouseDown={(e) => e.preventDefault()}
            onClick={(e) => {
              e.stopPropagation();
              const wasEditing = !!(document.activeElement && document.activeElement.tagName === 'INPUT');
              if (wasEditing) document.activeElement.blur();
              const delay = app.isDesktop || !wasEditing ? 0 : 220;
              setTimeout(() => setCatEditId(item.id), delay);
            }}
            aria-label={app.lang === 'es' ? 'Cambiar categoría' : 'Change category'}
            title={app.lang === 'es' ? 'Cambiar categoría' : 'Change category'}
            style={{
              width: 38, height: 38, borderRadius: theme.radius.md,
              // Mismo look que en modo compra: sin fondo de color, solo borde
              // del tema. Hereda c.ink para contraste correcto en light/dark.
              background: 'transparent', color: c.ink,
              border: `1.5px solid ${c.border}`,
              padding: 0, cursor: 'pointer',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              fontSize: 18, flexShrink: 0,
            }}><CatGlyph cat={cat} size={18} stroke={2.2} /></button>

          {editing ? (
            <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 6 }}>
              <input
                autoFocus
                value={draftName}
                onChange={e => setDraftName(e.target.value)}
                onKeyDown={e => { if (e.key === 'Enter') commitEdit(item.id); if (e.key === 'Escape') setEditingId(null); }}
                style={{
                  width: '100%', fontSize: FS_NAME, fontWeight: 700, fontFamily: theme.fontDisplay,
                  border: 'none', outline: 'none', background: 'transparent', color: c.ink,
                  borderBottom: `2px solid ${c.accent}`, padding: '2px 0',
                }}
              />
              <input
                value={draftQty}
                onChange={e => setDraftQty(e.target.value.replace(/\D/g, ''))}
                onKeyDown={e => { if (e.key === 'Enter') commitEdit(item.id); if (e.key === 'Escape') setEditingId(null); }}
                inputMode="numeric"
                pattern="[0-9]*"
                placeholder={t.qty}
                style={{
                  width: '100%', fontSize: 13, fontFamily: theme.fontMono,
                  border: 'none', outline: 'none', background: 'transparent', color: c.inkSub,
                  padding: 0,
                }}
              />
            </div>
          ) : (
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{
                fontSize: FS_NAME, fontWeight: 700, fontFamily: theme.fontDisplay,
                color: c.ink, lineHeight: 1.2,
                whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
              }}>{item.name}</div>
              {item.quantity && (
                <div style={{
                  fontSize: 12, color: c.inkSub, fontFamily: theme.fontMono,
                  marginTop: 2, letterSpacing: 0.2,
                }}>{item.quantity}</div>
              )}
            </div>
          )}

          {editing ? (
            <div style={{ display: 'flex', gap: 4 }}>
              <button onClick={() => setEditingId(null)} style={{
                width: 36, height: 36, borderRadius: theme.radius.pill,
                border: `1.5px solid ${c.border}`, background: 'transparent', color: c.ink, cursor: 'pointer',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}><Icon name="x" size={18} stroke={2.4} /></button>
              <button onClick={() => commitEdit(item.id)} style={{
                width: 36, height: 36, borderRadius: theme.radius.pill,
                border: 'none', background: c.accent, color: c.accentInk, cursor: 'pointer',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}><Icon name="check" size={18} stroke={2.6} /></button>
            </div>
          ) : (
            <div style={{ display: 'flex', gap: 2, flexShrink: 0 }}>
              {isDesktop && hovered && (
                <button
                  onClick={(e) => { e.stopPropagation(); app.togglePurchased(item.id); }}
                  title={item.is_purchased ? (app.lang === 'es' ? 'Marcar pendiente' : 'Mark pending') : t.bought}
                  style={{
                    width: 32, height: 32, borderRadius: theme.radius.sm,
                    border: 'none', background: 'transparent', color: c.success,
                    cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
                  }}
                >
                  <Icon name={item.is_purchased ? 'undo' : 'check'} size={16} stroke={2.2} />
                </button>
              )}
              {isDesktop && hovered && (
                <button
                  onClick={(e) => { e.stopPropagation(); app.deleteItem(item.id); }}
                  title={t.delete}
                  style={{
                    width: 32, height: 32, borderRadius: theme.radius.sm,
                    border: 'none', background: 'transparent', color: c.danger,
                    cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
                  }}
                >
                  <Icon name="trash" size={16} stroke={2} />
                </button>
              )}
              {isDesktop && (
                <button
                  onClick={() => startEdit(item)}
                  style={{
                    width: 32, height: 32,
                    borderRadius: theme.radius.sm,
                    border: 'none', background: 'transparent', color: c.inkMuted,
                    cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
                  }}
                >
                  <Icon name="edit" size={16} stroke={2} />
                </button>
              )}
            </div>
          )}
        </div>
      </div>
    );
  }

  const listColors = { lime: '#D4FF3A', pink: '#FF3D8B', cyan: '#5EEAD4', orange: '#FDBA74', violet: '#A78BFA' };

  const innerMax = isDesktop ? 720 : '100%';
  const sidePad = isDesktop ? 32 : 22;
  const bottomPad = isDesktop ? 32 : 220;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', background: c.bg }}>
      <div style={{
        padding: `${isDesktop ? 24 : 8}px ${sidePad}px 8px`,
        display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12,
        maxWidth: innerMax, margin: '0 auto', width: '100%', boxSizing: 'border-box',
      }}>
        <button
          onClick={() => openSheet('lists')}
          style={{
            display: 'flex', alignItems: 'center', gap: 8, padding: '8px 14px 8px 8px',
            background: c.bgCard, border: `1.5px solid ${c.border}`,
            borderRadius: theme.radius.pill, cursor: 'pointer', color: c.ink,
            fontFamily: theme.fontDisplay,
          }}
        >
          <span style={{
            width: 28, height: 28, borderRadius: '50%',
            background: listColors[app.list.color] || c.accent,
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            fontSize: 14, fontWeight: 800, color: c.ink,
          }}>{app.list.name[app.lang][0]}</span>
          <span style={{ fontSize: 15, fontWeight: 700 }}>{app.list.name[app.lang]}</span>
          <Icon name="chevron-down" size={16} stroke={2.4} />
        </button>
        <div style={{ display: 'flex', gap: 6 }}>
          {[
            { key: 'sort', sheet: 'sort', icon: 'list', danger: false,
              label: (t.sort && t.sort.title) || 'Sort' },
            { key: 'rename', sheet: 'rename', icon: 'edit', danger: false,
              label: app.lang === 'es' ? 'Renombrar lista' : 'Rename list' },
            { key: 'delete', sheet: 'deleteList', icon: 'trash', danger: true,
              label: app.lang === 'es' ? 'Eliminar lista' : 'Delete list' },
            { key: 'share', sheet: 'share', icon: 'share', danger: false,
              label: t.share },
          ].map(b => {
            const accentBg = b.danger ? c.danger : c.accent;
            const accentInk = b.danger ? '#fff' : c.accentInk;
            const isHover = hoverHeader === b.key;
            const isPress = pressHeader === b.key;
            const baseColor = b.danger ? c.danger : c.ink;
            return (
              <button key={b.key}
                onClick={() => openSheet(b.sheet)}
                onPointerEnter={() => setHoverHeader(b.key)}
                onPointerLeave={() => { setHoverHeader(null); setPressHeader(null); }}
                onPointerDown={() => setPressHeader(b.key)}
                onPointerUp={() => setPressHeader(null)}
                onPointerCancel={() => setPressHeader(null)}
                aria-label={b.label} title={b.label}
                style={{
                  width: 40, height: 40, borderRadius: '50%',
                  background: isPress ? accentBg : (isHover ? `${accentBg}26` : c.bgCard),
                  border: `1.5px solid ${isPress || isHover ? accentBg : c.border}`,
                  color: isPress ? accentInk : baseColor,
                  cursor: 'pointer',
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                  transform: isPress ? 'scale(.9)' : 'scale(1)',
                  transition: 'transform .12s cubic-bezier(.2,1.3,.4,1), background .12s ease, color .12s ease, border-color .12s ease',
                }}>
                <Icon name={b.icon} size={16} stroke={2.2} />
              </button>
            );
          })}
        </div>
      </div>

      <div style={{
        padding: `4px ${sidePad}px 16px`,
        maxWidth: innerMax, margin: '0 auto', width: '100%', boxSizing: 'border-box',
      }}>
        <div style={{
          fontSize: 12, fontWeight: 700, color: c.inkSub,
          textTransform: 'uppercase', letterSpacing: 1.5,
          fontFamily: theme.fontMono, marginBottom: 4,
        }}>
          {app.lang === 'es' ? 'Mi lista' : 'My list'}
        </div>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 12 }}>
          <span style={{
            fontSize: 72, lineHeight: 0.9, fontWeight: 800,
            fontFamily: theme.fontDisplay, color: c.ink,
            letterSpacing: -3,
          }}>{app.pending.length}</span>
          <span style={{
            fontSize: 18, fontWeight: 600, color: c.inkSub,
            fontFamily: theme.fontDisplay,
          }}>
            {app.pending.length === 1 ? t.pending_one : t.pending}
          </span>
          {app.bought.length > 0 && (
            <ChipBadge theme={theme} color={c.successBg} style={{ color: c.success, marginLeft: 'auto', fontSize: 12 }}>
              ✓ {app.bought.length}
            </ChipBadge>
          )}
        </div>
        {app.items.length > 0 && (
          <div style={{
            marginTop: 14, height: 4, background: c.border,
            borderRadius: 999, overflow: 'hidden',
          }}>
            <div style={{
              height: '100%', width: `${(app.bought.length / app.items.length) * 100}%`,
              background: c.accent, borderRadius: 999,
              transition: 'width .35s cubic-bezier(.2,.9,.3,1)',
            }} />
          </div>
        )}
      </div>

      {app.pending.length > 0 && (
        <div style={{
          padding: `0 ${sidePad}px 14px`, display: 'flex', gap: 8,
          maxWidth: innerMax, margin: '0 auto', width: '100%', boxSizing: 'border-box',
        }}>
          <Btn theme={theme} variant="solid" size="md" icon="cart" onClick={() => app.setTab('shop')} style={{ flex: 1 }}>
            {t.startShopping}
          </Btn>
          <Btn theme={theme} variant="ghost" size="md" onClick={() => openSheet('frequent')}>
            <Icon name="lightning" size={16} stroke={2.4} />
          </Btn>
        </div>
      )}

      <div className="sl-scroll" style={{
        flex: 1, overflow: 'auto',
        padding: `0 ${sidePad}px ${bottomPad}px`,
      }}>
        <div style={{
          maxWidth: innerMax, margin: '0 auto', width: '100%',
          display: 'flex', flexDirection: 'column', gap: density === 'compact' ? 6 : 8,
        }}>
          {isDesktop && <SmartInput app={app} theme={theme} placement="inline" />}
          {app.items.length === 0 ? (
            <EmptyState theme={theme} big="🥑" title={t.empty} sub={t.emptySub} />
          ) : (() => {
            const sortedPending = sortItems(app.pending);
            const sortedBought  = sortItems(app.bought);
            const renderRow = (item, idx, dim) => dim
              ? <div key={item.id} style={{ opacity: 0.5 }}>{renderItem(item, idx)}</div>
              : renderItem(item, idx);
            const CategoryHeader = ({ catKey }) => {
              const cat = CATEGORIES[catKey] || CATEGORIES.otros;
              const label = (t.cats && t.cats[catKey]) || catKey;
              return (
                <div style={{
                  display: 'flex', alignItems: 'center', gap: 8,
                  marginTop: 10, marginBottom: 2, padding: '0 4px',
                  fontSize: 11, fontWeight: 700, color: c.inkMuted,
                  textTransform: 'uppercase', letterSpacing: 1.5,
                  fontFamily: theme.fontMono,
                }}>
                  <CatGlyph cat={cat} size={14} stroke={2.4} />
                  <span>{label}</span>
                  <div style={{ flex: 1, height: 1, background: c.border }} />
                </div>
              );
            };
            const renderArr = (arr, dim) => app.groupByCategory
              ? groupItems(arr).map(g => (
                  <React.Fragment key={g.key}>
                    <CategoryHeader catKey={g.key} />
                    {g.items.map((it, i) => renderRow(it, i, dim))}
                  </React.Fragment>
                ))
              : arr.map((it, i) => renderRow(it, i, dim));
            return (
              <>
                {renderArr(sortedPending, false)}
                {app.bought.length > 0 && (
                  <>
                    <div style={{
                      marginTop: 14, marginBottom: 4, padding: '0 4px',
                      fontSize: 11, fontWeight: 700, color: c.inkMuted,
                      textTransform: 'uppercase', letterSpacing: 1.5,
                      fontFamily: theme.fontMono,
                      display: 'flex', alignItems: 'center', gap: 8,
                    }}>
                      <span style={{ textTransform: 'none' }}>✓ {t.bought_one.charAt(0).toUpperCase() + t.bought_one.slice(1)} · {app.bought.length}</span>
                      <div style={{ flex: 1, height: 1, background: c.border }} />
                      <button onClick={app.clearBought} style={{
                        background: 'transparent', border: 'none', color: c.inkSub,
                        fontFamily: theme.fontMono, fontSize: 11, fontWeight: 700,
                        letterSpacing: 1.5, cursor: 'pointer', padding: 0,
                        textTransform: 'uppercase',
                      }}>
                        {app.lang === 'es' ? 'LIMPIAR' : 'CLEAR'}
                      </button>
                    </div>
                    {renderArr(sortedBought, true)}
                  </>
                )}
              </>
            );
          })()}
        </div>
      </div>
      <CategoryPicker theme={theme} app={app}
        open={!!catEditId}
        onClose={() => setCatEditId(null)}
        onPick={(catKey) => { app.updateItem(catEditId, { category: catKey }); setCatEditId(null); }}
        selected={catEditId ? (app.items.find(i => i.id === catEditId)?.category) : null} />
    </div>
  );
}

window.ListScreen = ListScreen;
