# 사용 규칙

모든 규칙에 번호가 있다. 인용할 때는 번호(예: C4)를 쓴다.

## 색 조합

색은 이름(토큰)으로만 쓰고, 이름이 가진 의미를 지킨다.

| 번호 | 규칙 | 이유와 값 |
| --- | --- | --- |
| C1 | 화면 바탕은 `bg`, 대시보드형 화면은 `canvas`를 깐다. 그 위의 면은 `surface`다. 면 위에 면을 겹칠 때는 `well`이나 `card`를 쓴다. | 한 화면의 면 색은 3단계(바탕 → 면 → 홈) 이하로 한다. |
| C2 | 글자는 본문 `text`, 보조 `textSecondary`, 입력 안내 문구 `textTertiary`로 나눈다. 읽어야 하는 내용에 `textTertiary`를 쓰지 않는다. | `textTertiary`는 흰 면에서 대비가 약하다(색상 페이지의 대비 표). |
| C3 | `primary`는 행동과 선택 표시에만 쓴다. 한 화면에서 `primary`로 채운 큰 면은 1개(주 버튼)까지다. | 파란색(초록색)이 여러 곳에 있으면 무엇이 주 행동인지 알 수 없다. |
| C4 | 색이 채워진 면 위의 글자는 짝을 지킨다: `gradient`·`primaryStrong` 위는 `onPrimaryStrong`, `primary` 위는 `onPrimary`, `danger` 위는 `onDanger`, `successSoft` 위는 `successText`, `amberSoft` 위는 `amberText`, `dangerSoft` 위는 `danger`. | 짝이 맞아야 라이트·다크와 두 서비스 모두에서 글자가 읽힌다. |
| C5 | 상태 색의 뜻은 고정이다. `success`는 정답과 완료, `danger`는 오류·오답·삭제, `amber`는 주의와 추천, `primary`는 선택과 행동이다. 선택한 보기를 `success` 색으로 칠하지 않는다. | `OptionRow`는 선택 전 `primary`, 채점 뒤 정답 `success`, 오답 `danger`로 뜻을 나눈다. |
| C6 | 과목 색은 과목을 구분하는 작은 표식(아이콘 타일, 점, 막대)에만 쓴다. 과목 이름을 글자로 항상 함께 보여 준다. | 색만으로 과목을 알아보기 어려운 사용자가 있다. |
| C7 | 색만으로 상태를 알리지 않는다. 정답은 `success` 색 + 체크 아이콘 + "정답!" 글자를 함께 쓴다. | 색을 구분하기 어려운 사용자와 Morit(성공과 주색이 같은 초록)을 위해서다. |
| C8 | 코드에 HEX 값을 직접 쓰지 않는다. 반투명이 필요하면 `withAlpha(토큰, 투명도)`를 쓴다. | 서비스와 라이트·다크가 바뀌면 직접 쓴 HEX는 바뀌지 않는다. |

## 간격

간격 9단계 값만 쓰고, 묶음 안은 좁게 묶음 사이는 넓게 띄운다.

| 번호 | 규칙 | 이유와 값 |
| --- | --- | --- |
| S1 | 간격은 `xxs`(2) ~ `xxxl`(40) 9단계 값만 쓴다. 표에 없는 숫자(10, 14, 18 등)를 간격으로 쓰지 않는다. | 값이 정해져 있어야 화면끼리 리듬이 맞는다. |
| S2 | 화면의 좌우 여백은 `gutter`(20)다. 한 화면의 모든 요소가 같은 왼쪽 선에서 시작한다. | `Screen`이 20을 자동으로 넣는다. |
| S3 | 묶음 안의 간격은 묶음 사이의 간격보다 작다. 예: 묶음 안 8(`sm`) 또는 12(`md`), 묶음 사이 24(`xl`) 이상. | 간격 차이가 눈으로 묶음을 나눈다. |
| S4 | 섹션 제목은 위 간격이 아래 간격보다 크다. `SectionTitle`은 위 24, 아래 12다. | 제목이 아래 내용에 속한다는 것이 보인다. |
| S5 | 이웃한 눌림 요소 사이는 8 이상 띄운다. | `hitSlop`(사방 10)으로 넓힌 눌림 영역이 겹치지 않게 한다. |
| S6 | 카드 안쪽 여백은 `Card` 16, `Panel` 18이다. 안쪽 여백을 카드마다 다르게 하지 않는다. | 같은 종류의 면은 같은 여백을 가진다. |

## 정렬

왼쪽 정렬이 기본이다. 가운데 정렬은 정해진 경우에만 쓴다.

