/* global React, CharLead, CharPlanner, CharDev, CharDesigner, CharDesigner2, Cloud, Star, Heart, Sparkle, Diamond, Flower, IcoBrand, IcoWeb, IcoApp, IcoRocket, IcoChart, IcoChat, IcoSwatch, IcoFlag, ProjectThumb, PortfolioMockup, WorksSection, useLang, LangSwitcher */

const { useState, useEffect, useRef } = React;

/* =========================================================
   useReveal — IntersectionObserver hook for scroll-trigger reveal
   ========================================================= */
function useReveal(threshold = 0.15) {
  const ref = useRef(null);
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    if (!ref.current) return;
    const io = new IntersectionObserver(
      (entries) => {
        entries.forEach(e => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } });
      },
      { threshold }
    );
    io.observe(ref.current);
    return () => io.disconnect();
  }, [threshold]);
  return [ref, seen];
}

/* =========================================================
   useTyping — typewriter effect cycling phrases
   ========================================================= */
function useTyping(phrases, speed = 90, pauseMs = 1400) {
  const [text, setText] = useState('');
  const [i, setI] = useState(0);
  const [del, setDel] = useState(false);
  useEffect(() => {
    const cur = phrases[i % phrases.length];
    let t;
    if (!del && text.length < cur.length) {
      t = setTimeout(() => setText(cur.slice(0, text.length + 1)), speed);
    } else if (!del && text.length === cur.length) {
      t = setTimeout(() => setDel(true), pauseMs);
    } else if (del && text.length > 0) {
      t = setTimeout(() => setText(cur.slice(0, text.length - 1)), speed / 2);
    } else if (del && text.length === 0) {
      setDel(false);
      setI(v => v + 1);
    }
    return () => clearTimeout(t);
  }, [text, del, i, phrases, speed, pauseMs]);
  return text;
}

/* =========================================================
   Nav
   ========================================================= */
function Nav({ active }) {
  const { t, lang } = useLang();
  const brandName = lang === 'ko' ? '우친소' : 'WCS';
  const links = [
    { id: 'intro', label: t('nav_intro') },
    { id: 'about', label: t('nav_about') },
    { id: 'services', label: t('nav_services') },
    { id: 'skills', label: t('nav_skills') },
    { id: 'portfolio', label: t('nav_portfolio') },
    { id: 'cloud', label: t('nav_cloud') },
    { id: 'solutions', label: t('nav_solutions') },
    { id: 'process', label: t('nav_process') },
  ];
  return (
    <header className="site-header">
      <div className="site-header-inner">
        <a href="#intro" className="brand">
          <img src="/favicon.png" className="brand-logo" alt="WCS" />
          <span>{brandName}</span>
        </a>
        <nav className="nav">
          <div className="nav-links">
            {links.map(l => (
              <a key={l.id} href={`#${l.id}`} className={`nav-link ${active === l.id ? 'active' : ''}`}>
                {l.label}
              </a>
            ))}
          </div>
          <a href="#contact" className="nav-cta">{t('nav_cta')}</a>
        </nav>
        <div className="nav-lang">
          <LangSwitcher />
        </div>
      </div>
    </header>
  );
}

/* =========================================================
   Hero / Intro
   ========================================================= */
function Hero({ scrollY }) {
  const { t } = useLang();
  const phrases = [
    t('hero_phrase1'), t('hero_phrase2'), t('hero_phrase3'), t('hero_phrase4'),
  ];
  const typed = useTyping(phrases);

  const py = (factor) => `translateY(${scrollY * factor}px)`;

  return (
    <section className="section hero" id="intro">
      {/* Decorations with parallax */}
      <Cloud size={6} className="deco-cloud" style={{ top: 140, left: '6%', transform: py(-0.15) }} />
      <Cloud size={4} className="deco-cloud" style={{ top: 240, right: '12%', transform: py(-0.10) }} />
      <Star size={5} className="deco-star twinkle" style={{ top: 200, left: '38%', transform: py(0.10) }} />
      <Sparkle size={4} className="deco-star twinkle" style={{ top: 460, left: '10%', transform: py(0.20) }} />
      <Diamond size={4} className="deco-star twinkle" style={{ top: 720, right: '8%', transform: py(0.18) }} />
      <Heart size={4} className="deco-star" style={{ top: 600, right: '4%', transform: py(-0.08) }} />
      <Flower size={4} className="deco-cloud" style={{ bottom: 80, left: '4%', transform: py(-0.05) }} />

      <div className="section-inner" style={{ width: '100%' }}>
        <div className="hero-grid">
          <div>
            <div className="hero-eyebrow-row">
              <span className="eyebrow"><span className="eyebrow-dot"></span>{t('hero_eyebrow')}</span>
            </div>
            <h1 className="hero-title">
              <span className="under">{t('hero_line1')}</span>
              <br />
              <span className="nowrap">{t('hero_line2')}</span>
            </h1>
            <p className="hero-sub">{t('hero_sub')}</p>
            <div className="hero-typing">
              <span className="prompt">{t('hero_prompt')}</span>
              <span>{typed}</span>
              <span className="caret"></span>
            </div>
            <div className="hero-cta-row">
              <a className="btn" href="#portfolio">
                {t('hero_cta1')} <span style={{ fontSize: 18 }}>→</span>
              </a>
              <a className="btn ghost" href="#contact">
                <Heart size={2} color="#D88BB8" /> {t('hero_cta2')}
              </a>
            </div>
          </div>

          {/* Right scene — characters floating */}
          <div className="hero-scene">
            <div style={{ position: 'absolute', inset: '5% 8%', borderRadius: '50%', background: 'radial-gradient(closest-side, rgba(255, 214, 240, 0.55), transparent 75%)' }}></div>
            <div style={{ position: 'absolute', inset: '14% 22%', borderRadius: '50%', background: 'radial-gradient(closest-side, rgba(196, 241, 249, 0.40), transparent 75%)' }}></div>

            {/* Pixel ground */}
            <div style={{ position: 'absolute', left: '5%', right: '5%', bottom: '8%', height: 8, background: 'repeating-linear-gradient(90deg, #C4B6F0 0 12px, transparent 12px 22px)', borderRadius: 4 }}></div>

            <div className="hero-character bob bob-0" style={{ left: '12%', bottom: '14%' }}>
              <CharLead size={6} />
            </div>
            <div className="hero-character bob bob-2" style={{ left: '37%', bottom: '14%' }}>
              <CharDesigner size={6} />
            </div>
            <div className="hero-character bob bob-3" style={{ left: '62%', bottom: '14%' }}>
              <CharPlanner size={6} />
            </div>
            <div className="hero-character bob bob-0" style={{ left: '87%', bottom: '14%' }}>
              <CharDev size={6} />
            </div>

            {/* Floating stat cards */}
            <div className="hero-stat-card bob bob-2" style={{ top: '10%', right: '0%' }}>
              <Star size={3} color="#D4A82E" />
              <div>
                <div className="num">{t('hero_stat1_num')}</div>
                <div className="label">{t('hero_stat1_label')}</div>
              </div>
            </div>
            <div className="hero-stat-card bob bob-1" style={{ top: '38%', left: '-8%' }}>
              <Sparkle size={3} color="#8B7BC4" />
              <div>
                <div className="num">{t('hero_stat2_num')}</div>
                <div className="label">{t('hero_stat2_label')}</div>
              </div>
            </div>

            {/* Tiny floating sparkles */}
            <Sparkle size={3} className="twinkle" style={{ position: 'absolute', top: '18%', left: '50%' }} />
            <Sparkle size={3} className="twinkle" style={{ position: 'absolute', top: '60%', right: '5%', animationDelay: '-1s' }} />
            <Star size={3} className="twinkle" style={{ position: 'absolute', top: '70%', left: '8%', animationDelay: '-1.5s' }} color="#FFE89A" />
          </div>
        </div>
      </div>

      <div className="scroll-cue">
        <div className="scroll-cue-mouse"></div>
        <span>{t('scroll')}</span>
      </div>
    </section>
  );
}

/* =========================================================
   About
   ========================================================= */
