> ## Documentation Index
> Fetch the complete documentation index at: https://intro.codebucket.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# 포트폴리오

> 한수원 R&D 우수 실적, AI 번역 MVP, LMS, 매칭 플랫폼, 라이브 커머스, B2B 운영 SaaS, 스마트팩토리 등 코드버킷이 직접 만들어 온 시스템 13종 사례.

export const portfolioCategories = [{
  id: 'real',
  label: '연구과제•R&D',
  type: 'real',
  note: '',
  items: [{
    id: 'gamma-3d',
    icon: 'radiation',
    title: '감마선 3D 시각화',
    desc: '한수원 R&D 우수 실적 (95점)',
    longDesc: '원전해체 시 감마선 시각화 장비를 이용한 In-Situ 측정 R&D 과제. 한수원 최종 평가 95점 우수 실적입니다.',
    parts: {
      common: ['운영'],
      domain: ['분석', '측정', '3D 시각화']
    },
    meta: [{
      label: '분야',
      value: '원자력 / R&D'
    }, {
      label: '검증 영역',
      value: 'R&D 정밀 시스템'
    }, {
      label: '발주',
      value: '한수원 / 한국원자력연구원'
    }, {
      label: '최종 평가',
      value: '95점 · 우수'
    }],
    bento: [{
      src: '/images/portfolio/r%26d/radiation-detection/img1.png',
      caption: '감마선 검출 — 메인'
    }, {
      src: '/images/portfolio/r%26d/radiation-detection/img2.png',
      caption: '측정 데이터'
    }, {
      src: '/images/portfolio/r%26d/radiation-detection/img3.png',
      caption: '3D 시각화'
    }, {
      src: '/images/portfolio/r%26d/radiation-detection/img4.png',
      caption: '분석 리포트'
    }, {
      src: '/images/portfolio/r%26d/radiation-detection/img5.png',
      caption: '운영 콘솔'
    }],
    techPoints: ['3차원 공간형상 + 감마선 시각화 정합', '원전해체 In-Situ 측정 시스템 구축', '한수원 R&D 과제 95점·우수 평가']
  }, {
    id: 'pansori',
    icon: 'music',
    title: '판소리 명창 기록물 아카이빙',
    desc: '한국항공대 — 무형 문화재 디지털 아카이브',
    longDesc: '판소리 명창의 공연·구술 기록물을 디지털 아카이빙하여 검색·분류·열람할 수 있게 구축한 시스템입니다.',
    parts: {
      common: ['운영', '사용자', '콘텐츠'],
      domain: ['아카이빙', '검색', '미디어 관리']
    },
    meta: [{
      label: '분야',
      value: '디지털 인문학 / 아카이빙'
    }, {
      label: '검증 영역',
      value: '대용량 미디어 메타데이터'
    }, {
      label: '발주',
      value: '한국항공대학교 산학협력단'
    }, {
      label: '배포',
      value: '학사내 보안 서버'
    }],
    bento: [{
      src: '/images/portfolio/archive/pansori/img1.png',
      caption: '판소리 아카이빙 — 메인'
    }, {
      src: '/images/portfolio/archive/pansori/img2.png',
      caption: '명창 검색'
    }, {
      src: '/images/portfolio/archive/pansori/img3.png',
      caption: '기록물 상세'
    }, {
      src: '/images/portfolio/archive/pansori/img4.png',
      caption: '미디어 열람'
    }, {
      src: '/images/portfolio/archive/pansori/img5.png',
      caption: '관리자 콘솔'
    }],
    techPoints: ['미디어 메타데이터 구조화', '명창·연도·곡목 다축 검색', '대용량 영상 스트리밍']
  }]
}, {
  id: 'ai-app',
  label: 'AI 응용',
  type: 'real',
  note: '',
  items: [{
    id: 'ai-translation',
    icon: 'language',
    title: 'AI 번역 + 전문가 추천',
    desc: 'Gemini 2단 검수 · 전문가 5축 매칭 (MVP)',
    longDesc: 'Gemini로 1차 번역, 휴먼 에디터가 문장 단위 감수, 마지막에 다시 AI가 품질을 평가하는 2단 검수 파이프라인. 의뢰가 들어오면 의뢰 특성에 맞는 번역 전문가를 AI가 추천하고, 후보 간 비교 분석까지 도와주는 MVP입니다.',
    parts: {
      common: ['운영', '사용자', '콘텐츠'],
      domain: ['AI 번역', '휴먼 감수', '품질 평가', '전문가 매칭', '비교 분석']
    },
    meta: [{
      label: '분야',
      value: 'AI 응용 / 번역 워크플로'
    }, {
      label: '사용자',
      value: '의뢰자 + 휴먼 에디터 + 번역 전문가'
    }, {
      label: '핵심 흐름',
      value: 'AI 번역 → 휴먼 감수 → AI 품질 평가 → 전문가 매칭'
    }, {
      label: '단계',
      value: 'MVP (실제 수행)'
    }],
    bento: [{
      src: '/images/portfolio/ai/ai-translation/img1.png',
      caption: '휴먼 에디팅 — 원문/번역문 좌우 비교'
    }, {
      src: '/images/portfolio/ai/ai-translation/img2.png',
      caption: 'AI 품질 평가 — 4축·문장별 상세'
    }, {
      src: '/images/portfolio/ai/ai-translation/img3.png',
      caption: 'AI 매칭·스코어링 — 5축 후보 랭킹'
    }, {
      src: '/images/portfolio/ai/ai-translation/img4.png',
      caption: '전문가 상세 프로필 — AI 추천 이유'
    }, {
      src: '/images/portfolio/ai/ai-translation/img5.png',
      caption: '전문가 비교 — 5축 + AI 비교 코멘트'
    }],
    techPoints: ['Gemini 1차 번역 + 2차 품질 평가 파이프라인', '전문가 5축 스코어링(전문성·경력실적·가용성·비용·평판)', '후보 비교 시각화 + AI 비교 코멘트']
  }]
}, {
  id: 'b2c-match',
  label: 'B2C 매칭·플랫폼',
  type: 'mockup',
  items: [{
    id: 'pet-sitter',
    icon: 'dog',
    title: '펫시터·도그워커 매칭',
    desc: '시터 검색 · 케어 일지 · 분쟁 처리',
    longDesc: '펫시터·도그워커와 견주를 매칭하고, 시터가 미디어 일지(사진·영상)로 케어 상황을 공유하며, 분쟁 시 운영자가 개입할 수 있는 매칭 플랫폼입니다.',
    parts: {
      common: ['운영', '사용자', '콘텐츠'],
      domain: ['매칭', '예약', '결제', '알림', '케어 일지']
    },
    meta: [{
      label: '분야',
      value: '펫·반려동물 매칭'
    }, {
      label: '사용자',
      value: '견주 + 시터 (양면)'
    }, {
      label: '핵심 흐름',
      value: '매칭 → 예약 → 케어 일지 → 정산'
    }, {
      label: '추천 규모',
      value: '중소 매칭 플랫폼'
    }],
    bento: [{
      src: '/images/portfolio/match/pet-sitter/img1.png',
      caption: '메인 — 시터 검색'
    }, {
      src: '/images/portfolio/match/pet-sitter/img2.png',
      caption: '시터 상세'
    }, {
      src: '/images/portfolio/match/pet-sitter/img3.png',
      caption: '예약 진행'
    }, {
      src: '/images/portfolio/match/pet-sitter/img4.png',
      caption: '케어 일지'
    }, {
      src: '/images/portfolio/match/pet-sitter/img5.png',
      caption: '시터 정산'
    }],
    techPoints: ['양방향 매칭 — 시터·견주 양쪽 프로필', '케어 일지 미디어 업로드', '분쟁 처리 워크플로']
  }, {
    id: 'space-rental',
    icon: 'building',
    title: '공간 대여',
    desc: '시간 단위 예약 · 다중 호스트',
    longDesc: '스튜디오·회의실·파티룸 등을 시간 단위로 예약하고 결제하는 공간 대여 플랫폼입니다.',
    parts: {
      common: ['운영', '사용자', '콘텐츠'],
      domain: ['매칭', '예약', '결제', '호스트 관리']
    },
    meta: [{
      label: '분야',
      value: '공간 대여 플랫폼'
    }, {
      label: '사용자',
      value: '호스트 + 이용자'
    }, {
      label: '핵심 흐름',
      value: '검색 → 시간 예약 → 결제 → 정산'
    }, {
      label: '추천 규모',
      value: '다중 호스트 플랫폼'
    }],
    bento: [{
      src: '/images/portfolio/match/space-rental/img1.png',
      caption: '공간 검색'
    }, {
      src: '/images/portfolio/match/space-rental/img2.png',
      caption: '공간 상세 + 시간 예약'
    }, {
      src: '/images/portfolio/match/space-rental/img3.png',
      caption: '결제'
    }, {
      src: '/images/portfolio/match/space-rental/img4.png',
      caption: '호스트 대시보드'
    }, {
      src: '/images/portfolio/match/space-rental/img5.png',
      caption: '예약 관리'
    }],
    techPoints: ['시간단위 예약 충돌 처리', '다중 호스트 — 호스트별 독립 운영', '결제 + 정산 분리']
  }]
}, {
  id: 'b2c-live',
  label: 'B2C 라이브',
  type: 'mockup',
  items: [{
    id: 'live-commerce',
    icon: 'video',
    title: '라이브 커머스',
    desc: '실시간 송출 · 채팅 · 결제 · 다시보기',
    longDesc: '매니지드 라이브 스트리밍(AWS IVS / 네이버 클라우드) 위에 자체 채팅(WebSocket)·자체 결제·VOD를 직접 구축한 라이브 커머스 플랫폼입니다.',
    parts: {
      common: ['운영', '사용자', '콘텐츠'],
      domain: ['라이브 송출', '채팅', '상품', '결제', '다시보기']
    },
    meta: [{
      label: '분야',
      value: '라이브 커머스'
    }, {
      label: '사용자',
      value: '호스트 + 시청자'
    }, {
      label: '핵심 흐름',
      value: '송출 → 채팅 → 결제 → 다시보기'
    }, {
      label: '추천 규모',
      value: '자체 라이브 브랜드'
    }],
    bento: [{
      src: '/images/portfolio/live/commerce/img1.png',
      caption: '라이브 시청 + 채팅 + 결제'
    }, {
      src: '/images/portfolio/live/commerce/img2.png',
      caption: '호스트 송출 콘솔'
    }, {
      src: '/images/portfolio/live/commerce/img3.png',
      caption: '상품 등록'
    }, {
      src: '/images/portfolio/live/commerce/img4.png',
      caption: '다시보기(VOD)'
    }, {
      src: '/images/portfolio/live/commerce/img5.png',
      caption: '운영 대시보드'
    }],
    techPoints: ['매니지드 라이브 + 자체 채팅 WebSocket', '라이브 중 즉시 결제', 'VOD 변환 자동화']
  }]
}, {
  id: 'edu-lms',
  label: '교육·LMS',
  type: 'mockup',
  items: [{
    id: 'online-academy',
    icon: 'book-open',
    title: '온라인 강의 플랫폼',
    desc: '강의 카탈로그 · 수강 · 진도 · 평가',
    longDesc: '강사가 동영상·자료·과제를 올리고, 수강생이 결제·수강·진도 관리·평가를 진행하는 LMS 플랫폼입니다.',
    parts: {
      common: ['운영', '사용자', '콘텐츠'],
      domain: ['강의', '수강', '평가', '결제', '진도']
    },
    meta: [{
      label: '분야',
      value: '온라인 강의 / LMS'
    }, {
      label: '사용자',
      value: '강사 + 수강생'
    }, {
      label: '핵심 흐름',
      value: '강의 등록 → 수강 → 진도 → 평가'
    }, {
      label: '추천 규모',
      value: '단일 학원 / 다강사 플랫폼'
    }],
    bento: [{
      src: '/images/portfolio/lms/online-academy/img1.png',
      caption: '메인 — 강의 카탈로그'
    }, {
      src: '/images/portfolio/lms/online-academy/img2.png',
      caption: '강의 상세'
    }, {
      src: '/images/portfolio/lms/online-academy/img3.png',
      caption: '수강 진행'
    }, {
      src: '/images/portfolio/lms/online-academy/img4.png',
      caption: '진도 관리'
    }, {
      src: '/images/portfolio/lms/online-academy/img5.png',
      caption: '강사 콘솔'
    }],
    techPoints: ['단원·차시 단위 강의 구조', '동영상 + 자료 + 퀴즈 통합', '학습 진도 자동 추적']
  }]
}, {
  id: 'b2b-saas',
  label: 'B2B 운영 SaaS',
  type: 'mockup',
  items: [{
    id: 'rental-manage',
    icon: 'key',
    title: '부동산 임대 관리',
    desc: '임대 대시보드 · 수금 · 갱신',
    longDesc: '임대인이 다수의 매물·임차인·계약·수금을 한 곳에서 관리하는 운영 SaaS입니다.',
    parts: {
      common: ['운영', '사용자'],
      domain: ['임대', '계약', '수금', '알림']
    },
    meta: [{
      label: '분야',
      value: '부동산 임대 관리'
    }, {
      label: '사용자',
      value: '임대인 (관리자)'
    }, {
      label: '핵심 흐름',
      value: '계약 → 수금 → 갱신 → 정산'
    }, {
      label: '추천 규모',
      value: '다수 매물 보유 임대인'
    }],
    bento: [{
      src: '/images/portfolio/realestate/rental-manage/img1.png',
      caption: '임대 대시보드'
    }, {
      src: '/images/portfolio/realestate/rental-manage/img2.png',
      caption: '매물·임차인 상세'
    }, {
      src: '/images/portfolio/realestate/rental-manage/img3.png',
      caption: '수금 캘린더'
    }, {
      src: '/images/portfolio/realestate/rental-manage/img4.png',
      caption: '계약 갱신'
    }, {
      src: '/images/portfolio/realestate/rental-manage/img5.png',
      caption: '세금·정산 리포트'
    }],
    techPoints: ['계약·수금·세금·임차인 데이터 모델', '갱신·연체 자동 알림', '다수 매물 일괄 관리']
  }, {
    id: 'wedding-planner',
    icon: 'church',
    title: '웨딩 플래너 / 스드메',
    desc: '다중 업체 매칭 · 패키지 견적',
    longDesc: '웨딩 플래너가 스튜디오·드레스·메이크업 업체를 매칭하고, 패키지 견적·일정·고객을 관리하는 운영 SaaS입니다.',
    parts: {
      common: ['운영', '사용자'],
      domain: ['매칭', '견적', '일정', '고객 관리']
    },
    meta: [{
      label: '분야',
      value: '웨딩 플래너 / 스드메'
    }, {
      label: '사용자',
      value: '플래너 + 업체'
    }, {
      label: '핵심 흐름',
      value: '매칭 → 견적 → 일정 → 진행'
    }, {
      label: '추천 규모',
      value: '중간 유통 플래너 사무소'
    }],
    bento: [{
      src: '/images/portfolio/wedding/wedding-planner/img1.png',
      caption: '업체 검색'
    }, {
      src: '/images/portfolio/wedding/wedding-planner/img2.png',
      caption: '업체 상세'
    }, {
      src: '/images/portfolio/wedding/wedding-planner/img3.png',
      caption: '패키지 견적'
    }, {
      src: '/images/portfolio/wedding/wedding-planner/img4.png',
      caption: '일정 보드'
    }, {
      src: '/images/portfolio/wedding/wedding-planner/img5.png',
      caption: '고객 관리'
    }],
    techPoints: ['다중 업체 일정 충돌 검사', '패키지 견적 — 항목 조합 + 할인 룰', '고객별 진행 단계 추적']
  }, {
    id: 'hagwon-exam',
    icon: 'graduation-cap',
    title: '입시학원 운영',
    desc: '모의고사 채점 · 등급 분석',
    longDesc: '입시학원 운영 SaaS. 모의고사 점수를 채점·분석하고 등급을 추적하며, 학부모에게 정기 리포트를 보냅니다.',
    parts: {
      common: ['운영', '사용자'],
      domain: ['강의', '수강', '평가', '분석', '리포트']
    },
    meta: [{
      label: '분야',
      value: '입시학원 운영'
    }, {
      label: '사용자',
      value: '강사 + 학부모'
    }, {
      label: '핵심 흐름',
      value: '모의고사 → 채점 → 분석 → 리포트'
    }, {
      label: '추천 규모',
      value: '중대형 입시학원'
    }],
    bento: [{
      src: '/images/portfolio/edu/exam/img1.png',
      caption: '학원 대시보드'
    }, {
      src: '/images/portfolio/edu/exam/img2.png',
      caption: '학생 성적·등급 분석'
    }, {
      src: '/images/portfolio/edu/exam/img3.png',
      caption: '모의고사 채점 보드'
    }, {
      src: '/images/portfolio/edu/exam/img5.png',
      caption: '학부모 리포트'
    }, {
      src: '/images/portfolio/edu/exam/img6.png',
      caption: '학생 개별 코칭'
    }],
    techPoints: ['모의고사 점수 분석 — 등급 추적', '학생 단위 성적 데이터 모델', '정기 리포트 자동 생성']
  }, {
    id: 'case-manage',
    icon: 'scale-balanced',
    title: '법무·세무 사건 관리',
    desc: '사건 워크플로 · 기일 · 클라이언트 포털',
    longDesc: '로펌·세무법인의 사건을 워크플로 단위로 관리하고, 기일·서류·클라이언트 포털을 통합한 운영 SaaS입니다.',
    parts: {
      common: ['운영', '사용자'],
      domain: ['사건', '일정', '문서', '클라이언트 포털']
    },
    meta: [{
      label: '분야',
      value: '법무 / 세무 사건 관리'
    }, {
      label: '사용자',
      value: '변호사·세무사 + 클라이언트'
    }, {
      label: '핵심 흐름',
      value: '수임 → 진행 → 기일 → 종결'
    }, {
      label: '추천 규모',
      value: '1인 ~ 중형 법인'
    }],
    bento: [{
      src: '/images/portfolio/legal/case-manage/img1.png',
      caption: '사건 대시보드'
    }, {
      src: '/images/portfolio/legal/case-manage/img2.png',
      caption: '사건 상세 — 서류·일정'
    }, {
      src: '/images/portfolio/legal/case-manage/img3.png',
      caption: '기일 캘린더'
    }, {
      src: '/images/portfolio/legal/case-manage/img4.png',
      caption: '클라이언트 포털'
    }, {
      src: '/images/portfolio/legal/case-manage/img5.png',
      caption: '문서 보안'
    }],
    techPoints: ['사건 워크플로 단위 데이터 모델', '문서 보안 — 접근 권한·열람 로그', '클라이언트 포털']
  }]
}, {
  id: 'b2b-medical',
  label: 'B2B 의료·건강',
  type: 'mockup',
  items: [{
    id: 'clinic-korean',
    icon: 'leaf',
    title: '한의원 환자관리',
    desc: '진맥 · 체질 · 한방 처방',
    longDesc: '한의원 운영 SaaS. 진맥·체질 데이터를 기록하고, 한방 처방 이력과 예약을 통합 관리합니다.',
    parts: {
      common: ['운영', '사용자'],
      domain: ['차트', '진맥·체질', '처방', '예약']
    },
    meta: [{
      label: '분야',
      value: '한의원 운영'
    }, {
      label: '사용자',
      value: '한의사 + 직원'
    }, {
      label: '핵심 흐름',
      value: '진맥 → 체질 → 처방 → 예약'
    }, {
      label: '추천 규모',
      value: '1인 한의원'
    }],
    bento: [{
      src: '/images/portfolio/clinic/korean/img1.png',
      caption: '환자 차트'
    }, {
      src: '/images/portfolio/clinic/korean/img2.png',
      caption: '진맥·체질 데이터'
    }, {
      src: '/images/portfolio/clinic/korean/img3.png',
      caption: '한방 처방'
    }, {
      src: '/images/portfolio/clinic/korean/img4.png',
      caption: '예약 관리'
    }, {
      src: '/images/portfolio/clinic/korean/img5.png',
      caption: '환자 이력 조회'
    }],
    techPoints: ['한의학 도메인 모델 — 진맥·체질 분류', '한방 처방 이력 누적', '환자 이력 시각화']
  }]
}, {
  id: 'b2b-smart-factory',
  label: '스마트 팩토리',
  type: 'mockup',
  items: [{
    id: 'smart-factory',
    icon: 'industry',
    title: '스마트팩토리',
    desc: '라인 모니터 · 워크오더 · BOM',
    longDesc: '생산 라인 IoT 데이터를 실시간으로 모니터링하고, 워크오더와 BOM·재고·품질검사를 통합 관리하는 생산관리 SaaS입니다.',
    parts: {
      common: ['운영'],
      domain: ['분석', '라인 모니터', '워크오더', 'BOM', '품질 검사']
    },
    meta: [{
      label: '분야',
      value: '스마트팩토리 / 생산관리'
    }, {
      label: '사용자',
      value: '공장 운영자'
    }, {
      label: '핵심 흐름',
      value: '라인 모니터 → 워크오더 → BOM → 검사'
    }, {
      label: '추천 규모',
      value: '중소 제조 라인'
    }],
    bento: [{
      src: '/images/portfolio/factory/smart-factory/img1.png',
      caption: '라인 실시간 모니터'
    }, {
      src: '/images/portfolio/factory/smart-factory/img2.png',
      caption: '워크오더'
    }, {
      src: '/images/portfolio/factory/smart-factory/img3.png',
      caption: 'BOM·재고'
    }, {
      src: '/images/portfolio/factory/smart-factory/img4.png',
      caption: '품질 검사'
    }, {
      src: '/images/portfolio/factory/smart-factory/img5.png',
      caption: '운영 대시보드'
    }],
    techPoints: ['IoT 실시간 데이터 처리', '워크오더 워크플로', 'BOM·재고 일관성 보장']
  }]
}];

