// TownPost shared UI components — used across all screens

// ─── Tab bar context — lets the App pick a variant globally without
// having to thread `variant` through every screen call site.
const TPTabBarContext = React.createContext({ variant: 'classic', onAction: () => {} });

// Detect iOS frame ancestor (for home-indicator clearance)
function useIsIOSFrame(ref) {
  const [isIOS, setIsIOS] = React.useState(false);
  React.useEffect(() => {
    if (!ref.current) return;
    let el = ref.current.parentElement;
    while (el) {
      const cls = (el.className || '') + '';
      if (cls.indexOf('ios') !== -1 || el.dataset?.frame === 'ios') { setIsIOS(true); return; }
      el = el.parentElement;
    }
  }, []);
  return isIOS;
}

// Smart icon picker for tabs — uses the animated TPRadarIcon for the radar tab
// when it's active so the icon "scans" while you're on the screen. Falls back
// to standard TPIcon for everything else.
function TPTabIcon({ icon, size = 22, stroke = 1.6, active, color, tint }) {
  if (icon === 'tabAlerts' && active) {
    return <TPRadarIcon size={size} stroke={stroke} color={color} scanning={true} />;
  }
  return <TPIcon name={icon} size={size} stroke={stroke} filled={active} color={color} tint={tint} />;
}

// Single source of tab definitions per variant. Variants can rearrange / drop tabs.
const TP_TAB_DEFS = {
  // 5-tab classic order
  classic: [
    { id: 'home', icon: 'tabHome', label: 'Home' },
    { id: 'feed', icon: 'tabFeed', label: 'Feed' },
    { id: 'alerts', icon: 'tabAlerts', label: 'Radar', badge: 3 },
    { id: 'market', icon: 'tabMarket', label: 'Market' },
    { id: 'more', icon: 'tabMore', label: 'More' },
  ],
  // 4 tabs + center compose FAB (compose pushed to a separate action button)
  compose: [
    { id: 'home', icon: 'tabHome', label: 'Home' },
    { id: 'feed', icon: 'tabFeed', label: 'Feed' },
    { id: 'alerts', icon: 'tabAlerts', label: 'Radar', badge: 3 },
    { id: 'more', icon: 'tabMore', label: 'More' },
  ],
  // Map-promoted: Market → More (overflow), Map takes prime center seat
  mapFirst: [
    { id: 'home', icon: 'tabHome', label: 'Home' },
    { id: 'feed', icon: 'tabFeed', label: 'Feed' },
    { id: 'map', icon: 'tabMap', label: 'Map' },
    { id: 'alerts', icon: 'tabAlerts', label: 'Radar', badge: 3 },
    { id: 'more', icon: 'tabMore', label: 'More' },
  ],
};

// ─── Tab bar — dispatches to the chosen variant ─────────────────────────
function TPTabBar({ active = 'home', onChange = () => {}, variant: variantProp, onAction }) {
  const ctx = React.useContext(TPTabBarContext);
  const variant = variantProp || ctx.variant || 'classic';
  const action = onAction || ctx.onAction || (() => {});
  const Cmp = (
    variant === 'pill'      ? TabBarPill :
    variant === 'compose'   ? TabBarCompose :
    variant === 'editorial' ? TabBarEditorial :
    variant === 'mapFirst'  ? TabBarMapFirst :
    TabBarClassic
  );
  return <Cmp active={active} onChange={onChange} onAction={action} />;
}

