// tabs.jsx — bottom tab bar + Friends screen + Me (profile) screen

const TB = window.__cpMakeTheme();

// ─────────────────────────────────────────────────────────────
// TabBar
// ─────────────────────────────────────────────────────────────
const TAB_HEIGHT = 78;

function TabBar({ active, accent, badges, onChange }) {
  const items = [
    { id: 'home',    label: '홈',   icon: <HomeIcon /> },
    { id: 'friends', label: '친구', icon: <FriendsIcon /> },
    { id: 'me',      label: '나',   icon: <MeIcon /> },
  ];

  return (
    <div style={{
      position: 'absolute',
      bottom: 0, left: 0, right: 0,
      height: TAB_HEIGHT,
      background: TB.tabBg,
      backdropFilter: 'blur(20px)',
      WebkitBackdropFilter: 'blur(20px)',
      borderTop: `0.5px solid ${TB.hairlineStrong}`,
      display: 'flex',
      padding: '8px 12px 22px',
      zIndex: 100,
    }}>
      {items.map(it => {
        const isOn = active === it.id;
        const badge = badges && badges[it.id];
        return (
          <button key={it.id} onClick={() => onChange(it.id)} style={{
            flex: 1, background: 'transparent', border: 'none',
            padding: 0,
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 3,
            cursor: 'pointer', fontFamily: 'inherit',
            WebkitTapHighlightColor: 'transparent',
            position: 'relative',
            color: isOn ? accent : TB.ink3,
          }}>
            <span style={{
              position: 'relative',
              width: 30, height: 30,
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              transition: 'transform 0.16s ease',
              transform: isOn ? 'scale(1.06)' : 'scale(1)',
            }}>
              {React.cloneElement(it.icon, { filled: isOn, color: isOn ? accent : TB.ink3 })}
              {badge > 0 && (
                <span style={{
                  position: 'absolute', top: -2, right: -2,
                  minWidth: 16, height: 16, padding: '0 4px',
                  borderRadius: 999,
                  background: TB.danger,
                  color: '#FFF',
                  fontSize: 9.5, fontWeight: 700, letterSpacing: '-0.02em',
                  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                  border: `1.5px solid ${TB.tabBadgeBorder}`,
                }}>{badge > 9 ? '9+' : badge}</span>
              )}
            </span>
            <span style={{
              fontSize: 10.5, fontWeight: isOn ? 700 : 500,
              letterSpacing: '-0.01em',
            }}>{it.label}</span>
          </button>
        );
      })}
    </div>
  );
}

function HomeIcon({ filled, color = TB.ink3 }) {
  return filled ? (
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
      <path d="M4 11.5L12 4l8 7.5V20a1 1 0 0 1-1 1h-4v-7h-6v7H5a1 1 0 0 1-1-1v-8.5z"
            fill={color}/>
    </svg>
  ) : (
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
      <path d="M4 11.5L12 4l8 7.5V20a1 1 0 0 1-1 1h-4v-7h-6v7H5a1 1 0 0 1-1-1v-8.5z"
            stroke={color} strokeWidth="1.7" strokeLinejoin="round" fill="none"/>
    </svg>
  );
}

function FriendsIcon({ filled, color = TB.ink3 }) {
  return filled ? (
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
      <circle cx="9" cy="8" r="3.5" fill={color}/>
      <path d="M2 20c0-3 3-5.5 7-5.5s7 2.5 7 5.5v.5H2V20z" fill={color}/>
      <circle cx="17" cy="7" r="2.5" fill={color} fillOpacity="0.7"/>
      <path d="M14 15.5c.5-1.5 2-2.5 3.5-2.5 2.5 0 4.5 2 4.5 4.5v1H17" fill={color} fillOpacity="0.7"/>
    </svg>
  ) : (
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
      <circle cx="9" cy="8" r="3.5" stroke={color} strokeWidth="1.7"/>
      <path d="M2 20.5c0-3 3-5.5 7-5.5s7 2.5 7 5.5"
            stroke={color} strokeWidth="1.7" strokeLinecap="round"/>
      <circle cx="17" cy="7" r="2.5" stroke={color} strokeWidth="1.7"/>
      <path d="M14.5 15c.5-1.2 1.8-2 3.5-2 2.5 0 4 1.8 4 4"
            stroke={color} strokeWidth="1.7" strokeLinecap="round"/>
    </svg>
  );
}

