// mycards-pieces.jsx — Screen building blocks for My Cards.
// Header · SummaryStrip · TypeTabs · FilterRow · SearchInput · SortMenu ·
// ViewToggle · GridCard · ListRow · EmptyState · InlineSponsor.

// ─── Icons (small reusable) ─────────────────────────────────────────────────
function PIcon({ kind, size = 16 }) {
  switch (kind) {
    case 'back':
      return (<svg width={size} height={size} viewBox="0 0 16 16" fill="none">
        <path d="M9.5 3 L5 8 L9.5 13" stroke="currentColor" strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
      </svg>);
    case 'search':
      return (<svg width={size} height={size} viewBox="0 0 16 16" fill="none">
        <circle cx="7" cy="7" r="4" stroke="currentColor" strokeWidth="1.4"/>
        <path d="M10 10 L13 13" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/>
      </svg>);
    case 'sort':
      return (<svg width={size} height={size} viewBox="0 0 16 16" fill="none">
        <path d="M3 4 H13 M4 8 H12 M5 12 H11" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/>
      </svg>);
    case 'lock':
      return (<svg width={size} height={size} viewBox="0 0 18 18" fill="none">
        <rect x="4" y="8" width="10" height="7" rx="1.5" stroke="currentColor" strokeWidth="1.4"/>
        <path d="M6 8 V5.5 a3 3 0 0 1 6 0 V8" stroke="currentColor" strokeWidth="1.4" fill="none"/>
      </svg>);
    case 'expired':
      return (<svg width={size} height={size} viewBox="0 0 18 18" fill="none">
        <circle cx="9" cy="9" r="6.5" stroke="currentColor" strokeWidth="1.4"/>
        <path d="M9 5.5 V9 L12 10.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/>
      </svg>);
    case 'grid':
      return (<svg width={size} height={size} viewBox="0 0 16 16" fill="none">
        <rect x="2" y="2" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.4"/>
        <rect x="9" y="2" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.4"/>
        <rect x="2" y="9" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.4"/>
        <rect x="9" y="9" width="5" height="5" rx="1" stroke="currentColor" strokeWidth="1.4"/>
      </svg>);
    case 'list':
      return (<svg width={size} height={size} viewBox="0 0 16 16" fill="none">
        <rect x="2"  y="3"  width="3"  height="3" rx="0.5" fill="currentColor"/>
        <rect x="7"  y="3.5" width="7"  height="2" rx="1" fill="currentColor"/>
        <rect x="2"  y="11" width="3"  height="3" rx="0.5" fill="currentColor"/>
        <rect x="7"  y="11.5" width="7" height="2" rx="1" fill="currentColor"/>
      </svg>);
    case 'bell':
      return (<svg width={size} height={size} viewBox="0 0 16 16" fill="none">
        <path d="M4 11 V7 a4 4 0 0 1 8 0 V11 L13 12.5 H3 Z M6.5 14 H9.5"
              stroke="currentColor" strokeWidth="1.4" fill="none" strokeLinejoin="round" strokeLinecap="round"/>
      </svg>);
    case 'coin':
      return (<svg width={size} height={size} viewBox="0 0 16 16" fill="none">
        <circle cx="8" cy="8" r="6" stroke="currentColor" strokeWidth="1.4"/>
        <circle cx="8" cy="8" r="3" stroke="currentColor" strokeWidth="1.2" opacity="0.6"/>
      </svg>);
    case 'plus': // empty state CTA
      return (<svg width={size} height={size} viewBox="0 0 18 18" fill="none">
        <path d="M9 4 V14 M4 9 H14" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/>
      </svg>);
    default: return null;
  }
}

// ─── Header (mobile + desktop sharing styles) ──────────────────────────────
function MCHeader({ locale, count, coinBalance = 12450, showBack = true, onBack, dense = false }) {
  const ll = MC_I18N[locale];
  return (
    <header className={`mc-header ${dense ? 'is-dense' : ''}`}>
      {showBack && (
        <button className="mc-icon-btn" onClick={onBack} type="button" aria-label={ll.back}>
          <PIcon kind="back" />
        </button>
      )}
      <div className="mc-header-titles">
        <div className="mc-header-title">{ll.title}</div>
        <div className="mc-header-sub">{ll.subtitle(toLocaleDigits(count, locale))}</div>
      </div>
      <div className="mc-header-pill">
        <PIcon kind="coin" size={12} />
        <span>{toLocaleDigits(coinBalance.toLocaleString('en-US').replace(/,/g, ','), locale)}</span>
      </div>
      <button className="mc-icon-btn mc-icon-btn--ghost" type="button" aria-label={ll.notif}>
        <PIcon kind="bell" />
      </button>
    </header>
  );
}

// ─── Summary strip — two variants ─────────────────────────────────────────
// • 'chips'  → horizontal scrollable strip with one chip per card type
//              (Player / Null / Fan / Coach) — used on mobile.
// • 'tiles'  → grid of large stat tiles, same 4 counts — used on desktop
//              sidebar where vertical space is plentiful.
function SummaryStrip({ locale, counts, variant = 'chips' }) {
  const ll = MC_I18N[locale];
  // Single canonical data shape — both variants read from this so chips and
  // tiles always stay in sync.
  const types = [
    { key: 'player', label: ll.tabPlayer, value: counts.player, color: '#94A3B8' },
    { key: 'null',   label: ll.tabNull,   value: counts.null,   color: '#A88CFF' },
    { key: 'fan',    label: ll.tabFan,    value: counts.fan,    color: '#EF4444' },
    { key: 'coach',  label: ll.tabCoach,  value: counts.coach,  color: '#22C55E' },
  ];

  if (variant === 'tiles') {
    return (
      <div className="mc-summary mc-summary--tiles">
        {types.map((t) => (
          <div key={t.key} className="mc-summary-tile" style={{ '--tile': t.color }}>
            <div className="mc-summary-tile-value">{toLocaleDigits(t.value, locale)}</div>
            <div className="mc-summary-tile-label">{t.label}</div>
          </div>
        ))}
      </div>
    );
  }

  // chips (default)
  return (
    <div className="mc-summary mc-summary--chips" role="list">
      {types.map((t) => (
        <div key={t.key} className="mc-summary-chip" role="listitem">
          <span className="mc-summary-chip-dot" style={{ background: t.color }}></span>
          <span className="mc-summary-chip-value">{toLocaleDigits(t.value, locale)}</span>
          <span className="mc-summary-chip-label">{t.label}</span>
        </div>
      ))}
    </div>
  );
}

// ─── Type tabs (All / Player / Null / Fan / Coach) ─────────────────────────
function TypeTabs({ locale, value, onChange, counts, variant = 'pill' }) {
  const ll = MC_I18N[locale];
  const tabs = [
    { key: 'all',    label: ll.tabAll,    count: counts.all },
    { key: 'player', label: ll.tabPlayer, count: counts.player },
    { key: 'null',   label: ll.tabNull,   count: counts.null },
    { key: 'fan',    label: ll.tabFan,    count: counts.fan },
    { key: 'coach',  label: ll.tabCoach,  count: counts.coach },
  ];
  return (
    <div className={`mc-tabs mc-tabs--${variant}`} role="tablist">
      {tabs.map((t) => (
        <button key={t.key} role="tab" aria-selected={value === t.key}
                type="button"
                className={`mc-tab ${value === t.key ? 'is-active' : ''}`}
                onClick={() => onChange(t.key)}>
          <span>{t.label}</span>
          <span className="mc-tab-count">{toLocaleDigits(t.count, locale)}</span>
        </button>
      ))}
    </div>
  );
}