function About({ onOpenResume }) {
  const [ref, seen] = useReveal();
  const { t } = useLang();
  const [hdg0, hdg1] = t('about_heading').split('\n');
  const [hello0, hello1] = t('about_hello').split('\n');
  return (
    <section className="section tint-lavender" id="about">
      <div className="section-bg-tint"></div>
      <div className="section-inner">
        <div ref={ref} className={`s-head reveal ${seen ? 'in' : ''}`}>
          <span className="eyebrow"><span className="eyebrow-dot"></span>{t('about_eyebrow')}</span>
          <h2>{hdg0}<br/><span className="under">{hdg1}</span></h2>
          <p className="s-sub">{t('about_sub')}</p>
        </div>

        <div className={`about-grid reveal-stagger ${seen ? 'in' : ''}`}>
          <div className="about-card">
            <h3>{hello0}<br/>{hello1}</h3>
            <p>{t('about_story1')}</p>
            <p style={{ marginTop: 14 }}>{t('about_story2')}</p>
            <div className="about-stat-row">
              <div className="about-stat"><div className="v">{t('about_yr_val')}</div><div className="k">{t('about_yr_label')}</div></div>
              <div className="about-stat"><div className="v">{t('about_wk_val')}</div><div className="k">{t('about_wk_label')}</div></div>
              <div className="about-stat"><div className="v">{t('about_q_val')}</div><div className="k">{t('about_q_label')}</div></div>
            </div>
          </div>

          <div className="about-scene">
            <Cloud size={6} className="bob bob-0" style={{ position: 'absolute', top: '8%', left: '10%' }} />
            <Cloud size={4} className="bob bob-2" style={{ position: 'absolute', top: '18%', right: '12%', opacity: 0.7 }} />
            <Star size={4} className="twinkle" style={{ position: 'absolute', top: '30%', left: '50%' }} />
            <Sparkle size={3} className="twinkle" style={{ position: 'absolute', top: '55%', left: '20%' }} />
            <Diamond size={3} className="twinkle" style={{ position: 'absolute', top: '20%', right: '30%', animationDelay: '-1s' }} />
            <Heart size={3} className="twinkle" style={{ position: 'absolute', bottom: '20%', right: '8%' }} />

            <div style={{ position: 'absolute', left: '10%', right: '10%', bottom: '14%', height: 6, background: 'repeating-linear-gradient(90deg, rgba(107,91,168,0.4) 0 10px, transparent 10px 18px)' }}></div>

            <div className="mini-char bob bob-0" style={{ position: 'absolute', bottom: '20%', left: '12%' }} data-anim="wobble">
              <span className="mini-char-tag" style={{ background: 'var(--c-purple)' }}>Director</span>
              <CharLead size={5} />
            </div>
            <div className="mini-char bob bob-2" style={{ position: 'absolute', bottom: '20%', left: '37%' }} data-anim="lift">
              <span className="mini-char-tag" style={{ background: '#D4A82E' }}>Designer</span>
              <CharDesigner size={5} />
            </div>
            <div className="mini-char bob bob-3" style={{ position: 'absolute', bottom: '20%', left: '62%' }} data-anim="jiggle">
              <span className="mini-char-tag" style={{ background: '#D88BB8' }}>Planner</span>
              <CharPlanner size={5} />
            </div>
            <div className="mini-char bob bob-3" style={{ position: 'absolute', bottom: '20%', left: '87%' }} data-anim="sway">
              <span className="mini-char-tag" style={{ background: '#5BA8B5' }}>Developer</span>
              <CharDev size={5} />
            </div>
          </div>
        </div>

        {/* Core team */}
        <div style={{ display: 'flex', justifyContent: 'center', marginTop: 80, marginBottom: 24 }}>
          <span className="eyebrow"><span className="eyebrow-dot"></span>{t('about_core')}</span>
        </div>
        <div className="team-grid">
          {TEAM.map((m, i) => (
            <TeamCard key={m.name} member={m} index={i} onOpen={onOpenResume} />
          ))}
        </div>

        {/* Moonlighters */}
        <div style={{ display: 'flex', justifyContent: 'center', marginTop: 72, marginBottom: 24 }}>
          <span className="eyebrow"><span className="eyebrow-dot"></span>WITH US · {t('about_with')}</span>
        </div>
        <p style={{ textAlign: 'center', color: 'var(--t-soft)', fontSize: 15, maxWidth: 560, margin: '0 auto 32px' }}>
          {t('about_partner_sub')}
        </p>
        <div className="moonlighter-grid">
          {MOONLIGHTERS.map((m, i) => (
            <MoonlighterCard key={m.name} member={m} index={i} />
          ))}
        </div>
      </div>
    </section>
  );
}

const TEAM = [
  {
    id: 'lead',
    name: '윤다민', nameEn: 'Yun Damin',
    role: 'DIRECTOR · 총괄', roleEn: 'DIRECTOR · Head', roleJa: 'DIRECTOR · 総括',
    bio: '5년차 풀스택. 기획·디자인·개발을 모두 거쳐 지금은 팀의 사령탑이에요. 모든 프로젝트의 첫 미팅을 책임집니다.',
    bioEn: '5-year full-stack veteran. Has done planning, design, and dev — now leads the whole team. Handles every first client meeting personally.',
    bioJa: '5年のフルスタック経験。企画・デザイン・開発をすべて経て、現在はチームのリーダー。すべての初回ミーティングを自ら担当します。',
    skills: ['전략기획', 'UX 리서치', 'React', 'Next.js'],
    skillsEn: ['Strategic Planning', 'UX Research', 'React', 'Next.js'],
    skillsJa: ['戦略企画', 'UXリサーチ', 'React', 'Next.js'],
    color: 'lavender', char: 'lead',
  },
  {
    id: 'harin',
    name: '서현진', nameEn: 'Seo Hyeonjin',
    role: 'DESIGNER · UI/UX', roleEn: 'DESIGNER · UI/UX', roleJa: 'DESIGNER · UI/UX',
    bio: '브랜드 아이덴티티와 패키지, 로고에서 UI/UX까지 폭넓게 다루는 디자이너. 일관된 브랜드 경험과 디테일한 마감으로 사용성과 감성을 함께 담습니다.',
    bioEn: 'A designer spanning brand identity, packaging, and logos through to UI/UX. Crafts consistent brand experiences with meticulous finishing that balances usability and emotion.',
    bioJa: 'ブランドアイデンティティやパッケージ、ロゴからUI/UXまで幅広く手がけるデザイナー。一貫したブランド体験と丁寧な仕上げで、使いやすさと感性を両立します。',
    skills: ['브랜드 디자인', 'UI/UX', 'Figma', '패키지'],
    skillsEn: ['Brand Design', 'UI/UX', 'Figma', 'Packaging'],
    skillsJa: ['ブランドデザイン', 'UI/UX', 'Figma', 'パッケージ'],
    color: 'yellow', char: 'designer',
  },
  {
    id: 'planner',
    name: '김하늘', nameEn: 'Kim Haneul',
    role: 'PLANNER · 기획', roleEn: 'PLANNER · Planning', roleJa: 'PLANNER · 企画',
    bio: '서비스 기획자. 와이어프레임부터 IA, 콘텐츠 전략까지. 한 줄의 카피를 다듬는 데 한나절을 쓰는 사람이에요.',
    bioEn: 'Service planner covering wireframes, IA, and content strategy. Known to spend half a day perfecting a single line of copy.',
    bioJa: 'サービス企画者。ワイヤーフレームからIA・コンテンツ戦略まで。1行のコピーを磨くのに半日かける人。',
    skills: ['서비스 기획', 'IA', 'UX 라이팅', 'Figma'],
    skillsEn: ['Service Planning', 'IA', 'UX Writing', 'Figma'],
    skillsJa: ['サービス企画', 'IA', 'UXライティング', 'Figma'],
    color: 'pink', char: 'planner',
  },
  {
    id: 'dev',
    name: '정준혁', nameEn: 'Junhyeok Jeong',
    role: 'DEVELOPER · 개발', roleEn: 'DEVELOPER · Dev', roleJa: 'DEVELOPER · 開発',
    bio: '프론트엔드부터 백엔드까지. 코드보다 코드리뷰가 더 재밌다는, 약간 이상한 사람이에요. 새벽 4시까지 디버깅 가능.',
    bioEn: 'Front-to-back developer who somehow enjoys code reviews more than coding. Available for debugging sessions past 4 AM.',
    bioJa: 'フロントからバックエンドまで。コードよりコードレビューが好きという変わり者。朝4時までデバッグ可能。',
    skills: ['React', 'Node.js', 'TypeScript', 'AWS'],
    skillsEn: ['React', 'Node.js', 'TypeScript', 'AWS'],
    skillsJa: ['React', 'Node.js', 'TypeScript', 'AWS'],
    color: 'cyan', char: 'dev',
  },
];

