# UI Design System — Apple HIG

> 어떤 스택에서든 동일한 톤을 이식하기 위한 단일 소스. Apple Human Interface Guidelines의 공개 시스템 컬러·원칙을 웹 이식용으로 재해석한 문서다.
>
> **한 줄 정의**: **콘텐츠가 주인공, 인터페이스는 물러선다.** 시스템 블루(`#007aff`)를 유일한 틴트로, 그룹 배경(`#f2f2f7`)과 반투명 구분선으로 계층을 만들고, 명료함(Clarity)·존중(Deference)·깊이(Depth) 세 가치로 모든 결정을 검증하는 플랫폼 네이티브 시스템.

---

## 목차

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

---

## 1. 디자인 원칙

| 원칙 | 정의 |
|---|---|
| **Clarity (명료함)** | 모든 크기에서 텍스트가 읽히고, 아이콘이 정확하며, 장식이 기능을 가리지 않는다. |
| **Deference (존중)** | UI는 콘텐츠에 자리를 내준다. 크롬(chrome)은 얇고 반투명하며, 콘텐츠가 화면을 채운다. |
| **Depth (깊이)** | 계층은 반투명·블러·시차로 표현한다. 시트는 아래에서 올라오고, 뒤 콘텐츠가 비쳐 보인다. |
| **단일 틴트** | 앱 전체에 틴트 컬러 하나(`#007aff`)만. 인터랙티브 = 틴트, 비인터랙티브 = 뉴트럴이라는 계약. |
| **텍스트 버튼 우선** | 내비게이션 액션은 배경 없는 틴트 텍스트가 기본. 면 버튼은 주요 CTA에만. |
| **시맨틱 컬러** | 색은 `label`, `systemBackground`처럼 역할 이름으로 정의 — 라이트/다크 전환이 자동이 되게. |
| **플랫폼 존중** | 시스템 폰트·시스템 컨트롤·표준 제스처를 따른다. 커스텀은 콘텐츠 영역에서만. |

---

## 2. 색상 토큰

### 2-1. 시스템 컬러

```css
:root {
  --system-blue:   #007aff;  /* 기본 틴트 */
  --system-red:    #ff3b30;  /* 삭제·경고 */
  --system-green:  #34c759;  /* 성공 */
  --system-orange: #ff9500;
  --system-yellow: #ffcc00;
  --system-pink:   #ff2d55;
  --system-purple: #af52de;
  --system-teal:   #30b0c7;
  --system-indigo: #5856d6;
}
```

### 2-2. 시맨틱 레이어 (라이트)

```css
:root {
  /* Label — 텍스트 4계층 */
  --label:            #1d1d1f;              /* 기본 텍스트 */
  --label-secondary:  rgba(60, 60, 67, 0.6);  /* 보조 */
  --label-tertiary:   rgba(60, 60, 67, 0.3);  /* 플레이스홀더 */
  --label-quaternary: rgba(60, 60, 67, 0.18); /* 비활성 */

  /* Background — 표면 3계층 × 2계열 */
  --bg:                 #ffffff;  /* systemBackground */
  --bg-secondary:       #f2f2f7;  /* 그룹 리스트 페이지 배경 */
  --bg-tertiary:        #ffffff;  /* 그룹 배경 위 카드 */

  /* Fill & Separator */
  --fill:              rgba(120, 120, 128, 0.2);   /* 컨트롤 채움 */
  --fill-secondary:    rgba(120, 120, 128, 0.16);
  --separator:         rgba(60, 60, 67, 0.29);     /* 불투명 대체: #c6c6c8 */

  --tint:              var(--system-blue);
}
```

### 2-3. 사용 규칙

| 역할 | 토큰 |
|---|---|
| 제목·본문 | `var(--label)` |
| 보조 설명 | `var(--label-secondary)` |
| 플레이스홀더 | `var(--label-tertiary)` |
| 페이지 배경 (그룹 리스트) | `var(--bg-secondary)` |
| 카드·셀 표면 | `var(--bg-tertiary)` |
| 구분선 | `var(--separator)` 0.5~1px |
| 링크·버튼·선택 | `var(--tint)` |
| 파괴적 액션 | `var(--system-red)` |

