# Design System Inspired by Toss (토스 스타일 한국형 핀테크)

> 토스(Toss) 앱·TDS(Toss Design System)에서 영감을 받은 레퍼런스. 실제 토스 로고·브랜드명·일러스트를 복제하지 않는다. 결과물에는 자체 워드마크를 쓴다.
> 함께 적용: `designs/anti-slop.md`

---

## 1. 분위기 (Visual Theme & Atmosphere)

슬로건처럼 붙여 둘 문장은 **"단순함의 끝까지 다듬는다"**다. 화면은 흰 캔버스(`#FFFFFF`) 위에 거의 검은 본문(`#191F28`)과 회색 단계만 놓고, 색은 **토스 블루 하나**(`#3182F6`)만 쓴다. 블루는 장식에 쓰지 않는다. "지금 눌러야 할 단 하나의 버튼"을 가리킬 때만 등장한다.

금융 앱인데 딱딱하지 않다. 숫자는 크고 굵게, 문장은 친구에게 말하듯 해요체로 쓴다. "송금하시겠습니까?" 대신 "김지민님에게 50,000원을 보낼게요". 정보를 표로 늘어놓기보다 한 화면에 질문 하나, 답 하나만 둔다. 사용자가 스크롤보다 다음 단계로 넘어가며 생각하도록 흐름을 쪼갠다.

깊이는 그림자가 아니라 **회색 면의 단계**로 만든다. 홈은 `grey100` 배경 위에 흰 카드가 떠 있고, 카드 안 항목은 구분선 없이 여백과 글자 색으로만 나뉜다. 모서리는 12~20px로 부드럽지만 알약형 남발은 없다.

**핵심 특징**
- 한 화면, 한 강조 액션: 블루로 채운 버튼은 화면당 1개
- 하단 고정 풀폭 CTA (높이 56px, 반경 16px)
- 금액은 26~32px Bold, `tabular-nums`
- 오른쪽 셰브론이 있는 리스트 행이 기본 내비게이션 단위
- 거의 평면: 그림자는 바텀시트·토스트에만
- 해요체 마이크로카피, 주어는 "제가"가 아니라 사용자 중심
- Pretendard(실서비스는 Toss Product Sans) 단일 패밀리

---

## 2. 컬러 팔레트 & 역할

### Grey 스케일 (TDS 기준값)

| 토큰 | Light | Dark | 역할 |
|---|---|---|---|
| `--grey-50` | `#F9FAFB` | `#202027` | 입력 필드 배경, 눌림 상태 |
| `--grey-100` | `#F2F4F6` | `#2C2C35` | 홈 배경, 보조 버튼 면 |
| `--grey-200` | `#E5E8EB` | `#3C3C47` | 구분선, 비활성 테두리 |
| `--grey-300` | `#D1D6DB` | `#4D4D59` | 비활성 아이콘 |
| `--grey-400` | `#B0B8C1` | `#62626D` | 플레이스홀더, 셰브론 |
| `--grey-500` | `#8B95A1` | `#7E7E87` | 캡션, 보조 정보 |
| `--grey-600` | `#6B7684` | `#9E9EA4` | 리스트 서브텍스트 |
| `--grey-700` | `#4E5968` | `#C3C3C6` | 보조 본문 |
| `--grey-800` | `#333D4B` | `#E4E4E5` | 강조 본문 |
| `--grey-900` | `#191F28` | `#FFFFFF` | 제목, 금액, 본문 |

### Blue (유일한 브랜드 액센트)

| 토큰 | 값 | 역할 |
|---|---|---|
| `--blue-50` | `#E8F3FF` | 보조 버튼(약한 강조) 면, 선택된 칩 |
| `--blue-100` | `#C9E2FF` | 진행 바 트랙 |
| `--blue-400` | `#4593FC` | 다크모드 주 버튼 |
| `--blue-500` | `#3182F6` | 주 CTA, 링크, 포커스 |
| `--blue-600` | `#2272EB` | 주 CTA pressed |
| `--blue-700` | `#1B64DA` | 블루 위 텍스트 링크 |
| 로고 블루 | `#0064FF` | 브랜드 마크 전용. UI 컴포넌트에는 쓰지 않음 |

### Semantic