function MeIcon({ filled, color = TB.ink3 }) {
  return filled ? (
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
      <circle cx="12" cy="8.5" r="4" fill={color}/>
      <path d="M4 21c0-3.5 3.5-6.5 8-6.5s8 3 8 6.5v.5H4V21z" fill={color}/>
    </svg>
  ) : (
    <svg width="24" height="24" viewBox="0 0 24 24" fill="none">
      <circle cx="12" cy="8.5" r="4" stroke={color} strokeWidth="1.7"/>
      <path d="M4 21.5c0-3.5 3.5-6.5 8-6.5s8 3 8 6.5"
            stroke={color} strokeWidth="1.7" strokeLinecap="round"/>
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// Sample friend data
// ─────────────────────────────────────────────────────────────
const SAMPLE_FRIENDS = [
  { id: 'f1', name: '지수',  face: 'happy',   accent: '#C97B5C', lastActive: 0, sharedCount: 3, recentlyAdded: true },
  { id: 'f2', name: '민호',  face: 'glasses', accent: '#4A6B4F', lastActive: 1, sharedCount: 1, recentlyAdded: false },
  { id: 'f3', name: '서연',  face: 'wink',    accent: '#8B5C7A', lastActive: 3, sharedCount: 2, recentlyAdded: true },
  { id: 'f4', name: '준영',  face: 'starry',  accent: '#C9A86A', lastActive: 7, sharedCount: 0, recentlyAdded: false },
  { id: 'f5', name: '하늘',  face: 'sleepy',  accent: '#6B5D4A', lastActive: 14, sharedCount: 1, recentlyAdded: false },
];

const SAMPLE_SHARE_REQUESTS = [
  { id: 'sq1', from: '엠마',   fromFace: 'smile',   fromAccent: '#4A6B4F',
    name: '교토 절·신사 표현', count: 10, color: '#4A6B4F', cover: { kind: 'icon', icon: 'star' },
    requestedDays: 0,
    primaryLang: 'ja', primaryLangLabel: '일본어', isMultiLang: false,
    message: '교토 여행 같이 가는 거 기억나? 미리 외워두자!',
    cards: [
      { id:'sq1_1', lang:'ja', langLabel:'일본어', foreign:'拝観料はいくらですか？', pronunciation:'하이칸료-와 이쿠라데스카?', korean:'관람료는 얼마예요?', category:'관광/구경', addedDays:0 },
      { id:'sq1_2', lang:'ja', langLabel:'일본어', foreign:'御朱印いただけますか？', pronunciation:'고슈인 이타다케마스카?', korean:'고슈인 받을 수 있나요?', category:'관광/구경', addedDays:0 },
      { id:'sq1_3', lang:'ja', langLabel:'일본어', foreign:'写真撮ってもいいですか？', pronunciation:'샤신 톳테모 이이데스카?', korean:'사진 찍어도 될까요?', category:'관광/구경', addedDays:0 },
      { id:'sq1_4', lang:'ja', langLabel:'일본어', foreign:'入口はどちらですか？', pronunciation:'이리구치와 도치라데스카?', korean:'입구는 어디예요?', category:'관광/구경', addedDays:0 },
      { id:'sq1_5', lang:'ja', langLabel:'일본어', foreign:'お守りはありますか？', pronunciation:'오마모리와 아리마스카?', korean:'부적 있어요?', category:'관광/구경', addedDays:0 },
      { id:'sq1_6', lang:'ja', langLabel:'일본어', foreign:'おみくじを引きたいです。', pronunciation:'오미쿠지오 히키타이데스.', korean:'오미쿠지 뽑고 싶어요.', category:'관광/구경', addedDays:0 },
      { id:'sq1_7', lang:'ja', langLabel:'일본어', foreign:'静かにしてください。', pronunciation:'시즈카니 시테 쿠다사이.', korean:'조용히 해 주세요.', category:'관광/구경', addedDays:0 },
      { id:'sq1_8', lang:'ja', langLabel:'일본어', foreign:'閉門は何時ですか？', pronunciation:'헤이몬와 난지데스카?', korean:'폐문 시간은 몇 시예요?', category:'관광/구경', addedDays:0 },
      { id:'sq1_9', lang:'ja', langLabel:'일본어', foreign:'靴を脱ぐべきですか？', pronunciation:'쿠츠오 누구베키데스카?', korean:'신발을 벗어야 하나요?', category:'관광/구경', addedDays:0 },
      { id:'sq1_10', lang:'ja', langLabel:'일본어', foreign:'素晴らしいですね。', pronunciation:'스바라시-데스네.', korean:'정말 멋지네요.', category:'관광/구경', addedDays:0 },
    ],
  },
  { id: 'sq2', from: '도윤',   fromFace: 'basic',   fromAccent: '#8B5C7A',
    name: '베를린 카페 회화', count: 7, color: '#8B5C7A', cover: { kind: 'icon', icon: 'cup' },
    requestedDays: 1,
    primaryLang: 'de', primaryLangLabel: '독일어', isMultiLang: false,
    message: '독일어 카페 표현 정리해봤어. 받아둬!',
    cards: [
      { id:'sq2_1', lang:'de', langLabel:'독일어', foreign:'Einen Kaffee, bitte.', pronunciation:'아이넨 카페, 비테.', korean:'커피 한 잔 주세요.', category:'식당/카페', addedDays:1 },
      { id:'sq2_2', lang:'de', langLabel:'독일어', foreign:'Die Rechnung, bitte.', pronunciation:'디 레히눙, 비테.', korean:'계산서 부탁드려요.', category:'식당/카페', addedDays:1 },
      { id:'sq2_3', lang:'de', langLabel:'독일어', foreign:'Haben Sie WLAN?', pronunciation:'하벤 지 베란?', korean:'와이파이 있어요?', category:'식당/카페', addedDays:1 },
      { id:'sq2_4', lang:'de', langLabel:'독일어', foreign:'Zum Mitnehmen, bitte.', pronunciation:'춤 미트네멘, 비테.', korean:'포장해 주세요.', category:'식당/카페', addedDays:1 },
      { id:'sq2_5', lang:'de', langLabel:'독일어', foreign:'Mit Milch und Zucker.', pronunciation:'미트 밀히 운트 추커.', korean:'우유랑 설탕 넣어주세요.', category:'식당/카페', addedDays:1 },
      { id:'sq2_6', lang:'de', langLabel:'독일어', foreign:'Vielen Dank!', pronunciation:'필렌 당크!', korean:'정말 감사해요!', category:'인사/사교', addedDays:1 },
      { id:'sq2_7', lang:'de', langLabel:'독일어', foreign:'Ist hier noch frei?', pronunciation:'이스트 히어 노흐 프라이?', korean:'여기 자리 비어있나요?', category:'식당/카페', addedDays:1 },
    ],
  },
];

const RECEIVED_COLLECTIONS = [
  { id: 'rc1', from: '지수',   fromFace: 'happy',   fromAccent: '#C97B5C',
    name: '오사카 카페 투어', count: 12, color: '#C97B5C', cover: { kind: 'icon', icon: 'cup' },
    receivedDays: 0,
    primaryLang: 'ja', primaryLangLabel: '일본어', isMultiLang: false,
    cards: [
      { id:'rc1_1', lang:'ja', langLabel:'일본어', foreign:'コーヒーを一つください。', pronunciation:'코-히-오 히토츠 쿠다사이.', korean:'커피 한 잔 주세요.', category:'식당/카페', addedDays:0 },
      { id:'rc1_2', lang:'ja', langLabel:'일본어', foreign:'ホットでお願いします。', pronunciation:'홋토데 오네가이시마스.', korean:'따뜻한 걸로 부탁드려요.', category:'식당/카페', addedDays:0 },
      { id:'rc1_3', lang:'ja', langLabel:'일본어', foreign:'砂糖は要りません。', pronunciation:'사토-와 이리마센.', korean:'설탕은 빼주세요.', category:'식당/카페', addedDays:0 },
      { id:'rc1_4', lang:'ja', langLabel:'일본어', foreign:'店内で飲みます。', pronunciation:'텐나이데 노미마스.', korean:'매장에서 마실게요.', category:'식당/카페', addedDays:0 },
      { id:'rc1_5', lang:'ja', langLabel:'일본어', foreign:'おすすめのケーキは？', pronunciation:'오스스메노 케-키와?', korean:'추천 케이크는 뭐예요?', category:'식당/카페', addedDays:0 },
      { id:'rc1_6', lang:'ja', langLabel:'일본어', foreign:'Wi-Fiはありますか？', pronunciation:'와이파이와 아리마스카?', korean:'와이파이 있어요?', category:'식당/카페', addedDays:0 },
      { id:'rc1_7', lang:'ja', langLabel:'일본어', foreign:'コンセントを使えますか？', pronunciation:'콘센토오 츠카에마스카?', korean:'콘센트 써도 될까요?', category:'식당/카페', addedDays:0 },
      { id:'rc1_8', lang:'ja', langLabel:'일본어', foreign:'おかわりください。', pronunciation:'오카와리 쿠다사이.', korean:'리필 부탁드려요.', category:'식당/카페', addedDays:1 },
      { id:'rc1_9', lang:'ja', langLabel:'일본어', foreign:'これは何のお菓子ですか？', pronunciation:'코레와 난노 오카시데스카?', korean:'이건 무슨 과자예요?', category:'식당/카페', addedDays:1 },
      { id:'rc1_10', lang:'ja', langLabel:'일본어', foreign:'席は空いていますか？', pronunciation:'세키와 아이테 이마스카?', korean:'자리 비어있어요?', category:'식당/카페', addedDays:1 },
      { id:'rc1_11', lang:'ja', langLabel:'일본어', foreign:'もう一杯ください。', pronunciation:'모- 잇파이 쿠다사이.', korean:'한 잔 더 주세요.', category:'식당/카페', addedDays:1 },
      { id:'rc1_12', lang:'ja', langLabel:'일본어', foreign:'ごちそうさまでした。', pronunciation:'고치소-사마데시타.', korean:'잘 먹었습니다.', category:'식당/카페', addedDays:1 },
    ],
  },
  { id: 'rc2', from: '서연',   fromFace: 'wink',    fromAccent: '#8B5C7A',
    name: '런던 미술관 표현', count: 8,  color: '#8B5C7A', cover: { kind: 'icon', icon: 'star' },
    receivedDays: 2,
    primaryLang: 'en', primaryLangLabel: '영어', isMultiLang: false,
    cards: [
      { id:'rc2_1', lang:'en', langLabel:'영어', foreign:'One adult ticket, please.', pronunciation:'원 어덜트 티켓, 플리즈.', korean:'성인 티켓 한 장 주세요.', category:'관광/구경', addedDays:2 },
      { id:'rc2_2', lang:'en', langLabel:'영어', foreign:'Is photography allowed?', pronunciation:'이즈 포토그래피 얼라우드?', korean:'사진 촬영 가능한가요?', category:'관광/구경', addedDays:2 },
      { id:'rc2_3', lang:'en', langLabel:'영어', foreign:'Where is the gift shop?', pronunciation:'웨어 이즈 더 기프트 샵?', korean:'기프트샵은 어디예요?', category:'관광/구경', addedDays:2 },
      { id:'rc2_4', lang:'en', langLabel:'영어', foreign:'Do you have an audio guide in Korean?', pronunciation:'두 유 해브 언 오디오 가이드 인 코리언?', korean:'한국어 오디오 가이드 있나요?', category:'관광/구경', addedDays:3 },
      { id:'rc2_5', lang:'en', langLabel:'영어', foreign:'When does the exhibition close?', pronunciation:'웬 더즈 디 엑시비션 클로즈?', korean:'전시는 언제 끝나요?', category:'관광/구경', addedDays:3 },
      { id:'rc2_6', lang:'en', langLabel:'영어', foreign:'Could I see the map?', pronunciation:'쿠드 아이 시 더 맵?', korean:'지도를 볼 수 있을까요?', category:'관광/구경', addedDays:3 },
      { id:'rc2_7', lang:'en', langLabel:'영어', foreign:'Where can I leave my bag?', pronunciation:'웨어 캔 아이 리브 마이 백?', korean:'가방은 어디에 맡길 수 있어요?', category:'관광/구경', addedDays:4 },
      { id:'rc2_8', lang:'en', langLabel:'영어', foreign:'Thank you, this was wonderful.', pronunciation:'땡큐, 디스 워즈 원더풀.', korean:'감사합니다, 정말 좋았어요.', category:'관광/구경', addedDays:4 },
    ],
  },
];

function timeAgo(days) {
  if (days === 0) return '오늘';
  if (days === 1) return '어제';
  if (days < 7) return `${days}일 전`;
  if (days < 30) return `${Math.floor(days / 7)}주 전`;
  return `${Math.floor(days / 30)}개월 전`;
}

// ─────────────────────────────────────────────────────────────
// FriendsScreen
// ─────────────────────────────────────────────────────────────
function FriendsScreen({ accent, onOpenFriend, onOpenReceived, onOpenInvite, onOpenNudge, onOpenCollection, requests, received, onAccept, onReject }) {
  const pendingRequests = requests != null ? requests : SAMPLE_SHARE_REQUESTS;
  const receivedList = received != null ? received : RECEIVED_COLLECTIONS;
  const [tab, setTab] = React.useState(pendingRequests.length > 0 ? 'received' : 'list'); // 'list' | 'received'

  const friends = SAMPLE_FRIENDS;

  return (
    <div style={{ paddingBottom: TAB_HEIGHT + 20 }}>
      {/* Header — sticky */}
      <div style={{
        position: 'sticky', top: 0, zIndex: 30,
        background: TB.bg,
        padding: '54px 22px 12px',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        minHeight: 44,
      }}>
        <div style={{
          fontSize: 24, fontWeight: 700, letterSpacing: '-0.03em',
          color: TB.ink,
        }}>친구</div>
        <button onClick={onOpenInvite} style={{
          height: 32, padding: '0 12px 0 10px', borderRadius: 999,
          background: accent, color: '#FFF',
          border: 'none',
          display: 'inline-flex', alignItems: 'center', gap: 5,
          fontFamily: 'inherit', fontSize: 12.5, fontWeight: 600,
          letterSpacing: '-0.01em', cursor: 'pointer',
          WebkitTapHighlightColor: 'transparent',
        }}>
          <svg width="12" height="12" viewBox="0 0 14 14" fill="none">
            <path d="M7 2v10M2 7h10" stroke="#FFF" strokeWidth="2" strokeLinecap="round"/>
          </svg>
          초대
        </button>
      </div>

      {/* Quota perk banner */}
      <button onClick={onOpenInvite} style={{
        margin: '16px 22px 0',
        width: 'calc(100% - 44px)',
        padding: '14px 16px',
        background: `linear-gradient(135deg, ${accent}1A 0%, ${accent}08 100%)`,
        border: `0.5px solid ${accent}30`,
        borderRadius: 16,
        display: 'flex', alignItems: 'center', gap: 12,
        cursor: 'pointer',
        fontFamily: 'inherit',
        textAlign: 'left',
        WebkitTapHighlightColor: 'transparent',
      }}>
        <span style={{
          width: 40, height: 40, borderRadius: 12,
          background: accent, color: '#FFF',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          flexShrink: 0,
        }}>
          <svg width="20" height="20" viewBox="0 0 22 22" fill="none">
            <path d="M11 2L13.5 7L19 8L15 12L16 17.5L11 15L6 17.5L7 12L3 8L8.5 7L11 2Z"
                  fill="#FFF"/>
          </svg>
        </span>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{
            fontSize: 14, fontWeight: 700, color: TB.ink,
            letterSpacing: '-0.01em',
          }}>친구를 초대하면 +1개</div>
          <div style={{
            marginTop: 2,
            fontSize: 12, color: TB.ink2,
            letterSpacing: '-0.01em',
          }}>둘 다 한도가 늘어요</div>
        </div>
        <svg width="7" height="11" viewBox="0 0 8 14" fill="none">
          <path d="M1.5 1.5L6.5 7L1.5 12.5" stroke={accent} strokeWidth="1.8"
                strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
      </button>

      {/* Sub-tabs */}
      <div style={{
        margin: '20px 22px 0',
        display: 'flex',
        gap: 4,
        borderBottom: `0.5px solid ${TB.hairlineStrong}`,
      }}>
        {[
          { id: 'list',     label: '내 친구', count: friends.length },
          { id: 'received', label: '받은 주머니', count: receivedList.length + pendingRequests.length,
            hasDot: pendingRequests.length > 0 },
        ].map(t => {
          const isOn = tab === t.id;
          return (
            <button key={t.id} onClick={() => setTab(t.id)} style={{
              padding: '12px 4px 12px',
              background: 'transparent', border: 'none',
              borderBottom: isOn ? `2px solid ${accent}` : '2px solid transparent',
              marginBottom: -0.5,
              fontFamily: 'inherit', fontSize: 14, fontWeight: 600,
              color: isOn ? TB.ink : TB.ink3,
              letterSpacing: '-0.01em',
              cursor: 'pointer',
              display: 'inline-flex', alignItems: 'center', gap: 5,
              marginRight: 18,
              WebkitTapHighlightColor: 'transparent',
            }}>
              {t.label}
              <span style={{
                fontSize: 12, fontWeight: 500,
                color: isOn ? accent : TB.ink3,
              }}>{t.count}</span>
              {t.hasDot && !isOn && (
                <span style={{
                  width: 6, height: 6, borderRadius: 6,
                  background: '#B5483C',
                  marginLeft: 2,
                }}/>
              )}
            </button>
          );
        })}
      </div>

      {tab === 'list' ? (
        <div style={{ padding: '16px 22px 0', display: 'flex', flexDirection: 'column', gap: 8 }}>
          {friends.map(f => (
            <FriendRow key={f.id} friend={f} accent={accent}
                       onClick={() => onOpenFriend(f)}
                       onNudge={() => onOpenNudge && onOpenNudge(f)} />
          ))}
        </div>
      ) : (
        <div style={{ padding: '12px 22px 0', display: 'flex', flexDirection: 'column', gap: 10 }}>
          {/* Pending share requests */}
          {pendingRequests.length > 0 && (
            <>
              <div style={{
                padding: '12px 4px 4px',
                display: 'flex', alignItems: 'center', gap: 8,
                fontSize: 11, fontWeight: 700, color: TB.ink3,
                letterSpacing: '0.06em', textTransform: 'uppercase',
              }}>
                <span>공유 요청</span>
                <span style={{
                  minWidth: 18, height: 18, padding: '0 5px',
                  borderRadius: 999,
                  background: accent, color: '#FFF',
                  fontSize: 10, fontWeight: 700, letterSpacing: 0,
                  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                }}>{pendingRequests.length}</span>
              </div>
              {pendingRequests.map(req => (
                <ShareRequestCard key={req.id} request={req} accent={accent}
                                   onAccept={() => onAccept && onAccept(req)}
                                   onReject={() => onReject && onReject(req)}
                                   onPreview={() => onOpenReceived && onOpenReceived(req)} />
              ))}
              {receivedList.length > 0 && (
                <div style={{
                  padding: '14px 4px 0',
                  fontSize: 11, fontWeight: 700, color: TB.ink3,
                  letterSpacing: '0.06em', textTransform: 'uppercase',
                }}>받은 주머니</div>
              )}
            </>
          )}

          {/* Received collections list */}
          {receivedList.length === 0 && pendingRequests.length === 0 ? (
            <div style={{
              padding: '40px 18px',
              border: `1px dashed ${TB.hairlineStrong}`,
              borderRadius: 16,
              textAlign: 'center',
              color: TB.ink3, fontSize: 14, letterSpacing: '-0.01em',
            }}>아직 받은 주머니가 없어요</div>
          ) : receivedList.map(r => (
            <ReceivedCollectionRow key={r.id} item={r} accent={accent}
                                   onClick={() => onOpenReceived(r)} />
          ))}
        </div>
      )}
    </div>
  );
}

function FriendRow({ friend, accent, onClick, onNudge }) {
  return (
    <div style={{
      width: '100%',
      background: TB.surface,
      border: `0.5px solid ${TB.hairline}`,
      borderRadius: 14,
      padding: '12px 12px 12px 14px',
      fontFamily: 'inherit',
      display: 'flex', alignItems: 'center', gap: 12,
      WebkitTapHighlightColor: 'transparent',
    }}>
      <button onClick={onClick} style={{
        flex: 1, minWidth: 0,
        display: 'flex', alignItems: 'center', gap: 12,
        padding: 0, background: 'transparent', border: 'none',
        cursor: 'pointer', textAlign: 'left',
        fontFamily: 'inherit',
        WebkitTapHighlightColor: 'transparent',
      }}>
        {window.HamsterAvatar &&
          <window.HamsterAvatar size={44} accent={friend.accent}
                                count={3} face={friend.face} />}
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{
            display: 'flex', alignItems: 'center', gap: 6,
          }}>
            <span style={{
              fontSize: 15, fontWeight: 700, color: TB.ink,
              letterSpacing: '-0.01em',
            }}>{friend.name}</span>
            {friend.recentlyAdded && (
              <span style={{
                fontSize: 9.5, fontWeight: 700,
                padding: '2px 6px', borderRadius: 4,
                background: `${accent}1A`, color: accent,
                letterSpacing: '0.04em',
              }}>NEW</span>
            )}
          </div>
          <div style={{
            marginTop: 3,
            fontSize: 12, color: TB.ink3, letterSpacing: '-0.01em',
          }}>
            {friend.sharedCount > 0 ? (
              <>공유 주머니 <span style={{ fontWeight: 600, color: TB.ink2 }}>{friend.sharedCount}개</span> · </>
            ) : null}
            마지막 활동 {timeAgo(friend.lastActive)}
          </div>
        </div>
      </button>
      <button onClick={(e) => { e.stopPropagation(); onNudge && onNudge(); }} style={{
        width: 36, height: 36, borderRadius: 36,
        background: `${accent}14`,
        border: 'none',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        cursor: 'pointer', flexShrink: 0,
        WebkitTapHighlightColor: 'transparent',
      }} title="넷지 보내기">
        <svg width="18" height="18" viewBox="0 0 20 20" fill="none">
          <path d="M5 11l5-6 5 6" stroke={accent} strokeWidth="1.6"
                strokeLinecap="round" strokeLinejoin="round" fill="none"/>
          <path d="M7 14l3-3 3 3" stroke={accent} strokeWidth="1.6"
                strokeLinecap="round" strokeLinejoin="round" fill="none"/>
        </svg>
      </button>
    </div>
  );
}