> **핵심 규칙**: 틴트 색이 곧 "누를 수 있음"의 신호다. 인터랙티브하지 않은 요소에 틴트를 칠하지 않고, 인터랙티브한 요소에서 틴트를 빼지 않는다.

---

## 3. 타이포그래피

### 3-1. 폰트 — 시스템 폰트 스택

SF Pro(영문)·Apple SD Gothic Neo(한글)는 Apple 기기의 시스템 폰트로 제공된다. 웹에서는 시스템 스택으로 연결하고, 비 Apple 환경 폴백으로 Noto Sans KR을 로드한다.

```css
:root {
  --font-sans: -apple-system, BlinkMacSystemFont,
               'Apple SD Gothic Neo', 'Noto Sans KR',
               'Segoe UI', Roboto, sans-serif;
}

body {
  font-family: var(--font-sans);
  color: var(--label);
  background: var(--bg-secondary);
  -webkit-font-smoothing: antialiased;
}
```

### 3-2. 타입 스케일 — iOS Text Styles

| 스타일 | `font-size` | `font-weight` | 용도 |
|---|---|---|---|
| Large Title | 34px | 700 | 페이지 대제목 |
| Title 1 | 28px | 700 | 섹션 대제목 |
| Title 2 | 22px | 700 | 카드 그룹 제목 |
| Title 3 | 20px | 600 | 카드 제목 |
| Headline | 17px | 600 | 셀 제목 |
| Body | 17px | 400 | 본문 |
| Callout | 16px | 400 | 부연 |
| Subheadline | 15px | 400 | 보조 |
| Footnote | 13px | 400 | 각주 |
| Caption 1 | 12px | 400 | 캡션 |
| Caption 2 | 11px | 400 | 최소 캡션 |

```css
.large-title { font-size: 2.125rem; font-weight: 700; letter-spacing: 0.01em; }
.headline    { font-size: 1.0625rem; font-weight: 600; }
.body        { font-size: 1.0625rem; line-height: 1.47; }
.footnote    { font-size: 0.8125rem; color: var(--label-secondary); }
```

- **Body와 Headline이 같은 17px** — 크기가 아니라 웨이트(400 vs 600)로 위계를 만드는 것이 HIG의 특징.
- Dynamic Type 대응: 모든 크기 `rem`, 사용자가 텍스트를 310%까지 키워도 레이아웃이 견뎌야 한다.

---

## 4. 레이아웃 & 형태

```css
:root {
  --radius-card:    0.75rem;   /* 12px — 카드·그룹 셀 */
  --radius-button:  0.75rem;   /* 12px — 면 버튼 */
  --radius-sheet:   0.625rem;  /* 시트 상단 */
  --radius-pill:    62.4375rem;
  --margin-inline:  1rem;      /* 16px 기본 마진 */
}

.container { max-width: 44rem; margin-inline: auto; padding-inline: var(--margin-inline); }
```

- 라운드는 12px 내외의 **연속 곡률(continuous corner)** 감성 — 급격한 원호 대신 부드러운 전이.
- 그룹 리스트: `--bg-secondary` 페이지 위에 `--bg-tertiary` 라운드 그룹이 얹히는 구조가 기본 골격.

---

## 5. 핵심 컴포넌트

### 5-1. 그룹 리스트 (Inset Grouped List) — 시그니처

```html
<section class="group">
  <h3 class="group__header">일반</h3>
  <div class="group__body">
    <a class="row">
      <span class="row__label">화면 및 밝기</span>
      <span class="row__value">자동</span>
      <span class="row__chevron">›</span>
    </a>
    <a class="row">…</a>
  </div>
</section>
```

```css
.group { margin-block: 1.5rem; }
.group__header {
  font-size: 0.8125rem;
  text-transform: uppercase;
  color: var(--label-secondary);
  padding: 0 1rem 0.375rem;
}
.group__body {
  background: var(--bg-tertiary);
  border-radius: var(--radius-card);
  overflow: hidden;
}
.row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  min-height: 2.75rem;         /* 44px 터치 타깃 */
  text-decoration: none;
}
.row + .row { border-top: 0.5px solid var(--separator); }
.row:active { background: var(--fill-secondary); }
.row__label   { color: var(--label); font-size: 1.0625rem; flex: 1; }
.row__value   { color: var(--label-secondary); font-size: 1.0625rem; }
.row__chevron { color: var(--label-tertiary); }
```

