# UI Design System — Copper Monotone

> 어떤 스택에서든 동일한 톤을 이식하기 위한 단일 소스.
>
> **한 줄 정의**: **블랙(`#111111`) 모노톤과 카퍼(`#af6249`) 단일 포인트, 2px의 각진 라운드.** 무채색 스케일이 화면의 99%를 채우고, 카퍼는 활성 게이지·선택 순간에만 스치듯 등장하는 **프리미엄 오너십 앱** 시스템. 라이트·다크 쌍 토큰과 헤드/텍스트 이원 서체 체계가 럭셔리 톤을 지탱한다.

---

## 목차

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

---

## 1. 디자인 원칙

| 원칙 | 정의 |
|---|---|
| **모노톤 우선** | 화면은 블랙~그레이 무채색으로 완성한다. 색이 없는 상태가 기본이자 완성형. |
| **카퍼는 순간의 색** | `#af6249`는 게이지 활성·선택·프리미엄 순간에만. 버튼 채움·넓은 면 금지. |
| **각진 절제** | 라운드 2px — 곡선의 부드러움 대신 각의 정밀함. 원형은 아바타·인디케이터만. |
| **Head/Text 서체 이원** | 제목은 헤드 서체, 본문은 텍스트 서체. 역할 혼용 금지. |
| **여백이 럭셔리** | 정보 밀도를 낮추고 여백을 크게 — 한 화면에 하나의 메시지. |
| **양 테마 동등** | 모든 토큰이 라이트/다크 쌍. 다크는 딥 차콜(#202022) 기반. |

---

## 2. 색상 토큰

### 2-1. 뉴트럴 스케일 (라이트)

```css
:root {
  --surface:            #ffffff;
  --surface-low:        #f5f5f5;   /* 섹션·구획 배경 */
  --surface-container:  #ffffff;

  --on-surface:         #111111;   /* 기본 텍스트 */
  --on-surface-low:     #454547;
  --on-surface-mid:     #535356;   /* 보조 텍스트 */
  --on-surface-high:    #69696e;   /* 캡션 */
  --on-surface-highest: #929296;   /* 플레이스홀더 */
  --on-surface-disabled:#b7b7ba;

  --outline-low:        #eaeaeb;   /* 구분선 */
  --outline-mid:        #ceced0;   /* 입력 테두리 */
}
```

### 2-2. 포인트 & 보조

```css
:root {
  --copper:          #af6249;   /* 카퍼 — 활성·선택 */
  --copper-deep:     #703b28;   /* 카퍼 강조 보더 */
  --gauge-active:    #af6249;   /* 게이지·프로그레스 활성 */

  --info-blue:       #1a95cd;   /* 정보성 보조 (절제 사용) */
  --error:           #d4000e;
}
```

### 2-3. 사용 규칙

| 역할 | 토큰 |
|---|---|
| 제목·본문·수치 | `var(--on-surface)` |
| 보조 텍스트 | `var(--on-surface-mid)` |
| 캡션·단위 | `var(--on-surface-high)` |
| 페이지 배경 | `var(--surface)` |
| 구획 배경 | `var(--surface-low)` |
| 주 버튼 | `var(--on-surface)` 블랙 채움 + 흰 텍스트 |
| 게이지 활성·선택 표시 | `var(--copper)` |
| 구분선 | `var(--outline-low)` 1px |

> **핵심 규칙**: 카퍼가 한 화면에 두 곳 이상 보이면 이미 과하다. 액션은 블랙, 상태는 카퍼 한 점.

---

## 3. 타이포그래피

### 3-1. 폰트 — 헤드 / 텍스트 이원

원 시스템은 제목용·본문용 전용 서체를 분리해 사용한다. 공개 환경에서는 Noto Sans KR로 대체하되 역할 분리 구조는 유지한다.

```css
:root {
  --font-head: 'Noto Sans KR', 'Apple SD Gothic Neo', sans-serif;
  --font-text: 'Noto Sans KR', 'Apple SD Gothic Neo', sans-serif;
}

body { font-family: var(--font-text); color: var(--on-surface); background: var(--surface); }
h1, h2, h3, .display { font-family: var(--font-head); }
```

- **Head는 제목 전용, Text는 본문 전용** — 이 이원 구조가 브랜드 조판의 핵심.
- 미보유 환경 폴백은 Noto Sans KR.

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

| 역할 | `font-size` | `font-weight` | 서체 |
|---|---|---|---|
| Display | 28px | 400 | Head — 큰 제목도 Regular |
| Title | 22px | 500 | Head |
| Section | 17px | 500 | Head |
| Body | 15px | 400 | Text |
| Body Small | 13px | 400 | Text |
| Caption | 12px | 400 | Text |
| Label | 11px | 500 | Text |

- **Display가 Regular(400)** — 크기와 여백이 위계를 만들고 무게는 절제한다.
- 자간은 제목에서 살짝 넓게(`letter-spacing: 0.01em`) — 럭셔리 조판 관례.

---

## 4. 레이아웃 & 라운드

```css
:root {
  --radius:      0.125rem;   /* 2px — 버튼·카드·입력 */
  --radius-tab:  0.625rem;   /* 10px — 일부 상위 표면 */
  --radius-pill: 100px;      /* 인디케이터·아바타 */
}

.container { max-width: 40rem; margin-inline: auto; padding-inline: 1.5rem; }
.section   { padding-block: 2.5rem; }   /* 여백을 크게 */
```

- 홈은 차량 히어로가 화면 상단을 넓게 차지 — 이미지가 곧 럭셔리.
- 구획 사이는 보더 대신 `--surface-low` 면과 큰 여백.

---

## 5. 핵심 컴포넌트

### 5-1. 차량 히어로 & 게이지 — 시그니처

```html
<section class="hero">
  <img class="hero__img" src="..." alt="내 차량" />
  <h1 class="hero__name">My Sedan</h1>
  <div class="gauge" role="meter" aria-valuenow="72" aria-valuemin="0" aria-valuemax="100"
       aria-label="배터리 72%">
    <div class="gauge__track"><div class="gauge__fill" style="width: 72%"></div></div>
    <p class="gauge__value">72<em>%</em> <span>418km</span></p>
  </div>
</section>
```

```css
.hero__name {
  font-family: var(--font-head);
  font-size: 1.75rem;
  font-weight: 400;
  letter-spacing: 0.01em;
}
.gauge__track {
  height: 3px;                       /* 얇은 선 게이지 */
  background: var(--outline-low);
}
.gauge__fill  { height: 100%; background: var(--gauge-active); }
.gauge__value { font-size: 1.25rem; font-weight: 500; }
.gauge__value em { font-size: 0.75rem; font-style: normal; font-weight: 400; }
.gauge__value span { font-size: 0.8125rem; color: var(--on-surface-high); margin-left: 0.5rem; }
```

### 5-2. 버튼

```css
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3.25rem;
  padding: 0.875rem 1.75rem;
  border-radius: var(--radius);      /* 2px */
  font-family: var(--font-text);
  font-size: 0.9375rem;
  font-weight: 500;
  cursor: pointer;
  transition: opacity 0.2s ease, background-color 0.2s ease;
}
.btn--primary { background: var(--on-surface); color: #ffffff; border: none; }
.btn--primary:active { opacity: 0.85; }
.btn--outline { background: transparent; color: var(--on-surface);
                border: 1px solid var(--on-surface); }   /* 블랙 1px — 각진 아웃라인 */
.btn--text    { background: none; border: none; color: var(--on-surface);
                text-decoration: underline; text-underline-offset: 4px; }
.btn:disabled { background: var(--surface-low); color: var(--on-surface-disabled); border: none; }
```

### 5-3. 리스트 행 (설정·차량 관리)

```css
.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 3.5rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--outline-low);
}
.row__label { font-size: 0.9375rem; }
.row__value { font-size: 0.9375rem; color: var(--on-surface-high); }
.row--selected .row__label::before {   /* 선택 표시 — 카퍼 한 점 */
  content: '';
  display: inline-block;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--copper);
  margin-right: 0.5rem;
  vertical-align: middle;
}
```

### 5-4. 탭

```css
.tabs { display: flex; gap: 1.5rem; border-bottom: 1px solid var(--outline-low); }
.tab {
  padding: 0.75rem 0;
  background: none; border: none;
  font-family: var(--font-head);
  font-size: 0.9375rem;
  color: var(--on-surface-high);
  border-bottom: 2px solid transparent;
  cursor: pointer;
}
.tab[aria-selected="true"] {
  color: var(--on-surface);
  border-bottom-color: var(--copper);   /* 카퍼 언더라인 */
}
```

### 5-5. 바텀시트 & 약관 동의

- 공통 모듈: 로딩 → 약관 동의(전체/개별) → 앱 링크 흐름이 규격화되어 있다.
- 시트는 상단만 라운드(10px), 내부 컴포넌트는 2px 각을 유지.

---

## 6. 인터랙션

- 전환 `0.2s ease`, 페이드 중심 — 슬라이드·바운스 최소화. 럭셔리는 느긋한 페이드.
- 게이지 채움은 최초 1회만 0→값 애니메이션(0.6s ease-out), 갱신은 즉시.
- 탭 전환은 언더라인 이동 없이 크로스페이드 — 각진 절제 유지.
- `prefers-reduced-motion` 시 게이지 애니메이션 제거.

---

## 7. 다크 모드

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

  --surface:            #111111;
  --surface-low:        #202022;   /* 딥 차콜 구획 */
  --surface-container:  #202022;

  --on-surface:         #ffffff;
  --on-surface-low:     #ceced0;
  --on-surface-mid:     #9c9ca0;
  --on-surface-high:    #929296;
  --on-surface-highest: #86868d;
  --on-surface-disabled:#535356;

  --outline-low:        #3a3a3c;
  --outline-mid:        #454547;

  --copper:       #b5664b;    /* 카퍼 미세 상향 */
  --gauge-active: #b5664b;
  --info-blue:    #64abed;
  --error:        #ff6066;
}
```

- 다크의 주 버튼은 **화이트 채움 + 블랙 텍스트** 반전.
- 차량 이미지는 다크 배경에서 더 살아난다 — 히어로 영역은 다크 우선으로 검수.

---

## 8. 접근성

- `--on-surface`(#111111) 대비 19.1:1 — AAA. `--on-surface-mid`(#535356) 7.0:1 — AAA.
- 카퍼(#af6249) 대비 4.6:1 — 작은 텍스트 사용 시 AA 경계. 상태 표시는 텍스트 병기.
- 게이지는 `role="meter"` + `aria-valuenow` — 색만으로 잔량을 전달하지 않는다.
- 언더라인 텍스트 버튼은 색이 아닌 밑줄로 액션임을 표시 — 색약 대응.
- 터치 타깃 48px 이상 (버튼 min-height 52px).

---

## 9. 안티패턴

| 금지 | 이유 |
|---|---|
| 카퍼 채움 버튼·넓은 카퍼 면 | 카퍼는 순간의 색 — 게이지·선택 표시만 |
| 8px+ 라운드 (시트 상단 제외) | 2px 각진 절제가 정체성 |
| Head/Text 서체 혼용 | 제목=Head, 본문=Text 고정 |
| Display에 Bold | 큰 제목은 Regular — 여백이 위계 |
| 화면당 카퍼 2곳 이상 | 모노톤 우선 원칙 |
| 정보 과밀 화면 | 한 화면 하나의 메시지 |
| 바운스·스프링 모션 | 페이드 중심의 느긋함 |
| 라이트 전용 색 추가 | 라이트/다크 쌍 필수 |

---

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

### 10-1. Tailwind CSS v4

```css
@import "tailwindcss";