// ════════════════════════════════════════════════════════════════════════════
// Variant A — Classic (the original): chip + tiny top indicator + label
// ════════════════════════════════════════════════════════════════════════════
function TabBarClassic({ active, onChange }) {
  const tabs = TP_TAB_DEFS.classic;
  const ref = React.useRef(null);
  const isIOS = useIsIOSFrame(ref);
  return (
    <div ref={ref} style={{
      background: 'linear-gradient(to bottom, rgba(251,247,240,0.96), rgba(251,247,240,1))',
      backdropFilter: 'saturate(1.1)',
      borderTop: `1px solid ${TP.hairline}`,
      padding: isIOS ? '8px 6px 26px' : '8px 6px 10px',
      display: 'flex', alignItems: 'stretch', justifyContent: 'space-between',
      gap: 2,
    }}>
      {tabs.map(t => {
        const isA = t.id === active;
        return (
          <button key={t.id} onClick={() => onChange(t.id)} style={{
            flex: 1, background: 'none', border: 'none', cursor: 'pointer',
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 2,
            padding: '4px 0 2px', fontFamily: TP.sans, fontSize: 10,
            fontWeight: isA ? 600 : 500, letterSpacing: 0.2,
            color: isA ? TP.forest : TP.mutedSoft, position: 'relative',
            transition: 'color 200ms ease',
            minWidth: 0,
          }}>
            <div style={{
              position: 'relative', height: 30, minWidth: 0, maxWidth: '100%',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              padding: '0 8px', borderRadius: 999,
              background: isA ? 'rgba(45, 80, 22, 0.10)' : 'transparent',
              transform: isA ? 'translateY(-1px)' : 'translateY(0)',
              transition: 'background 220ms ease, transform 220ms cubic-bezier(.2,.7,.2,1)',
            }}>
              <TPTabIcon icon={t.icon} size={22} stroke={1.6} active={isA} color={isA ? TP.forest : TP.muted} tint={isA ? 'rgba(45,80,22,0.18)' : undefined} />
              {t.badge && <TabBadge n={t.badge} />}
            </div>
            <span style={{ marginTop: 1 }}>{t.label}</span>
          </button>
        );
      })}
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// Variant B — Floating Pill: capsule that hovers above the home indicator
// Icon-only at rest; active tab expands and reveals its label inline.
// ════════════════════════════════════════════════════════════════════════════
function TabBarPill({ active, onChange }) {
  const tabs = TP_TAB_DEFS.classic;
  const ref = React.useRef(null);
  const isIOS = useIsIOSFrame(ref);
  return (
    <div ref={ref} style={{
      background: 'transparent',
      padding: isIOS ? '8px 16px 22px' : '8px 16px 12px',
      display: 'flex', justifyContent: 'center',
    }}>
      <div style={{
        background: 'rgba(251,247,240,0.78)',
        backdropFilter: 'saturate(1.2) blur(14px)',
        WebkitBackdropFilter: 'saturate(1.2) blur(14px)',
        border: `1px solid ${TP.hairlineStrong}`,
        borderRadius: 999,
        padding: 5,
        display: 'flex', alignItems: 'center', gap: 2,
        boxShadow: '0 8px 24px rgba(31,27,22,0.10), 0 1px 0 rgba(255,255,255,0.6) inset',
      }}>
        {tabs.map(t => {
          const isA = t.id === active;
          return (
            <button key={t.id} onClick={() => onChange(t.id)} style={{
              background: isA ? TP.forest : 'transparent',
              border: 'none', cursor: 'pointer',
              height: 38, padding: isA ? '0 14px 0 11px' : '0 11px',
              borderRadius: 999,
              display: 'flex', alignItems: 'center', gap: 7,
              color: isA ? TP.cream : TP.muted,
              fontFamily: TP.sans, fontSize: 12.5, fontWeight: 600, letterSpacing: 0.1,
              transition: 'all 200ms cubic-bezier(.2,.7,.2,1)',
              position: 'relative',
            }}>
              <span style={{ display: 'inline-flex', position: 'relative' }}>
                <TPTabIcon icon={t.icon} size={20} stroke={1.6} active={isA} color={isA ? TP.cream : TP.muted} tint={isA ? 'rgba(251,247,240,0.18)' : undefined} />
                {t.badge && !isA && <TabBadge n={t.badge} />}
              </span>
              {isA && <span style={{ whiteSpace: 'nowrap' }}>{t.label}</span>}
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// Variant C — Compose-First (4 + 1): the post button is the hero.
// Center FAB notches into a flat bar. Tapping it triggers onAction('compose').
// ════════════════════════════════════════════════════════════════════════════
function TabBarCompose({ active, onChange, onAction }) {
  const tabs = TP_TAB_DEFS.compose;
  const ref = React.useRef(null);
  const isIOS = useIsIOSFrame(ref);
  // 2 tabs left, FAB, 2 tabs right
  const left = tabs.slice(0, 2);
  const right = tabs.slice(2);
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      {/* FAB hovering above */}
      <button
        onClick={() => onAction('compose')}
        aria-label="New post"
        style={{
          position: 'absolute', top: -22, left: '50%', transform: 'translateX(-50%)',
          width: 56, height: 56, borderRadius: '50%',
          background: TP.forest, border: `3px solid ${TP.paper}`, cursor: 'pointer',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          color: TP.cream, zIndex: 5,
          boxShadow: '0 10px 22px rgba(45,80,22,0.32), 0 2px 4px rgba(0,0,0,0.08)',
          transition: 'transform 140ms ease',
        }}
        onMouseDown={(e) => e.currentTarget.style.transform = 'translateX(-50%) scale(0.94)'}
        onMouseUp={(e) => e.currentTarget.style.transform = 'translateX(-50%)'}
        onMouseLeave={(e) => e.currentTarget.style.transform = 'translateX(-50%)'}
      >
        <TPIcon name="plus" size={26} stroke={2.4} color={TP.cream} />
      </button>
      <div style={{
        background: TP.paper,
        borderTop: `1px solid ${TP.hairline}`,
        padding: isIOS ? '8px 8px 26px' : '8px 8px 10px',
        display: 'grid',
        gridTemplateColumns: '1fr 1fr 72px 1fr 1fr',
        alignItems: 'stretch',
      }}>
        {left.map(t => <ComposeTabBtn key={t.id} t={t} active={active} onChange={onChange} />)}
        <div /> {/* spacer for FAB */}
        {right.map(t => <ComposeTabBtn key={t.id} t={t} active={active} onChange={onChange} />)}
      </div>
    </div>
  );
}
function ComposeTabBtn({ t, active, onChange }) {
  const isA = t.id === active;
  return (
    <button onClick={() => onChange(t.id)} style={{
      background: 'none', border: 'none', cursor: 'pointer',
      display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4,
      padding: '4px 0', fontFamily: TP.sans, fontSize: 10,
      fontWeight: isA ? 700 : 500, letterSpacing: 0.3, textTransform: 'uppercase',
      color: isA ? TP.forest : TP.mutedSoft,
    }}>
      <div style={{ position: 'relative', height: 24, display: 'flex', alignItems: 'center' }}>
        <TPTabIcon icon={t.icon} size={22} stroke={1.6} active={isA} color={isA ? TP.forest : TP.muted} tint={isA ? 'rgba(45,80,22,0.16)' : undefined} />
        {t.badge && <TabBadge n={t.badge} />}
      </div>
      <span>{t.label}</span>
    </button>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// Variant D — Editorial Underline: text-forward, no chips. A single forest
// underline travels between labels. Reads like a newspaper masthead.
// ════════════════════════════════════════════════════════════════════════════
function TabBarEditorial({ active, onChange }) {
  const tabs = TP_TAB_DEFS.classic;
  const ref = React.useRef(null);
  const wrapRef = React.useRef(null);
  const isIOS = useIsIOSFrame(ref);
  const [bar, setBar] = React.useState({ left: 0, width: 0 });

  React.useLayoutEffect(() => {
    if (!wrapRef.current) return;
    const el = wrapRef.current.querySelector(`[data-tab="${active}"]`);
    if (!el) return;
    const wrapBox = wrapRef.current.getBoundingClientRect();
    const elBox = el.getBoundingClientRect();
    setBar({ left: elBox.left - wrapBox.left, width: elBox.width });
  }, [active]);

  return (
    <div ref={ref} style={{
      background: TP.paper,
      borderTop: `1px solid ${TP.hairline}`,
      padding: isIOS ? '4px 0 24px' : '4px 0 8px',
    }}>
      <div ref={wrapRef} style={{ position: 'relative', display: 'flex', alignItems: 'stretch' }}>
        {tabs.map(t => {
          const isA = t.id === active;
          return (
            <button key={t.id} data-tab={t.id} onClick={() => onChange(t.id)} style={{
              flex: 1, background: 'none', border: 'none', cursor: 'pointer',
              padding: '12px 0 14px',
              display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6,
              fontFamily: TP.serif, fontSize: 16, fontStyle: 'italic',
              color: isA ? TP.ink : TP.mutedSoft,
              letterSpacing: -0.2,
              transition: 'color 180ms ease',
              position: 'relative',
            }}>
              <span style={{ position: 'relative', display: 'inline-flex' }}>
                {t.label}
                {t.badge && (
                  <span style={{
                    position: 'absolute', top: -3, right: -10,
                    width: 6, height: 6, borderRadius: '50%', background: TP.alertRed,
                  }} />
                )}
              </span>
            </button>
          );
        })}
        {/* Animated underline */}
        <div style={{
          position: 'absolute', bottom: 0, height: 2, background: TP.forest,
          left: bar.left, width: bar.width,
          transition: 'left 280ms cubic-bezier(.2,.7,.2,1), width 280ms cubic-bezier(.2,.7,.2,1)',
          borderRadius: 2,
        }} />
      </div>
    </div>
  );
}

// ════════════════════════════════════════════════════════════════════════════
// Variant E — Map-First: hyper-local apps live on the map. Center seat
// gets a slightly elevated dome with the map glyph; market is demoted to More.
// ════════════════════════════════════════════════════════════════════════════
function TabBarMapFirst({ active, onChange }) {
  const tabs = TP_TAB_DEFS.mapFirst;
  const ref = React.useRef(null);
  const isIOS = useIsIOSFrame(ref);
  return (
    <div ref={ref} style={{
      background: TP.paper,
      borderTop: `1px solid ${TP.hairline}`,
      padding: isIOS ? '4px 6px 24px' : '4px 6px 8px',
      display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between',
    }}>
      {tabs.map(t => {
        const isA = t.id === active;
        const isCenter = t.id === 'map';
        if (isCenter) {
          return (
            <button key={t.id} onClick={() => onChange(t.id)} style={{
              flex: 1, background: 'none', border: 'none', cursor: 'pointer',
              display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3,
              padding: '0 0 4px', fontFamily: TP.sans, fontSize: 10.5,
              fontWeight: isA ? 700 : 600, letterSpacing: 0.2,
              color: isA ? TP.forest : TP.ink,
              position: 'relative',
            }}>
              <div style={{
                width: 52, height: 52, borderRadius: '50%',
                background: isA ? TP.forest : TP.cream,
                border: `1.5px solid ${isA ? TP.forest : TP.hairlineStrong}`,
                marginTop: -18, marginBottom: 2,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                boxShadow: isA
                  ? '0 8px 18px rgba(45,80,22,0.28)'
                  : '0 4px 12px rgba(31,27,22,0.10)',
                transition: 'all 180ms ease',
              }}>
                <TPIcon name="tabMap" size={26} stroke={2} color={isA ? TP.cream : TP.forest} />
              </div>
              <span>Nearby</span>
            </button>
          );
        }
        return (
          <button key={t.id} onClick={() => onChange(t.id)} style={{
            flex: 1, background: 'none', border: 'none', cursor: 'pointer',
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3,
            padding: '8px 0 4px', fontFamily: TP.sans, fontSize: 10.5,
            fontWeight: isA ? 600 : 500, letterSpacing: 0.1,
            color: isA ? TP.forest : TP.muted, position: 'relative',
          }}>
            <div style={{
              position: 'relative', height: 28, minWidth: 44,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <TPTabIcon icon={t.icon} size={22} stroke={1.6} active={isA} color={isA ? TP.forest : TP.muted} tint={isA ? 'rgba(45,80,22,0.16)' : undefined} />
              {t.badge && <TabBadge n={t.badge} />}
              {isA && <div style={{
                position: 'absolute', bottom: -2, width: 4, height: 4, borderRadius: '50%', background: TP.forest,
              }} />}
            </div>
            <span>{t.label}</span>
          </button>
        );
      })}
    </div>
  );
}

// ─── Tiny shared notification badge ───────────────────────────────────────
function TabBadge({ n }) {
  return (
    <div style={{
      position: 'absolute', top: -2, right: -4,
      background: TP.alertRed, color: '#fff',
      fontSize: 9, fontWeight: 700, lineHeight: 1,
      minWidth: 14, height: 14, padding: '0 4px',
      borderRadius: 8, boxSizing: 'border-box',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      border: `1.5px solid ${TP.paper}`,
      fontFamily: 'Geist, system-ui, sans-serif',
    }}>{n}</div>
  );
}

// ─── Header bar (Home/Feed top) ──────────────────────────
function TPTopBar({ title, subtitle, leading, trailing }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 10,
      padding: '12px 16px 12px', background: TP.paper,
      borderBottom: `1px solid ${TP.hairline}`,
    }}>
      {leading}
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          fontFamily: TP.serif, fontSize: 24, color: TP.ink,
          lineHeight: 1, letterSpacing: -0.3,
        }}>{title}</div>
        {subtitle && (
          <div style={{
            fontFamily: TP.sans, fontSize: 11, color: TP.muted,
            marginTop: 3, letterSpacing: 0.2, textTransform: 'uppercase',
            fontWeight: 600,
          }}>{subtitle}</div>
        )}
      </div>
      {trailing}
    </div>
  );
}

// ─── Rich text — styles #hashtags, @mentions, and {location} tokens ──
function TPRichText({ text, style }) {
  if (!text) return null;
  // Split on hashtags, @mentions, location markers (here we treat any @Word as mention,
  // any #Word as hashtag, and we don't have explicit location tokens — but we accept
  // them as "@Place" via convention for simplicity).
  const parts = String(text).split(/(\s+)/);
  return (
    <span style={style}>
      {parts.map((p, i) => {
        if (/^#[A-Za-z0-9_]+$/.test(p)) {
          return <span key={i} style={{ color: TP.forest, fontWeight: 600, cursor: 'pointer' }}>{p}</span>;
        }
        if (/^@[A-Za-z0-9_]+$/.test(p)) {
          return <span key={i} style={{ color: TP.terracotta, fontWeight: 600, cursor: 'pointer' }}>{p}</span>;
        }
        return <span key={i}>{p}</span>;
      })}
    </span>
  );
}

// ─── Author rating block — star + score + helpful count ──────────
function TPAuthorRating({ rating, helpful, verified, compact = false }) {
  if (!rating) return null;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 3,
      fontFamily: TP.mono, fontSize: compact ? 10.5 : 11,
      color: TP.inkSoft, fontWeight: 600, letterSpacing: 0.2,
    }}>
      <span style={{ color: TP.ochre, fontSize: compact ? 11 : 11.5, lineHeight: 1 }}>★</span>
      {rating.toFixed(1)}
      {helpful != null && (
        <>
          <span style={{ color: TP.mutedSoft, margin: '0 1px' }}>·</span>
          <span>{helpful >= 1000 ? `${(helpful / 1000).toFixed(1)}k` : helpful} helpful</span>
        </>
      )}
      {verified && (
        <span style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 12, height: 12, borderRadius: '50%', background: TP.forest, marginLeft: 2 }}>
          <TPIcon name="check" size={7} color="#fff" stroke={3.5} />
        </span>
      )}
    </span>
  );
}

// ─── Trending badge — small mono label with flame ──────────────────
function TPTrendingBadge({ size = 'sm', compact = false }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: compact ? 0 : 3,
      padding: compact ? '4px 6px' : (size === 'sm' ? '2px 7px' : '3px 9px'),
      borderRadius: 999,
      background: TP.terracotta + '14',
      color: TP.terracotta,
      fontFamily: TP.mono, fontSize: size === 'sm' ? 9.5 : 10.5,
      fontWeight: 700, letterSpacing: 0.8, textTransform: 'uppercase',
      lineHeight: 1, flexShrink: 0,
    }}>
      <TPIcon name="fire" size={compact ? 11 : (size === 'sm' ? 9 : 10)} color={TP.terracotta} stroke={2.4} />
      {!compact && 'Trending'}
    </span>
  );
}