export const PortfolioTiles = ({categories}) => {
  const [activeId, setActiveId] = useState(null);
  const allItems = categories.flatMap(cat => cat.items.map(item => ({
    ...item,
    _category: cat
  })));
  const active = activeId ? allItems.find(it => it.id === activeId) : null;
  const renderEmptyState = () => <div className="rounded-2xl flex flex-col items-center justify-center gap-3 p-8 min-h-[400px] lg:min-h-[560px]">
      <div className="w-14 h-14 rounded-full border border-gray-300 dark:border-white/10 flex items-center justify-center text-gray-400 dark:text-gray-500">
        <Icon icon="hand-pointer" size="22" />
      </div>
      <p className="text-base font-medium text-gray-700 dark:text-gray-300 text-center m-0">
        포트폴리오를 선택해 주세요
      </p>
      <p className="text-sm text-gray-500 dark:text-gray-400 text-center m-0">
        왼쪽 목록에서 항목을 클릭하면<br />화면이 펼쳐집니다.
      </p>
    </div>;
  const renderGallery = item => {
    if (!item) return renderEmptyState();
    const images = item.bento ?? [];
    const isReal = item._category?.type === 'real';
    const [hero, ...thumbs] = images;
    return <div className="space-y-4">
        {hero?.src ? <img src={hero.src} alt={hero.caption} className="aspect-[16/10] w-full object-cover mint-rounded-2xl mint-shadow-xl" /> : <div className="aspect-[16/10] rounded-xl bg-gray-50 dark:bg-white/[0.03] border border-gray-200 dark:border-white/10 flex items-center justify-center">
            <span className="text-sm text-gray-400">{hero?.caption || '이미지 준비 중'}</span>
          </div>}
        {thumbs.length > 0 && <div className="grid grid-cols-2 gap-3">
            {thumbs.slice(0, 4).map((img, i) => img.src ? <img key={i} src={img.src} alt={img.caption} className="aspect-video w-full object-cover mint-rounded-2xl mint-shadow-xl" /> : <div key={i} className="aspect-video rounded-lg bg-gray-50 dark:bg-white/[0.03] border border-gray-200 dark:border-white/10 flex items-center justify-center p-3">
                  <span className="text-[11px] text-gray-400 text-center leading-tight">
                    {img.caption || '이미지 준비 중'}
                  </span>
                </div>)}
          </div>}
        {item.meta && <div className="grid grid-cols-2 gap-2 pt-2">
            {item.meta.map((m, i) => <div key={i} className="rounded-xl border border-gray-200 dark:border-white/10 px-4 py-3 bg-white dark:bg-white/[0.02] shadow-sm shadow-gray-900/5 dark:shadow-black/20">
                <div className="text-[10px] uppercase tracking-wider text-gray-500 dark:text-gray-400 mb-1 font-semibold">
                  {m.label}
                </div>
                <div className="text-sm text-gray-800 dark:text-gray-200">{m.value}</div>
              </div>)}
          </div>}
      </div>;
  };
  return <div className="not-prose">
      <div className="bg-gray-100 dark:bg-[#141414] border border-gray-200 dark:border-white/5 rounded-2xl p-2 lg:p-3">
        <div className="grid grid-cols-1 lg:grid-cols-[5fr_7fr] gap-2 lg:gap-3">
          <div className="space-y-7 p-2 lg:p-4">
            {categories.map(cat => <div key={cat.id}>
                <div className="flex items-center gap-2 mb-3 px-1">
                <span className="text-xs uppercase tracking-wider font-semibold text-gray-500 dark:text-gray-400">
                  {cat.label}
                </span>
              </div>
              <div className="space-y-1.5">
                {cat.items.map(item => {
    const isActive = item.id === activeId;
    return <button key={item.id} type="button" onClick={() => setActiveId(activeId === item.id ? null : item.id)} className={`w-full text-left rounded-2xl transition-all px-5 py-4 ${isActive ? 'bg-white dark:bg-white/5' : ''}`}>
                      <div className="flex items-start gap-3">
                        <div className="flex-1 min-w-0">
                          <div className="flex items-center justify-between gap-2">
                            <h3 className="font-medium text-sm text-gray-900 dark:text-white m-0">
                              {item.title}
                            </h3>
                            <div className={`flex-none transition-transform ${isActive ? 'rotate-90' : ''} text-gray-400`}>
                              <Icon icon="chevron-right" size="14" />
                            </div>
                          </div>
                          <p className={`text-xs m-0 mt-1 ${isActive ? 'text-gray-700 dark:text-gray-300' : 'text-gray-500 dark:text-gray-400'}`}>
                            {isActive ? item.longDesc ?? item.desc : item.desc}
                          </p>
                          {isActive && item.parts && <div className="flex flex-wrap gap-1.5 mt-3">
                              {(item.parts.common ?? []).map(p => <span key={`c-${p}`} className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs bg-gray-100 dark:bg-white/10 text-gray-700 dark:text-gray-300">
                                  {p}
                                </span>)}
                              {(item.parts.domain ?? []).map(p => <span key={`d-${p}`} className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs bg-primary/10 dark:bg-primary/20 text-primary-dark dark:text-primary-light font-medium">
                                  {p}
                                </span>)}
                            </div>}
                          {isActive && item.techPoints && <ul className="text-sm font-semibold text-gray-600 dark:text-gray-400 mt-6 space-y-1 pl-4 list-disc m-0">
                              {item.techPoints.map((tp, i) => <li key={i}>{tp}</li>)}
                            </ul>}
                        </div>
                      </div>
                    </button>;
  })}
              </div>
            </div>)}
        </div>
          <div className="bg-white dark:bg-[#1c1c1c] rounded-xl border border-gray-200/80 dark:border-white/5 p-4 lg:p-6">
            <div className="lg:sticky lg:top-24">
              {renderGallery(active)}
            </div>
          </div>
        </div>
      </div>
    </div>;
};