const MOONLIGHTERS = [
  {
    name: '이지우', nameEn: 'Lee Jiwoo',
    role: '현직 테크 스타트업 프로덕트 디자이너', roleEn: 'Product Designer at a Tech Startup', roleJa: 'テックスタートアップ プロダクトデザイナー',
    bio: '7년차 UI/UX 디자이너. Figma 기반 UX 설계부터 디자인 시스템 구축까지 전 과정을 맡아요.',
    bioEn: '7-year UI/UX designer. Covers everything from Figma-based UX design to building design systems.',
    bioJa: '7年のUI/UXデザイナー。FigmaベースのUX設計からデザインシステム構築まで全工程を担当します。',
    tag: 'UI/UX 파트너', tagEn: 'UI/UX Partner', tagJa: 'UI/UXパートナー', color: 'pink', char: 'designer',
  },
  {
    name: '박서현', nameEn: 'Park Seohyun',
    role: '현직 브랜딩 에이전시 수석 디자이너', roleEn: 'Lead Designer at a Branding Agency', roleJa: 'ブランディングエージェンシー シニアデザイナー',
    bio: '9년차 브랜드 디자이너. BI 설계, 패키지, 인쇄물까지 브랜드 전 영역의 감도를 책임집니다.',
    bioEn: '9-year brand designer. Handles BI, packaging, and print — responsible for the full brand aesthetic.',
    bioJa: '9年のブランドデザイナー。BI設計・パッケージ・印刷物まで、ブランド全領域のクオリティを担います。',
    tag: '브랜드 파트너', tagEn: 'Brand Partner', tagJa: 'ブランドパートナー', color: 'yellow', char: 'designer',
  },
  {
    name: '최민호', nameEn: 'Choi Minho',
    role: '현직 커머스 플랫폼 서비스 기획자', roleEn: 'Service Planner at a Commerce Platform', roleJa: 'コマースプラットフォーム サービス企画者',
    bio: '6년차 서비스 기획자. IA 설계·와이어프레임·UX 라이팅이 주특기. 요구사항을 구조로 바꿉니다.',
    bioEn: '6-year service planner. Specializes in IA, wireframes, and UX writing. Turns requirements into structure.',
    bioJa: '6年のサービス企画者。IA設計・ワイヤーフレーム・UXライティングが得意。要件を構造に変えます。',
    tag: '기획 파트너', tagEn: 'Planning Partner', tagJa: '企画パートナー', color: 'lavender', char: 'planner',
  },
  {
    name: '김나영', nameEn: 'Kim Nayoung',
    role: '현직 핀테크 프로덕트 매니저', roleEn: 'Product Manager at a Fintech Company', roleJa: 'フィンテック プロダクトマネージャー',
    bio: '8년차 PM. 요구사항 정의부터 스프린트 운영·출시까지 전 과정을 조율하고 속도를 냅니다.',
    bioEn: '8-year PM. Coordinates requirements, sprints, and launch from start to finish — and keeps things moving.',
    bioJa: '8年のPM。要件定義からスプリント運営・出荷まで全工程を調整し、スピードを出します。',
    tag: 'PM 파트너', tagEn: 'PM Partner', tagJa: 'PMパートナー', color: 'cyan', char: 'lead',
  },
  {
    name: '정승호', nameEn: 'Jeong Seungho',
    role: '현직 IT 대기업 프론트엔드 개발자', roleEn: 'Frontend Developer at a Major IT Corp', roleJa: 'IT大手 フロントエンドデベロッパー',
    bio: '7년차 프론트엔드. React·Next.js 전문. 퍼블리싱부터 상태관리·성능 최적화까지 맡아요.',
    bioEn: '7-year frontend dev. React & Next.js specialist. From publishing to state management and performance tuning.',
    bioJa: '7年のフロントエンド。React・Next.js専門。パブリッシングから状態管理・パフォーマンス最適化まで担当。',
    tag: '프론트엔드 파트너', tagEn: 'Frontend Partner', tagJa: 'フロントエンドパートナー', color: 'pink', char: 'dev',
  },
  {
    name: '한준서', nameEn: 'Han Junseo',
    role: '현직 클라우드 기업 백엔드 엔지니어', roleEn: 'Backend Engineer at a Cloud Company', roleJa: 'クラウド企業 バックエンドエンジニア',
    bio: '8년차 백엔드. Node.js·Spring 기반 API 설계, 대용량 트래픽 처리, 인프라 구성이 전문입니다.',
    bioEn: '8-year backend engineer. API design, high-traffic processing, and infra setup with Node.js & Spring.',
    bioJa: '8年のバックエンド。Node.js・Spring基盤のAPI設計・大量トラフィック処理・インフラ構成が専門。',
    tag: '백엔드 파트너', tagEn: 'Backend Partner', tagJa: 'バックエンドパートナー', color: 'cyan', char: 'dev',
  },
  {
    name: '오다은', nameEn: 'Oh Daeun',
    role: '현직 모바일 스타트업 앱 개발자', roleEn: 'App Developer at a Mobile Startup', roleJa: 'モバイルスタートアップ アプリ開発者',
    bio: '6년차 앱 개발자. React Native·Swift 전문. 앱스토어·플레이스토어 배포 20회 이상 경험.',
    bioEn: '6-year app developer. React Native & Swift. 20+ App Store and Play Store releases.',
    bioJa: '6年のアプリ開発者。React Native・Swift専門。App Store・Play Storeへの配信20回以上の実績。',
    tag: '앱 파트너', tagEn: 'App Partner', tagJa: 'アプリパートナー', color: 'lavender', char: 'dev',
  },
  {
    name: '윤채린', nameEn: 'Yoon Chaerin',
    role: '현직 디지털 마케팅 에이전시 팀장', roleEn: 'Team Lead at a Digital Marketing Agency', roleJa: 'デジタルマーケティングエージェンシー チームリーダー',
    bio: '7년차 마케터. SNS 채널 기획, 콘텐츠 마케팅, 메타·구글 광고 집행을 총괄합니다.',
    bioEn: '7-year marketer. Leads SNS channel strategy, content marketing, and Meta & Google ad campaigns.',
    bioJa: '7年のマーケター。SNSチャンネル企画・コンテンツマーケティング・Meta・Google広告を統括します。',
    tag: '마케팅 파트너', tagEn: 'Marketing Partner', tagJa: 'マーケティングパートナー', color: 'yellow', char: 'lead',
  },
];

function MoonlighterCard({ member, index }) {
  const [ref, seen] = useReveal(0.15);
  const { lang } = useLang();
  const Char = { lead: CharLead, planner: CharPlanner, dev: CharDev, designer: CharDesigner, designer2: CharDesigner2 }[member.char];
  const n = lang === 'ko' ? member.name : member.nameEn;
  const tag = lang === 'ko' ? member.tag : lang === 'ja' ? member.tagJa : member.tagEn;
  const role = lang === 'ko' ? member.role : lang === 'ja' ? member.roleJa : member.roleEn;
  const bio = lang === 'ko' ? member.bio : lang === 'ja' ? member.bioJa : member.bioEn;
  return (
    <div ref={ref} className={`ml-card reveal ${seen ? 'in' : ''}`} data-c={member.color} style={{ transitionDelay: `${index * 80}ms` }}>
      <div className={`ml-avatar bob bob-${index}`}>
        <Char size={4} />
      </div>
      <div className="ml-meta">
        <div className="ml-name">{n} <span className="ml-tag">{tag}</span></div>
        <div className="ml-role">{role}</div>
        <p className="ml-bio">{bio}</p>
      </div>
    </div>
  );
}