### 5-2. 버튼

```css
/* 기본형 — 틴트 텍스트 버튼 */
.btn-text {
  background: none;
  border: none;
  color: var(--tint);
  font-size: 1.0625rem;
  cursor: pointer;
}
.btn-text:active { opacity: 0.3; }
.btn-text--destructive { color: var(--system-red); }

/* 주요 CTA — 면 버튼 */
.btn-filled {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  padding: 0.75rem 1.25rem;
  border: none;
  border-radius: var(--radius-button);
  background: var(--tint);
  color: #ffffff;
  font-size: 1.0625rem;
  font-weight: 600;
  cursor: pointer;
}
.btn-filled:active { opacity: 0.75; }

/* 옅은 틴트 면 */
.btn-tinted {
  background: rgba(0, 122, 255, 0.15);
  color: var(--tint);
}
```

### 5-3. 시트(모달)

```css
.sheet-backdrop { background: rgba(0, 0, 0, 0.4); }
.sheet {
  background: var(--bg);
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.15);
}
.sheet__grabber {
  width: 36px; height: 5px;
  border-radius: var(--radius-pill);
  background: var(--label-quaternary);
  margin: 0.375rem auto;
}
```

### 5-4. 세그먼트 컨트롤

```css
.segment {
  display: inline-flex;
  background: var(--fill);
  border-radius: 0.5625rem;
  padding: 2px;
}
.segment__item {
  padding: 0.375rem 1rem;
  border: none;
  background: transparent;
  border-radius: 0.4375rem;
  font-size: 0.8125rem;
  color: var(--label);
  cursor: pointer;
}
.segment__item[aria-pressed="true"] {
  background: var(--bg);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
  font-weight: 600;
}
```

---

## 6. 인터랙션

- 탭 피드백은 **불투명도**로: 텍스트 버튼 `opacity: 0.3`, 면 버튼 `0.75`, 즉시 적용.
- 전환은 스프링 감각의 `0.3s cubic-bezier(0.25, 0.1, 0.25, 1)`. 시트는 아래에서 위로.
- 스크롤은 콘텐츠가 주도 — 헤더는 스크롤에 따라 Large Title → 인라인 제목으로 축소.
- `prefers-reduced-motion` 시 이동 애니메이션을 크로스페이드로 대체.

---

## 7. 다크 모드

시맨틱 토큰만 뒤집는다. 다크는 반전이 아니라 **별도의 팔레트**다.

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

  --label:            #f5f5f7;
  --label-secondary:  rgba(235, 235, 245, 0.6);
  --label-tertiary:   rgba(235, 235, 245, 0.3);
  --label-quaternary: rgba(235, 235, 245, 0.16);

  --bg:            #000000;   /* systemBackground */
  --bg-secondary:  #1c1c1e;   /* elevated 그룹 배경 */
  --bg-tertiary:   #2c2c2e;   /* 카드·셀 */

  --fill:           rgba(120, 120, 128, 0.36);
  --fill-secondary: rgba(120, 120, 128, 0.32);
  --separator:      rgba(84, 84, 88, 0.65);

  /* 시스템 컬러도 다크 전용 값으로 상향 */
  --system-blue:   #0a84ff;
  --system-red:    #ff453a;
  --system-green:  #30d158;
  --system-orange: #ff9f0a;
  --tint:          var(--system-blue);
}
```

- 시스템 컬러가 다크에서 **한 단계 밝은 전용 값**으로 바뀌는 것이 HIG 다크 모드의 핵심 (blue `#007aff → #0a84ff`).
- 표면은 순수 검정 배경 위 `#1c1c1e → #2c2c2e`로 밝아지며 계층을 만든다.

---

## 8. 접근성