// ─── Compact (X-style) post ──────────────────────────
function TPPostCompact({ post, onTap }) {
  return (
    <div onClick={onTap} style={{
      display: 'flex', gap: 12, padding: '14px 16px',
      borderBottom: `1px solid ${TP.hairline}`,
      cursor: 'pointer', background: TP.paper,
    }}>
      <TPAvatar name={post.author} hue={post.hue} size={40} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 5, marginBottom: 2 }}>
          <span style={{ fontFamily: TP.sans, fontWeight: 600, fontSize: 14, color: TP.ink, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{post.author}</span>
          {post.verified && (
            <span style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 13, height: 13, borderRadius: '50%', background: TP.forest, flexShrink: 0 }}>
              <TPIcon name="check" size={7.5} color="#fff" stroke={3.5} />
            </span>
          )}
          {post.rating && (
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 2, fontFamily: TP.mono, fontSize: 11, fontWeight: 600, color: TP.inkSoft, marginLeft: 2 }}>
              <span style={{ color: TP.ochre }}>★</span>
              {post.rating.toFixed(1)}
            </span>
          )}
          <span style={{ fontFamily: TP.sans, fontSize: 12, color: TP.mutedSoft, marginLeft: 'auto' }}>{post.time}</span>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6, fontFamily: TP.sans, fontSize: 11.5, color: TP.muted, whiteSpace: 'nowrap', overflow: 'hidden' }}>
          <TPIcon name="location" size={11} stroke={2} color={TP.muted} />
          <span>{post.neighborhood}</span>
          {post.trending && <span style={{ marginLeft: 'auto' }}><TPTrendingBadge /></span>}
        </div>
        <div style={{
          fontFamily: TP.sans, fontSize: 14, color: TP.inkSoft,
          lineHeight: 1.45, marginBottom: 8,
        }}>
          <TPRichText text={post.text} />
        </div>
        <TPPostActions stats={post.stats} compact />
      </div>
    </div>
  );
}

