# SCSS Helpers

`@orioncactuscorp/ui`가 SCSS source로 제공하는 consumer용 mixin/function입니다. 각 모듈은 `@orioncactuscorp/ui/scss/*` subpath로 import하고, `@use ... as *;` 형태를 사용합니다.

```scss
@use '@orioncactuscorp/ui/scss/mixins/element' as *;
@use '@orioncactuscorp/ui/scss/mixins/breakpoint' as *;
```

> `@orioncactuscorp/ui/scss/index.scss` 통합 entry는 mixin뿐 아니라 **foundation CSS(토큰 + reset)를 함께 방출**합니다. `foundations.css`를 이미 import하고 있다면 토큰이 중복 방출되므로, mixin/function만 필요할 때는 위처럼 개별 mixin 모듈을 import하세요. 통합 entry는 prebuilt `foundations.css` 대신 SCSS foundation source를 직접 compile하는 경로에서만 사용합니다.

이 문서에 있는 helper가 공개 계약입니다. 문서화되지 않은 export는 내부 구현이며 예고 없이 바뀔 수 있습니다([Stability Policy](./stability.md)).

## oc-border — layout에 영향 없는 surface stroke

`@orioncactuscorp/ui/scss/mixins/element`

실제 CSS `border` 대신 `box-shadow`로 stroke를 그립니다. 요소의 content/padding/layout 크기를 바꾸지 않습니다.

```scss
@include oc-border($tokens...);
```

CSS `border` shorthand와 비슷하게 토큰을 순서 무관하게 나열합니다.

| 토큰      | 값                                                  | 기본값         | 비고                                                                   |
| --------- | --------------------------------------------------- | -------------- | ---------------------------------------------------------------------- |
| width     | number (1개)                                        | `1px`          | `1.5px` 같은 half-pixel은 WebKit/DPR 보정 출력 포함                    |
| color     | color, `var(...)` (1개)                             | `currentColor` |                                                                        |
| side      | `top`, `right`, `bottom`, `left` (복수 가능), `all` | `all`          | 개별 side는 해당 방향 단일 stroke                                      |
| placement | `inset`, `outer`                                    | `inset`        | `outer`는 요소 바깥에 그림 (역시 layout 무영향)                        |
| style     | `solid`                                             | -              | CSS shorthand 익숙함을 위해 수용만 함 (box-shadow stroke는 항상 solid) |

```scss
.surface {
  @include oc-border; // 1px currentColor inset
}

.surfaceAccent {
  @include oc-border(var(--oc-color-theme-primary-normal));
}

.surfaceInvalid {
  @include oc-border(1.5px, var(--oc-color-theme-status-negative));
}

.underline {
  @include oc-border(bottom); // 아래쪽만
}

.focusRing {
  @include oc-border(2px, var(--oc-color-theme-primary-normal), outer);
}
```

`box-shadow` 한 채널을 사용하므로, 같은 요소에서 다른 `box-shadow`와 함께 쓸 때는 직접 shadow 목록을 조합해야 합니다.

## oc-radius — 전역 radius factor 연동

`@orioncactuscorp/ui/scss/mixins/radius`

```scss
oc-radius($radius, $factor-token: var(--oc-atomic-radius-factor))
```

`rem`/`em`/`px`/`clamp(...)` 기반 radius 값을 전역 radius factor에 연결합니다. `--oc-atomic-radius-factor`를 `0`으로 두면 이 helper를 거친 컴포넌트 로컬 radius도 함께 각지게 됩니다.

```scss
@use '@orioncactuscorp/ui/scss/mixins/radius' as *;

.badge {
  --oc-badge-radius: #{oc-radius(0.4em)};
}
```

## oc-focus-ring — 키보드 포커스 ring

`@orioncactuscorp/ui/scss/mixins/focus`

```scss
oc-focus-ring($color: var(--oc-color-theme-focus-ring), $width: var(--oc-focus-ring-width), $offset: var(--oc-focus-ring-offset))
```

`:focus-visible` ring을 foundation 토큰으로 그립니다. `outline` 기반이라 layout에 영향이 없고 요소의 border-radius를 그대로 따라가며 forced-colors 모드에서도 유지됩니다. reset 레이어가 `button`/`a[href]`/`summary`/`[tabindex]`에 같은 ring을 전역 기본값으로 제공하므로, 이 믹스인은 `all: unset`을 쓰는 요소나 ring을 다른 요소로 리다이렉트하는 경우(예: 선택 컨트롤의 wrapper)에 사용합니다.

```scss
@use '@orioncactuscorp/ui/scss/mixins/focus' as *;

.trigger {
  all: unset;

  &:focus-visible {
    @include oc-focus-ring;
  }
}
```

## oc-alpha — 토큰 기반 알파 색상

