/* eslint-disable */
// ─────────────────────────────────────────────────────────────
// searchgg · 커뮤니티 (목록 화면)
// 게시판: 자유 / 공략·팁 / 질문 / 파티 모집 — 텍스트 리스트형
// 사이드: 인기글(HOT) · 주간 베스트
// ─────────────────────────────────────────────────────────────
const CMPT = '#48515f';
const CMCH = "'Chakra Petch',sans-serif";

// ── 게시글 더미 데이터 (시드 고정) ──
const CM_BOARDS = ['자유', '공략·팁', '질문', '파티 모집'];
const CM_POSTS = (() => {
  const titles = {
    '자유': ['오늘 제3보급 진짜 미친 매치 했다', '시즌2 보상 다들 받았음?', '요즘 저녁 큐 잡히는 속도 어떰', '복귀했는데 감도 설정 다 까먹음', '클랜전 하다가 현타온 썰', '이번 패치 평가 어떻게 생각함', '10년차 유저인데 아직도 재밌네', '오랜만에 5연승 함 ㅋㅋ', '새벽 매치 분위기 좋아서 글 남김', '내일 점검이라는데 뭐 바뀜?', '신캐 나오면 누구 뽑을 거임', '오늘자 명장면.gif 올림'],
    '공략·팁': ['데드폴 수비 루트 총정리 (시즌2 기준)', '웨어하우스 러시 타이밍 분석', '저감도 vs 고감도 — 결론 정리해줌', '라이플 반동 제어 연습법 공유', '컨테이너시티 스나 포지션 5곳', '클랜 랭크전 픽 우선순위 가이드', '초보가 제일 많이 하는 실수 7가지', '3vs3 맵별 스폰 위치 정리', '에임 워밍업 루틴 추천', '파티 랭크전 콜 사인 정리본'],
    '질문': ['랭크 점수 산정 방식 아시는 분?', '티어 강등 기준이 어떻게 되나요', '클랜 옮기면 클랜전 기록 초기화되나요?', '모니터 144hz 체감 큰가요', '복귀 유저인데 뭐부터 하면 됨?', '계급이랑 티어 차이가 뭔가요', '신고하면 처리 결과 알 수 있나요', '파티 랭크전 듀오 가능한가요', '토너먼트 참가 조건 아시는 분', '전적 갱신이 안 되는데 저만 그런가요'],
    '파티 모집': ['파티 랭크전 같이 하실 분 (골드 이상)', '저녁 9시 클랜전 용병 1명 구해요', '3보급 내전 인원 모집합니다', '주말 토너먼트 팀원 구함 (스나 1)', '심야 듀오 구합니다 — 마스터 부근', '즐겜 파티 상시 모집 중', '음성 가능한 파티 멤버 2명', 'A보급 연습 같이 하실 분', '평일 오후 파티 고정 멤버 구해요', '랭커 도전 듀오 모집 (진지하게)'],
  };
  const nicks = ['독수리오형제', '한밤의저격수', '돌격대장', '연사의신', '클러치킹', '광속에임', '벽뚫는소리', '플래시뱅', '노스코프', '리코일제로', '소음기장착', '검은표범', '강철멘탈', '야시경', '엄폐엄폐', '침착한손', '스나는예술', '원피스원킬'];
  const out = [];
  let id = 0;
  CM_BOARDS.forEach((board, bi) => {
    titles[board].forEach((title, ti) => {
      const seed = (bi * 131 + ti * 17 + title.length * 7) % 9973;
      const hours = 1 + (seed % 70);
      out.push({
        id: ++id, board, title,
        author: nicks[(seed + bi) % nicks.length],
        time: hours < 24 ? `${hours}시간 전` : `${Math.floor(hours / 24)}일 전`,
        hoursAgo: hours,
        views: 120 + (seed % 4200),
        cmt: seed % 46,
        up: seed % 88,
        hot: seed % 5 === 0,
        hasImage: seed % 3 === 0,
        party: board === '파티 모집' ? {
          ptype: ['클랜전', '파티 랭크전', '클랜 랭크전', '토너먼트', '생존', '기타'][seed % 6],
          voice: seed % 3 !== 0,
        } : null,
      });
    });
  });
  return out.sort((a, b) => a.hoursAgo - b.hoursAgo);
})();

// ── 고정 공지 ──
const CM_NOTICES = [
  { title: '커뮤니티 이용 규칙 안내 — 비방·도배·정치 글 제재', time: '운영팀' },
  { title: '파티 모집 글은 파티 모집 게시판에만 작성해주세요', time: '운영팀' },
];

// 파티 모집 유형
const CM_PARTY_TYPES = ['클랜전', '파티 랭크전', '클랜 랭크전', '토너먼트', '생존', '기타'];
// 파티 모집 조건 → 배지 라벨 배열
function cmPartyBadges(party) {
  return [party.ptype, party.voice ? '보이스 채팅 필수' : null].filter(Boolean);
}

// 개념글 기준 추천 수
const CM_BEST_UP = 40;