// ─── Filter chip row (tier or position or status) ─────────────────────────
function ChipRow({ chips, value, onChange, locale, variant = 'pill' }) {
  return (
    <div className={`mc-chips mc-chips--${variant}`} role="tablist">
      {chips.map((c) => (
        <button key={c.key} role="tab" aria-selected={value === c.key} type="button"
                className={`mc-chip ${value === c.key ? 'is-active' : ''}`}
                onClick={() => onChange(c.key)}
                style={c.color ? { '--chip-accent': c.color } : null}>
          {c.dot && <span className="mc-chip-dot" style={{ background: c.color || 'currentColor' }}></span>}
          <span>{c.label}</span>
          {c.count != null && (
            <span className="mc-chip-count">{toLocaleDigits(c.count, locale)}</span>
          )}
        </button>
      ))}
    </div>
  );
}

// ─── Search input ───────────────────────────────────────────────────────────
function SearchInput({ locale, value, onChange }) {
  const ll = MC_I18N[locale];
  return (
    <label className="mc-search" aria-label={ll.search}>
      <PIcon kind="search" size={14} />
      <input type="text"
             placeholder={ll.search}
             value={value}
             onChange={(e) => onChange(e.target.value)}/>
      {value && (
        <button className="mc-search-clear" onClick={() => onChange('')} type="button" aria-label="clear">
          <svg width="12" height="12" viewBox="0 0 12 12" fill="none">
            <path d="M3 3 L9 9 M9 3 L3 9" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/>
          </svg>
        </button>
      )}
    </label>
  );
}

