/* ============================================================ INDIC LEAGUE NEWS — Card Stack with full swipe physics - Axis lock on first 6px (h vs v) - Drag transform = translate(dx,0) rotate(dx*0.065deg) - Threshold |dx| > 90 → fly-off; below → spring snap-back - Left swipe = next; Right swipe = previous (per plan F06) - tappedFab flag prevents FAB taps from triggering tap-to-open - Web Audio sounds + Vibration haptics on transitions ============================================================ */ function ArticleCard({ article, isActive, onTapBody, onTapShare, onTapLike, onTapSave, onTapSkip, liked, saved, cardRef, onPointerDown }) { // FABs need to NOT propagate as drag/tap. We set a marker on the card body. const fabClick = (e, fn) => { e.stopPropagation(); fn && fn(); }; return (
{article.badge}
{article.publishedAt}
{article.category} {article.politicalConfidence >= 0.4 && ( {article.politicalLabel} )}

{article.headline}

{article.summary}

{article.authorAvatar ? : article.author.split(' ').map(w => w[0]).join('').slice(0, 2)}
By {article.author}
); } function GhostCard({ offset = 1, tint = 'peach' }) { const transform = `translateY(${offset * 8}px) scale(${1 - offset * 0.035}) rotate(${offset === 1 ? -2.4 : 2.4}deg)`; return (