# UI Design System — Gmarket GDS

> 어떤 스택에서든 동일한 톤을 이식하기 위한 단일 소스. G마켓의 브랜드 자산과 대규모 이커머스 UI 관례를 웹 이식용으로 재해석한 문서다.
>
> **한 줄 정의**: **브랜드 그린(`#00c73c`)은 정체성, 세일 레드(`#fa2828`)는 혜택, 블랙(`#111`)은 정보.** 세 색의 역할을 엄격히 분리한 위에, 상품 카드·가격·뱃지의 고밀도 정보를 4px의 낮은 라운드와 얇은 보더로 정돈하는 대규모 쇼핑 시스템.

---

## 목차

1. [디자인 원칙](#1-디자인-원칙)
2. [색상 토큰](#2-색상-토큰)
3. [타이포그래피](#3-타이포그래피)
4. [레이아웃 & 그리드](#4-레이아웃--그리드)
5. [핵심 컴포넌트](#5-핵심-컴포넌트)
6. [인터랙션](#6-인터랙션)
7. [다크 모드](#7-다크-모드)
8. [접근성](#8-접근성)
9. [안티패턴](#9-안티패턴)
10. [프레임워크 어댑터](#10-프레임워크-어댑터)
11. [이식 가이드](#11-이식-가이드)

---

## 1. 디자인 원칙

| 원칙 | 정의 |
|---|---|
| **3색 역할 분리** | 그린=브랜드·완료, 레드=할인·혜택·긴급, 블랙=상품 정보. 서로의 영역을 침범하지 않는다. |
| **가격이 주인공** | 상품 카드에서 시선의 종착지는 가격. 할인율(레드) → 판매가(블랙 Bold) → 정가(회색 취소선) 순의 고정 위계. |
| **고밀도, 그러나 정돈** | 한 화면에 수십 개 상품이 떠도 읽히도록 — 카드 규격 통일, 텍스트 2줄 말줄임, 뱃지 위치 고정. |
| **낮은 라운드** | 4px. 상품 이미지·카드·버튼 모두 절제된 곡률로 정보 밀도를 지킨다. |
| **뱃지는 시스템** | 무료배송·쿠폰·랭킹 등 뱃지는 정해진 색·위치·우선순위로만. 임의 뱃지 금지. |
| **브랜드는 헤더에, 정보는 본문에** | 그린은 GNB·CTA·브랜드 요소에 집중. 상품 목록 안에서는 무채색+레드만. |

---

## 2. 색상 토큰

### 2-1. 브랜드 & 시맨틱

```css
:root {
  --brand:        #00c73c;  /* G마켓 그린 — GNB·브랜드·완료 */
  --brand-dark:   #00a832;
  --brand-surface:#e9f9ee;

  --sale:         #fa2828;  /* 할인율·특가·품절임박 */
  --sale-surface: #ffefef;

  --link:         #0066c3;  /* 텍스트 링크 */
}
```

### 2-2. 뉴트럴

```css
:root {
  --bg:           #ffffff;
  --surface:      #f4f4f4;  /* 섹션 구분·검색 바 배경 */
  --text:         #111111;  /* 상품명·가격 */
  --text-sub:     #757575;  /* 보조 정보·배송 안내 */
  --text-hint:    #999999;  /* 정가 취소선·메타 */
  --border:       #e5e5e5;  /* 카드·구분선 */
  --border-strong:#cccccc;  /* 입력·탭 하단 */
}
```

### 2-3. 사용 규칙

| 역할 | 토큰 |
|---|---|
| 상품명·판매가 | `var(--text)` |
| 배송·리뷰 수 | `var(--text-sub)` |
| 정가(취소선) | `var(--text-hint)` |
| 할인율·특가 뱃지 | `var(--sale)` |
| GNB·주 CTA·구매 완료 | `var(--brand)` |
| 카드 보더 | `var(--border)` 1px |
| 섹션 배경 | `var(--surface)` |

> **핵심 규칙**: 할인·혜택 이외의 요소에 레드를 쓰지 않는다. 레드가 흔해지면 혜택 신호가 죽는다.

---

## 3. 타이포그래피

### 3-1. 폰트

제목·브랜드 영역은 **Gmarket Sans**(무료 배포 브랜드 서체), 본문·상품 정보는 가독성 중심의 고딕체.

```css
:root {
  --font-display: 'Gmarket Sans', 'Noto Sans KR', sans-serif;   /* 프로모션 제목 */
  --font-sans:    'Noto Sans KR', 'Malgun Gothic', 'Apple SD Gothic Neo', sans-serif;
}

body { font-family: var(--font-sans); color: var(--text); background: var(--bg); }
h1, h2, .promo-title { font-family: var(--font-display); }
```

```html
<link rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;500;700&display=swap" />
```

### 3-2. 타입 스케일

| 역할 | `font-size` | `font-weight` | 비고 |
|---|---|---|---|
| 프로모션 타이틀 | 24px | 700 | Gmarket Sans |
| 섹션 제목 | 18px | 700 | |
| 상품명 (목록) | 14px | 400 | 2줄 말줄임 |
| 판매가 | 16px | 700 | `tabular-nums` |
| 할인율 | 16px | 700 | `--sale` |
| 정가 | 13px | 400 | 취소선, `--text-hint` |
| 뱃지·메타 | 11px | 500 | |

```css
.price      { font-size: 1rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.price__won { font-size: 0.8125rem; font-weight: 400; }
.discount   { font-size: 1rem; font-weight: 700; color: var(--sale); }
.original   { font-size: 0.8125rem; color: var(--text-hint); text-decoration: line-through; }
```

---

## 4. 레이아웃 & 그리드

```css
:root {
  --radius:  0.25rem;   /* 4px */
  --gap:     0.75rem;   /* 카드 간격 12px */
}

.container { max-width: 78rem; margin-inline: auto; padding-inline: 1rem; }

.product-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.25rem var(--gap);
}
@media (min-width: 768px)  { .product-grid { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 1200px) { .product-grid { grid-template-columns: repeat(5, 1fr); } }
```

- 상품 이미지는 1:1 고정 비율. 카드 높이는 그리드 행 단위로 통일.
- 섹션 사이는 `--surface` 8px 두께 면으로 분리(모바일 관례).

---

## 5. 핵심 컴포넌트

### 5-1. 상품 카드 — 시그니처

```html
<a class="product" href="...">
  <div class="product__thumb">
    <img src="..." alt="상품명" />
    <span class="badge badge--rank">1위</span>
  </div>
  <p class="product__name">상품명은 최대 두 줄까지 표시되고 넘치면 말줄임…</p>
  <p class="product__price">
    <span class="discount">32%</span>
    <span class="price">12,900<span class="price__won">원</span></span>
    <span class="original">18,900원</span>
  </p>
  <p class="product__meta">무료배송 · 리뷰 1,234</p>
</a>
```

```css
.product { display: block; text-decoration: none; }
.product__thumb {
  position: relative;
  aspect-ratio: 1;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.product__name {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: var(--text);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.product__price { margin-top: 0.375rem; display: flex; align-items: baseline; gap: 0.375rem; }
.product__meta  { margin-top: 0.25rem; font-size: 0.75rem; color: var(--text-sub); }
```

### 5-2. 뱃지 시스템

```css
.badge {
  display: inline-block;
  padding: 0.125rem 0.375rem;
  border-radius: var(--radius);
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1.4;
}
.badge--rank     { position: absolute; top: 0; left: 0; background: #111; color: #fff; border-radius: 0; }
.badge--delivery { background: var(--surface); color: var(--text-sub); }
.badge--coupon   { background: var(--sale-surface); color: var(--sale); }
.badge--brand    { background: var(--brand-surface); color: var(--brand-dark); }
```

- 뱃지 우선순위: 랭킹 > 쿠폰 > 배송. 카드당 최대 2개.

### 5-3. 버튼

```css
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  padding: 0.625rem 1.25rem;
  border-radius: var(--radius);
  font-size: 0.9375rem;
  font-weight: 700;
  cursor: pointer;
  transition: background-color 0.15s ease;
}
.btn--primary   { background: var(--brand); color: #fff; border: none; }
.btn--primary:hover { background: var(--brand-dark); }
.btn--secondary { background: #fff; color: var(--text); border: 1px solid var(--border-strong); }
.btn--buy       { background: var(--sale); color: #fff; border: none; }  /* 바로구매 */
.btn:disabled   { background: var(--surface); color: var(--text-hint); border: none; }
```

### 5-4. 탭 (카테고리)

```css
.tabs { display: flex; border-bottom: 1px solid var(--border); overflow-x: auto; }
.tab {
  padding: 0.75rem 1rem;
  font-size: 0.9375rem;
  color: var(--text-sub);
  background: none; border: none;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
  cursor: pointer;
}
.tab[aria-selected="true"] {
  color: var(--text);
  font-weight: 700;
  border-bottom-color: var(--text);
}
```

---

## 6. 인터랙션

- 카드 호버: 이미지 미세 확대(`scale(1.03)`, 0.2s) + 상품명 밑줄. 모바일에서는 생략.
- 전환은 `0.15~0.2s ease`. 가격·타이머 등 숫자 변동은 즉시 반영(애니메이션 금지 — 신뢰 문제).
- 무한 스크롤 목록은 스켈레톤 카드로 로딩 표시.

---

## 7. 다크 모드

```css
.dark {
  color-scheme: dark;

  --bg:           #121212;
  --surface:      #1e1e1e;
  --text:         #ececec;
  --text-sub:     #9e9e9e;
  --text-hint:    #6e6e6e;
  --border:       #2e2e2e;
  --border-strong:#454545;

  --brand:        #00d341;   /* 그린 한 단계 밝게 */
  --brand-surface:#0d2617;
  --sale:         #ff5252;   /* 레드 한 단계 밝게 */
  --sale-surface: #33191b;
  --link:         #4d9fff;
}
```

- 상품 이미지는 다크에서도 흰 배경이 대부분 — 이미지에 `border` 1px을 유지해 경계를 잡는다.

---

## 8. 접근성

- `--text`(#111) 대비 19.1:1, `--text-sub`(#757575) 4.6:1 — AA 통과.
- 할인율·가격은 색+굵기+취소선으로 삼중 구분 — 색약 사용자도 정가/판매가를 구분 가능.
- 상품 카드 전체가 하나의 링크 — 내부에 중첩 링크 금지.
- 뱃지는 `aria-label`로 의미 명시("무료배송 상품").
- 타이머·품절임박 등 긴급 신호는 색만이 아니라 텍스트로 병기.

---

## 9. 안티패턴

| 금지 | 이유 |
|---|---|
| 할인 이외 요소에 레드 사용 | 혜택 신호 희석 |
| 상품 목록 안에 브랜드 그린 남용 | 그린은 GNB·CTA 전용 |
| 카드마다 다른 이미지 비율 | 1:1 고정 — 그리드 붕괴 방지 |
| 상품명 3줄 이상 노출 | 2줄 말줄임 고정 |
| 임의 위치·임의 색 뱃지 | 뱃지는 시스템(색·위치·우선순위 고정) |
| 가격 변동 애니메이션 | 가격은 즉시·정확하게 — 신뢰 요소 |
| 8px 이상 라운드 | 고밀도 정보에는 낮은 곡률 |
| 정가만 표시 (판매가 없이) | 가격 위계(할인율→판매가→정가) 고정 |

---

## 10. 프레임워크 어댑터

### 10-1. Tailwind CSS v4

```css
@import "tailwindcss";

@theme {
  --color-bg:       #ffffff;
  --color-surface:  #f4f4f4;
  --color-text:     #111111;
  --color-text-sub: #757575;
  --color-border:   #e5e5e5;
  --color-brand:    #00c73c;
  --color-sale:     #fa2828;
  --radius:         0.25rem;
}

@custom-variant dark (&:where(.dark, .dark *));
```

### 10-2. Tailwind CSS v3

```js
module.exports = {
  darkMode: 'class',
  theme: {
    extend: {
      colors: {
        bg:        'var(--bg)',
        surface:   'var(--surface)',
        text:      'var(--text)',
        'text-sub':'var(--text-sub)',
        border:    'var(--border)',
        brand:     'var(--brand)',
        sale:      'var(--sale)',
      },
      borderRadius: { DEFAULT: '0.25rem' },
    },
  },
};
```

### 10-3. React / Vue / Svelte

CSS 변수가 원천. 상품 카드를 단일 컴포넌트로 만들고 뱃지·가격 위계를 props가 아닌 데이터로 제어한다.

---

## 11. 이식 가이드

### Step 1 — 토큰 복사

§2 + §7 블록을 전역 CSS에 붙인다.

### Step 2 — 폰트 연결

Noto Sans KR 링크 추가. Gmarket Sans 보유 시 프로모션 제목에만 연결.

### Step 3 — 시그니처 3종 적용

| 패턴 | 핵심 CSS |
|---|---|
| **상품 카드** | 1:1 썸네일 + 2줄 말줄임 + 할인율/판매가/정가 3단 가격 |
| **가격 위계** | 레드 Bold 할인율 → 블랙 Bold 판매가 → 회색 취소선 정가 |
| **뱃지 시스템** | 고정 색·위치·우선순위, 카드당 최대 2개 |

### Step 4 — 그리드 검증

2/4/5열 반응형에서 카드 높이가 줄 단위로 정렬되는지 확인한다.

### 신규 컴포넌트 결정 트리

```
새 컴포넌트가 필요하다
  → 상품 정보를 담는가?
    yes → 상품 카드의 변형(가로형·리스트형)으로 — 가격 위계 유지
    no  → 색이 필요한가?
      → 혜택·긴급인가? → 레드
      → 브랜드·완료인가? → 그린
      → 그 외 → 무채색만
```