// ─── Rich (FB-style) post w/ media ──────────────────────────
function TPPostRich({ post, onTap }) {
  return (
    <div onClick={onTap} style={{
      background: TP.paper, marginBottom: 0,
      borderBottom: `1px solid ${TP.hairline}`,
      cursor: 'pointer',
    }}>
      <div style={{ display: 'flex', gap: 10, padding: '14px 16px 10px', alignItems: 'center' }}>
        <TPAvatar name={post.author} hue={post.hue} size={40} />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 5, flexWrap: 'nowrap', minWidth: 0 }}>
            <span style={{ fontFamily: TP.sans, fontWeight: 600, fontSize: 14, color: TP.ink, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{post.author}</span>
            {post.verified && (
              <span style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 13, height: 13, borderRadius: '50%', background: TP.forest, flexShrink: 0 }}>
                <TPIcon name="check" size={7.5} color="#fff" stroke={3.5} />
              </span>
            )}
            {post.rating && (
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 2, fontFamily: TP.mono, fontSize: 11, fontWeight: 600, color: TP.inkSoft, marginLeft: 2 }}>
                <span style={{ color: TP.ochre }}>★</span>
                {post.rating.toFixed(1)}
              </span>
            )}
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontFamily: TP.sans, fontSize: 11, color: TP.muted, marginTop: 2, whiteSpace: 'nowrap', overflow: 'hidden' }}>
            <TPIcon name="location" size={11} stroke={2} />
            <span>{post.neighborhood}</span>
            <span style={{ color: TP.mutedSoft }}>·</span>
            <span>{post.time}</span>
          </div>
        </div>
        {post.trending && <TPTrendingBadge compact />}
      </div>
      {post.text && (
        <div style={{
          padding: '0 16px 12px',
          fontFamily: TP.sans, fontSize: 14.5, color: TP.inkSoft, lineHeight: 1.5,
        }}>
          <TPRichText text={post.text} />
        </div>
      )}
      {(post.images || post.image) && (
        <div style={{ padding: '4px 14px 0' }}>
          <TPImageGallery
            images={
              post.images
                ? post.images.map((img, i) => typeof img === 'string'
                    ? { label: img, hue: (post.hue + i) % 6 }
                    : { hue: post.hue, ...img })
                : [{ label: post.image, hue: post.hue }]
            }
            height={post.images && post.images.length > 1 ? 240 : 200}
            radius={16}
          />
        </div>
      )}
      {post.title && (
        <div style={{ padding: '14px 18px 8px' }}>
          <div style={{ fontFamily: TP.serif, fontSize: 22, color: TP.ink, lineHeight: 1.2, letterSpacing: -0.2 }}>{post.title}</div>
          {post.subtitle && <div style={{ fontFamily: TP.sans, fontSize: 12, color: TP.muted, marginTop: 6 }}>{post.subtitle}</div>}
        </div>
      )}
      <div style={{ padding: '10px 16px 12px' }}>
        <TPPostActions stats={post.stats} />
      </div>
      {(post.kind === 'news' || post.official || post.kind === 'alert') && (
        <TPHelpfulRow postId={post.id} baseCount={Math.max(3, Math.round((post.stats?.likes || 20) * 0.18))} />
      )}
    </div>
  );
}