function TeamCard({ member, index, onOpen }) {
  const [ref, seen] = useReveal(0.2);
  const { t, lang } = useLang();
  const Char = { lead: CharLead, planner: CharPlanner, dev: CharDev, designer: CharDesigner, designer2: CharDesigner2 }[member.char];
  const n = lang === 'ko' ? member.name : member.nameEn;
  const role = t(`team_${member.id}_role`);
  const bio = t(`team_${member.id}_bio`);
  const skills = t(`team_${member.id}_skills`).split(',');
  return (
    <div
      ref={ref}
      className={`team-card reveal ${seen ? 'in' : ''}`}
      data-c={member.color}
      style={{ transitionDelay: `${index * 100}ms` }}
      onClick={() => onOpen(member.id)}
      role="button"
      tabIndex={0}
    >
      <div className={`team-avatar bob bob-${index}`}>
        <Char size={6} />
      </div>
      <div className="team-name">{n}</div>
      <div className="team-role">{role}</div>
      <p className="team-bio">{bio}</p>
      <div className="team-skills">
        {skills.map(s => <span key={s} className="team-skill">{s}</span>)}
      </div>
      <div className="team-cta">
        <span>{t('team_cta')}</span> <span className="arrow-r">→</span>
      </div>
    </div>
  );
}

/* =========================================================
   Services
   ========================================================= */