// 서든어택 계정 인증 여부 (닉네임 시드 고정)
function cmVerified(name) {
  if (!name) return false;
  if (window.SA && window.SA.me && name === window.SA.me.name) return true;
  let s = 0;
  for (let i = 0; i < name.length; i++) s = (s + name.charCodeAt(i) * (i + 1)) % 997;
  return s % 3 !== 0; // 약 2/3 인증
}
// 인증 배지 (인증=서든 마크 / 미인증=표시 없음)
function CmVerifiedTag({ name, size = 13 }) {
  if (!cmVerified(name)) return null;
  return (
    <span title="서든어택 계정 인증 유저" style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: size, height: size, borderRadius: '50%', background: CMPT, flexShrink: 0 }}>
      <svg width={size * 0.68} height={size * 0.68} viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="3.4" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5" /></svg>
    </span>
  );
}
function CmAuthor({ name, style }) {
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, minWidth: 0 }}>
      <span style={{ ...style, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{name}</span>
      <CmVerifiedTag name={name} />
    </span>
  );
}

// ── 글 상세 더미 (본문·댓글, 시드 고정) ──
const CM_BODIES = {
  '자유': '오늘 매치 돌리면서 느낀 점 적어봅니다.\n\n요즘 큐 잡히는 속도도 그렇고 전반적인 매치 퀄리티가 시즌 초반보다 확실히 좋아진 느낌이에요. 다들 체감 어떠신지 궁금합니다.\n\n댓글로 의견 남겨주세요!', '공략·팁': '직접 테스트해보고 정리한 내용입니다.\n\n1. 진입 타이밍은 소리 정보가 제일 중요합니다. 발소리 출력을 충분히 키우세요.\n2. 교전 전에 미니맵으로 아군 위치를 확인하는 습관을 들이면 생존율이 크게 올라갑니다.\n3. 마지막으로, 장시간 연승보다 짧게 끊어서 집중하는 게 에임 유지에 좋았습니다.\n\n궁금한 점은 댓글로 물어보세요.', '질문': '검색해봐도 정확한 내용이 안 나와서 질문 남깁니다.\n\n아시는 분 계시면 답변 부탁드려요. 미리 감사합니다!', '파티 모집': '안녕하세요, 글 제목 그대로 함께하실 분 찾습니다.\n\n· 매너 좋으신 분이면 실력 무관\n· 저녁 시간대 위주로 활동합니다\n\n댓글이나 쪽지 주세요!',
};
const CM_CMT_TEXTS = ['완전 공감합니다 ㅋㅋ', '좋은 글 감사합니다. 추천 누르고 갑니다', '이거 진짜 유용하네요. 저장해둡니다', '저는 생각이 좀 다른데... 그래도 잘 봤습니다', '댓글 보고 바로 해봤는데 효과 있음', '이런 글 많이 올라오면 좋겠어요', '쪽지 보냈습니다!', '오 나도 어제 비슷한 경험 함', '정리 깔낁하네요 잘 읽었습니다', '이거 때문에 요즘 매치 분위기 좋아짐'];
const CM_CMT_NICKS = ['안개손절이', '플래그팔로우', '리스폰지옥', '점수지키미', '안전제일', '한발더', '에임수엽', '무릎샇소리'];
function cmDetail(p) {
  const seed = (p.id * 37) % 9973;
  const n = 2 + (seed % 5);
  const comments = [];
  for (let i = 0; i < n; i++) {
    comments.push({
      author: CM_CMT_NICKS[(seed + i * 3) % CM_CMT_NICKS.length],
      text: CM_CMT_TEXTS[(seed + i * 5) % CM_CMT_TEXTS.length],
      time: `${1 + ((seed + i * 7) % 20)}시간 전`,
      up: (seed + i * 11) % 18,
      replies: i === 0 ? [{ author: CM_CMT_NICKS[(seed + 5) % CM_CMT_NICKS.length], text: '맞아요, 저도 비슷하게 느꼈습니다.', time: `${1 + (seed % 12)}시간 전` }] : [],
    });
  }
  return { body: p.body || CM_BODIES[p.board], comments };
}