export const Title = ({children}) => {
  return <div className="text-gray-900 dark:text-gray-200 text-2xl tracking-tight">
      {children}
    </div>;
};

export const Container = ({children}) => {
  return <div className="px-4 lg:px-10 py-14">
      {children}
    </div>;
};

<script type="application/ld+json">
  {`{"@context":"https://schema.org","@graph":[{"@type":"ItemList","@id":"https://intro.codebucket.dev/portfolio#itemlist","name":"코드버킷 포트폴리오","description":"코드버킷이 직접 설계·개발한 R&D 시스템 2종, AI 응용 MVP 1종, 분야별 재구성 시안 10종. 각 사례는 파트 단위 자체 개발의 적용 사례입니다.","inLanguage":"ko-KR","isPartOf":{"@id":"https://intro.codebucket.dev/#website"},"publisher":{"@id":"https://codebucket.dev/#organization"},"numberOfItems":13,"itemListElement":[{"@type":"ListItem","position":1,"item":{"@type":"CreativeWork","name":"감마선 3D 시각화 — 한수원 R&D 우수","description":"원전해체 시 감마선 시각화 장비를 이용한 In-Situ 측정 R&D 과제. 한수원 최종 평가 95점 우수 실적","keywords":"R&D 시스템 개발, 정부과제 산출물, 감마선 시각화, 원전해체 측정"}},{"@type":"ListItem","position":2,"item":{"@type":"CreativeWork","name":"판소리 명창 기록물 아카이빙","description":"한국항공대 산학협력 — 판소리 명창의 공연·구술 기록물을 디지털 아카이빙한 시스템","keywords":"산학협력 시스템 개발, 디지털 아카이빙, 대용량 미디어 메타데이터"}},{"@type":"ListItem","position":3,"item":{"@type":"CreativeWork","name":"AI 번역 + 전문가 추천 (MVP)","description":"Gemini 1차 번역 + 휴먼 감수 + AI 2차 품질 평가 + 번역 전문가 5축 매칭/비교까지 통합한 AI 응용 MVP","keywords":"AI 번역 워크플로, Gemini 번역, 번역 품질 평가, 전문가 매칭 스코어링"}},{"@type":"ListItem","position":4,"item":{"@type":"CreativeWork","name":"펫시터·도그워커 매칭","description":"양면 매칭 — 시터 검색·예약·케어 일지·정산까지 통합한 매칭 플랫폼","keywords":"매칭 플랫폼 개발, 양면 매칭, 케어 일지"}},{"@type":"ListItem","position":5,"item":{"@type":"CreativeWork","name":"공간 대여 — 시간 단위 예약","description":"스튜디오·회의실·파티룸을 시간 단위로 예약·결제하는 다중 호스트 플랫폼","keywords":"공간 대여 플랫폼, 다중 호스트, 시간 단위 예약"}},{"@type":"ListItem","position":6,"item":{"@type":"CreativeWork","name":"라이브 커머스","description":"매니지드 라이브 + 자체 채팅·결제·VOD를 결합한 라이브 커머스 플랫폼","keywords":"라이브 커머스, 실시간 송출, 자체 채팅 WebSocket"}},{"@type":"ListItem","position":7,"item":{"@type":"CreativeWork","name":"온라인 강의 플랫폼 (LMS)","description":"강의 카탈로그·수강·진도·평가까지 통합한 LMS 플랫폼","keywords":"LMS 개발, 온라인 강의 플랫폼, 학습 진도 추적"}},{"@type":"ListItem","position":8,"item":{"@type":"CreativeWork","name":"부동산 임대 관리 SaaS","description":"임대인이 다수의 매물·임차인·계약·수금을 한 곳에서 관리하는 운영 SaaS","keywords":"임대 관리 SaaS, 운영 SaaS 개발, 자동 수금 알림"}},{"@type":"ListItem","position":9,"item":{"@type":"CreativeWork","name":"웨딩 플래너 / 스드메 운영","description":"플래너가 스튜디오·드레스·메이크업 업체를 매칭하고 패키지 견적을 관리하는 운영 SaaS","keywords":"웨딩 플래너 SaaS, 다중 업체 매칭, 패키지 견적"}},{"@type":"ListItem","position":10,"item":{"@type":"CreativeWork","name":"입시학원 운영 SaaS","description":"모의고사 채점·등급 분석·학부모 정기 리포트를 통합한 학원 운영 SaaS","keywords":"입시학원 SaaS, 성적 분석, 학부모 리포트"}},{"@type":"ListItem","position":11,"item":{"@type":"CreativeWork","name":"법무·세무 사건 관리","description":"로펌·세무법인의 사건 워크플로·기일·클라이언트 포털을 통합한 운영 SaaS","keywords":"법무 사건 관리, 세무 운영 SaaS, 클라이언트 포털"}},{"@type":"ListItem","position":12,"item":{"@type":"CreativeWork","name":"한의원 환자관리","description":"진맥·체질·한방 처방·예약을 통합한 한의원 운영 SaaS","keywords":"한의원 운영, 환자관리 SaaS, 한방 처방 이력"}},{"@type":"ListItem","position":13,"item":{"@type":"CreativeWork","name":"스마트팩토리 / 생산관리","description":"IoT 라인 모니터·워크오더·BOM·품질검사를 통합한 생산관리 SaaS","keywords":"스마트팩토리 개발, IoT 데이터 처리, 워크오더 관리"}}]},{"@type":"BreadcrumbList","@id":"https://intro.codebucket.dev/portfolio#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"홈","item":"https://intro.codebucket.dev/"},{"@type":"ListItem","position":2,"name":"포트폴리오","item":"https://intro.codebucket.dev/portfolio"}]}]}`}