function ShareRequestCard({ request, accent, onAccept, onReject, onPreview }) {
  return (
    <div style={{
      width: '100%',
      background: TB.surface,
      border: `1px solid ${request.color}40`,
      borderRadius: 16,
      padding: 14,
      display: 'flex', flexDirection: 'column', gap: 12,
      fontFamily: 'inherit',
      position: 'relative',
      overflow: 'hidden',
    }}>
      {/* Decorative tint */}
      <div style={{
        position: 'absolute', inset: 0,
        background: `linear-gradient(135deg, ${request.color}10 0%, transparent 60%)`,
        pointerEvents: 'none',
      }} />

      {/* Top: sender + meta */}
      <button onClick={onPreview} style={{
        position: 'relative', zIndex: 1,
        background: 'transparent', border: 'none', padding: 0,
        display: 'flex', alignItems: 'flex-start', gap: 11,
        cursor: 'pointer', textAlign: 'left',
        WebkitTapHighlightColor: 'transparent',
      }}>
        <div style={{
          width: 44, height: 44, borderRadius: 12,
          background: `linear-gradient(155deg, ${request.color} 0%, ${shadeHex(request.color, -18)} 100%)`,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          flexShrink: 0,
        }}>
          {request.cover && request.cover.kind === 'icon' && window.CoverIcon &&
            <window.CoverIcon name={request.cover.icon || 'star'} size={22} color="#FFF" />}
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{
            display: 'inline-flex', alignItems: 'center', gap: 5,
            fontSize: 11.5, color: TB.ink3, letterSpacing: '-0.01em',
            marginBottom: 3,
          }}>
            {window.HamsterAvatar &&
              <window.HamsterAvatar size={16} accent={request.fromAccent}
                                    count={3} face={request.fromFace} />}
            <span><span style={{ color: TB.ink, fontWeight: 700 }}>{request.from}</span>님이 보냄</span>
            <span>·</span>
            <span>{timeAgo(request.requestedDays)}</span>
          </div>
          <div style={{
            fontSize: 16, fontWeight: 700, color: TB.ink,
            letterSpacing: '-0.02em', lineHeight: 1.25,
            display: '-webkit-box', WebkitLineClamp: 1, WebkitBoxOrient: 'vertical',
            overflow: 'hidden',
          }}>{request.name}</div>
          <div style={{
            marginTop: 3,
            display: 'inline-flex', alignItems: 'center', gap: 5,
            fontSize: 11.5, color: TB.ink2, letterSpacing: '-0.01em',
          }}>
            <span style={{ fontSize: 12, lineHeight: 1 }}>
              {request.isMultiLang ? '🌐' :
                ({ja:'🇯🇵',es:'🇪🇸',en:'🇺🇸',fr:'🇫🇷',zh:'🇨🇳',th:'🇹🇭',de:'🇩🇪',it:'🇮🇹',vi:'🇻🇳',pt:'🇵🇹',id:'🇮🇩'})[request.primaryLang] || '🌐'}
            </span>
            <span>{request.isMultiLang ? '여러 언어' : request.primaryLangLabel}</span>
            <span>·</span>
            <span style={{ fontWeight: 600 }}>{request.count}개</span>
          </div>
        </div>
      </button>

      {/* Message */}
      {request.message && (
        <div style={{
          position: 'relative', zIndex: 1,
          padding: '10px 12px',
          background: TB.inkOverlaySoft,
          borderRadius: 10,
          fontSize: 12.5, color: TB.ink2,
          letterSpacing: '-0.01em', lineHeight: 1.45,
          fontStyle: 'italic',
        }}>"{request.message}"</div>
      )}

      {/* Actions */}
      <div style={{
        position: 'relative', zIndex: 1,
        display: 'flex', gap: 8,
      }}>
        <button onClick={onReject} style={{
          flex: 1, height: 42, borderRadius: 12,
          background: 'transparent', color: TB.ink2,
          border: `0.5px solid ${TB.hairlineStrong}`,
          fontFamily: 'inherit', fontSize: 14, fontWeight: 500,
          letterSpacing: '-0.01em',
          cursor: 'pointer', WebkitTapHighlightColor: 'transparent',
        }}>거절</button>
        <button onClick={onAccept} style={{
          flex: 2, height: 42, borderRadius: 12,
          background: accent, color: '#FFF',
          border: 'none',
          fontFamily: 'inherit', fontSize: 14, fontWeight: 700,
          letterSpacing: '-0.01em',
          cursor: 'pointer', WebkitTapHighlightColor: 'transparent',
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 5,
        }}>
          <svg width="13" height="13" viewBox="0 0 14 14" fill="none">
            <path d="M3 7.2l2.8 2.8L11 5" stroke="#FFF" strokeWidth="2.2"
                  strokeLinecap="round" strokeLinejoin="round"/>
          </svg>
          수락하고 받기
        </button>
      </div>
    </div>
  );
}