// ── 목록 행 ──
function CmRow({ p, zebra, onOpen }) {
  return (
    <div onClick={() => onOpen && onOpen(p)} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 14px', background: zebra ? '#fbfbfc' : '#fff', borderBottom: '1px solid #eef0f2', cursor: 'pointer' }}>
      <span style={{ flexShrink: 0, fontSize: 10.5, fontWeight: 700, padding: '1px 7px', borderRadius: 4, background: '#f1f3f5', border: '1px solid var(--line)', color: '#5a5f66', minWidth: 44, textAlign: 'center' }}>{p.board}</span>
      <span style={{ flex: 1, minWidth: 0, display: 'flex', alignItems: 'center', gap: 6 }}>
        <span style={{ minWidth: 0, flexShrink: 1, fontSize: 13.5, lineHeight: 1.3, color: '#33373d', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.title}</span>
        {p.hasImage && (
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="var(--t3)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }} title="사진 포함">
            <rect x="3" y="3" width="18" height="18" rx="2" /><circle cx="8.5" cy="8.5" r="1.5" /><path d="M21 15l-5-5L5 21" />
          </svg>
        )}
        {p.cmt > 0 && <span style={{ flexShrink: 0, fontFamily: CMCH, fontSize: 11.5, lineHeight: 1, fontWeight: 700, color: CMPT }}>[{p.cmt}]</span>}
        {p.hot && <span style={{ flexShrink: 0, fontFamily: CMCH, fontSize: 9.5, lineHeight: 1, fontWeight: 800, color: '#b23b3b' }}>HOT</span>}
        {p.party && (
          <span style={{ flexShrink: 0, display: 'inline-flex', alignItems: 'center', gap: 4 }}>
            {cmPartyBadges(p.party).slice(0, 3).map((b) => (
              <span key={b} style={{ display: 'inline-flex', alignItems: 'center', height: 18, fontSize: 9.5, fontWeight: 700, lineHeight: 1, color: 'var(--t2)', border: '1px solid var(--line2)', borderRadius: 3, padding: '0 5px', boxSizing: 'border-box' }}>{b}</span>
            ))}
          </span>
        )}
      </span>
      <span style={{ flexShrink: 0, fontFamily: CMCH, fontSize: 11, width: 52, textAlign: 'right', color: p.up >= CM_BEST_UP ? CMPT : 'var(--t3)', fontWeight: p.up >= CM_BEST_UP ? 700 : 400 }}>추천 {p.up}</span>
      <span style={{ flexShrink: 0, width: 92, display: 'flex', justifyContent: 'flex-end' }}><CmAuthor name={p.author} style={{ fontSize: 12, color: 'var(--t2)' }} /></span>
      <span style={{ flexShrink: 0, fontSize: 11, color: 'var(--t3)', width: 56, textAlign: 'right' }}>{p.time}</span>
      <span style={{ flexShrink: 0, fontFamily: CMCH, fontSize: 11, color: 'var(--t3)', width: 52, textAlign: 'right' }}>{window.SA.fmt(p.views)}</span>
    </div>
  );
}

// ── 사이드 위젯 ──
function CmSidePanel({ title, en, posts, valueOf, onOpen }) {
  return (
    <Panel title={title} en={en} bodyPad="4px 0 6px">
      {posts.map((p, i) => (
        <div key={p.id} onClick={() => onOpen && onOpen(p)} style={{ display: 'flex', alignItems: 'center', gap: 9, padding: '9px 14px', borderBottom: i < posts.length - 1 ? '1px solid #f1f2f4' : 'none', cursor: 'pointer' }}>
          <span style={{ width: 14, textAlign: 'center', fontFamily: CMCH, fontWeight: 700, fontSize: 12.5, lineHeight: 1, color: i < 3 ? CMPT : 'var(--t3)', flexShrink: 0 }}>{i + 1}</span>
          <span style={{ flex: 1, minWidth: 0, fontSize: 12.5, lineHeight: 1.3, color: '#33373d', fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.title}</span>
          <span style={{ flexShrink: 0, fontFamily: CMCH, fontSize: 10.5, lineHeight: 1, color: 'var(--t3)', whiteSpace: 'nowrap' }}>{valueOf(p)}</span>
        </div>
      ))}
    </Panel>
  );
}

// ── 글 상세 ──
function CmPostDetail({ p, onBack }) {
  const d = React.useMemo(() => cmDetail(p), [p.id]);
  const [comments, setComments] = React.useState(d.comments);
  const [draft, setDraft] = React.useState('');
  const [up, setUp] = React.useState(p.up);
  const [voted, setVoted] = React.useState(0); // 0 없음 / 1 추천 / -1 비추
  React.useEffect(() => { setComments(d.comments); setDraft(''); setUp(p.up); setVoted(0); setCmtVoted({}); }, [p.id]);
  const vote = (v) => {
    if (voted === v) { setVoted(0); setUp(up - v); return; }
    setUp(up - voted + v);
    setVoted(v);
  };
  const delCmt = (i) => setComments(comments.map((c, idx) => idx === i ? { ...c, deleted: true } : c));
  const post = () => {
    const text = draft.trim();
    if (!text) return;
    setComments([...comments, { author: window.SA.me.name, text, time: '방금 전', up: 0, replies: [] }]);
    setDraft('');
  };
  const [replyAt, setReplyAt] = React.useState(-1);
  const [replyDraft, setReplyDraft] = React.useState('');
  const [cmtVoted, setCmtVoted] = React.useState({});
  const voteCmt = (i) => setCmtVoted((v) => ({ ...v, [i]: !v[i] }));
  const postReply = (ci) => {
    const text = replyDraft.trim();
    if (!text) return;
    setComments(comments.map((c, idx) => idx === ci ? { ...c, replies: [...(c.replies || []), { author: window.SA.me.name, text, time: '방금 전' }] } : c));
    setReplyDraft('');
    setReplyAt(-1);
  };
  return (
    <div style={{ background: '#fff', border: '1px solid var(--line)', borderRadius: 8, overflow: 'hidden' }}>
      {/* 상단 */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 14px', borderBottom: '1px solid var(--line)' }}>
        <button onClick={onBack} style={{ display: 'flex', alignItems: 'center', gap: 4, border: '1px solid var(--line2)', background: '#fff', borderRadius: 6, padding: '6px 12px', cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 12, color: 'var(--t2)' }}>
          <Icon name="chevL" size={13} stroke="var(--t2)" /> 목록
        </button>
        <span style={{ fontSize: 10.5, fontWeight: 700, padding: '1px 7px', borderRadius: 4, background: '#f1f3f5', border: '1px solid var(--line)', color: '#5a5f66' }}>{p.board}</span>
      </div>

      {/* 제목 + 메타 */}
      <div style={{ padding: '16px 18px 14px', borderBottom: '1px solid var(--line)' }}>
        <h2 style={{ margin: 0, fontSize: 19, fontWeight: 800, color: 'var(--ink)', letterSpacing: '-.3px', lineHeight: 1.4 }}>{p.title}</h2>
        <div style={{ marginTop: 9, display: 'flex', alignItems: 'center', gap: 8, fontSize: 12, color: 'var(--t3)', flexWrap: 'wrap' }}>
          <CmAuthor name={p.author} style={{ fontWeight: 700, color: 'var(--t2)' }} />
          <span>·</span><span>{p.time}</span>
          <span>·</span><span>조회 <b style={{ fontFamily: CMCH, color: 'var(--t2)' }}>{window.SA.fmt(p.views)}</b></span>
          <span>·</span><span>추천 <b style={{ fontFamily: CMCH, color: up >= CM_BEST_UP ? CMPT : 'var(--t2)' }}>{up}</b></span>
        </div>
        {p.party && (
          <div style={{ marginTop: 11, display: 'flex', gap: 6 }}>
            {cmPartyBadges(p.party).map((b) => (
              <span key={b} style={{ display: 'inline-flex', alignItems: 'center', height: 22, fontSize: 11, fontWeight: 700, color: 'var(--t2)', border: '1px solid var(--line2)', borderRadius: 4, padding: '0 8px' }}>{b}</span>
            ))}
          </div>
        )}
      </div>

      {/* 본문 */}
      <div style={{ padding: '18px 18px 8px', fontSize: 14, lineHeight: 1.8, color: '#33373d', whiteSpace: 'pre-line' }}>{d.body}</div>

      {/* 추천/비추 */}
      <div style={{ display: 'flex', justifyContent: 'center', gap: 8, padding: '16px 0 20px' }}>
        <button onClick={() => vote(1)} style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '9px 18px', borderRadius: 7, cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 13,
          border: `1px solid ${voted === 1 ? CMPT : 'var(--line2)'}`, background: voted === 1 ? CMPT : '#fff', color: voted === 1 ? '#fff' : 'var(--t2)' }}>
          ▲ 추천 <span style={{ fontFamily: CMCH }}>{up}</span>
        </button>
        <button onClick={() => vote(-1)} style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '9px 18px', borderRadius: 7, cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 13,
          border: `1px solid ${voted === -1 ? '#b23b3b' : 'var(--line2)'}`, background: voted === -1 ? '#b23b3b' : '#fff', color: voted === -1 ? '#fff' : 'var(--t2)' }}>
          ▼ 비추
        </button>
      </div>

      {/* 댓글 */}
      <div style={{ borderTop: '1px solid var(--line)', padding: '14px 18px 18px' }}>
        <div style={{ fontSize: 13, fontWeight: 800, color: 'var(--ink)', marginBottom: 10 }}>댓글 <span style={{ fontFamily: CMCH, color: CMPT }}>{comments.length}</span></div>
        {comments.map((c, i) => (
          <div key={i} style={{ display: 'flex', gap: 9, padding: '10px 0', borderTop: i ? '1px solid #f1f2f4' : 'none' }}>
            <div style={{ width: 28, height: 28, borderRadius: '50%', background: '#eef0f2', color: '#7a8089', display: 'grid', placeItems: 'center', fontWeight: 700, fontSize: 12, flexShrink: 0, opacity: c.deleted ? .5 : 1 }}>{c.deleted ? '–' : c.author.slice(0, 1)}</div>
            <div style={{ flex: 1, minWidth: 0 }}>
              {c.deleted ? (
                <div style={{ fontSize: 13, color: 'var(--t3)', fontStyle: 'italic', padding: '5px 0' }}>삭제된 댓글입니다.</div>
              ) : (
              <React.Fragment>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 7 }}>
                <CmAuthor name={c.author} style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--ink)' }} />
                <span style={{ fontSize: 11, color: 'var(--t3)' }}>{c.time}</span>
                <button onClick={() => { setReplyAt(replyAt === i ? -1 : i); setReplyDraft(''); }} style={{ border: 'none', background: 'transparent', cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 11, color: CMPT, padding: 0 }}>
                  {replyAt === i ? '취소' : '답글'}
                </button>
                {c.author === window.SA.me.name && (
                  <button onClick={() => delCmt(i)} style={{ border: 'none', background: 'transparent', cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 11, color: '#b23b3b', padding: 0 }}>삭제</button>
                )}
                <button onClick={() => voteCmt(i)} title="댓글 추천" style={{ marginLeft: 'auto', display: 'inline-flex', alignItems: 'center', gap: 4, border: `1px solid ${cmtVoted[i] ? CMPT : 'var(--line2)'}`, background: cmtVoted[i] ? CMPT : '#fff', color: cmtVoted[i] ? '#fff' : 'var(--t3)', borderRadius: 5, padding: '3px 8px', cursor: 'pointer', fontFamily: CMCH, fontSize: 10.5, fontWeight: 700 }}>
                  ▲ {c.up + (cmtVoted[i] ? 1 : 0)}
                </button>
              </div>
              <div style={{ fontSize: 13, color: '#3a4049', marginTop: 3, lineHeight: 1.55 }}>{c.text}</div>
              </React.Fragment>
              )}

              {/* 답글 목록 */}
              {(c.replies || []).map((rp, j) => (
                <div key={j} style={{ display: 'flex', gap: 9, marginTop: 13, paddingLeft: 10, borderLeft: `2px solid ${CMPT}33` }}>
                  <div style={{ width: 28, height: 28, borderRadius: '50%', background: `${CMPT}1c`, color: CMPT, display: 'grid', placeItems: 'center', fontWeight: 800, fontSize: 12, flexShrink: 0 }}>{rp.author.slice(0, 1)}</div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ display: 'flex', alignItems: 'baseline', gap: 7 }}>
                      <CmAuthor name={rp.author} style={{ fontSize: 12.5, fontWeight: 700, color: 'var(--ink)' }} />
                      <span style={{ fontSize: 11, color: 'var(--t3)' }}>{rp.time}</span>
                    </div>
                    <div style={{ fontSize: 13, color: '#3a4049', marginTop: 3, lineHeight: 1.55 }}>{rp.text}</div>
                  </div>
                </div>
              ))}

              {/* 답글 입력 */}
              {replyAt === i && (
                <div style={{ display: 'flex', gap: 7, marginTop: 13, paddingLeft: 10, borderLeft: `2px solid ${CMPT}33` }}>
                  <input autoFocus value={replyDraft} onChange={(e) => setReplyDraft(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') postReply(i); }} placeholder="답글을 남겨보세요"
                    style={{ flex: 1, minWidth: 0, border: '1px solid var(--line2)', borderRadius: 6, padding: '7px 10px', fontSize: 12.5, fontFamily: "'Pretendard',sans-serif", outline: 'none' }} />
                  <button onClick={() => postReply(i)} disabled={!replyDraft.trim()} style={{ padding: '0 13px', borderRadius: 6, border: 'none', background: replyDraft.trim() ? CMPT : '#c4c8ce', color: '#fff', fontWeight: 700, fontSize: 11.5, cursor: replyDraft.trim() ? 'pointer' : 'not-allowed', fontFamily: "'Pretendard',sans-serif", flexShrink: 0 }}>등록</button>
                </div>
              )}
            </div>
          </div>
        ))}
        <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
          <input value={draft} onChange={(e) => setDraft(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') post(); }} placeholder="댓글을 남겨보세요"
            style={{ flex: 1, minWidth: 0, border: '1px solid var(--line2)', borderRadius: 6, padding: '10px 12px', fontSize: 13, fontFamily: "'Pretendard',sans-serif", outline: 'none' }} />
          <button onClick={post} disabled={!draft.trim()} style={{ padding: '0 18px', borderRadius: 6, border: 'none', background: draft.trim() ? CMPT : '#c4c8ce', color: '#fff', fontWeight: 700, fontSize: 13, cursor: draft.trim() ? 'pointer' : 'not-allowed', fontFamily: "'Pretendard',sans-serif", flexShrink: 0 }}>등록</button>
        </div>
      </div>
    </div>
  );
}

