임동욱 임동욱 08-11
revert: 근거 없이 생성된 디자인 토큰 값 제거
색상·타이포·간격·radius·그림자·모션·브레이크포인트 토큰은 실제 디자인 자료 없이
임의로 만들어진 값이었다. 디자인 시스템은 제공된 자료로만 구축한다는 원칙에 따라
값과 그에 딸린 함수·믹스인·리셋을 모두 제거한다.

자료를 받는 시점에 구조부터 다시 세운다.

Co-Authored-By: Claude Opus 5 
@c3d840ea9964adc4e828d8ad38a067364f0a97cf
 
@fox/README.md (deleted)
--- @fox/README.md
@@ -1,123 +0,0 @@
-# @fox — 포터블 디자인 시스템
-
-프로젝트에 종속되지 않는 디자인 시스템 패키지. **이 폴더를 통째로 복사하고 설정 2줄을
-추가하면** 다른 프로젝트에서 그대로 동작합니다.
-
-```
-@fox/
-  styles/                SCSS 토큰 · 함수 · 믹스인
-    index.scss           글로벌 진입점 (앱이 딱 한 번 import — CSS 출력)
-    abstracts.scss       저작 진입점 (컴포넌트가 @use — CSS 출력 0)
-    tokens/              토큰 map = 단일 진실 공급원(SSOT)
-    _root.scss           map → --fox-* 커스텀 프로퍼티 생성
-    _reset.scss          리셋 & 베이스
-    _functions.scss      fox.color() 등 토큰 접근 + 검증
-    _mixins.scss         fox.typo() · fox.media() 등 조합 패턴
-  core/
-    components/          공용 컴포넌트 (규약은 components/README.md)
-    utils/               cx() 등 의존성 없는 유틸
-```
-
-## 다른 프로젝트로 이식하기
-
-1. `@fox/` 폴더를 대상 프로젝트 루트에 복사합니다.
-
-2. `sass`를 설치합니다.
-
-   ```bash
-   npm install --save-dev sass
-   ```
-
-3. **TypeScript 경로 별칭** — `tsconfig.json`:
-
-   ```json
-   { "compilerOptions": { "paths": { "@fox/*": ["./@fox/*"] } } }
-   ```
-
-4. **SCSS 로드 경로** — `next.config.ts`:
-
-   ```ts
-   sassOptions: { loadPaths: [path.join(process.cwd())] }
-   ```
-
-   TypeScript의 `paths`는 번들러 전용이라 Sass의 `@use` 해석에는 관여하지 않습니다.
-   그래서 같은 경로를 양쪽에 각각 선언해야 TS와 SCSS의 import 표기가 일치합니다.
-   이게 없으면 컴포넌트마다 `../../../` 상대 경로를 써야 해서 폴더 복사가 불가능해집니다.
-
-5. 앱의 글로벌 스타일에서 진입점을 한 번 import 합니다.
-
-   ```scss
-   /* app/globals.scss */
-   @use "@fox/styles";
-   ```
-
-6. (선택) 폰트를 주입합니다 — 아래 "호스트 앱과의 계약" 참고.
-
-Next.js가 아닌 번들러라면 4번만 그 도구의 Sass 옵션(`includePaths` / `loadPaths`)으로
-바꿔주면 됩니다.
-
-## 핵심 설계
-
-**토큰의 SSOT는 `tokens/`의 SCSS map 하나뿐입니다.** 여기서 두 가지가 함께 파생됩니다 —
-`_root.scss`가 만드는 `--fox-*` CSS 커스텀 프로퍼티와, `_functions.scss`가 검증에 쓰는
-유효 이름 목록. 값과 이름이 한 곳에만 있으므로 둘이 어긋날 수 없습니다.
-
-**규율을 컴파일러가 강제합니다.** 화면 코드는 `color: #4f46e5`를 쓸 수 없고
-`fox.color(primary)`로 토큰을 지목해야 합니다. 없는 이름을 쓰면 빌드가 실패하며, 에러
-메시지가 사용 가능한 토큰 목록을 함께 출력합니다.
-
-```
-Error: [@fox] 알 수 없는 color 토큰: `primry` — 사용 가능한 값: primary, primary-hover, ...
-```
-
-**1rem = 10px입니다.** `_reset.scss`의 `html { font-size: 62.5% }`가 근거입니다. px → rem
-환산이 10으로 나누기가 되어 토큰 값이 읽기 쉽고, px 고정과 달리 사용자가 브라우저 글자
-크기를 키우면 앱 전체가 비례해 확대됩니다.
-
-> ⚠️ **미디어 쿼리 안의 `rem`은 예외입니다.** 미디어 쿼리는 `html`의 `font-size` 영향을
-> 받지 않고 항상 브라우저 기본 크기(보통 16px) 기준으로 계산합니다. 그래서
-> `tokens/_layout.scss`의 브레이크포인트 `48rem`은 480px가 아니라 **768px**입니다.
-> 각 값에 px 환산을 주석으로 달아 두었습니다.
-
-**라이트/다크는 값이 한 곳에만 존재합니다.** `light-dark(라이트, 다크)`로 한 줄에 두 값을
-함께 쓰고, 전환은 `color-scheme`이 담당합니다. 다크 전용 오버라이드 블록이 없으므로 한쪽만
-고쳐서 생기는 테마 불일치가 구조적으로 불가능합니다.
-`<html data-theme="light"|"dark">`로 수동 선택을 덮어쓸 수 있고, 속성이 없으면 OS 설정을
-따릅니다.
-
-> **브라우저 지원** — `light-dark()` 자체는 Chrome 123 / Safari 17.5 / Firefox 120 이상이
-> 필요하지만, Next.js 16(Turbopack)의 Lightning CSS가 현재 설정에서 이를
-> `var(--lightningcss-light, 라이트) var(--lightningcss-dark, 다크)` 조합으로 폴리필해
-> 출력하므로 구형 브라우저에서도 동작합니다. browserslist 타깃을 좁히면 폴리필이 빠지고
-> 원본 `light-dark()`가 그대로 나가므로, 타깃을 바꿀 때 이 전제를 다시 확인하세요.
-> Lightning CSS를 쓰지 않는 번들러로 옮길 때도 마찬가지입니다.
-
-## 호스트 앱과의 계약
-
-`@fox`가 소유하지 않고 앱에서 받는 값입니다.
-
-| CSS 변수 | 용도 | 미주입 시 |
-| --- | --- | --- |
-| `--app-font-sans` | 기본 서체 | `system-ui`로 폴백 |
-| `--app-font-mono` | 고정폭 서체 | `ui-monospace`로 폴백 |
-
-폰트 파일은 앱이 소유합니다(Next.js에서는 `next/font`가 최적화·자체 호스팅을 담당). `@fox`는
-변수를 참조만 하므로, 폴더를 복사해 간 프로젝트는 그 프로젝트의 폰트를 그대로 씁니다.
-
-```tsx
-// app/layout.tsx
-const sans = localFont({ src: [...], variable: "--app-font-sans" });
-<html className={sans.variable}>
-```
-
-테마 토글을 붙이려면 `<html>`의 `data-theme` 속성을 `"light" | "dark"`로 설정하고, 전환
-애니메이션이 필요하면 같은 tick에 `data-theme-transition` 속성을 부여한 뒤 200ms 후
-제거합니다(`_root.scss`가 그 동안만 색상 트랜지션을 겁니다).
-
-## 토큰 추가하기
-
-1. `tokens/`의 해당 map에 항목을 추가합니다. 그것으로 끝입니다 — 커스텀 프로퍼티 생성과
-   함수 검증 목록이 자동으로 따라옵니다.
-2. 값의 출처(Figma file/node 등)를 주석으로 남깁니다.
-3. **새 토큰 그룹**(map 자체를 신설)이 필요하면 `tokens/_index.scss`에 `@forward`를 추가하고,
-   `_functions.scss`에 접근 함수를, `_root.scss`에 `@each` 블록을 각각 추가합니다.
 