| 토큰 | 값 | 역할 |
|---|---|---|
| `--red-500` | `#F04452` | 출금·손실·에러 (주식 하락은 블루, 상승은 레드 — 한국 관례) |
| `--red-50` | `#FFEEEE` | 에러 배지 면 |
| `--green-500` | `#03B26C` | 완료·안전 상태 |
| `--green-50` | `#F0FAF6` | 성공 배지 면 |
| `--orange-500` | `#FE9800` | 주의, 만료 임박 |

### CSS 변수

```css
:root {
  --bg: #FFFFFF;
  --bg-sub: #F2F4F6;           /* 홈 배경 */
  --surface: #FFFFFF;
  --field: #F9FAFB;
  --line: #E5E8EB;
  --text-strong: #191F28;
  --text: #333D4B;
  --text-sub: #6B7684;
  --text-caption: #8B95A1;
  --primary: #3182F6;
  --primary-pressed: #2272EB;
  --primary-weak: #E8F3FF;
  --on-primary: #FFFFFF;
  --danger: #F04452;
  --success: #03B26C;
  --dim: rgba(0, 23, 51, 0.36); /* 바텀시트 뒤 딤 */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-xl: 20px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #17171C;
    --bg-sub: #101013;
    --surface: #202027;
    --field: #2C2C35;
    --line: #3C3C47;
    --text-strong: #FFFFFF;
    --text: #E4E4E5;
    --text-sub: #9E9EA4;
    --text-caption: #7E7E87;
    --primary: #4593FC;
    --primary-pressed: #3182F6;
    --primary-weak: rgba(69, 147, 252, 0.16);
    --danger: #F66570;
    --success: #1DC57F;
    --dim: rgba(0, 0, 0, 0.6);
  }
}
```

**규칙**: 블루 채움은 화면당 1곳. 금액 증감은 레드/블루 텍스트로만 표시하고 배경을 채색하지 않는다.

---

## 3. 타이포그래피

### 폰트
- **Primary**: `Pretendard Variable`, fallback `-apple-system, "Apple SD Gothic Neo", sans-serif`
- CDN: `https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css`
- 숫자: `font-variant-numeric: tabular-nums;` 금액·계좌번호·시간 전부
- 한글 자간: 본문 `-0.01em`, 제목 `-0.02em`. `word-break: keep-all`

### 모바일 스케일 (TDS t1~t7 근사)

| 토큰 | 크기 / 행간 | 굵기 | 용도 |
|---|---|---|---|
| `amount` | 32 / 40 | 700 | 금액 입력·잔액 디스플레이 |
| `t1` | 30 / 40 | 700 | 완료 화면 큰 제목 |
| `t2` | 26 / 35 | 700 | 페이지 제목 ("얼마를 보낼까요?") |
| `t3` | 22 / 31 | 700 | 섹션 제목, 카드 속 잔액 |
| `t4` | 20 / 29 | 600 | 바텀시트 제목 |
| `t5` | 17 / 25 | 600 | 리스트 주 텍스트, 버튼 |
| `t6` | 15 / 22 | 500 | 본문, 리스트 보조 금액 |
| `t7` | 13 / 19 | 500 | 캡션, 계좌번호, 타임스탬프 |

### 원칙
- 위계는 크기보다 **색(grey900 → grey600 → grey500)**으로 먼저 만든다.
- 한 화면 제목은 1개. 제목은 질문형 해요체: "누구에게 보낼까요?"
- 금액 단위 "원"은 숫자와 같은 크기·굵기로 붙이고, 입력 중 커서는 블루 2px.
- 굵기는 500/600/700 세 단계만. 300·800 금지.

---

## 4. 컴포넌트

### 하단 CTA (Bottom CTA)

```css
.cta-wrap {
  position: sticky; bottom: 0;
  padding: 12px 20px calc(12px + env(safe-area-inset-bottom));
  background: linear-gradient(to top, var(--bg) 80%, transparent);
}
.cta {
  width: 100%; height: 56px;
  border: 0; border-radius: var(--radius-lg);
  background: var(--primary); color: var(--on-primary);
  font: 600 17px/1 "Pretendard Variable", sans-serif;
  transition: transform .1s ease, background .15s ease;
}
.cta:active { transform: scale(0.98); background: var(--primary-pressed); }
.cta:disabled { background: var(--primary-weak); color: #90C2FF; }
/* 두 버튼이 필요할 때: 왼쪽은 약한 강조, 오른쪽만 채움 */
.cta-row { display: grid; grid-template-columns: 1fr 2fr; gap: 8px; }
.cta--weak { background: var(--bg-sub); color: var(--text); }
```

