feat(outsourcing): Deep Field 재스킨 + 쇼케이스 풀 그리드 + 운영 실증 카피

- 라이트 → 다크 캔버스 전환 (메인과 동일 비주얼 언어: 다크 루트 div + -mt-16 hero + border-t 섹션 리듬 + 모노 라벨 헤더)
- Hero 축약 ~60vh + HeroField 배경
- #showcase 섹션 ShowcaseGrid variant="full"(8슬롯), #portfolio 하위호환 앵커 유지
- 구 SAMPLES(/work/website/samples) 노출 링크 제거 — 쇼케이스가 대체
- 운영 실사례/제공분야/프로세스/FAQ 다크 카드 + ScrollReveal 스태거
- OutsourcingRequestForm 다크 스킨(스타일 값만, 로직 diff 0) + placeholder dark-soft
- "7년차"·"대기업" 잔존 카피 전부 운영 실증 톤으로 교체 (metadata 포함)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 01:10:54 +09:00
parent 4cd4a50869
commit b705f35c2d
3 changed files with 391 additions and 351 deletions

View File

@@ -16,9 +16,9 @@ const KOR_TIGHT = { letterSpacing: '-0.02em' } as const;
const KOR_BODY = { letterSpacing: '-0.01em' } as const; const KOR_BODY = { letterSpacing: '-0.01em' } as const;
const INPUT_STYLE = { const INPUT_STYLE = {
background: 'var(--jsm-surface)', background: 'var(--jsm-dark-surface)',
border: '1px solid var(--jsm-line)', border: '1px solid var(--jsm-dark-line)',
color: 'var(--jsm-ink)', color: 'var(--jsm-dark-ink)',
} as const; } as const;
const PROJECT_TYPES = [ const PROJECT_TYPES = [
@@ -195,13 +195,13 @@ export default function OutsourcingRequestForm() {
ref={setHeadingRef} ref={setHeadingRef}
tabIndex={-1} tabIndex={-1}
className="text-xl font-bold break-keep outline-none" className="text-xl font-bold break-keep outline-none"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }}
> >
</h3> </h3>
<p <p
className="mt-3 text-sm leading-relaxed break-keep" className="mt-3 text-sm leading-relaxed break-keep"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
> >
2 . 2 .
</p> </p>
@@ -218,7 +218,7 @@ export default function OutsourcingRequestForm() {
</Link> </Link>
<p <p
className="mt-3 text-xs leading-relaxed break-keep" className="mt-3 text-xs leading-relaxed break-keep"
style={{ color: 'var(--jsm-ink-faint)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
> >
. .
</p> </p>
@@ -232,7 +232,7 @@ export default function OutsourcingRequestForm() {
const canAdvance = stepValid(step); const canAdvance = stepValid(step);
return ( return (
<div> <div className="jsm-dark-form">
{/* 진행 표시기 */} {/* 진행 표시기 */}
<ol className="flex items-center gap-2 mb-7" aria-label="진행 단계"> <ol className="flex items-center gap-2 mb-7" aria-label="진행 단계">
{STEPS.map((s, i) => { {STEPS.map((s, i) => {
@@ -244,7 +244,7 @@ export default function OutsourcingRequestForm() {
className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-bold shrink-0 transition-colors" className="flex items-center justify-center w-6 h-6 rounded-full text-xs font-bold shrink-0 transition-colors"
style={ style={
state === 'upcoming' state === 'upcoming'
? { background: 'var(--jsm-surface-alt)', color: 'var(--jsm-ink-faint)' } ? { background: 'var(--jsm-dark-surface)', color: 'var(--jsm-dark-soft)', boxShadow: 'inset 0 0 0 1px var(--jsm-dark-line)' }
: { background: 'var(--jsm-accent)', color: '#ffffff' } : { background: 'var(--jsm-accent)', color: '#ffffff' }
} }
aria-current={state === 'current' ? 'step' : undefined} aria-current={state === 'current' ? 'step' : undefined}
@@ -255,7 +255,7 @@ export default function OutsourcingRequestForm() {
className="text-xs font-semibold truncate hidden sm:inline" className="text-xs font-semibold truncate hidden sm:inline"
style={{ style={{
color: color:
state === 'upcoming' ? 'var(--jsm-ink-faint)' : 'var(--jsm-ink)', state === 'upcoming' ? 'var(--jsm-dark-soft)' : 'var(--jsm-dark-ink)',
...KOR_BODY, ...KOR_BODY,
}} }}
> >
@@ -264,7 +264,7 @@ export default function OutsourcingRequestForm() {
{i < STEPS.length - 1 && ( {i < STEPS.length - 1 && (
<span <span
className="w-4 sm:w-6 h-px shrink-0" className="w-4 sm:w-6 h-px shrink-0"
style={{ background: 'var(--jsm-line)' }} style={{ background: 'var(--jsm-dark-line)' }}
aria-hidden aria-hidden
/> />
)} )}
@@ -281,13 +281,13 @@ export default function OutsourcingRequestForm() {
ref={setHeadingRef} ref={setHeadingRef}
tabIndex={-1} tabIndex={-1}
className="text-lg font-bold break-keep outline-none mb-1" className="text-lg font-bold break-keep outline-none mb-1"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }}
> >
? ?
</legend> </legend>
<p <p
className="text-sm leading-relaxed break-keep mb-5" className="text-sm leading-relaxed break-keep mb-5"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
> >
. .
</p> </p>
@@ -303,12 +303,12 @@ export default function OutsourcingRequestForm() {
className="px-4 py-3.5 rounded-lg text-sm font-semibold text-center break-keep transition-colors outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]" className="px-4 py-3.5 rounded-lg text-sm font-semibold text-center break-keep transition-colors outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]"
style={{ style={{
border: selected border: selected
? '1px solid var(--jsm-accent)' ? '1px solid var(--jsm-accent-bright)'
: '1px solid var(--jsm-line)', : '1px solid var(--jsm-dark-line)',
background: selected background: selected
? 'var(--jsm-accent-soft)' ? 'rgba(96,165,250,0.12)'
: 'var(--jsm-surface)', : 'var(--jsm-dark-surface)',
color: selected ? 'var(--jsm-accent)' : 'var(--jsm-ink)', color: selected ? 'var(--jsm-accent-bright)' : 'var(--jsm-dark-ink)',
...KOR_BODY, ...KOR_BODY,
}} }}
> >
@@ -327,13 +327,13 @@ export default function OutsourcingRequestForm() {
ref={setHeadingRef} ref={setHeadingRef}
tabIndex={-1} tabIndex={-1}
className="text-lg font-bold break-keep outline-none mb-1" className="text-lg font-bold break-keep outline-none mb-1"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }}
> >
</h3> </h3>
<p <p
className="text-sm leading-relaxed break-keep mb-5" className="text-sm leading-relaxed break-keep mb-5"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
> >
. . . .
</p> </p>
@@ -341,7 +341,7 @@ export default function OutsourcingRequestForm() {
<fieldset className="mb-6"> <fieldset className="mb-6">
<legend <legend
className="text-sm font-semibold mb-2.5" className="text-sm font-semibold mb-2.5"
style={{ color: 'var(--jsm-ink)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_BODY }}
> >
</legend> </legend>
@@ -360,7 +360,7 @@ export default function OutsourcingRequestForm() {
<fieldset> <fieldset>
<legend <legend
className="text-sm font-semibold mb-2.5" className="text-sm font-semibold mb-2.5"
style={{ color: 'var(--jsm-ink)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_BODY }}
> >
</legend> </legend>
@@ -385,13 +385,13 @@ export default function OutsourcingRequestForm() {
ref={setHeadingRef} ref={setHeadingRef}
tabIndex={-1} tabIndex={-1}
className="text-lg font-bold break-keep outline-none mb-1" className="text-lg font-bold break-keep outline-none mb-1"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }}
> >
</h3> </h3>
<p <p
className="text-sm leading-relaxed break-keep mb-5" className="text-sm leading-relaxed break-keep mb-5"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
> >
. 10 . . 10 .
</p> </p>
@@ -413,7 +413,7 @@ export default function OutsourcingRequestForm() {
/> />
<p <p
className="mt-1.5 text-xs" className="mt-1.5 text-xs"
style={{ color: 'var(--jsm-ink-faint)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
> >
{trimmedMessage.length}/10 {trimmedMessage.length}/10
</p> </p>
@@ -427,13 +427,13 @@ export default function OutsourcingRequestForm() {
ref={setHeadingRef} ref={setHeadingRef}
tabIndex={-1} tabIndex={-1}
className="text-lg font-bold break-keep outline-none mb-1" className="text-lg font-bold break-keep outline-none mb-1"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }}
> >
? ?
</h3> </h3>
<p <p
className="text-sm leading-relaxed break-keep mb-5" className="text-sm leading-relaxed break-keep mb-5"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
> >
2 . 2 .
</p> </p>
@@ -443,7 +443,7 @@ export default function OutsourcingRequestForm() {
<label <label
htmlFor="req-name" htmlFor="req-name"
className="block text-sm font-medium mb-1.5" className="block text-sm font-medium mb-1.5"
style={{ color: 'var(--jsm-ink)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_BODY }}
> >
<span style={{ color: 'var(--jsm-accent)' }}>*</span> <span style={{ color: 'var(--jsm-accent)' }}>*</span>
</label> </label>
@@ -465,7 +465,7 @@ export default function OutsourcingRequestForm() {
<label <label
htmlFor="req-email" htmlFor="req-email"
className="block text-sm font-medium mb-1.5" className="block text-sm font-medium mb-1.5"
style={{ color: 'var(--jsm-ink)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_BODY }}
> >
<span style={{ color: 'var(--jsm-accent)' }}>*</span> <span style={{ color: 'var(--jsm-accent)' }}>*</span>
</label> </label>
@@ -487,7 +487,7 @@ export default function OutsourcingRequestForm() {
<label <label
htmlFor="req-phone" htmlFor="req-phone"
className="block text-sm font-medium mb-1.5" className="block text-sm font-medium mb-1.5"
style={{ color: 'var(--jsm-ink)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_BODY }}
> >
</label> </label>
@@ -530,10 +530,10 @@ export default function OutsourcingRequestForm() {
type="button" type="button"
onClick={goPrev} onClick={goPrev}
disabled={submitting} disabled={submitting}
className="px-5 py-3 rounded-lg text-sm font-semibold border transition-colors hover:bg-[var(--jsm-surface-alt)] disabled:opacity-50 disabled:cursor-not-allowed" className="px-5 py-3 rounded-lg text-sm font-semibold border transition-colors hover:bg-[var(--jsm-dark-surface)] disabled:opacity-50 disabled:cursor-not-allowed"
style={{ style={{
...INPUT_STYLE, ...INPUT_STYLE,
borderColor: 'var(--jsm-line)', borderColor: 'var(--jsm-dark-line)',
...KOR_BODY, ...KOR_BODY,
}} }}
> >
@@ -548,7 +548,7 @@ export default function OutsourcingRequestForm() {
className="flex-1 py-3 rounded-lg text-sm font-semibold text-white transition-colors" className="flex-1 py-3 rounded-lg text-sm font-semibold text-white transition-colors"
style={{ style={{
background: !canAdvance || submitting background: !canAdvance || submitting
? 'var(--jsm-ink-faint)' ? 'var(--jsm-dark-line)'
: 'var(--jsm-accent)', : 'var(--jsm-accent)',
cursor: !canAdvance || submitting ? 'not-allowed' : 'pointer', cursor: !canAdvance || submitting ? 'not-allowed' : 'pointer',
...KOR_BODY, ...KOR_BODY,
@@ -563,7 +563,7 @@ export default function OutsourcingRequestForm() {
disabled={!canAdvance} disabled={!canAdvance}
className="flex-1 inline-flex items-center justify-center gap-2 py-3 rounded-lg text-sm font-semibold text-white transition-colors" className="flex-1 inline-flex items-center justify-center gap-2 py-3 rounded-lg text-sm font-semibold text-white transition-colors"
style={{ style={{
background: canAdvance ? 'var(--jsm-accent)' : 'var(--jsm-ink-faint)', background: canAdvance ? 'var(--jsm-accent)' : 'var(--jsm-dark-line)',
cursor: canAdvance ? 'pointer' : 'not-allowed', cursor: canAdvance ? 'pointer' : 'not-allowed',
...KOR_BODY, ...KOR_BODY,
}} }}
@@ -595,9 +595,9 @@ function Chip({
aria-pressed={selected} aria-pressed={selected}
className="px-4 py-2.5 rounded-lg text-sm font-semibold break-keep transition-colors outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]" className="px-4 py-2.5 rounded-lg text-sm font-semibold break-keep transition-colors outline-none focus-visible:ring-2 focus-visible:ring-[var(--jsm-accent)]"
style={{ style={{
border: selected ? '1px solid var(--jsm-accent)' : '1px solid var(--jsm-line)', border: selected ? '1px solid var(--jsm-accent-bright)' : '1px solid var(--jsm-dark-line)',
background: selected ? 'var(--jsm-accent-soft)' : 'var(--jsm-surface)', background: selected ? 'rgba(96,165,250,0.12)' : 'var(--jsm-dark-surface)',
color: selected ? 'var(--jsm-accent)' : 'var(--jsm-ink)', color: selected ? 'var(--jsm-accent-bright)' : 'var(--jsm-dark-ink)',
...KOR_BODY, ...KOR_BODY,
}} }}
> >

View File

@@ -198,6 +198,13 @@ body {
pointer-events: none; pointer-events: none;
} }
/* 외주 의뢰 폼 — 다크 스킨 placeholder (Deep Field 재스킨) */
.jsm-dark-form input::placeholder,
.jsm-dark-form textarea::placeholder {
color: var(--jsm-dark-soft);
opacity: 1;
}
/* Service card hover */ /* Service card hover */
.service-card { .service-card {
transition: transform 0.2s ease, box-shadow 0.2s ease; transition: transform 0.2s ease, box-shadow 0.2s ease;

View File

@@ -2,14 +2,20 @@ import Link from 'next/link';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import OutsourcingRequestForm from '@/app/components/OutsourcingRequestForm'; import OutsourcingRequestForm from '@/app/components/OutsourcingRequestForm';
// 외주 개발 의뢰 페이지 (서버 컴포넌트) import HeroField from '@/app/components/deepfield/HeroField';
// PublicShell이 TopNav(h-16)·푸터·main 배경을 제공하므로 여기서는 콘텐츠 섹션만 렌더한다. import ShowcaseGrid from '@/app/components/deepfield/ShowcaseGrid';
// 메인(/)의 토큰·타이포 패턴(KOR_TIGHT/KOR_BODY)·섹션 리듬과 일관되게 구성한다. import ScrollReveal from '@/app/components/deepfield/ScrollReveal';
import { SHOWCASE_SLOTS } from '@/lib/showcase';
// 외주 개발 의뢰 페이지 (서버 컴포넌트) — Deep Field 다크 캔버스.
// PublicShell이 TopNav(h-16, /outsourcing 다크 인지)·푸터·main 배경(라이트)을 제공한다.
// 이 페이지는 자기 풀-블리드 다크 배경을 소유해 main의 라이트 배경을 덮고,
// 메인(/)과 동일한 비주얼 언어(다크 루트 div + -mt-16 hero + 섹션 border-t 리듬 + 모노 라벨 헤더)를 따른다.
export const metadata: Metadata = { export const metadata: Metadata = {
title: '외주 개발', title: '외주 개발',
description: description:
'7년차 대기업 백엔드 개발자가 직접 진행하는 맞춤 소프트웨어 외주 개발. 웹 서비스, 업무 자동화, API·백엔드, 봇, AI 연동까지 기획부터 납품·하자보수까지 단독으로 책임집니다.', '24시간 돌아가는 실서비스를 직접 설계·운영하는 손으로, 맞춤 소프트웨어를 만들어 드립니다. 웹 서비스·업무 자동화·API·백엔드·봇·AI 연동까지 기획부터 납품·하자보수까지 단독으로 책임집니다.',
}; };
const KOR_TIGHT = { letterSpacing: '-0.02em' } as const; const KOR_TIGHT = { letterSpacing: '-0.02em' } as const;
@@ -51,7 +57,7 @@ const PROCESS = [
{ n: '06', t: '무상 하자보수 30일', d: '납품 후 30일간 결함·수정을 무상으로 대응해 안정화까지 책임집니다.' }, { n: '06', t: '무상 하자보수 30일', d: '납품 후 30일간 결함·수정을 무상으로 대응해 안정화까지 책임집니다.' },
]; ];
// 기존 work/freelance(lib/freelance-portfolio) 실사례를 토큰 기준으로 재구성. // 기존 work/freelance(lib/freelance-portfolio) 실사례를 다크 토큰 기준으로 재구성.
const CASES = [ const CASES = [
{ {
t: '주식 자동매매 시스템', t: '주식 자동매매 시스템',
@@ -97,14 +103,6 @@ const CASES = [
}, },
]; ];
// /work/website/samples/* 중 대표 샘플 — 이 라우트는 숨김이 아니라 포트폴리오용으로 잔존.
const SAMPLES = [
{ slug: 'corporate', t: '기업 홈페이지', sub: '테크솔루션㈜', tag: 'B2B · 신뢰' },
{ slug: 'shopping', t: '개인 쇼핑몰', sub: 'MELLOW STUDIO', tag: '쇼핑몰 · 브랜드' },
{ slug: 'dashboard', t: '관리자 대시보드', sub: 'DataFlow SaaS', tag: 'SaaS · 자동화' },
{ slug: 'portfolio', t: '개인 포트폴리오', sub: 'Kim Jisu', tag: '크리에이터 · 수주' },
];
const FAQ = [ const FAQ = [
{ {
q: '견적은 어떻게 산정되나요?', q: '견적은 어떻게 산정되나요?',
@@ -145,395 +143,430 @@ function ArrowRight() {
export default function OutsourcingPage() { export default function OutsourcingPage() {
return ( return (
<> // 풀-블리드 다크 캔버스 — main의 라이트 배경을 덮는다.
{/* ─── 1. Hero ─── */} <div style={{ background: 'var(--jsm-dark-bg)', color: 'var(--jsm-dark-ink)' }}>
<section className="border-b" style={{ borderColor: 'var(--jsm-line)' }}> {/* ─────────────────── 1. HERO (축약 ~60vh) ─────────────────── */}
<div className="max-w-6xl mx-auto px-6 lg:px-8 py-24 lg:py-32"> {/* -mt-16 pt-16: 고정 헤더 아래로 끌어올려 상단 라이트 띠 제거 */}
<section className="relative -mt-16 flex min-h-[60vh] items-center overflow-hidden pt-16">
<HeroField className="absolute inset-0" />
{/* 콘텐츠 가독성용 스크림 (radial 광원 위 텍스트 대비) */}
<div
aria-hidden
className="pointer-events-none absolute inset-0"
style={{
background:
'linear-gradient(to bottom, rgba(7,13,26,0.55) 0%, transparent 30%, transparent 62%, rgba(7,13,26,0.78) 100%)',
}}
/>
<div className="relative z-10 mx-auto w-full max-w-6xl px-6 py-20 lg:px-8 lg:py-24">
<div className="max-w-3xl"> <div className="max-w-3xl">
<span <span
className="inline-block text-xs font-semibold mb-6 px-2.5 py-1 rounded" className="mb-7 inline-flex items-center gap-2 font-mono text-[11px] uppercase tracking-[0.22em]"
style={{ color: 'var(--jsm-accent)', background: 'var(--jsm-accent-soft)', ...KOR_BODY }} style={{ color: 'var(--jsm-accent-bright)' }}
> >
<span
className="inline-block h-1 w-1 rounded-full"
style={{ background: 'var(--jsm-accent-bright)' }}
/>
outsourcing
</span> </span>
<h1 <h1
className="text-4xl sm:text-5xl lg:text-[3.5rem] font-bold leading-[1.2] break-keep" className="font-bold break-keep"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} style={{
color: 'var(--jsm-dark-ink)',
fontSize: 'clamp(2.4rem, 7vw, 5rem)',
lineHeight: 1.06,
letterSpacing: '-0.04em',
}}
> >
{' '}
<span style={{ color: 'var(--jsm-accent)' }}> </span> <br />
<span style={{ color: 'var(--jsm-accent-bright)' }}>.</span>
</h1> </h1>
<p <p
className="mt-7 text-lg lg:text-xl leading-relaxed break-keep max-w-2xl" className="mt-7 max-w-2xl break-keep text-lg leading-relaxed lg:text-xl"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
> >
. . 7 . .
· .
</p> </p>
<div className="mt-10 flex flex-col sm:flex-row gap-3"> <div className="mt-10 flex flex-col gap-3 sm:flex-row">
<Link <Link
href="#contact" href="#contact"
className="inline-flex items-center justify-center gap-2 px-6 py-3.5 rounded-lg font-semibold text-white transition-colors duration-150 hover:bg-[var(--jsm-accent-hover)]" className="inline-flex items-center justify-center gap-2 rounded-lg px-6 py-3.5 font-semibold text-white transition-transform duration-200 hover:translate-y-[-1px]"
style={{ background: 'var(--jsm-accent)', ...KOR_BODY }} style={{ background: 'var(--jsm-accent)', ...KOR_BODY }}
> >
<ArrowRight /> <ArrowRight />
</Link> </Link>
<Link <Link
href="#portfolio" href="#showcase"
className="inline-flex items-center justify-center gap-2 px-6 py-3.5 rounded-lg font-semibold border transition-colors duration-150 hover:bg-[var(--jsm-surface-alt)]" className="inline-flex items-center justify-center gap-2 rounded-lg border px-6 py-3.5 font-semibold transition-colors duration-200 hover:bg-[var(--jsm-dark-surface)]"
style={{ style={{
color: 'var(--jsm-ink)', color: 'var(--jsm-dark-ink)',
borderColor: 'var(--jsm-line)', borderColor: 'var(--jsm-dark-line)',
background: 'var(--jsm-surface)',
...KOR_BODY, ...KOR_BODY,
}} }}
> >
</Link> </Link>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
{/* ─── 2. 제공 분야 ─── */} {/* ─────────────────── 2. SHOWCASE (풀 그리드) ─────────────────── */}
<section style={{ background: 'var(--jsm-surface-alt)' }}> <section id="showcase" className="scroll-mt-20 border-t" style={{ borderColor: 'var(--jsm-dark-line)' }}>
<div className="max-w-6xl mx-auto px-6 lg:px-8 py-20 lg:py-28"> {/* 하위 호환: 기존 /outsourcing#portfolio 링크(메인 footer 등)용 앵커 유지 */}
<div className="max-w-2xl"> <div id="portfolio" className="scroll-mt-20" />
<div className="mx-auto max-w-6xl px-6 py-24 lg:px-8 lg:py-32">
<ScrollReveal>
<p <p
className="text-xs font-semibold uppercase tracking-wider mb-3" className="mb-3 font-mono text-[11px] uppercase tracking-[0.22em]"
style={{ color: 'var(--jsm-accent)' }} style={{ color: 'var(--jsm-accent-bright)' }}
> >
Scope showcase
</p> </p>
<h2 <h2
className="text-3xl lg:text-4xl font-bold break-keep" className="max-w-2xl break-keep text-3xl font-bold lg:text-[2.75rem] lg:leading-[1.12]"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} style={{ color: 'var(--jsm-dark-ink)', letterSpacing: '-0.03em' }}
> >
</h2> </h2>
</div> </ScrollReveal>
<div className="mt-12 grid sm:grid-cols-2 lg:grid-cols-3 gap-6">
{FIELDS.map((f) => ( <div className="mt-14">
<div <ShowcaseGrid slots={SHOWCASE_SLOTS} variant="full" />
key={f.t}
className="rounded-2xl p-7 border"
style={{ background: 'var(--jsm-surface)', borderColor: 'var(--jsm-line)' }}
>
<h3
className="text-lg font-bold break-keep"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}
>
{f.t}
</h3>
<p
className="mt-2.5 text-sm leading-relaxed break-keep"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}
>
{f.d}
</p>
</div>
))}
</div> </div>
</div> </div>
</section> </section>
{/* ─── 3. 진행 프로세스 ─── */} {/* ─────────────────── 3. 운영 실사례 ─────────────────── */}
<section id="process" className="scroll-mt-20" style={{ background: 'var(--jsm-bg)' }}> <section className="border-t" style={{ borderColor: 'var(--jsm-dark-line)' }}>
<div className="max-w-6xl mx-auto px-6 lg:px-8 py-20 lg:py-28"> <div className="mx-auto max-w-6xl px-6 py-24 lg:px-8 lg:py-32">
<div className="max-w-2xl"> <ScrollReveal>
<p <p
className="text-xs font-semibold uppercase tracking-wider mb-3" className="mb-3 font-mono text-[11px] uppercase tracking-[0.22em]"
style={{ color: 'var(--jsm-accent)' }} style={{ color: 'var(--jsm-accent-bright)' }}
> >
Process in production
</p> </p>
<h2 <h2
className="text-3xl lg:text-4xl font-bold break-keep" className="max-w-2xl break-keep text-3xl font-bold lg:text-[2.75rem] lg:leading-[1.12]"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} style={{ color: 'var(--jsm-dark-ink)', letterSpacing: '-0.03em' }}
>
,
</h2>
</div>
<div
className="mt-12 grid sm:grid-cols-2 lg:grid-cols-3 gap-px rounded-2xl overflow-hidden border"
style={{ borderColor: 'var(--jsm-line)', background: 'var(--jsm-line)' }}
>
{PROCESS.map((s) => (
<div key={s.n} className="p-7 lg:p-8" style={{ background: 'var(--jsm-surface)' }}>
<span
className="text-sm font-bold"
style={{ color: 'var(--jsm-accent)', fontFamily: 'monospace' }}
>
{s.n}
</span>
<h3
className="mt-4 text-lg font-bold break-keep"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}
>
{s.t}
</h3>
<p
className="mt-2 text-sm leading-relaxed break-keep"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}
>
{s.d}
</p>
</div>
))}
</div>
</div>
</section>
{/* ─── 4. 포트폴리오 ─── */}
<section id="portfolio" className="scroll-mt-20" style={{ background: 'var(--jsm-surface-alt)' }}>
<div className="max-w-6xl mx-auto px-6 lg:px-8 py-20 lg:py-28">
<div className="max-w-2xl">
<p
className="text-xs font-semibold uppercase tracking-wider mb-3"
style={{ color: 'var(--jsm-accent)' }}
>
Portfolio
</p>
<h2
className="text-3xl lg:text-4xl font-bold break-keep"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}
> >
, ,
</h2> </h2>
<p <p
className="mt-4 leading-relaxed break-keep" className="mt-4 max-w-xl break-keep leading-relaxed"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
> >
. . . .
</p> </p>
</div> </ScrollReveal>
{/* 실사례 카드 */} <div className="mt-14 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
<div className="mt-12 grid sm:grid-cols-2 lg:grid-cols-3 gap-6"> {CASES.map((c, i) => (
{CASES.map((c) => ( <ScrollReveal key={c.t} delay={i * 80}>
<div <div
key={c.t} className="flex h-full flex-col rounded-2xl border p-7"
className="flex flex-col rounded-2xl p-7 border" style={{
style={{ background: 'var(--jsm-surface)', borderColor: 'var(--jsm-line)' }} background: 'var(--jsm-dark-surface)',
> borderColor: 'var(--jsm-dark-line)',
<span }}
className="self-start inline-flex items-center gap-1.5 text-[11px] font-semibold px-2.5 py-1 rounded-full mb-5"
style={
c.live
? { color: 'var(--jsm-accent)', background: 'var(--jsm-accent-soft)' }
: { color: 'var(--jsm-ink-soft)', background: 'var(--jsm-surface-alt)' }
}
>
{c.live && (
<span
className="w-1.5 h-1.5 rounded-full"
style={{ background: 'var(--jsm-accent)' }}
/>
)}
{c.cat}
</span>
<h3
className="text-lg font-bold break-keep"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}
>
{c.t}
</h3>
<p
className="mt-2.5 text-sm leading-relaxed break-keep flex-1"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}
>
{c.d}
</p>
<div className="mt-5 flex flex-wrap gap-1.5">
{c.tags.map((tag) => (
<span
key={tag}
className="text-xs px-2.5 py-1 rounded"
style={{
color: 'var(--jsm-ink-soft)',
background: 'var(--jsm-surface-alt)',
...KOR_BODY,
}}
>
{tag}
</span>
))}
</div>
</div>
))}
</div>
{/* 웹사이트 샘플 링크 */}
<div className="mt-14">
<h3
className="text-lg font-bold break-keep"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }}
>
</h3>
<p
className="mt-2 text-sm leading-relaxed break-keep"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }}
>
. .
</p>
<div className="mt-6 grid sm:grid-cols-2 lg:grid-cols-4 gap-5">
{SAMPLES.map((s) => (
<Link
key={s.slug}
href={`/work/website/samples/${s.slug}`}
className="group flex flex-col rounded-2xl p-6 border transition-colors duration-200 hover:border-[var(--jsm-accent)]"
style={{ background: 'var(--jsm-surface)', borderColor: 'var(--jsm-line)' }}
> >
<span <span
className="text-[11px] font-semibold uppercase tracking-wider" className="mb-5 inline-flex items-center gap-1.5 self-start rounded-full px-2.5 py-1 text-[11px] font-semibold"
style={{ color: 'var(--jsm-accent)' }} style={
c.live
? { color: 'var(--jsm-accent-bright)', background: 'rgba(96,165,250,0.12)' }
: { color: 'var(--jsm-dark-soft)', background: 'rgba(148,163,184,0.08)' }
}
> >
{s.tag} {c.live && (
<span
className="h-1.5 w-1.5 rounded-full"
style={{ background: 'var(--jsm-accent-bright)' }}
/>
)}
{c.cat}
</span> </span>
<h4 <h3
className="mt-3 text-base font-bold break-keep" className="break-keep text-lg font-bold"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }}
> >
{s.t} {c.t}
</h4> </h3>
<p <p
className="mt-1 text-sm break-keep" className="mt-2.5 flex-1 break-keep text-sm leading-relaxed"
style={{ color: 'var(--jsm-ink-faint)', ...KOR_BODY }} style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
> >
{s.sub} {c.d}
</p> </p>
<span <div className="mt-5 flex flex-wrap gap-1.5">
className="mt-5 inline-flex items-center gap-1.5 text-sm font-semibold transition-colors duration-150 group-hover:text-[var(--jsm-accent-hover)]" {c.tags.map((tag) => (
style={{ color: 'var(--jsm-accent)', ...KOR_BODY }} <span
> key={tag}
className="rounded px-2.5 py-1 text-xs"
<ArrowRight /> style={{
</span> color: 'var(--jsm-dark-soft)',
</Link> background: 'rgba(148,163,184,0.08)',
))} ...KOR_BODY,
</div> }}
>
{tag}
</span>
))}
</div>
</div>
</ScrollReveal>
))}
</div> </div>
</div> </div>
</section> </section>
{/* ─── 5. FAQ ─── */} {/* ─────────────────── 4a. 제공 분야 ─────────────────── */}
<section style={{ background: 'var(--jsm-bg)' }}> <section className="border-t" style={{ borderColor: 'var(--jsm-dark-line)' }}>
<div className="max-w-3xl mx-auto px-6 lg:px-8 py-20 lg:py-28"> <div className="mx-auto max-w-6xl px-6 py-24 lg:px-8 lg:py-32">
<div className="mb-12"> <ScrollReveal>
<p <p
className="text-xs font-semibold uppercase tracking-wider mb-3" className="mb-3 font-mono text-[11px] uppercase tracking-[0.22em]"
style={{ color: 'var(--jsm-accent)' }} style={{ color: 'var(--jsm-accent-bright)' }}
> >
FAQ scope
</p> </p>
<h2 <h2
className="text-3xl lg:text-4xl font-bold break-keep" className="max-w-2xl break-keep text-3xl font-bold lg:text-[2.75rem] lg:leading-[1.12]"
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} style={{ color: 'var(--jsm-dark-ink)', letterSpacing: '-0.03em' }}
>
</h2>
</ScrollReveal>
<div className="mt-14 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{FIELDS.map((f, i) => (
<ScrollReveal key={f.t} delay={i * 80}>
<div
className="h-full rounded-2xl border p-7"
style={{
background: 'var(--jsm-dark-surface)',
borderColor: 'var(--jsm-dark-line)',
}}
>
<h3
className="break-keep text-lg font-bold"
style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }}
>
{f.t}
</h3>
<p
className="mt-2.5 break-keep text-sm leading-relaxed"
style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
>
{f.d}
</p>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
{/* ─────────────────── 4b. 진행 프로세스 ─────────────────── */}
<section id="process" className="scroll-mt-20 border-t" style={{ borderColor: 'var(--jsm-dark-line)' }}>
<div className="mx-auto max-w-6xl px-6 py-24 lg:px-8 lg:py-32">
<ScrollReveal>
<p
className="mb-3 font-mono text-[11px] uppercase tracking-[0.22em]"
style={{ color: 'var(--jsm-accent-bright)' }}
>
process
</p>
<h2
className="max-w-2xl break-keep text-3xl font-bold lg:text-[2.75rem] lg:leading-[1.12]"
style={{ color: 'var(--jsm-dark-ink)', letterSpacing: '-0.03em' }}
>
,
</h2>
</ScrollReveal>
<div className="mt-14 grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
{PROCESS.map((s, i) => (
<ScrollReveal key={s.n} delay={i * 80}>
<div
className="relative h-full rounded-2xl border p-7 lg:p-8"
style={{
background: 'var(--jsm-dark-surface)',
borderColor: 'var(--jsm-dark-line)',
}}
>
<span
className="relative z-10 inline-flex h-12 w-12 items-center justify-center rounded-full font-mono text-sm font-bold"
style={{
color: 'var(--jsm-accent-bright)',
background: 'var(--jsm-dark-bg)',
boxShadow: 'inset 0 0 0 1px var(--jsm-dark-line)',
}}
>
{s.n}
</span>
<h3
className="mt-5 break-keep text-lg font-bold"
style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }}
>
{s.t}
</h3>
<p
className="mt-2 break-keep text-sm leading-relaxed"
style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
>
{s.d}
</p>
</div>
</ScrollReveal>
))}
</div>
</div>
</section>
{/* ─────────────────── 5. FAQ ─────────────────── */}
<section className="border-t" style={{ borderColor: 'var(--jsm-dark-line)' }}>
<div className="mx-auto max-w-3xl px-6 py-24 lg:px-8 lg:py-32">
<ScrollReveal>
<p
className="mb-3 font-mono text-[11px] uppercase tracking-[0.22em]"
style={{ color: 'var(--jsm-accent-bright)' }}
>
faq
</p>
<h2
className="break-keep text-3xl font-bold lg:text-[2.75rem] lg:leading-[1.12]"
style={{ color: 'var(--jsm-dark-ink)', letterSpacing: '-0.03em' }}
> >
</h2> </h2>
</div> </ScrollReveal>
<div className="space-y-3">
{FAQ.map((item) => ( <div className="mt-14 space-y-3">
<details {FAQ.map((item, i) => (
key={item.q} <ScrollReveal key={item.q} delay={i * 80}>
className="group rounded-2xl border overflow-hidden" <details
style={{ background: 'var(--jsm-surface)', borderColor: 'var(--jsm-line)' }} className="group overflow-hidden rounded-2xl border"
> style={{
<summary background: 'var(--jsm-dark-surface)',
className="flex items-center justify-between gap-4 cursor-pointer list-none px-6 py-5 font-semibold break-keep" borderColor: 'var(--jsm-dark-line)',
style={{ color: 'var(--jsm-ink)', ...KOR_TIGHT }} }}
> >
{item.q} <summary
<svg className="flex cursor-pointer list-none items-center justify-between gap-4 break-keep px-6 py-5 font-semibold"
className="shrink-0 transition-transform duration-200 group-open:rotate-45" style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }}
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
aria-hidden
style={{ color: 'var(--jsm-ink-faint)' }}
> >
<path d="M12 5v14M5 12h14" /> {item.q}
</svg> <svg
</summary> className="shrink-0 transition-transform duration-200 group-open:rotate-45"
<p width="18"
className="px-6 pb-5 text-sm leading-relaxed break-keep" height="18"
style={{ color: 'var(--jsm-ink-soft)', ...KOR_BODY }} viewBox="0 0 24 24"
> fill="none"
{item.a} stroke="currentColor"
</p> strokeWidth="2"
</details> strokeLinecap="round"
aria-hidden
style={{ color: 'var(--jsm-dark-soft)' }}
>
<path d="M12 5v14M5 12h14" />
</svg>
</summary>
<p
className="break-keep px-6 pb-5 text-sm leading-relaxed"
style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
>
{item.a}
</p>
</details>
</ScrollReveal>
))} ))}
</div> </div>
</div> </div>
</section> </section>
{/* ─── 6. 의뢰 폼 ─── */} {/* ─────────────────── 6. 의뢰 폼 ─────────────────── */}
<section id="contact" className="scroll-mt-20" style={{ background: 'var(--jsm-navy)' }}> <section id="contact" className="scroll-mt-20 border-t" style={{ borderColor: 'var(--jsm-dark-line)' }}>
<div className="max-w-6xl mx-auto px-6 lg:px-8 py-20 lg:py-28"> <div className="mx-auto max-w-6xl px-6 py-24 lg:px-8 lg:py-32">
<div className="grid lg:grid-cols-5 gap-10 lg:gap-12"> <div className="grid gap-10 lg:grid-cols-5 lg:gap-12">
{/* 안내 */} {/* 안내 */}
<div className="lg:col-span-2"> <div className="lg:col-span-2">
<p <ScrollReveal>
className="text-xs font-semibold uppercase tracking-wider mb-3" <p
style={{ color: '#7aa7ff' }} className="mb-3 font-mono text-[11px] uppercase tracking-[0.22em]"
> style={{ color: 'var(--jsm-accent-bright)' }}
Contact
</p>
<h2
className="text-3xl lg:text-[2.5rem] font-bold leading-tight text-white break-keep"
style={KOR_TIGHT}
>
</h2>
<p
className="mt-5 text-lg leading-relaxed text-white/70 break-keep"
style={KOR_BODY}
>
2 .
.
</p>
<div
className="mt-8 pt-8 border-t space-y-3"
style={{ borderColor: 'rgba(255,255,255,0.12)' }}
>
<a
href="mailto:bgg8988@gmail.com"
className="flex items-center gap-3 text-sm text-white/80 hover:text-white transition-colors"
style={KOR_BODY}
> >
<span className="text-white/40 text-xs uppercase tracking-wider w-12">Mail</span> contact
bgg8988@gmail.com </p>
</a> <h2
<a className="break-keep text-3xl font-bold leading-tight lg:text-[2.5rem]"
href="tel:010-3907-1392" style={{ color: 'var(--jsm-dark-ink)', ...KOR_TIGHT }}
className="flex items-center gap-3 text-sm text-white/80 hover:text-white transition-colors"
style={KOR_BODY}
> >
<span className="text-white/40 text-xs uppercase tracking-wider w-12">Tel</span>
010-3907-1392 </h2>
</a> <p
</div> className="mt-5 break-keep text-lg leading-relaxed"
style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
>
2 .
.
</p>
<div
className="mt-8 space-y-3 border-t pt-8"
style={{ borderColor: 'var(--jsm-dark-line)' }}
>
<a
href="mailto:bgg8988@gmail.com"
className="flex items-center gap-3 text-sm transition-colors hover:text-[var(--jsm-dark-ink)]"
style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
>
<span
className="w-12 font-mono text-xs uppercase tracking-wider"
style={{ color: 'var(--jsm-accent-bright)' }}
>
Mail
</span>
bgg8988@gmail.com
</a>
<a
href="tel:010-3907-1392"
className="flex items-center gap-3 text-sm transition-colors hover:text-[var(--jsm-dark-ink)]"
style={{ color: 'var(--jsm-dark-soft)', ...KOR_BODY }}
>
<span
className="w-12 font-mono text-xs uppercase tracking-wider"
style={{ color: 'var(--jsm-accent-bright)' }}
>
Tel
</span>
010-3907-1392
</a>
</div>
</ScrollReveal>
</div> </div>
{/* 폼 */} {/* 폼 */}
<div className="lg:col-span-3"> <div className="lg:col-span-3">
<div <ScrollReveal delay={100}>
className="rounded-2xl p-6 lg:p-8" <div
style={{ background: 'var(--jsm-surface)' }} className="rounded-2xl border p-6 lg:p-8"
> style={{
<OutsourcingRequestForm /> background: 'var(--jsm-dark-surface)',
</div> borderColor: 'var(--jsm-dark-line)',
}}
>
<OutsourcingRequestForm />
</div>
</ScrollReveal>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
</> </div>
); );
} }