function Services() {
  const [ref, seen] = useReveal();
  const { t } = useLang();
  const SERVICES = [
    { n:'01', t:t('svc1_t'), c:'lavender', ico:<IcoBrand size={5} />, d:t('svc1_d'), items:[t('svc1_i1'),t('svc1_i2'),t('svc1_i3')] },
    { n:'02', t:t('svc2_t'), c:'pink',     ico:<IcoWeb size={5} />,   d:t('svc2_d'), items:[t('svc2_i1'),t('svc2_i2'),t('svc2_i3')] },
    { n:'03', t:t('svc3_t'), c:'cyan',     ico:<IcoApp size={5} />,   d:t('svc3_d'), items:[t('svc3_i1'),t('svc3_i2'),t('svc3_i3')] },
    { n:'04', t:t('svc4_t'), c:'yellow',   ico:<IcoFlag size={5} />,  d:t('svc4_d'), items:[t('svc4_i1'),t('svc4_i2'),t('svc4_i3')] },
    { n:'05', t:t('svc5_t'), c:'mint',     ico:<IcoSwatch size={5} />,d:t('svc5_d'), items:[t('svc5_i1'),t('svc5_i2'),t('svc5_i3')] },
    { n:'06', t:t('svc6_t'), c:'lavender', ico:<IcoChat size={5} />,  d:t('svc6_d'), items:[t('svc6_i1'),t('svc6_i2'),t('svc6_i3')] },
  ];
  return (
    <section className="section tint-pink" id="services">
      <div className="section-bg-tint"></div>
      <div className="section-inner">
        <div ref={ref} className={`s-head reveal ${seen ? 'in' : ''}`}>
          <span className="eyebrow"><span className="eyebrow-dot"></span>{t('svc_eyebrow')}</span>
          <h2>{t('svc_heading')}</h2>
          <p className="s-sub">{t('svc_sub')}</p>
        </div>

        <div className={`services-grid reveal-stagger ${seen ? 'in' : ''}`}>
          {SERVICES.map(s => (
            <div key={s.t} className="service-card" data-c={s.c}>
              <span className="service-card-num">{s.n}</span>
              <div className="service-card-icon">{s.ico}</div>
              <h3>{s.t}</h3>
              <p>{s.d}</p>
              <ul>{s.items.map(i => <li key={i}>{i}</li>)}</ul>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}


/* =========================================================
   Skills
   ========================================================= */
function Skills() {
  const [ref, seen] = useReveal();
  const { t } = useLang();
  const CATS = [
    { title: 'DESIGN', items: [
      { n: 'Figma', l: 5 }, { n: 'Adobe Suite', l: 5 }, { n: 'Framer', l: 4 },
      { n: 'After Effects', l: 4 }, { n: 'Rive', l: 3 },
    ]},
    { title: 'FRONTEND', items: [
      { n: 'React / Next.js', l: 5 }, { n: 'TypeScript', l: 5 }, { n: 'Tailwind', l: 5 },
      { n: 'Three.js', l: 3 }, { n: 'GSAP', l: 4 },
    ]},
    { title: 'MOBILE', items: [
      { n: 'React Native', l: 5 }, { n: 'Flutter', l: 4 }, { n: 'Swift / iOS', l: 4 },
      { n: 'Kotlin / Android', l: 4 }, { n: 'Expo', l: 5 },
    ]},
    { title: 'BACKEND', items: [
      { n: 'Node.js', l: 5 }, { n: 'NestJS', l: 4 }, { n: 'Postgres', l: 4 },
      { n: 'GraphQL', l: 4 }, { n: 'Supabase', l: 4 },
    ]},
    { title: 'INFRA', items: [
      { n: 'AWS', l: 5 }, { n: 'GCP', l: 4 }, { n: 'Vercel', l: 5 },
      { n: 'Docker', l: 4 }, { n: 'GitHub Actions', l: 5 },
    ]},
    { title: 'PRODUCT', items: [
      { n: 'Notion', l: 5 }, { n: 'Linear', l: 5 }, { n: 'Slack', l: 5 },
      { n: 'GA4 / Mixpanel', l: 4 }, { n: 'Hotjar', l: 4 },
    ]},
  ];
  const marquee = ['React', 'TypeScript', 'Next.js', 'Figma', 'Tailwind', 'Node.js', 'Swift', 'Kotlin', 'Flutter', 'GSAP', 'Three.js', 'Framer', 'Supabase', 'GraphQL', 'Vercel', 'AWS', 'GCP', 'Docker', 'React Native'];
  return (
    <section className="section tint-cyan" id="skills">
      <div className="section-bg-tint"></div>
      <div className="section-inner">
        <div ref={ref} className={`s-head reveal ${seen ? 'in' : ''}`}>
          <span className="eyebrow"><span className="eyebrow-dot"></span>{t('skill_eyebrow')}</span>
          <h2>{t('skill_heading')}</h2>
          <p className="s-sub">{t('skill_sub')}</p>
        </div>

        <div className={`skills-frame reveal ${seen ? 'in' : ''}`}>
          <div className="skills-cats">
            {CATS.map(cat => (
              <div key={cat.title}>
                <div className="skills-cat-title">▸ {cat.title}</div>
                <div className="skill-row">
                  {cat.items.map(it => (
                    <div key={it.n} className="skill-pill">
                      <span>{it.n}</span>
                      <span className="lvl">
                        {[1,2,3,4,5].map(i => <span key={i} className={i <= it.l ? 'on' : ''}></span>)}
                      </span>
                    </div>
                  ))}
                </div>
              </div>
            ))}
          </div>

          <div className="skills-marquee">
            <div className="marquee-track">
              {[...marquee, ...marquee].map((m, i) => (
                <div key={i} className="marquee-item">
                  <span style={{ width: 8, height: 8, background: 'var(--c-purple)', borderRadius: 2 }}></span>
                  {m}
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* =========================================================
   DesignGallery — 디자인 갤러리 (앨범별 수평 슬라이더)
   ========================================================= */
const HARIN_ALBUM_KEYS = [
  'harin_app', 'harin_brand', 'harin_stream', 'harin_food',
  'harin_product', 'harin_outdoor', 'harin_package', 'harin_landing',
  'harin_sns', 'harin_promo', 'harin_clinic', 'harin_web',
  'harin_print', 'harin_logo',
];
const HARIN_FILTER_GROUPS = [
  { id: 'all' },
  { id: 'uxui', keys: ['harin_app', 'harin_stream', 'harin_food', 'harin_product', 'harin_outdoor'] },
  { id: 'brand', keys: ['harin_brand', 'harin_logo'] },
  { id: 'print', keys: ['harin_package', 'harin_print'] },
  { id: 'web', keys: ['harin_landing', 'harin_sns', 'harin_web', 'harin_promo', 'harin_clinic'] },
];

function toThumbSrc(src) {
  return src.replace('/portfolio/harin/', '/portfolio/harin/thumbs/').replace(/\.(png|jpeg)$/i, '.jpg');
}

// 슬라이더 카드 — 개별 이미지
// useThumb=true → /thumbs/ 소형 이미지 (4장+ 스크롤 모드용)
// useThumb=false → 원본 이미지 (1/2/3장 대형 카드용, 화질 보장)
function DgSlideCard({ img, onClick, useThumb }) {
  const [loaded, setLoaded] = useState(false);
  const [err, setErr] = useState(false);
  const src = useThumb ? toThumbSrc(img.src) : img.src;
  return (
    <button className="dg-slide-card" onClick={onClick} title={img.caption || ''}>
      {!loaded && !err && <div className="dg-slide-skel" />}
      <img
        src={src}
        alt={img.caption || ''}
        className={`dg-slide-img ${loaded ? 'loaded' : ''}`}
        loading="lazy"
        decoding="async"
        onLoad={() => setLoaded(true)}
        onError={() => { setErr(true); setLoaded(true); }}
      />
      {img.caption && <span className="dg-slide-cap">{img.caption}</span>}
    </button>
  );
}

// 앨범별 수평 슬라이더
function DgAlbumSlider({ albumKey, project, lang, onImageClick }) {
  const trackRef = useRef(null);
  const [atStart, setAtStart] = useState(true);
  const [atEnd, setAtEnd] = useState(false);

  const count = project.images.length;
  const isScroll = count > 3; // 4장 이상만 스크롤 모드

  function checkBounds() {
    const el = trackRef.current;
    if (!el) return;
    setAtStart(el.scrollLeft <= 2);
    setAtEnd(el.scrollLeft >= el.scrollWidth - el.clientWidth - 2);
  }

  useEffect(() => {
    if (!isScroll) return;
    const el = trackRef.current;
    if (!el) return;
    el.addEventListener('scroll', checkBounds, { passive: true });
    const t = setTimeout(checkBounds, 300);
    return () => { el.removeEventListener('scroll', checkBounds); clearTimeout(t); };
  }, [isScroll]);

  function slide(dir) {
    const el = trackRef.current;
    if (el) el.scrollBy({ left: dir * 640, behavior: 'smooth' });
  }

  const title = lang === 'ko' ? project.title
    : lang === 'ja' ? (project.titleJa || project.titleEn) : project.titleEn;

  const countAttr = count <= 3 ? String(count) : 'many';

  return (
    <div className="dg-album-slider">
      <div className="dg-as-hd">
        <span className="dg-as-name">{title}</span>
        <span className="dg-as-cnt">{count}</span>
        {isScroll && (
          <div className="dg-as-nav">
            <button className="dg-as-arr" disabled={atStart} onClick={() => slide(-1)}>‹</button>
            <button className="dg-as-arr" disabled={atEnd} onClick={() => slide(1)}>›</button>
          </div>
        )}
      </div>
      <div className="dg-as-track" ref={trackRef} data-count={countAttr}>
        {project.images.map((img, i) => (
          <DgSlideCard key={i} img={img} onClick={() => onImageClick(i)} useThumb={isScroll} />
        ))}
      </div>
    </div>
  );
}

// 라이트박스 이미지 컴포넌트 (fade 전환 + preload + zoom/pan)
function DgLightboxImg({ src, alt, images, index, zoom, pan, isDragging }) {
  const [loaded, setLoaded] = useState(false);
  const [curSrc, setCurSrc] = useState(src);

  useEffect(() => {
    setLoaded(false);
    setCurSrc(src);
    [-1, 1, 2].forEach(offset => {
      const ni = index + offset;
      if (ni >= 0 && ni < images.length) {
        const img = new Image();
        img.src = images[ni].src;
      }
    });
  }, [src]);

  return (
    <div className="dg-lb-img-wrap">
      {!loaded && <div className="dg-lb-skeleton" />}
      <img
        key={curSrc}
        src={curSrc}
        alt={alt}
        className={`dg-lb-img ${loaded ? 'loaded' : ''}`}
        style={{
          transform: `scale(${zoom}) translate(${pan.x / zoom}px, ${pan.y / zoom}px)`,
          transformOrigin: 'center center',
          transition: isDragging ? 'none' : 'transform 0.15s ease',
          userSelect: 'none',
        }}
        onLoad={() => setLoaded(true)}
        draggable={false}
      />
    </div>
  );
}

function DesignGallery() {
  const { lang } = useLang();
  const isKo = lang === 'ko';
  const isJa = lang === 'ja';
  const pick = (ko, en, ja) => isKo ? ko : isJa ? (ja || en) : en;

  const [filter, setFilter] = useState('all');
  const [lightbox, setLightbox] = useState(null);
  const touchStartX = useRef(null);
  const [ref, seen] = useReveal();

  // 줌/팬 상태
  const [lbZoom, setLbZoom] = useState(1);
  const [lbPan, setLbPan] = useState({ x: 0, y: 0 });
  const [isDragging, setIsDragging] = useState(false);
  const lbDragRef = useRef(null);
  const lbContentRef = useRef(null);

  const PI = window.PROJECT_INFO;

  const filterLabels = {
    all:   { ko: '전체', en: 'All', ja: '全て' },
    uxui:  { ko: 'UI/UX', en: 'UI/UX', ja: 'UI/UX' },
    brand: { ko: '브랜드', en: 'Brand', ja: 'ブランド' },
    print: { ko: '인쇄·패키지', en: 'Print', ja: '印刷·パッケージ' },
    web:   { ko: '웹·SNS', en: 'Web/SNS', ja: 'Web·SNS' },
  };

  const filteredKeys = filter === 'all'
    ? HARIN_ALBUM_KEYS
    : (HARIN_FILTER_GROUPS.find(f => f.id === filter)?.keys || HARIN_ALBUM_KEYS);

  const allImages = filteredKeys.flatMap(key =>
    PI[key].images.map(img => ({
      ...img,
      albumTitle: PI[key].title,
      albumTitleEn: PI[key].titleEn,
      albumTitleJa: PI[key].titleJa,
    }))
  );

  const openLightbox = (albumKey, imgIndex) => {
    const flatIndex = filteredKeys
      .slice(0, filteredKeys.indexOf(albumKey))
      .reduce((acc, k) => acc + PI[k].images.length, 0) + imgIndex;
    setLightbox({ images: allImages, index: flatIndex });
  };

  const lbPrev = () => { setLightbox(lb => lb ? { ...lb, index: (lb.index - 1 + lb.images.length) % lb.images.length } : null); };
  const lbNext = () => { setLightbox(lb => lb ? { ...lb, index: (lb.index + 1) % lb.images.length } : null); };

  // 이미지 변경 시 줌/팬 리셋
  useEffect(() => {
    setLbZoom(1);
    setLbPan({ x: 0, y: 0 });
    setIsDragging(false);
    lbDragRef.current = null;
  }, [lightbox?.index]);

  // 휠 이벤트 (non-passive, 페이지 스크롤 차단)
  useEffect(() => {
    const el = lbContentRef.current;
    if (!el || !lightbox) return;
    const onWheel = (e) => {
      e.preventDefault();
      const delta = e.deltaY > 0 ? -0.25 : 0.25;
      setLbZoom(z => {
        const nz = Math.max(1, Math.min(5, z + delta));
        if (nz === 1) setLbPan({ x: 0, y: 0 });
        return nz;
      });
    };
    el.addEventListener('wheel', onWheel, { passive: false });
    return () => el.removeEventListener('wheel', onWheel);
  }, [lightbox]);

  const lbZoomIn  = () => setLbZoom(z => Math.min(5, parseFloat((z + 0.5).toFixed(1))));
  const lbZoomOut = () => setLbZoom(z => { const nz = Math.max(1, parseFloat((z - 0.5).toFixed(1))); if (nz === 1) setLbPan({ x: 0, y: 0 }); return nz; });
  const lbReset   = () => { setLbZoom(1); setLbPan({ x: 0, y: 0 }); };

  const onLbMouseDown = (e) => {
    if (lbZoom <= 1) return;
    e.preventDefault();
    setIsDragging(true);
    lbDragRef.current = { startX: e.clientX - lbPan.x, startY: e.clientY - lbPan.y };
  };
  const onLbMouseMove = (e) => {
    if (!lbDragRef.current) return;
    setLbPan({ x: e.clientX - lbDragRef.current.startX, y: e.clientY - lbDragRef.current.startY });
  };
  const onLbMouseUp = () => { setIsDragging(false); lbDragRef.current = null; };

  useEffect(() => {
    if (!lightbox) return;
    const handler = (e) => {
      if (e.key === 'ArrowLeft') lbPrev();
      else if (e.key === 'ArrowRight') lbNext();
      else if (e.key === 'Escape') setLightbox(null);
      else if (e.key === '+' || e.key === '=') lbZoomIn();
      else if (e.key === '-') lbZoomOut();
      else if (e.key === '0') lbReset();
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, [lightbox]);

  useEffect(() => {
    document.body.style.overflow = lightbox ? 'hidden' : '';
    return () => { document.body.style.overflow = ''; };
  }, [lightbox]);

  const onTouchStart = (e) => { touchStartX.current = e.touches[0].clientX; };
  const onTouchEnd = (e) => {
    if (touchStartX.current === null) return;
    const dx = e.changedTouches[0].clientX - touchStartX.current;
    if (Math.abs(dx) > 40) { dx < 0 ? lbNext() : lbPrev(); }
    touchStartX.current = null;
  };

  const cur = lightbox ? lightbox.images[lightbox.index] : null;

  return (
    <div className="design-gallery-block">
      <div ref={ref} className={`design-gallery-head reveal ${seen ? 'in' : ''}`}>
        <span className="eyebrow"><span className="eyebrow-dot"></span>DESIGN GALLERY</span>
        <h3>{pick('디자인 갤러리', 'Design Gallery', 'デザインギャラリー')}</h3>
        <p>{pick('브랜드·UI/UX·패키지·웹 — 전체 디자인 작업물', 'Brand · UI/UX · Packaging · Web — All design works', 'ブランド·UI/UX·パッケージ·Web — 全デザイン作品')}</p>
      </div>

      <div className="design-gallery-filters">
        {HARIN_FILTER_GROUPS.map(f => (
          <button key={f.id}
            className={`dg-filter ${filter === f.id ? 'on' : ''}`}
            onClick={() => setFilter(f.id)}>
            {pick(filterLabels[f.id].ko, filterLabels[f.id].en, filterLabels[f.id].ja)}
          </button>
        ))}
      </div>

      <div className="design-gallery-sliders">
        {filteredKeys.map(key => (
          <DgAlbumSlider
            key={key}
            albumKey={key}
            project={PI[key]}
            lang={lang}
            onImageClick={(i) => openLightbox(key, i)}
          />
        ))}
      </div>

      {lightbox && cur && ReactDOM.createPortal(
        <div className="dg-lightbox"
          onClick={() => { if (lbZoom <= 1) setLightbox(null); }}
          onTouchStart={onTouchStart}
          onTouchEnd={onTouchEnd}>
          <button className="dg-lb-close" onClick={() => setLightbox(null)}>✕</button>
          <button className="dg-lb-prev" onClick={(e) => { e.stopPropagation(); lbPrev(); }}>‹</button>
          <div className="dg-lb-content" ref={lbContentRef}
            onClick={(e) => e.stopPropagation()}
            onMouseDown={onLbMouseDown}
            onMouseMove={onLbMouseMove}
            onMouseUp={onLbMouseUp}
            onMouseLeave={onLbMouseUp}
            style={{ cursor: lbZoom > 1 ? (isDragging ? 'grabbing' : 'grab') : 'default' }}>
            <DgLightboxImg
              src={cur.src}
              alt={cur.caption || ''}
              images={lightbox.images}
              index={lightbox.index}
              zoom={lbZoom}
              pan={lbPan}
              isDragging={isDragging}
            />
            <div className="dg-lb-caption">
              <span className="dg-lb-album">{pick(cur.albumTitle, cur.albumTitleEn, cur.albumTitleJa)}</span>
              {cur.caption && <span className="dg-lb-text">{cur.caption}</span>}
              <span className="dg-lb-counter">{lightbox.index + 1} / {lightbox.images.length}</span>
            </div>
          </div>
          <button className="dg-lb-next" onClick={(e) => { e.stopPropagation(); lbNext(); }}>›</button>
          <div className="dg-lb-zoom-bar" onClick={(e) => e.stopPropagation()}>
            <button className="dg-lb-zoom-btn" onClick={lbZoomOut} disabled={lbZoom <= 1}>−</button>
            <span className="dg-lb-zoom-pct">{Math.round(lbZoom * 100)}%</span>
            <button className="dg-lb-zoom-btn" onClick={lbZoomIn} disabled={lbZoom >= 5}>+</button>
            {lbZoom > 1 && <button className="dg-lb-zoom-reset" onClick={lbReset}>↺</button>}
          </div>
        </div>,
        document.body
      )}
    </div>
  );
}

/* =========================================================
   Portfolio
   ========================================================= */
const PROJECTS = [
  { id: 'dash', title: '콘텐츠랩', titleEn: 'ContentLab', titleJa: 'コンテンツラボ', client: '크리에이터 SaaS · 2025', clientEn: 'Creator SaaS · 2025', clientJa: 'クリエイターSaaS · 2025', desc: '유튜버를 위한 통합 분석 대시보드. 5개 플랫폼 지표를 한눈에. 베타 6주 만에 유료 전환율 23% 달성.', descEn: 'Integrated analytics dashboard for YouTubers. Five platforms in one view. 23% paid conversion rate in the first 6 weeks of beta.', descJa: 'YouTuber向け統合分析ダッシュボード。5プラットフォームの指標を一画面に。ベータ6週間で有料転換率23%達成。', tags: ['SaaS', 'Dashboard', 'Data Viz'], thumb: 'dash', bg: 'lavender', feat: true },
  { id: 'admin', title: '모찌배달 어드민', titleEn: 'Mochi Delivery Admin', titleJa: 'モチデリバリー 管理画面', client: '푸드테크 운영팀 · 2025', clientEn: 'Food-Tech Ops · 2025', clientJa: 'フードテック 運営チーム · 2025', desc: '배달 운영팀이 매일 쓰는 관리자 페이지. 주문·상품·고객·정산을 한 화면에. 처리 시간 65% 단축.', descEn: 'The admin panel used daily by a food delivery ops team. Orders, products, customers, and settlements in one screen. 65% reduction in processing time.', descJa: '配達運営チームが毎日使う管理ページ。注文・商品・顧客・精算を一画面に。処理時間65%短縮。', tags: ['Admin', 'Dashboard', 'Operations'], thumb: 'admin', bg: 'peach', feat: true },
  { id: 'brand', title: '올리브 베이커리', titleEn: 'Olive Bakery', titleJa: 'オリーブベーカリー', client: '동네 베이커리 · 2024', clientEn: 'Local Bakery · 2024', clientJa: '街のベーカリー · 2024', desc: '망원동 작은 베이커리의 브랜드 사이트. 매장 분위기를 그대로 담아낸 에디토리얼 톤.', descEn: 'Brand website for a small neighborhood bakery. Editorial tone that captures the warmth of the store.', descJa: '小さなベーカリーのブランドサイト。店の温かみをそのままエディトリアルトーンで表現。', tags: ['Brand Site', 'Web', 'Branding'], thumb: 'brand', bg: 'yellow', feat: true },
  { id: 'delivery', title: '모찌배달', titleEn: 'Mochi Delivery', titleJa: 'モチデリバリー', client: '푸드테크 스타트업 · 2025', clientEn: 'Food-Tech Startup · 2025', clientJa: 'フードテックスタートアップ · 2025', desc: '동네 단위 디저트 배달 앱. 4주 만에 MVP 출시, 출시 첫 주 만에 2,400명 다운로드.', descEn: 'Neighborhood dessert delivery app. MVP launched in 4 weeks. 2,400 downloads in the first week.', descJa: '近所のデザートデリバリーアプリ。4週間でMVP公開、初週2,400ダウンロード達成。', tags: ['Mobile App', 'E-Commerce', 'Branding'], thumb: 'delivery', bg: 'pink' },
  { id: 'cafe', title: '별다방 리워드', titleEn: 'Byeoldabang Rewards', titleJa: 'ビョルダバン リワード', client: '체인 카페 브랜드 · 2024', clientEn: 'Chain Café Brand · 2024', clientJa: 'チェーンカフェブランド · 2024', desc: '12,000명 회원 마이그레이션 + 신규 스탬프 시스템. 오프라인 매장 단말기까지 연동.', descEn: 'Migration of 12,000 members + new stamp system. Integrated with in-store terminals.', descJa: '12,000人会員移行＋新スタンプシステム。オフライン店舗端末とも連携。', tags: ['Mobile App', 'Offline', 'Branding'], thumb: 'cafe', bg: 'mint' },
  { id: 'chat', title: '또또톡', titleEn: 'DotoDok', titleJa: 'ドットドク', client: '동호회 커뮤니티 · 2024', clientEn: 'Community App · 2024', clientJa: 'コミュニティアプリ · 2024', desc: '취향 기반 1:1 매칭 채팅 서비스. 풀스택 자체 개발 + 실시간 푸시.', descEn: 'Interest-based 1:1 matching chat service. Full-stack in-house build with real-time push.', descJa: '趣味ベースの1:1マッチングチャットサービス。フルスタック自社開発＋リアルタイムプッシュ。', tags: ['Mobile App', 'Real-time', 'UI/UX'], thumb: 'chat', bg: 'cyan' },
  { id: 'fit', title: '운동친구', titleEn: 'FitPal', titleJa: 'フィットパル', client: '헬스케어 D2C · 2024', clientEn: 'Healthcare D2C · 2024', clientJa: 'ヘルスケアD2C · 2024', desc: '러닝 메이트 매칭 + 코스 공유. 부산·서울 동시 런칭.', descEn: 'Running mate matching and route sharing. Launched simultaneously in Busan and Seoul.', descJa: 'ランニングメイトマッチング＋コース共有。釜山・ソウル同時ローンチ。', tags: ['Landing', 'Mobile', 'Branding'], thumb: 'fit', bg: 'peach' },
];

function Portfolio() {
  const [ref, seen] = useReveal();
  const { t, lang } = useLang();
  const isKo = lang === 'ko';
  return (
    <section className="section tint-yellow" id="portfolio">
      <div className="section-bg-tint"></div>
      <div className="section-inner">
        <div ref={ref} className={`s-head reveal ${seen ? 'in' : ''}`}>
          <span className="eyebrow"><span className="eyebrow-dot"></span>{t('port_eyebrow')}</span>
          <h2>{t('port_heading')}</h2>
          <p className="s-sub">{t('port_sub')}</p>
        </div>

        <div className={`portfolio-grid reveal-stagger ${seen ? 'in' : ''}`}>
          {PROJECTS.map(p => (
            <div key={p.id} className={`portfolio-card ${p.feat ? 'feat' : ''}`}>
              <div className="portfolio-thumb">
                <div className={`thumb-bg ${p.bg}`}></div>
                <div className="portfolio-thumb-inner">
                  <PortfolioMockup kind={p.thumb} />
                </div>
                {/* Decoration in thumb */}
                <Sparkle size={3} className="twinkle" style={{ position: 'absolute', top: 16, right: 18, zIndex: 3 }} color="#FFFFFF" />
                <Star size={2} className="twinkle" style={{ position: 'absolute', bottom: 24, left: 18, animationDelay: '-1s', zIndex: 3 }} color="#FFFFFF" />
              </div>
              <div className="portfolio-meta">
                <div className="portfolio-tags">
                  {p.tags.map(tag => <span key={tag} className="portfolio-tag">{tag}</span>)}
                </div>
                <h3>{lang === 'ko' ? p.title : lang === 'ja' ? p.titleJa : p.titleEn}</h3>
                <p className="desc">{lang === 'ko' ? p.desc : lang === 'ja' ? p.descJa : p.descEn}</p>
                <div className="footer">
                  <span className="client">{lang === 'ko' ? p.client : lang === 'ja' ? p.clientJa : p.clientEn}</span>
                </div>
              </div>
            </div>
          ))}
        </div>

        <WorksSection />
        <DesignGallery />
      </div>
    </section>
  );
}

/* =========================================================
   MOAI Cloud — 우친소 자체 SaaS 제품 (moai.page 연동)
   ========================================================= */
const CLOUD_MODULES = [
  { name: 'Moai Lingua', c: 'lavender', ico: <IcoChat size={5} />,   d: 'cloud_m1_d' },
  { name: 'Moai Notify', c: 'cyan',     ico: <IcoRocket size={5} />, d: 'cloud_m2_d' },
  { name: 'Moai AdMesh', c: 'yellow',   ico: <IcoChart size={5} />,  d: 'cloud_m3_d' },
  { name: 'Moai Anon',   c: 'pink',     ico: <IcoSwatch size={5} />, d: 'cloud_m4_d' },
  { name: 'Moai Oracle', c: 'mint',     ico: <IcoFlag size={5} />,   d: 'cloud_m5_d' },
  { name: 'Moai Chat',   c: 'lavender', ico: <IcoApp size={5} />,    d: 'cloud_m6_d' },
];

function MoaiCloud() {
  const [ref, seen] = useReveal();
  const { t } = useLang();
  return (
    <section className="section tint-cyan" id="cloud">
      <div className="section-bg-tint"></div>
      <Cloud size={6} className="deco-cloud" style={{ top: 100, right: '7%' }} />
      <Cloud size={4} className="deco-cloud" style={{ top: 220, left: '5%' }} />
      <Sparkle size={4} className="deco-star twinkle" style={{ top: 160, left: '40%' }} />
      <div className="section-inner">
        <div ref={ref} className={`s-head reveal ${seen ? 'in' : ''}`}>
          <span className="eyebrow"><span className="eyebrow-dot"></span>SaaS</span>
          <h2>{t('cloud_heading')}</h2>
          <p className="s-sub">{t('cloud_sub')}</p>
        </div>

        <div className={`services-grid reveal-stagger ${seen ? 'in' : ''}`}>
          {CLOUD_MODULES.map(m => (
            <div key={m.name} className="service-card" data-c={m.c}>
              <div className="service-card-icon">{m.ico}</div>
              <h3>{m.name}</h3>
              <p>{t(m.d)}</p>
            </div>
          ))}
        </div>

        <div
          className={`reveal ${seen ? 'in' : ''}`}
          style={{
            marginTop: 40, display: 'flex', flexWrap: 'wrap', alignItems: 'center',
            justifyContent: 'center', gap: 16, textAlign: 'center',
          }}
        >
          <span
            style={{
              display: 'inline-flex', alignItems: 'center', gap: 8, padding: '6px 14px',
              borderRadius: 999, background: 'rgba(255,255,255,0.55)',
              border: '1px solid rgba(107,91,168,0.25)', color: 'var(--c-purple)',
              fontSize: 13, fontWeight: 700,
            }}
          >
            <Star size={2} color="#D4A82E" /> {t('cloud_badge')}
          </span>
          <a className="btn" href="https://moai.page" target="_blank" rel="noopener noreferrer">
            {t('cloud_cta')} <span style={{ fontSize: 18 }}>→</span>
          </a>
          <span style={{ flexBasis: '100%', color: 'var(--c-purple)', opacity: 0.7, fontSize: 14 }}>
            {t('cloud_free')}
          </span>
        </div>
      </div>
    </section>
  );
}

/* =========================================================
   Process
   ========================================================= */
function Process() {
  const [ref, seen] = useReveal();
  const { t } = useLang();
  const STEPS = [
    { n: '01', t: t('proc1_t'), d: t('proc1_d'), ico: <IcoChat size={4} /> },
    { n: '02', t: t('proc2_t'), d: t('proc2_d'), ico: <IcoChart size={4} /> },
    { n: '03', t: t('proc3_t'), d: t('proc3_d'), ico: <IcoBrand size={4} /> },
    { n: '04', t: t('proc4_t'), d: t('proc4_d'), ico: <IcoWeb size={4} /> },
    { n: '05', t: t('proc5_t'), d: t('proc5_d'), ico: <IcoFlag size={4} /> },
  ];
  return (
    <section className="section tint-lavender" id="process">
      <div className="section-bg-tint"></div>
      <div className="section-inner">
        <div ref={ref} className={`s-head reveal ${seen ? 'in' : ''}`}>
          <span className="eyebrow"><span className="eyebrow-dot"></span>{t('proc_eyebrow')}</span>
          <h2>{t('proc_heading')}</h2>
          <p className="s-sub">{t('proc_sub')}</p>
        </div>

        <div className="process-track">
          <div className="process-line"></div>
          <div className={`process-steps reveal-stagger ${seen ? 'in' : ''}`}>
            {STEPS.map((s, i) => (
              <div key={s.n} className="process-step">
                <div className="process-bubble">
                  <span className="step-num">{s.n}</span>
                  <div>{s.ico}</div>
                </div>
                <h4>{s.t}</h4>
                <p>{s.d}</p>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
}

/* =========================================================
   Contact
   ========================================================= */
function Contact() {
  const [ref, seen] = useReveal();
  const { t } = useLang();
  const BUDGET_KEYS = ['budget_1', 'budget_2', 'budget_3', 'budget_4', 'budget_tbd'];
  const budgets = BUDGET_KEYS.map(k => ({ key: k, label: t(k) }));
  const [budgetKey, setBudgetKey] = useState('budget_2');
  const [sent, setSent] = useState(false);
  const [senderEmail, setSenderEmail] = useState('');
  const [company, setCompany] = useState('');
  const [description, setDescription] = useState('');
  const [loading, setLoading] = useState(false);
  const [errorMsg, setErrorMsg] = useState('');
  const [hdg0, hdg1] = t('contact_heading').split('\n');

  const COOLDOWN_KEY = 'wcs-contact-sent-at';
  const COOLDOWN_MS = 5 * 60 * 1000;

  async function handleSubmit(e) {
    e.preventDefault();
    setErrorMsg('');

    if (!senderEmail || !company || !description) {
      setErrorMsg(t('contact_error_required'));
      return;
    }
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(senderEmail)) {
      setErrorMsg(t('contact_error_email'));
      return;
    }

    const lastSent = localStorage.getItem(COOLDOWN_KEY);
    if (lastSent && Date.now() - parseInt(lastSent) < COOLDOWN_MS) {
      const remainMins = Math.ceil((COOLDOWN_MS - (Date.now() - parseInt(lastSent))) / 60000);
      setErrorMsg(t('contact_error_cooldown').replace('{n}', remainMins));
      return;
    }

    setLoading(true);
    try {
      const res = await fetch('/api/mail/portfolio-contact', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          name: company,
          email: senderEmail,
          company,
          contactType: t(budgetKey),
          title: `Agency Inquiry — ${company}`,
          content: description,
        }),
      });

      if (!res.ok) {
        const data = await res.json().catch(() => ({}));
        if (res.status === 429) {
          setErrorMsg(t('contact_error_cooldown').replace('{n}', '60'));
        } else {
          setErrorMsg(data.message || t('contact_error_send'));
        }
        return;
      }

      localStorage.setItem(COOLDOWN_KEY, String(Date.now()));
      setSent(true);
    } catch {
      setErrorMsg(t('contact_error_send'));
    } finally {
      setLoading(false);
    }
  }

  function handleReset() {
    setSent(false);
    setSenderEmail('');
    setCompany('');
    setDescription('');
    setBudgetKey('budget_2');
    setErrorMsg('');
  }

  return (
    <section className="section" id="contact">
      <div className="section-inner">
        <div ref={ref} className={`contact-frame reveal ${seen ? 'in' : ''}`}>
          <Cloud size={6} className="deco bob bob-0" style={{ top: 30, left: 40 }} />
          <Cloud size={4} className="deco bob bob-2" style={{ top: 80, right: 80 }} />
          <Star size={5} className="deco twinkle" style={{ top: 60, right: 200 }} />
          <Sparkle size={4} className="deco twinkle" style={{ bottom: 60, left: 60 }} />
          <Heart size={4} className="deco bob bob-1" style={{ bottom: 100, right: 50 }} />
          <Flower size={4} className="deco bob bob-3" style={{ top: 200, left: 100 }} />

          <div className="contact-grid">
            <div>
              <span className="eyebrow"><span className="eyebrow-dot"></span>{t('contact_eyebrow')}</span>
              <h2 style={{ marginTop: 16 }}>
                {hdg0}<br/>
                <span className="under pink">{hdg1}</span>
              </h2>
              <p>{t('contact_sub')}</p>
              <div className="contact-info">
                <div className="contact-info-item">
                  <span className="ico"><IcoChat size={3} /></span>
                  <div><strong>{t('contact_email_label')}</strong> · luvwcs@gmail.com</div>
                </div>
                <div className="contact-info-item">
                  <span className="ico"><IcoBrand size={3} /></span>
                  <div><strong>{t('contact_kakao_label')}</strong> · <a href="http://pf.kakao.com/_MxfusX" target="_blank" rel="noopener noreferrer" style={{ color: 'inherit', textDecoration: 'underline' }}>@woochinso</a></div>
                </div>
                <div className="contact-info-item">
                  <span className="ico"><IcoChart size={3} /></span>
                  <div><strong>{t('contact_hours_label')}</strong> · {t('contact_hours_val')}</div>
                </div>
              </div>
            </div>

            <div className="contact-card">
              {sent ? (
                <div style={{ textAlign: 'center', padding: '40px 0' }}>
                  <div style={{ marginBottom: 20 }}><CharLead size={6} /></div>
                  <h3 style={{ fontSize: 28, marginBottom: 8 }}>{t('contact_thanks')}</h3>
                  <p>{t('contact_thanks_sub')}</p>
                  <button className="btn" style={{ marginTop: 24 }} onClick={handleReset}>
                    {t('contact_again')}
                  </button>
                </div>
              ) : (
                <form onSubmit={handleSubmit} noValidate>
                  {errorMsg && (
                    <div style={{ color: '#e53e3e', fontSize: 13, marginBottom: 12, padding: '8px 12px', background: '#fff5f5', borderRadius: 6, border: '1px solid #fed7d7' }}>
                      {errorMsg}
                    </div>
                  )}
                  <div className="form-row">
                    <label>{t('contact_email_ph')}</label>
                    <input
                      type="email"
                      value={senderEmail}
                      onChange={e => setSenderEmail(e.target.value)}
                      placeholder="you@example.com"
                    />
                  </div>
                  <div className="form-row">
                    <label>{t('contact_company_ph')}</label>
                    <input
                      type="text"
                      value={company}
                      onChange={e => setCompany(e.target.value)}
                      placeholder={t('contact_company_ph')}
                    />
                  </div>
                  <div className="form-row">
                    <label>{t('contact_budget_label')}</label>
                    <div className="budget-chips">
                      {budgets.map(b => (
                        <button
                          key={b.key}
                          type="button"
                          className={`budget-chip ${budgetKey === b.key ? 'on' : ''}`}
                          onClick={() => setBudgetKey(b.key)}
                        >{b.label}</button>
                      ))}
                    </div>
                  </div>
                  <div className="form-row">
                    <label>{t('contact_desc_ph')}</label>
                    <textarea
                      value={description}
                      onChange={e => setDescription(e.target.value)}
                      placeholder={t('contact_desc_ph')}
                    ></textarea>
                  </div>
                  <button
                    type="submit"
                    className="btn"
                    style={{ width: '100%', justifyContent: 'center', opacity: loading ? 0.7 : 1 }}
                    disabled={loading}
                  >
                    {loading ? t('contact_sending') : <>{t('contact_submit')} <Heart size={2} color="#FFFFFF" /></>}
                  </button>
                </form>
              )}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

/* =========================================================
   Footer
   ========================================================= */
function Footer() {
  const { t } = useLang();
  return (
    <footer className="footer">
      <div className="footer-mark">{t('footer_tagline')}</div>
      <div>© 2024 WOOCHINSO · MADE WITH ♡ IN KOREA</div>
      <div style={{ marginTop: 14, display: 'flex', gap: 8, justifyContent: 'center' }}>
        <Sparkle size={3} className="twinkle" />
        <Heart size={3} />
        <Star size={3} />
        <Diamond size={3} />
        <Sparkle size={3} className="twinkle" style={{ animationDelay: '-1s' }} />
      </div>
    </footer>
  );
}

Object.assign(window, { Nav, Hero, About, Services, Skills, Portfolio, MoaiCloud, Process, Contact, Footer, useReveal });
