designpaca/packages/skill/references/color.md
Yun Chan 6805fb2be7 feat(skill): absorb external design skills, restore interview gate, add review route
- Restore the step-0 interview as a mechanical gate the skill explicitly
  depends on; add harness.md (per-harness question tools, limits,
  fallbacks) and brief-interview.md (slots, question cards, rounds).
- Add 10 reference docs absorbed from external design skills
  (accessibility, interaction-feel, elevation, color, icons, product-copy,
  component-systems, critique, change-review, print-email) and extend
  existing references.
- Add a review-only route and two hard-gate clauses (truncated content
  reachability, three-flashes limit).
- design-gate: split tap targets into WCAG 2.5.8 and 44px contract layers,
  run axe-core when available, and fix false positives found on a real
  site (decorative alt="", stacked wordmark line count, url-only pages).
- lint-skill: fail if the interview gate section or its links disappear.
- Ship agents/openai.yaml and THIRD_PARTY_NOTICES.md.
2026-09-24 13:26:03 +09:00

24 KiB

color — 색 체계 상세

3단계에서 tokens.md §2 의 역할 토큰(--surface·--surface-raised·--ink·--ink-muted·--line·--accent·--accent-ink)을 실제 값으로 채울 때 필요한 절만 연다. 역할 토큰이 정본이고 이 문서는 방법이다 — 여기서 새 역할을 만들거나 tokens.md의 규칙을 바꾸지 않는다. 이 문서는 그 역할에 어떤 값을 어떻게 채우는지, 다크모드·그라디언트·대비를 어떻게 다루는지를 다룬다.

이 문서를 읽는 법

상황 읽을 곳
역할 토큰에 채울 실제 색이 없다(새 시스템) §1~§3
여러 단계(램프)가 필요하다 §2
그라디언트를 쓴다 §4
다크모드를 만들거나 다듬는다 §5
대비가 실패했거나 대비 근거가 필요하다 §6
상태색·강조색의 의미와 로케일을 정한다 §7
표준 7개 역할 밖의 색(비활성·scrim 등)이 필요하다 §8
고채도 브랜드 색이 화면에서 탁하게 보인다 §9
리디자인에서 기존 팔레트를 정리한다 §10
값을 어떤 표기법(hex·oklch 등)으로 쓸지 모르겠다 §11
마무리 전 확인 §12

§0. 언제

색을 다루는 모든 순간이 아니라, 역할 토큰에 값을 채우는 3단계와 다크모드·그라디언트·리디자인처럼 별도 결정이 필요한 순간에만 연다. 브리프·기존 코드에 이미 정해진 색이 있으면 그것을 재사용하고 이 문서는 건너뛴다.

판정 위계는 이 문서 전체에서 세 층으로 나뉜다. 하드 게이트는 WCAG 2 대비처럼 협상 대상이 아닌 규범이다. 프로젝트 계약은 브리프·다크모드 지원 여부·특정 프레임워크 채택처럼 이 프로젝트가 선택하면 지키는 약속이다. 관찰 후보는 스타일 휴리스틱이며 시작값일 뿐 통과 기준이 아니다.


§1. 역할 우선과 선택적 원시값 계층

언제: 다중 hue 브랜드(강조색이 여러 개 필요)이거나 정밀한 다크모드 튜닝이 필요할 때만 연다.

tokens.md §2의 7개 역할 토큰은 대부분의 프로젝트에 충분한 시맨틱 계층이다. 시맨틱 토큰은 직무를 이름 짓고(--accent, --ink-muted) 컴포넌트가 참조하는 유일한 계층이다.

그 아래에 원시값(primitive) 계층을 둘지는 선택이다. 원시값은 값을 이름 짓고(--blue-500, --neutral-200) 컴포넌트에 절대 직접 쓰이지 않으며, 시맨틱 토큰이 그것을 가리킨다. 이 2계층 구조가 다크모드·화이트라벨 테마·증가-대비 변형을 가능하게 하는 이음매다 — 경계가 없으면 다크 모드를 만들 때마다 "이 파랑이 강조를 뜻했는지 그냥 파랑을 원했는지"를 모든 사용처에서 가려내야 한다 [SKILL-BETTER-COLORS].

