임동욱 임동욱 08-12
docs: @fox 전반의 주석 축약
설명이 길거나 코드를 그대로 옮겨 적은 주석을 걷어내고, 코드만 봐서는
알 수 없는 이유(선언 원문을 쓰는 근거, next/image를 피하는 이유,
:disabled 특이도, 토큰 아닌 값의 승인 근거)만 남긴다.

Co-Authored-By: Claude Opus 5 
@229df213c6fd9f068da1ebc0242261aa4e9c8aee
@fox/core/components/fox-button/fox-button.tsx
--- @fox/core/components/fox-button/fox-button.tsx
+++ @fox/core/components/fox-button/fox-button.tsx
@@ -7,25 +7,20 @@
 export type FoxButtonSize = "lg" | "md" | "sm" | "xsm";
 
 export interface FoxButtonProps {
-  /** 시각 계열. 디자인은 Figma 시안(node 390-439) 기준으로 추후 적용한다. */
   type?: FoxButtonType;
   size: FoxButtonSize;
-  /** 네이티브 `type` 속성. prop 이름의 `type`이 시각 계열을 쓰므로 분리했다. */
+  /** 네이티브 `type` — prop의 `type`이 시각 계열을 쓰므로 분리했다. */
   htmlType?: "button" | "submit" | "reset";
-  /** 배치(마진·그리드) 조정용. 디자인 값 주입은 금지 — 모양이 달라야 하면 `type`을 추가한다. */
+  /** 배치 조정용. 모양이 달라야 하면 여기 말고 `type`을 추가한다. */
   className?: string;
-  /**
-   * 아이콘 엘리먼트. 계열별 색은 슬롯이 `color`로 내려주므로 **`currentColor`로 그린
-   * SVG**를 넣어야 시안대로 물든다(primary는 흰색, secondary는 파랑 …).
-   * 크기는 슬롯이 `form-icon-*` 토큰으로 정하므로 아이콘 자체에 크기를 두지 않아도 된다.
-   */
+  /** `currentColor`로 그린 SVG여야 계열별 색이 적용된다. 크기는 슬롯이 정한다. */
   leadingIcon?: ReactNode;
   trailingIcon?: ReactNode;
   label: string;
   disabled?: boolean;
-  /** 참이면 아무것도 렌더하지 않는다(DOM에 남지 않는다). */
+  /** 참이면 렌더하지 않는다(DOM에 남지 않는다). */
   hidden?: boolean;
-  /** 호출부가 소유하는 상태다 — 버튼은 이 값을 읽기만 하고 스스로 켜지 않는다. */
+  /** 호출부가 소유한다 — 버튼이 스스로 켜지 않는다. */
   loading?: boolean;
   fullWidth?: boolean;
   onAction?: () => void;
@@ -34,13 +29,7 @@
   ref?: Ref<HTMLButtonElement>;
 }
 