`@orioncactuscorp/ui/scss/mixins/color`

```scss
oc-alpha($color, $opacity)
```

`color-mix(in srgb, ...)`로 알파가 적용된 색을 만듭니다. runtime CSS 변수 색상에도 알파를 적용할 수 있다는 점이 Sass `rgba()`와의 차이입니다.

- `$color`: Sass color, `var(...)`, 또는 global color 토큰 suffix (`--oc-color-global-` 뒤 이름)
- `$opacity`: `0`~`1` 숫자, 또는 global opacity 토큰 suffix (`--oc-color-global-opacity-` 뒤 이름)

```scss
@use '@orioncactuscorp/ui/scss/mixins/color' as *;

.scrim {
  background-color: oc-alpha(var(--oc-color-theme-primary-normal), 0.4);
}
```

## typo — typography 토큰 조합

`@orioncactuscorp/ui/scss/mixins/typo`

```scss
@include typo($variant, $weight: normal);
```

`font-size`, `line-height`, `letter-spacing`, `font-weight`를 `--oc-typo-*` 토큰에서 한 번에 출력합니다. raw `var(--oc-typo-size-*)` 직접 참조 대신 이 mixin을 사용하세요 — `--oc-typo-size-factor` runtime multiplier가 자동 반영됩니다.

- `$variant`: foundation typo variant 이름 (`title1`, `body1` 등 — 역할과 기본값은 [Typography](./typography.md))
- `$weight`: `normal` | `medium` | `bold`

19개 variant는 모두 `normal | medium | bold`를 제공하며, 의미상 같은 weight라도 작은 계층에서 숫자가 단계적으로 낮아집니다. 전체 weight·responsive stop 표는 [Typography](./typography.md)를 참조하세요.

```scss
@use '@orioncactuscorp/ui/scss/mixins/typo' as *;

.heading {
  @include typo(title2, bold);
}
```

## respond-to — breakpoint media query

`@orioncactuscorp/ui/scss/mixins/breakpoint`

```scss
@include respond-to($bp1, $bp2: null) { ... }
```

named breakpoint: `sm`(480px), `md`(768px), `lg`(1280px), `xl`(1600px), `hg`(1920px). `@use ... with ($breakpoint-md: 800px)`로 override할 수 있습니다.

| 호출                                                 | 출력 media                                                    | 용도                                 |
| ---------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------ |
| `respond-to(sm)`, `respond-to(md)`                   | `(max-width: bp)`                                             | 좁은 viewport 예외 보정              |
| `respond-to(lg)`, `respond-to(xl)`, `respond-to(hg)` | `(min-width: bp + 1px)`                                       | 넓은 viewport 확장                   |
| `respond-to(min, $bp)`                               | `(min-width: bp + 1px)` (named) / `(min-width: 값)` (직접 값) | mobile-first progressive enhancement |
| `respond-to(max, $bp)`                               | `(max-width: bp)`                                             | 상한                                 |
| `respond-to($bp1, $bp2)`                             | `(min-width: 작은쪽 + 1px) and (max-width: 큰쪽)`             | 구간                                 |

직접 숫자 값(`respond-to(min, 900px)`)도 받습니다. raw `@media (min-width: ...)` 대신 항상 이 mixin을 사용하세요.

oc-ui SCSS는 mobile-first가 기본입니다: base rule은 narrow viewport 기준으로 쓰고, desktop 이상 차이는 `respond-to(min, md)`에서 더합니다. `respond-to(md)`(max-width)는 `Mobile(md)` 전용 예외 보정에만 사용합니다.

## fluidClamp / toRem — fluid 값 유틸

`@orioncactuscorp/ui/scss/mixins/utils`

```scss
fluidClamp($from, $bp, $anchor: to, $to)
```

`clamp($from, <viewport 비례식>, $to)`를 출력합니다. `$bp`는 기준 breakpoint(px), `$anchor`는 비례식이 어느 끝값에 정렬될지(`to` 기본, `from` 선택)입니다. foundation typo/space 토큰의 fluid 출력에 쓰이는 것과 같은 helper로, 커스텀 fluid 값을 만들 때 사용합니다.

```scss
@use '@orioncactuscorp/ui/scss/mixins/utils' as *;

.hero {
  padding-block: fluidClamp(toRem(24), 1280, to, toRem(64));
}
```

`toRem($px)`는 `16px = 1rem` 기준으로 숫자를 rem으로 변환합니다.

## Motion / Spring

transition·animation helper(`oc-motion`, `oc-spring`)는 별도 가이드를 참조하세요.

- [Semantic Motion](./motion.md) — intent/phase/pace 기반 motion 계약
- [Spring Motion](./spring.md) — iOS perceptual duration 기반 spring transition