:root {
  /* 원시값(1계층) — 값을 이름 짓는다. 컴포넌트에 직접 쓰지 않는다 */
  --blue-500: #3b82f6;
  --neutral-700: #374151;

  /* 시맨틱(2계층) — 직무를 이름 짓는다. tokens.md §2의 역할과 일치시킨다 */
  --accent: var(--blue-500);
  --ink-muted: var(--neutral-700);
}

단순 프로젝트에 원시값 계층을 강제하지 않는다. 다중 hue나 정밀 다크모드 튜닝이 필요 없으면 tokens.md의 7개 역할 토큰에 값을 직접 채우는 것으로 끝낸다 — 계층을 늘리는 것 자체가 목적이 아니다.


§2. 램프 생성

언제: 하나의 hue에서 여러 단계(호버·활성·옅은 배경·솔리드 필 등)가 동시에 필요할 때만 연다. 역할 토큰 하나에 값 하나면 이 절은 필요 없다.

잘 만든 램프는 네 가지 속성을 갖는다 [SKILL-BETTER-COLORS].

  1. 지각 명도 간격이 고르다. 포맷이 부르는 명도가 아니라 사람이 실제로 느끼는 명도로 계단진다 — HSL의 명도는 비지각적이라 고르게 벌린 HSL 값이 한쪽으로 뭉친다.
  2. hue가 끝까지 일정하다. 방황하는 hue는 두 색이 섞인 것처럼 읽힌다.
  3. 생생함(채도·명도의 지각적 강도)은 중간에서 정점을 찍고 양끝에서 떨어진다. 양끝까지 완전 채도를 유지하면 빛나는 밝은 끝과 잉크를 쏟은 듯한 어두운 끝이 된다.
  4. 밝은 끝일수록 스텝이 촘촘하다. 밝은 배경은 더 세밀한 구분이 필요하다 — 전 범위를 고르게 배치하면 옅은 끝의 두 표면(예: 페이지 배경과 카드 배경)이 구별되지 않는다.

관찰 후보 — 브랜드 색을 고정하는 두 방식. 계약상 정확히 지켜야 하는 브랜드 색은 핀(pin) — 그 값을 정확히 유지하고 램프가 그 주변에서 바깥으로 지어지며, 그 스텝만 약간 고르지 않게 배치된다. 그 외에는 스냅(snap) — 램프에 맞춰 모든 스텝을 고르게 배치한다. 스냅이 대개 더 고르게 보이고, 스와치를 나란히 대보지 않으면 차이가 잘 드러나지 않는다 [SKILL-BETTER-COLORS].

절대 손이나 눈으로 계산하지 않는다. 색 라이브러리(culori, colorjs.io, chroma.js 등)로 지각 공간에서 보간하고 프로젝트 표기법으로 출력한다 [SKILL-BETTER-COLORS].

import { formatHex, interpolate, samples } from 'culori'

// 지각적 보간. hex로 받아 hex로 낸다
const ramp = interpolate(['#eff6ff', '#3b82f6', '#172554'], 'lab')
const steps = samples(11).map((t) => formatHex(ramp(t)))

Tailwind 50-950 11스텝, Radix 1-12 12스텝 매핑은 그 체계를 이미 쓰는 프로젝트에서만 참조한다. 이 매핑을 새 프로젝트의 기본값으로 강제하지 않는다. 두 컨벤션은 번호가 아니라 종류가 다르다 — Radix는 스텝을 역할로 정의해 다크 스케일이 같은 번호를 재사용하는 별도 램프라 --accent-9가 라이트·다크 양쪽에서 "솔리드 필"을 뜻하지만, Tailwind는 스텝을 명도로 정의해(50=밝음, 950=어두움) 다크모드에서 매핑이 반전된다(페이지 배경이 950이 됨) [SKILL-BETTER-COLORS]. 양끝 모두 순수 검정·흰색에는 못 미치게 둔다 — 거기 닿는 순간 색이 페이지 배경이 사는 지점에서 정체성을 잃는다.