// ─── Was this helpful? row ──────────────────────────
function TPHelpfulRow({ postId, baseCount = 12 }) {
  const [vote, setVote] = React.useState(null); // 'up' | 'down' | null
  const [count, setCount] = React.useState(baseCount);
  const [showWhy, setShowWhy] = React.useState(false);
  const [reason, setReason] = React.useState(null);

  const submitUp = (e) => {
    e.stopPropagation();
    if (vote) return;
    setVote('up'); setCount(c => c + 1);
  };
  const submitDown = (e) => {
    e.stopPropagation();
    if (vote) return;
    setVote('down'); setShowWhy(true);
  };

  // Voted up — confirmation
  if (vote === 'up') {
    return (
      <div style={{
        display: 'flex', alignItems: 'center', gap: 8,
        margin: '0 16px 14px', padding: '10px 12px',
        background: TP.forestTint, borderRadius: TP.r.md,
        fontFamily: TP.sans, fontSize: 12.5, color: TP.forest, fontWeight: 500,
      }}>
        <TPIcon name="check" size={15} color={TP.forest} stroke={2.4} />
        <span>Thanks — marked helpful · {count} neighbors agree</span>
      </div>
    );
  }

  // Voted down — followup chips
  if (vote === 'down' && showWhy && !reason) {
    const reasons = ['Inaccurate', 'Off-topic', 'Outdated', 'Other'];
    return (
      <div style={{ margin: '0 16px 14px', padding: '10px 12px',
        background: TP.cream, border: `1px solid ${TP.hairline}`, borderRadius: TP.r.md,
      }}>
        <div style={{ fontFamily: TP.sans, fontSize: 12, color: TP.inkSoft, fontWeight: 500, marginBottom: 8 }}>
          What's off about this?
        </div>
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {reasons.map(r => (
            <button key={r} onClick={(e) => { e.stopPropagation(); setReason(r); }} style={{
              background: TP.paper, border: `1px solid ${TP.hairlineStrong}`,
              padding: '5px 10px', borderRadius: TP.r.pill, cursor: 'pointer',
              fontFamily: TP.sans, fontSize: 11.5, fontWeight: 500, color: TP.inkSoft,
            }}>{r}</button>
          ))}
        </div>
      </div>
    );
  }

  // Voted down with reason — confirmation
  if (vote === 'down' && reason) {
    return (
      <div style={{
        display: 'flex', alignItems: 'center', gap: 8,
        margin: '0 16px 14px', padding: '10px 12px',
        background: TP.cream, border: `1px solid ${TP.hairline}`, borderRadius: TP.r.md,
        fontFamily: TP.sans, fontSize: 12.5, color: TP.muted, fontWeight: 500,
      }}>
        <TPIcon name="check" size={15} color={TP.muted} stroke={2.4} />
        <span>Got it — flagged as "{reason.toLowerCase()}"</span>
      </div>
    );
  }

  // Initial state
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 10,
      margin: '0 16px 14px', padding: '8px 12px',
      background: TP.cream, border: `1px solid ${TP.hairline}`, borderRadius: TP.r.md,
    }}>
      <span style={{ fontFamily: TP.sans, fontSize: 12.5, color: TP.inkSoft, fontWeight: 500, flex: 1 }}>
        Was this helpful?
        {count >= 5 && <span style={{ color: TP.muted, fontWeight: 400 }}> · {count} say yes</span>}
      </span>
      <button onClick={submitUp} style={{
        background: TP.paper, border: `1px solid ${TP.hairlineStrong}`,
        padding: '5px 12px', borderRadius: TP.r.pill, cursor: 'pointer',
        display: 'flex', alignItems: 'center', gap: 4,
        fontFamily: TP.sans, fontSize: 12, fontWeight: 600, color: TP.forest,
      }}>
        <TPIcon name="check" size={13} color={TP.forest} stroke={2.4} />
        Yes
      </button>
      <button onClick={submitDown} style={{
        background: TP.paper, border: `1px solid ${TP.hairlineStrong}`,
        padding: '5px 12px', borderRadius: TP.r.pill, cursor: 'pointer',
        display: 'flex', alignItems: 'center', gap: 4,
        fontFamily: TP.sans, fontSize: 12, fontWeight: 600, color: TP.muted,
      }}>
        <TPIcon name="close" size={13} color={TP.muted} stroke={2.4} />
        No
      </button>
    </div>
  );
}

