// homehub-pieces.jsx — Reusable primitives for the Home Hub.
//
// Public primitives:
//   AppBar           — mobile (compact, sticky)
//   DesktopTopbar    — desktop variant
//   BottomNav        — 5/6 tabs, scroll-aware shrink
//   MatchHero        — next-match preview with LED billboards + countdown
//   StatTile         — single stat with optional progress + delta
//   QuickActionCard  — large tappable action tile
//   FeaturedRail     — horizontal compact-card carousel (uses window.PlayerCard)
//   GoldenMissionCard
//   DailyMissionRow  — also renders sponsored-mission variant when sponsored=true
//   PackCallout      — pack-of-the-day teaser
//   SponsorSkyscraper — reuses window.SponsorBlock from MyCards
//   HHIcon           — central icon set (one consistent stroke/family)

// ─── helpers ───────────────────────────────────────────────────────────────
const _toDigits = (n, locale) =>
  (typeof window.toLocaleDigits === 'function')
    ? window.toLocaleDigits(n, locale)
    : String(n);

function HHIcon({ name, size = 18, strokeWidth = 1.7, style }) {
  const s = size;
  const sw = strokeWidth;
  const stroke = 'currentColor';
  const common = {
    width: s, height: s, viewBox: '0 0 24 24', fill: 'none',
    stroke, strokeWidth: sw, strokeLinecap: 'round', strokeLinejoin: 'round',
    style,
  };
  switch (name) {
    case 'home':
      return (<svg {...common}><path d="M3 11.5 12 4l9 7.5"/><path d="M5 10v9.5h4.5V14h5v5.5H19V10"/></svg>);
    case 'predict':
      return (<svg {...common}><path d="M12 3v3M12 18v3M3 12h3M18 12h3M5.6 5.6l2.1 2.1M16.3 16.3l2.1 2.1M5.6 18.4l2.1-2.1M16.3 7.7l2.1-2.1"/><circle cx="12" cy="12" r="3.2"/></svg>);
    case 'lineup':
      return (<svg {...common}><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 12h18M12 4v16"/><circle cx="12" cy="12" r="2.4"/></svg>);
    case 'cards':
      return (<svg {...common}><rect x="6" y="3" width="11" height="16" rx="2"/><path d="M8.5 18.5l1.5 2.5 4-1.5"/></svg>);
    case 'rank':
      return (<svg {...common}><path d="M5 21h14M7 14v7M12 8v13M17 11v10"/><path d="M9 4l3-2 3 2v3a3 3 0 1 1-6 0V4z"/></svg>);
    case 'shop':
      return (<svg {...common}><path d="M4 7h16l-1.4 11.4a2 2 0 0 1-2 1.6H7.4a2 2 0 0 1-2-1.6L4 7z"/><path d="M8.5 7V5a3.5 3.5 0 1 1 7 0v2"/></svg>);
    case 'bell':
      return (<svg {...common}><path d="M6 16V11a6 6 0 1 1 12 0v5l1.5 2.2H4.5L6 16z"/><path d="M10 20.5a2 2 0 0 0 4 0"/></svg>);
    case 'menu':
      return (<svg {...common}><path d="M4 7h16M4 12h16M4 17h10"/></svg>);
    case 'search':
      return (<svg {...common}><circle cx="11" cy="11" r="6.5"/><path d="M16 16l4.5 4.5"/></svg>);
    case 'coin':
      // Locale-neutral coin glyph (concentric ring + center dot) — earlier
      // version drew an "S" that read as a Latin $ sign and felt reversed in
      // RTL. Now it's clearly a coin shape with no script direction.
      return (<svg {...common}><circle cx="12" cy="12" r="8.5"/><circle cx="12" cy="12" r="5.2"/><circle cx="12" cy="12" r="1.6" fill="currentColor" stroke="none"/></svg>);
    case 'xp':
      return (<svg {...common}><path d="M4 4l4 16M4 4l-1 4M8 20l1-4M16 4l4 16M16 4l-1 4M20 20l1-4"/></svg>);
    case 'flame':
      return (<svg {...common}><path d="M12 22c-4 0-7-2.7-7-6.5 0-2.8 1.6-4.4 3-5.6 1.2-1 1.5-2 1.2-3.6 2 .8 3.4 2.3 3.5 4.3 2-1.7 2.8-3 2.8-4.6 2 2.5 3.5 5.4 3.5 8.6 0 4-3 7.4-7 7.4z"/></svg>);
    case 'chevron':
      return (<svg {...common}><path d="M9 6l6 6-6 6"/></svg>);
    case 'plus':
      return (<svg {...common}><path d="M12 5v14M5 12h14"/></svg>);
    case 'gift':
      return (<svg {...common}><rect x="3.5" y="9" width="17" height="11" rx="2"/><path d="M3.5 13.5h17M12 9v11"/><path d="M8 9c-1.5 0-2.5-1-2.5-2.5S6.5 4 8 4c2 0 4 5 4 5s-2 0-4 0zM16 9c1.5 0 2.5-1 2.5-2.5S17.5 4 16 4c-2 0-4 5-4 5s2 0 4 0z"/></svg>);
    case 'users':
      return (<svg {...common}><circle cx="8.5" cy="9" r="3.5"/><path d="M2.5 19c0-3 2.8-5 6-5s6 2 6 5"/><circle cx="17" cy="10" r="2.8"/><path d="M14.5 19c0-2 1.6-3.5 4-3.5s3 1.4 3 3"/></svg>);
    case 'check':
      return (<svg {...common}><path d="M4 12.5l5 5 11-12"/></svg>);
    case 'clock':
      return (<svg {...common}><circle cx="12" cy="12" r="8.5"/><path d="M12 7v5.5L15.5 15"/></svg>);
    case 'trophy':
      return (<svg {...common}><path d="M8 4h8v4a4 4 0 1 1-8 0V4z"/><path d="M5 5h3v3a3 3 0 0 1-3-3zM19 5h-3v3a3 3 0 0 0 3-3zM10 13.5v3M14 13.5v3M8 20h8M9 17h6"/></svg>);
    case 'sparkle':
      return (<svg {...common}><path d="M12 3l1.6 5.4L19 10l-5.4 1.6L12 17l-1.6-5.4L5 10l5.4-1.6L12 3z"/></svg>);
    case 'dot':
      return (<svg {...common}><circle cx="12" cy="12" r="4" fill="currentColor"/></svg>);
    default:
      return null;
  }
}

// ─── AppBar (mobile) ───────────────────────────────────────────────────────
// Two density modes: 'comfortable' (greeting line) and 'compact' (single row).
// avatarSide: 'start' (default, RTL = right) or 'end'.
function AppBar({
  locale = 'fa',
  user = HH_USER,
  density = 'comfortable',  // 'comfortable' | 'compact'
  avatarSide = 'start',
  showStreak = false,        // ← daily-login streak surfaces as a mission row instead
  showCoin = true,
  showXP = true,
  showBell = true,
  showMenu = false,           // ← removed by default: redundant with avatar tap
  notifications = 0,
  onAvatar, onBell, onMenu, onCoin, onXP, onStreak,
}) {
  const ll = HH_I18N[locale];
  const avatarBlock = (
    <button className="hh-avatar-btn" type="button" data-app-nav="profile" onClick={onAvatar} aria-label={user.displayName[locale]}>
      <div className="hh-avatar">
        <div className="hh-avatar-glow"></div>
        <span className="hh-avatar-initial">{user.avatarInitial}</span>
      </div>
      {density === 'comfortable' && (
        <div className="hh-avatar-meta">
          <div className="hh-avatar-greet">{hhGreeting(locale, 11)}</div>
          <div className="hh-avatar-name">{user.shortName[locale]}</div>
        </div>
      )}
    </button>
  );

  const pills = (
    <div className="hh-appbar-pills">
      {showStreak && (
        <button type="button" className="hh-pill hh-pill--streak" onClick={onStreak}
                aria-label={`${user.streak} ${ll.statStreak}`}>
          <HHIcon name="flame" size={14}/>
          <span className="tabular-nums">{_toDigits(user.streak, locale)}</span>
        </button>
      )}
      {showCoin && (
        <button type="button" className="hh-pill hh-pill--coin" onClick={onCoin}>
          <HHIcon name="coin" size={14}/>
          <span className="tabular-nums">{_toDigits(user.coinBalance.toLocaleString('en-US'), locale)}</span>
        </button>
      )}
      {showXP && (
        <button type="button" className="hh-pill hh-pill--xp" onClick={onXP}
                aria-label={`${ll.level} ${user.level}`}>
          <span className="hh-pill-lvl-label">{ll.level}</span>
          <span className="hh-pill-lvl-num tabular-nums">{_toDigits(user.level, locale)}</span>
        </button>
      )}
      {showBell && (
        <button type="button" className="hh-icon-btn" data-app-nav="notifications" onClick={onBell} aria-label={ll.notifications}>
          <HHIcon name="bell" size={18}/>
          {notifications > 0 && <span className="hh-notif-dot">{_toDigits(notifications, locale)}</span>}
        </button>
      )}
      {showMenu && (
        <button type="button" className="hh-icon-btn" onClick={onMenu} aria-label={ll.menu}>
          <HHIcon name="menu" size={18}/>
        </button>
      )}
    </div>
  );

  return (
    <header className={`hh-appbar hh-appbar--${density} hh-appbar--av-${avatarSide}`}>
      <div className="hh-appbar-row">
        {avatarBlock}
        <div className="hh-appbar-spacer"></div>
        {pills}
      </div>
    </header>
  );
}

// ─── Desktop topbar ────────────────────────────────────────────────────────
function DesktopTopbar({ locale = 'fa', user = HH_USER, activeTab = 'home',
                         notifications = 0, fiveTabs = false }) {
  const ll = HH_I18N[locale];
  const tabs = hhNavTabs(locale, fiveTabs);
  return (
    <header className="hh-desk-topbar">
      <div className="hh-desk-topbar-left">
        <div className="hh-desk-logo">
          <span className="hh-desk-logo-mark">R</span>
          <span className="hh-desk-logo-text">
            {locale === 'fa' ? 'رختکن' : locale === 'ar' ? 'رختكن' : 'Rakhtkan'}
          </span>
        </div>
        <nav className="hh-desk-nav" aria-label="primary">
          {tabs.map((t) => (
            <a key={t.key} href="#" data-tab-key={t.key}
               className={`hh-desk-nav-item ${activeTab === t.key ? 'is-active' : ''}`}>
              <HHIcon name={t.icon} size={16}/>
              <span>{t.label}</span>
              {HH_NAV_BADGES[t.key] > 0 && <span className="hh-desk-nav-badge">{_toDigits(HH_NAV_BADGES[t.key], locale)}</span>}
            </a>
          ))}
        </nav>
      </div>
      <div className="hh-desk-topbar-right">
        <button type="button" className="hh-desk-search" aria-label={ll.search}>
          <HHIcon name="search" size={15}/>
          <span>{ll.search}</span>
          <span className="hh-desk-kbd">⌘K</span>
        </button>
        <button type="button" className="hh-pill hh-pill--xp"
                aria-label={`${ll.level} ${user.level}`}>
          <span className="hh-pill-lvl-label">{ll.level}</span>
          <span className="hh-pill-lvl-num tabular-nums">{_toDigits(user.level, locale)}</span>
        </button>
        <button type="button" className="hh-pill hh-pill--coin">
          <HHIcon name="coin" size={14}/>
          <span className="tabular-nums">{_toDigits(user.coinBalance.toLocaleString('en-US'), locale)}</span>
        </button>
        <button type="button" className="hh-icon-btn" data-app-nav="notifications" aria-label={ll.notifications}>
          <HHIcon name="bell" size={18}/>
          {notifications > 0 && <span className="hh-notif-dot">{_toDigits(notifications, locale)}</span>}
        </button>
        <button type="button" className="hh-desk-avatar" data-app-nav="profile" aria-label={user.displayName[locale]}>
          <span>{user.avatarInitial}</span>
        </button>
      </div>
    </header>
  );
}

// ─── BottomNav ─────────────────────────────────────────────────────────────
// Detached glass pill that floats above content. Scroll-aware: when `shrunk`
// is true, labels collapse and only icons show (active stays as a soft
// accent-tinted bubble + glow).
function BottomNav({ locale = 'fa', activeTab = 'home', shrunk = false,
                     fiveTabs = false, scrollAware = true }) {
  const tabs = hhNavTabs(locale, fiveTabs);
  return (
    <nav className={`hh-bnav ${shrunk ? 'is-shrunk' : ''} ${scrollAware ? 'is-scroll-aware' : ''}`}
         aria-label="primary">
      {/* Decorative sheen — top highlight + bottom accent wash, mix-blend
          screen so it sits over the glass without darkening. */}
      <span className="hh-bnav-sheen" aria-hidden="true"></span>
      {tabs.map((t) => {
        const active = t.key === activeTab;
        const badge = HH_NAV_BADGES[t.key];
        return (
          <button key={t.key} type="button"
                  data-tab-key={t.key}
                  className={`hh-bnav-tab ${active ? 'is-active' : ''}`}>
            <span className="hh-bnav-icon">
              <HHIcon name={t.icon} size={20}/>
              {badge > 0 && <span className="hh-bnav-badge">{_toDigits(badge, locale)}</span>}
            </span>
            <span className="hh-bnav-label">{t.label}</span>
          </button>
        );
      })}
    </nav>
  );
}

// ─── PredictionSlider ───────────────────────────────────────────────────────
// Horizontal carousel of upcoming matches the user can predict. Each card
// shows: two crests, kickoff time + countdown, reward range, number of open
// prediction items, and a "پیش‌بینی کن" CTA that opens the prediction
// details sheet (multi-question: نتیجه نهایی / تعداد گل / BTTS / ...).
//
// Above all cards: header strip with global headline (`۴ بازی منتظر`),
// total reward, next-lock countdown, and "همه بازی‌ها" link. Below: pagination dots.
//
// Drag-scroll on mouse: pointer events drive scrollLeft while held; on
// release we snap to the nearest card. Touch keeps native scroll (smoother).
function PredictionSlider({ locale = 'fa', matches, sponsorId = 'mci',
                            dateMode = 'hybrid', nextLock, rewardTotal,
                            dense = false, cardsPerView = 1,
                            onPredict, onAllMatches }) {
  const ll = HH_I18N[locale];
  const sp = HH_SPONSORS[sponsorId];
  const list = (matches && matches.length) ? matches : HH_PREDICTIONS.matches;
  const trackRef = React.useRef(null);
  const [active, setActive] = React.useState(0);
  // Drag state — persists across renders without retriggering
  const drag = React.useRef({
    down: false, startX: 0, startScroll: 0, moved: false, pointerId: null,
  });

  // Helpers — compute card width inc. gap (used by drag-snap + dot taps)
  const cardWidth = () => {
    const el = trackRef.current;
    if (!el) return 0;
    const card = el.querySelector('.hh-pred-card');
    if (!card) return 0;
    const gap = parseFloat(getComputedStyle(el).gap || '0');
    return card.getBoundingClientRect().width + gap;
  };

  // Update active index from scroll position
  const onScroll = React.useCallback(() => {
    const el = trackRef.current;
    if (!el) return;
    const w = cardWidth();
    if (!w) return;
    const idx = Math.round(Math.abs(el.scrollLeft) / w);
    setActive(Math.min(list.length - 1, Math.max(0, idx)));
  }, [list.length]);

  // Programmatic jump (used by pagination dots)
  const goTo = (i) => {
    const el = trackRef.current;
    if (!el) return;
    const cards = Array.from(el.querySelectorAll('.hh-pred-card'));
    if (!cards[i]) return;
    cards[i].scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest' });
  };

  // ─── Pointer drag handlers (mouse only — touch uses native scroll) ───
  const onPointerDown = (e) => {
    // Only handle mouse / pen — let touch keep its native momentum.
    if (e.pointerType === 'touch') return;
    const el = trackRef.current;
    if (!el) return;
    drag.current = {
      down: true,
      startX: e.clientX,
      startScroll: el.scrollLeft,
      moved: false,
      pointerId: e.pointerId,
    };
    el.classList.add('is-dragging');
    try { el.setPointerCapture && el.setPointerCapture(e.pointerId); } catch (_) {}
  };
  const onPointerMove = (e) => {
    const d = drag.current;
    if (!d.down) return;
    const el = trackRef.current;
    if (!el) return;
    const dx = e.clientX - d.startX;
    if (Math.abs(dx) > 4) d.moved = true;
    el.scrollLeft = d.startScroll - dx;
  };
  const endDrag = (e) => {
    const d = drag.current;
    if (!d.down) return;
    const el = trackRef.current;
    if (!el) return;
    try { el.releasePointerCapture && el.releasePointerCapture(d.pointerId); } catch (_) {}
    el.classList.remove('is-dragging');
    // Manually snap to nearest card so scroll-snap stays accurate after JS-driven scroll
    const w = cardWidth();
    if (w) {
      const idx = Math.round(Math.abs(el.scrollLeft) / w);
      const cards = Array.from(el.querySelectorAll('.hh-pred-card'));
      cards[Math.max(0, Math.min(list.length - 1, idx))]
        ?.scrollIntoView({ behavior: 'smooth', inline: 'start', block: 'nearest' });
    }
    // Keep `moved` until the click handler has a chance to suppress
    setTimeout(() => { drag.current.moved = false; }, 50);
    drag.current.down = false;
  };
  // Suppress button clicks that occur at the end of a drag (so dragging the
  // slider over the "پیش‌بینی کن" CTA never accidentally fires it).
  const onClickCapture = (e) => {
    if (drag.current.moved) {
      e.stopPropagation();
      e.preventDefault();
    }
  };

  // Compose nextLock countdown
  const lockCd = nextLock
    ? `${_toDigits(String(nextLock.h).padStart(2,'0'), locale)}:`
    + `${_toDigits(String(nextLock.m).padStart(2,'0'), locale)}:`
    + `${_toDigits(String(nextLock.s).padStart(2,'0'), locale)}`
    : null;

  return (
    <article className={`hh-pred ${dense ? 'hh-pred--dense' : ''} ${cardsPerView > 1 ? 'hh-pred--multi' : ''}`}
             style={{ '--pred-cards-per-view': cardsPerView }}>
      {/* Background — atmospheric, shared across all cards */}
      <div className="hh-pred-bg" aria-hidden="true">
        <div className="hh-pred-bg-glow"></div>
        <div className="hh-pred-bg-vignette"></div>
      </div>

      {/* LED billboard sponsor strip */}
      <div className="hh-pred-led" aria-hidden="true">
        <div className="hh-pred-led-track">
          {[0,1,2,3].map((i) => (
            <span key={i} className="hh-pred-led-item">
              <span className="hh-pred-led-eyebrow">{sp.tag[locale]}</span>
              <span className="hh-pred-led-sep">·</span>
              <span className="hh-pred-led-cta">{sp.tagline[locale]}</span>
              <span className="hh-pred-led-sep">·</span>
            </span>
          ))}
        </div>
        <div className="hh-pred-led-shine" aria-hidden="true"></div>
      </div>

      {/* Header strip: headline + total reward + next lock + all-matches link */}
      <header className="hh-pred-head">
        <div className="hh-pred-head-titles">
          <div className="hh-pred-head-eyebrow">
            <HHIcon name="predict" size={11}/>
            <span>{ll.predictTitle}</span>
          </div>
          <div className="hh-pred-head-title">
            {ll.predictHeadline(_toDigits(list.length, locale))}
          </div>
        </div>
        <div className="hh-pred-head-meta">
          <div className="hh-pred-head-reward">
            <HHIcon name="coin" size={13}/>
            <span>{ll.predictTotalReward(_toDigits(rewardTotal != null ? rewardTotal.toLocaleString('en-US') : '2,500', locale))}</span>
          </div>
          {lockCd && (
            <div className="hh-pred-head-lock">
              <HHIcon name="clock" size={11}/>
              <span className="hh-pred-head-lock-label">{ll.predictNextLock}</span>
              <span className="hh-pred-head-lock-value tabular-nums">{lockCd}</span>
            </div>
          )}
        </div>
      </header>

      {/* Slider track — pointer events for mouse drag, native scroll for touch */}
      <div className="hh-pred-slider"
           ref={trackRef}
           onScroll={onScroll}
           onPointerDown={onPointerDown}
           onPointerMove={onPointerMove}
           onPointerUp={endDrag}
           onPointerCancel={endDrag}
           onClickCapture={onClickCapture}>
        {list.map((m) => (
          <PredictionMatchCard key={m.id} match={m} locale={locale}
                               dateMode={dateMode}
                               onPredict={onPredict}/>
        ))}
      </div>

      {/* Pagination */}
      <div className="hh-pred-pager" aria-hidden="true">
        {list.map((_, i) => (
          <button key={i} type="button" onClick={() => goTo(i)}
                  className={`hh-pred-dot ${i === active ? 'is-active' : ''}`}
                  aria-label={`go to match ${i + 1}`}/>
        ))}
        <button type="button" className="hh-pred-allmatches" onClick={onAllMatches}>
          <span>{ll.predictAllCta}</span>
          <HHIcon name="chevron" size={12}/>
        </button>
      </div>
    </article>
  );
}

// ─── PredictionMatchCard ───────────────────────────────────────────────────
function PredictionMatchCard({ match, locale, dateMode = 'hybrid', onPredict }) {
  const ll = HH_I18N[locale];
  const home = match.home, away = match.away;

  const dPrimary = dateMode === 'gregorian' ? match.dateGregorian
                 : (match.dateJalali ? match.dateJalali[locale] : '');
  const dSecondary = dateMode === 'hybrid' && match.dateJalali
    ? (locale === 'fa' ? match.dateGregorian : match.dateJalali[locale])
    : null;

  const cd = `${_toDigits(String(match.hours || 0).padStart(2,'0'), locale)}:`
           + `${_toDigits(String(match.minutes || 0).padStart(2,'0'), locale)}:`
           + `${_toDigits(String(match.seconds || 0).padStart(2,'0'), locale)}`;

  const homeIsLight = home.color.toLowerCase() === '#ffffff' || home.color.toLowerCase() === '#fff';
  const awayIsLight = away.color.toLowerCase() === '#ffffff' || away.color.toLowerCase() === '#fff';

  const handleCta = () => {
    if (onPredict) onPredict({ matchId: match.id, match });
  };

  return (
    <div className="hh-pred-card" role="group" aria-label={`${home[locale]} vs ${away[locale]}`}>
      <div className="hh-pred-card-top">
        <span className="hh-pred-card-league">{match.leagueShort ? match.leagueShort[locale] : match.league[locale]}</span>
        <div className="hh-pred-card-top-meta">
          {match.tag && (
            <span className="hh-pred-card-tag">{match.tag[locale]}</span>
          )}
        </div>
      </div>

      <div className="hh-pred-card-teams">
        <div className="hh-pred-card-team">
          <div className="hh-pred-card-crest"
               style={{ background: `linear-gradient(155deg, ${home.color} 0%, rgba(0,0,0,0.65) 100%)`,
                        color: homeIsLight ? '#0E0E16' : 'rgba(255,255,255,0.95)' }}>
            <span className="hh-pred-card-crest-code">{home.code}</span>
          </div>
          <div className="hh-pred-card-team-name">{home[locale]}</div>
        </div>

        <div className="hh-pred-card-center">
          <div className="hh-pred-card-time tabular-nums" title={dSecondary || ''}>{match.kickoff?.[locale] || '—'}</div>
          <div className="hh-pred-card-vs">{ll.vs}</div>
          <div className="hh-pred-card-countdown tabular-nums">{cd}</div>
          <div className="hh-pred-card-date">{dPrimary}</div>
        </div>

        <div className="hh-pred-card-team">
          <div className="hh-pred-card-crest"
               style={{ background: `linear-gradient(155deg, ${away.color} 0%, rgba(0,0,0,0.65) 100%)`,
                        color: awayIsLight ? '#0E0E16' : 'rgba(255,255,255,0.95)' }}>
            <span className="hh-pred-card-crest-code">{away.code}</span>
          </div>
          <div className="hh-pred-card-team-name">{away[locale]}</div>
        </div>
      </div>

      <footer className="hh-pred-card-foot">
        <div className="hh-pred-card-chips">
          <span className="hh-pred-card-chip hh-pred-card-chip--reward">
            <HHIcon name="coin" size={12}/>
            <span className="tabular-nums">{ll.predictMatchReward(_toDigits(match.rewardMax.toLocaleString('en-US'), locale))}</span>
          </span>
          <span className="hh-pred-card-chip hh-pred-card-chip--count">
            <HHIcon name="predict" size={12}/>
            <span>{ll.predictCount(_toDigits(match.predictionCount, locale))}</span>
          </span>
        </div>
        <button type="button" className="hh-pred-card-cta" onClick={handleCta}>
          <span>{ll.predictCta}</span>
          <HHIcon name="chevron" size={14}/>
        </button>
      </footer>
    </div>
  );
}

// ─── SubmitStatusTile ───────────────────────────────────────────────────────
// Stat-style tile. Compact enough to sit alongside XP/Rank stats. CTA is the
// whole tile (clickable button) — no separate button — to match the visual
// weight of the other bento stats.
function SubmitStatusTile({ locale = 'fa', deck = HH_DECK, onCta }) {
  const ll = HH_I18N[locale];
  const ready = deck.ready === deck.total;
  const empty = deck.ready === 0;
  const pct = deck.ready / deck.total;
  const cd = `${_toDigits(String(deck.freeIn.h).padStart(2,'0'), locale)}:`
           + `${_toDigits(String(deck.freeIn.m).padStart(2,'0'), locale)}:`
           + `${_toDigits(String(deck.freeIn.s).padStart(2,'0'), locale)}`;

  return (
    <button type="button" onClick={onCta}
            className={`hh-submit-tile ${ready ? 'is-ready' : ''}`}>
      <header className="hh-submit-tile-head">
        <span className="hh-submit-tile-title-row">
          <HHIcon name="lineup" size={13}/>
          <span className="hh-submit-tile-title">{ll.submitTileTitle}</span>
        </span>
        <HHIcon name="chevron" size={14}/>
      </header>

      <div className="hh-submit-tile-status">
        {ready ? ll.submitTileReady
              : empty ? ll.submitTileEmpty
              : ll.submitTilePartial(_toDigits(deck.ready, locale), _toDigits(deck.total, locale))}
      </div>

      <div className="hh-submit-tile-slots" aria-hidden="true">
        {Array.from({ length: deck.total }).map((_, i) => (
          <span key={i} className={`hh-submit-tile-slot ${i < deck.ready ? 'is-filled' : 'is-empty'}`}></span>
        ))}
      </div>

      <div className="hh-submit-tile-foot">
        <HHIcon name="clock" size={11}/>
        <span className="hh-submit-tile-foot-label">{ll.submitTileCountdown}</span>
        <span className="hh-submit-tile-foot-value tabular-nums">{cd}</span>
      </div>
    </button>
  );
}

// ─── CoinPackTile ───────────────────────────────────────────────────────────
// Two visual variants:
//   • 'tile' (default) — square bento cell used in Home Hub. Compact stats
//      stacked vertically with a small free-pack hint.
//   • 'hero' (v1.5, Shop module) — full-width horizontal hero pill used at
//      the top of the Shop screen. Larger balance number, inline "buy coins"
//      CTA on the inline-end side, and meta hints (free packs + level).
//      Localized strings still come from HH_I18N (canonical), but the Shop
//      screen passes overrides via `ctaLabel` / `freeHint` / `levelHint`
//      so SHOP_I18N keys can drive the page-specific copy.
function CoinPackTile({ locale = 'fa', coinBalance = HH_USER.coinBalance,
                        freePacks = 1, onCta,
                        // v1.5 hero variant additions
                        variant = 'tile', ctaLabel, freeHint, levelHint }) {
  const ll = HH_I18N[locale];
  if (variant === 'hero') {
    const showFree  = freePacks > 0 && (freeHint != null);
    const showLevel = levelHint != null;
    return (
      <div className="hh-coin-tile hh-coin-tile--hero">
        <div className="hh-coin-tile-glow" aria-hidden="true"></div>
        <div className="hh-coin-tile-hero-main">
          <header className="hh-coin-tile-head">
            <HHIcon name="coin" size={14}/>
            <span>{ll.coinTileTitle}</span>
          </header>
          <div className="hh-coin-tile-balance">
            <div className="hh-coin-tile-balance-num tabular-nums">
              {_toDigits(coinBalance.toLocaleString('en-US'), locale)}
            </div>
            <div className="hh-coin-tile-hero-meta">
              {showFree && (
                <span className="hh-coin-tile-hero-meta-item">
                  <HHIcon name="gift" size={11}/>
                  <span>{freeHint}</span>
                </span>
              )}
              {showLevel && (
                <span className="hh-coin-tile-hero-meta-item">
                  <HHIcon name="sparkle" size={11}/>
                  <span>{levelHint}</span>
                </span>
              )}
            </div>
          </div>
        </div>
        {onCta && (
          <button type="button" onClick={onCta} className="hh-coin-tile-hero-cta">
            <HHIcon name="plus" size={12}/>
            <span>{ctaLabel || ll.coinTilePackCta}</span>
          </button>
        )}
      </div>
    );
  }
  return (
    <button type="button" onClick={onCta} className="hh-coin-tile">
      <div className="hh-coin-tile-glow" aria-hidden="true"></div>
      <header className="hh-coin-tile-head">
        <HHIcon name="coin" size={13}/>
        <span>{ll.coinTileTitle}</span>
        <HHIcon name="chevron" size={14}/>
      </header>
      <div className="hh-coin-tile-balance">
        <div className="hh-coin-tile-balance-num tabular-nums">
          {_toDigits(coinBalance.toLocaleString('en-US'), locale)}
        </div>
        <div className="hh-coin-tile-balance-label">{ll.coinTileBalance}</div>
      </div>
      {freePacks > 0 && (
        <div className="hh-coin-tile-hint">
          <HHIcon name="gift" size={11}/>
          <span>{ll.coinTilePackHint(_toDigits(freePacks, locale))}</span>
        </div>
      )}
    </button>
  );
}

// ─── StatTile ──────────────────────────────────────────────────────────────
// Single stat tile. Modes: 'plain' | 'progress' | 'rank' | 'streak' | 'winrate'.
function StatTile({ locale = 'fa', mode = 'plain', icon, label, value, sub,
                    progress, accent = 'var(--accent-primary)', tone = 'glass', delta }) {
  const isUp = typeof delta === 'number' && delta > 0;
  const isDown = typeof delta === 'number' && delta < 0;
  return (
    <div className={`hh-stat hh-stat--${tone} hh-stat--${mode}`} style={{ '--stat-accent': accent }}>
      {icon && (
        <div className="hh-stat-icon" aria-hidden="true">
          <HHIcon name={icon} size={16}/>
        </div>
      )}
      <div className="hh-stat-body">
        <div className="hh-stat-value">
          <span className="tabular-nums">{value}</span>
          {typeof delta === 'number' && delta !== 0 && (
            <span className={`hh-stat-delta ${isUp ? 'is-up' : 'is-down'}`}>
              <span aria-hidden="true">{isUp ? '▲' : '▼'}</span>
              <span className="tabular-nums">{_toDigits(Math.abs(delta), locale)}</span>
            </span>
          )}
        </div>
        <div className="hh-stat-label">{label}</div>
        {sub && <div className="hh-stat-sub">{sub}</div>}
        {mode === 'progress' && typeof progress === 'number' && (
          <div className="hh-stat-bar" aria-hidden="true">
            <span style={{ width: `${Math.min(100, Math.max(0, progress * 100))}%` }}></span>
          </div>
        )}
      </div>
    </div>
  );
}

// ─── QuickActionCard ────────────────────────────────────────────────────────
// 3 modes:
//   • default  — horizontal row with icon + body + arrow (good in stacks)
//   • big      — vertical, icon top-left + body + bottom-right arrow
//   • tile     — bento-style square card: icon top, label centered,
//                sub at the bottom. Designed for narrow bento cells.
function QuickActionCard({ icon, label, sub, accent, onClick, locale,
                           big = false, tile = false, glyph }) {
  if (tile) {
    return (
      <button type="button" className="hh-qa-tile"
              style={{ '--qa-accent': accent || 'var(--accent-primary)' }}
              onClick={onClick}>
        <span className="hh-qa-tile-bg" aria-hidden="true"></span>
        <span className="hh-qa-tile-icon" aria-hidden="true">
          {glyph || <HHIcon name={icon} size={20}/>}
        </span>
        <span className="hh-qa-tile-label">{label}</span>
        {sub && <span className="hh-qa-tile-sub">{sub}</span>}
      </button>
    );
  }
  return (
    <button type="button" className={`hh-qa ${big ? 'hh-qa--big' : ''}`}
            style={{ '--qa-accent': accent || 'var(--accent-primary)' }}
            onClick={onClick}>
      <span className="hh-qa-bg" aria-hidden="true"></span>
      <span className="hh-qa-icon" aria-hidden="true">
        {glyph || <HHIcon name={icon} size={big ? 28 : 22}/>}
      </span>
      <span className="hh-qa-body">
        <span className="hh-qa-label">{label}</span>
        {sub && <span className="hh-qa-sub">{sub}</span>}
      </span>
      <span className="hh-qa-arrow" aria-hidden="true">
        <HHIcon name="chevron" size={14}/>
      </span>
    </button>
  );
}

// ─── FeaturedRail ───────────────────────────────────────────────────────────
// Horizontal carousel of compact PlayerCards from window.PlayerCard.
function FeaturedRail({ locale = 'fa', items, onPick }) {
  const ll = HH_I18N[locale];
  return (
    <div className="hh-rail">
      <div className="hh-rail-track" role="list">
        {items.map((it, idx) => (
          <div key={idx} className="hh-rail-item" role="listitem">
            <FeaturedCardWrap item={it} locale={locale} onPick={onPick}/>
          </div>
        ))}
      </div>
    </div>
  );
}

function FeaturedCardWrap({ item, locale, onPick }) {
  const ll = HH_I18N[locale];
  const PC = window.PlayerCard;
  if (!PC) return <div className="hh-rail-fallback">PlayerCard not loaded</div>;

  const badgeText = item.badge === 'new' ? ll.badgeNew
                  : item.badge === 'bonus' ? ll.badgeBonus
                  : item.badge === 'rare' ? ll.badgeRare
                  : item.badge === 'mission' ? ll.badgeMission
                  : null;
  const badgeAccent = item.badge === 'new' ? 'var(--success)'
                    : item.badge === 'bonus' ? 'var(--accent-primary)'
                    : item.badge === 'rare' ? 'var(--tier-platinum)'
                    : item.badge === 'mission' ? 'var(--warning)'
                    : 'var(--text-secondary)';

  // Resolve locale-aware name/team — handle both string and {fa,en,ar} shapes.
  const _resolve = (v) => {
    if (v == null) return '';
    if (typeof v === 'string') return v;
    return v[locale] || v.fa || v.en || '';
  };

  // Build PlayerCard props
  const pcProps = {
    tier: item.tier,
    locale,
    position: item.position,
    overall: item.overall,
    statKey: item.statKey || 'mid',
    statValue: item.statValue || item.overall - 1,
    playerName: _resolve(item.playerName),
    teamName:   _resolve(item.teamName),
    playerImage: item.image,
    size: 'compact',
    onDetails: () => onPick && onPick(item),
  };

  return (
    <div className="hh-rail-card">
      {badgeText && (
        <div className={`mc-grid-card-ribbons hh-rail-ribbons`}>
          <div className={`mc-ribbon mc-ribbon--${item.badge === 'new' ? 'new' : item.badge === 'bonus' ? 'bonus' : item.badge === 'rare' ? 'rare' : 'mission'}`}>
            {badgeText}
          </div>
        </div>
      )}
      <div className="hh-rail-card-clip">
        <PC {...pcProps}/>
      </div>
    </div>
  );
}

// ─── GoldenMissionCard ─────────────────────────────────────────────────────
function GoldenMissionCard({ locale = 'fa', mission = HH_MISSIONS.golden, onView, onPack }) {
  const ll = HH_I18N[locale];
  const pct = mission.have / mission.total;
  const timer = `${_toDigits(String(mission.hours).padStart(2,'0'), locale)}:`
              + `${_toDigits(String(mission.minutes).padStart(2,'0'), locale)}:`
              + `${_toDigits(String(mission.seconds).padStart(2,'0'), locale)}`;

  return (
    <article className="hh-mission hh-mission--golden">
      <div className="hh-mission-bg" aria-hidden="true"></div>
      <header className="hh-mission-head">
        <div className="hh-mission-tag">
          <HHIcon name="trophy" size={12}/>
          <span>{ll.missionsGoldenTag}</span>
        </div>
        <div className="hh-mission-reward tabular-nums">
          +{_toDigits(mission.rewardXP.toLocaleString('en-US'), locale)} XP
        </div>
      </header>
      <h3 className="hh-mission-title">{mission.title[locale]}</h3>
      <p className="hh-mission-desc">{mission.desc[locale]}</p>

      {/* Mini-card row */}
      <div className="hh-mission-cards" aria-hidden="true">
        {mission.slots.map((s, i) => (
          <div key={i} className={`hh-mission-mcard hh-mission-mcard--${s.state}`}
               style={{ '--mc-tier': `var(--tier-${s.tier})` }}>
            {s.state === 'owned' ? <HHIcon name="check" size={14}/> : <HHIcon name="plus" size={14}/>}
          </div>
        ))}
      </div>

      {/* Progress + timer */}
      <div className="hh-mission-meta">
        <div className="hh-mission-progress">
          <div className="hh-mission-progress-bar">
            <span style={{ width: `${pct * 100}%` }}></span>
          </div>
          <div className="hh-mission-progress-text">
            {ll.missionsGoldenProgress(_toDigits(mission.have, locale), _toDigits(mission.total, locale))}
          </div>
        </div>
        <div className="hh-mission-timer">
          <HHIcon name="clock" size={12}/>
          <span className="tabular-nums">{timer}</span>
        </div>
      </div>

      <footer className="hh-mission-actions">
        <button type="button" className="hh-btn hh-btn--primary" onClick={onView}>{ll.missionsGoldenCta}</button>
        <button type="button" className="hh-btn hh-btn--ghost" onClick={onPack}>{ll.missionsGoldenCta2}</button>
      </footer>
    </article>
  );
}

// ─── DailyMissionRow ───────────────────────────────────────────────────────
function DailyMissionRow({ locale = 'fa', mission }) {
  const ll = HH_I18N[locale];
  const sp = mission.sponsored ? HH_SPONSORS[mission.sponsored] : null;
  const pct = mission.progress / mission.total;

  return (
    <div className={`hh-drow ${sp ? 'hh-drow--sponsored' : ''}`}
         style={sp ? { '--drow-accent': sp.accent } : null}>
      {sp && (
        <div className="hh-drow-spbar" aria-hidden="true">
          <span className="hh-drow-spbar-shine"></span>
        </div>
      )}
      <div className="hh-drow-icon" aria-hidden="true">
        {sp ? <span className="hh-drow-sp-mark">{sp.brand[locale].slice(0, 1)}</span>
            : <HHIcon name="check" size={16}/>}
      </div>
      <div className="hh-drow-body">
        <div className="hh-drow-titles">
          {sp && <div className="hh-drow-sp-tag">{ll.sponsorMissionTag}</div>}
          <div className="hh-drow-title">{mission.title[locale]}</div>
        </div>
        <div className="hh-drow-bar">
          <span style={{ width: `${pct * 100}%` }}></span>
        </div>
      </div>
      <div className="hh-drow-end">
        <div className="hh-drow-progress tabular-nums">
          {_toDigits(mission.progress, locale)} / {_toDigits(mission.total, locale)}
        </div>
        <div className="hh-drow-reward">{mission.reward[locale]}</div>
      </div>
    </div>
  );
}

// ─── PackCallout ───────────────────────────────────────────────────────────
function PackCallout({ locale = 'fa', onCta, compact = false }) {
  const ll = HH_I18N[locale];
  return (
    <article className={`hh-pack ${compact ? 'hh-pack--compact' : ''}`}>
      <div className="hh-pack-bg" aria-hidden="true"></div>
      <div className="hh-pack-mark" aria-hidden="true">
        <div className="hh-pack-spine"></div>
        <div className="hh-pack-face">
          <HHIcon name="gift" size={28}/>
        </div>
        <div className="hh-pack-shine"></div>
      </div>
      <div className="hh-pack-body">
        <div className="hh-pack-tag">
          <HHIcon name="sparkle" size={11}/>
          <span>{ll.packTitle}</span>
        </div>
        <div className="hh-pack-sub">{ll.packSub}</div>
        <div className="hh-pack-price">
          <span className="hh-pack-price-now tabular-nums">{ll.packPrice}</span>
          <span className="hh-pack-price-was tabular-nums">{_toDigits(ll.packPriceWas, locale)}</span>
        </div>
      </div>
      <button type="button" className="hh-pack-cta" onClick={onCta}>
        <span>{ll.packCta}</span>
        <HHIcon name="chevron" size={14}/>
      </button>
    </article>
  );
}

// ─── SponsorMiniGrid — compact 3-up sponsor row for desktop bento ──────────
// Renders a small grid/stack of sponsor "ad slots" with brand, tagline,
// and accent border. Layout: `cols` controls columns (default 1 = stacked).
function SponsorMiniGrid({ locale = 'fa', sponsorIds = ['mci', 'blu', 'mili'],
                           cols = 1, onPick }) {
  const ll = HH_I18N[locale];
  const list = sponsorIds.map((id) => ({ id, ...HH_SPONSORS[id] })).filter(Boolean);
  return (
    <div className={`hh-sponsor-grid hh-sponsor-grid--cols-${cols}`}>
      <div className="hh-sponsor-grid-head">
        <span className="hh-sponsor-grid-eyebrow">
          {locale === 'fa' ? 'حامیان رختکن'
            : locale === 'ar' ? 'الرعاة' : 'Our sponsors'}
        </span>
      </div>
      <div className="hh-sponsor-grid-track">
        {list.map((sp) => (
          <button key={sp.id} type="button" className="hh-sponsor-mini"
                  style={{ '--sp-accent': sp.accent }}
                  onClick={() => onPick && onPick(sp.id)}>
            <span className="hh-sponsor-mini-mark" aria-hidden="true">
              {/* short text mark — first letter of localized brand */}
              <span>{sp.brand[locale].trim().charAt(0)}</span>
            </span>
            <span className="hh-sponsor-mini-body">
              <span className="hh-sponsor-mini-brand">{sp.brand[locale]}</span>
              <span className="hh-sponsor-mini-tagline">{sp.tagline[locale]}</span>
            </span>
            <HHIcon name="chevron" size={12}/>
          </button>
        ))}
      </div>
    </div>
  );
}

// ─── SponsorSkyscraper — uses MyCards SponsorBlock if available ────────────
function SponsorSkyscraper({ locale = 'fa', sponsorId = 'mili' }) {
  const SB = window.SponsorBlock;
  if (SB) {
    return (
      <div className="hh-sponsor-wrap">
        <SB locale={locale} sponsorId={sponsorId}/>
      </div>
    );
  }
  // Fallback if MyCards pieces not loaded
  const sp = HH_SPONSORS[sponsorId];
  const ll = HH_I18N[locale];
  return (
    <div className="hh-sponsor-fallback">
      <div className="hh-sponsor-eyebrow">{sp.tag[locale]}</div>
      <div className="hh-sponsor-name">{sp.brand[locale]}</div>
      <div className="hh-sponsor-tagline">{sp.tagline[locale]}</div>
    </div>
  );
}

// ─── EmptyState (new-user) ─────────────────────────────────────────────────
// Canonical empty state per §13 of the Design Log. Used in lobby/list pages
// when there is nothing to show. Defaults use `HH_I18N[locale]` ("welcome to
// the locker") but every label can be overridden so other pages can host it
// without needing to extend HH_I18N. Optional secondary CTA was added in v1.3
// (Prediction Hub refactor) so the Prediction empty state can share this
// primitive: primary = "see upcoming", secondary = "notify me".
function HHEmptyState({
  locale = 'fa',
  // Optional content overrides — fall back to HH_I18N when unset.
  title, body, ctaLabel, ctaIcon = 'gift', glyphIcon = 'gift',
  onCta,
  // Optional secondary CTA (e.g. "اعلان فعال شدن بازی")
  secondaryCtaLabel, secondaryCtaIcon, onSecondaryCta,
}) {
  const ll = HH_I18N[locale];
  const eTitle = title ?? ll.emptyTitle;
  const eBody  = body  ?? ll.emptyBody;
  const eCta   = ctaLabel ?? ll.emptyCta;
  return (
    <div className="hh-empty">
      <div className="hh-empty-art" aria-hidden="true">
        <div className="hh-empty-pack">
          <HHIcon name={glyphIcon} size={40}/>
        </div>
        <div className="hh-empty-orb hh-empty-orb-a"></div>
        <div className="hh-empty-orb hh-empty-orb-b"></div>
      </div>
      <h2 className="hh-empty-title">{eTitle}</h2>
      <p className="hh-empty-body">{eBody}</p>
      <div className="hh-empty-ctas">
        <button type="button" className="hh-btn hh-btn--primary hh-btn--lg" onClick={onCta}>
          {ctaIcon && <HHIcon name={ctaIcon} size={14}/>}
          <span>{eCta}</span>
        </button>
        {secondaryCtaLabel && (
          <button type="button" className="hh-btn hh-btn--ghost hh-btn--lg" onClick={onSecondaryCta}>
            {secondaryCtaIcon && <HHIcon name={secondaryCtaIcon} size={14}/>}
            <span>{secondaryCtaLabel}</span>
          </button>
        )}
      </div>
    </div>
  );
}

// ─── TeamCrest — canonical 3-letter brand-tinted crest (v1.3) ──────────────
// Extracted from Prediction Hub (was PRTeamCrest) and HomeHub's
// PredictionMatchCard inline crest, per Design Log §14.1 row 6. Single
// implementation across all surfaces:
//   • PredictionMatchCard (Home Hub slider)
//   • PredictionMatchRow / PredictionMatchSheet (Prediction Hub)
//   • Lineup match callouts (future)
//
// Props:
//   team   — { code: 'PER', name: {…}, color: '#hex' }
//   size   — pixel diameter (default 36; row=28–36, featured=56, header=40)
//   layout — 'inline' (default) | 'featured' — used to scope CSS variants
//   dim    — boolean — used for settled/locked states (lower opacity)
function TeamCrest({ team, size = 36, layout = 'inline', dim = false }) {
  if (!team) return null;
  const isLight = (team.color || '').toLowerCase() === '#ffffff'
               || (team.color || '').toLowerCase() === '#fff';
  return (
    <div className={`hh-crest hh-crest--${layout} ${dim ? 'is-dim' : ''}`}
         style={{
           width: size, height: size,
           background: `linear-gradient(155deg, ${team.color} 0%, rgba(0,0,0,0.6) 100%)`,
           color: isLight ? '#0E0E16' : 'rgba(255,255,255,0.95)',
         }}
         aria-hidden="true">
      <span className="hh-crest-code" style={{ fontSize: Math.max(10, Math.round(size * 0.32)) }}>
        {team.code}
      </span>
    </div>
  );
}

// ─── SectionHead — small caption block above a section ─────────────────────
function SectionHead({ title, sub, action }) {
  return (
    <div className="hh-section-head">
      <div className="hh-section-titles">
        <div className="hh-section-title">{title}</div>
        {sub && <div className="hh-section-sub">{sub}</div>}
      </div>
      {action && (
        <button type="button" className="hh-section-action">
          <span>{action}</span>
          <HHIcon name="chevron" size={12}/>
        </button>
      )}
    </div>
  );
}

// ─── Scroll-aware bottom-nav controller ────────────────────────────────────
// Custom hook: returns `shrunk` boolean for a scroll container ref.
function useScrollShrink(ref, threshold = 60) {
  const [shrunk, setShrunk] = React.useState(false);
  const lastY = React.useRef(0);
  React.useEffect(() => {
    const el = ref && ref.current;
    if (!el) return;
    const onScroll = () => {
      const y = el.scrollTop;
      const dy = y - lastY.current;
      lastY.current = y;
      if (y < 20) setShrunk(false);
      else if (dy > 6) setShrunk(true);
      else if (dy < -6) setShrunk(false);
    };
    el.addEventListener('scroll', onScroll, { passive: true });
    return () => el.removeEventListener('scroll', onScroll);
  }, [ref, threshold]);
  return shrunk;
}

// ─── Export ────────────────────────────────────────────────────────────────
Object.assign(window, {
  HHIcon, AppBar, DesktopTopbar, BottomNav,
  PredictionSlider, PredictionMatchCard, SubmitStatusTile, CoinPackTile,
  StatTile, QuickActionCard, FeaturedRail, FeaturedCardWrap,
  GoldenMissionCard, DailyMissionRow, PackCallout, SponsorSkyscraper,
  SponsorMiniGrid,
  HHEmptyState, SectionHead, TeamCrest, useScrollShrink,
});