- Dynamic Type: 텍스트 310% 확대를 견디는 레이아웃 — 고정 높이 금지, `rem` 필수.
- `--label` 대비 16.1:1(라이트) — 본문 AAA. `--label-secondary`는 보조 텍스트까지만.
- 터치 타깃 최소 44×44pt — 모든 행·버튼 `min-height: 2.75rem`.
- 색상 단독 의미 전달 금지 — 틴트 텍스트 버튼은 위치·문맥으로도 액션임이 드러나야 한다.
- `prefers-reduced-transparency` 대응: 반투명 크롬을 불투명 배경으로 대체할 수 있게 토큰화.
- VoiceOver 기준 레이블: 아이콘 버튼은 `aria-label` 필수.

---

## 9. 안티패턴

| 금지 | 이유 |
|---|---|
| 여러 틴트 컬러 혼용 | 단일 틴트 = 인터랙션 신호 체계 |
| 비인터랙티브 요소에 틴트 사용 | "누를 수 있음" 계약 위반 |
| 인터랙티브 요소에서 틴트 제거 | 동일 |
| 다크 모드를 명도 반전으로 처리 | 다크 전용 팔레트 사용 (blue #0a84ff 등) |
| 고정 px 타이포 | Dynamic Type 대응 불가 |
| 44px 미만 터치 타깃 | HIG 최소 기준 |
| 두꺼운 불투명 구분선 | separator는 반투명 0.5~1px |
| 커스텀 컨트롤로 시스템 컨트롤 대체 | 플랫폼 존중 원칙 |
| 콘텐츠 위를 덮는 장식 크롬 | Deference 위반 |

---

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

### 10-1. Tailwind CSS v4

```css
@import "tailwindcss";

@theme {
  --color-label:        #1d1d1f;
  --color-label-2:      rgb(60 60 67 / 0.6);
  --color-bg:           #ffffff;
  --color-bg-secondary: #f2f2f7;
  --color-separator:    rgb(60 60 67 / 0.29);
  --color-tint:         #007aff;
  --color-destructive:  #ff3b30;
  --radius-card:        0.75rem;
}

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

### 10-2. Tailwind CSS v3

```js
module.exports = {
  darkMode: 'class',
  theme: {
    extend: {
      colors: {
        label:       'var(--label)',
        'label-2':   'var(--label-secondary)',
        bg:          'var(--bg)',
        'bg-2':      'var(--bg-secondary)',
        'bg-3':      'var(--bg-tertiary)',
        separator:   'var(--separator)',
        tint:        'var(--tint)',
        destructive: 'var(--system-red)',
      },
      borderRadius: { card: '0.75rem' },
    },
  },
};
```

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

CSS 변수가 원천. 다크 전환은 `.dark` 토글 — 시스템 컬러 전용 값 전환까지 토큰이 처리한다.

---

## 11. 이식 가이드

### Step 1 — 시맨틱 토큰 복사

§2 라이트 + §7 다크 블록을 전역 CSS에 붙인다. 시스템 컬러 원시값도 함께.

### Step 2 — 시스템 폰트 스택 설정

`-apple-system` 스택 + Noto Sans KR 폴백 링크를 연결한다.

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

| 패턴 | 핵심 CSS |
|---|---|
| **그룹 리스트** | `--bg-secondary` 페이지 + `--bg-tertiary` 12px 라운드 그룹 + 반투명 separator |
| **틴트 텍스트 버튼** | `color: var(--tint); background: none` — 탭 시 `opacity: 0.3` |
| **44px 행** | `min-height: 2.75rem` + 라벨/값/셰브런 3열 구조 |

### Step 4 — Dynamic Type 검증

브라우저 글자 크기 200%에서 그룹 리스트가 깨지지 않는지 확인한다.

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

```
새 컴포넌트가 필요하다
  → 시스템 표준 컨트롤(리스트·세그먼트·시트)로 표현 가능한가?
    yes → 표준 사용
    no  → Clarity(읽히는가) / Deference(콘텐츠를 가리지 않는가) /
          Depth(계층이 자연스러운가) 3검증 통과 시 추가
  → 색이 필요한가?
    → 인터랙티브한가? → 틴트
    → 의미 전달인가? → 시스템 컬러 (red/green/orange)
    → 그 외 → label/fill/separator 뉴트럴만
```