@fox/core/components/README.md (deleted)
--- @fox/core/components/README.md
@@ -1,87 +0,0 @@
-# 컴포넌트 작성 규약
-
-아직 컴포넌트가 없습니다. 디자인 확정에 따라 하나씩 추가합니다.
-
-## 파일 배치
-
-컴포넌트 하나당 폴더 하나. 스타일을 같은 폴더에 두어야 폴더째 복사·삭제가 가능합니다.
-
-```
-components/
-  button/
-    button.tsx          컴포넌트
-    button.module.scss  스타일 (반드시 .module.scss — 전역 오염 방지)
-    index.ts            export { Button } from "./button";
-  index.ts              배럴 — export * from "./button";
-```
-
-## 작성 규칙
-
-**1. 스타일은 `abstracts`만 `@use` 한다.**
-
-```scss
-@use "@fox/styles/abstracts" as fox;
-
-.button {
-  padding: fox.space(2) fox.space(4);
-  border-radius: fox.radius(md);
-  background: fox.color(primary);
-  color: fox.color(on-primary);
-
-  @include fox.typo(label-lg);
-  @include fox.focus-ring;
-  @include fox.transition((background-color, color));
-}
-```
-
-`@fox/styles`(진입점)를 `@use` 하면 안 됩니다 — 그쪽은 CSS를 출력하므로 컴포넌트마다
-토큰 선언 전체가 복제됩니다. `abstracts`는 출력이 0입니다.
-
-**2. 원시 디자인 값을 쓰지 않는다.**
-
-`color: #4f46e5`, `padding: 13px`, `border-radius: 12px` 금지. 전부 `fox.*()` 함수로
-토큰을 지목합니다. 없는 토큰 이름을 쓰면 빌드가 실패하므로 오타는 배포까지 갈 수
-없습니다. **맞는 토큰이 없다고 해서 원시 값을 쓰지 말고, 토큰을 먼저 추가**합니다
-(`@fox/styles/tokens/`).
-
-예외는 의미가 고정되어 토큰화가 무의미한 값뿐입니다 — `0`, `100%`, `1px`(구분선),
-`auto`, `inherit`.
-
-**3. 기본은 Server Component로 둔다.**
-
-`'use client'`는 상호작용(상태·이벤트 핸들러·브라우저 API)이 실제로 필요한 컴포넌트에만
-붙입니다. CSS Module은 빌드타임에 클래스명 문자열로 바뀔 뿐이라 런타임 JS가 없으므로,
-스타일링만 하는 컴포넌트는 서버에 남을 수 있습니다. 여기에 불필요하게 `'use client'`를
-붙이면 이 컴포넌트를 쓰는 화면 전체가 클라이언트로 내려갑니다.
-
-**4. variant는 클래스 맵으로 고정한다.**
-
-```tsx
-import styles from "./button.module.scss";
-import { cx } from "@fox/core/utils";
-
-type ButtonVariant = "primary" | "secondary" | "ghost";
-
-const VARIANT: Record<ButtonVariant, string> = {
-  primary: styles.primary,
-  secondary: styles.secondary,
-  ghost: styles.ghost,
-};
-
-export function Button({ variant = "primary", className, ...props }: ButtonProps) {
-  return <button className={cx(styles.button, VARIANT[variant], className)} {...props} />;
-}
-```
-
-`Record<Variant, string>`이라 variant를 추가하면 맵에 항목을 빠뜨릴 수 없습니다(타입 에러).
-
-**5. `className` prop은 배치용으로만 열어 둔다.**
-
-호출부가 `className`으로 넘기는 것은 margin·grid 배치 같은 **위치** 조정이지, 색·크기 같은
-**디자인 값**이 아닙니다. 디자인이 달라져야 하면 variant를 추가합니다.
-
-**6. 호스트 앱에 의존하지 않는다.**
-
-`@fox/` 안에서는 `@/lib/...`, `@/app/...` 같은 앱 경로를 import 하지 않습니다. 이 폴더는
-다른 프로젝트로 통째로 복사되어야 하므로, 앱이 주는 값은 반드시 prop이나 CSS 변수로
-받습니다(폰트가 `--app-font-sans`를 받는 것과 같은 방식).
@fox/core/utils/cx.ts
--- @fox/core/utils/cx.ts
+++ @fox/core/utils/cx.ts
@@ -1,15 +1,6 @@
 export type ClassValue = string | false | null | undefined;
 