</script>

<div className="px-5 divide-y divide-gray-100 dark:divide-white/10">
  <Container>
    <div className="flex flex-col w-full mb-8">
      <div className="text-sm font-semibold text-primary dark:text-primary-light mb-2">
        포트폴리오
      </div>

      <h1 className="text-3xl md:text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-100 m-0">
        포트폴리오
      </h1>

      <p className="text-base lg:text-lg text-gray-600 dark:text-gray-400 mt-3 mb-0 leading-relaxed">
        코드버킷이 만들어 온 시스템 구축 사례와 분야별 재구성을 확인해 보세요.<br />각 사례에서 어떤 파트들이 어떻게 조합되는지 한눈에 볼 수 있습니다.
      </p>
    </div>

    <div>
      <p class="text-sm text-gray-400 dark:text-gray-600">
        ※ 각 포트폴리오는 실제 사용 화면을 노출시킬 수 없어 이해를 돕기 위한 재구성 시안으로 구성되었습니다.
      </p>
    </div>

    <PortfolioTiles categories={portfolioCategories} />
  </Container>

  <Container>
    <CardGroup cols={2}>
      <Card title="파트 카탈로그" icon="boxes" href="/catalog">
        포트폴리오에 적용된 파트들의 전체 목록
      </Card>

      <Card title="상담·견적 의뢰" icon="paper-plane" href="https://codebucket.dev/inquiry">
        구상 단계부터 함께 검토합니다.
      </Card>
    </CardGroup>
  </Container>
</div>