### 리스트 행 (List Row)

```css
.row {
  display: flex; align-items: center; gap: 16px;
  min-height: 64px; padding: 12px 24px;
}
.row:active { background: var(--field); }
.row__icon { width: 40px; height: 40px; border-radius: 50%; background: var(--bg-sub);
  display: grid; place-items: center; flex-shrink: 0; }
.row__main { flex: 1; min-width: 0; }
.row__title { font: 600 17px/25px inherit; color: var(--text-strong); }
.row__sub { font: 500 13px/19px inherit; color: var(--text-sub); }
.row__value { font: 600 17px/25px inherit; font-variant-numeric: tabular-nums; }
.row__chevron { width: 16px; height: 16px; color: var(--grey-400, #B0B8C1); }
```
구분선을 넣지 않는다. 행 사이 경계는 여백과 눌림 배경으로 충분하다.

### 금액 입력 키패드

```css
.amount-display { padding: 24px; font: 700 32px/40px inherit; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; color: var(--text-strong); }
.amount-display.is-empty { color: var(--grey-300, #D1D6DB); }
.amount-hint { padding: 0 24px; font: 500 15px/22px inherit; color: var(--text-sub); }
.amount-hint.is-error { color: var(--danger); }
.keypad { display: grid; grid-template-columns: repeat(3, 1fr); padding: 0 8px; }
.keypad button { height: 60px; border: 0; background: none; border-radius: var(--radius-md);
  font: 600 24px/1 inherit; color: var(--text-strong); }
.keypad button:active { background: var(--bg-sub); }
.quick-chips { display: flex; gap: 8px; padding: 0 20px; }
.quick-chips button { height: 36px; padding: 0 14px; border-radius: 18px; border: 0;
  background: var(--bg-sub); color: var(--text); font: 600 14px/1 inherit; }
```
키패드는 `1-9, 00, 0, ←` 배열. 숫자 입력 시 천 단위 콤마를 실시간 반영하고 아래에 "17만 원" 같은 한글 읽기를 보여준다.

### 카드

```css
.card { background: var(--surface); border-radius: var(--radius-xl); padding: 20px 0; }
.card__head { padding: 0 24px 8px; font: 700 20px/29px inherit; }
.page--home { background: var(--bg-sub); padding: 12px 12px 0; display: grid; gap: 12px; }
```
카드는 테두리·그림자 없이 회색 배경 위의 흰 면으로만 구분한다.

### 배지

```css
.badge { display: inline-flex; align-items: center; height: 22px; padding: 0 8px;
  border-radius: 6px; font: 600 12px/1 inherit; }
.badge--blue { background: var(--primary-weak); color: #1B64DA; }
.badge--grey { background: var(--bg-sub); color: var(--text-sub); }
.badge--red { background: #FFEEEE; color: #E42939; }
```

### 토스트

```css
.toast { position: fixed; left: 20px; right: 20px; bottom: calc(88px + env(safe-area-inset-bottom));
  padding: 14px 20px; border-radius: var(--radius-md);
  background: rgba(25, 31, 40, 0.92); color: #fff; font: 500 15px/22px inherit;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  animation: toast-in .2s ease-out; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } }
```
문구는 결과만 짧게: "계좌번호를 복사했어요".

### 바텀시트

```css
.sheet-dim { position: fixed; inset: 0; background: var(--dim); }
.sheet { position: fixed; left: 0; right: 0; bottom: 0; max-height: 90vh;
  background: var(--surface); border-radius: 24px 24px 0 0;
  padding: 8px 0 calc(16px + env(safe-area-inset-bottom));
  animation: sheet-up .25s cubic-bezier(.2,.8,.2,1); }
.sheet__handle { width: 36px; height: 4px; border-radius: 2px; background: var(--line); margin: 0 auto 16px; }
.sheet__title { padding: 0 24px 16px; font: 700 20px/29px inherit; }
@keyframes sheet-up { from { transform: translateY(100%); } }
```
확인·선택은 모달 다이얼로그가 아니라 바텀시트로. 시트 안에도 CTA는 1개.

---

## 5. 레이아웃 원칙