@theme {
  --color-surface:         #ffffff;
  --color-surface-low:     #f5f5f5;
  --color-on-surface:      #111111;
  --color-on-surface-mid:  #535356;
  --color-on-surface-high: #69696e;
  --color-outline-low:     #eaeaeb;
  --color-copper:          #af6249;
  --radius:                0.125rem;
}

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

### 10-2. Tailwind CSS v3

```js
module.exports = {
  darkMode: 'class',
  theme: {
    extend: {
      colors: {
        surface:        'var(--surface)',
        'surface-low':  'var(--surface-low)',
        'on-surface':   'var(--on-surface)',
        'on-surface-mid': 'var(--on-surface-mid)',
        'outline-low':  'var(--outline-low)',
        copper:         'var(--copper)',
      },
      borderRadius: { DEFAULT: '0.125rem', sheet: '0.625rem' },
      fontFamily: {
        head: ['Noto Sans KR', 'sans-serif'],
        text: ['Noto Sans KR', 'sans-serif'],
      },
    },
  },
};
```

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

CSS 변수가 원천. Head/Text 서체 이원은 `font-head`/`font-text` 유틸리티로 강제한다.

---

## 11. 이식 가이드

### Step 1 — 토큰 복사

§2 라이트 + §7 다크 블록을 전역 CSS에 붙인다.

### Step 2 — 서체 이원 설정

전용 헤드/텍스트 서체 보유 시 각각 연결, 아니면 Noto Sans KR 단일 폴백.

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

| 패턴 | 핵심 CSS |
|---|---|
| **2px 블랙 버튼** | `background: #111; border-radius: 2px` / 아웃라인은 블랙 1px |
| **얇은 카퍼 게이지** | 3px 트랙 + `#af6249` 채움 + 수치·단위 짝 |
| **카퍼 언더라인 탭** | 선택 시 `border-bottom: 2px solid #af6249` |

### Step 4 — 카퍼 총량 검증

화면마다 카퍼 등장 횟수를 세어 1곳 이내인지 확인한다.

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

```
새 컴포넌트가 필요하다
  → 무채색만으로 완성되는가?
    yes → 그대로 진행 (기본이자 완성형)
    no  → 활성·선택 순간인가? → 카퍼 한 점 (총량 확인)
          그 외 색 → 재검토
  → 라운드는 2px인가? (시트 상단만 10px)
  → 제목=Head, 본문=Text를 지켰는가?
```