§3. OKLCH 파생

oklch(L C H) — 명도(L) 01, 채도(C) 0약 0.4, hue(H) 0~360, 알파는 /로 분리한다. 지각적으로 균일한 명도·안정적 hue·예측 가능한 램프가 장점이며, 2023년 5월부터 주요 브라우저에서 널리 지원된다(Baseline Widely) [WEB-BASELINE].

hue와 chroma를 고정하고 lightness만 움직이면 라이트·다크 쌍을 체계적으로 파생할 수 있다.

:root {
  /* hue(259)·chroma(0.19)는 고정, lightness만 움직인다 — 어두운 배경 위에서는 강조색을 밝게 올린다 */
  --accent-light: oklch(0.55 0.19 259);
  --accent-dark:  oklch(0.75 0.19 259);
}

진짜 새 색 시스템이면 oklch()가 최선의 기본값이다. 그 외에는 색 라이브러리로 프로젝트 고유 표기법에 맞춰 같은 연산을 한다 — 표기법 선택 자체는 §11을 따른다.

color-mix()는 상태용 색 파생(호버·비활성 등)에 유용하며 Baseline Widely다(2023년 5월부터) [WEB-BASELINE]. 다만 생성값이 토큰 계층 밖에 놓여 디자인 툴에서 검사할 수 없다는 한계가 있으므로, 반복해서 쓰이는 값이면 토큰으로 승격할지 판단한다. 상대 색 문법(oklch(from var(--x) calc(l - 0.1) c h))도 같은 종류로 강력하지만, 3중 이상 연쇄 파생은 읽을 수 없어진다 — 관찰 후보로 두고 체인이 길어지면 고정 값으로 되돌린다 [SKILL-BETTER-COLORS].


§4. 그라디언트 보간

언제: 실제로 그라디언트를 쓸 때만 연다.

기본값(아무것도 지정하지 않았을 때)인 sRGB 보간은 직선(rectangular) 공간이다. hue 휠에서 반대편에 있는 두 색 사이를 직선으로 잇기 때문에 그 직선이 중립축 근처를 지나며 중간 지점이 탁하고 어두운 회색으로 꺼진다(회색 데드존). oklab도 직선 보간이지만 지각적으로 균일한 밝기를 유지해 sRGB보다 낫다. oklch는 극좌표(polar) 공간이라 hue 각도를 돌아가며 보간해 생생함이 끝까지 유지되지만, 대신 두 스톱 사이의 모든 hue를 훑고 지나간다(예: 파랑→핑크가 보라를 거쳐 간다 — 의도한 룩일 수도, 서프라이즈일 수도 있다) [SKILL-BETTER-COLORS].