function ReceivedCollectionRow({ item, accent, onClick }) {
  return (
    <button onClick={onClick} style={{
      width: '100%',
      background: TB.surface,
      border: `0.5px solid ${TB.hairline}`,
      borderRadius: 14,
      padding: 6,
      cursor: 'pointer',
      fontFamily: 'inherit',
      textAlign: 'left',
      display: 'flex', alignItems: 'stretch', gap: 12,
      WebkitTapHighlightColor: 'transparent',
      overflow: 'hidden',
      position: 'relative',
    }}>
      {/* Cover block */}
      <div style={{
        position: 'relative',
        width: 64, height: 64, borderRadius: 10,
        overflow: 'hidden', flexShrink: 0,
        background: `linear-gradient(155deg, ${item.color} 0%, ${shadeHex(item.color, -18)} 100%)`,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
      }}>
        {item.cover.kind === 'icon' && window.CoverIcon &&
          <window.CoverIcon name={item.cover.icon || 'star'} size={28} color="#FFF" />}
      </div>

      <div style={{ flex: 1, minWidth: 0,
        display: 'flex', flexDirection: 'column', justifyContent: 'center',
        padding: '4px 4px 4px 0',
      }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 5,
          fontSize: 11, color: TB.ink3, letterSpacing: '-0.01em',
          marginBottom: 3,
        }}>
          {window.HamsterAvatar &&
            <window.HamsterAvatar size={16} accent={item.fromAccent}
                                  count={3} face={item.fromFace} />}
          <span><span style={{ color: TB.ink, fontWeight: 600 }}>{item.from}</span>님이 보냄</span>
          <span>·</span>
          <span>{timeAgo(item.receivedDays)}</span>
        </div>
        <div style={{
          fontSize: 15.5, fontWeight: 700, color: TB.ink,
          letterSpacing: '-0.02em',
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>{item.name}</div>
        <div style={{
          marginTop: 3,
          fontSize: 11.5, color: TB.ink2, letterSpacing: '-0.01em',
        }}>
          <span style={{ fontWeight: 600 }}>{item.count}개</span>
          <span style={{ marginLeft: 8, color: accent, fontWeight: 600 }}>받기 ›</span>
        </div>
      </div>
    </button>
  );
}

function shadeHex(hex, percent) {
  const h = hex.replace('#', '');
  const r = parseInt(h.slice(0, 2), 16);
  const g = parseInt(h.slice(2, 4), 16);
  const b = parseInt(h.slice(4, 6), 16);
  const adj = (n) => Math.max(0, Math.min(255, Math.round(n + (percent / 100) * 255)));
  return '#' + [adj(r), adj(g), adj(b)].map(n => n.toString(16).padStart(2, '0')).join('');
}

// ─────────────────────────────────────────────────────────────
// MeScreen — profile, stats, quota, settings entry
// ─────────────────────────────────────────────────────────────
function MeScreen({ accent, profile, quotaUsed, quotaTotal, dailyCap, todayBoost, streakDays = 14, practiceDays, onEditProfile, onOpenSettings, onOpenNotifications, onOpenHelp, onOpenAbout, onUpgradeQuota }) {
  const totalCards = (window.EXPANDED_CARDS || []).length || 0;
  const remaining = Math.max(0, quotaTotal - quotaUsed);
  const ratio = Math.min(1, quotaUsed / quotaTotal);

  // Hamster tap reactions — clicking the character on the quota widget
  const TAP_REACTIONS = React.useMemo(() => [
    { face: 'wink',   bubble: '윙크 한 번!',     emoji: '😉' },
    { face: 'starry', bubble: '반짝반짝!',       emoji: '✨' },
    { face: 'blush',  bubble: '간지러워…',       emoji: '🥹' },
    { face: 'happy',  bubble: '안녕!',          emoji: '👋' },
    { face: 'wink',   bubble: '오늘도 잘 부탁!',  emoji: '🤝' },
  ], []);
  const [tap, setTap] = React.useState({ face: null, bubble: null, key: 0 });
  const handlePouchTap = () => {
    const idx = tap.key % TAP_REACTIONS.length;
    const r = TAP_REACTIONS[idx];
    setTap({ face: r.face, bubble: r.bubble, key: tap.key + 1 });
  };
  React.useEffect(() => {
    if (!tap.bubble) return;
    const t = setTimeout(() => setTap(s => ({ ...s, face: null, bubble: null })), 1500);
    return () => clearTimeout(t);
  }, [tap.bubble, tap.key]);

  // Cute, context-aware label for the quota widget
  const pouchLabel = quotaUsed === 0 ? '오늘 볼주머니가 비어 있어요'
                  : ratio >= 0.92    ? '오늘 볼주머니가 통통해요'
                  : ratio >= 0.65    ? '오늘 볼주머니가 두둑해지는 중'
                  : ratio >= 0.30    ? '오늘 볼주머니가 채워지는 중'
                  :                    '오늘 볼주머니가 가뿐해요';
  const autoFace = ratio >= 0.85 ? 'sleepy' : ratio >= 0.5 ? 'happy' : 'basic';
  const displayFace = tap.face || autoFace;

  return (
    <div style={{ paddingBottom: TAB_HEIGHT + 30 }}>
      {/* Top bar — sticky */}
      <div style={{
        position: 'sticky', top: 0, zIndex: 30,
        background: TB.bg,
        padding: '54px 22px 12px',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        minHeight: 44,
      }}>
        <div style={{
          fontSize: 24, fontWeight: 700, letterSpacing: '-0.03em',
          color: TB.ink,
        }}>나</div>
        <button onClick={onOpenSettings} style={{
          width: 38, height: 38, borderRadius: 38,
          background: 'transparent', border: 'none', padding: 0,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          cursor: 'pointer',
          WebkitTapHighlightColor: 'transparent',
        }}>
          <svg width="20" height="20" viewBox="0 0 20 20" fill="none">
            <circle cx="10" cy="10" r="2.5" stroke={TB.ink} strokeWidth="1.6"/>
            <path d="M10 1.5v3M10 15.5v3M1.5 10h3M15.5 10h3M3.9 3.9l2.1 2.1M14 14l2.1 2.1M16.1 3.9L14 6M6 14l-2.1 2.1"
                  stroke={TB.ink} strokeWidth="1.6" strokeLinecap="round"/>
          </svg>
        </button>
      </div>

      {/* Hero — compact horizontal */}
      <div style={{
        margin: '14px 22px 0',
        padding: '14px 16px',
        background: TB.surface,
        border: `0.5px solid ${TB.hairline}`,
        borderRadius: 18,
        display: 'flex', alignItems: 'center', gap: 14,
      }}>
        {window.HamsterAvatar &&
          <window.HamsterAvatar size={56} accent={accent}
                                count={3} face={profile?.face || 'basic'} />}
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{
            fontSize: 17, fontWeight: 700, color: TB.ink,
            letterSpacing: '-0.02em', lineHeight: 1.2,
            whiteSpace: 'nowrap',
            overflow: 'hidden', textOverflow: 'ellipsis',
          }}>{profile?.name || '윤재'}</div>
          <div style={{
            marginTop: 3,
            fontSize: 12, color: TB.ink3, letterSpacing: '-0.01em',
            whiteSpace: 'nowrap',
          }}>CheekPouch와 <span style={{ color: TB.ink2, fontWeight: 600 }}>124일</span> 째</div>
        </div>
        <button onClick={onEditProfile} style={{
          height: 30, padding: '0 12px', borderRadius: 999,
          background: 'transparent',
          border: `0.5px solid ${TB.hairlineStrong}`,
          color: TB.ink2,
          fontFamily: 'inherit', fontSize: 12, fontWeight: 500,
          letterSpacing: '-0.01em', cursor: 'pointer',
          flexShrink: 0,
          WebkitTapHighlightColor: 'transparent',
        }}>편집</button>
      </div>

      {/* Stats */}
      <div style={{
        margin: '16px 22px 0',
        display: 'grid', gridTemplateColumns: '1fr 1fr',
        gap: 10,
      }}>
        <StatTile value={totalCards} label="담은 표현"
                  sub="누적" accent={accent} />
        <StatTile value={streakDays} label="연속 학습"
                  sub="일" accent={accent} highlight />
      </div>

      {/* Streak calendar */}
      <StreakCalendar accent={accent} streakDays={streakDays} practiceDays={practiceDays} />

      {/* Quota */}
      <div style={{ padding: '24px 22px 0' }}>
        <div style={{
          padding: '12px 14px',
          background: TB.surface,
          border: `0.5px solid ${TB.hairline}`,
          borderRadius: 16,
          position: 'relative',
          overflow: 'hidden',
        }}>
          {/* Decorative aura behind hamster */}
          <div style={{
            position: 'absolute',
            right: -28, top: '50%',
            transform: 'translateY(-50%)',
            width: 120, height: 120, borderRadius: 120,
            background: `radial-gradient(circle at 30% 40%, ${accent}1A 0%, ${accent}06 55%, transparent 80%)`,
            pointerEvents: 'none',
          }} />

          <div style={{
            position: 'relative',
            display: 'flex', alignItems: 'center', gap: 12,
          }}>
            {/* Hamster — puffs based on quota ratio; tap to react */}
            <button onClick={handlePouchTap}
                    aria-label="볼주머니 친구 쓰다듬기"
                    style={{
              flexShrink: 0, marginLeft: -4,
              background: 'transparent', border: 'none', padding: 0,
              cursor: 'pointer',
              position: 'relative',
              animation: tap.bubble ? `cp-puff 0.55s cubic-bezier(0.4, 1.5, 0.6, 1)` : 'none',
              animationFillMode: 'both',
              WebkitTapHighlightColor: 'transparent',
            }}>
              {window.CheekPouch &&
                <window.CheekPouch count={quotaUsed} max={quotaTotal} accent={accent}
                                   size={62} animateOnChange={true}
                                   face={displayFace} />}
              {tap.bubble && (
                <div key={tap.key} style={{
                  position: 'absolute',
                  left: '100%', top: -4,
                  marginLeft: 6,
                  background: TB.ink, color: '#FFF',
                  fontSize: 10.5, fontWeight: 600,
                  letterSpacing: '-0.01em', whiteSpace: 'nowrap',
                  padding: '5px 9px', borderRadius: 999,
                  boxShadow: '0 4px 12px rgba(31,24,18,0.18)',
                  animation: 'cp-toast-in 220ms cubic-bezier(.2,.7,.2,1) both',
                  pointerEvents: 'none',
                  zIndex: 2,
                }}>
                  <span style={{
                    position: 'absolute', left: -3, top: 12,
                    width: 6, height: 6, transform: 'rotate(45deg)',
                    background: TB.ink,
                  }} />
                  {tap.bubble}
                </div>
              )}
            </button>

            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{
                display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8,
              }}>
                <div style={{ minWidth: 0 }}>
                  <div style={{
                    fontSize: 12, fontWeight: 600, color: TB.ink2,
                    letterSpacing: '-0.01em', whiteSpace: 'nowrap',
                    display: 'inline-flex', alignItems: 'center', gap: 4,
                  }}>
                    {window.SunflowerGlyph && <window.SunflowerGlyph color={accent} />}
                    {pouchLabel}
                  </div>
                  <div style={{ marginTop: 3, whiteSpace: 'nowrap' }}>
                    <span style={{
                      fontSize: 20, fontWeight: 800, color: TB.ink,
                      letterSpacing: '-0.03em',
                      fontVariantNumeric: 'tabular-nums',
                    }}>{quotaUsed}</span>
                    <span style={{
                      fontSize: 13, color: TB.ink2, fontWeight: 500,
                      letterSpacing: '-0.01em',
                    }}> / {quotaTotal}개 <span style={{ color: TB.ink3, fontSize: 11 }}>오늘 모은 씨앗</span></span>
                  </div>
                </div>
                <button onClick={onUpgradeQuota} style={{
                  height: 28, padding: '0 12px', borderRadius: 999,
                  background: accent, color: '#FFF',
                  border: 'none',
                  fontFamily: 'inherit', fontSize: 11.5, fontWeight: 600,
                  letterSpacing: '-0.01em', cursor: 'pointer',
                  display: 'inline-flex', alignItems: 'center', gap: 3,
                  flexShrink: 0,
                  WebkitTapHighlightColor: 'transparent',
                }}>볼주머니 키우기
                  <svg width="6" height="10" viewBox="0 0 8 14" fill="none">
                    <path d="M1.5 1.5L6.5 7L1.5 12.5" stroke="#FFF" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/>
                  </svg>
                </button>
              </div>

              {/* Seed row (replaces flat progress bar) */}
              {(() => {
                const cap = dailyCap || quotaTotal;
                const boost = todayBoost || Math.max(0, quotaTotal - cap);
                const total = cap + boost;
                const seeds = [];
                for (let i = 0; i < cap; i++) {
                  seeds.push({ type: 'daily', filled: i < quotaUsed });
                }
                for (let i = 0; i < boost; i++) {
                  seeds.push({ type: 'boost', filled: (cap + i) < quotaUsed });
                }
                return (
                  <div style={{
                    marginTop: 10,
                    display: 'flex', flexWrap: 'wrap', gap: 4,
                  }}>
                    {seeds.map((s, i) => (
                      window.Seed
                        ? <window.Seed key={i} type={s.type} filled={s.filled} accent={accent} />
                        : null
                    ))}
                  </div>
                );
              })()}
            </div>
          </div>
        </div>
      </div>

      {/* Quick links */}
      <div style={{ padding: '24px 22px 0' }}>
        <div style={{
          padding: '0 6px 8px',
          fontSize: 11, fontWeight: 600, color: TB.ink3,
          letterSpacing: '0.08em', textTransform: 'uppercase',
        }}>설정</div>
        <div style={{
          background: TB.surface,
          border: `0.5px solid ${TB.hairline}`,
          borderRadius: 14,
          overflow: 'hidden',
        }}>
          <MeRow icon={<GearGlyph />}   label="앱 설정"     sub="주 언어 · 테마 · 소리"
                 onClick={onOpenSettings} first />
          <MeRow icon={<BellGlyph />}   label="알림"
                 sub="복습 · 여행 모드"
                 onClick={onOpenNotifications} />
          <MeRow icon={<HelpGlyph />}   label="도움말"
                 sub="자주 묻는 질문"
                 onClick={onOpenHelp} />
          <MeRow icon={<InfoGlyph />}   label="CheekPouch에 대하여"
                 sub="버전 · 팜·개인정보"
                 onClick={onOpenAbout} />
        </div>
      </div>
    </div>
  );
}