// ─── Sort menu (dropdown shown as a tag-style button) ──────────────────────
function SortMenu({ locale, value, onChange, options }) {
  const ll = MC_I18N[locale];
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const close = (e) => {
      if (ref.current && !ref.current.contains(e.target)) setOpen(false);
    };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, [open]);
  const labels = {
    overall:  ll.sortOverall,
    recent:   ll.sortRecent,
    tier:     ll.sortTier,
    name:     ll.sortName,
    team:     ll.sortTeam,
    position: ll.sortPosition,
  };
  return (
    <div className="mc-sort" ref={ref}>
      <button className="mc-sort-trigger" type="button" onClick={() => setOpen(!open)}>
        <PIcon kind="sort" size={13} />
        <span>{labels[value] || ll.sortLabel}</span>
        <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
          <path d="M2.5 3.5 L5 6.5 L7.5 3.5" stroke="currentColor" strokeWidth="1.4" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
      </button>
      {open && (
        <div className="mc-sort-menu">
          {options.map((opt) => (
            <button key={opt} type="button"
                    className={`mc-sort-option ${value === opt ? 'is-active' : ''}`}
                    onClick={() => { onChange(opt); setOpen(false); }}>
              {labels[opt]}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

// ─── Filter dropdown (mobile-first: label + current value + chevron) ──────
// Same affordance as SortMenu trigger, but expresses one of several filter
// dimensions (tier / position / status). Dropdown panel lists the options with
// a leading dot when one is supplied. Closes on outside click / Escape.
function FilterDropdown({ label, value, options, onChange, locale }) {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const close = (e) => {
      if (ref.current && !ref.current.contains(e.target)) setOpen(false);
    };
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    document.addEventListener('mousedown', close);
    document.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('mousedown', close);
      document.removeEventListener('keydown', onKey);
    };
  }, [open]);

  const current = options.find((o) => o.key === value) || options[0];
  // Compact label format: «پست: مهاجم» / «Position: FWD»
  const triggerText = current.short || current.label;

  return (
    <div className="mc-filter-dd" ref={ref}>
      <button className={`mc-filter-dd-trigger ${value !== 'all' ? 'is-set' : ''}`}
              type="button" onClick={() => setOpen(!open)}
              aria-haspopup="listbox" aria-expanded={open}>
        <span className="mc-filter-dd-label">{label}</span>
        <span className="mc-filter-dd-value">
          {current.dot && current.color && (
            <span className="mc-filter-dd-dot" style={{ background: current.color }}></span>
          )}
          <span className="mc-filter-dd-value-text">{triggerText}</span>
        </span>
        <svg className="mc-filter-dd-chev" width="10" height="10" viewBox="0 0 10 10" fill="none"
             aria-hidden="true" style={{ transform: open ? 'rotate(180deg)' : 'none' }}>
          <path d="M2.5 3.5 L5 6.5 L7.5 3.5" stroke="currentColor" strokeWidth="1.4"
                fill="none" strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
      </button>
      {open && (
        <div className="mc-filter-dd-menu" role="listbox">
          {options.map((o) => (
            <button key={o.key} type="button" role="option"
                    aria-selected={o.key === value}
                    className={`mc-filter-dd-option ${o.key === value ? 'is-active' : ''}`}
                    onClick={() => { onChange(o.key); setOpen(false); }}>
              {o.dot && (
                <span className="mc-filter-dd-dot"
                      style={{ background: o.color || 'transparent', opacity: o.color ? 1 : 0 }}></span>
              )}
              <span className="mc-filter-dd-option-label">{o.label}</span>
              {o.count != null && (
                <span className="mc-filter-dd-option-count">{toLocaleDigits(o.count, locale)}</span>
              )}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

// ─── Grid/List view toggle ─────────────────────────────────────────────────
function ViewToggle({ locale, value, onChange }) {
  const ll = MC_I18N[locale];
  return (
    <div className="mc-view-toggle" role="tablist">
      <button type="button" role="tab" aria-selected={value === 'grid'}
              className={`mc-view-opt ${value === 'grid' ? 'is-active' : ''}`}
              onClick={() => onChange('grid')}
              aria-label={ll.viewGrid} title={ll.viewGrid}>
        <PIcon kind="grid" size={13} />
      </button>
      <button type="button" role="tab" aria-selected={value === 'list'}
              className={`mc-view-opt ${value === 'list' ? 'is-active' : ''}`}
              onClick={() => onChange('list')}
              aria-label={ll.viewList} title={ll.viewList}>
        <PIcon kind="list" size={14} />
      </button>
    </div>
  );
}

// ─── Grid card — wraps PlayerCard/NullCard/FanCard/CoachCard with state ───
function GridCard({ item, locale, onClick, isPinned, density = 2 }) {
  const ll = MC_I18N[locale];
  const isReserved = item.status === 'reserved';
  const isExpired  = item.status === 'expired';
  const isNew      = item.isNew;

  // Compact card scaling tuned for My Cards grid. Source player photos vary
  // in framing (mes/c7/azmoon webps all crop differently), so a single large
  // scale makes some look comically big. Pulling the scale closer to 1 keeps
  // proportions consistent across players and card types.
  // Tuned for action-figure renders in compact grid — keeps base + nameplate
  // clipped behind the stats panel, same crop as Lineup compact (compact mode
  // halves imageOffsetY → effective 102px).
  const imgProps = { imageScale: 1.52, imageOffsetY: 204 };

  // Render inner card by type. All compact size.
  let inner = null;
  if (item.type === 'player') {
    const p = item.card;
    inner = (
      <PlayerCard locale={locale} size="compact"
        tier={p.tier} position={p.position}
        overall={p.overall} statKey={p.statKey} statValue={p.statValue}
        playerName={p.name[locale]} teamName={p.team[locale]}
        playerImage={p.image} {...imgProps}/>
    );
  } else if (item.type === 'null') {
    inner = (
      <NullCard locale={locale} size="compact"
        tier={item.card.tier} overall={item.card.overall}
        image="assets/null.webp" imageScale={0.95} imageOffsetY={18}/>
    );
  } else if (item.type === 'fan') {
    inner = (
      <FanCard locale={locale} size="compact"
        bonusValue={item.card.bonus} team={item.card.team[locale]}
        image="assets/fan.webp" {...imgProps}/>
    );
  } else {
    inner = (
      <CoachCard locale={locale} size="compact"
        multiplier={item.card.multiplier}
        coachName={item.card.name[locale]}
        condition={item.card.condition[locale]}
        image="assets/coach.webp" {...imgProps}/>
    );
  }

  return (
    <div className={`mc-grid-card ${isReserved ? 'is-reserved' : ''} ${isExpired ? 'is-expired' : ''} mc-grid-card--d${density}`}
         data-status={item.status}>
      <div className="mc-grid-card-inner" aria-hidden="true">
        {inner}
      </div>

      {/* Overlay click target — captures clicks; the inner card has pointer-events:none. */}
      <button className="mc-grid-card-hit"
              type="button"
              onClick={() => onClick && onClick(item)}
              aria-label={item.type === 'player' ? item.card.name[locale] : null}>
      </button>

      {/* State overlay (visual only) */}
      {(isReserved || isExpired) && (
        <div className="mc-grid-card-overlay">
          <div className="mc-grid-card-overlay-pill">
            {isReserved ? <PIcon kind="lock" size={14} /> : <PIcon kind="expired" size={14} />}
            <span>{isReserved ? ll.overlayInDeck : ll.overlayExpired}</span>
          </div>
        </div>
      )}

      {/* Top corner ribbons — non-blocking */}
      <div className="mc-grid-card-ribbons">
        {isNew && <div className="mc-ribbon mc-ribbon--new">{ll.badgeNew}</div>}
        {isPinned && <div className="mc-ribbon mc-ribbon--mission">{ll.badgeMission}</div>}
      </div>
    </div>
  );
}

// ─── List row — extends PlayerTile pattern to all 4 card types ─────────────
function ListRow({ item, locale, onClick }) {
  const ll = MC_I18N[locale];
  const llBase = I18N[locale];
  const isReserved = item.status === 'reserved';
  const isExpired  = item.status === 'expired';

  let stripColor, imgBg, name, meta, primaryStat, secondaryStat, posLabel, badge;
  if (item.type === 'player') {
    const p = item.card;
    const tt = TIER[p.tier];
    stripColor = tt.base; imgBg = tt.field;
    name = p.name[locale];
    meta = `${llBase.posShort[p.position]} · ${p.team[locale]}`;
    primaryStat = { val: toLocaleDigits(p.overall, locale), color: tt.overallColor, stroke: tt.pillStroke };
    secondaryStat = { key: llBase.posShort[p.position], val: toLocaleDigits(p.statValue, locale) };
  } else if (item.type === 'null') {
    const tt = TIER[item.card.tier];
    stripColor = '#A88CFF';
    imgBg = 'radial-gradient(ellipse 90% 70% at 50% 42%, #3D2980 0%, #1F1455 45%, #0E0830 80%)';
    name = MC_I18N[locale].tabNull;
    meta = `${SPECIAL_I18N[locale].nullType} · ${tt.name[locale]}`;
    primaryStat = { val: toLocaleDigits(item.card.overall, locale), color: tt.overallColor, stroke: tt.pillStroke };
    secondaryStat = { key: '★', val: '' };
    badge = 'WILD';
  } else if (item.type === 'fan') {
    stripColor = '#EF4444';
    imgBg = 'radial-gradient(ellipse 90% 70% at 50% 42%, #7A1C1C 0%, #3D0E0E 45%, #1A0606 80%)';
    name = `${SPECIAL_I18N[locale].fanName} · ${item.card.team[locale]}`;
    meta = SPECIAL_I18N[locale].fanType;
    primaryStat = { val: '+' + toLocaleDigits(item.card.bonus, locale), color: '#FFB8B8', stroke: 'rgba(255,160,160,0.45)' };
    secondaryStat = null;
    badge = 'FAN';
  } else {
    stripColor = '#22C55E';
    imgBg = 'radial-gradient(ellipse 90% 70% at 50% 42%, #2D5A3E 0%, #1A3326 45%, #0C1812 80%)';
    name = item.card.name[locale];
    meta = item.card.condition[locale];
    primaryStat = { val: '×' + toLocaleDigits(String(item.card.multiplier), locale), color: '#B8F2CD', stroke: 'rgba(160,240,190,0.48)' };
    secondaryStat = null;
    badge = 'COACH';
  }

  // Choose image per type
  let imgSrc = null;
  if (item.type === 'player') imgSrc = item.card.image;
  else if (item.type === 'null')  imgSrc = 'assets/null.webp';
  else if (item.type === 'fan')   imgSrc = 'assets/fan.webp';
  else                            imgSrc = 'assets/coach.webp';

  return (
    <div className={`mc-row ${isReserved ? 'is-reserved' : ''} ${isExpired ? 'is-expired' : ''}`}>
      <button className="mc-row-main" type="button" onClick={() => onClick && onClick(item)}>
        <div className="mc-row-strip" style={{ background: stripColor }}></div>
        <div className="mc-row-img" style={{ background: imgBg }}>
          <img src={imgSrc} alt="" loading="lazy" onError={(e) => { e.target.style.opacity = '0.2'; }} />
          {badge && <div className="mc-row-img-badge">{badge}</div>}
        </div>
        <div className="mc-row-body">
          <div className="mc-row-name">
            {item.isNew && <span className="mc-row-new">{ll.badgeNew}</span>}
            <span className="mc-row-name-text">{name}</span>
          </div>
          <div className="mc-row-meta">{meta}</div>
        </div>
        <div className="mc-row-stats">
          <div className="mc-row-ovr" style={{ color: primaryStat.color, borderColor: primaryStat.stroke }}>
            {primaryStat.val}
          </div>
          {secondaryStat && secondaryStat.val !== '' && (
            <div className="mc-row-stat">
              <span className="mc-row-stat-key">{secondaryStat.key}</span>
              <span className="mc-row-stat-val">{secondaryStat.val}</span>
            </div>
          )}
        </div>
        {(isReserved || isExpired) && (
          <div className="mc-row-overlay">
            {isReserved ? <PIcon kind="lock" size={14} /> : <PIcon kind="expired" size={14} />}
            <span>{isReserved ? ll.overlayInDeck : ll.overlayExpired}</span>
          </div>
        )}
      </button>
      {/* Info icon — explicit affordance for "open card details", consistent
          with the Lineup picker's PlayerTile pattern. Split hit-area: the
          main tile may grow to other actions in the future (e.g. quick-add to
          Lineup), the (i) always opens this card's detail modal. */}
      <button className="mc-row-info"
              type="button"
              onClick={(e) => { e.stopPropagation(); onClick && onClick(item); }}
              aria-label={I18N[locale].details}
              title={I18N[locale].details}>
        <svg width="16" height="16" viewBox="0 0 18 18" fill="none" aria-hidden="true">
          <circle cx="9" cy="9" r="7" stroke="currentColor" strokeWidth="1.4"/>
          <circle cx="9" cy="5.5" r="0.8" fill="currentColor"/>
          <path d="M9 8 V13" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/>
        </svg>
      </button>
    </div>
  );
}

// ─── Inline sponsor strip — compact variant, fits as a grid item or row ──
// Used between every 8 cards in the grid + above the list.
function InlineSponsor({ locale, sponsorId, spans = 2 }) {
  // Use the existing SponsorStrip (compact) from lineup-pieces.
  const s = SPONSORS[sponsorId] || SPONSORS.mci;
  return (
    <div className="mc-sponsor-inline" style={{ gridColumn: `span ${spans}` }}>
      <div className="mc-sponsor-inline-card">
        <div className="mc-sponsor-mark" style={{ background: `linear-gradient(135deg, ${s.color}, ${s.color2})` }}>
          <span>{s.mark}</span>
        </div>
        <div className="mc-sponsor-text">
          <div className="mc-sponsor-eye">{MC_I18N[locale].sponsorEyebrow}</div>
          <div className="mc-sponsor-name">{s.name[locale]}</div>
        </div>
        <div className="mc-sponsor-tag">{s.tagline[locale]}</div>
        <button className="mc-sponsor-cta" type="button">{MC_I18N[locale].sponsorCta}</button>
        <div className="mc-sponsor-shine" aria-hidden="true"></div>
      </div>
    </div>
  );
}

// ─── Sponsor block (desktop sidebar — bigger banner variant) ──────────────
// Vertical-ish layout, room for a tagline and CTA. Same shimmer pass.
function SponsorBlock({ locale, sponsorId }) {
  const s = SPONSORS[sponsorId] || SPONSORS.mci;
  return (
    <div className="mc-sponsor-block" style={{ '--brand': s.color, '--brand-2': s.color2 }}>
      <div className="mc-sponsor-block-eye">{MC_I18N[locale].sponsorEyebrow}</div>
      <div className="mc-sponsor-block-mark">
        <span>{s.mark}</span>
      </div>
      <div className="mc-sponsor-block-name">{s.name[locale]}</div>
      <div className="mc-sponsor-block-tag">{s.tagline[locale]}</div>
      <button className="mc-sponsor-block-cta" type="button">
        <span>{MC_I18N[locale].sponsorCta}</span>
        <svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
          <path d="M4.5 3 L7.5 6 L4.5 9" stroke="currentColor" strokeWidth="1.6"
                fill="none" strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
      </button>
      <div className="mc-sponsor-shine" aria-hidden="true"></div>
    </div>
  );
}

// ─── Empty state ───────────────────────────────────────────────────────────
function EmptyState({ locale, onCta }) {
  const ll = MC_I18N[locale];
  return (
    <div className="mc-empty">
      <div className="mc-empty-art" aria-hidden="true">
        {/* Stack of 3 outlined card silhouettes */}
        <svg width="120" height="120" viewBox="0 0 120 120" fill="none">
          <rect x="22" y="38" width="46" height="64" rx="8"
                stroke="rgba(255,255,255,0.12)" strokeWidth="1.4"
                fill="rgba(255,255,255,0.02)"
                transform="rotate(-10 45 70)"/>
          <rect x="52" y="34" width="46" height="64" rx="8"
                stroke="rgba(255,255,255,0.18)" strokeWidth="1.4"
                fill="rgba(255,255,255,0.03)"
                transform="rotate(8 75 66)"/>
          <rect x="37" y="22" width="46" height="64" rx="8"
                stroke="var(--accent)" strokeWidth="1.6"
                fill="rgba(113,99,217,0.08)"/>
          <circle cx="60" cy="46" r="4" fill="var(--accent)" opacity="0.5"/>
          <path d="M48 58 H72 M48 64 H66 M48 70 H70"
                stroke="rgba(255,255,255,0.18)" strokeWidth="1.2" strokeLinecap="round"/>
        </svg>
      </div>
      <div className="mc-empty-title">{ll.emptyTitle}</div>
      <div className="mc-empty-sub">{ll.emptySub}</div>
      <button className="mc-empty-cta" type="button" onClick={onCta}>
        <PIcon kind="plus" size={14} />
        <span>{ll.emptyCta}</span>
      </button>
    </div>
  );
}

// ─── Filter sort helpers (pure data) ──────────────────────────────────────
function applyFilters(items, { type, tier, position, status, search, locale }) {
  return items.filter((it) => {
    if (type !== 'all' && it.type !== type) return false;
    if (tier !== 'all') {
      if (it.type === 'player' || it.type === 'null') {
        if (it.card.tier !== tier) return false;
      } else {
        return false;
      }
    }
    if (position !== 'all') {
      if (it.type !== 'player') return false;
      if (it.card.position !== position) return false;
    }
    if (status !== 'all') {
      if (it.status !== status) return false;
    }
    if (search) {
      const q = search.toLowerCase();
      const fields = [];
      if (it.type === 'player') {
        Object.values(it.card.name).forEach((v) => fields.push(v));
        Object.values(it.card.team).forEach((v) => fields.push(v));
        fields.push(it.card.position);
      } else if (it.type === 'null') {
        fields.push('null', 'wild', 'wildcard');
      } else if (it.type === 'fan') {
        Object.values(it.card.team).forEach((v) => fields.push(v));
        fields.push('fan');
      } else if (it.type === 'coach') {
        Object.values(it.card.name).forEach((v) => fields.push(v));
        Object.values(it.card.condition).forEach((v) => fields.push(v));
        fields.push('coach');
      }
      if (!fields.some((f) => String(f).toLowerCase().includes(q))) return false;
    }
    return true;
  });
}

function applySort(items, sort, locale) {
  const out = [...items];
  const getOverall = (it) => {
    if (it.type === 'player' || it.type === 'null') return it.card.overall;
    if (it.type === 'fan')   return it.card.bonus / 4;     // rough comparability
    if (it.type === 'coach') return (it.card.multiplier * 50) + 50;
    return 0;
  };
  const tierOrder = { platinum: 4, gold: 3, silver: 2, bronze: 1 };
  switch (sort) {
    case 'overall':
      out.sort((a, b) => getOverall(b) - getOverall(a)); break;
    case 'recent':
      out.sort((a, b) => a.acquired_days_ago - b.acquired_days_ago); break;
    case 'tier':
      out.sort((a, b) => {
        const at = (a.type === 'player' || a.type === 'null') ? tierOrder[a.card.tier] : 0;
        const bt = (b.type === 'player' || b.type === 'null') ? tierOrder[b.card.tier] : 0;
        if (bt !== at) return bt - at;
        return getOverall(b) - getOverall(a);
      });
      break;
    case 'name':
      out.sort((a, b) => {
        const an = a.type === 'player' || a.type === 'coach' ? a.card.name[locale]
                  : a.type === 'fan' ? a.card.team[locale]
                  : 'null';
        const bn = b.type === 'player' || b.type === 'coach' ? b.card.name[locale]
                  : b.type === 'fan' ? b.card.team[locale]
                  : 'null';
        return String(an).localeCompare(String(bn), locale);
      });
      break;
    case 'team':
      out.sort((a, b) => {
        const ag = a.type === 'player' ? a.card.team[locale] : a.type === 'fan' ? a.card.team[locale] : 'zzz';
        const bg = b.type === 'player' ? b.card.team[locale] : b.type === 'fan' ? b.card.team[locale] : 'zzz';
        return String(ag).localeCompare(String(bg), locale);
      });
      break;
    case 'position':
      out.sort((a, b) => {
        const ord = { GK: 0, DEF: 1, MID: 2, FWD: 3 };
        const ap = a.type === 'player' ? ord[a.card.position] : 99;
        const bp = b.type === 'player' ? ord[b.card.position] : 99;
        return ap - bp;
      });
      break;
  }
  return out;
}

Object.assign(window, {
  MCHeader, SummaryStrip, TypeTabs, ChipRow, SearchInput, SortMenu, ViewToggle,
  GridCard, ListRow, EmptyState, InlineSponsor, SponsorBlock, FilterDropdown,
  applyFilters, applySort, PIcon,
});

// ─── styles ─────────────────────────────────────────────────────────────────
const MC_PIECES_CSS = `
  /* ───── Header ───── */
  .mc-header {
    display: flex; align-items: center;
    gap: 10px;
    padding: 12px 16px;
    background: rgba(8,8,14,0.85);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid rgba(255,255,255,0.05);
    position: sticky;
    top: 0;
    z-index: 50;
    font-family: var(--font-current);
  }
  .mc-header.is-dense { padding: 8px 14px; }
  .mc-header-titles {
    flex: 1 1 auto;
    min-width: 0;
    display: flex; flex-direction: column;
    line-height: 1.1;
  }
  .mc-header-title {
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .mc-header-sub {
    font-size: 11px;
    color: var(--text-tertiary);
    margin-top: 2px;
  }
  .mc-header-pill {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 6px 10px;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,0.08);
    background: rgba(255,255,255,0.02);
    color: var(--text-secondary);
    font-size: 11px;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
  }
  html[lang="fa"] .mc-header-pill,
  html[lang="ar"] .mc-header-pill { font-family: inherit; }
  .mc-icon-btn {
    width: 34px; height: 34px;
    border-radius: 50%;
    border: 1px solid rgba(255,255,255,0.06);
    background: rgba(255,255,255,0.02);
    color: var(--text-secondary);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    flex-shrink: 0;
    transition: background .12s, color .12s, transform .12s;
    font-family: inherit !important;
  }
  .mc-icon-btn:hover { background: rgba(255,255,255,0.06); color: var(--text-primary); }
  .mc-icon-btn:active { transform: scale(0.94); }
  .mc-icon-btn--ghost {
    border-color: transparent;
    background: transparent;
  }
  html[dir="rtl"] .mc-icon-btn svg { transform: scaleX(-1); }

  /* ───── Summary strip ───── */
  .mc-summary {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 10px 14px;
    overflow-x: auto;
    scrollbar-width: none;
    font-family: var(--font-current);
  }
  .mc-summary::-webkit-scrollbar { display: none; }

  .mc-summary--chips { gap: 6px; }
  .mc-summary-chip {
    flex-shrink: 0;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 10px;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,0.05);
    background: rgba(255,255,255,0.02);
    color: var(--text-secondary);
    font-size: 12px;
  }
  .mc-summary-chip-dot {
    width: 6px; height: 6px;
    border-radius: 50%;
    flex-shrink: 0;
    box-shadow: 0 0 6px currentColor;
  }
  .mc-summary-chip-value {
    color: var(--text-primary);
    font-weight: 700;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
    font-size: 13px;
  }
  html[lang="fa"] .mc-summary-chip-value,
  html[lang="ar"] .mc-summary-chip-value { font-family: inherit; }
  .mc-summary-chip-label { font-size: 11px; opacity: 0.85; }

  /* subtitle variant */
  .mc-summary--subtitle {
    padding: 4px 16px 8px;
    color: var(--text-tertiary);
    font-size: 12px;
  }

  /* tiles variant */
  .mc-summary--tiles {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 8px;
    padding: 8px 14px 12px;
    overflow: visible;
  }
  .mc-summary-tile {
    background: rgba(255,255,255,0.025);
    border: 1px solid rgba(255,255,255,0.05);
    border-top: 2px solid var(--tile, var(--accent));
    border-radius: 12px;
    padding: 10px 8px;
    display: flex; flex-direction: column; gap: 2px;
    align-items: center;
    text-align: center;
  }
  .mc-summary-tile-value {
    font-size: 22px;
    font-weight: 800;
    line-height: 1;
    color: var(--text-primary);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
  }
  html[lang="fa"] .mc-summary-tile-value,
  html[lang="ar"] .mc-summary-tile-value { font-family: inherit; }
  .mc-summary-tile-label {
    font-size: 11px;
    color: var(--text-tertiary);
  }

  /* ───── Type tabs ───── */
  .mc-tabs {
    display: flex;
    gap: 4px;
    padding: 4px 12px;
    overflow-x: auto;
    scrollbar-width: none;
    font-family: var(--font-current);
  }
  .mc-tabs::-webkit-scrollbar { display: none; }

  /* pill variant */
  .mc-tabs--pill { gap: 6px; padding: 8px 14px; }
  .mc-tabs--pill .mc-tab {
    flex-shrink: 0;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 14px;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,0.06);
    background: rgba(255,255,255,0.02);
    color: var(--text-secondary);
    font-size: 13px;
    font-weight: 500;
    font-family: inherit !important;
    cursor: pointer;
    transition: background .14s, border-color .14s, color .14s;
  }
  .mc-tabs--pill .mc-tab:hover { background: rgba(255,255,255,0.06); color: var(--text-primary); }
  .mc-tabs--pill .mc-tab.is-active {
    background: linear-gradient(180deg, rgba(113,99,217,0.30) 0%, rgba(83,74,183,0.22) 100%);
    border-color: rgba(113,99,217,0.50);
    color: var(--text-primary);
    box-shadow: 0 6px 18px rgba(113,99,217,0.20);
  }
  .mc-tab-count {
    font-size: 10px;
    padding: 1px 6px;
    border-radius: 999px;
    background: rgba(255,255,255,0.10);
    color: var(--text-primary);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
    font-weight: 700;
  }
  html[lang="fa"] .mc-tab-count,
  html[lang="ar"] .mc-tab-count { font-family: inherit; }
  .mc-tabs--pill .mc-tab.is-active .mc-tab-count {
    background: rgba(255,255,255,0.18);
  }

  /* underline variant */
  .mc-tabs--underline {
    gap: 0;
    padding: 0 12px;
    border-bottom: 1px solid rgba(255,255,255,0.05);
  }
  .mc-tabs--underline .mc-tab {
    flex-shrink: 0;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 12px 14px;
    border: 0;
    border-bottom: 2px solid transparent;
    background: transparent;
    color: var(--text-tertiary);
    font-size: 13px;
    font-weight: 500;
    font-family: inherit !important;
    cursor: pointer;
    transition: color .12s, border-color .12s;
  }
  .mc-tabs--underline .mc-tab:hover { color: var(--text-secondary); }
  .mc-tabs--underline .mc-tab.is-active {
    color: var(--text-primary);
    border-bottom-color: var(--accent);
  }
  .mc-tabs--underline .mc-tab-count {
    background: rgba(255,255,255,0.06);
    color: var(--text-secondary);
  }

  /* ───── Chip row ───── */
  .mc-chips {
    display: flex;
    gap: 6px;
    padding: 6px 14px;
    overflow-x: auto;
    scrollbar-width: none;
    font-family: var(--font-current);
  }
  .mc-chips::-webkit-scrollbar { display: none; }

  .mc-chip {
    flex-shrink: 0;
    display: inline-flex; align-items: center; gap: 5px;
    padding: 6px 11px;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,0.06);
    background: rgba(255,255,255,0.02);
    color: var(--text-secondary);
    font-size: 12px;
    cursor: pointer;
    font-family: inherit !important;
    transition: background .12s, border-color .12s, color .12s;
  }
  .mc-chip:hover { background: rgba(255,255,255,0.06); color: var(--text-primary); }
  .mc-chip.is-active {
    color: var(--text-primary);
    background: rgba(113,99,217,0.18);
    border-color: var(--chip-accent, rgba(113,99,217,0.50));
  }
  .mc-chip-dot {
    width: 6px; height: 6px;
    border-radius: 50%;
    flex-shrink: 0;
    box-shadow: 0 0 4px currentColor;
  }
  .mc-chip-count {
    font-size: 10px;
    opacity: 0.7;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
  }
  html[lang="fa"] .mc-chip-count,
  html[lang="ar"] .mc-chip-count { font-family: inherit; }

  /* underline variant for chips (mirrors tabs underline) */
  .mc-chips--underline {
    padding-bottom: 0;
  }
  .mc-chips--underline .mc-chip {
    border-radius: 0;
    border: 0;
    border-bottom: 2px solid transparent;
    padding: 8px 12px;
    background: transparent;
  }
  .mc-chips--underline .mc-chip.is-active {
    color: var(--text-primary);
    background: transparent;
    border-bottom-color: var(--accent);
  }

  /* ───── Search ───── */
  .mc-search {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 14px;
    margin: 8px 14px 4px;
    border-radius: 14px;
    background: rgba(255,255,255,0.05);
    border: 1px solid rgba(255,255,255,0.10);
    color: var(--text-secondary);
    font-family: var(--font-current);
    transition: background .14s, border-color .14s, box-shadow .14s;
  }
  .mc-search:focus-within {
    background: rgba(255,255,255,0.08);
    border-color: rgba(113,99,217,0.55);
    box-shadow: 0 0 0 3px rgba(113,99,217,0.18);
  }
  .mc-search > svg { flex-shrink: 0; color: var(--text-tertiary); }
  .mc-search:focus-within > svg { color: var(--accent); }
  .mc-search input {
    flex: 1 1 auto;
    min-width: 0;
    background: transparent; border: 0;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 14px;
    line-height: 1.2;
    outline: none;
    padding: 0;
  }
  .mc-search input::placeholder { color: var(--text-tertiary); }
  .mc-search-clear {
    flex-shrink: 0;
    width: 22px; height: 22px;
    border-radius: 50%;
    border: 0;
    background: rgba(255,255,255,0.08);
    color: var(--text-secondary);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    font-family: inherit !important;
  }
  .mc-search-clear:hover { background: rgba(255,255,255,0.14); color: var(--text-primary); }

  /* ───── Sort menu ───── */
  .mc-sort {
    position: relative;
    flex-shrink: 0;
  }
  .mc-sort-trigger {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 7px 11px;
    border-radius: 10px;
    border: 1px solid rgba(255,255,255,0.06);
    background: rgba(255,255,255,0.02);
    color: var(--text-secondary);
    font-size: 12px;
    cursor: pointer;
    font-family: inherit !important;
    transition: background .12s, color .12s;
  }
  .mc-sort-trigger:hover { background: rgba(255,255,255,0.06); color: var(--text-primary); }
  .mc-sort-menu {
    position: absolute;
    top: calc(100% + 4px);
    inset-inline-end: 0;
    min-width: 160px;
    background: rgba(20,20,30,0.96);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 12px;
    padding: 4px;
    box-shadow: 0 18px 40px rgba(0,0,0,0.5);
    display: flex; flex-direction: column;
    z-index: 100;
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
  }
  .mc-sort-option {
    text-align: start;
    padding: 8px 12px;
    border: 0;
    background: transparent;
    color: var(--text-secondary);
    font-size: 12px;
    border-radius: 8px;
    cursor: pointer;
    font-family: inherit !important;
  }
  .mc-sort-option:hover { background: rgba(255,255,255,0.06); color: var(--text-primary); }
  .mc-sort-option.is-active {
    background: rgba(113,99,217,0.20);
    color: var(--text-primary);
  }

  /* ───── View toggle ───── */
  .mc-view-toggle {
    display: inline-flex;
    border-radius: 10px;
    background: rgba(255,255,255,0.02);
    border: 1px solid rgba(255,255,255,0.06);
    padding: 2px;
    flex-shrink: 0;
  }
  .mc-view-opt {
    width: 30px; height: 28px;
    border: 0;
    background: transparent;
    color: var(--text-tertiary);
    border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    font-family: inherit !important;
    transition: background .12s, color .12s;
  }
  .mc-view-opt:hover { color: var(--text-primary); }
  .mc-view-opt.is-active {
    background: rgba(255,255,255,0.08);
    color: var(--text-primary);
  }

  /* ───── Grid card ───── */
  .mc-grid-card {
    position: relative;
    border-radius: 18px;
    aspect-ratio: 200 / 311;
    overflow: hidden;
    /* Allow inner card's box-shadow rim to show */
    isolation: isolate;
  }
  /* My Cards inverts the corner-sparkle role: the small ⭐ in the top-left of
     compact cards is decorative on the standalone card, but in a tight 2- or
     3-column grid it competes with the tier/COACH/FAN/WILD badge in the
     opposite corner and reads as a status indicator. Hide it here; the badge
     in the other corner is enough. */
  .mc-grid-card .pc-corner-sparkle { display: none; }
  .mc-grid-card-inner {
    width: 100%;
    height: 100%;
    pointer-events: none;
    display: flex; align-items: stretch; justify-content: center;
  }
  /* Make the .pc inside fill the cell — override the fixed 200px width. */
  .mc-grid-card-inner .pc {
    width: 100% !important;
    height: 100% !important;
    aspect-ratio: 200 / 311 !important;
  }

  .mc-grid-card-hit {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
    background: transparent;
    cursor: pointer;
    border-radius: inherit;
    font-family: inherit !important;
    z-index: 4;
    transition: background .12s, transform .12s;
  }
  .mc-grid-card-hit:hover {
    background: rgba(255,255,255,0.02);
  }
  .mc-grid-card-hit:active { transform: scale(0.985); }
  .mc-grid-card-hit:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -3px;
  }

  /* state overlay */
  .mc-grid-card.is-reserved .mc-grid-card-inner { opacity: 0.45; }
  .mc-grid-card.is-expired .mc-grid-card-inner { filter: grayscale(0.85) brightness(0.55); }
  .mc-grid-card-overlay {
    position: absolute;
    inset: 0;
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(180deg, rgba(7,7,12,0.08) 0%, rgba(7,7,12,0.45) 100%);
    pointer-events: none;
    z-index: 5;
  }
  .mc-grid-card-overlay-pill {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 6px 12px;
    border-radius: 999px;
    background: rgba(15,15,22,0.86);
    border: 1px solid rgba(255,255,255,0.10);
    color: var(--text-primary);
    font-size: 11px;
    font-weight: 600;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
  }
  .mc-grid-card.is-reserved .mc-grid-card-overlay-pill {
    color: var(--accent);
    border-color: rgba(113,99,217,0.35);
  }
  .mc-grid-card.is-expired .mc-grid-card-overlay-pill {
    color: var(--text-tertiary);
  }

  /* Ribbons (NEW / MISSION) — fixed to physical top-left, opposite the tier
     badge (which lives at physical top-right in PlayerCard). Using
     inset-inline-start would flip with locale and collide with the tier badge
     in RTL — use plain "left" so the position stays put across fa / en / ar. */
  .mc-grid-card-ribbons {
    position: absolute;
    top: 8px;
    left: 8px;
    display: flex; flex-direction: column; gap: 4px;
    z-index: 6;
    pointer-events: none;
  }
  .mc-ribbon {
    display: inline-flex; align-items: center; gap: 3px;
    padding: 3px 8px;
    border-radius: 6px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.10em;
    text-transform: uppercase;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    backdrop-filter: blur(4px);
  }
  html[lang="fa"] .mc-ribbon,
  html[lang="ar"] .mc-ribbon { font-family: inherit; letter-spacing: 0; text-transform: none; font-size: 10px; }
  .mc-ribbon--new {
    background: linear-gradient(180deg, rgba(52,211,153,0.95) 0%, rgba(16,185,129,0.95) 100%);
    color: #07070C;
  }
  .mc-ribbon--mission {
    background: linear-gradient(180deg, rgba(255,214,10,0.95) 0%, rgba(245,158,11,0.92) 100%);
    color: #07070C;
  }

  /* ───── List row ───── */
  .mc-row {
    position: relative;
    display: flex;
    align-items: stretch;
    border-radius: 14px;
    border: 1px solid rgba(255,255,255,0.05);
    background: rgba(20,20,30,0.55);
    overflow: hidden;
    transition: background .12s, border-color .12s;
  }
  .mc-row:hover:not(.is-reserved):not(.is-expired) {
    background: rgba(30,30,42,0.7);
    border-color: rgba(255,255,255,0.10);
  }
  .mc-row.is-reserved { opacity: 0.65; }
  .mc-row.is-expired { filter: grayscale(0.7); opacity: 0.55; }

  .mc-row-main {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border: 0;
    background: transparent;
    color: var(--text-primary);
    cursor: pointer;
    text-align: start;
    font-family: inherit !important;
    transition: transform .12s;
    min-width: 0;
  }
  .mc-row-main:active { transform: scale(0.997); }
  .mc-row-info {
    flex-shrink: 0;
    width: 40px;
    align-self: stretch;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-inline-start: 1px solid rgba(255,255,255,0.05);
    background: transparent;
    color: var(--text-tertiary);
    cursor: pointer;
    transition: background .12s, color .12s;
    font-family: inherit !important;
  }
  .mc-row-info:hover {
    background: rgba(113,99,217,0.10);
    color: var(--accent);
  }
  .mc-row-info:active { transform: scale(0.92); }
  .mc-row-strip {
    width: 3px; height: 44px;
    border-radius: 999px;
    flex-shrink: 0;
  }
  .mc-row-img {
    width: 48px; height: 48px;
    position: relative;
    border-radius: 10px;
    overflow: hidden;
    flex-shrink: 0;
    border: 1px solid rgba(255,255,255,0.06);
  }
  .mc-row-img img {
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: top center;
  }
  .mc-row-img-badge {
    position: absolute;
    bottom: 2px;
    inset-inline-end: 2px;
    background: rgba(0,0,0,0.7);
    color: white;
    font-size: 7px;
    font-weight: 700;
    padding: 2px 4px;
    border-radius: 4px;
    letter-spacing: 0.06em;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
  }
  .mc-row-body { flex: 1 1 auto; min-width: 0; }
  .mc-row-name {
    display: flex; align-items: center; gap: 6px;
    font-size: 14px;
    font-weight: 700;
    color: var(--text-primary);
  }
  .mc-row-name-text {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    min-width: 0; flex: 0 1 auto;
  }
  .mc-row-new {
    flex-shrink: 0;
    font-size: 9px;
    font-weight: 700;
    padding: 1px 5px;
    border-radius: 4px;
    background: rgba(52,211,153,0.18);
    color: var(--success);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
  }
  html[lang="fa"] .mc-row-new,
  html[lang="ar"] .mc-row-new { font-family: inherit; letter-spacing: 0; text-transform: none; font-size: 10px; }
  .mc-row-meta {
    display: flex; align-items: center; gap: 5px;
    font-size: 11px;
    color: var(--text-tertiary);
    margin-top: 2px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .mc-row-stats { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
  .mc-row-ovr {
    min-width: 42px;
    padding: 4px 8px;
    border-radius: 8px;
    border: 1px solid;
    text-align: center;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-weight: 800;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
  }
  html[lang="fa"] .mc-row-ovr,
  html[lang="ar"] .mc-row-ovr { font-family: inherit; }
  .mc-row-stat {
    display: flex; flex-direction: column;
    align-items: center; line-height: 1.1;
    min-width: 26px;
  }
  .mc-row-stat-key {
    font-size: 9px;
    color: var(--text-tertiary);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    letter-spacing: 0.06em;
  }
  html[lang="fa"] .mc-row-stat-key,
  html[lang="ar"] .mc-row-stat-key { font-family: inherit; letter-spacing: 0; }
  .mc-row-stat-val {
    font-size: 12px; font-weight: 700;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
  }
  .mc-row-overlay {
    position: absolute;
    inset-inline-end: 14px;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(15,15,22,0.86);
    border: 1px solid rgba(255,255,255,0.10);
    color: var(--accent);
    font-size: 10px;
    font-weight: 600;
    pointer-events: none;
  }
  .mc-row.is-expired .mc-row-overlay { color: var(--text-tertiary); }

  /* ───── Filter dropdown (mobile) ───── */
  .mc-filter-dd {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
  }
  .mc-filter-dd-trigger {
    width: 100%;
    display: flex; align-items: center; gap: 6px;
    padding: 9px 10px;
    border-radius: 12px;
    border: 1px solid rgba(255,255,255,0.06);
    background: rgba(255,255,255,0.025);
    color: var(--text-secondary);
    font-size: 12px;
    cursor: pointer;
    font-family: inherit !important;
    transition: background .12s, border-color .12s, color .12s;
    min-width: 0;
  }
  .mc-filter-dd-trigger:hover {
    background: rgba(255,255,255,0.05);
    color: var(--text-primary);
  }
  .mc-filter-dd-trigger.is-set {
    border-color: rgba(113,99,217,0.40);
    background: rgba(113,99,217,0.08);
    color: var(--text-primary);
  }
  .mc-filter-dd-label {
    color: var(--text-tertiary);
    font-size: 11px;
    flex-shrink: 0;
  }
  .mc-filter-dd-trigger.is-set .mc-filter-dd-label { color: var(--text-secondary); }
  .mc-filter-dd-value {
    display: inline-flex; align-items: center; gap: 5px;
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
  }
  .mc-filter-dd-value-text {
    color: var(--text-primary);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
  }
  .mc-filter-dd-dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
    box-shadow: 0 0 4px currentColor;
  }
  .mc-filter-dd-chev {
    color: var(--text-tertiary);
    flex-shrink: 0;
    transition: transform .15s;
  }
  .mc-filter-dd-menu {
    position: absolute;
    top: calc(100% + 4px);
    inset-inline-start: 0;
    inset-inline-end: 0;
    background: rgba(20,20,30,0.97);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 12px;
    padding: 4px;
    box-shadow: 0 20px 48px rgba(0,0,0,0.55);
    display: flex; flex-direction: column;
    z-index: 100;
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    max-height: 320px;
    overflow-y: auto;
    scrollbar-width: thin;
  }
  .mc-filter-dd-option {
    display: flex; align-items: center; gap: 8px;
    text-align: start;
    padding: 9px 10px;
    border: 0;
    background: transparent;
    color: var(--text-secondary);
    font-size: 12px;
    border-radius: 8px;
    cursor: pointer;
    font-family: inherit !important;
    transition: background .12s, color .12s;
  }
  .mc-filter-dd-option:hover {
    background: rgba(255,255,255,0.06);
    color: var(--text-primary);
  }
  .mc-filter-dd-option.is-active {
    background: rgba(113,99,217,0.18);
    color: var(--text-primary);
  }
  .mc-filter-dd-option-label {
    flex: 1 1 auto;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .mc-filter-dd-option-count {
    font-size: 10px;
    opacity: 0.6;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
  }
  html[lang="fa"] .mc-filter-dd-option-count,
  html[lang="ar"] .mc-filter-dd-option-count { font-family: inherit; }

  /* Row of dropdowns (mobile filter shelf) */
  .mc-filter-row {
    display: flex; gap: 8px;
    padding: 6px 14px 4px;
  }

  /* ───── Inline sponsor ───── */
  .mc-sponsor-inline { display: block; }
  .mc-sponsor-inline-card {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 14px;
    border-radius: 14px;
    background: linear-gradient(180deg, rgba(255,255,255,0.03) 0%, rgba(255,255,255,0.01) 100%);
    border: 1px solid rgba(255,255,255,0.05);
    position: relative;
    overflow: hidden;
    isolation: isolate;
  }
  .mc-sponsor-inline-card::before {
    content: 'AD';
    position: absolute;
    top: 4px;
    inset-inline-end: 6px;
    font-size: 7px;
    font-weight: 700;
    letter-spacing: 0.1em;
    color: var(--text-tertiary);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    opacity: 0.5;
    z-index: 2;
  }
  .mc-sponsor-mark {
    width: 36px; height: 36px;
    border-radius: 10px;
    color: white;
    font-weight: 800;
    font-size: 16px;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    box-shadow: 0 6px 16px rgba(0,0,0,0.3);
    font-family: 'Boldonse', 'Inter', sans-serif;
    position: relative;
    z-index: 1;
  }
  .mc-sponsor-mark span {
    font-family: inherit;
    line-height: 1;
  }
  .mc-sponsor-text {
    display: flex; flex-direction: column;
    gap: 1px;
    min-width: 0;
    flex-shrink: 0;
    position: relative;
    z-index: 1;
  }
  .mc-sponsor-eye {
    font-size: 9px;
    color: var(--text-tertiary);
    font-weight: 500;
    letter-spacing: 0.06em;
  }
  .mc-sponsor-name {
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
  }
  .mc-sponsor-tag {
    font-size: 11px;
    color: var(--text-secondary);
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    position: relative;
    z-index: 1;
  }
  .mc-sponsor-cta {
    flex-shrink: 0;
    padding: 6px 12px;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,0.10);
    background: rgba(255,255,255,0.04);
    color: var(--text-secondary);
    font-size: 11px;
    cursor: pointer;
    font-family: inherit !important;
    transition: background .12s, color .12s;
    position: relative;
    z-index: 1;
  }
  .mc-sponsor-cta:hover { background: rgba(255,255,255,0.10); color: var(--text-primary); }
  @media (max-width: 480px) {
    .mc-sponsor-tag { display: none; }
  }

  /* ───── Sponsor block (desktop sidebar) ───── */
  .mc-sponsor-block {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    border-radius: 18px;
    border: 1px solid rgba(255,255,255,0.06);
    background:
      radial-gradient(ellipse 120% 80% at 50% 0%, rgba(var(--brand-rgb, 220, 38, 38), 0.06) 0%, transparent 60%),
      linear-gradient(180deg, rgba(255,255,255,0.04) 0%, rgba(255,255,255,0.01) 100%);
    padding: 22px 18px 18px;
    display: flex; flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 6px;
  }
  .mc-sponsor-block::before {
    content: 'AD';
    position: absolute;
    top: 8px;
    inset-inline-end: 12px;
    font-size: 8px;
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--text-tertiary);
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    opacity: 0.55;
    z-index: 2;
  }
  .mc-sponsor-block-eye {
    font-size: 10px;
    color: var(--text-tertiary);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    font-family: 'JetBrains Mono', ui-monospace, monospace;
    margin-bottom: 4px;
    position: relative; z-index: 1;
  }
  html[lang="fa"] .mc-sponsor-block-eye,
  html[lang="ar"] .mc-sponsor-block-eye {
    font-family: inherit; text-transform: none; letter-spacing: 0; font-size: 11px;
  }
  .mc-sponsor-block-mark {
    width: 64px; height: 64px;
    border-radius: 18px;
    background: linear-gradient(135deg, var(--brand), var(--brand-2));
    color: white;
    display: flex; align-items: center; justify-content: center;
    font-family: 'Boldonse', 'Inter', sans-serif;
    font-weight: 800;
    font-size: 28px;
    box-shadow:
      0 14px 30px rgba(0,0,0,0.40),
      0 0 28px color-mix(in srgb, var(--brand) 25%, transparent),
      inset 0 1px 0 rgba(255,255,255,0.20);
    position: relative; z-index: 1;
  }
  .mc-sponsor-block-name {
    font-size: 18px;
    font-weight: 800;
    color: var(--text-primary);
    margin-top: 8px;
    line-height: 1.2;
    position: relative; z-index: 1;
  }
  .mc-sponsor-block-tag {
    font-size: 12px;
    color: var(--text-secondary);
    line-height: 1.45;
    margin-bottom: 12px;
    max-width: 220px;
    position: relative; z-index: 1;
  }
  .mc-sponsor-block-cta {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 16px;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,0.12);
    background: rgba(255,255,255,0.05);
    color: var(--text-primary);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    font-family: inherit !important;
    transition: background .14s, border-color .14s;
    position: relative; z-index: 1;
  }
  .mc-sponsor-block-cta:hover {
    background: rgba(255,255,255,0.12);
    border-color: rgba(255,255,255,0.20);
  }
  html[dir="rtl"] .mc-sponsor-block-cta svg { transform: scaleX(-1); }

  /* ───── Sponsor light sweep (shared, ported from Lineup) ───── */
  /* Soft diagonal highlight that travels across the surface, simulating a
     passing reflection on a glossy ad. Lives behind text via z-index. */
  .mc-sponsor-shine {
    position: absolute;
    top: -50%;
    left: -30%;
    width: 35%;
    height: 200%;
    background: linear-gradient(115deg,
      transparent 0%,
      rgba(255,255,255,0.10) 35%,
      rgba(255,255,255,0.24) 50%,
      rgba(255,255,255,0.10) 65%,
      transparent 100%);
    transform: skewX(-18deg) translateX(-150%);
    animation: mc-sponsor-shine 5.4s ease-in-out infinite;
    z-index: 0;
    pointer-events: none;
    mix-blend-mode: screen;
  }
  /* Stagger the second placement so two sponsors on screen don't shine in
     unison — picks the same animation but with a delay/duration variant. */
  .mc-sponsor-block .mc-sponsor-shine { animation-duration: 6.2s; animation-delay: 1.4s; }
  @keyframes mc-sponsor-shine {
    0%       { transform: skewX(-18deg) translateX(-150%); opacity: 0; }
    8%       { opacity: 1; }
    55%, 100%{ transform: skewX(-18deg) translateX(900%);  opacity: 0; }
  }
  @media (prefers-reduced-motion: reduce) {
    .mc-sponsor-shine { animation: none; opacity: 0; }
  }

  /* ───── Empty state ───── */
  .mc-empty {
    display: flex; flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 64px 24px;
    gap: 8px;
  }
  .mc-empty-art {
    margin-bottom: 12px;
    opacity: 0.95;
  }
  .mc-empty-title {
    font-size: 22px;
    font-weight: 800;
    color: var(--text-primary);
    line-height: 1.2;
  }
  .mc-empty-sub {
    font-size: 13px;
    color: var(--text-secondary);
    line-height: 1.5;
    max-width: 280px;
    margin-bottom: 18px;
  }
  .mc-empty-cta {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 12px 22px;
    border-radius: 14px;
    background: linear-gradient(180deg, var(--accent) 0%, var(--accent-2) 100%);
    color: white;
    border: 1px solid rgba(255,255,255,0.10);
    font-family: inherit !important;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 12px 32px rgba(113,99,217,0.30), inset 0 1px 0 rgba(255,255,255,0.18);
    transition: transform .12s, box-shadow .14s;
  }
  .mc-empty-cta:active { transform: scale(0.985); }
  .mc-empty-cta:hover { box-shadow: 0 16px 40px rgba(113,99,217,0.45), inset 0 1px 0 rgba(255,255,255,0.25); }
`;

const __mcPiecesStyle = document.createElement('style');
__mcPiecesStyle.textContent = MC_PIECES_CSS;
document.head.appendChild(__mcPiecesStyle);