// ─── Post actions (replies / share / like / views / bookmark) ──────────────────────────
function TPPostActions({ stats = {}, compact = false, detail = false, helpfulCount, onHelpful }) {
  const fs = compact ? 12 : 13;
  const sz = compact ? 16 : 18;
  const [liked, setLiked] = React.useState(false);
  const [helpfulOn, setHelpfulOn] = React.useState(false);
  // Synthesize a view count if not provided: ~ likes * 12 + replies * 4 + shares * 8 (rounded)
  const views = stats.views ?? ((stats.likes || 0) * 12 + (stats.replies || 0) * 4 + (stats.shares || 0) * 8 + 47);
  const fmtViews = (n) => n >= 1000 ? (n / 1000).toFixed(1).replace(/\.0$/, '') + 'K' : String(n);
  const baseHelpful = helpfulCount ?? Math.max(3, Math.round((stats.likes || 20) * 0.18));
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: compact ? 14 : 16,
      color: TP.muted, fontFamily: TP.sans, fontSize: fs, fontWeight: 500,
    }}>
      <ActionBtn icon="chat" size={sz} count={stats.replies} fs={fs} />
      <button onClick={(e) => { e.stopPropagation(); setLiked(!liked); }} style={{
        background: 'none', border: 'none', padding: 0, cursor: 'pointer',
        display: 'flex', alignItems: 'center', gap: 5,
        color: liked ? TP.alertRed : TP.muted,
        fontFamily: 'inherit', fontSize: 'inherit', fontWeight: 'inherit',
      }}>
        <TPIcon name="heart" size={sz} stroke={2} fill={liked ? TP.alertRed : 'none'} color={liked ? TP.alertRed : 'currentColor'} />
        <span>{(stats.likes || 0) + (liked ? 1 : 0)}</span>
      </button>
      {detail ? (
        <button onClick={(e) => { e.stopPropagation(); setHelpfulOn(!helpfulOn); onHelpful && onHelpful(!helpfulOn); }} style={{
          background: 'none', border: 'none', padding: 0, cursor: 'pointer',
          display: 'flex', alignItems: 'center', gap: 5,
          color: helpfulOn ? TP.terracotta : TP.muted,
          fontFamily: 'inherit', fontSize: 'inherit', fontWeight: helpfulOn ? 600 : 'inherit',
        }}>
          <TPIcon name="helpful" size={sz} stroke={2} color={helpfulOn ? TP.terracotta : 'currentColor'} />
          <span>{baseHelpful + (helpfulOn ? 1 : 0)}</span>
        </button>
      ) : null}
      <ActionBtn icon="eye" size={sz} count={fmtViews(views)} fs={fs} />
      <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: compact ? 12 : 14 }}>
        {!detail && <ActionBtn icon="share" size={sz} fs={fs} />}
        <button onClick={(e) => e.stopPropagation()} style={{
          background: 'none', border: 'none', padding: 0, cursor: 'pointer',
          display: 'flex', alignItems: 'center', color: 'inherit',
        }}>
          <TPIcon name="bookmark" size={sz} stroke={1.8} />
        </button>
      </div>
    </div>
  );
}
function ActionBtn({ icon, size, count, fs }) {
  return (
    <button onClick={(e) => e.stopPropagation()} style={{
      background: 'none', border: 'none', padding: 0, cursor: 'pointer',
      display: 'flex', alignItems: 'center', gap: 5, color: 'inherit',
      fontFamily: 'inherit', fontSize: fs, fontWeight: 500,
    }}>
      <TPIcon name={icon} size={size} stroke={1.8} />
      {count !== undefined && <span>{count}</span>}
    </button>
  );
}

// ─── Alert card ──────────────────────────
function TPAlertCard({ alert, onTap }) {
  const tones = {
    red: { bg: TP.redTint, accent: TP.alertRed, label: 'URGENT' },
    amber: { bg: TP.amberTint, accent: TP.alertAmber, label: 'ADVISORY' },
    blue: { bg: TP.blueTint, accent: TP.alertBlue, label: 'NOTICE' },
    forest: { bg: TP.forestTint, accent: TP.forest, label: 'UPDATE' },
  };
  const t = tones[alert.tone] || tones.amber;
  const [feedback, setFeedback] = React.useState(null); // null | 'helpful' | 'false' | 'outdated'
  const stop = (e) => e.stopPropagation();
  const cast = (kind) => (e) => { e.stopPropagation(); setFeedback(kind); };
  return (
    <div onClick={onTap} style={{
      background: t.bg, padding: '14px 16px',
      borderBottom: `1px solid ${TP.hairline}`,
      cursor: 'pointer', position: 'relative',
    }}>
      <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 4, background: t.accent }} />
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
        <div style={{
          width: 28, height: 28, borderRadius: 8, background: t.accent, color: '#fff',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          <TPIcon name={alert.icon || 'alert'} size={16} stroke={2.2} color="#fff" />
        </div>
        <div style={{
          fontFamily: TP.mono, fontSize: 10, fontWeight: 700, color: t.accent,
          letterSpacing: 1.2,
        }}>{t.label}</div>
        {(alert.stage || alert.official) && (
          <TPTrustBadge stage={alert.stage} confirms={alert.confirms} official={alert.official} compact />
        )}
        <div style={{ marginLeft: 'auto', fontFamily: TP.sans, fontSize: 11, color: TP.muted }}>{alert.time}</div>
      </div>
      <div style={{
        fontFamily: TP.serif, fontSize: 19, color: TP.ink, lineHeight: 1.2,
        letterSpacing: -0.2, marginBottom: 4,
      }}>{alert.title}</div>
      <div style={{ fontFamily: TP.sans, fontSize: 13, color: TP.inkSoft, lineHeight: 1.5, marginBottom: 8 }}>{alert.body}</div>
      <div style={{ display: 'flex', alignItems: 'center', gap: 14, fontFamily: TP.sans, fontSize: 11, color: TP.muted }}>
        <span style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
          <TPIcon name="location" size={11} stroke={2} /> {alert.area}
        </span>
        {alert.source && <span>· via {alert.source}</span>}
        <span style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 3 }}>
          <TPIcon name="eye" size={11} stroke={2} /> {alert.views}
        </span>
      </div>

      {/* Community signal row — Helpful / False / Outdated */}
      <div onClick={stop} style={{
        display: 'flex', alignItems: 'center', gap: 6,
        marginTop: 10, paddingTop: 10,
        borderTop: `1px dashed ${TP.hairlineStrong}`,
      }}>
        {feedback ? (
          <div style={{
            display: 'flex', alignItems: 'center', gap: 6,
            fontFamily: TP.sans, fontSize: 11.5, color: TP.muted, fontWeight: 500,
          }}>
            <TPIcon name="check" size={13} stroke={2.6} color={t.accent} />
            <span>
              Marked
              {' '}
              <span style={{ color: TP.inkSoft, fontWeight: 600 }}>
                {feedback === 'helpful' ? 'helpful' : feedback === 'false' ? 'a false alarm' : 'outdated'}
              </span>
              {' '}· thanks for confirming.
            </span>
          </div>
        ) : (
          <>
            <span style={{ fontFamily: TP.sans, fontSize: 11, color: TP.muted, fontWeight: 600, letterSpacing: 0.2, textTransform: 'uppercase', marginRight: 4 }}>
              Still accurate?
            </span>
            <FeedbackChip icon="check"  label="Helpful"   onClick={cast('helpful')}  tone="forest" />
            <FeedbackChip icon="flag"   label="False"     onClick={cast('false')}    tone="red" />
            <FeedbackChip icon="cloud"  label="Outdated"  onClick={cast('outdated')} tone="muted" />
          </>
        )}
      </div>
    </div>
  );
}