-/**
- * 클래스명은 `@fox/styles/_fox-button.scss`의 BEM 이름을 그대로 쓴다 — CSS Modules로
- * 감싸지 않는 이유는 이 스타일이 React 밖에서도 쓰여야 하기 때문이다. 이름이 `fox-`
- * 접두사로 전역 유일해서 스코프가 필요 없다.
- *
- * variant마다 `Record`로 고정해 계열을 추가하면 항목 누락이 타입 에러가 되게 한다.
- */
+/** `Record`로 고정해 계열을 추가하면 항목 누락이 타입 에러가 되게 한다. */
 const TYPE_CLASS: Record<FoxButtonType, string> = {
   primary: "fox-button--primary",
   secondary: "fox-button--secondary",
@@ -56,17 +45,10 @@
 };
 
 /**
- * @fox 공용 버튼.
- *
- * 상태를 갖지 않는 프레젠테이션 컴포넌트다 — `loading`·`disabled`는 호출부가 소유하고
- * 버튼은 그에 따라 상호작용을 막기만 한다. 버튼이 스스로 로딩을 켜면 호출부의 상태와
- * 어긋날 수 있어 그 책임을 지지 않는다.
- *
- * 모양은 Figma 시안(관리자페이지 node 390:439)을 토큰으로만 옮긴 것이며 규칙은
- * `@fox/styles/_fox-button.scss`에 있다. `error` 계열만 시안 미정이라 비어 있다.
+ * @fox 공용 버튼. 상태를 갖지 않는다.
  *
  * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
- * (또는 `@use "@fox/styles/fox-button"`)로 한 번 불러와야 한다.
+ * (또는 개별 파티셜)로 한 번 불러와야 한다.
  */
 export function FoxButton({
   type = "default",
@@ -88,7 +70,7 @@
     return null;
   }
 
-  // 로딩 중에도 클릭을 막아야 같은 요청이 두 번 나가지 않는다.
+  // 같은 요청이 두 번 나가지 않게 로딩 중에도 막는다.
   const inactive = disabled || loading;
 
   return (
@@ -109,8 +91,7 @@
       onMouseLeave={onHoverChange ? () => onHoverChange(false) : undefined}
     >
       {loading ? (
-        // 스피너 비주얼은 시안에 없어 자리만 잡아둔다. 아이콘과 같은 크기를 차지하므로
-        // 로딩으로 바뀔 때 버튼 폭이 흔들리지 않는다.
+        // 스피너 비주얼은 시안 미정. 아이콘과 같은 크기라 전환 시 폭이 흔들리지 않는다.
         <span className="fox-button__spinner" aria-hidden="true" />
       ) : (
         leadingIcon && (
@fox/dev-test/component-registry.tsx
--- @fox/dev-test/component-registry.tsx
+++ @fox/dev-test/component-registry.tsx
@@ -1,26 +1,16 @@
 import type { ReactNode } from "react";
 import { FoxButton } from "../core/components/fox-button";
 
-/**
- * 컴포넌트 예제 하나. 사이드바의 "컴포넌트" 분류에 항목으로 뜬다.
- */
 export interface ComponentExample {
-  /** 해시 링크와 React key에 쓰이는 식별자. kebab-case. */
+  /** 해시 링크에 쓰이는 kebab-case 식별자. */
   id: string;
-  /** 사이드바에 표시할 이름. */
   name: string;
-  /** 한 줄 설명 (선택). */
   description?: string;
-  /**
-   * 이 컴포넌트가 가질 수 있는 상태들. variant·size·disabled처럼 **눈으로 비교해야 하는
-   * 조합을 빠짐없이** 넣는다 — 예제가 곧 회귀 확인 수단이다.
-   */
+  /** 눈으로 비교해야 하는 조합을 빠짐없이 넣는다 — 예제가 곧 회귀 확인 수단이다. */
   variants: { label: string; node: ReactNode }[];
 }
 
-// 예제용 아이콘 — 시안의 실제 아이콘이 아니라 자리 확인용 도형이다.
-// `currentColor`로 그려야 버튼이 계열별로 색을 입힐 수 있다(슬롯이 `color`를 내려준다).
-// 크기는 슬롯이 `form-icon-*` 토큰으로 정하므로 100%로 채우기만 한다.
+// 자리 확인용 도형. `currentColor`로 그려야 계열별 색이 입혀진다.
 function DemoIcon() {
   return (
     <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true">
@@ -29,10 +19,7 @@
   );
 }
 
-/**
- * 컴포넌트를 만들 때마다 여기에 한 항목씩 추가한다. 사이드바·본문은 이 배열만 보고
- * 그리므로 다른 파일을 고칠 필요가 없다.
- */
+/** 컴포넌트를 만들 때마다 항목 하나를 추가한다 — 다른 파일은 고치지 않는다. */
 export const COMPONENT_EXAMPLES: ComponentExample[] = [
   {
     id: "fox-button",
@fox/dev-test/dev-test-page.tsx
--- @fox/dev-test/dev-test-page.tsx
+++ @fox/dev-test/dev-test-page.tsx
@@ -10,9 +10,7 @@
 import { useCssTokens } from "./use-css-tokens";
 import styles from "./dev-test.module.scss";
 
-// 선택 상태는 URL 해시가 SSOT다 — 새로고침하거나 링크를 공유해도 보던 섹션이 유지되고,
-// React state를 따로 두지 않으므로 둘이 어긋날 일이 없다.
-// 형식: `#token:light` / `#component:button`
+// 선택 상태는 URL 해시가 SSOT다. 형식: `#token:light` / `#component:fox-button`
 function subscribeHash(onChange: () => void): () => void {
   window.addEventListener("hashchange", onChange);
   return () => window.removeEventListener("hashchange", onChange);
@@ -36,18 +34,13 @@
   window.location.hash = `${kind}:${id}`;
 }
 
-/** 안내 항목의 식별자 — 등록된 컴포넌트 id와 겹치지 않게 별도로 둔다. */
 const GUIDE_ID = "guide";
 
 function isRegistered(id: string): boolean {
   return COMPONENT_EXAMPLES.some((example) => example.id === id);
 }
 
-/**
- * 사이드바 분류는 원본 JSON 파일 구조를 그대로 따른다 — Mode(Light/Dark),
- * Responsive(PC/Mobile), 그리고 단일 모드인 Size·Theme·Primitive. 이 화면의 목적이
- * Figma 변수 페이지와 1:1로 대조하는 것이라, 우리 CSS 그룹이 아니라 원본 구획이 기준이다.
- */
+/** Figma 변수 페이지와 대조하는 화면이라 우리 CSS 그룹이 아닌 원본 구획을 따른다. */
 function groupedSections(sections: CssSection[]) {
   const groups: { category: string | null; sections: CssSection[] }[] = [];
 
@@ -140,8 +133,7 @@
                 </li>
               ))}
 
-              {/* 컴포넌트가 아니라 안내 항목이라 항상 목록 맨 아래에 두고 생김새를 달리한다.
-                  등록된 컴포넌트가 없을 때도 사라지지 않아야 추가 방법을 찾을 수 있다. */}
+              {/* 컴포넌트가 아니라 안내라 항상 맨 아래에 두고 생김새를 달리한다. */}
               <li>
                 <button
                   type="button"
@fox/dev-test/read-css-tokens.ts
--- @fox/dev-test/read-css-tokens.ts
+++ @fox/dev-test/read-css-tokens.ts
@@ -25,10 +25,7 @@
   return match ? match[1] : null;
 }
 
-/**
- * `var(--name, 내용)`에서 괄호 짝을 세어 `내용`만 잘라낸다.
- * 내용 자체가 `var(--fox-…)`를 품고 있어 정규식으로는 안전하게 못 자른다.
- */
+/** 내용에 `var(--fox-…)`가 중첩돼 정규식으로는 못 자르므로 괄호 짝을 센다. */
 function extractFallback(text: string, marker: string): string | null {
   const start = text.indexOf(marker);
   if (start < 0) {
@@ -44,7 +41,7 @@
   return text.slice(start + marker.length, i - 1).trim();
 }
 
-/** 최상위 콤마 하나로 두 조각을 나눈다(괄호 안의 콤마는 무시). */
+/** 괄호 안의 콤마는 무시하고 최상위 콤마로 나눈다. */
 function splitTopLevel(text: string): [string, string] | null {
   let depth = 0;
   for (let i = 0; i < text.length; i += 1) {
@@ -59,11 +56,8 @@
 }
 
 /**
- * 라이트/다크 두 값을 분해한다.
- *
- * Lightning CSS가 `light-dark()`를 폴리필해
- * `var(--lightningcss-light, A) var(--lightningcss-dark, B)`로 내보내므로 그 형태를 먼저 보고,
- * 폴리필이 없는 설정(브라우저 타깃을 좁힌 경우)을 대비해 원형도 함께 처리한다.
+ * Lightning CSS가 `light-dark()`를 폴리필한 형태를 먼저 보고, 폴리필이 없는 설정을
+ * 대비해 원형도 처리한다.
  */
 function splitLightDark(declaration: string): { light: string; dark: string } | null {
   const light = extractFallback(declaration, "var(--lightningcss-light,");
@@ -144,14 +138,8 @@
 const PRIMITIVE_PREFIX = /^(primitive|font-family|font-weight|number)-/;
 
 /**
- * 컴파일된 CSS만 읽어 섹션을 구성한다.
- *
- * **매니페스트가 아니라 실제 스타일시트가 값의 출처다.** 토큰 SCSS를 고치면(원칙적으로
- * 자동 생성물이라 고치면 안 되지만) 이 화면에 즉시 반영되므로, 생성물과 화면이 어긋날
- * 여지가 없다.
- * 선언 **원문**을 읽는 것이 요점이다 — 계산값을 읽으면 참조(`var(--fox-…)`)가 이미
- * 풀려 버리고, 현재 테마·뷰포트 한쪽 값만 보인다. 원문에는 light/dark와 PC/모바일이
- * 모두 남아 있어 현재 화면 상태와 무관하게 네 조합을 전부 볼 수 있다.
+ * 컴파일된 스타일시트에서 섹션을 구성한다. 계산값이 아니라 **선언 원문**을 읽는 것이
+ * 요점 — 계산값은 참조가 이미 풀려 있고 현재 테마·뷰포트 한쪽만 보인다.
  */
 export function readCssSections(): CssSection[] {
   const { base, pc } = readRaw();
@@ -188,7 +176,7 @@
       primitive.push(name);
       continue;
     }
-    // 분류에 없는 새 토큰도 버리지 않는다 — Size 뒤에 붙여 눈에 띄게 둔다.
+    // 분류에 없는 새 토큰도 버리지 않는다.
     size.push(name);
   }
 
@fox/dev-test/theme-switch.tsx
--- @fox/dev-test/theme-switch.tsx
+++ @fox/dev-test/theme-switch.tsx
@@ -15,11 +15,8 @@
 ];
 
 /**
- * `<html data-theme>` 자체가 SSOT이므로 React state를 두지 않고 DOM을 구독한다 —
- * 서버/클라이언트 출력이 갈리지 않아 hydration 불일치 표면적이 0이다.
- *
- * 개발용 미리보기 컨트롤이라 **선택을 저장하지 않는다.** 저장 키는 호스트 앱이 소유하는
- * 값이라(앱마다 다르다) `@fox`가 알 필요가 없고, 알면 포터빌리티가 깨진다.
+ * `<html data-theme>`가 SSOT라 React state를 두지 않는다. 저장 키는 호스트 앱이
+ * 소유하는 값이라 `@fox`가 알면 포터빌리티가 깨지므로 선택을 저장하지 않는다.
  */
 function subscribe(onChange: () => void): () => void {
   const observer = new MutationObserver(onChange);
@fox/dev-test/token-view.tsx
--- @fox/dev-test/token-view.tsx
+++ @fox/dev-test/token-view.tsx
@@ -5,14 +5,9 @@
 import styles from "./dev-test.module.scss";
 
 /**
- * 미리보기 — 토큰 이름으로 무엇을 보여줄지 고른다.
- *
- * ⚠️ 값은 그 토큰의 CSS 변수가 아니라 **그 섹션의 선언 원문**을 넣는다. `var(--fox-그토큰)`을
- * 쓰면 PC 섹션을 좁은 창에서 볼 때 모바일 값이 그려지고 Light 섹션이 다크 테마에서 다크 색으로
- * 그려진다 — 이 화면은 각 모드가 정의한 값을 보여야 하므로 현재 테마·뷰포트에 흔들리면 안 된다.
- * 원문이 참조(`var(--fox-primitive-…)`)인 경우는 그대로 넣어도 안전하다. 참조 대상인
- * primitive·theme는 모드와 무관한 단일 값이기 때문이다.
- * 인라인 `style`을 쓰는 예외인 이유도 같다: 렌더할 토큰을 미리 알 수 없다.
+ * ⚠️ 값으로 그 토큰의 CSS 변수가 아니라 **섹션의 선언 원문**을 넣는다. 변수를 쓰면 PC
+ * 섹션이 좁은 창에서 모바일 값으로, Light 섹션이 다크 테마에서 다크 색으로 그려진다.
+ * 렌더할 토큰을 미리 알 수 없어 인라인 `style`을 쓰는 예외 지점이기도 하다.
  */
 const PREVIEWS: { match: RegExp; render: (value: string) => ReactNode }[] = [
   {
@@ -38,7 +33,7 @@
     render: (value) => <div className={styles.demoRadius} style={{ borderRadius: value }} />,
   },
   {
-    // 브라우저가 자체적으로 그리는 컨트롤이라 별도 에셋 없이 크기만 확인할 수 있다.
+    // 브라우저가 그리는 컨트롤이라 별도 에셋 없이 크기만 확인한다.
     match: /(^|-)icon(-|$)/,
     render: (value) => (
       <input
@@ -67,9 +62,8 @@
     match: /^backdrop-/,
     render: (value) => (
       <div className={styles.demoBackdrop}>
-        {/* eslint-disable-next-line @next/next/no-img-element -- @fox는 프레임워크에 의존하지
-            않아야 이식된다. next/image를 쓰면 이 폴더가 Next 전용이 되고 외부 호스트마다
-            remotePatterns 설정도 필요해진다. */}
+        {/* eslint-disable-next-line @next/next/no-img-element -- next/image를 쓰면 이
+            폴더가 Next 전용이 된다. */}
         <img
           src="https://picsum.photos/seed/picsum/200/300"
           alt=""
@@ -117,16 +111,12 @@
   return hit ? hit.render(token.declaration) : null;
 }
 
-/** 색 토큰 판별 — 이 세 접두사만 색이다(font-·number-는 아니다). */
+/** 이 세 접두사만 색이다. */
 function isColor(token: CssToken): boolean {
   return /^(color|primitive|theme)-/.test(token.name);
 }
 
-/**
- * 칩 배경으로 선언 원문을 그대로 넣는다. 참조(`var(--fox-primitive-neutral-0)`)든
- * 리터럴이든 CSS가 알아서 해석하고, 참조 대상인 primitive·theme는 모드와 무관한
- * 값이라 Light 섹션은 라이트 색이, Dark 섹션은 다크 색이 정확히 그려진다.
- */
+/** 참조든 리터럴이든 원문을 그대로 넣는다 — 참조 대상은 모드 무관 값이라 안전하다. */
 function chipStyle(token: CssToken): CSSProperties {
   return { background: token.declaration };
 }
@fox/dev-test/use-css-tokens.ts
--- @fox/dev-test/use-css-tokens.ts
+++ @fox/dev-test/use-css-tokens.ts
@@ -1,12 +1,8 @@
 import { useSyncExternalStore } from "react";
 import { readCssSections, type CssSection } from "./read-css-tokens";
 
-// 스타일시트는 React 바깥의 외부 시스템이라 `useSyncExternalStore`가 맞는 도구다
-// (effect에서 setState 하면 렌더가 연쇄된다).
-//
-// 선언 **원문**을 읽으므로 결과가 현재 테마·뷰포트에 영향받지 않는다 — 한 번 읽어
-// 캐시하면 그만이다. `useSyncExternalStore`는 매 렌더마다 getSnapshot을 호출하므로
-// 매번 새 배열을 돌려주면 무한 루프가 된다.
+// 선언 원문을 읽어 결과가 테마·뷰포트에 무관하므로 한 번만 읽어 캐시한다.
+// getSnapshot이 매 렌더 호출되므로 매번 새 배열을 돌려주면 무한 루프가 된다.
 let cached: CssSection[] | null = null;
 
 function subscribe(): () => void {
@@ -22,7 +18,7 @@
   return null;
 }
 
-/** 서버 렌더와 하이드레이션 첫 렌더에서는 `null`, 그 이후 CSS에서 읽은 섹션 목록. */
+/** 서버 렌더·하이드레이션 첫 렌더에서는 `null`. */
 export function useCssTokens(): CssSection[] | null {
   return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
 }
@fox/styles/_fox-button.scss
--- @fox/styles/_fox-button.scss
+++ @fox/styles/_fox-button.scss
@@ -1,30 +1,20 @@
-// FoxButton 스타일 — 시안: 관리자페이지 Figma, node 390:439 (`btn`)
+// FoxButton — 시안: 관리자페이지 Figma node 390:439
 //
-// **프레임워크 무관.** 클래스명이 `fox-` 접두사 + BEM이라 전역에 그대로 풀어도 충돌하지
-// 않는다. React 없이 SCSS만 쓰는 프로젝트도 이 파일 하나만 `@use`하고 아래 마크업 계약을
-// 지키면 동일한 버튼을 얻는다.
-//
+// 마크업 계약 (React 밖 소비자용):
 //   <button class="fox-button fox-button--primary fox-button--md">
 //     <span class="fox-button__icon">…svg…</span>   <!-- 선택 -->
 //     <span class="fox-button__label">버튼</span>
 //     <span class="fox-button__icon">…svg…</span>   <!-- 선택 -->
 //   </button>
+// 비활성은 네이티브 `disabled`, 로딩은 앞 아이콘 자리에 `fox-button__spinner` + `disabled`.
+// 아이콘 SVG는 `currentColor`로 그려야 계열별 색이 적용된다.
 //
-// - 비활성은 네이티브 `disabled` 속성으로 표현한다(별도 모디파이어 없음).
-// - 로딩은 앞쪽 아이콘 자리에 `fox-button__spinner`를 두고 `disabled`를 함께 건다.
-// - 아이콘 SVG는 `currentColor`로 그려야 계열별 색이 적용된다. 크기는 슬롯이 정한다.
-//
-// **모든 디자인 값은 토큰으로만 지목한다.** 시안의 Figma 변수가 우리 토큰과 1:1로
-// 대응하므로 예외가 필요 없었고, 아래 세 가지만 토큰이 아니다(사용자 승인 후 사용):
-//
-//   1. `line-height: 1` / `letter-spacing: -0.025em`
-//      시안 텍스트 스타일 `label/*-strong`의 값이다(lineHeight 1, letterSpacing -2.5%).
-//      Figma에서 텍스트 스타일로만 존재하고 변수로 export되지 않아 토큰이 없다.
-//      네 크기가 모두 같은 값이라 스케일이 아니고 규칙 하나로 끝난다.
-//   2. `box-sizing: border-box`
-//      높이가 고정인데 secondary·default가 1px 테두리를 가져, 없으면 계열별로 바깥
-//      높이가 2px 어긋난다. 디자인 값이 아니라 레이아웃 메커니즘이다.
-//   3. `cursor` / `white-space` / `flex-shrink` 등 구조·상호작용 규칙.
+// 토큰이 아닌 값 3건(사용자 승인):
+//   - line-height / letter-spacing: 시안 텍스트 스타일 label/*-strong의 값이나 Figma가
+//     변수로 export하지 않는다. 네 크기가 같은 값이라 규칙 하나로 끝난다.
+//   - box-sizing: 높이 고정 + secondary·default의 1px 테두리 때문에 필수. 없으면 계열별
+//     바깥 높이가 2px 어긋난다.
+//   - cursor / white-space / flex-shrink: 구조·상호작용 규칙.
 
 @use "abstracts" as fox;
 
@@ -36,7 +26,6 @@
   border: none;
   cursor: pointer;
 
-  // 시안 label/*-strong. 크기별 font-size는 아래 크기 모디파이어가 정한다.
   font-family: fox.font-family(body);
   font-weight: fox.font-weight(medium);
   line-height: 1;
@@ -47,12 +36,11 @@
     cursor: default;
   }
 
-  // 라벨이 길어도 아이콘을 밀어내지 않게 라벨만 줄어들 수 있게 둔다.
+  // 라벨만 줄어들게 해 아이콘이 밀리지 않게 한다.
   &__label {
     min-inline-size: 0;
   }
 
-  // 아이콘·로딩 슬롯. 크기는 크기 모디파이어가, 색은 계열 모디파이어가 정한다.
   &__icon,
   &__spinner {
     display: inline-flex;
@@ -70,8 +58,7 @@
     inline-size: 100%;
   }
 
-  // ── 크기 ──────────────────────────────────────────────────────────────────
-  // 높이만 고정이고 너비는 내용에 따라 가변이다(시안도 좌우 padding만 지정).
+  // ── 크기 (높이만 고정, 너비는 가변) ────────────────────────────────────────
   &--lg {
     block-size: fox.form(height-lg);
     padding-inline: fox.form(padding-lg);
@@ -114,7 +101,7 @@
     }
   }
 
-  // xsm만 gap이 한 단계 좁다(시안 확인).
+  // xsm만 gap이 한 단계 좁다.
   &--xsm {
     block-size: fox.form(height-xsm);
     padding-inline: fox.form(padding-xsm);
@@ -130,8 +117,7 @@
   }
 
   // ── 계열 ──────────────────────────────────────────────────────────────────
-  // 아이콘 색은 라벨 색과 별개 토큰으로 지정돼 있어(시안) 각각 지목한다 —
-  // 지금은 두 값이 같지만 토큰이 갈라지면 시안을 따라가야 한다.
+  // 아이콘 색은 시안이 라벨과 별개 토큰으로 지정한다(지금은 값이 같다).
   &--primary {
     background: fox.color(button-primary-surface);
     color: fox.color(button-primary-font);
@@ -185,14 +171,13 @@
     }
   }
 
-  // ⚠️ error 계열은 시안 미정이라 규칙을 두지 않는다. 확정되면 여기에 채운다.
+  // ⚠️ error 계열은 시안 미정.
   &--error {
   }
 }
 
-// ── 비활성 ──────────────────────────────────────────────────────────────────
-// 계열과 무관하게 같은 모양이고 **테두리가 없다**(시안에서 disabled-border 미사용).
-// 계열 모디파이어보다 특이도가 높아야 이기므로 `.fox-button` 블록과 함께 지목한다.
+// 계열과 무관하게 같고 테두리가 없다(시안에서 disabled-border 미사용).
+// 계열 모디파이어를 이기려면 특이도가 높아야 해 블록과 함께 지목한다.
 .fox-button:disabled {
   border: none;
   background: fox.color(button-disabled-surface);
@fox/styles/_functions.scss
--- @fox/styles/_functions.scss
+++ @fox/styles/_functions.scss
@@ -1,13 +1,5 @@
-// 토큰 접근 함수 — 디자인 시스템 규율을 **컴파일러가 강제**하는 지점.
-//
-// 화면 코드는 `color: #256EF4`나 `padding: 13px`를 쓸 수 없고, 반드시
-// `color: fox.color(font-neutral-strong)` / `padding: fox.padding(6)`로 토큰을
-// 지목해야 한다. 존재하지 않는 이름을 쓰면 `@error`로 **빌드가 실패**하고 사용
-// 가능한 토큰 목록이 함께 출력된다.
-//
-// 반환값은 CSS 커스텀 프로퍼티 참조(`var(--fox-*)`)다. 값이 아니라 참조를 돌려주므로
-// (1) 라이트/다크와 pc/모바일이 런타임에 전환되고 (2) 특정 영역만 토큰을 덮어쓰는
-// 스코프 오버라이드가 가능하며 (3) devtools에서 어떤 토큰인지 그대로 보인다.
+// 토큰 접근 함수. 없는 이름은 `@error`로 빌드를 실패시키고 사용 가능한 목록을 출력한다.
+// 값이 아니라 `var(--fox-*)` 참조를 돌려주므로 라이트/다크·PC/모바일이 런타임에 전환된다.
 
 @use "sass:map";
 @use "tokens";
@fox/styles/_mixins.scss
--- @fox/styles/_mixins.scss
+++ @fox/styles/_mixins.scss
@@ -1,18 +1,14 @@
-// 믹스인 — 여러 선언이 항상 함께 가야 하는 패턴을 묶는다.
-
 @use "tokens";
 
-/// PC 이상(>= 768px)에서 적용. 모바일 우선이므로 기본 스타일은 밖에 쓴다.
-///
-/// ⚠️ 미디어 쿼리 조건부는 `var()`를 해석하지 못하므로 브레이크포인트만은 CSS 변수가
-/// 아닌 컴파일타임 값이다. 그래서 이 믹스인 경유가 강제된다.
+/// PC 이상(>= 768px). 미디어 쿼리 조건부는 `var()`를 해석하지 못해 브레이크포인트만
+/// 컴파일타임 값이고, 그래서 이 믹스인 경유가 강제된다.
 @mixin pc {
   @media (min-width: tokens.$breakpoint-pc) {
     @content;
   }
 }
 
-/// PC 미만에서만 적용. `pc`와 경계가 겹치지 않도록 0.02px을 뺀다.
+/// PC 미만. `pc`와 경계가 겹치지 않도록 0.02px을 뺀다.
 @mixin mobile {
   @media (max-width: tokens.$breakpoint-pc - 0.02px) {
     @content;
@fox/styles/_root.scss
--- @fox/styles/_root.scss
+++ @fox/styles/_root.scss
@@ -1,16 +1,11 @@
-// 토큰 CSS 출력 — `tokens/`의 SCSS map을 `--fox-*` 커스텀 프로퍼티로 선언한다.
-//
-// **앱 전체에서 딱 한 번만 로드되어야 한다** (`index.scss` 경유).
-// 컴포넌트의 `.module.scss`에서는 절대 `@use` 하지 않는다.
-//
-// map을 순회해 생성하므로 토큰을 추가할 때 이 파일은 손대지 않는다.
+// 토큰 map을 `--fox-*` 커스텀 프로퍼티로 출력한다. **앱 전체에서 한 번만 로드한다.**
+// map을 순회하므로 토큰을 추가할 때 이 파일은 손대지 않는다.
 
 @use "sass:map";
 @use "tokens";
 
 :root {
-  // 기본은 OS 설정 추종. 아래 `[data-theme]` 규칙이 이 값만 덮어써 수동 선택을
-  // 처리하므로, 색상 값 자체는 `tokens/_color.scss` 한 곳에만 존재한다.
+  // 아래 `[data-theme]`가 이 값만 덮어써 수동 선택을 처리한다 — 색상 값은 한 곳에만 둔다.
   color-scheme: light dark;
 
   @each $name, $value in tokens.$primitive {
@@ -63,9 +58,8 @@
   color-scheme: dark;
 }
 
-// ⚠️ 1rem = 10px 규약의 근거. 브라우저 기본 글자 크기(16px)의 62.5%가 10px다.
-// 모든 토큰의 rem 값이 이 선언을 전제로 계산돼 있다.
-// 미디어 쿼리 안의 rem은 이 값의 영향을 받지 않는다(항상 브라우저 기본 크기 기준).
+// ⚠️ 1rem = 10px 규약의 근거. 모든 토큰의 rem 값이 이 선언을 전제로 한다.
+// 미디어 쿼리 안의 rem은 영향을 받지 않는다(항상 브라우저 기본 크기 기준).
 html {
   font-size: 62.5%;
 }
@fox/styles/components.scss
--- @fox/styles/components.scss
+++ @fox/styles/components.scss
@@ -1,14 +1,4 @@
-// 공용 컴포넌트 스타일 **묶음** 진입점 — 한 줄로 전부 가져올 때 쓴다.
-//
-//   @use "@fox/styles/components";
-//
-// 필요한 것만 쓰려면 개별 파티셜을 직접 가져온다(안 쓰는 컴포넌트 CSS가 번들에 안 실린다).
-//
-//   @use "@fox/styles/fox-button";
-//
-// 둘을 같이 써도 Sass가 모듈을 한 번만 로드하므로 CSS가 중복되지 않는다.
-//
-// ⚠️ 토큰(`@use "@fox/styles"`)은 별도다. 컴포넌트 스타일은 토큰 커스텀 프로퍼티를
-// 참조하므로, 이 파일만 가져오고 토큰 진입점을 빼면 값이 비어 렌더된다.
+// 공용 컴포넌트 스타일 묶음. 필요한 것만 쓰려면 개별 파티셜(`@fox/styles/fox-button`)을
+// 직접 @use 한다. 둘을 같이 써도 Sass가 모듈을 한 번만 로드해 중복되지 않는다.
 
 @use "fox-button";
Add a comment
List