히어로에 헤드라인·서브·CTA 2개·군집 밴드·순환 링이 다 들어가 세로 예산이 포화라 위를 벌리면 아래가 터지는 상태였다. 링을 옮겨 자리를 만든다. - 순환 링을 강화학습 섹션으로. "협상할수록 좋아진다"를 말하는 자리라 루프가 의미상 속하는 곳이기도 하다. 텍스트 좌 / 링 우 2단 배치. - OrbitRing 에 자체 시계 모드 추가 — progressRef·phase 를 안 주면 스스로 돈다. 덕분에 히어로 캔버스와 무관한 섹션에서도 단독으로 쓸 수 있다. - 히어로 상단 여백 14vh → 19vh, 밴드를 하단 전체(0.63/0.30)로 확장. - 군집 라벨 y 계산 버그 수정. 밴드 지역 좌표(0.5)를 화면 좌표로 착각해 밴드를 옮길 때마다 라벨이 엉뚱한 곳으로 갔다. 이제 행 수·행간에서 격자 상단을 실제로 계산해 투영한다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
88 lines
3.5 KiB
TypeScript
88 lines
3.5 KiB
TypeScript
import { motion } from "motion/react"
|
|
import { GitMerge, RefreshCw, Scale, type LucideIcon } from "lucide-react"
|
|
|
|
import { Section } from "@/components/ui/section"
|
|
import { SectionHeading } from "@/components/ui/section-heading"
|
|
import { Typography } from "@/components/ui/typography"
|
|
import { OrbitRing } from "@/components/ui/orbit-ring"
|
|
import { useFadeUp } from "@/lib/motion"
|
|
|
|
/** 강화학습 섹션 — 협상할수록 좋아진다는 3개 필러 카드. */
|
|
export function Reinforcement() {
|
|
const fadeUp = useFadeUp()
|
|
|
|
return (
|
|
<Section id="reinforcement" bg="stage" width="lg">
|
|
{/* 순환 링은 원래 히어로에 있었는데, 루프가 의미상 속하는 자리는 여기다 —
|
|
"협상할수록 좋아진다"를 말하는 섹션이고, 히어로는 이미 세로 예산이 포화였다. */}
|
|
<motion.div {...fadeUp} className="grid grid-cols-1 lg:grid-cols-12 gap-12 lg:gap-16 items-center mb-20">
|
|
<div className="lg:col-span-7">
|
|
<SectionHeading
|
|
className="text-center lg:text-left"
|
|
tone="stage"
|
|
eyebrow="Reinforcement Learning"
|
|
title="협상할수록, 더 좋은 조건으로"
|
|
description={
|
|
<>
|
|
잘 깎는 요령은 담당자 머릿속에만 남고, 결과는 그날 컨디션에 흔들립니다. negotium은 지난 거래 기록과
|
|
협력사가 거절한 지점을 <span className="font-semibold text-on-stage">강화학습</span>에 넣습니다. 어디까지가
|
|
받아들여지는 선인지를 데이터로 익혀서, 결렬 없이 도달 가능한 최선을 찾아갑니다.
|
|
</>
|
|
}
|
|
descriptionClassName="mt-8"
|
|
/>
|
|
</div>
|
|
<div className="lg:col-span-5 flex justify-center">
|
|
<OrbitRing className="w-[280px] md:w-[340px] h-auto" />
|
|
</div>
|
|
</motion.div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
|
{PILLARS.map((pillar, idx) => (
|
|
<PillarCard key={pillar.title} pillar={pillar} delay={0.1 * (idx + 1)} />
|
|
))}
|
|
</div>
|
|
</Section>
|
|
)
|
|
}
|
|
|
|
type Pillar = { icon: LucideIcon; title: string; description: string }
|
|
|
|
function PillarCard({ pillar, delay }: { pillar: Pillar; delay: number }) {
|
|
const fadeUp = useFadeUp(delay)
|
|
|
|
return (
|
|
<motion.div {...fadeUp} className="bg-stage-raised border border-stage-line p-8 rounded-card flex flex-col justify-between h-[240px]">
|
|
<div className="w-11 h-11 rounded-control bg-primary/15 text-on-stage flex items-center justify-center">
|
|
<pillar.icon className="w-5 h-5" />
|
|
</div>
|
|
<div>
|
|
<Typography variant="cardTitle" className="mb-2 text-on-stage">
|
|
{pillar.title}
|
|
</Typography>
|
|
<Typography variant="caption" className="text-on-stage-soft">
|
|
{pillar.description}
|
|
</Typography>
|
|
</div>
|
|
</motion.div>
|
|
)
|
|
}
|
|
|
|
const PILLARS: Pillar[] = [
|
|
{
|
|
icon: Scale,
|
|
title: "협상 기준의 일관성",
|
|
description: "개인 감정이나 친분에 휘둘리지 않고, 사내 기준과 가이드라인대로만 협상합니다.",
|
|
},
|
|
{
|
|
icon: RefreshCw,
|
|
title: "쓸수록 올라가는 기준선",
|
|
description: "협상이 쌓일수록 기준선이 올라갑니다. 운영 기간이 그대로 협상력이 됩니다.",
|
|
},
|
|
{
|
|
icon: GitMerge,
|
|
title: "결렬 없는 합의",
|
|
description: "성사되지 않을 선까지 밀지 않습니다. 합의 가능한 범위 안에서 최선을 찾습니다.",
|
|
},
|
|
]
|