// ── 글쓰기 화면 (일반 / 파티 모집) ──
function CmWrite({ initialBoard, onCancel, onSubmit }) {
  const [board, setBoard] = React.useState(initialBoard && initialBoard !== '전체' ? initialBoard : '자유');
  const [title, setTitle] = React.useState('');
  const [body, setBody] = React.useState('');
  const [hasImage, setHasImage] = React.useState(false);
  const fileRef = React.useRef(null);
  // 파티 모집 전용
  const [ptype, setPtype] = React.useState(CM_PARTY_TYPES[0]);
  const [voice, setVoice] = React.useState(true);

  const isParty = board === '파티 모집';
  const valid = title.trim() && body.trim();
  const label = { fontSize: 12, fontWeight: 700, color: 'var(--t2)', marginBottom: 7 };
  const chip = (on) => ({ padding: '6px 12px', borderRadius: 5, border: `1px solid ${on ? 'var(--ink)' : 'var(--line2)'}`, cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 12, background: on ? 'var(--ink)' : '#fff', color: on ? '#fff' : 'var(--t2)' });
  const inputBase = { width: '100%', border: '1px solid var(--line2)', borderRadius: 7, padding: '10px 12px', fontSize: 13.5, fontFamily: "'Pretendard',sans-serif", color: 'var(--ink)', outline: 'none', boxSizing: 'border-box' };

  const submit = () => {
    if (!valid) return;
    onSubmit({
      board, title: title.trim(),
      author: window.SA.me.name, time: '방금 전', hoursAgo: 0,
      views: 1, cmt: 0, up: 0, hot: false, hasImage,
      body: body.trim(),
      party: isParty ? { ptype, voice } : null,
    });
  };

  return (
    <div style={{ background: '#fff', border: '1px solid var(--line)', borderRadius: 8, overflow: 'hidden' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '13px 16px', borderBottom: '1px solid var(--line)' }}>
        <span style={{ fontSize: 15.5, fontWeight: 800, color: 'var(--ink)' }}>글쓰기</span>
        <button onClick={onCancel} style={{ border: '1px solid var(--line2)', background: '#fff', borderRadius: 6, padding: '6px 12px', cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 12, color: 'var(--t2)' }}>목록</button>
      </div>

      <div style={{ padding: '18px 18px 20px' }}>
        {/* 게시판 */}
        <div style={{ marginBottom: 16 }}>
          <div style={label}>게시판</div>
          <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
            {CM_BOARDS.map((b) => {
              const on = board === b;
              return <button key={b} onClick={() => setBoard(b)} style={{ padding: '7px 14px', borderRadius: 20, cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 12.5, border: `1px solid ${on ? CMPT : 'var(--line2)'}`, background: on ? CMPT : '#fff', color: on ? '#fff' : 'var(--t2)' }}>{b}</button>;
            })}
          </div>
        </div>

        {/* 제목 */}
        <div style={{ marginBottom: 16 }}>
          <div style={label}>제목</div>
          <input value={title} onChange={(e) => setTitle(e.target.value)} placeholder={isParty ? '예: 저녁 9시 파티 랭크전 같이 하실 분' : '제목을 입력하세요'} style={inputBase} />
        </div>

        {/* 모집 유형 */}
        {isParty && (
          <div style={{ marginBottom: 16 }}>
            <div style={label}>모집 유형</div>
            <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
              {CM_PARTY_TYPES.map((t) => (
                <button key={t} onClick={() => setPtype(t)} style={chip(ptype === t)}>{t}</button>
              ))}
            </div>
          </div>
        )}

        {/* 참여 조건 */}
        {isParty && (
          <div style={{ marginBottom: 16 }}>
            <div style={label}>참여 조건</div>
            <button onClick={() => setVoice((v) => !v)} style={chip(voice)}>보이스 채팅 필수</button>
          </div>
        )}

        {/* 내용 */}
        <div style={{ marginBottom: 14 }}>
          <div style={label}>내용</div>
          <textarea value={body} onChange={(e) => setBody(e.target.value)} rows={10} placeholder={isParty ? '활동 시간대, 분위기, 디스코드/오픈카톡 연락 방법 등을 적어주세요.' : '내용을 입력하세요.'} style={{ ...inputBase, resize: 'vertical', lineHeight: 1.7 }} />
        </div>

        {/* 사진 첨부 */}
        <input ref={fileRef} type="file" accept="image/*" style={{ display: 'none' }} onChange={(e) => { if (e.target.files && e.target.files.length) setHasImage(true); e.target.value = ''; }} />
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 18 }}>
          <button onClick={() => fileRef.current && fileRef.current.click()} style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '8px 13px', borderRadius: 7, cursor: 'pointer', background: '#fff', border: '1px dashed var(--line2)', color: 'var(--t2)', fontWeight: 700, fontSize: 12, fontFamily: "'Pretendard',sans-serif" }}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" /><circle cx="8.5" cy="8.5" r="1.5" /><path d="M21 15l-5-5L5 21" /></svg>
            사진 첨부
          </button>
          {hasImage && (
            <span style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12, color: 'var(--t2)', fontWeight: 600 }}>
              사진 1장 첨부됨
              <button onClick={() => setHasImage(false)} style={{ border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--t3)', fontSize: 14, padding: 0 }}>×</button>
            </span>
          )}
        </div>

        {/* 버튼 */}
        <div style={{ display: 'flex', gap: 10, borderTop: '1px solid var(--line)', paddingTop: 16 }}>
          <button onClick={onCancel} style={{ flex: 1, padding: '12px 0', borderRadius: 7, border: '1px solid var(--line2)', background: '#fff', color: '#3a4049', fontWeight: 700, fontSize: 14, cursor: 'pointer', fontFamily: "'Pretendard',sans-serif" }}>취소</button>
          <button onClick={submit} disabled={!valid} style={{ flex: 2, padding: '12px 0', borderRadius: 7, border: 'none', background: valid ? CMPT : '#c4c8ce', color: '#fff', fontWeight: 700, fontSize: 14, cursor: valid ? 'pointer' : 'not-allowed', fontFamily: "'Pretendard',sans-serif" }}>등록하기</button>
        </div>
      </div>
    </div>
  );
}