// Small inline chip used by the alert-card feedback row
function FeedbackChip({ icon, label, onClick, tone = 'forest' }) {
  const tones = {
    forest: { fg: TP.forest,    bg: TP.forestTint },
    red:    { fg: TP.alertRed,  bg: TP.redTint },
    muted:  { fg: TP.inkSoft,   bg: 'rgba(31,27,22,0.06)' },
  };
  const t = tones[tone] || tones.forest;
  return (
    <button onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: 4,
      padding: '4px 9px 4px 7px', borderRadius: TP.r.pill,
      background: t.bg, border: `1px solid ${TP.hairline}`,
      color: t.fg, fontFamily: TP.sans, fontSize: 11.5, fontWeight: 600,
      cursor: 'pointer', letterSpacing: 0.1,
    }}>
      <TPIcon name={icon} size={12} stroke={2.4} color={t.fg} />
      {label}
    </button>
  );
}

// ─── Trust badge for community-sourced alerts ──────────────────────────
function TPTrustBadge({ stage = 'reported', confirms = 0, official = false, compact = false }) {
  if (official) {
    return (
      <span style={{
        display: 'inline-flex', alignItems: 'center', gap: 3,
        padding: compact ? '2px 6px' : '3px 8px',
        background: TP.forest, color: TP.cream, borderRadius: 4,
        fontFamily: TP.mono, fontSize: compact ? 9 : 9.5, fontWeight: 700, letterSpacing: 0.8,
      }}>
        <TPIcon name="check" size={compact ? 9 : 10} stroke={2.6} color={TP.cream} />
        OFFICIAL
      </span>
    );
  }
  const stages = {
    reported: { bg: TP.muted, fg: TP.cream, label: 'REPORTED', icon: 'eye' },
    confirmed: { bg: TP.ochre, fg: '#3a2a08', label: `CONFIRMED · ${confirms}`, icon: 'check' },
    verified: { bg: TP.forest, fg: TP.cream, label: `VERIFIED · ${confirms}`, icon: 'check' },
  };
  const s = stages[stage] || stages.reported;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 3,
      padding: compact ? '2px 6px' : '3px 8px',
      background: s.bg, color: s.fg, borderRadius: 4,
      fontFamily: TP.mono, fontSize: compact ? 9 : 9.5, fontWeight: 700, letterSpacing: 0.8,
    }}>
      <TPIcon name={s.icon} size={compact ? 9 : 10} stroke={2.6} color={s.fg} />
      {s.label}
    </span>
  );
}

// ─── Section header ──────────────────────────
function TPSection({ title, subtitle, action, children, padded = true }) {
  return (
    <div style={{ marginBottom: 6 }}>
      <div style={{
        display: 'flex', alignItems: 'baseline', gap: 8,
        padding: padded ? '14px 16px 8px' : '14px 0 8px',
      }}>
        <div style={{
          fontFamily: TP.serif, fontSize: 19, color: TP.ink,
          letterSpacing: -0.2, lineHeight: 1,
        }}>{title}</div>
        {subtitle && (
          <div style={{ fontFamily: TP.sans, fontSize: 11, color: TP.muted, fontWeight: 500 }}>{subtitle}</div>
        )}
        {action && <div style={{ marginLeft: 'auto', fontFamily: TP.sans, fontSize: 12, color: TP.forest, fontWeight: 600 }}>{action}</div>}
      </div>
      {children}
    </div>
  );
}

// ─── Three-dot more menu (report / mute / etc.) ──────────────────────
function TPMoreMenu({ items = [] }) {
  const [open, setOpen] = React.useState(false);
  return (
    <div style={{ position: 'relative' }}>
      <button onClick={(e) => { e.stopPropagation(); setOpen(!open); }} style={{
        background: 'none', border: 'none', padding: '4px 6px', cursor: 'pointer',
        color: TP.muted, display: 'flex', alignItems: 'center', gap: 2,
      }} aria-label="More">
        <span style={{ width: 3, height: 3, borderRadius: '50%', background: 'currentColor' }} />
        <span style={{ width: 3, height: 3, borderRadius: '50%', background: 'currentColor' }} />
        <span style={{ width: 3, height: 3, borderRadius: '50%', background: 'currentColor' }} />
      </button>
      {open && (
        <>
          <div onClick={(e) => { e.stopPropagation(); setOpen(false); }} style={{
            position: 'fixed', inset: 0, zIndex: 50, background: 'transparent',
          }} />
          <div style={{
            position: 'absolute', right: 0, top: '100%', marginTop: 4, zIndex: 51,
            minWidth: 180, background: TP.paper,
            border: `1px solid ${TP.hairline}`, borderRadius: TP.r.md,
            boxShadow: '0 8px 24px rgba(0,0,0,0.12), 0 2px 6px rgba(0,0,0,0.06)',
            overflow: 'hidden',
          }}>
            {items.map((it, i) => (
              <button key={i} onClick={(e) => { e.stopPropagation(); setOpen(false); it.onClick && it.onClick(); }} style={{
                display: 'flex', alignItems: 'center', gap: 10,
                width: '100%', padding: '10px 14px', background: 'transparent',
                border: 'none', cursor: 'pointer', textAlign: 'left',
                fontFamily: TP.sans, fontSize: 13, color: it.tone === 'danger' ? TP.alertRed : TP.ink,
                borderBottom: i < items.length - 1 ? `1px solid ${TP.hairline}` : 'none',
              }}>
                <TPIcon name={it.icon} size={15} color={it.tone === 'danger' ? TP.alertRed : TP.muted} stroke={2} />
                {it.label}
              </button>
            ))}
          </div>
        </>
      )}
    </div>
  );
}