function StreakCalendar({ accent, streakDays = 14, practiceDays }) {
  // practiceDays: optional Set of "days-ago" numbers that were practice days.
  // Default: build deterministic plausible set — recent streakDays solid,
  // plus a few earlier scattered.
  const today = new Date();
  const days = practiceDays || (() => {
    const s = new Set();
    for (let i = 0; i < streakDays; i++) s.add(i);
    // scatter earlier
    [streakDays + 2, streakDays + 3, streakDays + 5, streakDays + 8, streakDays + 11, streakDays + 13, streakDays + 18, streakDays + 22, streakDays + 26].forEach(d => s.add(d));
    return s;
  })();

  // Build a 7×5 (35-day) grid ending today, oldest at top-left
  const cells = 35;
  const grid = [];
  for (let i = cells - 1; i >= 0; i--) {
    const d = new Date(today);
    d.setDate(d.getDate() - i);
    grid.push({
      daysAgo: i,
      date: d.getDate(),
      isToday: i === 0,
      practiced: days.has(i),
    });
  }

  const monthLabel = `${today.getMonth() + 1}월`;
  const dayLabels = ['월', '화', '수', '목', '금', '토', '일'];
  // Compute current weekday offset so the last column is "today"
  // Simpler: just lay out chronologically, label by weekday under each col

  return (
    <div style={{ padding: '24px 22px 0' }}>
      <div style={{
        padding: '16px 16px 14px',
        background: TB.surface,
        border: `0.5px solid ${TB.hairline}`,
        borderRadius: 16,
      }}>
        <div style={{
          display: 'flex', alignItems: 'baseline', justifyContent: 'space-between',
          marginBottom: 12,
        }}>
          <div>
            <div style={{
              fontSize: 13, fontWeight: 600, color: TB.ink2,
              letterSpacing: '-0.01em',
            }}>학습 달력</div>
            <div style={{
              marginTop: 3,
              fontSize: 11.5, color: TB.ink3, letterSpacing: '-0.01em',
            }}>최근 5주 · {monthLabel}</div>
          </div>
          <div style={{
            display: 'inline-flex', alignItems: 'center', gap: 5,
            fontSize: 11, color: TB.ink3,
            letterSpacing: '-0.01em',
          }}>
            <span style={{
              width: 9, height: 9, borderRadius: 3,
              background: accent,
            }} />
            <span>학습한 날</span>
          </div>
        </div>

        {/* Grid: 7 cols x 5 rows */}
        <div style={{
          display: 'grid',
          gridTemplateColumns: 'repeat(7, 1fr)',
          gap: 6,
        }}>
          {grid.map((c, i) => {
            // Intensity: today gets ring, practiced gets fill
            const opacity = c.practiced
              ? (c.daysAgo < streakDays ? 1 : 0.55)
              : 0;
            return (
              <div key={i} style={{
                aspectRatio: '1',
                borderRadius: 6,
                background: c.practiced ? accent : 'rgba(60,42,20,0.06)',
                opacity: c.practiced ? opacity : 1,
                border: c.isToday ? `1.5px solid ${TB.ink}` : 'none',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                fontSize: 9.5, fontWeight: 600,
                color: c.practiced ? '#FFF' : TB.ink3,
                letterSpacing: '-0.02em',
                fontVariantNumeric: 'tabular-nums',
                position: 'relative',
              }}>
                {c.date}
              </div>
            );
          })}
        </div>

        {/* Encouragement */}
        <div style={{
          marginTop: 12,
          padding: '8px 10px',
          background: `${accent}10`,
          borderRadius: 8,
          fontSize: 12, color: TB.ink,
          letterSpacing: '-0.01em', lineHeight: 1.4,
          display: 'flex', alignItems: 'center', gap: 8,
        }}>
          <span style={{ fontSize: 14 }}>🔥</span>
          <span>
            <span style={{ fontWeight: 700, color: accent }}>{streakDays}일 연속</span>
            <span style={{ color: TB.ink2 }}> 학습 중이에요. 오늘도 화이팅!</span>
          </span>
        </div>
      </div>
    </div>
  );
}