| 번호 | 규칙 | 이유와 값 |
| --- | --- | --- |
| A1 | 글자는 왼쪽 정렬이 기본이다. 가운데 정렬은 빈 화면(`EmptyState`)의 제목과 설명, 버튼·탭 안의 글자, 숫자 하나만 놓인 칸에만 쓴다. | 여러 줄 글자를 가운데 정렬하면 읽는 시작점이 줄마다 달라진다. |
| A2 | 목록 행은 앞(아이콘 타일) · 가운데(제목과 보조 줄, 남는 폭 전부) · 뒤(값, 화살표) 순서다. 뒤쪽 요소는 오른쪽 끝에 맞춘다. | `WellRow`, `SettingsRow`가 이 구조다. |
| A3 | 표와 차트의 숫자는 오른쪽 끝에 맞추고 단위를 붙여 쓴다. | 자릿수가 맞아 크기를 비교하기 쉽다. |
| A4 | 화면 아래에 고정하는 주 버튼은 폭을 가득 채우고(좌우 `gutter`), `Screen`의 `footer`에 넣는다. | 엄지가 닿는 위치에 하나뿐인 주 행동이 있다. |
| A5 | 아이콘과 글자는 세로 가운데로 맞춘다. 사이 간격은 버튼 안 6, 행 안 8~12다. | `PrimaryButton`은 6, `WellRow`는 12를 쓴다. |
| A6 | 웹에서 긴 글의 한 줄은 약 46rem(736px) 이하로 한다. 한글은 65~75자 안이다. | 줄이 너무 길면 다음 줄의 시작을 찾기 어렵다. |

## 글자

글자 스타일은 11종 중에서만 고른다.

| 번호 | 규칙 | 이유와 값 |
| --- | --- | --- |
| T1 | 한 화면에서 글자 스타일은 3~4종만 쓴다. | 제목, 본문, 보조만으로 위계가 충분하다. |
| T2 | 화면 제목은 `title`, 카드 제목은 `headline`, 본문은 `body`, 보조 줄은 `small` 또는 `caption`이다. | 글자 스타일 페이지의 "용도" 열과 같다. |
| T3 | 문제 본문, 보기, 해설은 줄을 자르지 않는다(`numberOfLines`를 쓰지 않는다). 목록 행의 제목만 1~2줄로 자른다. | 잘린 문제는 풀 수 없다. |
| T4 | 버튼 글자는 한 줄이다. 길면 80%까지 줄이고, 그래도 안 들어가면 글자를 짧게 고친다. | `PrimaryButton`은 `minimumFontScale` 0.8을 쓴다. |
| T5 | 글자 스타일 밖의 크기를 쓰려면 줄 높이도 함께 지정한다. | 줄 높이가 모자라면 글자의 아래쪽이 잘린다. |
| T6 | 한국어 글은 단어 중간에서 줄을 바꾸지 않는다. 앱은 `keepWords()`, 웹은 `word-break: keep-all`을 쓴다. | Android는 "무엇인가/요?"처럼 단어를 쪼갠다. |

## 행동과 버튼

화면마다 가장 중요한 행동이 하나이고, 나머지는 무게를 낮춘다.

| 번호 | 규칙 | 이유와 값 |
| --- | --- | --- |
| B1 | 한 화면(또는 한 시트)에 `PrimaryButton`은 1개다. | 주 행동이 둘이면 사용자가 고르지 못한다. |
| B2 | 행동의 무게는 `PrimaryButton` > `SecondaryButton` > `TextButton` 순서다. 두 번째 행동은 `SecondaryButton`, 선택 행동("나중에")은 `TextButton`이다. | 무게 차이가 중요도 차이를 보여 준다. |
| B3 | 되돌릴 수 없는 행동(삭제, 탈퇴)은 `dialog.confirm`을 `tone: "danger"`로 호출해 한 번 더 묻는다. 대화상자에 무엇이 사라지는지 적는다. | 실수로 누른 삭제를 막는다. |
| B4 | 결과를 기다리는 동안은 `busy`, 누를 수 없는 이유가 있으면 `disabled`와 함께 이유를 글자로 알린다. | 이유 없는 비활성 버튼은 고장으로 보인다. |
| B5 | 아이콘만 있는 버튼에는 `label`을 반드시 쓴다. | 화면 읽기 프로그램이 이름을 읽는다. |

## 모양

모서리와 그림자는 면의 종류를 나타낸다.