// ── 커뮤니티 화면 ──
function CommunityScreen({ onClose, onLogin, onClan, onCommunity }) {
  const [per, setPer] = React.useState(15);
  const [board, setBoard] = React.useState('전체');
  const [ptypeF, setPtypeF] = React.useState('전체');
  const [voiceF, setVoiceF] = React.useState('전체');
  const [q, setQ] = React.useState('');
  const [qScope, setQScope] = React.useState('제목');
  const [page, setPage] = React.useState(1);
  const [view, setView] = React.useState(null);
  const [writing, setWriting] = React.useState(false);
  const [extra, setExtra] = React.useState([]); // 새로 쓴 글

  const allPosts = [...extra, ...CM_POSTS];
  let list = board === '전체' ? allPosts : allPosts.filter((p) => p.board === board);
  if (board === '파티 모집') {
    if (ptypeF !== '전체') list = list.filter((p) => p.party && p.party.ptype === ptypeF);
    if (voiceF !== '전체') list = list.filter((p) => p.party && (voiceF === '필수' ? p.party.voice : !p.party.voice));
  }
  if (q.trim()) {
    const k = q.trim();
    list = list.filter((p) =>
      qScope === '제목' ? p.title.includes(k)
      : qScope === '작성자' ? p.author.includes(k)
      : (CM_BODIES[p.board] || '').includes(k)
    );
  }
  const totalPages = Math.max(1, Math.ceil(list.length / per));
  const cur = Math.min(page, totalPages);
  const rows = list.slice((cur - 1) * per, cur * per);
  const goPage = (n) => setPage(Math.max(1, Math.min(totalPages, n)));

  const hot = [...CM_POSTS].sort((a, b) => b.views - a.views).slice(0, 5);
  const best = [...CM_POSTS].sort((a, b) => b.up - a.up).slice(0, 5);

  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 200, background: 'var(--bg2)', display: 'flex', flexDirection: 'column', animation: 'sgFade .22s ease' }}>
      <window.Nav active="커뮤니티" onLogin={onLogin} onClan={onClan} />
      <div style={{ flex: 1, overflowY: 'auto' }}>
        <div style={{ maxWidth: 1180, margin: '0 auto', padding: '24px 28px 46px' }}>
          {/* 타이틀 + 검색 */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 16, flexWrap: 'wrap' }}>
            <div>
              <div style={{ fontFamily: CMCH, fontSize: 10.5, fontWeight: 700, letterSpacing: '2.2px', color: 'var(--t3)' }}>COMMUNITY</div>
              <h1 style={{ margin: '3px 0 0', fontSize: 24, fontWeight: 800, color: 'var(--ink)', letterSpacing: '-.4px' }}>커뮤니티</h1>
            </div>
            <div style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 8 }}>
              <select value={qScope} onChange={(e) => { setQScope(e.target.value); setPage(1); }} style={{ fontFamily: "'Pretendard',sans-serif", fontSize: 12.5, fontWeight: 700, color: 'var(--ink)', border: '1px solid var(--line2)', borderRadius: 7, padding: '9px 10px', background: '#fff', cursor: 'pointer' }}>
                {['제목', '작성자', '내용'].map((s) => <option key={s} value={s}>{s}</option>)}
              </select>
              <div style={{ position: 'relative', width: 250 }}>
                <span style={{ position: 'absolute', left: 12, top: '50%', transform: 'translateY(-50%)', display: 'flex' }}><Icon name="search" size={15} stroke="var(--t3)" /></span>
                <input value={q} onChange={(e) => { setQ(e.target.value); setPage(1); }} placeholder={`${qScope} 검색`}
                  style={{ width: '100%', height: 38, paddingLeft: 36, paddingRight: 12, borderRadius: 7, border: '1px solid var(--line2)', background: '#fff', fontSize: 13, outline: 'none', fontFamily: "'Pretendard',sans-serif", color: 'var(--ink)', boxSizing: 'border-box' }} />
              </div>
            </div>
            <button onClick={() => { setWriting(true); setView(null); }} style={{ padding: '10px 18px', borderRadius: 7, border: 'none', background: CMPT, color: '#fff', fontWeight: 700, fontSize: 13, cursor: 'pointer', fontFamily: "'Pretendard',sans-serif" }}>글쓰기</button>
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: '1fr 340px', gap: 18, alignItems: 'start' }}>
            {/* 본문: 글쓰기 / 상세 / 게시판 */}
            {writing ? (
              <CmWrite initialBoard={board} onCancel={() => setWriting(false)} onSubmit={(p) => {
                const np = { ...p, id: 100000 + extra.length };
                setExtra([np, ...extra]);
                setWriting(false);
                setBoard(p.board);
                setPage(1);
                setView(np);
              }} />
            ) : view ? <CmPostDetail p={view} onBack={() => setView(null)} /> : (
            <div style={{ background: '#fff', border: '1px solid var(--line)', borderRadius: 8, overflow: 'hidden' }}>
              {/* 게시판 탭 */}
              <div style={{ display: 'flex', gap: 6, padding: '12px 14px', borderBottom: '1px solid var(--line)', overflowX: 'auto', whiteSpace: 'nowrap' }}>
                {['전체', ...CM_BOARDS].map((b) => {
                  const on = board === b;
                  return (
                    <button key={b} onClick={() => { setBoard(b); setPage(1); if (b !== '파티 모집') { setPtypeF('전체'); setVoiceF('전체'); } }} style={{ flexShrink: 0, padding: '6px 14px', borderRadius: 20, cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 12.5,
                      border: `1px solid ${on ? CMPT : 'var(--line2)'}`, background: on ? CMPT : '#fff', color: on ? '#fff' : 'var(--t2)' }}>{b}</button>
                  );
                })}
                <span style={{ marginLeft: 'auto', alignSelf: 'center', fontSize: 11.5, color: 'var(--t3)', fontWeight: 600, flexShrink: 0 }}>{list.length}개 글</span>
                <select value={per} onChange={(e) => { setPer(Number(e.target.value)); setPage(1); }} style={{ alignSelf: 'center', flexShrink: 0, fontFamily: "'Pretendard',sans-serif", fontSize: 11.5, fontWeight: 700, color: 'var(--ink)', border: '1px solid var(--line2)', borderRadius: 5, padding: '5px 7px', background: '#fff', cursor: 'pointer' }}>
                  {[15, 30, 50].map((n) => <option key={n} value={n}>{n}개씩</option>)}
                </select>
              </div>

              {/* 파티 모집 조건 필터 */}
              {board === '파티 모집' && (
                <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 14px', borderBottom: '1px solid var(--line)', background: '#fafbfc', flexWrap: 'wrap' }}>
                  <span style={{ fontSize: 11, fontWeight: 700, color: 'var(--t3)', flexShrink: 0 }}>모집 유형</span>
                  <div style={{ display: 'flex', gap: 5, flexWrap: 'wrap' }}>
                    {['전체', ...CM_PARTY_TYPES].map((t) => {
                      const on = ptypeF === t;
                      return <button key={t} onClick={() => { setPtypeF(t); setPage(1); }} style={{ padding: '5px 11px', borderRadius: 20, cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 11.5, border: `1px solid ${on ? CMPT : 'var(--line2)'}`, background: on ? CMPT : '#fff', color: on ? '#fff' : 'var(--t2)' }}>{t}</button>;
                    })}
                  </div>
                  <span style={{ width: 1, height: 16, background: 'var(--line2)', flexShrink: 0 }} />
                  <span style={{ fontSize: 11, fontWeight: 700, color: 'var(--t3)', flexShrink: 0 }}>보이스</span>
                  <div style={{ display: 'flex', gap: 5 }}>
                    {['전체', '필수', '자율'].map((t) => {
                      const on = voiceF === t;
                      return <button key={t} onClick={() => { setVoiceF(t); setPage(1); }} style={{ padding: '5px 11px', borderRadius: 20, cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", fontWeight: 700, fontSize: 11.5, border: `1px solid ${on ? CMPT : 'var(--line2)'}`, background: on ? CMPT : '#fff', color: on ? '#fff' : 'var(--t2)' }}>{t}</button>;
                    })}
                  </div>
                  {(ptypeF !== '전체' || voiceF !== '전체') && (
                    <button onClick={() => { setPtypeF('전체'); setVoiceF('전체'); setPage(1); }} style={{ marginLeft: 'auto', border: 'none', background: 'transparent', color: 'var(--t2)', fontWeight: 700, fontSize: 11.5, cursor: 'pointer', fontFamily: "'Pretendard',sans-serif", textDecoration: 'underline', flexShrink: 0 }}>초기화</button>
                  )}
                </div>
              )}

              {CM_NOTICES.map((n, i) => (
                <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 14px', background: '#f4f6f3', borderBottom: '1px solid #e6e9e4', cursor: 'pointer' }}>
                  <span style={{ flexShrink: 0, fontSize: 10.5, fontWeight: 800, padding: '1px 7px', borderRadius: 4, background: CMPT, color: '#fff', minWidth: 44, textAlign: 'center', boxSizing: 'border-box' }}>공지</span>
                  <span style={{ flex: 1, minWidth: 0, fontSize: 13.5, color: 'var(--ink)', fontWeight: 700, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{n.title}</span>
                  <span style={{ flexShrink: 0, fontSize: 11.5, color: 'var(--t3)', fontWeight: 600 }}>{n.time}</span>
                </div>
              ))}

              {/* 목록 */}
              {rows.map((p, i) => <CmRow key={p.id} p={p} zebra={i % 2 === 1} onOpen={setView} />)}
              {rows.length === 0 && (
                <div style={{ padding: '36px 0', textAlign: 'center', fontSize: 13, color: 'var(--t3)' }}>검색 결과가 없어요.</div>
              )}

              {/* 페이지네이션 */}
              {totalPages > 1 && (
                <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6, padding: '14px 0' }}>
                  <button onClick={() => goPage(cur - 1)} disabled={cur === 1} style={{ width: 30, height: 30, borderRadius: 6, border: '1px solid var(--line2)', background: '#fff', cursor: cur === 1 ? 'default' : 'pointer', opacity: cur === 1 ? .4 : 1, display: 'grid', placeItems: 'center' }}>
                    <Icon name="chevL" size={14} stroke="var(--t2)" />
                  </button>
                  {Array.from({ length: totalPages }, (_, i) => i + 1).map((n) => (
                    <button key={n} onClick={() => goPage(n)} style={{ minWidth: 30, height: 30, padding: '0 6px', borderRadius: 6, cursor: 'pointer', fontFamily: CMCH, fontWeight: 700, fontSize: 12.5,
                      border: n === cur ? 'none' : '1px solid var(--line2)', background: n === cur ? CMPT : '#fff', color: n === cur ? '#fff' : 'var(--t2)' }}>{n}</button>
                  ))}
                  <button onClick={() => goPage(cur + 1)} disabled={cur === totalPages} style={{ width: 30, height: 30, borderRadius: 6, border: '1px solid var(--line2)', background: '#fff', cursor: cur === totalPages ? 'default' : 'pointer', opacity: cur === totalPages ? .4 : 1, display: 'grid', placeItems: 'center' }}>
                    <Icon name="chevR" size={14} stroke="var(--t2)" />
                  </button>
                </div>
              )}
            </div>
            )}

            {/* 사이드 */}
            <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
              <CmSidePanel title="인기글" en="HOT" posts={hot} valueOf={(p) => `조회 ${window.SA.fmt(p.views)}`} onOpen={setView} />
              <CmSidePanel title="주간 베스트" en="WEEKLY BEST" posts={best} valueOf={(p) => `추천 ${p.up}`} onOpen={setView} />
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { CommunityScreen });