-/**
- * 조건부 클래스명을 합친다. falsy 값은 버린다.
- *
- *   cx(styles.button, isActive && styles.active, className)
- *
- * 유틸리티 CSS 프레임워크에서 쓰는 클래스 병합 라이브러리(tailwind-merge 등)가
- * 필요 없는 이유: CSS Module은 클래스명이 파일 단위로 스코프되므로 서로 다른
- * 컴포넌트의 클래스가 같은 속성을 두고 충돌하지 않는다. 한 컴포넌트 안에서의
- * 충돌은 선언 순서(뒤에 온 규칙이 이김)로 결정되며, 이는 CSS의 정상 동작이다.
- */
+
 export function cx(...values: ClassValue[]): string {
   return values.filter(Boolean).join(" ");
 }
 
@fox/styles/_functions.scss (deleted)
--- @fox/styles/_functions.scss
@@ -1,75 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 토큰 접근 함수 — 디자인 시스템 규율을 **컴파일러가 강제**하는 지점.
-//
-// 화면 코드는 `color: #4f46e5`나 `padding: 13px`를 쓸 수 없고, 반드시
-// `color: fox.color(primary)` / `padding: fox.space(3)`로 토큰을 지목해야 한다.
-// 존재하지 않는 이름을 쓰면 `@error`로 **빌드가 실패한다** — 오타나 임의 값이
-// 리뷰를 통과해 배포까지 흘러가는 경로가 원천 차단된다.
-//
-// 반환값은 CSS 커스텀 프로퍼티 참조(`var(--fox-*)`)다. 값 자체가 아니라 참조를
-// 돌려주므로 (1) 라이트/다크가 런타임에 전환되고 (2) 특정 영역만 토큰을 덮어쓰는
-// 스코프 오버라이드가 가능하며 (3) devtools에서 어떤 토큰인지 그대로 보인다.
-// ─────────────────────────────────────────────────────────────────────────────
-
-@use "sass:map";
-@use "tokens";
-
-/// 토큰 이름을 검증하고 대응하는 CSS 커스텀 프로퍼티 참조를 반환한다.
-/// @param {String} $group - 토큰 그룹(커스텀 프로퍼티 접두사에 그대로 쓰인다)
-/// @param {String|Number} $name - 토큰 이름
-/// @param {Map} $registry - 검증 기준이 되는 토큰 map
-@function _token($group, $name, $registry) {
-  @if not map.has-key($registry, $name) {
-    @error "[@fox] 알 수 없는 #{$group} 토큰: `#{$name}` — 사용 가능한 값: #{map.keys($registry)}";
-  }
-
-  @return var(--fox-#{$group}-#{$name});
-}
-
-@function color($name) {
-  @return _token("color", $name, tokens.$color);
-}
-
-@function space($name) {
-  @return _token("space", $name, tokens.$space);
-}
-
-@function radius($name) {
-  @return _token("radius", $name, tokens.$radius);
-}
-
-@function shadow($name) {
-  @return _token("shadow", $name, tokens.$shadow);
-}
-
-@function duration($name) {
-  @return _token("duration", $name, tokens.$duration);
-}
-
-@function easing($name) {
-  @return _token("easing", $name, tokens.$easing);
-}
-
-@function font($name) {
-  @return _token("font", $name, tokens.$font-family);
-}
-
-@function weight($name) {
-  @return _token("weight", $name, tokens.$font-weight);
-}
-
-@function z($name) {
-  @return _token("z", $name, tokens.$z);
-}
-
-/// 브레이크포인트 원값(rem 리터럴)을 반환한다 — **유일하게 `var()`가 아닌 실제 값을
-/// 돌려주는 함수**다. 미디어 쿼리가 `var()`를 해석하지 못하기 때문이다(`tokens/_layout.scss`).
-/// 미디어 쿼리 자체는 `media()` 믹스인을 쓰고, 이 함수는 컨테이너 `max-width`처럼
-/// 브레이크포인트와 같은 값을 선언에 직접 써야 할 때만 쓴다.
-@function bp($name) {
-  @if not map.has-key(tokens.$breakpoint, $name) {
-    @error "[@fox] 알 수 없는 breakpoint 토큰: `#{$name}` — 사용 가능한 값: #{map.keys(tokens.$breakpoint)}";
-  }
-
-  @return map.get(tokens.$breakpoint, $name);
-}
 
@fox/styles/_mixins.scss (deleted)
--- @fox/styles/_mixins.scss
@@ -1,109 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 믹스인 — 여러 선언이 항상 함께 가야 하는 패턴을 한 줄로 묶는다.
-//
-// 함수(`_functions.scss`)가 "값 하나"를 강제한다면, 믹스인은 "값들의 조합"을
-// 강제한다. 타이포 4종(크기·행간·굵기·자간)이나 감소 모션 분기처럼 하나만 빠져도
-// 어긋나는 것들을 화면마다 되풀이해 적지 않게 만드는 것이 목적이다.
-// ─────────────────────────────────────────────────────────────────────────────
-
-@use "sass:map";
-@use "tokens";
-@use "functions" as fn;
-
-/// 타이포 프리셋 적용 — 크기·행간·굵기·자간 4종을 한 번에.
-/// 개별 스칼라를 따로 고르지 못하게 해서 타이포 조합이 무한히 갈라지는 것을 막는다.
-@mixin typo($name) {
-  @if not map.has-key(tokens.$typo, $name) {
-    @error "[@fox] 알 수 없는 typo 프리셋: `#{$name}` — 사용 가능한 값: #{map.keys(tokens.$typo)}";
-  }
-
-  font-size: var(--fox-typo-#{$name}-size);
-  font-weight: var(--fox-typo-#{$name}-weight);
-  line-height: var(--fox-typo-#{$name}-line-height);
-  letter-spacing: var(--fox-typo-#{$name}-letter-spacing);
-}
-
-/// 지정 브레이크포인트 **이상**에서 적용 (모바일 우선).
-@mixin media($name) {
-  @media (min-width: fn.bp($name)) {
-    @content;
-  }
-}
-
-/// 지정 브레이크포인트 **미만**에서 적용.
-/// `media()`와 경계가 겹치지 않도록 0.01rem을 뺀다 — 같은 뷰포트 폭에서 두 블록이
-/// 동시에 적용되면 나중 선언이 이기는 미묘한 버그가 생긴다.
-@mixin media-below($name) {
-  @media (max-width: fn.bp($name) - 0.01rem) {
-    @content;
-  }
-}
-
-/// 트랜지션 — `prefers-reduced-motion: no-preference`로 감싸 감소 모션 환경에서는
-/// 아예 선언되지 않게 한다(값을 0으로 만드는 것보다 확실하다).
-/// @param {List} $properties - 전환할 속성. 여러 개면 괄호로 묶어 전달한다.
-@mixin transition($properties, $duration: base, $easing: out) {
-  @media (prefers-reduced-motion: no-preference) {
-    transition-property: $properties;
-    transition-duration: fn.duration($duration);
-    transition-timing-function: fn.easing($easing);
-  }
-}
-
-/// 키프레임 애니메이션 — 감소 모션 분기는 `transition()`과 동일하게 내장.
-@mixin animate($name, $duration: base, $easing: out, $fill: both) {
-  @media (prefers-reduced-motion: no-preference) {
-    animation: $name fn.duration($duration) fn.easing($easing) $fill;
-  }
-}
-
-/// 키보드 포커스 링 — `:focus-visible`만 대상으로 하므로 마우스 클릭 시에는
-/// 나타나지 않는다. 모든 상호작용 요소에 반드시 넣는다(접근성).
-@mixin focus-ring($color: null, $width: 0.2rem, $offset: 0.2rem) {
-  $ring-color: fn.color(primary);
-
-  @if $color != null {
-    $ring-color: $color;
-  }
-
-  &:focus-visible {
-    outline: $width solid $ring-color;
-    outline-offset: $offset;
-  }
-}
-
-/// 화면에는 보이지 않지만 스크린리더는 읽는 텍스트.
-/// `display: none`이나 `visibility: hidden`은 보조기기에서도 사라지므로 쓰지 않는다.
-@mixin visually-hidden {
-  position: absolute;
-  width: 1px;
-  height: 1px;
-  margin: -1px;
-  padding: 0;
-  overflow: hidden;
-  clip-path: inset(50%);
-  white-space: nowrap;
-  border: 0;
-}
-
-/// 말줄임 — 1줄이면 `text-overflow`, 여러 줄이면 line-clamp.
-@mixin truncate($lines: 1) {
-  overflow: hidden;
-
-  @if $lines == 1 {
-    text-overflow: ellipsis;
-    white-space: nowrap;
-  } @else {
-    display: -webkit-box;
-    -webkit-box-orient: vertical;
-    -webkit-line-clamp: $lines;
-  }
-}
-
-/// 페이지 콘텐츠 가로 폭 제한 + 좌우 여백.
-@mixin container($max: xl, $gutter: 4) {
-  width: 100%;
-  max-width: fn.bp($max);
-  margin-inline: auto;
-  padding-inline: fn.space($gutter);
-}
 
@fox/styles/_reset.scss (deleted)
--- @fox/styles/_reset.scss
@@ -1,121 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 리셋 & 베이스
-//
-// 브라우저 기본 스타일 중 디자인 시스템과 충돌하는 것만 걷어낸다. 전면 리셋(모든
-// 요소를 무스타일로)이 아니라, 시맨틱 태그의 기본 동작은 살리고 시각 표현만
-// 토큰으로 되돌리는 방식이다.
-// ─────────────────────────────────────────────────────────────────────────────
-
-@use "abstracts" as fox;
-
-*,
-*::before,
-*::after {
-  box-sizing: border-box;
-}
-
-// ⚠️ **1rem = 10px 규약의 근거.** 브라우저 기본 글자 크기(16px)의 62.5%가 10px다.
-// px → rem 환산이 10으로 나누기가 되어 토큰 값이 읽기 쉬워진다.
-// px 고정과 달리 사용자가 브라우저 글자 크기를 키우면 앱 전체가 비례해 확대된다
-// (접근성 설정 존중). 그 대신 `body`에서 실제 본문 크기를 되돌려 놓아야 한다 —
-// 아래 `body`의 `typo(body-md)`가 그 역할이다.
-//
-// ⚠️ 미디어 쿼리 안의 `rem`은 이 값의 영향을 받지 않는다(항상 브라우저 기본 크기
-// 기준). `tokens/_layout.scss` 참고.
-html {
-  font-size: 62.5%;
-  -webkit-text-size-adjust: 100%;
-}
-
-body {
-  margin: 0;
-  background-color: fox.color(background);
-  color: fox.color(foreground);
-  font-family: fox.font(sans);
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-
-  @include fox.typo(body-md);
-}
-
-// 제목·문단의 기본 여백을 제거한다 — 간격은 레이아웃(gap/margin 토큰)이 책임지고,
-// 태그가 스스로 여백을 갖지 않게 해야 조립 결과를 예측할 수 있다.
-h1,
-h2,
-h3,
-h4,
-h5,
-h6,
-p,
-figure,
-blockquote,
-dl,
-dd {
-  margin: 0;
-}
-
-// 제목 태그의 기본 크기/굵기도 제거한다 — 시각적 위계는 `typo()` 프리셋으로만
-// 정하고, 태그 선택은 문서 구조(접근성) 기준으로 하게 만든다.
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
-  font-size: inherit;
-  font-weight: inherit;
-}
-
-ul,
-ol {
-  margin: 0;
-  padding: 0;
-  list-style: none;
-}
-
-// 폼 요소는 폰트를 상속하지 않는 것이 브라우저 기본값이라 명시적으로 되돌린다.
-button,
-input,
-select,
-textarea {
-  margin: 0;
-  font: inherit;
-  color: inherit;
-  letter-spacing: inherit;
-}
-
-button {
-  padding: 0;
-  border: 0;
-  background: none;
-  cursor: pointer;
-}
-
-button:disabled {
-  cursor: default;
-}
-
-a {
-  color: inherit;
-  text-decoration: none;
-}
-
-img,
-svg,
-video,
-canvas {
-  display: block;
-  max-width: 100%;
-}
-
-table {
-  border-collapse: collapse;
-  border-spacing: 0;
-}
-
-// 브라우저 기본 포커스 링을 지우지 않는다 — 컴포넌트가 `focus-ring()` 믹스인으로
-// 자기 링을 정의하면 그것이 우선하고, 정의하지 않은 요소는 기본 링이 남아 키보드
-// 사용자가 길을 잃지 않는다.
-:where(:focus-visible) {
-  outline-offset: 0.2rem;
-}
 
@fox/styles/_root.scss (deleted)
--- @fox/styles/_root.scss
@@ -1,104 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 토큰 CSS 출력 — `tokens/` 의 SCSS map을 `--fox-*` 커스텀 프로퍼티로 선언한다.
-//
-// **이 파일은 앱 전체에서 딱 한 번만 로드되어야 한다** (`index.scss` 경유).
-// 컴포넌트의 `.module.scss`에서는 절대 `@use` 하지 않는다 — CSS Module은 파일마다
-// 별도 컴파일 단위여서, 컴포넌트마다 `:root` 블록 전체가 복제된다.
-//
-// map을 순회해 생성하므로 토큰을 추가할 때 이 파일은 손대지 않는다. 값의 이름·개수는
-// 언제나 `tokens/` 쪽 map 하나에만 존재한다.
-// ─────────────────────────────────────────────────────────────────────────────
-
-@use "sass:map";
-@use "tokens";
-
-:root {
-  // 기본은 OS 설정 추종. 아래 `[data-theme]` 규칙이 이 값만 덮어써 수동 선택을
-  // 처리하므로, 색상 값 자체는 `tokens/_color.scss` 한 곳에만 존재한다.
-  color-scheme: light dark;
-
-  @each $name, $value in tokens.$color {
-    --fox-color-#{$name}: #{$value};
-  }
-
-  @each $name, $value in tokens.$space {
-    --fox-space-#{$name}: #{$value};
-  }
-
-  @each $name, $value in tokens.$radius {
-    --fox-radius-#{$name}: #{$value};
-  }
-
-  @each $name, $value in tokens.$shadow {
-    --fox-shadow-#{$name}: #{$value};
-  }
-
-  @each $name, $value in tokens.$duration {
-    --fox-duration-#{$name}: #{$value};
-  }
-
-  @each $name, $value in tokens.$easing {
-    --fox-easing-#{$name}: #{$value};
-  }
-
-  @each $name, $value in tokens.$font-family {
-    --fox-font-#{$name}: #{$value};
-  }
-
-  @each $name, $value in tokens.$font-weight {
-    --fox-weight-#{$name}: #{$value};
-  }
-
-  @each $name, $value in tokens.$z {
-    --fox-z-#{$name}: #{$value};
-  }
-
-  // 브레이크포인트는 **미디어 쿼리에서 쓸 수 없다** — 조건부는 `var()`를 해석하지
-  // 않는다. 그럼에도 내보내는 이유는 컨테이너 `max-width`처럼 선언부에서 같은 값을
-  // 참조할 일이 있고, 카탈로그가 토큰 목록을 CSSOM에서 읽기 때문이다.
-  // 미디어 쿼리는 언제나 `fox.media()` 믹스인을 쓴다.
-  @each $name, $value in tokens.$breakpoint {
-    --fox-breakpoint-#{$name}: #{$value};
-  }
-
-  // 타이포 프리셋은 한 이름당 4개의 프로퍼티로 펼쳐진다 — `fox.typo()` 믹스인이
-  // 이 네 개를 함께 참조한다.
-  @each $name, $preset in tokens.$typo {
-    --fox-typo-#{$name}-size: #{map.get($preset, size)};
-    --fox-typo-#{$name}-weight: #{map.get($preset, weight)};
-    --fox-typo-#{$name}-line-height: #{map.get($preset, line-height)};
-    --fox-typo-#{$name}-letter-spacing: #{map.get($preset, letter-spacing)};
-  }
-}
-
-// 수동 테마 선택 — `color-scheme`만 고정하면 `light-dark()`가 해당 분기로 확정된다.
-// 색상 값을 여기서 재정의하지 않으므로 라이트/다크 값이 어긋날 수 없다.
-// 속성이 없거나 `"system"`이면 위 `:root`의 `light dark`가 유지되어 OS를 따른다.
-:root[data-theme="light"] {
-  color-scheme: light;
-}
-
-:root[data-theme="dark"] {
-  color-scheme: dark;
-}
-
-// 테마 전환 애니메이션 — 호스트 앱이 토글 직전 `<html>`에 `[data-theme-transition]`을
-// 부여하고 ~200ms 후 제거하는 **시간 한정 opt-in**이다. 상시 트랜지션이 아니므로
-// 다른 hover 트랜지션과 경쟁하지 않는다.
-// `prefers-reduced-motion` 게이팅으로 감소 모션 환경에서는 즉시 반영된다.
-// `!important`는 이 200ms 동안만 존재하는 규칙이 컴포넌트의 transition 선언에
-// 밀리지 않게 하기 위한 것이다.
-@media (prefers-reduced-motion: no-preference) {
-  html[data-theme-transition],
-  html[data-theme-transition] *,
-  html[data-theme-transition] *::before,
-  html[data-theme-transition] *::after {
-    transition:
-      background-color var(--fox-duration-base) var(--fox-easing-out),
-      border-color var(--fox-duration-base) var(--fox-easing-out),
-      color var(--fox-duration-base) var(--fox-easing-out),
-      fill var(--fox-duration-base) var(--fox-easing-out),
-      stroke var(--fox-duration-base) var(--fox-easing-out),
-      outline-color var(--fox-duration-base) var(--fox-easing-out) !important;
-  }
-}
 
@fox/styles/abstracts.scss (deleted)
--- @fox/styles/abstracts.scss
@@ -1,22 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 저작(authoring) 진입점 — 컴포넌트의 `.module.scss`가 `@use`하는 파일.
-//
-//   @use "@fox/styles/abstracts" as fox;
-//
-//   .button {
-//     padding: fox.space(2) fox.space(4);
-//     background: fox.color(primary);
-//     border-radius: fox.radius(md);
-//     @include fox.typo(label-lg);
-//     @include fox.focus-ring;
-//   }
-//
-// ⚠️ **이 파일은 CSS를 한 줄도 출력하지 않는다.** 함수·믹스인·map 정의만 있다.
-// CSS Module은 파일마다 별도 컴파일 단위라, CSS를 출력하는 모듈을 여기서 forward하면
-// 컴포넌트 수만큼 같은 CSS가 복제된다. 실제 CSS 출력(토큰 선언·리셋)은 앱이 딱 한 번
-// import하는 `index.scss`가 전담한다.
-// ─────────────────────────────────────────────────────────────────────────────
-
-@forward "tokens";
-@forward "functions";
-@forward "mixins";
@fox/styles/index.scss
--- @fox/styles/index.scss
+++ @fox/styles/index.scss
@@ -1,13 +1,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 글로벌 스타일 진입점 — **호스트 앱이 딱 한 번 import한다.**
-//
-//   // app/globals.scss
-//   @use "@fox/styles";
-//
-// 여기서만 CSS가 출력된다(토큰 선언 + 리셋). 컴포넌트의 `.module.scss`는 이 파일이
-// 아니라 `abstracts.scss`를 `@use`해야 한다 — 그쪽은 CSS 출력이 0이라 몇 번을
-// 참조해도 중복이 생기지 않는다.
-// ─────────────────────────────────────────────────────────────────────────────
-
-@use "root";
-@use "reset";
 
@fox/styles/tokens/_color.scss (deleted)
--- @fox/styles/tokens/_color.scss
@@ -1,61 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 색상 토큰
-//
-// 이 map이 단일 진실 공급원(SSOT)이다. 여기서 두 가지가 함께 파생된다:
-//   1. `_root.scss` → `--fox-color-*` CSS 커스텀 프로퍼티 선언
-//   2. `_functions.scss`의 `color()` → 토큰 이름 유효성 컴파일타임 검증
-// 값과 이름 목록이 한 파일에만 존재하므로 둘 사이의 드리프트가 구조적으로 불가능하다.
-//
-// 라이트/다크는 `light-dark(라이트값, 다크값)` 한 줄로 함께 보유한다. 테마 전환은
-// `_root.scss`의 `color-scheme`이 담당하므로 다크 전용 블록을 따로 두지 않는다 —
-// 한쪽만 고쳐서 생기는 테마 불일치가 애초에 발생할 수 없다.
-//
-// 브라우저 지원: `light-dark()` 자체는 Chrome 123 / Safari 17.5 / Firefox 120 이상이
-// 필요하지만, Next.js 16(Turbopack)의 Lightning CSS가 현재 설정에서 이를
-// `var(--lightningcss-light, 라이트) var(--lightningcss-dark, 다크)` 조합으로 **폴리필**해
-// 출력하므로 구형 브라우저에서도 동작한다(2026-08-11 빌드 산출물에서 확인).
-// browserslist 타깃을 최신 브라우저로 좁히면 폴리필이 빠지고 원본 `light-dark()`가
-// 그대로 나가므로, 타깃을 바꿀 때 이 전제를 다시 확인한다.
-//
-// ⚠️ 아래 값은 전부 **임시 플레이스홀더**다. 파이프라인 검증과 /design 카탈로그
-// 렌더를 위한 중립 팔레트이며, 실제 브랜드 값은 사용자 제공 Figma/파일로 교체한다.
-// 교체 시 이 파일의 값만 바꾸면 앱 전체에 반영된다.
-// ─────────────────────────────────────────────────────────────────────────────
-
-$color: (
-  // 브랜드
-  primary: light-dark(#4f46e5, #818cf8),
-  primary-hover: light-dark(#4338ca, #a5b4fc),
-  primary-subtle: light-dark(#eef2ff, #312e81),
-  on-primary: light-dark(#ffffff, #1e1b34),
-
-  // 표면 — background(페이지 바닥) < surface(카드) < surface-raised(팝오버 등)
-  background: light-dark(#ffffff, #14161b),
-  surface: light-dark(#ffffff, #1e2128),
-  surface-muted: light-dark(#f5f7fa, #262a33),
-  surface-raised: light-dark(#ffffff, #2c3038),
-
-  // 전경(텍스트·아이콘)
-  foreground: light-dark(#1f2430, #f5f7fa),
-  foreground-muted: light-dark(#565d6b, #bbc4d8),
-  foreground-subtle: light-dark(#8790a3, #8790a3),
-  foreground-inverse: light-dark(#ffffff, #14161b),
-
-  // 경계선
-  border: light-dark(#dae0ed, #424752),
-  border-subtle: light-dark(#eaeef6, #2f343d),
-  border-strong: light-dark(#b6bfd2, #5a616e),
-
-  // 상태 — 각 상태색 위에 얹는 텍스트색을 on-* 로 함께 정의한다.
-  danger: light-dark(#dc2626, #f87171),
-  on-danger: light-dark(#ffffff, #1a0d0d),
-  success: light-dark(#16a34a, #4ade80),
-  on-success: light-dark(#ffffff, #0a1a10),
-  warning: light-dark(#d97706, #fbbf24),
-  on-warning: light-dark(#ffffff, #1a1205),
-  info: light-dark(#0284c7, #38bdf8),
-  on-info: light-dark(#ffffff, #05161f),
-
-  // 오버레이
-  scrim: light-dark(rgb(0 0 0 / 0.5), rgb(0 0 0 / 0.65))
-);
 
@fox/styles/tokens/_index.scss (deleted)
--- @fox/styles/tokens/_index.scss
@@ -1,13 +0,0 @@
-// 토큰 map 모음 진입점 — **CSS를 한 줄도 출력하지 않는다.**
-// 값 선언(이 폴더)과 CSS 출력(`../_root.scss`)을 분리해 두었기 때문에, 컴포넌트의
-// `.module.scss`가 몇 개든 `abstracts`를 `@use`해도 `:root` 블록이 중복 출력되지
-// 않는다(각 CSS Module은 별도 컴파일 단위라 CSS를 내보내는 모듈을 공유하면
-// 파일마다 같은 CSS가 복제된다).
-
-@forward "color";
-@forward "space";
-@forward "typography";
-@forward "radius";
-@forward "shadow";
-@forward "motion";
-@forward "layout";
 
@fox/styles/tokens/_layout.scss (deleted)
--- @fox/styles/tokens/_layout.scss
@@ -1,41 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 레이아웃 토큰 — 브레이크포인트와 z-index 층.
-// ─────────────────────────────────────────────────────────────────────────────
-
-// 브레이크포인트는 이 파일에서 **유일하게 CSS 커스텀 프로퍼티로 내보내지 않는
-// 토큰**이다. 미디어 쿼리 조건부는 `var()`를 해석하지 않기 때문에
-// (`@media (min-width: var(--x))`는 무효), 컴파일타임 SCSS 값이어야만 한다.
-// 그래서 브레이크포인트 사용은 `fox.media()` 믹스인 경유가 강제된다.
-//
-// ⚠️ **미디어 쿼리 안의 `rem`은 브라우저 기본 글자 크기(보통 16px) 기준이다.**
-// `html { font-size: 62.5% }`의 영향을 받지 않으므로, 다른 토큰의 "1rem = 10px"
-// 규칙이 여기서는 적용되지 않는다. 아래 px 환산을 반드시 함께 본다.
-// rem으로 두는 이유: 사용자가 브라우저 글자 크기를 키우면 브레이크포인트도 함께
-// 커져 확대 환경에서 레이아웃이 더 일찍 접힌다(px 고정은 이 대응이 불가능하다).
-$breakpoint: (
-  sm: 40rem,
-  // 640px
-  md: 48rem,
-  // 768px
-  lg: 64rem,
-  // 1024px
-  xl: 80rem,
-  // 1280px
-  2xl: 96rem
-  // 1536px
-);
-
-// z-index 층 — 숫자를 화면에서 직접 고르지 않게 하려는 토큰이다. 값 사이를 100씩
-// 띄워 둔 것은 나중에 층 사이에 새 층을 끼워 넣을 여지를 남기기 위함이다.
-$z: (
-  base: 0,
-  raised: 100,
-  sticky: 200,
-  dropdown: 300,
-  scrim: 400,
-  modal: 500,
-  popover: 600,
-  toast: 700,
-  tooltip: 800,
-  splash: 900
-);
 
@fox/styles/tokens/_motion.scss (deleted)
--- @fox/styles/tokens/_motion.scss
@@ -1,26 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 모션 토큰 — 지속시간과 이징.
-// 이징은 "어느 방향으로 움직이는가"로 이름 붙인다: 화면에 들어올 때는 감속(out),
-// 나갈 때는 가속(in), 제자리에서 상태만 바뀔 때는 in-out.
-//
-// 실제 트랜지션·애니메이션은 `_mixins.scss`의 `transition()` / `animate()`를 쓴다 —
-// 두 믹스인 모두 `prefers-reduced-motion` 분기를 내장하고 있어 감소 모션 환경
-// 대응을 화면마다 되풀이할 필요가 없다.
-// ─────────────────────────────────────────────────────────────────────────────
-
-$duration: (
-  instant: 0ms,
-  fast: 120ms,
-  base: 200ms,
-  slow: 300ms,
-  slower: 500ms
-);
-
-$easing: (
-  linear: linear,
-  in: cubic-bezier(0.4, 0, 1, 1),
-  out: cubic-bezier(0, 0, 0.2, 1),
-  in-out: cubic-bezier(0.4, 0, 0.2, 1),
-  // 살짝 오버슈트 — 토글·체크 같은 작은 확인 동작에.
-  spring: cubic-bezier(0.34, 1.56, 0.64, 1)
-);
 
@fox/styles/tokens/_radius.scss (deleted)
--- @fox/styles/tokens/_radius.scss
@@ -1,17 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 모서리 반경 토큰 — 1rem = 10px 기준.
-// `full`은 pill 형태(캡슐 버튼·뱃지)를 위한 값으로, 높이보다 크기만 하면 되므로
-// 임의의 큰 값을 쓴다.
-// ⚠️ 값은 임시 플레이스홀더 — Figma 확정 시 교체.
-// ─────────────────────────────────────────────────────────────────────────────
-
-$radius: (
-  none: 0,
-  xs: 0.4rem,
-  sm: 0.6rem,
-  md: 0.8rem,
-  lg: 1.2rem,
-  xl: 1.6rem,
-  2xl: 2.4rem,
-  full: 999rem
-);
 
@fox/styles/tokens/_shadow.scss (deleted)
--- @fox/styles/tokens/_shadow.scss
@@ -1,18 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 그림자 토큰 — 고도(elevation)를 역할 이름으로 표현한다.
-// 크기(sm/md/lg)가 아니라 쓰임(card/dialog/…)으로 이름 붙이면 "이 요소는 어느
-// 층에 뜨는가"가 코드에 드러나고, 나중에 값이 바뀌어도 의미가 유지된다.
-//
-// 그림자는 라이트/다크에서 같은 값을 쓰지 않는 편이 자연스럽다(어두운 배경에서는
-// 그림자가 거의 보이지 않는다). 필요해지면 여기서 `light-dark()`로 분기한다.
-// ⚠️ 값은 임시 플레이스홀더 — Figma 확정 시 교체.
-// ─────────────────────────────────────────────────────────────────────────────
-
-$shadow: (
-  none: none,
-  card: light-dark(0 0.1rem 0.3rem rgb(16 24 40 / 0.08), 0 0.1rem 0.3rem rgb(0 0 0 / 0.4)),
-  raised: light-dark(0 0.4rem 0.8rem rgb(16 24 40 / 0.1), 0 0.4rem 0.8rem rgb(0 0 0 / 0.45)),
-  popup: light-dark(0 0.8rem 1.6rem rgb(16 24 40 / 0.12), 0 0.8rem 1.6rem rgb(0 0 0 / 0.5)),
-  dialog: light-dark(0 1.6rem 3.2rem rgb(16 24 40 / 0.16), 0 1.6rem 3.2rem rgb(0 0 0 / 0.55)),
-  toast: light-dark(0 1rem 2rem rgb(16 24 40 / 0.18), 0 1rem 2rem rgb(0 0 0 / 0.6))
-);
 
@fox/styles/tokens/_space.scss (deleted)
--- @fox/styles/tokens/_space.scss
@@ -1,29 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 간격 토큰 (4/8 grid)
-//
-// **모든 치수는 rem 기준이며 `1rem = 10px`이다** (`_reset.scss`의
-// `html { font-size: 62.5% }`). px → rem 환산이 10으로 나누기라 암산이 되고,
-// 사용자가 브라우저 기본 글자 크기를 키우면 레이아웃 전체가 함께 확대된다
-// (px 고정과 달리 접근성 설정을 존중한다).
-//
-// 키는 4px 배수 단위다 — `space(4)` = 16px. 임의 값이 필요해 보이면 스케일에
-// 단계를 추가할 일인지 먼저 검토한다(§10.4).
-// ─────────────────────────────────────────────────────────────────────────────
-
-$space: (
-  0: 0,
-  1: 0.4rem,
-  2: 0.8rem,
-  3: 1.2rem,
-  4: 1.6rem,
-  5: 2rem,
-  6: 2.4rem,
-  8: 3.2rem,
-  10: 4rem,
-  12: 4.8rem,
-  16: 6.4rem,
-  20: 8rem,
-  24: 9.6rem
-);
-// 키 → px 환산: 1=4 · 2=8 · 3=12 · 4=16 · 5=20 · 6=24 · 8=32 · 10=40 · 12=48 ·
-// 16=64 · 20=80 · 24=96
 
@fox/styles/tokens/_typography.scss (deleted)
--- @fox/styles/tokens/_typography.scss
@@ -1,52 +0,0 @@
-// ─────────────────────────────────────────────────────────────────────────────
-// 타이포그래피 토큰
-//
-// 폰트 패밀리는 **호스트 앱이 주입하는 계약**이다 — `@fox`는 `--app-font-sans` /
-// `--app-font-mono`를 참조만 하고 폰트 파일을 소유하지 않는다. Next.js는 `next/font`가
-// 앱의 layout에서 CSS 변수를 만들어 주므로(폰트 최적화·자체 호스팅이 앱 책임),
-// `@fox` 폴더를 다른 프로젝트로 복사해도 그 프로젝트의 폰트를 그대로 따른다.
-// 미주입 시에도 깨지지 않도록 `var()` 폴백을 반드시 둔다 — 폴백 없는 `var()`가
-// undefined면 font-family 선언 전체가 무효가 된다.
-//
-// 개별 스칼라(size/weight/…)보다 **프리셋(`$typo`)을 우선 사용**한다. 크기·행간·
-// 자간·굵기는 함께 움직여야 의도한 타이포가 되므로, 화면에서 넷을 따로 고르게 두면
-// 조합이 무한히 갈라진다. `@include fox.typo(title-md)` 한 줄로 넷이 함께 적용된다.
-//
-// ⚠️ 아래 값·이름은 임시 플레이스홀더다. 실제 타입 스케일은 Figma 확정 시 교체한다.
-// ─────────────────────────────────────────────────────────────────────────────
-
-$font-family: (
-  sans: (var(--app-font-sans, system-ui), "Apple SD Gothic Neo", sans-serif),
-  mono: (var(--app-font-mono, ui-monospace), monospace)
-);
-
-$font-weight: (
-  regular: 400,
-  medium: 500,
-  semibold: 600,
-  bold: 700
-);
-
-// 타이포 프리셋 — size / line-height / weight / letter-spacing 4종을 한 묶음으로.
-// 1rem = 10px 기준이므로 1.6rem = 16px.
-$typo: (
-  display-lg: (size: 4.8rem, line-height: 1.2, weight: 700, letter-spacing: -0.02em),
-  display-md: (size: 4rem, line-height: 1.2, weight: 700, letter-spacing: -0.02em),
-  display-sm: (size: 3.2rem, line-height: 1.25, weight: 700, letter-spacing: -0.02em),
-
-  headline-lg: (size: 2.8rem, line-height: 1.3, weight: 700, letter-spacing: -0.015em),
-  headline-md: (size: 2.4rem, line-height: 1.35, weight: 700, letter-spacing: -0.015em),
-  headline-sm: (size: 2rem, line-height: 1.4, weight: 700, letter-spacing: -0.01em),
-
-  title-lg: (size: 1.8rem, line-height: 1.45, weight: 600, letter-spacing: -0.01em),
-  title-md: (size: 1.6rem, line-height: 1.5, weight: 600, letter-spacing: 0),
-  title-sm: (size: 1.4rem, line-height: 1.5, weight: 600, letter-spacing: 0),
-
-  body-lg: (size: 1.6rem, line-height: 1.6, weight: 400, letter-spacing: 0),
-  body-md: (size: 1.4rem, line-height: 1.6, weight: 400, letter-spacing: 0),
-  body-sm: (size: 1.2rem, line-height: 1.55, weight: 400, letter-spacing: 0),
-
-  label-lg: (size: 1.4rem, line-height: 1.4, weight: 600, letter-spacing: 0),
-  label-md: (size: 1.3rem, line-height: 1.4, weight: 500, letter-spacing: 0),
-  label-sm: (size: 1.2rem, line-height: 1.35, weight: 500, letter-spacing: 0.01em)
-);
Add a comment
List