### 모바일 (기준)
- 프레임 폭 375~430px, 좌우 패딩 **24px**(리스트 행), 카드 바깥 여백 12px, CTA 좌우 20px.
- 상단 내비 높이 54px: 왼쪽 뒤로가기 셰브론, 가운데 제목 없음(본문 제목이 대신함), 오른쪽 텍스트 버튼 1개까지.
- 탭바 5개(홈·혜택·토스페이 류·주식·전체), 높이 56px + safe area, 아이콘 24px + 라벨 11px.
- 간격 스케일: 4 / 8 / 12 / 16 / 20 / 24 / 32 / 40. 제목과 본문 사이 8px, 섹션 사이 32px.

### 밀도
- 편안한(comfortable) 밀도. 리스트 행 64px 이상, 터치 타깃 48px 이상.
- 한 화면에 질문 1개. 입력 필드가 3개를 넘으면 스텝을 나눈다.

### 데스크톱 웹 적용
- 앱 플로우 화면은 **중앙 480px 컬럼**을 유지하고, 양옆은 `grey100`. 폭을 늘려 정보를 채우지 않는다.
- 마케팅/대시보드는 최대폭 1140px, 12컬럼, 거터 24px. 카드 반경은 20px 유지.
- 하단 CTA는 데스크톱에서 컬럼 하단 고정 → 컬럼 안 일반 버튼(높이 56px, 폭 100%)으로 전환.

---

## 6. 깊이 & 엘리베이션

| 레벨 | 처리 | 사용처 |
|---|---|---|
| 0 | 흰 면, 그림자 없음 | 페이지, 리스트 |
| 1 | `grey100` 배경 위 흰 카드 (톤 차이만) | 홈 카드 |
| 2 | `0 4px 16px rgba(0,0,0,0.12)` | 토스트, 플로팅 버튼 |
| 3 | 딤 `rgba(0,23,51,.36)` + 상단 반경 24px | 바텀시트 |

- 카드에 그림자를 주지 않는다. 깊이는 배경 회색 단계로만.
- 눌림 피드백은 `scale(0.98)` + 배경 한 단계 어둡게. 리플·글로우 없음.
- 모션 150~250ms, `cubic-bezier(.2,.8,.2,1)`. 화면 전환은 오른쪽에서 밀려오는 push.

---

## 7. Do / Don't

### Do
- **한 화면 한 액션**: 블루로 채운 버튼은 하나. 나머지는 `grey100` 면이나 텍스트 버튼.
- 금액은 화면에서 가장 큰 글자로. "원"까지 굵게 붙인다.
- 리스트 행 오른쪽에 셰브론을 두고, 행 전체를 터치 영역으로.
- 실패·빈 상태도 해요체로 이유와 다음 행동을 말한다: "잔액이 3,200원 부족해요. 채우고 보낼까요?"
- 완료 화면은 큰 체크 아이콘 + 결과 문장 1줄 + "확인" CTA.
- 계좌번호는 `은행명 + 번호` 순, 번호는 `tabular-nums`, 탭하면 복사 토스트.

### Don't
- 블루 버튼 2개 나란히, 블루 아이콘·블루 링크·블루 배지를 한 화면에 다 쓰기.
- 카드에 테두리 + 그림자 동시 적용. 그라디언트 배경. 보라색.
- "~하시겠습니까?", "~되었습니다", "확인 버튼을 눌러주십시오" 같은 합쇼체·피동.
- "에러가 발생했습니다(코드 E1023)"처럼 원인을 사용자에게 떠넘기는 문구.
- 이모지 아이콘. 실제 토스 로고·캐릭터 복제.
- 표처럼 빽빽한 금융 정보. 숫자를 가운데 정렬.

### UX 라이팅 규칙 (해요체)
| 피하기 | 이렇게 |
|---|---|
| 송금이 완료되었습니다. | 김지민님에게 50,000원을 보냈어요 |
| 비밀번호를 입력하십시오. | 비밀번호를 입력해 주세요 |
| 잔액이 부족합니다. | 잔액이 부족해요 |
| 계좌 등록 | 계좌 연결하기 |
| 취소하시겠습니까? | 송금을 그만할까요? |