/* 기본값(sRGB): 지정 안 하면 이것 — 중간이 탁해진다 */
.a { background: linear-gradient(to right, #eff6ff, #3b82f6); }

/* 최선 기본값: 직선 보간이면서 균일한 밝기 */
.b { background: linear-gradient(in oklab, #eff6ff, #3b82f6); }

/* hue 휠을 도는 룩이 필요할 때 */
.c { background: linear-gradient(in oklch longer hue, #eff6ff, #3b82f6); }

그라디언트 보간 공간 지정 문법은 Baseline Newly available이다(2024년 6월 기준, Firefox가 마지막으로 지원을 완료) — 아직 Widely에는 이르지 않았으므로 지정하지 않았을 때의 기본 sRGB 결과가 허용 가능한지 확인하거나 @supports 폴백을 둔다 [WEB-BASELINE].

밴딩은 스톱 간 대비가 낮은 넓은 영역에서 8비트 디스플레이의 계단이 드러나는 현상이다. 대비를 넓히거나 영역을 줄이거나 미세한 노이즈 텍스처를 얹는다. shorter hue/longer hue 키워드로 oklch 보간이 도는 방향을 고를 수 있다.


§5. 다크모드 재조정과 전환 메커니즘

언제: 프로젝트가 다크모드를 지원하기로 했을 때 연다. tokens.md §2는 "다크는 반전이 아니라 역할별 재정의"라고 이미 선언한다 — 이 절은 그 재정의를 실행하는 구체 체크리스트다.

반전은 출발점이지 결과물이 아니다. 라이트 팔레트를 기계적으로 뒤집은 뒤, 거의 항상 아래 세 가지를 수동으로 다듬어야 한다 [SKILL-BETTER-COLORS]. 이는 프로젝트 계약 — 다크모드를 지원하기로 했다면 지킨다.

  1. 생생함을 낮춘다. 흰 배경 위에서 자신감 있게 읽히던 색이 거의 검정 위에서는 네온으로 읽힌다. 다크 외형에서는 강조색을 1~2스텝 덜 생생하게 조정한다.
  2. 어두운 끝을 분리한다. 옅은 배경에서 구분되던 스텝이 어두운 표면에서는 서로 뭉개진다. 어두운 끝에 스텝을 더 둔다.
  3. 대비 비대칭을 재검사한다. 대비는 거울상이 아니다 — 라이트에서 통과한 쌍이 반전되면 실패할 수 있다. 두 외형 모두 실제 렌더 배경에 대해 전경을 다시 검사한다.

전환 메커니즘은 하나를 고르고 전체에 쓴다. 메커니즘을 섞는 것이 흔한 실패다 — 일부 토큰은 미디어쿼리로, 다른 토큰은 클래스로 설정하면 사용자가 시스템 선호를 오버라이드하는 순간 반쯤만 테마된 인터페이스가 된다 [SKILL-BETTER-COLORS].

메커니즘 맞는 상황 주의
prefers-color-scheme 단독 테마 토글 UI가 없을 때 persist·hydrate할 상태가 없어야 성립한다
.dark 클래스 사용자가 시스템 설정을 오버라이드할 수 있을 때 미디어쿼리는 초깃값만 정하고, 클래스가 최종 결정이다
light-dark() color-scheme도 함께 선언하는 프로젝트 클래스 기반 토글이라도 color-scheme 속성을 함께 갱신해야 값이 반영된다. Baseline Newly available(2024년 5월 기준, 아직 Widely 아님)이므로 지원 범위를 확인한다 [WEB-BASELINE]
:root {
  color-scheme: light dark;
  --surface: light-dark(#fbfaf8, #14130f);
  --ink:     light-dark(#1a1917, #e8e4dc);
}

테마 전환 순간 색·배경·테두리·그림자가 동시에 바뀌어 뭉개지는(smear) 것을 막는 전환 억제 레시피는 구현 기법이므로 motion.md를 따른다 — 이 문서에서는 값만 다룬다.


§6. 대비

하드 게이트: WCAG 2 대비. 일반 텍스트(24px 미만, bold 18.5px 미만) AA 4.5:1, 큰 텍스트(24px 이상, bold 18.5px 이상) AA 3:1 [WCAG-READ]. UI 컴포넌트와 그래픽 객체는 인접 색과 3:1 — 비활성 컴포넌트, 필수 로고·브랜드 마크, 장식용 그래픽, 텍스트 대체물이 있는 그래픽은 예외다 [WCAG-NONTEXT]. 이 수치는 협상 대상이 아니다.

수정 절차: 명도를 먼저 바꾼다. 대비가 실제로 반응하는 채널은 명도다 — hue와 채도는 측정값을 훨씬 덜 움직이므로, hue를 바꿔 대비를 고치려는 시도는 대체로 헛수고다. hue·채도를 고정한 채 전경을 배경에서 지각적으로 더 멀리 옮기고 재측정한다. hue를 고정하는 이유는 "대비 수정"이 조용히 "팔레트 변경"이 되는 것을 막기 위해서다 [SKILL-BETTER-COLORS]. APCA 기준으로는 지각 명도 약 75% 안팎 배경에서 순수 검정도 Lc 60 안팎에 그친다[SKILL-BETTER-COLORS] — WCAG 2 비율로는 이 배경에서 검정 텍스트가 여유 있게 통과하므로 두 척도를 섞지 않는다. WCAG 2 기준으로 흑·백 어느 전경도 여유가 적은 구간은 중간 회색(CIELAB L* 약 50 부근, 최대 약 4.6:1)이며, 그런 배경에서는 전경보다 배경을 바꾸는 편이 낫다. 명도를 밀면 갬멀을 벗어날 수 있으니 렌더 가능하도록 채도를 함께 낮춘다. 값을 바꾼 뒤에는 항상 재측정한다 — 고쳐졌다고 가정하지 않는다.

APCA는 규범이 아니라 보조 진단이다. 2026년 9월 확인 기준 WCAG 3 초안 본문은 대비 알고리즘 자체를 아직 정하지 않았고(APCA라는 이름조차 명시되어 있지 않다), APCA 자체 문서도 스스로를 "beta"로 표시하며 미래 표준의 평가 후보일 뿐이라고 밝힌다 [APCA-STATUS]. 그래서 designpaca는 WCAG 2 비율을 대비의 하드 게이트로 유지한다. APCA는 "라이트 모드에서 통과한 쌍이 다크 모드에서 실패하는가" 같은 추가 신호가 필요할 때만 보조로 참고한다. 쓴다면 본문 텍스트는 Lc 75(선호 90), 라벨·헤드라인 같은 비본문은 Lc 60(선호 75)을 시작값으로 둔다 — 실측 조정 [SKILL-BETTER-COLORS].

렌더 타임 계산값은 렌더된 결과를 측정한다. color-mix(), 상대 색 문법, light-dark()는 모두 렌더 타임에 해석되므로 선언값이 아니라 실제 렌더 결과를 측정해야 한다. backdrop-filter가 걸린 표면은 뒤로 스크롤되는 콘텐츠에 따라 실효 색이 바뀌므로, 가장 밝은·가장 어두운 콘텐츠에서 테스트하거나 표면을 충분히 불투명하게 만든다 [SKILL-BETTER-COLORS].


§7. 의미와 상태색

시맨틱 색을 비파괴 액션에 쓰지 않는다. 상태색(danger, success 등)은 그 상태를 실제로 표시하는 곳에만 쓴다. 삭제 같은 파괴적 행동이 아닌 일반 강조에 danger 색을 빌려 쓰면 사용자가 실제로 위험한 것으로 오독한다. 프로젝트 계약: 하나의 색은 하나의 의미만 진다 — hue 15도 이내는 같은 색으로 취급하므로, 강조색이 "인터랙티브"를 뜻하면 그 hue가 정적 텍스트에 쓰이는 순간 클릭 불가능한 것을 클릭하라고 말하는 셈이다 [SKILL-BETTER-COLORS].

뷰당 채색된 주요 액션은 하나다. 채운 색이 주요 강조를 인코딩할 때는 뷰당 주 행동 하나만 색을 채우고 나머지는 중성으로 둔다. 색은 배경에 올리지 라벨에 올리지 않는다 — 채운 버튼은 방 건너편에서도 주요 행동으로 읽히지만, 중성 버튼 위 강조색 텍스트는 링크로 읽힌다. 서로 다른 상태·카테고리를 인코딩하는 경우라면 여러 색 배경도 괜찮다 [SKILL-BETTER-COLORS]. 프로젝트 계약.

색만으로 의미를 전달하지 않는다. 이 규칙 자체(비색각 사용자·회색조 인쇄를 위한 아이콘·라벨 병기)는 하드 게이트이며 정본은 accessibility.md다.

문화적 의미. 색은 문화마다 다르게 읽힌다. 서구 관행에서 빨강=위험·손실, 초록=성공·이익이라는 연상이 흔히 쓰이지만, 중국어권 금융 UI는 반대로 상승을 빨강, 하락을 초록으로 표시한다 [SKILL-BETTER-COLORS]. 한국 증권 화면의 "빨강=상승" 관행도 이번 조사에서 한국거래소 등의 1차 공식 규정을 찾지 못했다 — 국제 표준이 아니라 시장 관행일 가능성이 높다. 그러므로 손익·상태처럼 문화적으로 뒤집힐 수 있는 색은 하드코딩하지 않고, 데이터 제공자(증권사·거래소 API)와 브리프가 실제로 쓰는 관례를 확인해 로케일별 토큰으로 둔다. 확인하지 못한 관행을 확인된 사실처럼 쓰지 않는다.


§8. 역할 확장 목록

언제: 필요할 때만 연다. tokens.md §2의 7개 역할이 최소 집합이며 기본값이다. 컴포넌트가 요구할 때마다 무분별하게 역할을 추가하면 팔레트가 맨 처음 만든 화면의 모양으로 굳는다 — 실제로 그 역할을 렌더하는 화면이 생겼을 때만 아래에서 골라 추가한다.

확장 역할 용도 위계
비활성 텍스트(disabled) 조작 불가 상태의 라벨·값 프로젝트 계약 — 대비는 충분히 유지하되 활성 상태처럼 읽혀서는 안 된다
반전(inverse) 어두운/밝은 표면 위에 반대 톤으로 놓이는 텍스트 프로젝트 계약
on-accent 강조 배경 위 텍스트·아이콘(--accent-ink와 별도 구분이 필요할 때) 프로젝트 계약
sunken 입력창·웰처럼 표면보다 가라앉아 보이는 배경 관찰 후보
scrim 모달·오버레이 뒤에 어둡게 깔리는 층 프로젝트 계약
포커스 링 키보드 포커스 표시 인접 색과 3:1 이상 — 하드 게이트, 정본은 accessibility.md
separator vs border 구분선(콘텐츠를 나눔) vs 테두리(컨트롤을 둘러쌈) 관찰 후보 — 오늘 값이 같아도 역할은 분리해 둔다. 입력창을 재스타일링하는 순간 둘이 갈라진다 [SKILL-BETTER-COLORS]

이 목록은 역할 재고이지 강제 목록이 아니다. tokens.md §2의 "역할에 토큰이 없으면 토큰을 추가한다"는 원칙을 그대로 따르되, 추가할 이름을 고를 때 여기서 고른다.


§9. 넓은 색역 — P3

언제: 고채도 브랜드 색이 화면에서 탁하거나 밋밋해 보일 때만 연다(점진적 향상).

모든 sRGB 색은 Display P3 색역 안에 있지만 역은 성립하지 않는다. P3는 sRGB보다 약 50% 더 많은 색을 커버하며, 그 차이는 가장 채도 높은 값에서만 의미가 있다 — 최대 생생함의 60% 이하인 색은 양쪽 색역에서 똑같아 보인다 [SKILL-BETTER-COLORS].

순서가 중요하다. sRGB 값을 먼저 선언하고, @media (color-gamut: p3) 안에서 더 채도 높은 P3 값으로 오버라이드한다.

:root {
  --accent: #3b82f6; /* sRGB 먼저 */
}
@media (color-gamut: p3) {
  :root {
    --accent: color(display-p3 0.28 0.52 0.95);
  }
}

클리핑은 우아하지 않다. sRGB로 표시 못 하는 P3 값을 지원 안 하는 디스플레이에 그대로 보내면 이웃 스텝들을 하나의 렌더 색으로 뭉갠다 — 최대 생생함은 hue마다 달라서(시안이 빨강·보라보다 훨씬 낮다) 일부 스텝에서만 클리핑이 일어나 램프가 고르지 않게 무너진다. 프로젝트 계약 — P3 값을 쓰면 sRGB 폴백을 먼저 선언한다. 폴백 없이는 우아하게 저하되지 않고 램프가 무너진다 [SKILL-BETTER-COLORS].


§10. 기존 팔레트 감사 5단계

언제: 리디자인에서 팔레트를 재구조화하기 전에 연다.

  1. 모든 리터럴을 수집한다. hex, rgb(, hsl(, oklch(, 프로젝트 유틸리티 클래스 접두어를 grep한다. 스타일시트뿐 아니라 SVG fill/stroke, 차트 설정, 이메일 템플릿까지 포함한다 — 색은 스타일시트 밖에도 숨는다.
  2. 각 hue 계열 안에서 지각된 명도로 정렬한다. 근접 중복이 이웃으로 즉시 드러난다.
  3. 근접 중복을 합친다. 대략 1램프 스텝보다 가까운 두 색은 드리프트한 하나의 색이다 — 가장 많이 쓰인 값을 남기고 나머지는 폐기한다. 절대 평균 내지 않는다.
  4. 생존자마다 §8의 역할을 배정한다. 어떤 역할과도 맞지 않는 색은 누락된 토큰이거나 실수다 — 어느 쪽인지 정해 finding에 적는다.
  5. 역할당 램프가 1개를 넘는지 센다. 넘는다면 팔레트가 구조를 벗어난 것이지 제품에 색이 더 필요한 게 아니다.

[SKILL-BETTER-COLORS]

아무것도 바꾸기 전에 인벤토리부터 보고한다. 팔레트 통합은 아무도 건드리라 하지 않은 화면의 렌더 결과까지 바꾸므로, 사용자가 수락할 때까지는 제안으로 남긴다.


§11. 표기법은 프로젝트를 따른다

프로젝트가 이미 쓰는 표기법을 재사용한다. hex를 쓰는 프로젝트가 잘못하고 있는 게 아니다 — 값 하나 고치려고 두 번째 표기법을 더하지 않는다. hex와 oklch()가 섞인 것보다 일관된 hex 체계가 낫다 [SKILL-BETTER-COLORS].

변환은 다음 세 경우에만 한다. 사용자가 요청했을 때, 합의된 마이그레이션이 스코프일 때, 프로젝트가 표기법을 표준화하는 중이고 이 값이 낙오자일 때. 이 문서가 열렸다는 이유만으로 변환하지 않는다.

변환 스코프 안에서도 CSS 키워드(currentColor, inherit, transparent, initial, unset)는 그대로 두고, 그라디언트 함수는 색 스톱만 바꾸고 보간 방식은 건드리지 않는다. 대량 변환은 정리(cleanup)가 아니라 마이그레이션이다 — 렌더된 모든 색을 반올림 오차만큼 바꾸고 아무도 요청하지 않은 파일까지 건드리므로, 부수효과가 아니라 그 자체가 별도 작업이어야 한다 [SKILL-BETTER-COLORS].


§12. 체크리스트

  • tokens.md §2의 역할 토큰이 먼저 채워져 있다. 원시값 계층은 다중 hue·정밀 다크모드가 실제로 필요할 때만 추가했다.
  • 라이트·다크 두 외형 모두 실제 렌더 배경에 대해 대비를 측정했다(WCAG 2, 하드 게이트).
  • 대비를 고쳤다면 명도를 먼저 바꾸고 hue를 고정했으며, 값을 바꾼 뒤 재측정했다.
  • 그라디언트를 썼다면 보간 공간을 의도적으로 골랐고, Newly available 문법에는 결과가 허용 가능한 기본 sRGB 폴백이 있다.
  • 다크모드를 반전이 아니라 재조정했다(생생함 낮추기·어두운 끝 분리·대비 비대칭 재검사 3항목).
  • 전환 메커니즘을 하나만 골라 전체에 썼다(미디어쿼리·클래스·light-dark() 혼용 없음).
  • 상태색·강조색이 하나의 색=하나의 의미를 지킨다. 뷰당 채색된 주요 액션이 하나다.
  • 색만으로 의미를 전달하는 곳이 없다(accessibility.md).
  • 손익·상태처럼 문화적으로 뒤집힐 수 있는 색은 데이터 제공자·브리프의 실제 관례를 확인했다(지어내지 않았다).
  • P3를 썼다면 sRGB 폴백이 먼저 선언돼 있다.
  • 리디자인이면 기존 팔레트를 5단계로 감사해 인벤토리를 먼저 보고했다.
  • 표기법은 프로젝트 것을 따랐고, 이 문서를 열었다는 이유만으로 값을 변환하지 않았다.