| 번호 | 규칙 | 이유와 값 |
| --- | --- | --- |
| R1 | 시트와 대화상자는 `sheet`(24), 카드는 `card`(20) 또는 `lg`(16), 입력 칸은 `md`(12), 짧은 눌림 요소만 `pill`이다. | 큰 면을 알약으로 만들지 않는다. |
| R2 | 그림자는 기본 없음이다. 카드와 버튼은 `shadow(1)`, 떠 있는 요소는 `shadow(2)`, 대화상자는 `shadow(3)`만 쓴다. | 면 구분은 먼저 배경색 차이와 1px 선으로 한다. |
| R3 | 카드 안에 카드를 넣지 않는다. 카드(패널) 안의 묶음은 `well`(홈)이나 구분선으로 나눈다. | `Panel` 안에서 `WellRow`가 하는 일이다. |
| R4 | 목록의 행마다 그림자를 주지 않는다. | 행이 많으면 그림자가 화면을 어지럽힌다. |
| R5 | 기본 테두리는 1px `line`이다. 선택된 항목은 `primary` 테두리 1.2~1.8px을 쓴다. | `ChoiceCard`는 선택 전 1.2, 선택 후 1.8이다. |

## 접근성

누구나 읽고 누를 수 있어야 한다.

| 번호 | 규칙 | 이유와 값 |
| --- | --- | --- |
| X1 | 작은 글자는 바탕과 4.5:1 이상, 큰 글자(굵은 18.66px 이상)는 3:1 이상이다. | 색상 페이지의 "글자 색 대비" 표에서 서비스와 모드별로 확인한다. 웹에서는 `textSecondaryInk`, `primaryInk`를 쓴다. |
| X2 | 눌리는 영역은 48 × 48 이상을 목표로 한다. 보이는 크기가 작으면 `hitSlop`이나 주변 여백으로 채운다. | 손끝이 눌리는 영역보다 크다. |
| X3 | 눌리는 요소에는 역할(`accessibilityRole`), 이름(`accessibilityLabel` 또는 안의 글자), 상태(`accessibilityState`)를 지정한다. | 화면 읽기 프로그램이 "버튼, 저장, 사용할 수 없음"처럼 읽는다. |
| X4 | 글자 크기 1.24배(앱 설정)와 시스템 설정 최대 1.6배에서도 글자가 잘리지 않게 한다. 높이는 고정하지 않고 `minHeight`를 쓴다. | `Field`, `WellRow`는 `minHeight`다. |
| X5 | 상태는 색 + 아이콘 + 글자를 함께 쓴다. | C7과 같다. |
| X6 | 웹에서는 모든 조작을 키보드로 할 수 있게 하고, 포커스 링(2.5px 실선, 3px 띄움, `primaryInk` 색)을 지운 채로 두지 않는다. `prefers-reduced-motion`을 지킨다. | 앱에는 포커스 표시가 없으므로 웹에서 새로 그린다. |
| X7 | 사진과 그림에는 대체 글(`alt`, `accessibilityLabel`)을 쓴다. 장식 아이콘은 읽지 않게 숨긴다. | `ImageBlock`은 `alt`를 접근성 이름으로 쓴다. |

## 서비스 색 전환

서비스가 달라도 같은 코드를 쓰고 색 값만 바꾼다.

| 번호 | 규칙 | 이유와 값 |
| --- | --- | --- |
| V1 | 색은 토큰 이름으로만 쓴다. 코드에서 `if (service === "morit")`처럼 서비스를 보고 색을 고르지 않는다. | 서비스가 늘어도 코드를 고치지 않게 한다. |
| V2 | 색 말고는 서비스별로 바꾸지 않는다. 간격, 글자, 모서리, 그림자, 모션은 모든 서비스에서 같다. | 화면이 같은 시스템에서 나왔다는 것이 보여야 한다. |
| V3 | 새 색이 필요하면 모든 서비스의 라이트·다크 값을 함께 추가한다. | 한 서비스에만 값이 있으면 다른 서비스 화면이 깨진다. |
| V4 | Morit에서는 `success`와 `primary`가 같은 초록이다. 성공은 항상 체크 아이콘과 글자를 함께 쓴다. | 색으로 성공과 선택을 구분할 수 없다. |
| V5 | 화면을 만든 뒤 서비스 2개 × 모드 2개(라이트·다크), 모두 4가지 조합에서 확인한다. | 한 조합에서만 읽히는 색을 막는다. |

## 문구

앱의 문장은 짧고 구체적으로 쓴다.

| 번호 | 규칙 | 이유와 값 |
| --- | --- | --- |
| W1 | 문장은 해요체로 쓰고, 한 문장에 한 가지 내용만 담는다. | 앱의 문구("거절했어요", "다시 가입할 수 있어요")가 이 말투다. |
| W2 | 버튼 글자는 행동의 이름이다. "저장", "다음으로", "지금 풀기"처럼 쓴다. "확인"은 알림을 닫을 때만 쓴다. | 버튼만 읽어도 무슨 일이 일어나는지 알아야 한다. |
| W3 | 오류 문구는 무엇이 문제인지와 다음에 할 일을 함께 쓴다. | 문제만 알리면 사용자가 멈춘다. |
| W4 | 숫자에는 단위를 붙여 쓴다. "12문제", "약 3분", "D-24". | 숫자만 있으면 무엇의 수인지 알 수 없다. |