- 버튼 라벨은 동사로 끝낸다: "보내기", "다음", "확인", "연결하기".
- 사용자를 주어로, 서비스를 낮춘다: "제가 알려드릴게요"보다 "알림을 받을 수 있어요".
- 한 문장에 정보 하나. 숫자는 구체적으로(“최대 5분”, “수수료 0원”).

---

## 8. 반응형

| 구간 | 폭 | 동작 |
|---|---|---|
| Mobile S | 320~374 | 금액 28px, 키패드 높이 52px, 좌우 패딩 20px |
| Mobile | 375~430 | 기준값 |
| Tablet | 431~1023 | 콘텐츠 480px 중앙 고정, 하단 CTA도 같은 폭 |
| Desktop | 1024+ | 앱 플로우는 480px 중앙 카드(반경 24px), 마케팅은 1140px 그리드 |

- 탭바는 768px 이상에서 좌측 사이드 내비(폭 240px)로 바뀐다.
- 바텀시트는 768px 이상에서 중앙 모달(폭 420px, 반경 24px)로.
- `env(safe-area-inset-bottom)`을 CTA·탭바·시트에 반드시 반영.
- `prefers-reduced-motion`이면 시트·토스트 애니메이션 제거.

---

## 9. 에이전트 프롬프트 가이드

### 빠른 컬러 참조
- 배경 `#FFFFFF` / 홈 배경 `#F2F4F6` / 필드 `#F9FAFB`
- 텍스트 `#191F28` / 보조 `#6B7684` / 캡션 `#8B95A1`
- 구분선 `#E5E8EB`
- 주 액션 `#3182F6` (pressed `#2272EB`, 약한 면 `#E8F3FF`)
- 에러 `#F04452` / 성공 `#03B26C`
- 폰트 Pretendard Variable, 반경 12/16/20px

### 복사용 프롬프트

```
토스 스타일 핀테크 모바일 화면을 만들어줘.
- 흰 배경, 텍스트 #191F28, 보조 텍스트 #6B7684, 회색 면 #F2F4F6
- 강조색은 #3182F6 하나만, 화면에서 채워진 버튼은 하단 CTA 1개뿐
- 폰트 Pretendard Variable, 금액은 32px Bold tabular-nums
- 하단 고정 풀폭 버튼(높이 56px, 반경 16px, 좌우 20px 여백)
- 리스트 행은 64px, 왼쪽 40px 원형 아이콘, 오른쪽 셰브론, 구분선 없음
- 카드는 그림자 없이 #F2F4F6 배경 위 흰 면, 반경 20px
- 모든 문구는 해요체. 실제 같은 은행명·이름·금액 사용
- 이모지 금지, 아이콘은 lucide-react
```

```
송금 금액 입력 화면을 토스 스타일로 만들어줘.
상단: 받는 사람 "김지민 · 카카오뱅크 3333-01-5523871"
제목: "얼마를 보낼까요?" (26px Bold)
금액 표시: 입력 전 "금액 입력" 회색, 입력 후 "50,000원" 검정 32px Bold + 아래 "5만 원" 한글 읽기
잔액 안내: "내 신한 계좌 잔액 1,284,500원" 13px 회색, 초과 시 빨강 "잔액이 부족해요"
빠른 칩: +1만 / +5만 / +10만 / 전액
3x4 숫자 키패드(00, 0, 지우기), 하단 CTA "보내기" — 금액 0이면 비활성
```

```
홈 자산 요약 화면을 만들어줘. 배경 #F2F4F6, 흰 카드 반경 20px 간격 12px.
카드1: "토스뱅크 통장 2,384,120원" + 작은 보조 버튼 "송금"(회색 면)
카드2: "자산" 리스트 행 4개(은행·증권·카드·대출), 각 금액 오른쪽 정렬, 셰브론
카드3: "이번 달 쓴 금액 847,300원" + 지난달 대비 "12만 원 덜 썼어요"
하단 탭바 5개. 화면 안에 블루 채움 요소는 최대 1개.
```

### 반복 체크
1. 블루로 채워진 요소가 2개 이상인가? → 하나만 남긴다.
2. "~습니다/~십시오"가 남았나? → 해요체로.
3. 카드에 그림자나 테두리가 있나? → 지우고 회색 배경 위 흰 면으로.
4. 금액이 화면에서 가장 큰 글자인가?
5. 빈 상태(거래 내역 없음)·에러(잔액 부족)·로딩(스켈레톤 `#F2F4F6`)을 만들었나?