function quotaBarColor(ratio) {
  // Smooth green → yellow → red gradient based on ratio
  // 0..0.5: green → yellow, 0.5..1: yellow → red
  let r, g, b;
  if (ratio <= 0.5) {
    const t = ratio / 0.5;
    // #4A8A52 (74,138,82) → #D6A53A (214,165,58)
    r = Math.round(74  + (214 - 74)  * t);
    g = Math.round(138 + (165 - 138) * t);
    b = Math.round(82  + (58  - 82)  * t);
  } else {
    const t = (ratio - 0.5) / 0.5;
    // #D6A53A → #B5483C (181,72,60)
    r = Math.round(214 + (181 - 214) * t);
    g = Math.round(165 + (72  - 165) * t);
    b = Math.round(58  + (60  - 58)  * t);
  }
  return `rgb(${r}, ${g}, ${b})`;
}

function StatTile({ value, label, sub, accent, highlight }) {
  return (
    <div style={{
      padding: '14px 16px',
      background: highlight ? `linear-gradient(135deg, ${accent}1A 0%, ${accent}08 100%)` : TB.surface,
      border: highlight ? `0.5px solid ${accent}30` : `0.5px solid ${TB.hairline}`,
      borderRadius: 16,
      overflow: 'hidden',
    }}>
      <div style={{
        fontSize: 12, fontWeight: 600,
        color: highlight ? accent : TB.ink3,
        letterSpacing: '-0.01em',
        whiteSpace: 'nowrap',
      }}>{label}</div>
      <div style={{
        marginTop: 6,
        display: 'flex', alignItems: 'baseline', gap: 4,
        whiteSpace: 'nowrap',
      }}>
        <span style={{
          fontSize: 26, fontWeight: 800, color: TB.ink,
          letterSpacing: '-0.04em', lineHeight: 1,
          fontVariantNumeric: 'tabular-nums',
        }}>{value}</span>
        <span style={{
          fontSize: 12, color: TB.ink2, fontWeight: 500,
          letterSpacing: '-0.01em',
        }}>{sub}</span>
      </div>
    </div>
  );
}

function MeRow({ icon, label, sub, onClick, first }) {
  return (
    <button onClick={onClick} style={{
      width: '100%',
      display: 'flex', alignItems: 'center', gap: 12,
      padding: '13px 14px',
      borderTop: first ? 'none' : `0.5px solid ${TB.hairline}`,
      background: 'transparent', border: 'none',
      cursor: 'pointer', fontFamily: 'inherit',
      textAlign: 'left',
      WebkitTapHighlightColor: 'transparent',
    }}>
      <span style={{
        width: 30, height: 30, borderRadius: 9,
        background: 'rgba(60,42,20,0.06)',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0,
      }}>{icon}</span>
      <span style={{ flex: 1, minWidth: 0 }}>
        <span style={{
          display: 'block',
          fontSize: 15, fontWeight: 500, color: TB.ink,
          letterSpacing: '-0.01em',
        }}>{label}</span>
        {sub && (
          <span style={{
            display: 'block', marginTop: 2,
            fontSize: 12, color: TB.ink3,
            letterSpacing: '-0.01em', lineHeight: 1.4,
          }}>{sub}</span>
        )}
      </span>
      <svg width="7" height="11" viewBox="0 0 8 14" fill="none" style={{ flexShrink: 0 }}>
        <path d="M1.5 1.5L6.5 7L1.5 12.5" stroke={TB.ink3} strokeWidth="1.6"
              strokeLinecap="round" strokeLinejoin="round"/>
      </svg>
    </button>
  );
}