// ─── Threaded comment item ──────────────────────────
function TPComment({ comment, isReply = false, isTopReply = false, postAuthorIsViewer = true }) {
  const [helpfulOn, setHelpfulOn] = React.useState(comment.helpful || false);
  const [liked, setLiked] = React.useState(false);
  const [reported, setReported] = React.useState(false);
  const helpfulCount = (comment.helpfulCount || 0) + (helpfulOn && !comment.helpful ? 1 : 0);
  const fmtViews = (n) => n >= 1000 ? (n / 1000).toFixed(1).replace(/\.0$/, '') + 'K' : String(n);

  const menuItems = [
    ...(postAuthorIsViewer ? [{
      icon: 'helpful', label: helpfulOn ? 'Unmark as helpful' : 'Mark as helpful',
      onClick: () => setHelpfulOn(!helpfulOn),
    }] : []),
    { icon: 'flag', label: reported ? 'Reported' : 'Report', tone: 'danger', onClick: () => setReported(true) },
  ];

  return (
    <div style={{ display: 'flex', gap: 10 }}>
      <TPAvatar name={comment.author} hue={comment.hue} size={isReply ? 28 : 36} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
          <span style={{ fontFamily: TP.sans, fontSize: isReply ? 12.5 : 13.5, fontWeight: 600, color: TP.ink }}>{comment.author}</span>
          <span style={{ fontFamily: TP.sans, fontSize: 11, color: TP.muted }}>· {comment.time}</span>
          {(comment.helpful || helpfulOn) && (
            <span style={{
              display: 'inline-flex', alignItems: 'center', gap: 3,
              padding: '2px 7px', borderRadius: 999,
              background: TP.terracotta + '14', color: TP.terracotta,
              fontFamily: TP.mono, fontSize: 9.5, fontWeight: 700, letterSpacing: 0.6,
              textTransform: 'uppercase', lineHeight: 1,
            }}>
              <TPIcon name="helpful" size={9} color={TP.terracotta} stroke={2.4} />
              Helpful
            </span>
          )}
          <div style={{ marginLeft: 'auto' }}>
            <TPMoreMenu items={menuItems} />
          </div>
        </div>
        <div style={{
          fontFamily: TP.sans, fontSize: isReply ? 13 : 13.5,
          color: TP.inkSoft, lineHeight: 1.5, marginBottom: 8,
        }}>
          <TPRichText text={comment.text} />
        </div>
        {reported && (
          <div style={{
            display: 'inline-flex', alignItems: 'center', gap: 6,
            padding: '5px 10px', marginBottom: 8,
            background: TP.alertRedTint || 'rgba(180,60,60,0.08)',
            borderRadius: TP.r.sm, fontFamily: TP.sans, fontSize: 11.5,
            color: TP.alertRed, fontWeight: 500,
          }}>
            <TPIcon name="check" size={11} color={TP.alertRed} stroke={2.4} />
            Reported · thanks for letting us know
          </div>
        )}
        <div style={{ display: 'flex', alignItems: 'center', gap: 16, fontFamily: TP.sans, fontSize: 12, color: TP.muted }}>
          <button onClick={(e) => { e.stopPropagation(); setLiked(!liked); }} style={{
            background: 'none', border: 'none', padding: 0, cursor: 'pointer',
            display: 'flex', alignItems: 'center', gap: 5,
            color: liked ? TP.alertRed : 'inherit', fontFamily: 'inherit', fontSize: 'inherit',
          }}>
            <TPIcon name="heart" size={13} stroke={2} fill={liked ? TP.alertRed : 'none'} color={liked ? TP.alertRed : 'currentColor'} />
            {(comment.likes || 0) + (liked ? 1 : 0)}
          </button>
          {!isReply && (
            <button onClick={(e) => { e.stopPropagation(); setHelpfulOn(!helpfulOn); }} style={{
              background: 'none', border: 'none', padding: 0, cursor: 'pointer',
              display: 'flex', alignItems: 'center', gap: 5,
              color: helpfulOn ? TP.terracotta : 'inherit',
              fontFamily: 'inherit', fontSize: 'inherit',
              fontWeight: helpfulOn ? 600 : 'inherit',
            }}>
              <TPIcon name="helpful" size={13} stroke={2} color={helpfulOn ? TP.terracotta : 'currentColor'} />
              {helpfulCount > 0 ? helpfulCount : 'Helpful'}
            </button>
          )}
          <button style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer', color: 'inherit', fontFamily: 'inherit', fontSize: 'inherit' }}>Reply</button>
          <span style={{ display: 'flex', alignItems: 'center', gap: 5, marginLeft: 'auto' }}>
            <TPIcon name="eye" size={12} stroke={1.8} color={TP.mutedSoft} />
            {fmtViews(comment.views || 0)}
          </span>
        </div>
      </div>
    </div>
  );
}

// ─── Comment thread with nested replies ──────────────────────────
function TPCommentThread({ comment, isTopReply = false, postAuthorIsViewer = true }) {
  const [showAll, setShowAll] = React.useState(false);
  const replies = comment.replies || [];
  const hasReplies = replies.length > 0;
  const visibleReplies = showAll || replies.length <= 2 ? replies : replies.slice(0, 1);

  return (
    <div style={{
      background: TP.paper,
      padding: '14px 16px',
      borderBottom: `1px solid ${TP.hairline}`,
      borderLeft: isTopReply ? `3px solid ${TP.terracotta}` : 'none',
    }}>
      <TPComment comment={comment} isTopReply={isTopReply} postAuthorIsViewer={postAuthorIsViewer} />
      {hasReplies && (
        <div style={{ position: 'relative', marginTop: 12, paddingLeft: 22 }}>
          {/* Vertical connector running through the whole reply group */}
          <div style={{
            position: 'absolute', left: 9, top: 0, bottom: 12,
            width: 1.5, background: TP.hairlineStrong,
          }} />
          {visibleReplies.map((r, i) => (
            <div key={r.id} style={{ position: 'relative', marginBottom: i === visibleReplies.length - 1 ? 0 : 14 }}>
              {/* Horizontal connector branching off to this reply's avatar */}
              <div style={{
                position: 'absolute', left: -13, top: 14,
                width: 13, height: 1.5, background: TP.hairlineStrong,
              }} />
              <TPComment comment={r} isReply postAuthorIsViewer={postAuthorIsViewer} />
            </div>
          ))}
          {!showAll && replies.length > visibleReplies.length && (
            <button onClick={() => setShowAll(true)} style={{
              background: 'none', border: 'none', padding: '8px 0 0 0',
              cursor: 'pointer', color: TP.forest, fontFamily: TP.sans,
              fontSize: 12, fontWeight: 600,
            }}>
              View {replies.length - visibleReplies.length} more {replies.length - visibleReplies.length === 1 ? 'reply' : 'replies'} →
            </button>
          )}
        </div>
      )}
    </div>
  );
}

Object.assign(window, {
  TPTabBar, TPTabBarContext, TPTopBar, TPPostCompact, TPPostRich, TPPostActions, TPAlertCard, TPSection, TPHelpfulRow, TPTrustBadge,
  TPRichText, TPAuthorRating, TPTrendingBadge,
  TPMoreMenu, TPComment, TPCommentThread,
});