function GearGlyph() {
  return (
    <svg width="16" height="16" viewBox="0 0 18 18" fill="none">
      <circle cx="9" cy="9" r="2.3" stroke={TB.ink} strokeWidth="1.5"/>
      <path d="M9 1.5v2.5M9 14v2.5M1.5 9h2.5M14 9h2.5M3.7 3.7l1.8 1.8M12.5 12.5l1.8 1.8M14.3 3.7l-1.8 1.8M5.5 12.5l-1.8 1.8"
            stroke={TB.ink} strokeWidth="1.5" strokeLinecap="round"/>
    </svg>
  );
}
function BellGlyph() {
  return (
    <svg width="16" height="16" viewBox="0 0 18 18" fill="none">
      <path d="M4 13.5h10l-1-1.5V8a4 4 0 1 0-8 0v4l-1 1.5zM7.5 15.5a1.5 1.5 0 0 0 3 0"
            stroke={TB.ink} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
    </svg>
  );
}
function HelpGlyph() {
  return (
    <svg width="16" height="16" viewBox="0 0 18 18" fill="none">
      <circle cx="9" cy="9" r="7" stroke={TB.ink} strokeWidth="1.5"/>
      <path d="M7 7.2c0-1.1 1-2 2-2s2 .9 2 2c0 1.5-2 1.5-2 3M9 13h.01"
            stroke={TB.ink} strokeWidth="1.5" strokeLinecap="round"/>
    </svg>
  );
}
function InfoGlyph() {
  return (
    <svg width="16" height="16" viewBox="0 0 18 18" fill="none">
      <circle cx="9" cy="9" r="7" stroke={TB.ink} strokeWidth="1.5"/>
      <path d="M9 8.5v4M9 5.5h.01" stroke={TB.ink} strokeWidth="1.5" strokeLinecap="round"/>
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// FriendDetailScreen
// ─────────────────────────────────────────────────────────────
function FriendDetailScreen({ friend, accent, onBack }) {
  const sharedCollections = [
    { name: '오사카 카페 투어', count: 12, color: friend.accent, cover: { kind: 'icon', icon: 'cup' } },
    { name: '오사카 길찾기',     count: 6,  color: friend.accent, cover: { kind: 'icon', icon: 'map' } },
    { name: '간사이 식당 한마디', count: 9, color: friend.accent, cover: { kind: 'icon', icon: 'fork' } },
  ].slice(0, friend.sharedCount);

  return (
    <div style={{ paddingBottom: 60 }}>
      {/* Top bar — sticky */}
      <div style={{
        position: 'sticky', top: 0, zIndex: 30,
        background: TB.bg,
        padding: '54px 14px 8px',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
      }}>
        <button onClick={onBack} style={{
          width: 38, height: 38, borderRadius: 38,
          background: 'transparent', border: 'none', padding: 0,
          display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
          cursor: 'pointer',
          WebkitTapHighlightColor: 'transparent',
        }}>
          <svg width="22" height="22" viewBox="0 0 22 22" fill="none">
            <path d="M14 4L7 11l7 7" stroke={TB.ink} strokeWidth="1.8"
                  strokeLinecap="round" strokeLinejoin="round"/>
          </svg>
        </button>
        <div style={{ width: 38 }} />
      </div>

      {/* Hero */}
      <div style={{
        padding: '14px 22px 0',
        display: 'flex', flexDirection: 'column', alignItems: 'center',
        textAlign: 'center',
      }}>
        {window.HamsterAvatar &&
          <window.HamsterAvatar size={92} accent={friend.accent}
                                count={3} face={friend.face} ring />}
        <div style={{
          marginTop: 14,
          fontSize: 24, fontWeight: 700, color: TB.ink,
          letterSpacing: '-0.03em',
        }}>{friend.name}</div>
        <div style={{
          marginTop: 4,
          fontSize: 13, color: TB.ink2, letterSpacing: '-0.01em',
        }}>마지막 활동 {timeAgo(friend.lastActive)} · 공유 주머니 {friend.sharedCount}개</div>
      </div>

      {/* Shared collections */}
      <div style={{ padding: '28px 22px 0' }}>
        <div style={{
          padding: '0 6px 12px',
          fontSize: 11, fontWeight: 600, color: TB.ink3,
          letterSpacing: '0.08em', textTransform: 'uppercase',
        }}>공유 주머니 · {sharedCollections.length}개</div>
        {sharedCollections.length === 0 ? (
          <div style={{
            padding: '40px 18px',
            border: '1px dashed rgba(60,42,20,0.18)',
            borderRadius: 16,
            textAlign: 'center',
            color: TB.ink3, fontSize: 14, letterSpacing: '-0.01em',
          }}>아직 공유한 주머니가 없어요</div>
        ) : (
          <div style={{
            display: 'grid', gridTemplateColumns: '1fr 1fr',
            gap: 10,
          }}>
            {sharedCollections.map((c, i) => (
              <div key={i} style={{
                position: 'relative',
                background: `linear-gradient(155deg, ${c.color} 0%, ${shadeHex(c.color, -18)} 100%)`,
                borderRadius: 16,
                minHeight: 160,
                padding: '12px 14px',
                display: 'flex', flexDirection: 'column',
                color: '#FFF',
              }}>
                <div style={{
                  height: 22, padding: '0 10px', borderRadius: 999,
                  background: 'rgba(0,0,0,0.18)',
                  display: 'inline-flex', alignItems: 'center', gap: 3,
                  fontSize: 11.5, fontWeight: 600,
                  letterSpacing: '-0.01em', alignSelf: 'flex-start',
                }}>
                  <span>{c.count}</span>
                  <span style={{ opacity: 0.7, fontSize: 10 }}>개</span>
                </div>
                <div style={{
                  flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center',
                }}>
                  {window.CoverIcon &&
                    <window.CoverIcon name={c.cover.icon} size={36} color="#FFF" />}
                </div>
                <div>
                  <div style={{
                    width: 18, height: 1.5, borderRadius: 1,
                    background: 'rgba(255,255,255,0.45)',
                    marginBottom: 6,
                  }} />
                  <div style={{
                    fontSize: 14, fontWeight: 700,
                    letterSpacing: '-0.02em', lineHeight: 1.2,
                  }}>{c.name}</div>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Invite destination glyphs
// ─────────────────────────────────────────────────────────────
function MessageBubbleGlyph({ color = '#FFF' }) {
  return (
    <svg width="17" height="17" viewBox="0 0 22 22" fill="none">
      <path d="M3 7.5a4 4 0 0 1 4-4h8a4 4 0 0 1 4 4v4.5a4 4 0 0 1-4 4H9.2L5.5 19v-3.2A4 4 0 0 1 3 12V7.5z"
            fill={color}/>
    </svg>
  );
}
function KakaoChatGlyph({ color = '#191919' }) {
  return (
    <svg width="17" height="17" viewBox="0 0 22 22" fill="none">
      <path d="M11 4C6.6 4 3 6.9 3 10.5c0 2.3 1.5 4.3 3.8 5.4l-.7 2.7c-.1.3.3.5.5.3l3.2-2.1c.4 0 .8.1 1.2.1 4.4 0 8-2.9 8-6.4S15.4 4 11 4z"
            fill={color}/>
    </svg>
  );
}
function EnvelopeGlyph({ color = '#FFF' }) {
  return (
    <svg width="17" height="17" viewBox="0 0 22 22" fill="none">
      <rect x="3" y="5.5" width="16" height="11" rx="2.2" stroke={color} strokeWidth="1.7" fill="none"/>
      <path d="M3.8 6.5L11 12l7.2-5.5" stroke={color} strokeWidth="1.7"
            strokeLinecap="round" strokeLinejoin="round" fill="none"/>
    </svg>
  );
}
function MoreDotsGlyph() {
  return (
    <svg width="17" height="17" viewBox="0 0 22 22" fill="none">
      <circle cx="5.5" cy="11" r="1.7" fill="currentColor"/>
      <circle cx="11"  cy="11" r="1.7" fill="currentColor"/>
      <circle cx="16.5" cy="11" r="1.7" fill="currentColor"/>
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// InviteSheet
// ─────────────────────────────────────────────────────────────
function InviteSheet({ accent, onClose }) {
  const [copied, setCopied] = React.useState(false);
  const [sentVia, setSentVia] = React.useState(null); // {label, message}
  const code = 'CHK-7K2M';
  const url = `https://cheekpouch.app/i/${code}`;
  const shareMsg = `나랑 같이 CheekPouch 써볼래? 가입하면 우리 둘 다 매일 볼주머니가 +1개씩 영구 증가!\n초대 코드: ${code}\n${url}`;

  const copy = () => {
    if (navigator.clipboard) {
      navigator.clipboard.writeText(`${code}\n${url}`).catch(() => {});
    }
    setCopied(true);
    setTimeout(() => setCopied(false), 1600);
  };

  const flashSent = (label, message) => {
    setSentVia({ label, message });
    setTimeout(() => setSentVia(null), 2200);
  };

  // Try to open an external scheme; if it fails (iframe / no app), fall back to clipboard.
  const openScheme = (href, fallbackLabel, fallbackMsg) => {
    let opened = false;
    try {
      const a = document.createElement('a');
      a.href = href;
      a.rel = 'noopener';
      a.target = '_top';
      document.body.appendChild(a);
      a.click();
      a.remove();
      opened = true;
    } catch (e) { opened = false; }
    if (navigator.clipboard) {
      navigator.clipboard.writeText(shareMsg).catch(() => {});
    }
    flashSent(fallbackLabel, fallbackMsg || (opened ? `${fallbackLabel} 앱을 열었어요` : `초대 메시지를 복사했어요`));
  };

  const sendMessage = () => {
    openScheme(`sms:&body=${encodeURIComponent(shareMsg)}`, '메시지');
  };
  const sendKakao = () => {
    // Real Kakao share needs SDK; for prototype we copy + toast.
    if (navigator.clipboard) {
      navigator.clipboard.writeText(shareMsg).catch(() => {});
    }
    flashSent('카카오톡', '초대 메시지를 복사했어요 — 카톡에 붙여넣어 주세요');
  };
  const sendMail = () => {
    const subject = encodeURIComponent('CheekPouch 초대장');
    const body = encodeURIComponent(shareMsg);
    openScheme(`mailto:?subject=${subject}&body=${body}`, '메일');
  };
  const sendMore = async () => {
    const data = { title: 'CheekPouch 초대', text: shareMsg, url };
    try {
      if (navigator.share && (!navigator.canShare || navigator.canShare(data))) {
        await navigator.share(data);
        flashSent('공유', '초대를 보냈어요');
        return;
      }
    } catch (e) { /* user cancelled or failed */ }
    if (navigator.clipboard) {
      navigator.clipboard.writeText(shareMsg).catch(() => {});
    }
    flashSent('공유', '초대 메시지를 복사했어요');
  };

  const dests = [
    { label: '메시지', bg: '#34C759', icon: <MessageBubbleGlyph color="#FFF" />, onClick: sendMessage },
    { label: '카톡',   bg: '#FEE500', icon: <KakaoChatGlyph color="#191919" />, onClick: sendKakao },
    { label: '메일',   bg: '#0A84FF', icon: <EnvelopeGlyph color="#FFF" />, onClick: sendMail },
    { label: '더보기', bg: 'rgba(60,42,20,0.08)', iconAccent: true, icon: <MoreDotsGlyph />, onClick: sendMore },
  ];

  return (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 200,
      display: 'flex', flexDirection: 'column', justifyContent: 'flex-end',
    }}>
      <div onClick={onClose} style={{
        position: 'absolute', inset: 0,
        background: 'rgba(31, 24, 18, 0.40)',
        animation: 'cp-fade-bg 0.25s ease',
      }} />
      <div style={{
        position: 'relative',
        background: TB.surface,
        borderTopLeftRadius: 26, borderTopRightRadius: 26,
        paddingBottom: 28,
        maxHeight: '88%',
        boxShadow: '0 -8px 32px rgba(31,24,18,0.16)',
        animation: 'cp-sheet-up 0.32s cubic-bezier(0.22, 1, 0.36, 1)',
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{
          width: 38, height: 4.5, borderRadius: 4,
          background: 'rgba(31,24,18,0.18)',
          margin: '8px auto 14px',
        }} />

        <div style={{
          padding: '0 24px 0',
          display: 'flex', flexDirection: 'column', alignItems: 'center',
          textAlign: 'center',
        }}>
          {window.HamsterAvatar &&
            <window.HamsterAvatar size={84} accent={accent} count={6} face="happy" />}
          <div style={{
            marginTop: 14,
            fontSize: 22, fontWeight: 700, color: TB.ink,
            letterSpacing: '-0.03em', lineHeight: 1.15,
            textWrap: 'balance',
          }}>친구를 초대하면<br/>매일 +1개씩 받아요</div>
          <div style={{
            marginTop: 8,
            fontSize: 13.5, color: TB.ink2,
            letterSpacing: '-0.01em', lineHeight: 1.5,
          }}>친구가 CheekPouch에 가입하면<br/>매일 받는 한도가 영구적으로 늘어요</div>
        </div>

        {/* Invite code */}
        <div style={{ padding: '22px 22px 0' }}>
          <div style={{
            padding: '14px 16px',
            background: `${accent}10`,
            border: `1px dashed ${accent}50`,
            borderRadius: 14,
            display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12,
          }}>
            <div style={{ minWidth: 0 }}>
              <div style={{
                fontSize: 10.5, fontWeight: 600, color: accent,
                letterSpacing: '0.08em', textTransform: 'uppercase',
              }}>초대 코드</div>
              <div style={{
                marginTop: 4,
                fontSize: 20, fontWeight: 700, color: TB.ink,
                letterSpacing: '-0.02em',
                fontFamily: 'ui-monospace, SFMono-Regular, monospace',
              }}>{code}</div>
            </div>
            <button onClick={copy} style={{
              height: 36, padding: '0 14px', borderRadius: 999,
              background: copied ? accent : '#FFF',
              color: copied ? '#FFF' : TB.ink,
              border: copied ? 'none' : `0.5px solid ${TB.hairlineStrong}`,
              fontFamily: 'inherit', fontSize: 13, fontWeight: 600,
              letterSpacing: '-0.01em', cursor: 'pointer',
              WebkitTapHighlightColor: 'transparent',
              flexShrink: 0,
            }}>{copied ? '복사됨' : '복사'}</button>
          </div>
        </div>

        {/* Destinations */}
        <div style={{
          padding: '14px 22px 0',
          display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10,
        }}>
          {dests.map(d => (
            <button key={d.label} onClick={d.onClick} style={{
              height: 76, borderRadius: 14,
              background: TB.surface2,
              border: `0.5px solid ${TB.hairline}`,
              display: 'flex', flexDirection: 'column',
              alignItems: 'center', justifyContent: 'center', gap: 6,
              fontFamily: 'inherit', cursor: 'pointer',
              padding: 0,
              WebkitTapHighlightColor: 'transparent',
              transition: 'transform 100ms ease, background 160ms ease',
            }}
            onMouseDown={(e) => e.currentTarget.style.transform = 'scale(0.96)'}
            onMouseUp={(e) => e.currentTarget.style.transform = 'scale(1)'}
            onMouseLeave={(e) => e.currentTarget.style.transform = 'scale(1)'}
            >
              <span style={{
                width: 34, height: 34, borderRadius: 11,
                background: d.iconAccent ? `${accent}14` : d.bg,
                color: d.iconAccent ? accent : '#FFF',
                display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              }}>{d.icon}</span>
              <span style={{
                fontSize: 11, color: TB.ink2,
                letterSpacing: '-0.01em',
              }}>{d.label}</span>
            </button>
          ))}
        </div>

        {/* Inline status feedback */}
        <div style={{
          height: 24, padding: '8px 22px 0',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          {sentVia && (
            <div style={{
              display: 'inline-flex', alignItems: 'center', gap: 6,
              height: 24, padding: '0 12px', borderRadius: 999,
              background: `${accent}1A`, color: accent,
              fontSize: 11.5, fontWeight: 600, letterSpacing: '-0.01em',
              animation: 'cp-toast-in 220ms cubic-bezier(.2,.7,.2,1) both',
            }}>
              <svg width="11" height="11" viewBox="0 0 14 14" fill="none">
                <path d="M3 7.5l2.5 2.5L11 4.5" stroke={accent} strokeWidth="1.8"
                      strokeLinecap="round" strokeLinejoin="round"/>
              </svg>
              {sentVia.message}
            </div>
          )}
        </div>

        <div style={{ padding: '20px 22px 0' }}>
          <button onClick={onClose} style={{
            width: '100%', height: 48, borderRadius: 14,
            background: 'transparent', color: TB.ink,
            border: `1px solid ${TB.hairlineStrong}`,
            fontFamily: 'inherit', fontSize: 15, fontWeight: 500,
            cursor: 'pointer',
            WebkitTapHighlightColor: 'transparent',
          }}>닫기</button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, {
  TabBar, FriendsScreen, MeScreen, FriendDetailScreen, InviteSheet,
  NudgeSheet, NudgeToast,
  TAB_HEIGHT,
  SAMPLE_FRIENDS, RECEIVED_COLLECTIONS, SAMPLE_SHARE_REQUESTS,
});

// ─────────────────────────────────────────────────────────────
// NudgeSheet — send a friendly poke to a friend
// ─────────────────────────────────────────────────────────────
const NUDGE_PRESETS = [
  { id: 'today',    emoji: '👋', label: '오늘 한 장 어때?',         desc: '오늘 씨앗 안 담은 친구에게' },
  { id: 'trip',     emoji: '✈️', label: '여행 D-3, 준비됐어?',      desc: '여행 가는 친구에게' },
  { id: 'review',   emoji: '🔁', label: '복습할 시간이에요',         desc: '한동안 안 본 친구에게' },
  { id: 'share',    emoji: '💌', label: '주머니 하나 받아갈래?',    desc: '내 주머니 공유 의향' },
  { id: 'cheer',    emoji: '🥕', label: '잘하고 있어요!',           desc: '응원 한마디' },
];

function NudgeSheet({ friend, accent, onClose, onSend }) {
  const [picked, setPicked] = React.useState(NUDGE_PRESETS[0].id);
  const [custom, setCustom] = React.useState('');
  const [mode, setMode] = React.useState('preset'); // 'preset' | 'custom'
  const inputRef = React.useRef(null);

  React.useEffect(() => {
    if (mode === 'custom' && inputRef.current) {
      setTimeout(() => inputRef.current.focus(), 80);
    }
  }, [mode]);

  const selected = NUDGE_PRESETS.find(p => p.id === picked);
  const send = () => {
    const text = mode === 'custom' ? custom.trim() : selected.label;
    if (!text) return;
    onSend({ text, emoji: mode === 'custom' ? '✏️' : selected.emoji });
  };
  const canSend = mode === 'preset' ? !!selected : custom.trim().length > 0;

  return (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 200,
      display: 'flex', flexDirection: 'column', justifyContent: 'flex-end',
    }}>
      <div onClick={onClose} style={{
        position: 'absolute', inset: 0,
        background: 'rgba(31, 24, 18, 0.40)',
        animation: 'cp-fade-bg 0.25s ease',
      }} />
      <div style={{
        position: 'relative',
        background: TB.surface,
        borderTopLeftRadius: 26, borderTopRightRadius: 26,
        paddingBottom: 28,
        maxHeight: '90%',
        boxShadow: '0 -8px 32px rgba(31,24,18,0.16)',
        animation: 'cp-sheet-up 0.32s cubic-bezier(0.22, 1, 0.36, 1)',
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{
          width: 38, height: 4.5, borderRadius: 4,
          background: 'rgba(31,24,18,0.18)',
          margin: '8px auto 14px',
        }} />

        {/* Header with target friend */}
        <div style={{
          padding: '0 24px 4px',
          display: 'flex', alignItems: 'center', gap: 12,
        }}>
          {window.HamsterAvatar &&
            <window.HamsterAvatar size={44} accent={friend.accent}
                                  count={3} face={friend.face} />}
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{
              fontSize: 18, fontWeight: 700, color: TB.ink,
              letterSpacing: '-0.02em',
            }}>{friend.name}에게 넛지</div>
            <div style={{
              marginTop: 3,
              fontSize: 12.5, color: TB.ink3, letterSpacing: '-0.01em',
            }}>가볍게 알림을 보내요</div>
          </div>
        </div>

        {/* Mode segments */}
        <div style={{
          margin: '18px 22px 0',
          display: 'flex', gap: 2, padding: 3, borderRadius: 10,
          background: 'rgba(60,42,20,0.06)',
        }}>
          {[
            { value: 'preset', label: '추천 메시지' },
            { value: 'custom', label: '직접 쓰기' },
          ].map(o => {
            const on = mode === o.value;
            return (
              <button key={o.value} onClick={() => setMode(o.value)} style={{
                flex: 1, height: 32, border: 'none', borderRadius: 7,
                background: on ? TB.surface : 'transparent',
                boxShadow: on ? '0 1px 2px rgba(31,24,18,0.08)' : 'none',
                fontFamily: 'inherit', fontSize: 13, fontWeight: 500,
                color: on ? TB.ink : TB.ink2,
                cursor: 'pointer', letterSpacing: '-0.01em',
                WebkitTapHighlightColor: 'transparent',
              }}>{o.label}</button>
            );
          })}
        </div>

        <div style={{ overflowY: 'auto', padding: '14px 22px 8px' }}>
          {mode === 'preset' ? (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
              {NUDGE_PRESETS.map(p => {
                const on = picked === p.id;
                return (
                  <button key={p.id} onClick={() => setPicked(p.id)} style={{
                    padding: '12px 14px',
                    background: on ? `${accent}10` : TB.surface2,
                    border: on ? `1.5px solid ${accent}` : `0.5px solid ${TB.hairline}`,
                    borderRadius: 12,
                    display: 'flex', alignItems: 'center', gap: 12,
                    cursor: 'pointer', fontFamily: 'inherit', textAlign: 'left',
                    WebkitTapHighlightColor: 'transparent',
                  }}>
                    <span style={{
                      width: 36, height: 36, borderRadius: 12,
                      background: on ? `${accent}1F` : 'rgba(60,42,20,0.05)',
                      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                      fontSize: 18,
                      flexShrink: 0,
                    }}>{p.emoji}</span>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{
                        fontSize: 14.5, fontWeight: 600,
                        color: on ? accent : TB.ink,
                        letterSpacing: '-0.01em',
                      }}>{p.label}</div>
                      <div style={{
                        marginTop: 2,
                        fontSize: 11.5, color: TB.ink3, letterSpacing: '-0.01em',
                      }}>{p.desc}</div>
                    </div>
                    {on && (
                      <svg width="18" height="18" viewBox="0 0 18 18" fill="none" style={{ flexShrink: 0 }}>
                        <path d="M4 9.5l3.5 3.5L14 5.5" stroke={accent} strokeWidth="2.2"
                              strokeLinecap="round" strokeLinejoin="round"/>
                      </svg>
                    )}
                  </button>
                );
              })}
            </div>
          ) : (
            <div>
              <textarea
                ref={inputRef}
                value={custom}
                onChange={(e) => setCustom(e.target.value)}
                placeholder="짧은 메시지를 적어주세요"
                maxLength={60}
                style={{
                  width: '100%', minHeight: 100,
                  background: TB.surface2,
                  border: `1px solid ${TB.hairlineStrong}`,
                  borderRadius: 14,
                  padding: 14,
                  fontFamily: 'inherit', fontSize: 15, color: TB.ink,
                  outline: 'none', resize: 'none',
                  letterSpacing: '-0.01em', lineHeight: 1.45,
                  boxSizing: 'border-box',
                }}
              />
              <div style={{
                marginTop: 6,
                fontSize: 11, color: TB.ink3,
                textAlign: 'right',
                fontVariantNumeric: 'tabular-nums',
              }}>{custom.length} / 60</div>
            </div>
          )}
        </div>

        <div style={{ padding: '12px 22px 0', display: 'flex', gap: 10 }}>
          <button onClick={onClose} style={{
            flex: 1, height: 48, borderRadius: 14,
            background: 'transparent', color: TB.ink2,
            border: `1px solid ${TB.hairlineStrong}`,
            fontFamily: 'inherit', fontSize: 15, fontWeight: 500,
            cursor: 'pointer',
            WebkitTapHighlightColor: 'transparent',
          }}>취소</button>
          <button onClick={send} disabled={!canSend} style={{
            flex: 2, height: 48, borderRadius: 14,
            background: canSend ? accent : `${accent}30`,
            color: '#FFF', border: 'none',
            fontFamily: 'inherit', fontSize: 15, fontWeight: 600,
            letterSpacing: '-0.01em',
            cursor: canSend ? 'pointer' : 'default',
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6,
            WebkitTapHighlightColor: 'transparent',
          }}>
            <svg width="14" height="14" viewBox="0 0 16 16" fill="none">
              <path d="M2 8L14 2L11 14L8 9L2 8Z" fill="currentColor" stroke="currentColor"
                    strokeWidth="0.5" strokeLinejoin="round"/>
            </svg>
            넛지 보내기
          </button>
        </div>
      </div>
    </div>
  );
}

// Floating success toast
function NudgeToast({ friendName, message, accent, onClose, title, icon }) {
  React.useEffect(() => {
    const t = setTimeout(onClose, 2400);
    return () => clearTimeout(t);
  }, [onClose]);

  return (
    <div style={{
      position: 'absolute',
      bottom: TAB_HEIGHT + 18,
      left: 22, right: 22,
      zIndex: 300,
      padding: '12px 14px',
      background: TB.toastBg,
      borderRadius: 14,
      display: 'flex', alignItems: 'center', gap: 10,
      boxShadow: '0 8px 28px rgba(31,24,18,0.32)',
      animation: 'cp-toast-in 0.32s cubic-bezier(0.22, 1, 0.36, 1)',
    }}>
      <span style={{
        width: 26, height: 26, borderRadius: 26,
        background: accent,
        color: '#FFF',
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        flexShrink: 0,
      }}>
        {icon || (
          <svg width="13" height="13" viewBox="0 0 14 14" fill="none">
            <path d="M3 7.2l2.8 2.8L11 5" stroke="#FFF" strokeWidth="2.2"
                  strokeLinecap="round" strokeLinejoin="round"/>
          </svg>
        )}
      </span>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          fontSize: 13.5, fontWeight: 600, color: '#FFF',
          letterSpacing: '-0.01em',
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>{title || `${friendName}님에게 넛지를 보냈어요`}</div>
        {message && (
          <div style={{
            marginTop: 2,
            fontSize: 11.5, color: 'rgba(255,255,255,0.66)',
            letterSpacing: '-0.01em',
            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
          }}>{title ? message : `"${message}"`}</div>
        )}
      </div>
    </div>
  );
}
