# Changelog

## 1.25.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.25.0-next.0..HEAD`_

#### Other

- `2d748e5` 메뉴 표면 경계 밖 넘침 클리핑 수정 (#495)
- `2a50d3c` 둥근 표면 안 ScrollArea 스크롤바의 모서리 곡선 회피 (#496)
- `c75ca61` Reveal 진입 정책 통일과 본문·카드 영역 분리 (#497)
<!-- generated:end -->

### Minor Changes

- c75ca61: Reveal과 RevealGroup의 기본 in-view 진입 시점을 viewport 높이 60%로 통일하고 ScrollArea 내부 스크롤 영역에 자동 적용합니다. iframe에서도 콘텐츠가 속한 문서 기준을 유지합니다. 도달 불가능한 시작점에서는 콘텐츠를 즉시 표시하고, 자동 등장 중 설정 변경으로 재시작하지 않습니다. reduced-motion에서는 지연 없이 짧은 opacity 전환을 사용합니다.

  Migration Notes:

  `1.25.0-next.0` 대비 단독 Reveal과 RevealGroup, 해당 토큰을 참조하는 소비자 모두 기본 등장 시간이 1,000ms에서 600ms로 변경됩니다.

  RevealGroup의 Content와 Items는 각자의 60% 진입선을 기준으로 시작합니다. Items는 본문 이후 최소 여백도 충족해야 시작하며, 화면 아래에서 시차를 미리 소진하지 않습니다. Group의 contentGap 기본값은 400ms에서 80ms로 줄이고 카드 간격인 stagger는 160ms를 유지합니다. threshold를 생략한 단독 Reveal의 기존 15% 면적 교차 기준이 60% 높이 기준으로 바뀝니다. 명시한 threshold는 기존 면적 모드를 유지하며 Provider.threshold는 호환을 위해 보존하되 deprecated입니다. Provider에 명시한 trigger는 Group에도 적용되므로 Group만 별도 동작이 필요하면 인스턴스에서 trigger를 지정하세요. timing.contentGap과 timing.stagger도 duration처럼 pace와 전역 duration factor를 곱합니다. 명시한 timing 값은 normal pace와 전역 factor 1에서 동일하게 적용됩니다.

- 2a50d3c: 둥근 표면을 채우는 ScrollArea의 스크롤바가 모서리 곡선을 피해 시작하고 끝나도록 `--oc-scroll-area-radius`를 추가합니다. 스크롤바와 곡선 사이 간격은 옆면 간격(`--oc-scroll-area-padding`)과 같게 유지하며, header·footer chrome이 모서리를 덮으면 기존 chrome 위치를 그대로 씁니다. Menu와 popup Modal은 내부에서 표면 반경을 전달하므로 헤더·푸터가 없는 쪽의 스크롤바가 짧아집니다.

  `oc-corner-inset($outer-radius, $radius, $gap: 0px)` SCSS 함수를 `scss/mixins/radius`에 추가합니다. `oc-inner-radius`의 반대 방향으로, 둥근 컨테이너 안에서 자기 반경이 있는 요소가 모서리 곡선과 일정 간격을 유지하는 위치를 계산합니다.

  Migration Notes
  - 없음. `--oc-scroll-area-radius` 기본값은 `0`이라 직접 쓰는 ScrollArea의 스크롤바 위치는 바뀌지 않습니다.
  - 둥근 카드를 꽉 채우는 ScrollArea에 보정을 적용하려면 그 ScrollArea 자신에 `--oc-scroll-area-radius`를 지정합니다. 조상 요소에 지정하면 상속되지 않습니다.

- 3a8fa9a: `ActionAreaLayout` footer 배경을 스크롤 상태에 따라 켜고 끄던 방식에서, footer가 항상 그리는 `ScrollAreaEdge`로 바꿉니다. 끝에서 빠르게 위로 스크롤할 때 배경이 돌아오기 전에 버튼 밑으로 콘텐츠가 비치던 문제를 없앱니다.
  - `ActionAreaLayout.Footer`가 마지막 자식으로 `ScrollAreaEdge`(`data-oc-part="scroll-edge"`)를 그립니다. 버튼 영역은 항상 덮고, 위쪽 padding 구간에서 서서히 사라지며, 아래에 남은 콘텐츠 거리만큼만 0부터 이어서 위로 번집니다. 스크롤 중 렌더링은 일어나지 않습니다.
  - `ActionAreaLayout.Footer`에 `scrollEdgeVariant="auto | none | fade | progressive-blur"`(기본 `auto`: `scroll="document"`는 `fade`, `contained`는 `none`)와 `scrollEdgeAppearance="soft | hard"`(기본 `soft`)를 추가합니다. `ModalFooter`와 같은 축에 레이아웃 스크롤 방식을 따르는 `auto`를 더했습니다. `hard`이면 아래에 콘텐츠가 남은 동안 `data-oc-part="scroll-edge-divider"` 구분선이 보이고, footer에 `data-oc-overflow-y-end`가 붙습니다. 구분선은 `divider="normal | neutral | alternative | none"`(기본 `normal`, `ModalFooter`와 같은 축)로 정합니다. `ActionAreaLayoutFooterScrollEdgeVariant` 타입을 추가합니다.
  - footer의 직속 `ActionArea`가 비어 있으면 edge를 그리지 않습니다. `extraContent`는 예외 없이 같은 규칙을 따릅니다.
  - `scroll="document"`의 번짐 거리는 레이아웃 콘텐츠 끝에서 footer 아래 끝까지로 잽니다. 레이아웃을 담은 어떤 스크롤 컨테이너에도 반응합니다.
  - footer 안의 `ActionArea`는 스크롤 여부와 관계없이 위쪽 padding을 유지합니다. 스크롤될 때 그 padding을 body 아래 여백으로 옮기던 동작을 제거합니다.
  - 단독 `ActionArea`의 `background`는 자기 영역을 단색으로 채우는 것으로 바뀝니다. 위쪽으로 번지던 고정 그라디언트는 제거됩니다.
  - `contained`에서는 body가 footer 위에서 끝나므로 콘텐츠가 footer 밑으로 지나가지 않습니다. 이 점은 `document`와 다릅니다.
  - `ActionArea`가 `caption`과 `actions`(또는 `compact-row`)를 새 `data-oc-part="action-group"`으로 묶습니다. 간격은 margin 대신 flex `gap`으로 정합니다. extra와 묶음 사이는 `--oc-action-area-gap`, caption과 버튼 사이는 `--oc-space-item-gap-medium`입니다.

  Migration Notes
  - `ActionAreaLayout.ActionArea`의 `background` prop을 제거합니다. `background="auto"`와 `background`(`true`)는 지우면 됩니다. `scroll="document"`에서는 `fade` edge가 기본이고, `contained`에서는 body가 bar 위에서 끝나므로 기본으로 edge를 그리지 않습니다. contained에서 스크롤 중 bar 위 번짐을 유지하려면 Footer에 `scrollEdgeVariant="fade"`를 지정합니다. `background={false}`는 `<ActionAreaLayout.Footer scrollEdgeVariant="none">`으로 옮깁니다. `ActionAreaLayoutActionAreaBackground` 타입을 제거합니다.
  - footer 배경색은 `--oc-action-area-background-color`를 `ActionAreaLayout.Footer`나 그 조상에 지정합니다. layout 안의 `ActionArea`에 지정한 값은 footer 배경에 닿지 않습니다. internal이던 `--oc-action-area-layout-background-color`, `--oc-action-area-layout-gradient-overlap`, `--oc-action-area-layout-gradient-size`, `--oc-action-area-layout-body-padding-block-end`, `--oc-action-area-background-bleed`, `--oc-action-area-background-gradient-size`를 제거합니다.
  - `data-oc-background="true"`는 이제 단독 `ActionArea`의 고정 채우기만 뜻합니다. layout footer의 `ActionArea`에는 붙지 않습니다. 스크롤 상태 판단에는 footer의 `data-oc-overflow-y-end`를 씁니다.
  - `data-oc-scrollable="true"`일 때 footer `ActionArea`가 `--oc-action-area-padding-block-start: 0`을 받고 body가 아래 여백을 갖던 규칙을 제거합니다. 이 동작에 맞춘 스타일이 있다면 지웁니다.
  - 단독 `ActionArea`를 `absolute`나 `fixed`로 띄우고 `background`로 스크롤 콘텐츠를 가리던 경우, 위쪽 그라디언트가 사라집니다. 같은 모습을 내는 대체는 없으며, 스크롤 콘텐츠 위의 bar는 `ActionAreaLayout`(고정 높이 영역은 `contained`, 페이지 스크롤은 `scroll="document"`)이나 `ScrollArea`의 `ScrollAreaEdge` 패턴으로 옮깁니다.
  - `extraContent`가 있는 `ActionArea`의 불투명 배경과 위쪽 테두리를 제거합니다. `background`와 footer edge가 다른 경우와 같은 규칙으로 정합니다. 단단한 경계와 구분선이 필요하면 `ActionAreaLayout.Footer`에 `scrollEdgeAppearance="hard"`를, 단독 `ActionArea`에는 `background`와 직접 둔 `Divider`를 씁니다. `ModalFooter`·`FloatingWindowFooter` 안의 extra `ActionArea`도 불투명하지 않게 되어 footer 자체 edge가 보입니다.
  - `ActionAreaLayoutScrollState` 타입은 더 이상 쓰이지 않아 deprecated로 표시합니다.
  - `caption`, `actions`, `compact-row`는 이제 `ActionArea` 루트의 직속 자식이 아니라 `data-oc-part="action-group"` 안에 있습니다. 직속 자식 선택자(`[data-oc-component="action-area"] > [data-oc-part="actions"]` 등)를 쓰고 있다면 하위 선택자로 바꾸거나 `action-group`을 거치도록 고칩니다.
  - `--oc-action-area-gap`은 이제 extra와 action 묶음 사이 간격 전체입니다. 기본값이 `--oc-space-item-gap-small`에서 버튼 영역 상하 padding으로 바뀌고, padding을 더하던 계산은 없어집니다. 기본 간격은 `item-gap-small + padding`에서 `padding`으로 줄어듭니다. 이 변수를 지정하고 있었다면 원하는 전체 간격으로 다시 지정합니다.

- 4403c71: `ActionAreaLayout`이 페이지(문서) 스크롤 위에서 footer를 화면 아래에 붙여 두는 `scroll='document'` 모드를 추가합니다.
  - `ActionAreaLayout`에 `scroll='contained' | 'document'` prop(기본 `contained`)과 `ActionAreaLayoutScroll` 타입을 추가합니다. 루트는 현재 값을 `data-oc-scroll`로 노출합니다.
  - `document`에서는 body가 페이지 흐름에 남고 footer가 `position: sticky`로 뷰포트 아래 끝에 붙습니다. footer와 fade는 레이아웃이 놓인 컬럼 폭을 따르고, 레이아웃이 끝나면 footer가 풀려 뒤따르는 콘텐츠(페이지 footer 등) 위에 놓입니다.
  - `document`에서 `--oc-action-area-layout-block-size`는 고정 높이가 아니라 최소 높이로 쓰여, 콘텐츠가 짧아도 footer가 그 높이의 아래 끝에 놓입니다.
  - 콘텐츠가 짧을 때 모바일에서는 footer가 그 최소 높이의 아래 끝에 놓이고, `md` 이상에서는 최소 높이는 유지한 채 footer가 콘텐츠 바로 뒤에 놓이며 남는 공간은 footer 아래로 갑니다. 콘텐츠가 길면 두 환경 모두 footer가 뷰포트 아래에 붙습니다.
  - footer 배경은 레이아웃 끝까지 남은 거리에 따라 위로 번지며, 스크롤 중 렌더링이 일어나지 않습니다. 배경 계약은 footer `ScrollAreaEdge` 변경의 Migration Notes를 함께 확인합니다.
  - 스크롤바를 화면 오른쪽 끝에 두려면 `ScrollArea root` 안에서 사용합니다. `ScrollArea root` 없이 브라우저 기본 스크롤바와도 동작합니다.

  Migration Notes
  - `scroll` 기본값은 `contained`이며 루트에 `data-oc-scroll="contained"` attribute가 추가됩니다. footer 배경과 구조 변경은 footer `ScrollAreaEdge` Migration Notes를 함께 확인합니다.

- 1a78b07: Menu가 가용 공간 안에서 크기를 제한하고 ScrollArea로 많은 항목을 스크롤하도록 개선합니다. 일반 문자열 제목은 자동 중간 말줄임하며 원문 접근성 이름과 문자 검색을 보존합니다.

  Migration Notes
  - 문자열 제목의 기본 표시가 중간 말줄임으로 바뀝니다. 실제로 잘린 제목은 hover·키보드 포커스에서 원문 툴팁을 제공합니다. 커스텀 ReactNode content의 내부 표현은 소비자가 소유합니다.
  - `--oc-menu-max-inline-size`(기본 `24em`), `--oc-menu-max-block-size`(기본 화면 가용 높이)를 MenuContent className에서 조절할 수 있습니다. 메뉴 표면과 기존 container 사이에 ScrollArea viewport가 추가되므로 직계 자식에 의존하는 스타일은 공개 selector 계약을 확인하세요.
  - 스크롤 가능한 메뉴의 일반 터치 pan은 내부 스크롤로 동작합니다. trigger hold에서 이어진 드래그 선택과 짧은 메뉴의 기존 선택 동작은 유지합니다.
  - HistoryNavigationButton도 공통 Menu의 말줄임과 스크롤을 사용합니다. 툴팁은 터치의 탭 선택 동작을 변경하지 않습니다.

- 91c0346: `oc-inner-radius($outer-radius, $inset)` SCSS helper를 추가하고 Menu와 SegmentedControl에 적용
  - 바깥 radius에서 실제 inset을 빼고 음수 결과를 `0`으로 제한하며, radius factor는 중복 적용하지 않음
  - Menu의 셀 강조 배경과 focus ring radius를 popup radius와 실제 여백에서 파생하도록 변경
  - SegmentedControl의 기존 radius 계산과 시각 결과 유지

  Migration Notes
  - 필수 변경 없음
  - Menu의 기본 radius factor와 padding에서는 기존 모양을 유지하며, factor 또는 `--oc-menu-content-padding`을 조정한 경우 셀 radius가 바깥 surface 곡률에 맞춰 변경됨
  - 새 helper는 `@orioncactuscorp/ui/scss/mixins/radius`에서 import 가능

- add1db3: `MenuTrigger`에 길게 눌러 메뉴를 여는 `openOnHold`를 추가합니다.
  - `openOnHold`를 준 트리거는 탭·클릭·Enter·Space로 render한 control의 동작을 실행하고, 메뉴는 브라우저 뒤로 가기 버튼처럼 지름길로 엽니다. 손가락·펜·마우스 주 버튼으로 hold 판정 시간(`--oc-motion-duration-hold`, 기본 0.65초)을 채우면 메뉴가 열리고, 떼지 않은 채 항목으로 옮겨 놓으면 그 항목을 고릅니다. 판정 전에 움직이면 취소되고(터치는 페이지 스크롤로 양보), 판정 뒤에는 페이지가 스크롤되지 않습니다. 항목에 닿지 않고 떼면 메뉴는 열린 채로 남습니다.
  - `contextmenu` 이벤트(오른쪽 클릭, Control-클릭, 메뉴 키, VoiceOver VO+Shift+M)와 Shift+F10으로 바로 열리며, 키보드·보조기기는 이 경로를 씁니다. 별도 단축키와 `aria-keyshortcuts`는 없습니다. 링크 trigger는 `contextmenu`로 뜨는 브라우저 링크 메뉴를 유지합니다. iOS는 hold 트리거의 링크 callout을 보여 주지 않고 hold가 메뉴를 엽니다.
  - 메뉴가 열린 동안 trigger를 누르면 메뉴만 닫히고 control의 동작은 실행되지 않습니다.
  - 한 `MenuRoot`에 trigger가 여럿이면 hold·`contextmenu`로 메뉴를 연 trigger가 위치 기준, `aria-expanded`, 포커스 복귀 대상이 됩니다.
  - `nativeButton={false}` trigger에서도 Enter·Space가 render한 control의 `onClick`을 실행합니다.
  - hold 트리거는 `aria-haspopup`을 출력하지 않고 `openOnHover`를 무시합니다. 메뉴 항목은 화면에 보이는 다른 경로로도 닿을 수 있어야 합니다.
  - 충전 중 trigger에 입력 종류를 담은 `data-oc-holding="touch|mouse|pen"`, 판정 뒤 손을 뗄 때까지 `data-oc-held="true"`가 붙습니다. `BackgroundIconButton`과 `IconButton`은 이 상태에서 hold 모션으로 부풀었다가 판정 순간 돌아옵니다.
  - `MenuRoot`가 열림 상태를 직접 관리해 Base UI에 controlled `open`으로 전달합니다. `open`/`defaultOpen`/`onOpenChange` 사용법은 바뀌지 않습니다.
  - 모든 `Menu`가 닫힐 때 trigger로 포커스를 돌려주되, 마우스·터치·펜으로 닫았으면 포커스 링 없이 돌려줍니다(`focus({ focusVisible: false })`). 키보드로 닫았으면 기존처럼 포커스 링이 보이고, 닫히기 전에 포커스가 메뉴 밖 다른 요소로 옮겨 갔으면 돌려주지 않습니다. iOS Safari에서 손가락으로 닫은 뒤 trigger에 포커스 링이 남던 문제를 막습니다.
  - 누른 채 미끄러지는 선택이 끝나면 지나간 항목의 `data-oc-pressed`를 바로 지우지 않고, 그 항목에 포인터가 다시 들어오거나 그 항목을 누를 때까지 `false`로 둡니다. 마우스를 iframe·창 밖에서 놓았을 때 마지막 항목에 hover 강조가 남던 문제를 막습니다.
  - hover로 열지 않은 메뉴(hold, `contextmenu`, `open` prop으로 연 메뉴)가 마우스가 메뉴 밖으로 나갈 때 닫히던 문제를 고칩니다. hover로 연 메뉴는 기존처럼 닫힙니다.

  Migration Notes
  - 없음

- c123ea6: 열린 `Menu`에서 손가락을 누른 채 항목 사이를 미끄러져 고르는 터치 선택을 추가합니다.
  - 터치로 항목을 누른 채 움직이면 손가락 아래 항목이 눌린 상태로 바뀌고, 눌림 표시가 직전 항목 위치에서 출발해 이동합니다. 손을 뗀 항목이 실행됩니다. 마우스는 Base UI의 기존 누른 채 끌어 놓기 선택을 그대로 사용합니다.
  - 항목 사이 구분선이나 메뉴 안쪽 여백을 지나는 동안에는 직전 항목을 유지합니다. 항목 위아래 divider도 손가락 아래 항목을 따라 숨겨지고 복구됩니다. 메뉴 밖이나 disabled 항목에서 손을 떼면 아무것도 실행하지 않습니다.
  - 누른 채 움직이는 동안 메뉴 뒤 페이지는 스크롤되지 않습니다. 움직이지 않은 탭은 기존과 같이 동작합니다.
  - 실행은 항목의 기존 click 경로를 따르므로 `onClick`, `closeOnClick`, 링크 항목 동작은 바뀌지 않습니다.
  - `CellItem`에 owner가 붙이는 눌림 상태 selector `data-oc-pressed="true|false"`를 추가합니다. 속성이 있는 동안 항목과 그 안의 self Interaction 레이어 모두 `:hover`·`:active` 대신 이 값으로 눌림 표현과 divider 숨김을 결정하며, 속성이 없으면 기존과 같습니다.
  - `prefers-reduced-motion: reduce`에서는 눌림 표시가 이동하지 않고 항목별로 바뀝니다.

  Migration Notes
  - 없음

- 10daf2c: ScrollArea 세로 커스텀 스크롤바의 inline-start/end 위치 변수를 공개 override로 제공합니다. 좌우 분할 화면에서 root 스크롤바를 본문 열 경계에 배치할 수 있으며 기존 기본 배치는 유지됩니다.

  Migration Notes
  - 기존 사용법 변경은 필요하지 않습니다.
  - scrollbar part에 `inset-inline-end`를 직접 지정하던 경우 ScrollArea host의 `--oc-scroll-area-scrollbar-vertical-inset-inline-end` 지정으로 대체할 수 있습니다. 시작 쪽으로 옮길 때는 `--oc-scroll-area-scrollbar-vertical-inset-inline-start`와 함께 반대쪽 값을 `auto`로 지정합니다.

- 7963156: 버튼 등 명시적 명령으로 좌표를 이동하는 `animateScrollTo` 유틸과 `utils/scroll` 진입점 추가

  `useDragScroll`·스냅 페이지 이동·Carousel의 프로그램 이동과 대상별 실행 소유권 공유

  일반 좌표 이동의 정착 구간에서 픽셀 단위 최소 속도 강제를 제거하고 spring 감속 유지

  열린 Shadow DOM 경계를 포함한 중첩 스크롤 영역의 입력 소유권 유지

  유틸·React API의 네이밍 기준과 기존 `oc*` 도메인 진입점 역할 문서화

  Migration Notes
  - 기존 공개 API 이름과 기본 사용법 유지
  - 새 유틸은 `@orioncactuscorp/ui/utils/scroll`에서 import하고 실제 스크롤 요소 또는 `window`를 대상으로 지정
  - `animateScrollTo`와 `useDragScroll`을 조합할 때 수동 `cancel()` 연결 없이 자동 인계
  - native `scrollTo` 등 외부 API는 기존처럼 드래그의 `cancel()`을 직접 호출해 인계
  - reduced-motion에서는 즉시 이동하며, CSS snap에 따라 최종 좌표가 요청 좌표와 달라질 수 있음

- c78c6ec: 방문 기록을 관리하는 `useNavigationHistory`와 버튼 조합형 `HistoryNavigationButton` 추가

  Modal의 Depth Navigation with History 예시에 뒤로 이동과 hold 기록 선택, 화면별 제목의 기록 이름 재사용 적용

  `ModalHeader`에 긴 제목을 줄바꿈하는 `titleOverflow="wrap"` 추가

  `MenuTrigger openOnHold`의 Shift+F10 직접 열기 지원 (메뉴 키는 native contextmenu 경로 유지)

  Modal·FloatingWindow 등 dialog 안의 모든 Menu에서 부모 focus fallback 이후의 목적지 복원 보완

  Modal Header의 leading·title·trailing 영역 간격을 조절하는 `--oc-modal-header-gap` 공개 변수 추가 (기존 기본 간격 유지)

  Migration Notes
  - 기존 Modal 제목의 한 줄 말줄임 기본값 유지
  - 긴 제목은 `titleOverflow="wrap"`으로 표시하거나 소비자에게 원문 확인 경로 제공
  - history key와 계층 depth를 구분하고 입력값·라우터·이동 검증은 소비자에서 관리

- eb468be: Reveal·RevealProvider·RevealGroup을 추가해 콘텐츠의 한 번 등장을 fade·slide·blur로 표현하고, mount·in-view 조건과 영역별 기본값을 지원합니다. 세 효과는 체감 600ms의 바운스 없는 smooth를 공유하며 pace로 속도를 보정합니다. visible로 반복 등장·퇴장을 제어하고, 퇴장 중 입력 차단과 입력값 보존을 지원합니다. RevealGroup.Content와 Items로 본문과 항목을 선언하면 공통 viewport 시작점과 pace별 순차 등장을 처리합니다. pace를 유지하면서 timing의 duration·contentGap·stagger로 Group의 호흡을 조정할 수 있습니다. 개별 요소의 시차에는 delay를 사용할 수 있습니다. 초기 SSR 콘텐츠를 유지하고 reduced-motion에서는 짧은 fade만 사용합니다.

  Migration Notes

  기존 컴포넌트 변경은 없습니다. Reveal과 RevealGroup의 슬롯·항목은 div wrapper를 생성하므로 소비자의 레이아웃·semantic 구조에 맞춰 배치하세요. 모션 intent에 reveal이 추가되어 OcMotionIntent를 전수 매핑하는 소비자는 새 항목을 처리해야 합니다. reveal은 독립된 smooth 모션 정책을 사용하며 기존 move/fade intent는 바뀌지 않습니다.

  제어 모드의 native hidden은 visible로 대체하며 trigger·threshold와 동시에 지정할 수 없습니다. 높이 변화를 보간하지 않으므로 인라인 영역의 접힘은 별도 layout owner로 처리하세요.

### Patch Changes

- 2d748e5: Menu의 내부 ScrollArea 전체를 둥근 표면 경계에서 잘라 탄성 스크롤 중 항목이나 스크롤바가 메뉴 밖으로 나오는 문제를 수정합니다. 기존 탄성 스크롤과 스크롤바 위치 계산은 유지합니다.

  Migration Notes
  - 없음

- f75629f: `Menu`에서 누른 채 미끄러지는 선택이 끝난 뒤 지나간 항목에 hover 강조가 간헐적으로 남던 문제를 고칩니다.
  - 지나간 항목의 `data-oc-pressed="false"`를 다음 포인터 이동 때가 아니라, 포인터가 그 항목에 다시 들어오거나 그 항목을 누를 때 해제합니다.
  - Chrome은 마우스를 누른 채 끄는 동안 마지막으로 갱신한 항목에 `:hover`를 남기고, 포인터가 다른 곳으로 움직인 뒤에도 바로 바로잡지 않습니다. 이전에는 이 묵은 `:hover`가 강조로 드러났습니다.

  Migration Notes
  - 없음

- 2abadb2: bottom sheet의 snap 높이가 시트 최대 높이를 넘을 때 드래그로 닫히지 않던 문제를 수정합니다.
  - `Modal`의 `snapPoints`가 시트의 CSS 최대 높이(기본값은 뷰포트 높이에서 `--oc-modal-sheet-block-start-clearance`를 뺀 값)보다 크면 그 최대 높이로 해석합니다. 실제 시트는 원래 최대 높이까지만 그려졌지만 드래그 계산은 더 큰 snap 높이를 기준으로 삼아 두 값이 clearance만큼 어긋났습니다.
  - `resize='fixed'` 시트에서 이 조건일 때 임계 거리 이상 끌거나 빠르게 내려도 시트가 닫히지 않고 원위치로 돌아가던 문제가 해결됩니다. 기본 clearance(`3rem`)만으로도 `snapPoints={[1]}`이나 높이가 낮은 뷰포트에서 재현됐습니다.
  - 같은 조건의 `peekable` 시트가 peek로 내려갈 때 헤더 일부만 보이던 문제가 해결됩니다.
  - 같은 조건에서 더 낮은 snap이 지정한 높이보다 clearance만큼 낮게 멈추던 문제가 해결됩니다. 예를 들어 844px 뷰포트의 `snapPoints={[0.5, 1]}`에서 `0.5` snap은 374px가 아니라 422px로 멈춥니다.
  - `onSnapPointChange`가 전달하는 값은 바뀌지 않고 `snapPoints`에 지정한 원래 값 그대로입니다.

  Migration Notes
  - 최대 높이를 넘는 snap과 더 낮은 snap을 함께 쓰는 화면은 낮은 snap의 정지 위치가 clearance만큼 높아지므로 배치를 확인합니다. 그 밖의 변경은 필요 없습니다.

- fae9e74: `PageIndicator` 조작 모드에서 마우스로 점을 클릭할 때 hover 표시가 깜빡이던 문제를 고칩니다. 누르는 동안에도 끝의 작은 점은 `+` 힌트를 유지하고 누른 점은 확대된 크기를 유지합니다. 길게 눌러 스크럽이 시작되면 이전처럼 힌트가 사라집니다.

  Migration Notes
  - 없음

### Migration Notes

- `ActionAreaLayout.ActionArea`의 `background` prop과 `ActionAreaLayoutActionAreaBackground` 타입을 제거합니다. `background`/`background="auto"`는 지우고, `background={false}`는 Footer의 `scrollEdgeVariant="none"`으로 옮깁니다. `contained`에서 기존 번짐이 필요하면 Footer에 `scrollEdgeVariant="fade"`를 지정합니다.
- footer 배경색 `--oc-action-area-background-color`는 Footer나 조상에 지정합니다. 기존 스크롤 상태별 padding 보정, 단독 ActionArea 그라디언트와 extraContent 불투명 배경에 의존한 화면은 위 상세 Migration Notes에 따라 조정합니다.
- `caption`·`actions`·`compact-row`는 `action-group` 안으로 이동합니다. 직속 자식 선택자를 수정하고, `--oc-action-area-gap`은 extra와 action 묶음 사이 전체 간격으로 다시 확인합니다. `ActionAreaLayoutScrollState`는 deprecated입니다.
- 최대 높이를 넘는 snap과 더 낮은 snap을 함께 쓰는 bottom sheet는 낮은 snap의 정지 위치가 clearance만큼 높아지므로 배치를 확인합니다.
- ScrollArea scrollbar part의 직접 inset override는 host의 `--oc-scroll-area-scrollbar-vertical-inset-inline-start/end`로 옮길 수 있습니다. 기존 기본 배치는 유지됩니다.
- Menu 문자열 제목은 기본 중간 말줄임과 원문 툴팁으로 표시됩니다. 내부 ScrollArea viewport 추가에 따른 직속 자식 선택자를 확인하고, 스크롤 가능한 메뉴의 일반 터치 pan은 내부 스크롤로 동작하는지 확인합니다.
- Reveal과 RevealGroup의 div wrapper는 소비자 레이아웃·semantic 구조에 맞춰 배치합니다. `OcMotionIntent`를 전수 매핑하는 코드는 새 `reveal` 항목을 처리합니다. 제어 모드에서는 native `hidden` 대신 `visible`을 사용합니다.
- 방문 기록의 key와 계층 depth는 구분하며 입력값·라우터·이동 검증은 소비자가 관리합니다. Modal 제목은 기본 한 줄 말줄임을 유지하며 긴 제목은 `titleOverflow="wrap"`으로 표시할 수 있습니다.
- `animateScrollTo`는 `@orioncactuscorp/ui/utils/scroll`에서 import합니다. `useDragScroll`과 자동 인계하며, native `scrollTo` 등 외부 이동은 기존처럼 직접 `cancel()`을 연결합니다.
- Menu padding 또는 radius factor를 조정한 화면은 셀 radius를 확인합니다. 기본 Menu와 SegmentedControl 모양은 유지되며 `oc-inner-radius`는 `@orioncactuscorp/ui/scss/mixins/radius`에서 제공합니다.
- 정식 버전은 `@orioncactuscorp/ui@1.25.0`입니다. 프리릴리즈에서 전환할 때 설치 버전을 갱신합니다.
- `1.25.0-next.0`에서 전환하는 경우 Reveal의 기본 등장 시간 600ms, 공통 60% 진입선, Content/Items 독립 진입, 기본 contentGap 80ms와 timing의 pace·전역 factor 적용을 확인합니다. 명시한 threshold의 면적 모드는 유지하고 Provider.threshold는 deprecated입니다.
- 둥근 카드를 꽉 채우는 ScrollArea의 `--oc-scroll-area-radius`는 그 ScrollArea 자신에 지정합니다. 조상 요소에서는 상속되지 않습니다.

## 1.25.0-next.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.24.0..HEAD`_

#### Breaking Changes

- `3a8fa9a` ActionAreaLayout footer 배경의 ScrollAreaEdge 통합과 스크롤 연동 bleed (#488)

#### Features

- `10daf2c` feat(scroll-area): expose vertical scrollbar inline inset overrides (#487)

#### Maintenance

- `3aae529` chore(release): prepare ui 1.25.0-next.0

#### Other

- `08d9541` verify:pr e2e worker 8개 병렬 실행과 검증 단일 실행 잠금·포트 자동 할당 (#473)
- `c123ea6` Menu 터치 누른 채 미끄러져 선택과 Interaction 이동 엔진 분리 (#477)
- `2abadb2` bottom sheet snap 높이의 시트 최대 높이 상한 적용과 드래그 닫힘 복구 (#480)
- `75b2443` verify:pr 종료 시 하위 프로세스 정리와 cancelled 기록 (#476)
- `50bb026` verify:pr e2e worker 6개 조정과 호스트 부하 기록 (#481)
- `add1db3` Menu 트리거 길게 누르기 열기와 이어지는 터치 선택 (#479)
- `98235da` 실시간 Carousel·Modal spec의 시간 소유자별 준비·관측 보강과 입력 속도 결정론화 (#486)
- `fae9e74` PageIndicator 클릭 중 끝 점 + 힌트 깜빡임 수정 (#484)
- `4403c71` ActionAreaLayout 문서 스크롤 모드와 sticky footer (#482)
- `f75629f` Menu 누른 채 미끄러지는 선택 후 남는 hover 강조 수정 (#483)
- `eb468be` Reveal 등장·퇴장과 그룹 타이밍 제어 추가 (#490)
- `c78c6ec` 방문 기록 내비게이션과 Modal Header 계약 추가 (#491)
- `1a78b07` Menu 자동 말줄임·원문 툴팁과 내부 스크롤 개선 (#494)
- `7963156` 프로그램 스크롤 유틸과 드래그 실행 인계 추가 (#492)
- `91c0346` Menu·SegmentedControl 내부 곡률 계산의 공통 유틸화 (#493)
<!-- generated:end -->

### Minor Changes

- 1a78b07: Menu가 가용 공간 안에서 크기를 제한하고 ScrollArea로 많은 항목을 스크롤하도록 개선합니다. 일반 문자열 제목은 자동 중간 말줄임하며 원문 접근성 이름과 문자 검색을 보존합니다.

  Migration Notes
  - 문자열 제목의 기본 표시가 중간 말줄임으로 바뀝니다. 실제로 잘린 제목은 hover·키보드 포커스에서 원문 툴팁을 제공합니다. 커스텀 ReactNode content의 내부 표현은 소비자가 소유합니다.
  - `--oc-menu-max-inline-size`(기본 `24em`), `--oc-menu-max-block-size`(기본 화면 가용 높이)를 MenuContent className에서 조절할 수 있습니다. 메뉴 표면과 기존 container 사이에 ScrollArea viewport가 추가되므로 직계 자식에 의존하는 스타일은 공개 selector 계약을 확인하세요.
  - 스크롤 가능한 메뉴의 일반 터치 pan은 내부 스크롤로 동작합니다. trigger hold에서 이어진 드래그 선택과 짧은 메뉴의 기존 선택 동작은 유지합니다.
  - HistoryNavigationButton도 공통 Menu의 말줄임과 스크롤을 사용합니다. 툴팁은 터치의 탭 선택 동작을 변경하지 않습니다.

- 91c0346: `oc-inner-radius($outer-radius, $inset)` SCSS helper를 추가하고 Menu와 SegmentedControl에 적용
  - 바깥 radius에서 실제 inset을 빼고 음수 결과를 `0`으로 제한하며, radius factor는 중복 적용하지 않음
  - Menu의 셀 강조 배경과 focus ring radius를 popup radius와 실제 여백에서 파생하도록 변경
  - SegmentedControl의 기존 radius 계산과 시각 결과 유지

  Migration Notes
  - 필수 변경 없음
  - Menu의 기본 radius factor와 padding에서는 기존 모양을 유지하며, factor 또는 `--oc-menu-content-padding`을 조정한 경우 셀 radius가 바깥 surface 곡률에 맞춰 변경됨
  - 새 helper는 `@orioncactuscorp/ui/scss/mixins/radius`에서 import 가능

- 7963156: 버튼 등 명시적 명령으로 좌표를 이동하는 `animateScrollTo` 유틸과 `utils/scroll` 진입점 추가

  `useDragScroll`·스냅 페이지 이동·Carousel의 프로그램 이동과 대상별 실행 소유권 공유

  일반 좌표 이동의 정착 구간에서 픽셀 단위 최소 속도 강제를 제거하고 spring 감속 유지

  열린 Shadow DOM 경계를 포함한 중첩 스크롤 영역의 입력 소유권 유지

  유틸·React API의 네이밍 기준과 기존 `oc*` 도메인 진입점 역할 문서화

  Migration Notes
  - 기존 공개 API 이름과 기본 사용법 유지
  - 새 유틸은 `@orioncactuscorp/ui/utils/scroll`에서 import하고 실제 스크롤 요소 또는 `window`를 대상으로 지정
  - `animateScrollTo`와 `useDragScroll`을 조합할 때 수동 `cancel()` 연결 없이 자동 인계
  - native `scrollTo` 등 외부 API는 기존처럼 드래그의 `cancel()`을 직접 호출해 인계
  - reduced-motion에서는 즉시 이동하며, CSS snap에 따라 최종 좌표가 요청 좌표와 달라질 수 있음

- c78c6ec: 방문 기록을 관리하는 `useNavigationHistory`와 버튼 조합형 `HistoryNavigationButton` 추가

  Modal의 Depth Navigation with History 예시에 뒤로 이동과 hold 기록 선택, 화면별 제목의 기록 이름 재사용 적용

  `ModalHeader`에 긴 제목을 줄바꿈하는 `titleOverflow="wrap"` 추가

  `MenuTrigger openOnHold`의 Shift+F10 직접 열기 지원 (메뉴 키는 native contextmenu 경로 유지)

  Modal·FloatingWindow 등 dialog 안의 모든 Menu에서 부모 focus fallback 이후의 목적지 복원 보완

  Modal Header의 leading·title·trailing 영역 간격을 조절하는 `--oc-modal-header-gap` 공개 변수 추가 (기존 기본 간격 유지)

  Migration Notes
  - 기존 Modal 제목의 한 줄 말줄임 기본값 유지
  - 긴 제목은 `titleOverflow="wrap"`으로 표시하거나 소비자에게 원문 확인 경로 제공
  - history key와 계층 depth를 구분하고 입력값·라우터·이동 검증은 소비자에서 관리

- eb468be: Reveal·RevealProvider·RevealGroup을 추가해 콘텐츠의 한 번 등장을 fade·slide·blur로 표현하고, mount·in-view 조건과 영역별 기본값을 지원합니다. 세 효과는 체감 1,000ms의 바운스 없는 smooth를 공유하며 pace로 속도를 보정합니다. visible로 반복 등장·퇴장을 제어하고, 퇴장 중 입력 차단과 입력값 보존을 지원합니다. RevealGroup.Content와 Items로 본문과 항목을 선언하면 공통 viewport 시작점과 pace별 순차 등장을 처리합니다. pace를 유지하면서 timing의 duration·contentGap·stagger로 Group의 호흡을 조정할 수 있습니다. 개별 요소의 시차에는 delay를 사용할 수 있습니다. 초기 SSR 콘텐츠를 유지하고 reduced-motion에서는 짧은 fade만 사용합니다.

  Migration Notes

  기존 컴포넌트 변경은 없습니다. Reveal과 RevealGroup의 슬롯·항목은 div wrapper를 생성하므로 소비자의 레이아웃·semantic 구조에 맞춰 배치하세요. 모션 intent에 reveal이 추가되어 OcMotionIntent를 전수 매핑하는 소비자는 새 항목을 처리해야 합니다. reveal은 독립된 smooth 모션 정책을 사용하며 기존 move/fade intent는 바뀌지 않습니다.

  제어 모드의 native hidden은 visible로 대체하며 trigger·threshold와 동시에 지정할 수 없습니다. 높이 변화를 보간하지 않으므로 인라인 영역의 접힘은 별도 layout owner로 처리하세요.

- 3a8fa9a: `ActionAreaLayout` footer 배경을 스크롤 상태에 따라 켜고 끄던 방식에서, footer가 항상 그리는 `ScrollAreaEdge`로 바꿉니다. 끝에서 빠르게 위로 스크롤할 때 배경이 돌아오기 전에 버튼 밑으로 콘텐츠가 비치던 문제를 없앱니다.
  - `ActionAreaLayout.Footer`가 마지막 자식으로 `ScrollAreaEdge`(`data-oc-part="scroll-edge"`)를 그립니다. 버튼 영역은 항상 덮고, 위쪽 padding 구간에서 서서히 사라지며, 아래에 남은 콘텐츠 거리만큼만 0부터 이어서 위로 번집니다. 스크롤 중 렌더링은 일어나지 않습니다.
  - `ActionAreaLayout.Footer`에 `scrollEdgeVariant="auto | none | fade | progressive-blur"`(기본 `auto`: `scroll="document"`는 `fade`, `contained`는 `none`)와 `scrollEdgeAppearance="soft | hard"`(기본 `soft`)를 추가합니다. `ModalFooter`와 같은 축에 레이아웃 스크롤 방식을 따르는 `auto`를 더했습니다. `hard`이면 아래에 콘텐츠가 남은 동안 `data-oc-part="scroll-edge-divider"` 구분선이 보이고, footer에 `data-oc-overflow-y-end`가 붙습니다. 구분선은 `divider="normal | neutral | alternative | none"`(기본 `normal`, `ModalFooter`와 같은 축)로 정합니다. `ActionAreaLayoutFooterScrollEdgeVariant` 타입을 추가합니다.
  - footer의 직속 `ActionArea`가 비어 있으면 edge를 그리지 않습니다. `extraContent`는 예외 없이 같은 규칙을 따릅니다.
  - `scroll="document"`의 번짐 거리는 레이아웃 콘텐츠 끝에서 footer 아래 끝까지로 잽니다. 레이아웃을 담은 어떤 스크롤 컨테이너에도 반응합니다.
  - footer 안의 `ActionArea`는 스크롤 여부와 관계없이 위쪽 padding을 유지합니다. 스크롤될 때 그 padding을 body 아래 여백으로 옮기던 동작을 제거합니다.
  - 단독 `ActionArea`의 `background`는 자기 영역을 단색으로 채우는 것으로 바뀝니다. 위쪽으로 번지던 고정 그라디언트는 제거됩니다.
  - `contained`에서는 body가 footer 위에서 끝나므로 콘텐츠가 footer 밑으로 지나가지 않습니다. 이 점은 `document`와 다릅니다.
  - `ActionArea`가 `caption`과 `actions`(또는 `compact-row`)를 새 `data-oc-part="action-group"`으로 묶습니다. 간격은 margin 대신 flex `gap`으로 정합니다. extra와 묶음 사이는 `--oc-action-area-gap`, caption과 버튼 사이는 `--oc-space-item-gap-medium`입니다.

  Migration Notes
  - `ActionAreaLayout.ActionArea`의 `background` prop을 제거합니다. `background="auto"`와 `background`(`true`)는 지우면 됩니다. `scroll="document"`에서는 `fade` edge가 기본이고, `contained`에서는 body가 bar 위에서 끝나므로 기본으로 edge를 그리지 않습니다. contained에서 스크롤 중 bar 위 번짐을 유지하려면 Footer에 `scrollEdgeVariant="fade"`를 지정합니다. `background={false}`는 `<ActionAreaLayout.Footer scrollEdgeVariant="none">`으로 옮깁니다. `ActionAreaLayoutActionAreaBackground` 타입을 제거합니다.
  - footer 배경색은 `--oc-action-area-background-color`를 `ActionAreaLayout.Footer`나 그 조상에 지정합니다. layout 안의 `ActionArea`에 지정한 값은 footer 배경에 닿지 않습니다. internal이던 `--oc-action-area-layout-background-color`, `--oc-action-area-layout-gradient-overlap`, `--oc-action-area-layout-gradient-size`, `--oc-action-area-layout-body-padding-block-end`, `--oc-action-area-background-bleed`, `--oc-action-area-background-gradient-size`를 제거합니다.
  - `data-oc-background="true"`는 이제 단독 `ActionArea`의 고정 채우기만 뜻합니다. layout footer의 `ActionArea`에는 붙지 않습니다. 스크롤 상태 판단에는 footer의 `data-oc-overflow-y-end`를 씁니다.
  - `data-oc-scrollable="true"`일 때 footer `ActionArea`가 `--oc-action-area-padding-block-start: 0`을 받고 body가 아래 여백을 갖던 규칙을 제거합니다. 이 동작에 맞춘 스타일이 있다면 지웁니다.
  - 단독 `ActionArea`를 `absolute`나 `fixed`로 띄우고 `background`로 스크롤 콘텐츠를 가리던 경우, 위쪽 그라디언트가 사라집니다. 같은 모습을 내는 대체는 없으며, 스크롤 콘텐츠 위의 bar는 `ActionAreaLayout`(고정 높이 영역은 `contained`, 페이지 스크롤은 `scroll="document"`)이나 `ScrollArea`의 `ScrollAreaEdge` 패턴으로 옮깁니다.
  - `extraContent`가 있는 `ActionArea`의 불투명 배경과 위쪽 테두리를 제거합니다. `background`와 footer edge가 다른 경우와 같은 규칙으로 정합니다. 단단한 경계와 구분선이 필요하면 `ActionAreaLayout.Footer`에 `scrollEdgeAppearance="hard"`를, 단독 `ActionArea`에는 `background`와 직접 둔 `Divider`를 씁니다. `ModalFooter`·`FloatingWindowFooter` 안의 extra `ActionArea`도 불투명하지 않게 되어 footer 자체 edge가 보입니다.
  - `ActionAreaLayoutScrollState` 타입은 더 이상 쓰이지 않아 deprecated로 표시합니다.
  - `caption`, `actions`, `compact-row`는 이제 `ActionArea` 루트의 직속 자식이 아니라 `data-oc-part="action-group"` 안에 있습니다. 직속 자식 선택자(`[data-oc-component="action-area"] > [data-oc-part="actions"]` 등)를 쓰고 있다면 하위 선택자로 바꾸거나 `action-group`을 거치도록 고칩니다.
  - `--oc-action-area-gap`은 이제 extra와 action 묶음 사이 간격 전체입니다. 기본값이 `--oc-space-item-gap-small`에서 버튼 영역 상하 padding으로 바뀌고, padding을 더하던 계산은 없어집니다. 기본 간격은 `item-gap-small + padding`에서 `padding`으로 줄어듭니다. 이 변수를 지정하고 있었다면 원하는 전체 간격으로 다시 지정합니다.

- 4403c71: `ActionAreaLayout`이 페이지(문서) 스크롤 위에서 footer를 화면 아래에 붙여 두는 `scroll='document'` 모드를 추가합니다.
  - `ActionAreaLayout`에 `scroll='contained' | 'document'` prop(기본 `contained`)과 `ActionAreaLayoutScroll` 타입을 추가합니다. 루트는 현재 값을 `data-oc-scroll`로 노출합니다.
  - `document`에서는 body가 페이지 흐름에 남고 footer가 `position: sticky`로 뷰포트 아래 끝에 붙습니다. footer와 fade는 레이아웃이 놓인 컬럼 폭을 따르고, 레이아웃이 끝나면 footer가 풀려 뒤따르는 콘텐츠(페이지 footer 등) 위에 놓입니다.
  - `document`에서 `--oc-action-area-layout-block-size`는 고정 높이가 아니라 최소 높이로 쓰여, 콘텐츠가 짧아도 footer가 그 높이의 아래 끝에 놓입니다.
  - 콘텐츠가 짧을 때 모바일에서는 footer가 그 최소 높이의 아래 끝에 놓이고, `md` 이상에서는 최소 높이는 유지한 채 footer가 콘텐츠 바로 뒤에 놓이며 남는 공간은 footer 아래로 갑니다. 콘텐츠가 길면 두 환경 모두 footer가 뷰포트 아래에 붙습니다.
  - footer 배경은 레이아웃 끝까지 남은 거리에 따라 위로 번지며, 스크롤 중 렌더링이 일어나지 않습니다. 배경 계약은 위의 footer `ScrollAreaEdge` 변경과 Migration Notes를 참고하세요.
  - 스크롤바를 화면 오른쪽 끝에 두려면 `ScrollArea root` 안에서 사용합니다. `ScrollArea root` 없이 브라우저 기본 스크롤바와도 동작합니다.

  Migration Notes
  - `scroll` 기본값은 `contained`이며 루트에 `data-oc-scroll="contained"` attribute가 추가됩니다. footer 배경과 구조 변경은 위의 footer `ScrollAreaEdge` Migration Notes를 함께 확인합니다.

- add1db3: `MenuTrigger`에 길게 눌러 메뉴를 여는 `openOnHold`를 추가합니다.
  - `openOnHold`를 준 트리거는 탭·클릭·Enter·Space로 render한 control의 동작을 실행하고, 메뉴는 브라우저 뒤로 가기 버튼처럼 지름길로 엽니다. 손가락·펜·마우스 주 버튼으로 hold 판정 시간(`--oc-motion-duration-hold`, 기본 0.65초)을 채우면 메뉴가 열리고, 떼지 않은 채 항목으로 옮겨 놓으면 그 항목을 고릅니다. 판정 전에 움직이면 취소되고(터치는 페이지 스크롤로 양보), 판정 뒤에는 페이지가 스크롤되지 않습니다. 항목에 닿지 않고 떼면 메뉴는 열린 채로 남습니다.
  - `contextmenu` 이벤트(오른쪽 클릭, Control-클릭, 메뉴 키, Shift+F10, VoiceOver VO+Shift+M)로는 바로 열리며, 키보드·보조기기는 이 경로를 씁니다. 별도 단축키와 `aria-keyshortcuts`는 없습니다. 링크 trigger는 `contextmenu`로 뜨는 브라우저 링크 메뉴를 유지합니다. iOS는 hold 트리거의 링크 callout을 보여 주지 않고 hold가 메뉴를 엽니다.
  - 메뉴가 열린 동안 trigger를 누르면 메뉴만 닫히고 control의 동작은 실행되지 않습니다.
  - 한 `MenuRoot`에 trigger가 여럿이면 hold·`contextmenu`로 메뉴를 연 trigger가 위치 기준, `aria-expanded`, 포커스 복귀 대상이 됩니다.
  - `nativeButton={false}` trigger에서도 Enter·Space가 render한 control의 `onClick`을 실행합니다.
  - hold 트리거는 `aria-haspopup`을 출력하지 않고 `openOnHover`를 무시합니다. 메뉴 항목은 화면에 보이는 다른 경로로도 닿을 수 있어야 합니다.
  - 충전 중 trigger에 입력 종류를 담은 `data-oc-holding="touch|mouse|pen"`, 판정 뒤 손을 뗄 때까지 `data-oc-held="true"`가 붙습니다. `BackgroundIconButton`과 `IconButton`은 이 상태에서 hold 모션으로 부풀었다가 판정 순간 돌아옵니다.
  - `MenuRoot`가 열림 상태를 직접 관리해 Base UI에 controlled `open`으로 전달합니다. `open`/`defaultOpen`/`onOpenChange` 사용법은 바뀌지 않습니다.
  - 모든 `Menu`가 닫힐 때 trigger로 포커스를 돌려주되, 마우스·터치·펜으로 닫았으면 포커스 링 없이 돌려줍니다(`focus({ focusVisible: false })`). 키보드로 닫았으면 기존처럼 포커스 링이 보이고, 닫히기 전에 포커스가 메뉴 밖 다른 요소로 옮겨 갔으면 돌려주지 않습니다. iOS Safari에서 손가락으로 닫은 뒤 trigger에 포커스 링이 남던 문제를 막습니다.
  - 누른 채 미끄러지는 선택이 끝나면 지나간 항목의 `data-oc-pressed`를 바로 지우지 않고, 그 항목에 포인터가 다시 들어오거나 그 항목을 누를 때까지 `false`로 둡니다. 마우스를 iframe·창 밖에서 놓았을 때 마지막 항목에 hover 강조가 남던 문제를 막습니다.
  - hover로 열지 않은 메뉴(hold, `contextmenu`, `open` prop으로 연 메뉴)가 마우스가 메뉴 밖으로 나갈 때 닫히던 문제를 고칩니다. hover로 연 메뉴는 기존처럼 닫힙니다.

  Migration Notes
  - 없음

- c123ea6: 열린 `Menu`에서 손가락을 누른 채 항목 사이를 미끄러져 고르는 터치 선택을 추가합니다.
  - 터치로 항목을 누른 채 움직이면 손가락 아래 항목이 눌린 상태로 바뀌고, 눌림 표시가 직전 항목 위치에서 출발해 이동합니다. 손을 뗀 항목이 실행됩니다. 마우스는 Base UI의 기존 누른 채 끌어 놓기 선택을 그대로 사용합니다.
  - 항목 사이 구분선이나 메뉴 안쪽 여백을 지나는 동안에는 직전 항목을 유지합니다. 항목 위아래 divider도 손가락 아래 항목을 따라 숨겨지고 복구됩니다. 메뉴 밖이나 disabled 항목에서 손을 떼면 아무것도 실행하지 않습니다.
  - 누른 채 움직이는 동안 메뉴 뒤 페이지는 스크롤되지 않습니다. 움직이지 않은 탭은 기존과 같이 동작합니다.
  - 실행은 항목의 기존 click 경로를 따르므로 `onClick`, `closeOnClick`, 링크 항목 동작은 바뀌지 않습니다.
  - `CellItem`에 owner가 붙이는 눌림 상태 selector `data-oc-pressed="true|false"`를 추가합니다. 속성이 있는 동안 항목과 그 안의 self Interaction 레이어 모두 `:hover`·`:active` 대신 이 값으로 눌림 표현과 divider 숨김을 결정하며, 속성이 없으면 기존과 같습니다.
  - `prefers-reduced-motion: reduce`에서는 눌림 표시가 이동하지 않고 항목별로 바뀝니다.

  Migration Notes
  - 없음

- 10daf2c: ScrollArea 세로 커스텀 스크롤바의 inline-start/end 위치 변수를 공개 override로 제공합니다. 좌우 분할 화면에서 root 스크롤바를 본문 열 경계에 배치할 수 있으며 기존 기본 배치는 유지됩니다.

  Migration Notes
  - 기존 사용법 변경은 필요하지 않습니다.
  - scrollbar part에 `inset-inline-end`를 직접 지정하던 경우 ScrollArea host의 `--oc-scroll-area-scrollbar-vertical-inset-inline-end` 지정으로 대체할 수 있습니다. 시작 쪽으로 옮길 때는 `--oc-scroll-area-scrollbar-vertical-inset-inline-start`와 함께 반대쪽 값을 `auto`로 지정합니다.

### Patch Changes

- f75629f: `Menu`에서 누른 채 미끄러지는 선택이 끝난 뒤 지나간 항목에 hover 강조가 간헐적으로 남던 문제를 고칩니다.
  - 지나간 항목의 `data-oc-pressed="false"`를 다음 포인터 이동 때가 아니라, 포인터가 그 항목에 다시 들어오거나 그 항목을 누를 때 해제합니다.
  - Chrome은 마우스를 누른 채 끄는 동안 마지막으로 갱신한 항목에 `:hover`를 남기고, 포인터가 다른 곳으로 움직인 뒤에도 바로 바로잡지 않습니다. 이전에는 이 묵은 `:hover`가 강조로 드러났습니다.

  Migration Notes
  - 없음

- 2abadb2: bottom sheet의 snap 높이가 시트 최대 높이를 넘을 때 드래그로 닫히지 않던 문제를 수정합니다.
  - `Modal`의 `snapPoints`가 시트의 CSS 최대 높이(기본값은 뷰포트 높이에서 `--oc-modal-sheet-block-start-clearance`를 뺀 값)보다 크면 그 최대 높이로 해석합니다. 실제 시트는 원래 최대 높이까지만 그려졌지만 드래그 계산은 더 큰 snap 높이를 기준으로 삼아 두 값이 clearance만큼 어긋났습니다.
  - `resize='fixed'` 시트에서 이 조건일 때 임계 거리 이상 끌거나 빠르게 내려도 시트가 닫히지 않고 원위치로 돌아가던 문제가 해결됩니다. 기본 clearance(`3rem`)만으로도 `snapPoints={[1]}`이나 높이가 낮은 뷰포트에서 재현됐습니다.
  - 같은 조건의 `peekable` 시트가 peek로 내려갈 때 헤더 일부만 보이던 문제가 해결됩니다.
  - 같은 조건에서 더 낮은 snap이 지정한 높이보다 clearance만큼 낮게 멈추던 문제가 해결됩니다. 예를 들어 844px 뷰포트의 `snapPoints={[0.5, 1]}`에서 `0.5` snap은 374px가 아니라 422px로 멈춥니다.
  - `onSnapPointChange`가 전달하는 값은 바뀌지 않고 `snapPoints`에 지정한 원래 값 그대로입니다.

  Migration Notes
  - 최대 높이를 넘는 snap과 더 낮은 snap을 함께 쓰는 화면은 낮은 snap의 정지 위치가 clearance만큼 높아지므로 배치를 확인합니다. 그 밖의 변경은 필요 없습니다.

- fae9e74: `PageIndicator` 조작 모드에서 마우스로 점을 클릭할 때 hover 표시가 깜빡이던 문제를 고칩니다. 누르는 동안에도 끝의 작은 점은 `+` 힌트를 유지하고 누른 점은 확대된 크기를 유지합니다. 길게 눌러 스크럽이 시작되면 이전처럼 힌트가 사라집니다.

  Migration Notes
  - 없음

### Migration Notes

- `ActionAreaLayout.ActionArea`의 `background` prop과 `ActionAreaLayoutActionAreaBackground` 타입을 제거합니다. `background`/`background="auto"`는 지우고, `background={false}`는 Footer의 `scrollEdgeVariant="none"`으로 옮깁니다. `contained`에서 기존 번짐이 필요하면 Footer에 `scrollEdgeVariant="fade"`를 지정합니다.
- footer 배경색 `--oc-action-area-background-color`는 Footer나 조상에 지정합니다. 기존 스크롤 상태별 padding 보정, 단독 ActionArea 그라디언트와 extraContent 불투명 배경에 의존한 화면은 위 상세 Migration Notes에 따라 조정합니다.
- `caption`·`actions`·`compact-row`는 `action-group` 안으로 이동합니다. 직속 자식 선택자를 수정하고, `--oc-action-area-gap`은 extra와 action 묶음 사이 전체 간격으로 다시 확인합니다. `ActionAreaLayoutScrollState`는 deprecated입니다.
- 최대 높이를 넘는 snap과 더 낮은 snap을 함께 쓰는 bottom sheet는 낮은 snap의 정지 위치가 clearance만큼 높아지므로 배치를 확인합니다.
- ScrollArea scrollbar part의 직접 inset override는 host의 `--oc-scroll-area-scrollbar-vertical-inset-inline-start/end`로 옮길 수 있습니다. 기존 기본 배치는 유지됩니다.
- Menu 문자열 제목은 기본 중간 말줄임과 원문 툴팁으로 표시됩니다. 내부 ScrollArea viewport 추가에 따른 직속 자식 선택자를 확인하고, 스크롤 가능한 메뉴의 일반 터치 pan은 내부 스크롤로 동작하는지 확인합니다.
- Reveal과 RevealGroup의 div wrapper는 소비자 레이아웃·semantic 구조에 맞춰 배치합니다. `OcMotionIntent`를 전수 매핑하는 코드는 새 `reveal` 항목을 처리합니다. 제어 모드에서는 native `hidden` 대신 `visible`을 사용합니다.
- 방문 기록의 key와 계층 depth는 구분하며 입력값·라우터·이동 검증은 소비자가 관리합니다. Modal 제목은 기본 한 줄 말줄임을 유지하며 긴 제목은 `titleOverflow="wrap"`으로 표시할 수 있습니다.
- `animateScrollTo`는 `@orioncactuscorp/ui/utils/scroll`에서 import합니다. `useDragScroll`과 자동 인계하며, native `scrollTo` 등 외부 이동은 기존처럼 직접 `cancel()`을 연결합니다.
- Menu padding 또는 radius factor를 조정한 화면은 셀 radius를 확인합니다. 기본 Menu와 SegmentedControl 모양은 유지되며 `oc-inner-radius`는 `@orioncactuscorp/ui/scss/mixins/radius`에서 제공합니다.
- 소비 앱 검증에는 `@orioncactuscorp/ui@1.25.0-next.0`을 정확한 버전으로 고정합니다.

## 1.24.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.23.0..HEAD`_

#### Fixes

- `036d4e0` fix(page-indicator): derive hover hint from animated window (#468)

#### Other

- `a765fc1` InteractionScope 공유 hover 추가 (#430)
- `56a52f2` Slider 컴포넌트 추가 (#434)
- `50c26d5` PageIndicator 추가와 스냅 페이지 번호 훅 (#435)
- `fca5d1d` Carousel 컴포넌트 추가와 useDragScroll cancel 공개 (#438)
- `efb9b51` AnimatedNumber 컴포넌트 추가 (#436)
- `31d7450` PageIndicator 점 크기·활성 색 모션과 교차 축 판정 보완 (#437)
- `0f25fbb` InteractionScope 공유 hover 개별 영역 검사의 실시간 경쟁 조건 제거 (#441)
- `64ae693` PageIndicator 조작 모드와 터치 넘기기·탭 펼치기 추가 (#439)
- `d26137d` ScrollArea scroll edge와 Modal·FloatingWindow header·footer 크롬 추가 (#432)
- `7cded5c` Safari 텍스트 선택 방지용 -webkit-user-select 누락 보완과 재발 방지 검사 (#443)
- `2432167` SegmentedControl thumb 드래그 snap 인터랙션 (#431)
- `945dc1c` Modal 헤더 탭 키보드 테스트의 reveal spring 프레임 경쟁 조건 제거 (#444)
- `0cd848b` oc-motion 길게 누르기용 hold intent와 혼합 transition용 reduced 함수 추가 (#442)
- `3ec914e` PageIndicator 길게 누르기·마우스 머무르기에 hold 모션 적용 (#445)
- `e9da3a0` PageIndicator 작은 끝 점 중심 마우스 조작과 + 안내 (#448)
- `3eee4fa` PageIndicator 펼침 smooth 모션과 마우스 스크럽 거리 절반 (#449)
- `4147e68` SegmentedControl 말줄임 라벨 전체 텍스트 툴팁 (#446)
- `2af5ef0` Carousel slide loop 버튼·끌기·관성까지 양 끝을 넘는 순환 (#447)
- `cf386f3` Carousel slide 연타 이동의 속도 이어받기 (#450)
- `1512a21` Carousel 자동 넘김 일시정지 조건 보완과 슬라이드 텍스트 선택 허용 (#453)
- `52c88d6` Loading 확정 진행률과 끊김 없는 모드 전환·퇴장 모션 (#454)
- `852951c` ProgressIndicator 불확정 상태·흐름 하이라이트·퇴장 모션 (#457)
- `dcae01a` Carousel 제어형 index (#455)
- `d89b542` PageIndicator 인디케이터 hover 시 끝 점 + 힌트 (#456)
- `4e987e3` ageIndicator 숨은 점 hit area 상한으로 WebKit 멈춤 수정 (#462)
- `49f50bf` scrollToIndex 스크립트 이동으로 브라우저 간 동일한 smooth 스크롤 (#463)
- `7f74dd3` PageIndicator 터치 스크럽 이동 거리를 마우스와 동일하게 조정 (#464)
- `afb9b1c` Loading 확정 진행률 호를 실제 진행 비율로 표시 (#459)
- `1530e28` AnimatedNumber roll 모션 블러의 Safari 분홍 세로선 제거 (#460)
- `bbe4429` Carousel 터치 길게 누르기 텍스트 선택 차단과 선택 중 자동 넘김 정지 (#461)
- `654ec6c` PageIndicator 창 연속성 e2e의 transition seek 기반 결정적 측정 (#465)
- `2f2c59f` Slider 터치 세로 스와이프의 페이지 스크롤 전환과 터치 포커스 링 제거 (#466)
- `06db87a` Carousel slide 마우스 끝단 rubber band와 useDragScroll matchMedia 가드 (#467)
- `76095eb` 1.24.0 릴리스 노트와 배포 문서의 소스 대조 정정 (#469)
- `8ebcf37` Slider 터치 commit 판별·보류 값 보정과 Safari 마우스 드래그 텍스트 선택 차단 (#470)
- `7d3adf4` InteractionScope 묶음 안 빈 공간을 잇는 공유 hover 판정 (#471)
- `c24cb5d` 1.24.0 SegmentedControl Migration Notes 정정 (#472)
<!-- generated:end -->

### Minor Changes

- efb9b51: 값이 바뀔 때 바뀐 자리만 움직이는 숫자 `AnimatedNumber` 컴포넌트를 추가합니다.
  - `Intl.NumberFormat` 서식(`format`, `locales`)으로 정수, 소수, 통화, 퍼센트, compact 표기를 그립니다. 자리는 자릿값으로 추적해 99 → 100처럼 길이가 바뀌어도 남는 자리가 이어지고, 바뀐 폭은 남는 자리가 미끄러지며 맞춥니다.
  - `variant`(`none`·`slide`·`blur`·`roll`, 기본 `slide`)로 바뀐 자리의 표현을 고릅니다. `roll`은 사이 숫자를 지나 굴러가고, `spins`를 주면 모든 자리가 더 돌고 왼쪽부터 차례로 멈추는 값 공개 표현이 됩니다.
  - `trend`(`auto`·`up`·`down`)로 방향, `pace`(`quick`·`normal`·`slow`)로 공용 `move` motion 속도를 정합니다. 움직이는 도중 값이 바뀌면 현재 위치에서 이어집니다. reduced-motion에서는 opacity만 바뀝니다.
  - 움직이는 동안만 가장자리 fade mask를 적용하고, 정지 상태의 box와 글자는 같은 글꼴의 일반 텍스트와 같습니다. 글자 크기·굵기는 감싸는 요소를 상속하며 숫자는 기본 `tabular-nums`입니다.
  - 보조기술에는 최종 값 문자열만 노출하고 기본으로 변경을 안내하지 않습니다. 안내가 필요하면 `aria-live`를 지정하세요. SSR에서는 서식이 적용된 문자열을 그대로 출력합니다.
  - selector `data-oc-component="animated-number"`, `data-oc-variant`, `data-oc-moving`을 추가합니다. 공개 CSS 변수는 없습니다. `AnimatedNumber`는 client component입니다.

  ### Migration Notes
  - 없음

- fca5d1d: `CarouselRoot`, `CarouselSlide` 컴포넌트를 추가합니다.
  - `transition`(`slide`·`fade`, 기본 `slide`): slide는 네이티브 scroll-snap에 슬라이드를 나란히 두고 터치·트랙패드·휠을 브라우저에 맡기며 마우스 드래그만 보강합니다. loop가 아닌 slide에서 마우스로 양 끝을 더 끌면 트랙이 트랙패드처럼 살짝 늘어났다가 돌아옵니다(reduced-motion에서는 경계에서 멈춤). fade는 슬라이드를 겹쳐 두고 가로 드래그 거리에 맞춰 크로스페이드하며, 트랙패드 가로 스와이프 한 번에 한 장씩 넘기고 세로 스크롤은 페이지에 넘깁니다.
  - slide의 다음·이전 버튼, 자동 넘김, 인디케이터 클릭·방향키 이동은 `move` motion 토큰(`--oc-motion-duration-move`, 전역 duration 배율)을 따르는 스크립트 이동입니다. 빠르게 연달아 눌러도 속도를 이어받아 감속·재가속 없이 흐르고(loop에서는 이동보다 한 바퀴 이상 앞서 눌러도 누른 만큼 같은 방향으로 이어집니다), 남은 거리에 맞춰 늦게 감속해 마지막 슬라이드에 overshoot 없이 멈추며, 착지 직전 마지막 몇 픽셀도 프레임마다 1px 이상 이어서 움직여 멈칫하지 않습니다. reduced-motion에서는 즉시 이동하고, 이동 중 reduced-motion이나 방향(`dir`)이 바뀌면 선택된 슬라이드에 바로 착지합니다. 이동 중 터치·마우스 드래그로 잡으면 그 자리에서 손에 넘기고, 휠·키보드로 스크롤하면 멈춘 뒤 가까운 슬라이드로 미끄러져 정착합니다. 인디케이터는 연속 탭이 더블탭 확대로 처리되지 않도록 `touch-action: manipulation`을 사용합니다.
  - `loop`: fade는 끌기까지 끊김 없이 순환합니다. slide는 다음·이전 버튼, 자동 넘김, 인디케이터 방향키, 터치·트랙패드·휠·마우스 끌기와 그 관성으로 양 끝을 넘어 같은 방향으로 계속 이어집니다. 긴 칸 트랙 위에서 화면 밖 슬라이드만 옮기는 방식이라 빠르게 연달아 넘겨도 끝에 닿지 않습니다. 이를 위해 슬라이드의 DOM 복제본(`data-oc-clone`, `aria-hidden`, `inert`)을 함께 배치하며, DOM·탭·읽기 순서는 그대로이고 정지 상태에서는 항상 원본 슬라이드가 보입니다.
  - `autoplay`(`true` 또는 `{ interval, pauseOnHover }`, 기본 5초, 최소 1초): 스토리형 진행 막대가 타이머를 표시합니다. 누르고 있으면 잠시 멈추고, 짧게 클릭·탭하면 정지·재생이 바뀌며, 끌다가 놓으면 그 순간 착지할 슬라이드부터 다시 셉니다. 키보드 포커스가 들어오면 멈추고, reduced-motion에서는 시작하지 않습니다. 화면에 절반 이상 보일 때(화면보다 긴 캐러셀은 화면의 절반 이상을 채울 때)만 진행하고, 탭이 숨겨졌거나 슬라이드 안에 포커스나 선택된 텍스트가 있는 동안 잠시 멈춥니다. `pauseOnHover`(기본 `false`)를 켜면 마우스를 올린 동안 멈춥니다. `CarouselSlide`의 `loading`이 켜진 슬라이드에서는 시작 지점에서 기다립니다.
  - 슬라이드 내용은 텍스트를 선택할 수 있고, 컨트롤만 선택을 막습니다. 끌기가 누름을 가져가는 동안과 터치·펜으로 누르고 있는 동안에는 선택과 이미지 끌기가 시작되지 않습니다(길게 눌러 멈출 때 텍스트가 선택되지 않음). 마우스로 끌거나 길게 눌러 선택할 영역은 `data-oc-drag-scroll-ignore`로 표시합니다. 이 영역은 탭으로 자동 넘김을 토글하지도 않습니다.
  - `<>...</>`로 감싼 슬라이드도 한 장씩 셉니다.
  - 진행 막대는 현재 슬라이드 칸만 채워집니다. 앞으로 넘어가면 떠나는 칸이 꽉 차면서 사라지고(완료), 뒤로 가면 현재 값에서 되감깁니다. 모든 전환은 화면에 보이는 값에서 다시 시작하므로 빠르게 연달아 넘겨도 끊기지 않습니다. 방향은 인덱스가 아니라 이동 의도로 정하므로 loop의 마지막→처음 다음은 앞으로입니다.
  - `index`(제어형), `defaultIndex`, `onIndexChange`: `index`를 주면 바깥 썸네일·URL 상태와 선택을 공유합니다. 버튼·인디케이터·키·자동 넘김은 제안만 하고 `index`가 바뀌어야 움직입니다. 끌기·스와이프는 손을 따라 먼저 움직이고, 부모가 받아들이지 않으면 스크롤이 정착하거나 디졸브가 끝난 뒤 `index`로 돌아갑니다. `onIndexChange`는 현재 값으로는 부르지 않고, 끌기 한 번에 놓는 순간과 다른 슬라이드에 정착했을 때 최대 두 번 부릅니다. 바깥에서 바꾼 `index`는 loop에서 가까운 쪽으로 이동하며, 부모가 거절한 자동 넘김은 꽉 찬 진행 막대로 기다립니다. 제어형·비제어형 전환과 유한하지 않은 `index`는 개발 모드에서 경고합니다.
  - WAI-ARIA APG tabbed carousel 시맨틱: root `region` + `aria-roledescription="carousel"`, indicator `tablist`, 슬라이드 `tabpanel`, 키보드로만 보이는 첫 Tab 정지점의 자동 넘김 정지·재생 버튼. root에는 `aria-label`/`aria-labelledby`가 필요하며, 없으면 개발 모드에서 경고합니다.
  - 이전·다음 `BackgroundIconButton`은 hover 가능한 fine pointer 기기에서 hover·포커스 시 나타납니다.
  - 공개 CSS 변수 `--oc-carousel-radius`와 selector `data-oc-component="carousel"`, `data-oc-transition`, `data-oc-autoplay`, `data-oc-part="viewport|slides|indicator|segment|track|progress|navigation|autoplay-control|slide"`, 슬라이드의 `data-oc-state="active|inactive"`, loop slide 복제본의 `data-oc-clone`을 추가합니다.

  ### Migration Notes
  - 없음

- fca5d1d: `useDragScroll` 반환값에 `cancel()`을 추가합니다. 진행 중인 마우스 드래그와 release 관성·스냅 정착을 멈추고 스냅을 복원합니다. 스크롤 요소 밖 컨트롤에서 `scrollTo`를 호출하기 전에 부르면 release 정착이 새 스크롤을 덮어쓰지 않습니다.

  ### Migration Notes
  - 없음

- a765fc1: 나란히 놓인 컨트롤 사이에서 hover 표시 하나가 이동하는 공유 hover를 `InteractionScope`로 추가합니다.
  - `InteractionScope`로 감싼 영역에서 마우스 포인터가 참여 컨트롤 밖으로 나가지 않고 다음 컨트롤로 넘어가면, 새로 hover된 컨트롤의 Interaction이 직전 컨트롤의 위치·크기·radius·색에서 출발해 자기 자리로 이동합니다. 별도 레이어를 만들지 않으므로 각 컨트롤의 Interaction 색·radius·inset·강도 계약과 clipping은 그대로입니다.
  - 앱 루트를 감싸면 전체에, 일부를 감싸면 그 영역에만 적용됩니다. 안쪽 scope가 우선하며 `hover="individual"`로 영역 단위로 끌 수 있습니다. scope에서 연 portal 콘텐츠도 포함됩니다.
  - 자기 표면이 없는 컨트롤인 `IconButton`, `TextButton`, interactive `CellItem`, `TabsTab`, `SegmentedControlItem`이 참여합니다. 커스텀 host는 새 prop `<Interaction sharedHover />`로 참여합니다. `Button`처럼 표면이 있는 컨트롤은 참여하지 않습니다.
  - 직전 hover 표시가 사라지는 중이고, 직전 컨트롤에서 포인터까지의 경로가 참여 컨트롤과 같은 묶음의 빈 공간만 지날 때 이동합니다. 같은 묶음은 한 컨테이너에 나란히 놓인 컨트롤이며, header 내비게이션 링크나 Alert 액션처럼 사이에 layout gap이 있어도 이어집니다.
  - 사이에 텍스트·구분선·참여하지 않는 컨트롤이 있는 경우, 서로 다른 묶음이나 scope, disabled 대상, focus되거나 눌린 출발 컨트롤, 터치·펜 입력, `prefers-reduced-motion: reduce`에서는 기존처럼 개별로 반응합니다. 빈 공간을 천천히 건너 직전 표시가 다 사라진 뒤 도착해도 개별로 반응합니다. focus와 press 표시는 바뀌지 않습니다.
  - scope를 쓰지 않으면 동작과 렌더링 결과가 이전과 같습니다. 참여 컴포넌트의 Interaction에 `data-oc-shared-hover="true"` 속성만 추가됩니다.
  - selector `data-oc-component="interaction-scope"`, `data-oc-hover="shared|individual"`, `data-oc-shared-hover="true"`를 추가합니다. `InteractionScope`는 client component입니다.

  ### Migration Notes
  - 없음

- 52c88d6: `Loading`에 확정 진행률 `value`·`max`와 퇴장 모션 `visible`·`onExitComplete`를 추가합니다.
  - `value`가 숫자면 호 길이로 진행률을 그리고 `role="progressbar"`와 `aria-valuemin`·`aria-valuemax`·`aria-valuenow`를 쓰며, 불확정 모드와 달리 `aria-live`는 두지 않습니다. `null`·`undefined`면 기존 불확정 루프(`role="status"`)입니다. 호는 진행률과 같은 비율로 원을 그려 0%에서는 트랙 위 끝점만 남고 100%에서 닫히며, 확정 모드에서는 회전을 유지해 진행률이 멈춰도 작동 중임을 보여 줍니다.
  - 불확정 → 확정 → 100% → 불확정 대기 → 퇴장처럼 상태가 바뀌어도 지금 그려진 호에서 다음 모션이 이어지고 회전은 다시 시작되지 않습니다. 확정에서 불확정으로 갈 때는 호가 꼬리부터 감긴 뒤 루프로 이어집니다.
  - `visible={false}`는 호가 감기며 사라지는 퇴장을 재생하고 끝나면 `onExitComplete`를 호출합니다. 요소는 그때까지 남아 있으므로 `onExitComplete`에서 unmount합니다. 전환이나 퇴장 도중 상위 `Suspense`에 의해 숨겨졌다가 다시 보이면 중단된 전환을 목표 상태로 마무리합니다.
  - 확정 모드 트랙 색 `--oc-loading-track-color`(override)를 추가합니다. 기본은 스피너 색의 28%입니다.
  - 회전은 호(`circle`)가 아니라 `indicator`(`svg`)에서 일어나고, `track`·`arc` part와 `data-oc-state="indeterminate|determinate"`를 추가합니다. `[data-oc-part='indicator'] circle`에 `transform`이나 `animation`을 지정했다면 `arc` part 기준으로 옮겨야 합니다.
  - `Loading`은 client 컴포넌트(`'use client'`)가 됩니다. Server Component에서 그대로 렌더링할 수 있습니다.

  ### Migration Notes
  - 기존 사용(`value` 없음)은 그대로 동작합니다.
  - `[data-oc-part='indicator'] circle`을 직접 스타일링했다면 `[data-oc-part='arc']`로 옮기세요. 트랙 원이 추가되어 `circle` 선택자가 두 원에 모두 적용됩니다.

- 0cd848b: `oc-motion`에 길게 누르기·hover 체류용 `hold` intent와 `charge` phase를 추가합니다.
  - `hold charge`: 누르거나 머무는 동안 예열합니다. 시간은 `--oc-motion-duration-hold`(기본 0.65초) × `$pace`이고, 곡선은 iOS Haptic Touch 실측값 `--oc-motion-timing-hold`입니다. 입력 판정 시간이므로 `--oc-motion-duration-factor`와 `$duration-factor`를 적용하지 않고 reduced-motion에서도 바꾸지 않습니다.
  - `hold enter` / `hold release`: 판정 순간의 팝은 반동이 보이는 snappy spring(bounce 0.25), 판정 전 복귀는 snappy spring(bounce 0.15)을 사용합니다(response 0.2초). reduced-motion에서는 bounce 없는 smooth spring으로 바뀝니다.
  - `oc-motion-scale(..., hold)`는 `--oc-motion-scale-factor-hold`를 따르며, reduced-motion에서 `--oc-motion-scale-factor-hold-reduced`(기본 0.25)를 곱해 부풀기의 25%만 남깁니다.
  - runtime `resolveOcMotion({ intent: 'hold', phase: 'charge', element })`이 같은 token을 읽어 판정 타이머 시간을 돌려줍니다.
  - 새 token: `--oc-motion-duration-hold`, `--oc-motion-duration-hold-enter`, `--oc-motion-duration-hold-release`, `--oc-motion-timing-hold`, `--oc-motion-timing-hold-enter`, `--oc-motion-timing-hold-release`, `--oc-motion-scale-factor-hold`, `--oc-motion-scale-factor-hold-reduced`.
  - 여러 intent를 한 `transition`에 섞는 경우를 위해 reduced-motion transition item을 돌려주는 `oc-motion-reduced(...)` 함수를 추가합니다.
  - `charge`는 `hold` 전용이고 `hold`는 `charge`, `enter`, `release`만 받습니다. 잘못된 조합은 Sass와 runtime 모두 오류를 냅니다.

  ### Migration Notes
  - 없음

- 3ec914e: `PageIndicator` 조작 모드의 터치·마우스 길게 누르기에 `oc-motion`의 `hold` 모션을 적용합니다.
  - 판정 시간은 작은 컨트롤용 quick pace로 `--oc-motion-duration-hold` × `--oc-motion-pace-quick`(기본 약 0.49초)을 따르며, 터치와 마우스 길게 누르기가 같은 값을 사용합니다.
  - 누르는 동안 인디케이터가 조금씩 부풀고 캡슐 배경이 옅게 차오르며, 판정 순간 짧은 스프링으로 캡슐이 완전히 나타납니다. 판정 전에 놓으면 그 자리에서 되돌아갑니다. 터치 탭, 작은 끝 점 클릭, 키보드 포커스로 펼치고 접을 때는 튐 없는 `move` 모션을 사용합니다.
  - 마우스로 접힌 점을 판정 시간 동안 누르고 있으면 스크럽이 시작되고, 그대로 놓아도 클릭으로 처리하지 않습니다.
  - 캡슐(`capsule` part)을 `Background` 표면으로 렌더링합니다.
  - reduced-motion에서는 예열을 유지하되 부풀기를 줄이고, 판정 순간의 튐 없이 자리 잡습니다.
  - selector `data-oc-holding="touch|mouse"`를 추가합니다.

  ### Migration Notes
  - 없음

- 64ae693: `PageIndicator`에 점으로 페이지를 이동하는 조작 모드를 추가하고, `useScrollSnapIndex`가 `scrollToIndex`를 반환합니다.
  - `onIndexChange(index, { reason })`를 지정하면 `role="slider"`가 되어 방향키(RTL 반전)·Home/End·PageUp/PageDown으로 이동을 요청합니다. `aria-label` 또는 `aria-labelledby`가 필요하며 `getAriaValueText`로 값 문구를 지정합니다. 지정하지 않으면 기존 표시 전용 동작과 같습니다.
  - 마우스 hover는 점 배치를 바꾸지 않아, 보이는 점을 클릭하면 그 페이지로 이동을 요청합니다(`reason: 'press'`). hover한 점은 원래 크기로 커집니다. 포인터가 인디케이터 위에 있으면 끝의 가장 작은 점이 원래 크기로 커지며 옅은 `+` 아이콘을 보여 주고, 그 점을 hover하면 점 간격만큼 커지며 `+`가 선명해집니다. 이 점을 클릭하면 이동 대신 모든 페이지를 펼칩니다. 펼친 줄이 놓인 영역에 들어가지 않으면 `+` 없이 다른 점처럼 동작합니다. 숨은 점은 작은 점 바깥에 간격 없이 접혀 있다가 펼칠 때 간격과 함께 벌어집니다. 펼친 점은 클릭하거나 끌어 포인터 아래 페이지로 이동하며, 고른 뒤 또는 포인터가 벗어난 뒤 1초가 지나면 접힙니다. 키보드 포커스 동안에도 모든 페이지를 펼칩니다.
  - 접힌 점을 마우스로 4px 넘게 끌거나 길게 누르면 캡슐이 나타나고, 누른 점부터 점 간격의 절반마다 한 페이지씩 이동을 요청합니다(`reason: 'scrub'`).
  - 터치에서는 길게 누르면 캡슐이 나타나고, 이어서 좌우로 움직이면 마우스와 같이 점 간격의 절반마다 한 페이지씩 이동을 요청합니다(`reason: 'scrub'`). 인디케이터는 가로 이동을 직접 받으므로(`touch-action: pan-y`) 길게 누르기 전의 가로 스와이프는 아무 동작도 하지 않고, 세로 페이지 스크롤은 브라우저 동작을 유지합니다. 짧게 탭하면 모든 페이지를 펼치고, 펼친 점을 탭하거나 좌우로 끌어 원하는 페이지로 이동합니다. 펼친 폭이 들어가지 않으면 펼치지 않습니다.
  - `useScrollSnapIndex`가 `scrollToIndex(index, { behavior })`를 반환합니다. 기본 `'smooth'`는 브라우저 smooth scroll 대신 `Carousel` 버튼 이동과 같은 `move` 모션으로 스크립트 이동해 Safari에서도 같은 속도로 움직이고, 스냅 위치에 정확히 멈춥니다. 사용자 입력이 들어오면 즉시 멈추고, reduced-motion에서는 바로 이동합니다. `'auto'`는 CSS `scroll-behavior`를 따릅니다. 넘기기에는 `behavior: 'instant'`를 권장합니다.
  - selector `data-oc-interactive="true"`, `data-oc-scrubbing="mouse|touch"`, `data-oc-expanded="true"`, part `capsule`과 이동하는 묶음의 점 안에 part `icon`을 추가합니다. `+`는 작은 점 자리에서만 보이며 묶음 이동을 따라 연속으로 바뀝니다.

  ### Migration Notes
  - 없음

- 50c26d5: 캐러셀 페이지 위치를 점으로 표시하는 `PageIndicator`와 스냅 페이지 번호를 계산하는 `useScrollSnapIndex`를 추가합니다.
  - `PageIndicator`는 `count`와 0부터 시작하는 `index`를 받습니다. 6페이지 이상에서는 7칸을 표시하며 가운데 3칸은 원래 크기, 바깥으로 0.67배·0.33배입니다. 현재 페이지가 가운데 3칸을 벗어날 때만 점 묶음이 이동하며, 한 페이지씩 넘기면 한 칸, 멀리 이동하면 필요한 만큼 건너뜁니다. 5페이지 이하에서는 모든 점을 원래 크기로 표시합니다.
  - 묶음 이동과 점 크기 변화는 `move` 모션을 사용하며 reduced-motion에서는 즉시 바뀝니다. 활성 점 색은 `feedback` 모션으로 바뀌며 reduced-motion에서도 유지됩니다.
  - 점 색은 `--oc-page-indicator-color`(기본값 `label-normal`, 비활성 점은 이 색의 16%)와 `--oc-page-indicator-active-color`로 조정합니다.
  - 기본적으로 장식 요소(`aria-hidden="true"`)이며, `aria-label` 또는 `aria-labelledby`를 지정하면 `role="img"`로 렌더링합니다. 위치 안내는 캐러셀 슬라이드 레이블이 담당합니다.
  - `@orioncactuscorp/ui/react/scroll`의 `useScrollSnapIndex`는 네이티브 스냅 영역에서 다음 또는 이전 페이지가 절반을 넘게 보이면 페이지 번호를 갱신합니다.
  - selector `data-oc-component="page-indicator"`, part `track`·`dot`, dot의 `data-oc-state="active|inactive"`·`data-oc-tier="full|medium|small|hidden"`을 추가합니다. `PageIndicator`는 client component입니다.

  ### Migration Notes
  - 없음

- 852951c: `ProgressIndicator`에 불확정 상태, 흐름 하이라이트 `loading`, 퇴장 모션 `visible`·`onExitComplete`를 추가합니다.
  - `value`가 `null`·`undefined`면 불확정 상태로, `aria-valuenow` 없이 구간 하나가 머리가 먼저 달리고 꼬리가 쫓는 루프를 반복합니다. `value`는 이제 생략할 수 있습니다.
  - `loading`을 주면 확정 진행 중 채움 안에 스태틱 화이트 하이라이트가 일정한 속도로 흐릅니다(`data-oc-loading="true"`). 켜고 끌 때는 계속 흐르면서 서서히 나타나고 사라집니다. 기본은 꺼져 있어 단계 표시 등 기존 사용은 그대로입니다.
  - 확정 → 100% → 불확정 → 퇴장처럼 상태가 바뀌어도 지금 그려진 구간에서 다음 모션이 이어집니다. 확정에서 불확정으로 갈 때는 꼬리가 머리를 쫓아 감긴 뒤 루프가 시작되고, 진행 중인 구간은 되감기지 않고 먼저 감긴 뒤 시작 쪽부터 진행률이 자랍니다.
  - `visible={false}`는 구간이 감기며 사라지는 퇴장을 재생하고 끝나면 `onExitComplete`를 호출합니다. 요소는 그때까지 남아 있으므로 `onExitComplete`에서 unmount합니다. 전환이나 퇴장 도중 상위 `Suspense`에 의해 숨겨졌다가 다시 보이면 중단된 전환을 목표 상태로 마무리합니다.
  - 채움은 `inline-size` 대신 track 전체 너비 층을 `clip-path`로 잘라 그립니다. RTL 문서에서는 채움 층을 좌우 반전합니다. `data-oc-state`, `data-oc-loading` selector를 추가합니다.
  - `ProgressIndicator`는 client 컴포넌트(`'use client'`)가 됩니다. Server Component에서 그대로 렌더링할 수 있습니다.
  - reduced-motion에서는 감기기와 하이라이트를 생략하고 퇴장은 opacity 전환만 남깁니다. 불확정 루프는 느린 속도로 유지합니다.

  ### Migration Notes
  - 기존 사용(`value` 숫자)은 그대로 동작합니다.
  - `[data-oc-part='indicator']`에 `inline-size`·`inset`을 직접 지정한 스타일은 이제 track 전체를 덮는 채움 층의 크기·위치를 바꿔 진행 표시를 왜곡하므로 제거하세요. 길이는 `value`·`max`로 지정하고, 색·두께·radius는 기존 `--oc-progress-indicator-*` 변수를 사용하세요.

- d26137d: header·footer 아래로 스크롤되는 콘텐츠를 처리하는 `ScrollAreaEdge`와, 그 기반인 `ScrollArea`의 가장자리 넘침 상태를 추가합니다.
  - `ScrollArea` 루트가 `data-oc-overflow-y-start`, `data-oc-overflow-y-end`, `data-oc-overflow-x-start`, `data-oc-overflow-x-end`(`"true" | "false"`)를 노출합니다. 경계를 넘을 때만 DOM에 직접 갱신하므로 스크롤 중 React 렌더링이 없습니다. 기존 `ScrollArea`에도 이 속성이 추가되며, 그 밖의 동작과 렌더링 결과는 같습니다.
  - `ScrollAreaEdge`(`side="top | bottom"`, `variant="fade | progressive-blur"`)를 `ScrollArea`의 직계 자식으로 두면, 해당 쪽 bar를 덮고 그쪽으로 콘텐츠가 스크롤된 거리만큼 bar 너머로 가장자리 처리가 번집니다. 서버 컴포넌트에서도 렌더링할 수 있는 장식 요소이며 `aria-hidden`입니다.
  - 공개 CSS 변수 `--oc-scroll-area-edge-inset-block-start`/`-end`(bar 높이), `--oc-scroll-area-edge-bleed`(bar 너머로 번지는 길이), `--oc-scroll-area-edge-color`, `--oc-scroll-area-edge-blur`를 추가합니다. 세로 scrollbar track은 bar 높이만큼 비켜 시작하고, bar 너머로 번지는 edge는 track 아래에 그려집니다.
  - `prefers-reduced-transparency: reduce`에서는 `progressive-blur`가 불투명 scrim으로 바뀌고, `backdrop-filter`를 지원하지 않으면 tint를 진하게 합니다.
  - `ModalHeader`에 서로 독립된 `backgroundVariant`(`BackgroundVariant | 'none'`, 기본 `strong`)와 `scrollEdgeVariant`(`'none' | 'fade' | 'progressive-blur'`, 기본 `none`), `divider`(`DividerVariant | 'none'`, 기본 `normal`)를 추가합니다. scroll edge는 header를 덮고, 본문이 맨 위에 있을 때는 header 안에 머물다가 스크롤한 거리만큼만 bleed까지 번집니다. divider는 배경이 있고 scroll edge가 없는 header, 또는 `scrollEdgeAppearance="hard"`인 header에서 콘텐츠가 header 아래로 스크롤될 때 나타납니다. **기존 Modal·FloatingWindow header도 스크롤하면 하단 divider가 나타납니다.** 끄려면 `divider="none"`을 지정하세요. header에는 `data-oc-background-variant` 속성이 추가됩니다.
  - `ScrollAreaEdge`에 `appearance`(`'soft' | 'hard'`, 기본 `soft`, `data-oc-appearance`)를 추가하고, Modal·FloatingWindow header·footer는 이를 `scrollEdgeAppearance`로 넘깁니다. `hard`는 scroll edge를 bar 안에만 두고 bar 끝까지 균일하게 덮으며, owner가 divider로 경계를 닫습니다.
  - `ModalFooter`·`FloatingWindowFooter`에 같은 `backgroundVariant`(기본 `none`), `scrollEdgeVariant`(기본 `fade`), `divider`(기본 `normal`)를 추가합니다. footer의 scroll edge는 footer 안에 렌더링되어 키보드·높이 전환과 함께 움직이고, header처럼 항상 footer를 덮다가 아래에 남은 거리만큼 bleed까지 번집니다. `background={false}`이면 edge를 그리지 않고, 재질 footer의 divider는 기존 `background` 정책(`auto | true | false`)으로 표시됩니다. 기존 footer fade는 footer 위로 padding 두 배만큼 번졌지만, 이제 아래에 남은 콘텐츠가 있을 때만 남은 거리만큼 최대 `--oc-space-section-gap-large`까지 번지고 맨 끝에서는 footer 안에 머뭅니다. `FloatingWindowHeader`도 `ModalHeader`와 같은 prop을 받습니다.
  - `ScrollAreaEdge`는 항상 chrome을 덮고 스크롤한 거리만큼 bleed까지 늘어나며, owner가 끌 수 있는 `visible` prop(`data-oc-state="visible | hidden"`)과 공개 변수 `--oc-scroll-area-edge-fade-size`를 추가합니다. `progressive-blur` tint 기본 진하기는 74%(Background normal과 같음)입니다. bleed는 해당 쪽 끝에서 스크롤한 거리만큼만 적용되어, 맨 위·맨 끝에서는 edge가 bar 안에 머뭅니다.
  - `ScrollArea`의 CSS 변수 기본값을 specificity 0으로 낮춰, owner가 지정한 값이 번들의 CSS 순서와 관계없이 적용됩니다. 배포 `styles.css`에서 Modal body의 세로 scrollbar가 header 아래가 아니라 위쪽 끝에서 시작하던 문제도 함께 고칩니다.
  - Modal·FloatingWindow의 header·footer 높이를 측정해 본문 여백, scrollbar track, scroll edge의 공통 기준으로 씁니다. 본문이 스크롤될 때 footer가 위쪽 padding을 빼고 body가 그 공간을 대신 확보하던 동작을 없애, footer는 스크롤 상태와 관계없이 같은 크기를 유지합니다. 버튼의 화면상 위치는 그대로이며, scrollbar track은 header 아래에서 footer 위까지 정확히 맞습니다. 여러 줄 ActionArea처럼 SCSS 기본값보다 큰 footer도 본문 여백에 반영됩니다.
  - foundation 토큰 `--oc-atomic-blur-soft`(16px)을 추가합니다. `progressive-blur`의 최소 blur 반경은 `--oc-scroll-area-edge-blur-floor`(기본 `soft` 1px, `hard` 2px)로, tint 진하기는 `ScrollAreaEdge`에 지정하는 `--oc-scroll-area-edge-tint-opacity`로 조절합니다.

  ### Migration Notes
  - Modal·FloatingWindow header는 본문이 스크롤되면 하단 divider를 표시합니다. 이전처럼 divider 없이 쓰려면 `ModalHeader`에 `divider="none"`을 지정하세요. FloatingWindow header와 material footer도 `divider="none"`으로 끌 수 있습니다.
  - Modal·FloatingWindow footer의 스크롤 fade는 아래에 남은 콘텐츠가 있을 때만 footer 위로 번지고, 맨 끝까지 스크롤하면 footer 안에 머뭅니다. 별도 조치는 필요 없으며, footer 바로 위 콘텐츠가 가려지는 정도가 달라지므로 해당 화면을 확인하세요.

- 4147e68: `SegmentedControl`에서 말줄임으로 잘린 라벨의 전체 텍스트를 툴팁으로 보여 줍니다.
  - label이 실제로 잘린 세그먼트만 툴팁이 열립니다. 잘림은 열리는 순간 1px 미만의 넘침까지 측정합니다.
  - 마우스는 hover, 키보드는 focus-visible로 열리고 `Escape`로 닫힙니다. 터치는 500ms 길게 누르면 열리며, 이때 손을 떼도 세그먼트를 선택하지 않습니다.
  - 컨트롤 하나가 툴팁 하나를 공유하고, label children 대신 텍스트만 보여 줍니다. 접근 가능한 이름에 이미 전체 텍스트가 있어 `aria-describedby`는 추가하지 않습니다.
  - thumb를 잡고 있는 동안에는 hover·focus로 열리지 않고, 잡은 thumb가 다른 세그먼트로 움직이면 닫힙니다. 아이콘만 있는 세그먼트와 disabled 세그먼트는 툴팁을 띄우지 않습니다.

  ### Migration Notes
  - 세그먼트를 소비자 Tooltip으로 따로 감싸고 있었다면 label이 잘린 세그먼트에서 툴팁이 두 개 열리므로 감싼 Tooltip을 제거하세요.

- 2432167: `SegmentedControl`의 thumb를 iOS처럼 붙잡고 옮겨 다른 세그먼트를 고를 수 있습니다.
  - 선택된 세그먼트를 마우스·터치·펜으로 누른 채 옮기면 thumb가 포인터 아래 세그먼트로 칸 단위로 snap합니다. 선택은 손을 뗄 때 한 번만 확정되고, 탭과 같은 `onValueChange` 경로를 거치므로 `eventDetails.cancel()`이 그대로 동작합니다.
  - 시작 세그먼트로 돌아와 떼거나 `Escape`, pointer cancel이 발생하면 선택이 바뀌지 않습니다. 컨트롤 밖에서도 가장 가까운 끝 세그먼트를 따라가며, disabled 세그먼트에는 thumb가 들어가지 않습니다.
  - 마우스·펜은 누르는 즉시, 터치는 150ms를 누르고 있거나 가로로 먼저 움직이면 thumb를 잡습니다. 잡은 동안 thumb가 0.95배로 살짝 줄어들고 손을 떼면 돌아옵니다. reduced-motion 환경에서는 크기가 바뀌지 않습니다.
  - 드래그 중 `aria-checked`는 확정된 세그먼트에 남고, 선택 label 색은 thumb가 가리키는 세그먼트로 옮겨 갑니다.
  - 터치에서는 선택된 세그먼트에만 `touch-action: pan-y pinch-zoom`을 적용해 가로 이동을 드래그로 씁니다. thumb를 잡기 전의 빠른 세로 스와이프는 페이지 스크롤로 넘기고, 잡은 뒤에는 손을 뗄 때까지 세로 스크롤을 막습니다. 두 손가락 확대는 그대로 둡니다.
  - 드래그 상태 selector `data-oc-dragging="true"`(root)와 `data-oc-thumb-target="true"`(item)를 추가합니다.

  ### Migration Notes
  - 선택된 세그먼트를 누른 채 다른 세그먼트에서 떼면 이전에는 아무것도 바뀌지 않았지만, 이제 그 세그먼트가 선택됩니다. 막아야 하면 `onValueChange`에서 `eventDetails.cancel()`을 호출하세요.
  - 터치에서 선택된 세그먼트는 `touch-action: pan-y pinch-zoom`을 가집니다. `SegmentedControl`을 가로 스크롤 영역 안에 두었다면 선택된 세그먼트에서 시작한 가로 스와이프가 영역을 스크롤하지 않고 thumb를 옮기므로 해당 화면을 확인하세요.

- 56a52f2: 범위 안에서 값 하나 또는 구간을 고르는 `Slider` 컴포넌트를 추가합니다.
  - 값 하나(`value`/`defaultValue`가 숫자) 또는 구간(숫자 배열, thumb마다 값 하나)을 고릅니다. 구간 thumb은 서로를 밀어내며 `minStepsBetweenValues`로 최소 간격을 둘 수 있습니다.
  - 포인터와 키보드 입력 모두 `step` 단위로 맞춰집니다. `marks`로 눈금을 표시하며, `true`면 `step`마다, 배열이면 지정한 값에만 그립니다. 채움 구간 안의 눈금은 색이 바뀝니다.
  - 각 thumb은 `<input type="range">`를 가지며 방향키·Page Up/Down·Home/End, RTL, `format`/`getAriaValueText` 값 안내, `name` form 제출을 지원합니다. 비제어 사용에서는 form reset이 `defaultValue`를 복원합니다. `aria-label`/`aria-labelledby`가 없거나 구간 slider에 thumb별 `getAriaLabel`이 없으면 개발 모드에서 경고합니다. `largeStep`(Page Up/Down, Shift + 방향키)도 `step` 배수에 놓이며 기본값은 범위의 1/10입니다. `dir`이 없으면 상속된 문서 방향을 따릅니다.
  - thumb은 두 테마 모두 흰 손잡이에 그림자와 바깥 1.5px 라인을 두고, 최소·최대에서도 컴포넌트 밖으로 나가지 않습니다. hover·누름은 thumb 주위 halo로 표시하며 드래그하는 동안 누름 표시가 유지됩니다. 단계가 30개 이하이면 드래그 중에도 thumb이 단계 사이를 부드럽게 이동하고, 더 촘촘하면 포인터를 그대로 따라갑니다. 터치는 150ms를 누르고 있거나 가로로 먼저 움직이면 thumb을 잡고, 그 전의 세로 스와이프는 값을 바꾸지 않고 페이지 스크롤로 넘깁니다. 잡은 뒤에는 손을 뗄 때까지 iOS를 포함해 페이지 스크롤을 막고, 잡기 전에 손을 떼면 탭한 위치로 값이 옮겨집니다. 누르거나 터치해서 생긴 포커스에는 focus ring을 그리지 않고, 키를 누르면 다시 그립니다. thumb의 hit area는 다른 컨트롤과 같은 최소 터치 대상(`--oc-touch-target-min`, 기본 44px)을 따릅니다.
  - `size`(`medium`·`small`, 기본 `medium`)는 thumb 지름과 포인터 영역 높이를 바꿉니다.
  - 공개 CSS 변수 `--oc-slider-{track-color,indicator-color,thumb-color,thumb-shadow,thumb-border-color}`와 selector `data-oc-component="slider"`, `data-oc-part="control|track|indicator|mark|thumb"`, `data-oc-size`, `data-oc-range`, `data-oc-disabled`, `data-oc-dragging`, `data-oc-discrete`, `data-oc-active`를 추가합니다. `Slider`는 client component입니다.

  ### Migration Notes
  - 없음

### Patch Changes

- 06db87a: `useDragScroll`: `contentRef`를 연결한 스크롤 요소가 `matchMedia`가 없는 환경(jsdom 등)에서 마운트되어도 오류를 내지 않습니다. 이때는 reduced-motion 설정을 알 수 없으므로 경계 늘어남을 쓰지 않습니다. 브라우저 동작은 바뀌지 않습니다.

  ### Migration Notes
  - 없음

- cf386f3: `useDragScroll`: oc-ui 컴포넌트가 같은 스크롤 요소의 스냅을 잠시 끈 동안(예: Carousel의 버튼 이동) 마우스 드래그를 시작해도 놓을 때 원래 스냅 위치로 정착합니다. 스냅은 드래그와 컴포넌트 이동이 모두 끝난 뒤 복원되므로 스냅 지점 사이에서 다시 켜져 튀지 않습니다.

  ### Migration Notes
  - 없음

- 7cded5c: Safari(iOS·macOS)에서 길게 누르거나 드래그할 때 텍스트가 선택되던 문제를 고칩니다.
  - `AnimatedNumber`, `FloatingWindow`(드래그 중), `IconButton`, `Menu` popup, `Modal` 상단 고정 영역, `PositionSnap`(드래그 중), `ScrollArea` scrollbar track, `SegmentedControl` 항목이 `user-select: none`과 함께 `-webkit-user-select: none`을 출력합니다.
  - 공개 API, CSS 변수, `data-oc-*` selector 변경은 없습니다.

  ### Migration Notes
  - 없음

### Migration Notes

- Modal·FloatingWindow header는 본문이 스크롤되면 하단 divider를 표시합니다. 이전처럼 divider 없이 쓰려면 `ModalHeader`에 `divider="none"`을 지정하세요. FloatingWindow header와 material footer도 `divider="none"`으로 끌 수 있습니다.
- Modal·FloatingWindow footer의 스크롤 fade는 아래에 남은 콘텐츠가 있을 때만 footer 위로 번지고, 맨 끝까지 스크롤하면 footer 안에 머뭅니다. 별도 조치는 필요 없으며, footer 바로 위 콘텐츠가 가려지는 정도가 달라지므로 해당 화면을 확인하세요.
- `Loading`의 `[data-oc-part='indicator'] circle`을 직접 스타일링했다면 `[data-oc-part='arc']`로 옮기세요. 트랙 원이 추가되어 `circle` 선택자가 두 원에 모두 적용되고, 회전은 `indicator`(`svg`)에서 일어납니다.
- `ProgressIndicator`의 `[data-oc-part='indicator']`에 `inline-size`·`inset`을 직접 지정한 스타일은 이제 track 전체를 덮는 채움 층의 크기·위치를 바꿔 진행 표시를 왜곡하므로 제거하세요. 길이는 `value`·`max`로 지정하고, 색·두께·radius는 기존 `--oc-progress-indicator-*` 변수를 사용하세요.
- `SegmentedControl` 세그먼트를 소비자 Tooltip으로 따로 감싸고 있었다면 label이 잘린 세그먼트에서 툴팁이 두 개 열리므로 감싼 Tooltip을 제거하세요.
- `SegmentedControl`에서 선택된 세그먼트를 누른 채 다른 세그먼트에서 떼면 이제 그 세그먼트가 선택됩니다. 막아야 하면 `onValueChange`에서 `eventDetails.cancel()`을 호출하세요.
- 터치에서 `SegmentedControl`의 선택된 세그먼트는 `touch-action: pan-y pinch-zoom`을 가집니다. 가로 스크롤 영역 안에 두었다면 선택된 세그먼트에서 시작한 가로 스와이프가 영역을 스크롤하지 않고 thumb를 옮기므로 해당 화면을 확인하세요.
- `Loading`·`ProgressIndicator`는 client component가 됩니다. Server Component에서 그대로 렌더링할 수 있습니다.
- 그 밖의 추가·수정(AnimatedNumber, Carousel, PageIndicator, Slider, InteractionScope, ScrollAreaEdge, `oc-motion` `hold` intent, `useDragScroll` `cancel()`, Safari 텍스트 선택 수정 등)은 대응이 필요 없습니다.

## 1.23.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.22.1..HEAD`_

#### Breaking Changes

- `32ad5b8` ActionArea·AlertContent 작성 순서 렌더링과 슬롯 type 판별 금지 (#424)

#### Tests

- `ebfd9aa` test(scroll-area): hold arrow keys until keyboard scroll settles (#401)

#### Other

- `43379a8` CellItem slot 래퍼의 div 전환과 블록 콘텐츠 지원 (#395)
- `7bf973b` GitHub Actions 의존성 갱신과 Dependabot composite action 검사 추가 (#394)
- `68e805c` IconButton assistive variant 추가 (#396)
- `9763577` Safari root ScrollArea 네이티브 스크롤바 숨김 정적 CSS 전환과 WebKit 재생성 (#400)
- `633084e` 컴포넌트별 CSS의 oc-components 레이어 적용과 cascade 순서 통일 (#403)
- `8ef721a` Storybook 컴포넌트 CSS의 oc-components 레이어 적용으로 배포 cascade 검증 일치 (#404)
- `fd0061b` strong ActionArea sub 버튼의 disabled 상태 TextButton 형태 유지 (#407)
- `5d71c0f` leading/trailing slot 간격 contract 변수 공개 (#408)
- `25dc87b` SectionHeader slot의 제목 첫 줄 중앙 정렬 (#410)
- `d115773` TextButton loading 상태 추가와 strong ActionArea sub 버튼 loading 형태 유지 (#409)
- `c77c733` Button 로딩 스피너 RTL 중앙 정렬과 소비자 aria-busy 전달 보정 (#411)
- `5acfadc` Skeleton 고정 접근성 prop 타입 제외와 Alert/ActionArea children 구성 안내 (#413)
- `d617089` 컴포넌트 CSS 변수의 public/internal 계약 선언 (#415)
- `3ab0984` MenuContent className으로 지정하는 Menu content padding 변수 공개 (#417)
- `9b75564` Bottom Modal 안 iframe 입력 포커스 시 키보드 뒤로 밀리는 시트 보정 (#418)
- `5797a8e` Popup Modal 신호 없는 본문 콘텐츠 변경의 도착 높이 선노출 수정 (#420)
- `01614a0` Alert·ActionArea 슬롯 래핑 시 등록 기반 인식과 초기 포커스·경고 보정 (#419)
- `447a333` Stability Policy 버전 라인과 프리릴리즈 채널 명시 (#422)
- `3d9d3f6` Fieldset 자동 래핑 제거와 감싼 FieldLegend의 group 이름 유지 (#425)
- `1f1086a` SegmentedControl 컴포넌트 추가 (#427)
<!-- generated:end -->

### Minor Changes

- 32ad5b8: ActionArea와 AlertContent가 children을 작성 순서대로 렌더링합니다. 슬롯을 element type으로 찾아 재배치하던 동작을 없애, 소비자 컴포넌트로 감싼 슬롯도 직접 자식과 같은 결과를 냅니다. 작성 순서가 곧 화면 순서와 포커스 순서입니다.
  - `ActionArea`: `ActionAreaButton`을 priority 순서로 자동 정렬하지 않습니다. 작성 순서가 variant의 priority 순서와 다르면 개발 모드에서 필요한 순서를 담아 경고합니다.
  - `AlertContent`: `heading`·`description` prop을 맨 앞에, children을 작성 순서대로 렌더링합니다. `AlertHeading`·`AlertDescription`을 묶던 `data-oc-part="message"` 래퍼를 없앴고, heading 바로 뒤 description의 간격은 그대로입니다. `AlertActionArea`를 끝으로 옮기지 않으며, 뒤에 다른 내용이 있으면 개발 모드에서 경고합니다.
  - `heading` prop과 `AlertHeading`(또는 `description` prop과 `AlertDescription`)을 함께 쓰면 둘 다 렌더링합니다. 기존 경고는 유지하고, 먼저 렌더링되는 prop 쪽이 alertdialog의 이름·설명이 됩니다.
  - `AlertHeading`·`AlertDescription`은 각자 고유 id를 사용합니다.

  ### Migration Notes
  - `ActionAreaButton`을 variant의 priority 순서대로 작성합니다.
    - `strong`·`cancel`: main → equal → alternative → sub
    - `neutral`·`compact`: sub → alternative → equal → main
  - `AlertContent` children은 제목·설명 → 본문 → `AlertActionArea` 순서로 작성합니다.
  - `heading`·`description` prop과 같은 역할의 슬롯 컴포넌트 중 하나만 사용합니다.
  - `[data-oc-part="message"]`에 의존한 스타일은 `[data-oc-component="alert-heading"]`·`[data-oc-component="alert-description"]` 기준으로 옮깁니다.

- 633084e: 컴포넌트별 CSS를 `@layer oc-components` 안에 넣어, CSS chunk 로드 순서와 상관없이 consumer override가 같은 결과를 내도록 맞춥니다.
  - 컴포넌트를 import할 때 자동으로 로드되는 `dist/components/*/*.css`를 `@layer oc-components`로 감쌉니다. 지금까지는 layer 밖에 있어서, consumer가 같은 specificity로 slot을 덮으면 production 빌드의 chunk 순서에 따라 결과가 바뀌었습니다.
  - `foundations.css`, `reset.css`, `styles.css`, 컴포넌트별 CSS가 모두 `@layer oc-tokens, oc-reset, oc-components;`를 먼저 선언합니다. 컴포넌트 CSS가 foundations보다 먼저 로드되어도 layer 순서가 유지됩니다.
  - SCSS 통합 entry(`scss/index.scss`)도 reset을 `oc-reset` layer로 출력합니다.
  - `styles.css`를 쓰는 환경도 영향을 받습니다. 컴포넌트 JS가 layer 밖 컴포넌트 CSS를 함께 불러왔기 때문에 실제 cascade는 컴포넌트별 CSS와 같았습니다.

  ### Migration Notes
  - layer 밖의 consumer 전역 요소 선택자(`body h2`, `p`, `button` 등)가 이제 컴포넌트 내부 요소를 덮습니다. 예를 들어 `body h2 { ... }`는 `ModalContent` 제목과 `SectionHeader` heading에 적용됩니다. 전역 요소 스타일은 `@layer base, oc-tokens, oc-reset, oc-components;`처럼 oc-ui보다 낮은 layer로 옮기세요.
  - Tailwind CSS v4처럼 다른 layer를 쓰는 환경은 entry CSS 맨 앞에서 `@layer theme, base, oc-tokens, oc-reset, oc-components, components, utilities;`처럼 전체 순서를 선언하세요.
  - specificity를 올려 컴포넌트 규칙을 이기던 임시 override(예: `.item[data-oc-component='cell-item']`)는 단일 class로 되돌려도 됩니다.

- d617089: 컴포넌트 contract 변수(`--oc-{component}-*`)의 공개 범위를 문서로 선언합니다.
  - `docs/css-variables.md`를 추가합니다. 컴포넌트별로 변수를 override, 읽기 전용, internal로 구분하고 분류 기준, 값을 지정하는 위치, disabled 표현 방식을 함께 정리합니다.
  - override·읽기 전용으로 표시된 변수는 Stability Policy의 공개 계약이 됩니다. 제거·이름 변경·의미 변경은 major에서만 진행합니다.
  - `--oc-` prefix를 쓰지만 internal로 표시된 변수와 `--_-*` 변수는 계약이 아니며 예고 없이 바뀔 수 있습니다.
  - 변수 이름, 기본값, 렌더링 결과는 바뀌지 않습니다.

  ### Migration Notes
  - 없음. 다만 internal로 표시된 `--oc-*` 변수를 override하고 있다면 같은 목적의 override 변수나 prop으로 옮기는 것을 권장합니다.

- 3d9d3f6: `Fieldset`이 children을 자동으로 `FieldsetContent`로 감싸지 않고 작성한 그대로 렌더링합니다.
  - `FieldLegend`를 소비자 컴포넌트로 감싸면 legend를 찾지 못해 legend까지 content slot(`div`) 안에 넣던 문제를 고칩니다. legend가 fieldset의 직계 자식으로 남아 group의 접근 가능한 이름이 유지됩니다.
  - `FieldsetContent`를 소비자 컴포넌트로 감싸도 content slot이 중복으로 생기지 않습니다.
  - Selector Contract에 `Fieldset` 계약(`fieldset`, `field-legend`, `fieldset-content`, `required-mark`)과 legend·content 배치 규칙을 추가합니다.
  - legend float 기반 WebKit 첫 레이아웃 높이 보정과 `FieldsetContent` 간격 값은 바뀌지 않습니다.

  ### Migration Notes
  - `Fieldset` 안에 legend 다음 control을 `FieldsetContent` 없이 직접 두었다면 `FieldsetContent`로 감싸세요. 감싸지 않으면 legend·control 간 세로 간격과 control 세로 정렬(flex column)이 적용되지 않습니다.
  - legend 없이 `aria-label`만 쓰는 `Fieldset`도 같은 레이아웃이 필요하면 children을 `FieldsetContent`로 감싸세요.
  - `FieldGroup`과 이미 `FieldsetContent`를 명시한 코드는 변경할 필요가 없습니다.

- 68e805c: `IconButton`에 보조 액션용 `variant="assistive"`를 추가합니다.
  - 아이콘과 hover·focus·active interaction 색이 `--oc-color-theme-label-alternative`를 사용합니다. TextButton `assistive`와 같은 색 계약입니다.
  - root에 `data-oc-variant="assistive"`가 출력됩니다.
  - disabled 색(`--oc-color-theme-label-disable`), 키보드 포커스, 터치 타깃은 기존 `normal`·`primary`와 같습니다. 기본값은 계속 `normal`입니다.

  ### Migration Notes
  - 없음. 도움말 버튼처럼 소비자 CSS로 `label-alternative` 아이콘 색을 지정하던 곳은 `variant="assistive"`로 바꿀 수 있습니다.

- 1f1086a: 하나의 값을 고르는 `SegmentedControlRoot`, `SegmentedControlItem` 컴포넌트를 추가합니다.
  - iOS형 solid 표현: 회색 track 위에서 선택된 세그먼트로 thumb가 이동하며, reduced-motion에서는 즉시 이동합니다.
  - radio group 시맨틱(`role="radiogroup"`/`radio`): 방향키로 이동하면 바로 선택되고, 양끝에서 순환하며, RTL에서 반전되고, disabled 세그먼트는 건너뜁니다. `name`으로 form에 값을 제출하며, 비제어 사용에서는 form reset이 `defaultValue`를 복원합니다.
  - 세그먼트 콘텐츠는 Button과 같은 `leadingIcon`·라벨·`trailingIcon` 또는 `icon` 단독 구성을 지원합니다. 아이콘만 있는 세그먼트와 root에는 `aria-label`/`aria-labelledby`가 필요하며, 없으면 개발 모드에서 경고합니다.
  - `size`(`large`·`medium`·`small`, 기본 `medium`)에 따라 컨트롤 전체 높이가 같은 size의 Button과 같습니다. `fullWidth`는 컨테이너 폭을 채우고, 세그먼트는 등폭이며 공간이 부족하면 라벨을 말줄임합니다.
  - 공개 CSS 변수 `--oc-segmented-control-{track-color,thumb-color,thumb-shadow,padding,radius,label-color,label-selected-color,label-disabled-color}`와 selector `data-oc-component="segmented-control"`, `data-oc-part="item|thumb|content|label|leading-icon|trailing-icon|icon"`, `data-oc-thumb-ready`를 추가합니다.
  - 선택에 따라 다른 panel을 보여 주는 경우는 Tabs를 사용합니다.

  ### Migration Notes
  - 없음

- 5acfadc: Skeleton이 항상 고정하는 접근성 속성을 타입에서도 제외합니다.
  - `SkeletonProps`에서 `role`, `tabIndex`, `aria-hidden`을 제거합니다. 이 prop들은 이전에도 전달해도 무시됐습니다.
  - spread로 전달된 `role`/`tabIndex`도 계속 렌더링하지 않고, `aria-hidden="true"`를 유지합니다. 런타임 동작은 바뀌지 않습니다.
  - 로딩 상태는 Skeleton을 감싸는 영역의 `aria-busy="true"`와 상태 문구로 알리도록 Storybook과 selector 계약 문서에 안내를 추가합니다.

  ### Migration Notes
  - `<Skeleton>`에 `role` 또는 `tabIndex`를 직접 넘기던 코드는 타입 오류가 나므로 해당 prop을 삭제합니다. 원래 렌더링되지 않던 값이라 화면과 접근성 트리는 바뀌지 않습니다.
  - 로딩 상태를 보조기기에 알려야 하면 Skeleton 대신 감싸는 영역에 `aria-busy="true"`와 상태 문구(예: 시각적으로 숨긴 `role="status"` 텍스트)를 둡니다.

- 5d71c0f: leading/trailing slot과 콘텐츠 사이 간격을 contract 변수로 공개합니다. 기본 간격 값은 바뀌지 않습니다.
  - `TextButton`의 `--oc-text-button-gap`(기본 `0.125em`) 추가. Alert action에도 적용
  - `TextInput`, `Select`, `TextArea`, `InputGroup`의 `--oc-field-control-gap`(기본 `--oc-space-item-gap-small`) 추가. content row slot 간격, native 입력 slot offset, floating 라벨 offset이 같은 값을 따름
  - 기존 `--oc-button-gap`, `--oc-cell-gap`을 컴포넌트가 직접 선언하지 않고 internal default로 기본값 제공. host와 조상 지정값 모두 CSS 로딩 순서와 무관하게 적용
  - `Menu`의 `href`/`render` item도 `--oc-cell-gap`을 따르도록 수정. 이전에는 `0.5em` 고정
  - 변수별 지정 위치는 Selector Contract 문서의 "Slot 간격 계약" 참고

  ### Migration Notes
  - 필요한 consumer 대응은 없습니다.
  - 조상 요소에 `--oc-button-gap` 또는 `--oc-cell-gap`을 지정해 두었다면 이전에는 무시되던 값이 이제 하위 컴포넌트에 적용됩니다.

- d115773: button·anchor 형태 `TextButton`에 진행 중 상태용 `loading` prop을 추가합니다.
  - Button의 loading 계약을 따릅니다. variant 글자색을 유지하고, 아이콘 크기 상자의 스피너를 label 위에 겹쳐 폭과 접근성 이름을 보존합니다.
  - 포커스를 유지한 채 `aria-disabled="true"`, `aria-busy="true"`를 출력하고 click, Enter, Space와 폼 제출을 막습니다. `disabled`와 함께 쓰면 disabled가 우선합니다.
  - root에 `data-oc-loading="true"`와 `data-oc-disabled="true"`가 출력됩니다. 비활성 스타일 기준이 `[aria-disabled='true']`에서 `:disabled`, `[data-oc-disabled='true']`, 로딩이 아닌 `[aria-disabled='true']`로 바뀝니다.

  ### Migration Notes
  - 없음. TextButton 로딩 상태를 직접 스타일링하려면 `[data-oc-loading='true']`를 기준으로 사용합니다.

### Patch Changes

- fd0061b: `variant="strong"` ActionArea의 `priority="sub"` ActionAreaButton이 `disabled`일 때도 TextButton(assistive, small) 형태를 유지합니다.
  - 이전에는 `disabled`가 되면 outlined Button(assistive, large, fullWidth)으로 바뀌어 상태 전환마다 ActionArea 높이와 시각 위계가 달라졌습니다.
  - `disabled`는 TextButton에 전달됩니다. button 형태는 native `disabled`, `href` 형태는 `aria-disabled="true"`, `tabIndex=-1`과 activation 차단을 사용합니다.
  - `loading` sub 액션은 기존처럼 Button으로 렌더링됩니다. neutral·compact·cancel variant의 동작은 바뀌지 않습니다.

  ### Migration Notes
  - 없음. strong ActionArea의 sub 버튼을 TextButton 형태로 유지하려고 `disabled` 대신 `aria-disabled`와 click guard를 쓰던 곳은 `disabled`로 되돌릴 수 있습니다.

- d115773: `variant="strong"` ActionArea의 `priority="sub"` ActionAreaButton이 `loading`일 때도 TextButton(assistive, small) 형태를 유지합니다.
  - 이전에는 `loading`이 되면 outlined Button(assistive, large, fullWidth)으로 바뀌어 상태 전환마다 ActionArea 높이와 시각 위계가 달라졌습니다.
  - `loading`은 TextButton의 진행 중 상태로 전달됩니다. neutral·compact·cancel variant의 동작은 바뀌지 않습니다.

  ### Migration Notes
  - strong ActionArea의 `loading` sub 버튼을 `[data-oc-component='button']`이나 `[data-oc-loading='true']` Button 스타일로 다루던 곳은 `[data-oc-component='text-button']`을 기준으로 바꿉니다.

- 01614a0: Alert와 ActionArea의 슬롯 컴포넌트를 소비자 컴포넌트로 감싸도 인식되도록 슬롯 판별을 owner 등록 방식으로 바꿉니다.
  - `AlertAction`·`AlertActionArea`를 감싸도 `initialFocus="first" | "least-destructive"`와 `autoFocus` 초기 포커스가 적용되고, "at least one AlertAction" 경고가 잘못 뜨지 않습니다.
  - `AlertActionArea initialFocus="least-destructive"`에서 `negative` action이 앞에 있으면 첫 action(negative)에 포커스가 가던 문제를 고칩니다. 이제 `assistive` 또는 negative가 아닌 action에 포커스합니다.
  - `AlertHeading`·`AlertDescription`을 감싸도 alertdialog의 `aria-labelledby`·`aria-describedby`가 연결됩니다.
  - `ActionAreaButton`을 감싸도 main 개수·`variant="cancel"` 경고가 적용됩니다.
  - 개발 모드 경고는 렌더 시점이 아니라 마운트·슬롯 등록 시 판정하고, 같은 경고는 인스턴스마다 한 번만 표시합니다. Alert 경고는 Alert가 열린 뒤에만 표시하고, 서버 렌더링 중에는 두 컴포넌트 모두 경고하지 않습니다.
  - 공개 props, 타입, `data-oc-*` selector는 바뀌지 않습니다.

  ### Migration Notes
  - 없음

- c77c733: Button의 `loading` 처리 두 가지를 바로잡습니다.
  - `loading`이 아닐 때 소비자가 넘긴 `aria-busy`를 그대로 DOM에 전달합니다. 이전에는 `loading`이 false이면 `aria-busy`가 항상 제거됐습니다. `loading` 중에는 계속 `aria-busy="true"`로 고정합니다.
  - RTL(`dir="rtl"`)에서 로딩 스피너가 버튼 중앙에 오도록 보정합니다. 이전에는 스피너가 자기 너비만큼 왼쪽으로 치우쳤습니다.

  ### Migration Notes
  - 없음

- 43379a8: `CellItem` slot에 블록 요소를 넣으면 HTML 콘텐츠 모델을 위반하던 문제를 수정합니다.
  - `leading`·`content`·`text`·`label`·`description`·`trailing` slot 래퍼를 `span` 대신 `div`로 렌더링합니다.
  - `h2`·`p`·`ul`·`div` 같은 블록 요소를 slot에 그대로 넣어도 유효한 HTML이 됩니다.
  - `data-oc-part` 이름·계층과 레이아웃은 변경하지 않습니다.
  - `AccordionSummary`는 slot이 native button 안에 있어 기존 `span`을 유지합니다.

  ### Migration Notes
  - `span[data-oc-part='content']`처럼 요소 이름까지 지정한 selector는 공개 계약이 아니므로 `[data-oc-component='cell-item'] [data-oc-part='content']` 형태로 사용하세요.

- 3ab0984: `MenuContent`의 `className`에 지정한 `--oc-menu-content-padding`이 Menu popup padding과 separator 폭·간격에 적용됩니다.
  - 이전에는 popup 요소가 기본값 `1em`을 직접 선언해 `className`이 붙는 positioner에서 지정한 값이 가려졌습니다.
  - `--oc-menu-content-padding`을 internal에서 override 변수로 승격합니다. 기본값은 `1em` 그대로입니다.

  ### Migration Notes
  - 없음. popup 요소를 `[data-oc-component='menu-content']` selector로 직접 지정해 padding을 바꾸던 곳은 `MenuContent className`의 `--oc-menu-content-padding`으로 옮길 수 있습니다.

- 9b75564: Bottom Modal 안 iframe의 입력 필드에서 소프트 키보드가 열릴 때 시트가 키보드 뒤로 밀려나던 문제를 바로잡습니다.
  - iframe 내부 포커스는 상위 문서의 `focusin`으로 전달되지 않아 키보드 회피 세션이 시작되지 않았고, 시트가 줄어든 visual viewport 높이로 작아진 채 layout viewport 하단에 붙어 키보드 뒤에 가려졌습니다.
  - 터치 환경에서 Modal 안 iframe이 포커스를 받으면 시트 높이를 유지하는 세션을 시작합니다. 키보드 inset은 viewport가 실제로 줄어들 때만 적용하므로 키보드를 띄우지 않는 iframe 탭은 화면을 바꾸지 않습니다.
  - 포커스가 상위 문서로 돌아오거나 포커스를 가진 iframe이 제거되면 세션을 닫습니다. 시트 드래그·헤더 탭·배경 드래그의 키보드 닫기도 iframe 포커스를 해제합니다.

  ### Migration Notes
  - 없음

- 5797a8e: Popup(`resize='content'`, `contentTransition='auto'`)의 ModalBody 콘텐츠가 depth·탭 전환 없이 바뀔 때 도착 높이가 한 프레임 먼저 그려진 뒤 이전 높이부터 전환되던 문제를 수정합니다.
  - 이전에는 신호 없는 콘텐츠 변경을 ResizeObserver로 감지한 뒤 다음 animation frame에서 이전 높이를 고정해, 변경 직후 프레임에 최종 높이가 노출되었습니다.
  - 이제 ModalBody 안의 노드 추가·제거, 텍스트 변경, `style` 외 속성 변경은 페인트 전 MutationObserver 전달 시점에 이전 높이를 고정하고 바로 전환합니다.
  - inline `style`로 높이를 매 프레임 바꾸는 자체 애니메이션(예: NavigationSection expand)은 기존처럼 관찰 기반으로 분류해 surface가 자연 추종합니다.
  - 이미지 로드, inline `style`만 바뀌는 변경, header/footer 콘텐츠 변경은 기존 관찰 경로를 유지합니다.

  ### Migration Notes
  - 없음

- 9763577: Safari에서 `root` `ScrollArea`가 문서 루트의 네이티브 scrollbar를 숨기지 못하던 문제를 수정합니다.
  - 문서 루트 scrollbar 숨김 규칙을 런타임 `<style>` 주입에서 `foundations.css`의 reset 규칙으로 옮겨, 서버 렌더 페이지에서 첫 페인트부터 적용합니다.
  - 클라이언트 라우팅으로 나중에 마운트되거나 `scrollbarVisibility`·터치 모드가 바뀔 때, 마지막 `root` ScrollArea가 사라질 때 WebKit의 문서 scrollbar를 한 번 다시 만들어 숨김과 복원을 반영합니다. 스크롤 위치와 문서 루트의 인라인 `overflow` 값은 유지합니다.
  - `* { scrollbar-width: thin; }` 같은 소비자 전역 scrollbar 스타일이 있어도 문서 루트와 일반 스크롤 컨테이너의 네이티브 scrollbar 숨김을 유지합니다. 숨김 선언은 cascade layer 안에서도 우선하도록 `!important`로 선언합니다.
  - 컴포넌트 scrollbar 스타일은 정적 CSS만 사용하며 `oc-scroll-area-container-style`, `oc-scroll-area-root-style` `<style>` 요소를 더 이상 만들지 않습니다.

  ### Migration Notes
  - `foundations.css`를 첫 페인트 전에 적용되는 앱 root stylesheet로 불러오세요. 늦게 불러오면 Safari에서 다음 `ScrollArea` 상태 변화 전까지 네이티브 scrollbar가 남을 수 있습니다.
  - `#oc-scroll-area-container-style`, `#oc-scroll-area-root-style` 요소에 의존하던 코드는 제거하세요. 공개 계약이 아니었습니다.

- 25dc87b: `SectionHeader`의 `headingSlot`·`trailingSlot`이 제목 첫 줄 중앙에 정렬되지 않던 문제를 수정합니다.
  - 두 slot의 높이를 제목 첫 줄 높이로 고정해 아이콘·IconButton·텍스트가 첫 줄 중앙에 정렬됩니다. 제목이 여러 줄이어도 첫 줄 기준을 유지합니다.
  - `viewport="auto"`에서 화면 폭에 따라 제목 줄 높이가 바뀌어도 정렬이 유지됩니다.
  - slot의 `overflow: hidden`을 제거해 줄 높이보다 큰 콘텐츠와 IconButton interaction 영역이 잘리지 않습니다. 줄 높이보다 큰 콘텐츠는 첫 줄 중앙을 기준으로 위아래로 넘치며 레이아웃 공간은 차지하지 않습니다.
  - `--oc-typo-size-factor`가 1이 아닐 때도 slot 높이가 제목 줄 높이와 같도록 배율을 반영합니다.

  ### Migration Notes
  - slot에 `block-size`·`max-block-size: none`·`overflow: visible`을 덮어쓰던 소비자 CSS 우회는 제거할 수 있습니다.
  - 줄 높이보다 큰 trailing(예: 40px 버튼)을 두는 경우 위아래로 넘치는 만큼 헤더 주변 간격을 확인하세요.

- 447a333: Stability Policy에 버전 라인, 안정성 등급, 프리릴리즈 채널을 명시합니다.
  - 1.x는 공개 API를 다듬는 단계라 minor에서도 공개 API가 바뀔 수 있으며, 모든 변경을 Migration Notes에 기록합니다.
  - 2.0부터는 기존 Breaking change 기준과 Deprecation 절차를 따르고, deprecated 표면은 모아 다음 major에서 한꺼번에 제거합니다. 형태를 확정하기 전인 API는 experimental로 표시합니다.
  - 프리릴리즈 dist-tag는 `next`(현재 라인 후보)와 `beta`·`rc`(다음 major 후보, 2.0 이후)로 나눕니다.

  ### Migration Notes
  - 없음

### Migration Notes

- 컴포넌트별 CSS가 `@layer oc-components` 안으로 들어갑니다. layer 밖의 전역 요소 선택자(`body h2`, `p`, `button` 등)가 컴포넌트 내부 요소를 덮게 되므로, 전역 요소 스타일은 `@layer base, oc-tokens, oc-reset, oc-components;`처럼 oc-ui보다 낮은 layer로 옮기세요. Tailwind CSS v4처럼 다른 layer를 쓰는 환경은 entry CSS 맨 앞에서 `@layer theme, base, oc-tokens, oc-reset, oc-components, components, utilities;`처럼 전체 순서를 선언하세요.
- `ActionArea`는 `ActionAreaButton`을 자동 정렬하지 않습니다. variant의 priority 순서대로 작성하세요(`strong`·`cancel`: main → equal → alternative → sub, `neutral`·`compact`: sub → alternative → equal → main).
- `AlertContent` children은 제목·설명 → 본문 → `AlertActionArea` 순서로 작성하고, `heading`·`description` prop과 같은 역할의 슬롯 컴포넌트 중 하나만 사용하세요. `[data-oc-part="message"]` 래퍼가 없어졌으므로 관련 스타일은 `[data-oc-component="alert-heading"]`·`[data-oc-component="alert-description"]` 기준으로 옮기세요.
- `Fieldset`이 children을 자동으로 `FieldsetContent`로 감싸지 않습니다. legend 다음 control을 직접 두었거나 `aria-label`만 쓰는 `Fieldset`은 children을 `FieldsetContent`로 감싸야 기존 간격과 세로 정렬이 유지됩니다.
- `<Skeleton>`에 `role` 또는 `tabIndex`를 넘기던 코드는 타입 오류가 나므로 삭제하세요. 렌더링 결과는 바뀌지 않습니다.
- strong ActionArea의 `loading` sub 버튼은 TextButton으로 렌더링됩니다. 해당 버튼을 `[data-oc-component='button']` 기준으로 스타일링했다면 `[data-oc-component='text-button']`으로 바꾸세요.
- `foundations.css`를 첫 페인트 전에 적용되는 앱 root stylesheet로 불러오세요. `#oc-scroll-area-container-style`, `#oc-scroll-area-root-style` 요소는 더 이상 생성되지 않습니다.
- 조상 요소에 지정한 `--oc-button-gap`·`--oc-cell-gap`이 이제 하위 컴포넌트에 적용됩니다.
- 그 밖의 추가·수정(SegmentedControl, IconButton `assistive`, TextButton `loading`, CSS 변수 공개 범위 문서 등)은 대응이 필요 없습니다.

## 1.22.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.22.0..HEAD`_

#### Other

- `72a73ee` Next.js Webpack 빌드의 spring 모션 linear() 시작점 무효화 수정 (#385)
- `ea382ad` Badge padding 레이어 넘침과 방문 링크 색상 수정 (#387)
- `8b0d92d` useDragScroll의 네이티브 누름 포커스 복원과 자동 스크롤 원인 차단 (#386)
<!-- generated:end -->

### Patch Changes

- ea382ad: `padding` Badge의 border와 interaction 레이어가 badge 바깥으로 삐져나오던 문제를 수정합니다.
  - `--oc-badge-border-*` border와 hover·focus·active interaction 레이어가 `padding` Badge 영역 안에 맞게 그려집니다.
  - `padding` 없는 Badge의 바깥 확장 동작은 그대로입니다.

  ### Migration Notes
  - 없음

- 8b0d92d: `useDragScroll`이 `deferFocus: false`에서 마우스 누름의 기본 동작을 다시 유지해 포커스와 focus ring을 네이티브 클릭과 같게 합니다. Chromium에서 마우스로 누른 뒤 키보드 입력에 focus ring이 표시되지 않던 문제를 고칩니다. 누른 채 영역 밖으로 나갔을 때의 네이티브 자동 스크롤은 누름 기본 동작 대신 누르는 동안의 `selectstart`, `dragstart`, 버튼이 눌린 `pointermove`를 취소해 계속 막습니다.

  ### Migration Notes
  - `deferFocus: false`에서 드래그가 될 수 있는 누름의 `mousedown.defaultPrevented`가 다시 `false`입니다. 1.22.0 이후 이 값으로 드래그 후보를 판별한 상위 핸들러가 있으면 확인하세요. `deferFocus: true`는 기존처럼 취소합니다.
  - Safari에서 버튼·링크를 눌렀을 때 포커스를 주지 않는 네이티브 동작으로 돌아갑니다.
  - 누름 시점 ring을 숨기려고 `pointerdown`에서 `focus({ focusVisible: false })`를 호출하는 우회가 남아 있으면 Chromium에서 이후 키보드 ring이 다시 사라지므로 제거하세요.
  - 네이티브 자동 스크롤을 피하려고 `deferFocus: true`를 지정했다면, 포커스 시 활성화하는 컨트롤이 아닌 경우 제거하세요. `deferFocus: true`의 클릭 포커스는 Chromium에서 포커스를 옮기지 않는 키에 ring을 표시하지 않습니다.

- 72a73ee: Next.js `next build --webpack` 같은 cssnano 기반 프로덕션 빌드에서 spring motion의 `linear()` easing이 무효화되어 Modal, FloatingWindow, Menu, Tooltip, Accordion, Tabs, Switch 등 spring easing을 쓰는 컴포넌트의 전환이 적용되지 않던 문제를 수정합니다.
  - `oc-spring(...)`, `oc-spring-timing(...)`, `oc-motion(...)`의 spring 출력과 TypeScript `ocSpring.*().timingFunction`이 첫 stop의 입력 위치를 생략한 `linear(0, …)` 형태로 출력됩니다.
  - CSS Easing Level 2에서 첫 stop의 위치 생략은 `0%`와 같아 곡선은 이전과 동일합니다.

  ### Migration Notes
  - 없음

- ea382ad: 방문한 링크에서 컴포넌트 텍스트 색이 부모 색으로 바뀌던 문제를 수정합니다.
  - reset의 방문 링크 규칙을 `:where(a:visited)`로 바꿔 명시도를 0으로 낮춥니다. cascade layer 없이 SCSS 소스를 직접 쓰는 경우에도 `href`를 받은 Badge, Button, TextButton, IconButton 등이 방문 후에도 컴포넌트 색을 유지합니다.

  ### Migration Notes
  - 없음

### Migration Notes

- `useDragScroll`의 `deferFocus: false` 누름은 다시 `mousedown.defaultPrevented`가 `false`입니다. 1.22.0 이후 이 값으로 드래그 후보를 판별한 상위 핸들러가 있으면 확인하세요.
- Safari에서 버튼·링크 누름 시 포커스를 주지 않는 네이티브 동작으로 돌아갑니다.
- 누름 시점 ring을 숨기려고 `pointerdown`에서 `focus({ focusVisible: false })`를 호출하는 우회는 Chromium 키보드 ring을 다시 없애므로 제거하세요.
- 네이티브 자동 스크롤을 피하려고 `deferFocus: true`를 지정했다면, 포커스 시 활성화하는 컨트롤이 아닌 경우 제거하세요.
- Badge, 방문 링크 색상, spring `linear()` 수정은 대응이 필요 없습니다.

## 1.22.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.21.0..HEAD`_

#### Tests

- `840b103` test(scroll): click visible focus targets

#### Other

- `62a2f01` Button loading 상태의 disabled 표시 분리 (#376)
- `7e7e449` useDragScroll 포인터 포커스의 focus ring 표시 수정 (#378)
- `0325b50` wheel picker 레시피의 트랙패드 손가락 정지 오판 수정 (#377)
- `128df9b` ScrollArea의 네이티브 스크롤 접근성 계약 정리 (#379)
- `811bdc4` useDragScroll 느린 드래그의 포인터 추종 오차 수정 (#380)
<!-- generated:end -->

### Minor Changes

- 62a2f01: `Button`과 `ActionAreaButton`의 `loading`이 더 이상 disabled 스타일로 표시되지 않습니다. 로딩 중에도 variant의 배경과 글자색을 유지하고, 스피너는 글자색을 따르며, 커서는 `progress`로 표시합니다. 네이티브 `disabled` 대신 `aria-disabled="true"`와 `aria-busy="true"`를 사용해 포커스와 접근성 이름을 유지하면서 click, Enter, Space와 폼 제출(입력칸 Enter 포함)을 막습니다. `disabled`와 함께 쓰면 disabled 표시와 동작이 우선합니다.

  `disabled` prop 상태를 나타내는 `data-oc-disabled="true"` selector를 추가합니다.

  ### Migration Notes
  - 로딩 중인 `<button>`에는 `disabled` 속성이 붙지 않습니다. 로딩 상태를 jest-dom `toBeDisabled()`나 CSS `:disabled`로 확인하던 코드는 `aria-disabled="true"`, `aria-busy="true"` 또는 `[data-oc-loading='true']`로 바꿉니다. Playwright의 `toBeDisabled()`는 `aria-disabled`를 인식하므로 그대로 동작합니다.
  - 로딩 중에도 버튼 텍스트가 접근성 이름으로 유지됩니다. 로딩 중 이름이 비어 있다고 가정한 테스트는 버튼 텍스트로 찾도록 바꿉니다.
  - 로딩 중인 링크 형태 `Button`은 Tab 순서에 남습니다. `disabled`를 함께 주면 이전처럼 `tabIndex="-1"`입니다.
  - 로딩 중 버튼의 click은 부모 요소로 전파됩니다. 네이티브 disabled일 때는 부모 `onClick`이 호출되지 않았습니다.
  - 문서화되지 않은 내부 변수 `--oc-button-loading-color`를 제거했습니다. 스피너 색은 `--oc-button-color`를 따릅니다.

### Patch Changes

- 811bdc4: `useDragScroll`의 마우스 드래그가 천천히 끌 때 포인터보다 덜 따라가거나 더 따라가던 문제를 수정합니다. 브라우저가 스크롤 위치를 반올림하기 때문에, 읽어 온 위치에 포인터 이동량을 더하는 방식은 소수 픽셀 이동을 버리거나 두 배로 적용했습니다. 이제 드래그 중 요청한 위치를 반올림 없이 유지해 포인터의 전체 이동량을 그대로 따릅니다.

  ### Migration Notes
  - 없음. 공개 API와 드래그 정책은 그대로입니다.

- 7e7e449: `useDragScroll`이 마우스 누름·클릭으로 옮기는 포커스가 focus ring을 표시하던 문제를 수정합니다.
  - 누르는 순간(`deferFocus: false`)과 클릭 완료 시(`deferFocus: true`) 훅이 옮기는 포커스가 네이티브 마우스 클릭처럼 `:focus-visible`에 해당하지 않습니다. `tabIndex`를 준 스크롤 영역이나 `TabsList`를 마우스로 누르거나 드래그해도 ring이 표시되지 않습니다.
  - Tab 키 진입과 방향키 탐색의 focus ring은 기존처럼 표시됩니다.

  ### Migration Notes
  - 필수 대응은 없습니다. ring을 숨기려고 `pointerdown`에서 `focus({ focusVisible: false })`를 먼저 호출하던 우회는 제거해도 됩니다.

- 128df9b: `ScrollArea`의 커스텀 scrollbar를 보조기술에서 장식 요소로 숨깁니다. 네이티브 스크롤, 키보드 동작, Tab 순서와 커스텀 scrollbar의 시각·포인터 조작은 유지합니다.

  WebKit에서 포커스된 가로 스크롤 영역의 방향키 스크롤을 막던 `scrollbar-width: none` 경로를 조정하고, 네이티브·ScrollArea 가로 비교 예시를 추가합니다.

  ### Migration Notes
  - 커스텀 scrollbar의 track/thumb은 접근성 트리에 나타나지 않습니다. 해당 요소를 보조기술용 탐색 대상으로 가정한 사용처는 실제 스크롤 콘텐츠를 기준으로 확인하세요.

- 0325b50: `useDragScroll` 문서의 wheel picker 레시피를 바로잡습니다. 트랙패드에 손가락을 올린 채 행 사이에 멈추면, 마지막 `wheel` 이벤트 후 150ms라는 시간 조건만으로는 손가락을 뗀 것과 구별되지 않아 값 확정과 정렬 스크롤이 손가락 아래에서 실행되었습니다. 이제 레시피는 위치가 행의 스냅 위치에 정렬되어 있을 때만 정착으로 보고, 복제 벌 되돌리기도 정렬된 위치에서만 합니다.

  ### Migration Notes
  - 라이브러리 동작 변경은 없습니다. 이전 레시피로 값 확정을 구현했다면 정착 조건에 "현재 위치가 행 정렬 위치에서 1px 이내"를 추가하고(`getBoundingClientRect`로 소수점까지 측정), 복제 벌 되돌리기도 같은 조건(또는 훅의 release 중 인라인 `scroll-snap-type: none`)에서만 실행하세요.

### Migration Notes

- `Button` 로딩 상태를 네이티브 `disabled`나 CSS `:disabled`로 확인하던 코드는 `aria-disabled="true"`, `aria-busy="true"` 또는 `data-oc-loading="true"`를 기준으로 바꾸세요. 로딩 중 버튼과 링크는 Tab 순서 및 접근성 이름을 유지하며, 차단된 click은 부모로 전파됩니다.
- `ScrollArea`의 커스텀 scrollbar track/thumb은 접근성 트리에서 제외됩니다. 보조기술 탐색은 실제 스크롤 콘텐츠를 기준으로 확인하세요.
- 문서의 wheel picker 레시피를 적용했다면 값 확정과 복제 벌 되돌리기 전에 스냅 위치 정렬 여부를 확인하세요.
- `useDragScroll`의 느린 드래그 위치와 마우스 포커스 ring 수정은 공개 API 변경이 없습니다. 포커스 ring을 숨기기 위한 별도 `focus({ focusVisible: false })` 우회는 제거할 수 있습니다.

## 1.21.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.20.0..HEAD`_

#### Other

- `84d266d` drag-scroll 관성 테스트의 측정 속도 기준 판정 전환 (#362)
- `8034c0e` drag-scroll 속도·관성 테스트의 가상 시계 전환 (#363)
- `a7b0c46` useDragScroll의 네이티브 자동 스크롤 차단과 Safari 놓기 관성 유지 (#365)
- `6aea722` useDragScroll release를 놓기 직전 움직임에 연결하고 release 모델 분리 (#367)
- `9e1e0ed` useDragScroll contentRef 기반 경계 rubber band 및 잔여 속도 인계 (#368)
- `05d02e2` 마우스 드래그 놓기 관성 안정화 및 Wheel 진단 스토리 정리 (#369)
- `3138052` 스토리북 모달·버튼 예시의 클릭 동작 개선 (#372)
- `9d09cc7` Open 가로 드래그 스크롤 진단과 RTL·포커스 회귀 검증 보강 (#371)
- `f226a23` Interaction의 native tap highlight 자동 억제 계약 정리 (#370)
<!-- generated:end -->

### Minor Changes

- 9e1e0ed: useDragScroll의 contentRef 연결로 경계 rubber band를 옵트인하고 ocGesture.createRubberBandReturn을 추가합니다. 복귀 종료 시 잔여 속도를 일반 release에 인계하며 reduced-motion에서는 경계에서 멈춥니다.

  ### Migration Notes

  기존 호출 변경 없음. 경계 늘어남이 필요한 곳에서 반환된 contentRef를 스크롤 요소의 직계 콘텐츠에 연결합니다. 콘텐츠의 기존 인라인 transform은 덮어쓰지 않습니다.

### Patch Changes

- a7b0c46: `useDragScroll`이 `deferFocus` 없이도 네이티브 드래그 자동 스크롤을 차단합니다. 스크롤 영역에 `user-select: none`을 둔 상태에서 마우스를 누른 채 영역 밖으로 나가면 Safari에서 목록이 끝까지 달려가던 문제를 수정합니다.

  드래그가 될 수 있는 마우스 누름은 항상 기본 동작을 취소하고, `deferFocus: false`에서는 누르는 순간 훅이 포커스를 네이티브 클릭과 같은 요소로 옮깁니다.

  Safari에서 마우스 드래그를 빠르게 놓으면 간헐적으로 관성 없이 멈추던 문제도 수정합니다. 버튼이 이미 풀린 상태로 전달되는 마지막 이동 이벤트를 취소가 아니라 놓기로 처리합니다.

  ### Migration Notes
  - 입력 필드, `data-oc-drag-scroll-ignore`, 중첩 스크롤 영역, modifier 조합은 기존처럼 기본 동작을 유지합니다.
  - CSS `resize`로 크기를 조절하는 요소를 드래그 제외 대상에 추가했습니다. 누름을 취소하면 Chrome에서 크기 조절 핸들이 동작하지 않기 때문입니다.
  - Safari에서 `deferFocus: false`일 때 버튼·링크를 누르면 포커스가 스크롤 영역(또는 문서)이 아니라 그 요소로 갑니다. `deferFocus: true`와 Chrome은 이미 그렇게 동작했습니다.
  - `deferFocus: true` 우회나 자동 스크롤 방지 목적의 `user-select: none`은 더 이상 필요하지 않습니다. 그대로 두어도 동작은 같습니다.

- 6aea722: `useDragScroll`의 마우스 release가 놓기 직전의 움직임에 더 가깝게 이어집니다.
  - 속도를 줄이며 놓을 때 마지막 포인터 움직임보다 빠르게 다시 출발하던 문제를 수정합니다. 놓는 속도는 최근 100ms 평균과 최근 40ms 속도 중 느린 쪽입니다. 촘촘한 스냅 목록에서는 천천히 놓았을 때 여러 항목을 지나치지 않고 다음 항목에 정착합니다.
  - 놓은 직후 같은 위치가 한 프레임 더 그려지던 문제를 수정합니다.

  ### Migration Notes
  - 없음. 공개 API와 `ocGesture` 모델은 그대로입니다. 가속하는 flick의 관성 거리는 이전과 같고, 감속하며 놓은 경우의 관성 거리만 짧아집니다.

- f226a23: Interaction을 직계 자식으로 사용하는 interactive host의 native tap highlight를 touchTarget 설정과 무관하게 억제합니다. Tabs와 Modal navigation에도 동일하게 적용하며, 중첩 Interaction을 사용하는 Modal handle과 ScrollArea track은 실제 터치 영역에서 억제합니다.

  ### Migration Notes

  기존 Interaction 사용처는 별도 변경 없이 적용됩니다. touchTarget을 생략한 host의 텍스트 선택과 hit area는 유지됩니다. 중첩 composition은 실제 interactive host에 `-webkit-tap-highlight-color: transparent`를 선언해야 하며, Interaction이 없는 기본 trigger와 소비자 콘텐츠는 기존 동작을 유지합니다.

- 05d02e2: 마우스 드래그의 짧은 놓기 지연과 미세한 역방향 흔들림으로 관성이 갑자기 사라지거나 스냅 방향이 뒤집히는 현상을 수정합니다.

  Chrome에서 버튼을 놓을 때 `pointerup`보다 먼저 발생한 포인터 캡처 해제를 취소로 처리하여 관성이 중단되는 현상을 수정합니다. 버튼을 누른 상태의 캡처 해제와 실제 포인터 취소는 기존대로 중단합니다.

  Migration Notes: API 변경은 없습니다. 100ms 정지는 유지하며, 3px 미만의 역방향 움직임은 방향 전환으로 확정하지 않습니다. 네이티브 트랙패드·휠 처리와 rubber-band 복귀식은 유지합니다.

### Migration Notes

- 기존 `useDragScroll()` 호출은 변경할 필요가 없습니다. 경계 rubber band를 사용하려면 반환된 `contentRef`를 스크롤 요소의 직계 콘텐츠에 연결하세요. 기존 인라인 `transform`은 덮어쓰지 않습니다.
- Safari에서 `deferFocus: false`인 드래그 대상의 버튼·링크 포커스가 해당 요소로 이동합니다. CSS `resize` 대상은 드래그에서 제외됩니다. 자동 스크롤 방지만을 위한 `deferFocus: true` 또는 `user-select: none`은 더 이상 필요하지 않습니다.
- Interaction 중첩 composition에서 native tap highlight를 억제하려면 실제 interactive host에 `-webkit-tap-highlight-color: transparent`를 선언하세요.

## 1.20.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.19.1..HEAD`_

#### Tests

- `0cad322` test(release): accept patch updates of pinned changesets/action v2

#### Other

- `9d045c3` Merge pull request #342 from orioncactuscorp/dependabot/github_actions/changesets/action-2.1.2
- `4c005a9` useDragScroll 세로 축 지원 (#351)
- `5748b3c` 헤더 interactive target 키보드 회귀 테스트 보강 (#348)
- `7591eec` 릴리스 절차서 수동 npm 명령 레지스트리 옵션 보완 및 로컬 발행 절차 추가 (#350)
- `f71c87d` 세로 드래그 스냅 WebKit 실패와 start 정렬·calc 여백 계산 수정 (#353)
- `d2ca1bd` main CI 제한 시간 조정과 WebKit 간헐 실패 원인 수정 (#355)
- `8620f53` 세로 wheel picker 문서 예제 양끝 여백 보완 - #354 (#354)
- `282fd71` 변경 spec burn-in, 전환 settle helper, flaky ledger 추가 (#356)
- `2b6c5cf` 키보드 세션 중 Modal footer 버튼 마우스 클릭 누락 수정 (#357)
<!-- generated:end -->

### Minor Changes

- 4c005a9: `@orioncactuscorp/ui/react/scroll`의 `useDragScroll`이 `axis: 'x' | 'y'`를 지원합니다. 기존 기본값은 `'x'`이며, `axis: 'y'`에서는 네이티브 세로 스크롤 요소의 마우스 드래그·관성·단일 축 CSS 스냅을 지원합니다.

  세로 wheel picker는 `axis: 'y'`와 `scroll-snap-type: y mandatory` 또는 `block mandatory`를 사용하세요. 양축 마우스 pan과 세로 쓰기 모드는 이번 변경 범위에 포함하지 않습니다.

  ### Migration Notes
  - 기존 `useDragScroll()` 호출은 변경 없이 가로 축으로 동작합니다.
  - 세로 목록에는 `useDragScroll({ axis: 'y' })`를 지정하고 실제 `overflow-y: auto` scrollport에 ref를 연결하세요.
  - 터치·펜·휠, 클릭 억제, 입력 필드·중첩 스크롤 제외 정책은 기존과 같습니다.

### Patch Changes

- 2b6c5cf: `Modal`의 가상 키보드 세션 중 마우스·트랙패드·펜으로 footer 버튼을 누르면 클릭이 누락되던 문제를 수정했습니다. 누르는 순간 입력 필드가 blur되면서 footer가 바로 내려가 떼는 위치에 다른 요소가 오던 현상으로, 이제 surface 안에서 시작한 주 포인터 press가 끝날 때까지(`pointerup`·`pointercancel`·포인터 캡처 해제·창 blur·페이지 숨김) 올라간 footer 위치를 유지한 뒤 내려갑니다. 터치 입력, 키보드 포커스 이동, surface 안 다른 입력 필드로의 이동은 기존과 같습니다.

  ### Migration Notes
  - 없음

### Migration Notes

- 기존 `useDragScroll()` 호출은 변경 없이 가로 축으로 동작합니다.
- 세로 목록에는 `useDragScroll({ axis: 'y' })`를 지정하고 실제 `overflow-y: auto` scrollport에 ref를 연결하세요. 중앙 정렬 wheel picker는 첫·마지막 항목이 중앙에 올 수 있도록 목록 양끝에 여백을 두세요.

## 1.19.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.19.0..HEAD`_

#### Other

- `194b80f` Field 네이티브 터치 하이라이트 제거 (#339)
- `a16224f` Modal 헤더 탭 키보드 닫힘 보정 (#340)
- `a07f5b2` PositionSnap 터치 드래그가 자식 요소에서 시작하면 바로 놓아지는 문제 수정 (#341)
- `cf25602` 배포 전 패키지 진입점 검사 및 깨진 배포본 복구 절차 (#345)
- `6eaf0c8` 릴리스 changelog 기준 태그의 프리릴리즈 정렬 수정 (#347)
- `711d2a4` 키보드 모달 스크롤 경계 보정 (#346)
<!-- generated:end -->

### Patch Changes

- 194b80f: 네이티브 Field 컨트롤의 WebKit 터치 하이라이트를 제거해 underlined 및 outlined 입력이 디자인 시스템의 시각 피드백을 유지하도록 개선합니다.
- a16224f: 키보드가 열린 상태에서 `ModalHeader`를 탭하면 본문 스크롤 위치를 유지한 채 키보드만 닫습니다.
- 711d2a4: 키보드가 열린 Bottom Modal의 스크롤 경계에서 document pan이 발생하지 않도록 보정
- a07f5b2: 터치 기기에서 `PositionSnap` 콘텐츠나 핸들 안의 자식 요소(예: `Button`)를 잡고 드래그하면 시작 직후 놓아지던 문제를 수정합니다. 자식의 implicit touch capture가 positioner로 넘어갈 때 버블링되는 `lostpointercapture`를 드래그 종료로 처리하지 않습니다.
- cf25602: 1.19.0 배포본에서 누락된 `dist` 모듈을 복구합니다.
  - `@orioncactuscorp/ui/react/scroll`, `@orioncactuscorp/ui/react/refs`, `@orioncactuscorp/ui/utils/fling` 진입점이 1.19.0 소스와 문서대로 제공됩니다.
  - `TabsList`의 `dragScroll`, `dragScrollInertia` prop이 배포본 타입과 런타임에 포함됩니다.

  ## Migration Notes
  - 1.19.0을 정확한 버전으로 고정한 경우 1.19.1로 올려야 합니다.

### Migration Notes

- 1.19.0을 정확한 버전으로 고정한 소비 앱은 1.19.1로 올려야 합니다. 그 외 사용 코드 변경은 없습니다.

## 1.19.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.19.0-next.2..HEAD`_

#### Other

- `ef72e87` 모달 탭 전환·진입·드래그 복귀 애니메이션 보완 (#324)
- `6058b7c` Cell·Accordion 가장자리 여백 옵션 및 Modal 헤더 탭 여백 정렬 (#328)
- `a9f1fa8` 중첩 Modal·Alert backdrop 표시 및 퇴장 쌓임 순서·드래그 격리 (#331)
- `4ddf87b` 가로 스크롤 휠 수정 및 드래그·관성·스냅 지원 (#330)
- `bb4d757` non-modal 모달 키보드 세션의 배경 드래그 정책과 iOS viewport 앵커·툴바 대응 (#325)
- `40070af` 드래그 스냅의 WebKit 감속 및 입력 연속성 개선 (#332)
- `8f327cd` Tabs 클라이언트 전용 마운트 오류 수정 (#335)
- `ea1936f` Modal과 FloatingWindow 교차 stacking 순서 수정 (#336)
- `c47d8cd` 제스처 실행과 React 조합 유틸 공개 (#334)
- `862e0a3` 제스처 조합 가이드와 완료 기준 정리 및 테스트 실행 안정화 (#337)
<!-- generated:end -->

### Minor Changes

- Bottom 모달에 제어형 스냅 상태와 키보드·탭으로 높이를 전환하는 핸들을 추가합니다.
  - `snapPoint`와 `onSnapPointChange`로 활성 스냅을 제어하며 드래그·핸들·백드롭 요청 사유를 제공합니다.
  - 여러 유효 높이가 있는 핸들은 버튼으로 렌더링되어 Enter·Space·탭으로 순환합니다.
  - 닫힘은 기존 정책을 유지하며, 키보드 회피 중 핸들 조작은 잠시 비활성화됩니다.

  ## Migration Notes
  - 기존 props 변경은 필요 없습니다. 다중 스냅 핸들이 탭 순서에 포함되며 `handle-area`는 button, 내부 `handle`은 span으로 렌더링됩니다.
  - `handle={false}`로 기본 조작을 숨기는 경우 별도 접근 가능한 높이 변경 수단을 제공하세요.

- Cell과 Accordion에 목록 가장자리 padding 유지 옵션을 추가합니다.
  - `outerPadding` prop을 켜면 첫 항목 위쪽·마지막 항목 아래쪽 padding을 상쇄하던 음수 margin을 제거합니다.
  - 켜진 root에 `data-oc-outer-padding="true"` selector를 제공합니다.
  - 기본값은 `false`로 기존 레이아웃이 유지됩니다.

  ### Migration Notes
  - 없음

- TextInput에 밑줄형 `variant='underlined'`를 추가하고, Field의 `labelPlacement='floating'`으로 기존 FieldLabel이 입력값에 따라 이동·축소하도록 지원합니다. 기본 테두리형과 외부 라벨 조합은 유지됩니다.

  floating 라벨은 medium 굵기를 사용하고, placeholder는 입력 텍스트의 typography를 따릅니다. 모든 FieldLabel은 기본 label-alternative, 입력 영역 포커스 시 primary, invalid 시 오류 색상을 공통으로 사용합니다. 오류 색상이 포커스보다 우선하며 필수 표시도 같은 색상을 따릅니다. 밑줄 끝은 max radius로 둥글게 표현합니다.

  ### Migration Notes
  - floating의 높이를 축소 라벨 라인 높이 + 간격 + 입력 영역 + 하단 padding으로 구성해 상단 잔여 여백을 제거합니다. TextArea는 초기 minRows를 CSS로 확보하고 화면 크기·컨테이너 폭·폰트 로딩 변화에 맞춰 높이를 갱신합니다.
  - floating 라벨과 입력 텍스트 사이 간격은 item-gap-micro 토큰을 사용합니다. 세로 underlined outside 조합도 양수 gap을 사용하고 입력 상단 padding을 분리합니다. 헬퍼 텍스트 간격은 유지합니다.
  - 기존 사용 코드 변경은 필요하지 않습니다.
  - 기존 outside FieldLabel에도 포커스·오류 색상이 적용되며, 필수 표시의 색상도 라벨 상태에 맞춰 변경됩니다.
  - floating은 세로 Field의 underlined TextInput(text/email/password/search/tel/url)과 TextArea에서 기본 적용됩니다. 외부 라벨이 필요하면 labelPlacement="outside"를 명시합니다. 지원하지 않는 조합은 외부 라벨을 유지합니다.
  - floating 모드에서는 기존 FieldLabel을 사용합니다. placeholder가 있으면 포커스 시 라벨이 올라가고 안내가 fade로 표시되며, 없으면 값이 있을 때만 라벨이 올라갑니다.

- 분할 입력을 위한 InputGroup과 선택적 자동 포커스 이동을 추가합니다.
  - InputGroup의 outlined/underlined와 outside/floating 라벨 배치 지원
  - 네이티브 fieldset/legend 및 입력별 이름·설명·오류 연결 유지
  - 소비자가 전달한 aria-invalid 보존 및 개별 입력 disabled 스타일 지원
  - utils/focus의 ocFocus와 react/focus의 useAutoAdvance 제공
  - react/focus의 useInputNavigation으로 분할 입력 경계에서 선택적 화살표 탐색 제공
  - IME·수정·삭제·오류·검증 대기·비동기 결과 취소 처리

  ### Migration Notes
  - 기존 Field/TextInput 사용 변경 없음
  - 분할 입력은 InputGroup/InputGroupInput 조합으로 선택 적용
  - 자동 이동은 enabled를 명시하고 사전 안내 및 완료·검증 조건 제공 필요

- 배경 문서가 스크롤 가능한 non-modal Modal(`modal={false}` 또는 `'trap-focus'`)에서 소프트 키보드가 열린 채 모달 밖에서 시작한 터치가 드래그로 이어지면 입력 포커스를 해제해 키보드를 닫고, 그 제스처는 페이지를 스크롤하지 않습니다. 페이지 스크롤은 키보드가 완전히 닫혀 복원된 viewport가 보고된 뒤 다음 제스처부터 동작합니다. iOS Safari는 페이지 스크롤 중 fixed surface를 layout viewport 기준으로 밀어내고 키보드가 내려가는 중의 스크롤에서는 fixed 레이어 배치를 멈추므로 이벤트 기반 보정으로는 동기화할 수 없어, 네이티브 스크롤 뷰의 `keyboardDismissMode = onDrag`처럼 키보드를 먼저 닫습니다. 모달 내부 스크롤은 키보드를 유지합니다. `ModalContent`에 `keyboardDismiss?: 'background-scroll' | 'none'`(기본 `'background-scroll'`)을 추가합니다.

  `keyboardDismiss="none"`으로 키보드를 유지한 채 배경 문서를 스크롤하는 non-modal 표시에서는 키보드 세션 동안 viewport 레이어를 문서에 앵커하고 root scroll timeline으로 위치를 유지합니다(기본 정책은 세션 동안 페이지가 움직이지 않으므로 앵커를 쓰지 않습니다). iOS는 키보드가 닫히는 중 페이지 스크롤이 이어지면 스크롤이 끝날 때까지 fixed 레이어 배치와 VisualViewport 갱신을 멈추므로, fixed 레이어였던 모달이 페이지와 함께 밀려났다가 스크롤이 멈추는 순간 제자리로 튀던 문제를 compositor가 직접 위치를 유지하도록 바꿔 해결합니다. scroll-driven animation을 지원하지 않는 환경은 기존 fixed 보정을 유지합니다. iOS Safari는 앵커된 레이어가 스크롤 위치만큼 이동한 동안 그 안의 `backdrop-filter` 요소에 backdrop을 공급하지 않으므로 `none`에서는 `BackgroundIconButton` `normal` appearance가 단색으로 보일 수 있습니다. 또한 키보드가 닫히는 동안 브라우저 툴바가 접혀 viewport가 기준보다 커지면 세션이 해제되지 않던 문제를 수정합니다.

  ### Migration Notes
  - non-modal Modal에서 키보드가 열린 채 배경을 드래그하면 키보드가 닫히고 그 제스처는 페이지를 스크롤하지 않습니다. 이전처럼 키보드를 유지하려면 `keyboardDismiss="none"`을 지정하고, 소비자 앱 viewport meta에 `interactive-widget=resizes-content`를 추가하세요.

- Modal header 하단에 배치한 Tabs의 좌우 여백을 Modal header 여백에 자동으로 맞춥니다.
  - `ModalHeader bottomContent` 안의 `TabsList padding`은 viewport 여백 대신 `--oc-modal-header-padding-inline`(기본값 `--oc-modal-container-padding-inline`)을 사용해 탭 시작선을 header 콘텐츠 시작선에 정렬합니다. `leadingContent`가 없으면 title과 같은 시작선입니다.
  - `padding=false` Tabs와 Modal 밖 Tabs는 기존과 같습니다.

  ### Migration Notes
  - Modal header 안 `TabsList padding`의 좌우 여백이 viewport 여백에서 Modal header 여백으로 바뀌어 넓은 화면에서 탭 시작 위치가 안쪽으로 이동합니다.
  - 정렬을 맞추려고 Modal 조상에 `--oc-tabs-list-padding-inline`을 지정했다면 제거할 수 있습니다. 다른 값을 유지하려면 `TabsList`의 `className`에서 지정합니다.

- 드래그 스크롤의 자유 관성을 macOS WebKit 플랫폼 관성 계산기 측정에 맞춘 유한 시간 감속으로 변경합니다. `useDragScroll`의 `inertia`와 `TabsList`의 `dragScrollInertia`를 기본 true로 변경합니다. 스냅 정착과 공용 normal/fast 감속률은 유지합니다.

  ### Migration Notes

  스냅 없는 드래그를 놓자마자 멈추려면 `inertia: false` 또는 `dragScrollInertia={false}`를 지정하세요. 터치와 트랙패드는 계속 네이티브 동작을 사용합니다.

- `@orioncactuscorp/ui/react/scroll`에 `useDragScroll`을 추가합니다. 네이티브 가로 스크롤에 마우스 드래그를 더하고 드래그 후 클릭을 억제합니다. 터치·펜·트랙패드 입력은 네이티브 동작을 유지합니다.

  TabsList는 넘치는 탭 목록에서 마우스 드래그 스크롤을 기본 지원합니다. 드래그 중에는 탭 선택을 유지하고 일반 클릭과 키보드 탐색은 기존 동작을 유지합니다.

  ### Migration Notes

  `TabsList dragScroll={false}`로 마우스 드래그를 끌 수 있습니다. 훅은 실제 스크롤 요소에 반환된 ref를 연결합니다. 일반 드래그 영역의 텍스트 선택은 Shift+드래그 또는 `data-oc-drag-scroll-ignore` 영역을 사용합니다. 입력 필드와 중첩 네이티브 스크롤 영역은 드래그 대상에서 제외됩니다. 기존 슬라이더와 같은 요소에 동시에 연결하지 않습니다.

  `useDragScroll({ inertia: true })`와 `TabsList`의 `dragScrollInertia`로 ocGesture 기반 마우스 관성을 선택할 수 있습니다. CSS 스냅은 드래그·관성 중 잠시 해제한 뒤 원래 설정으로 복원합니다. 관성 기본값은 true이며 새 입력에서는 관성을 중단합니다.

  가로 mandatory 스냅에서는 CSS 정렬·padding·margin과 RTL을 읽어 release 목표를 정하고, macOS WebKit 관성 계산기 측정에 기반한 `ocGesture.projectSnap`·`createSnap`으로 정착합니다. 자유 관성과 스냅은 같은 네이티브 기반 투사를 사용하며 유한 시간에 목표에 도달한 뒤 CSS를 복원합니다. 재입력 시 정착을 중단합니다. reduced-motion에서는 관성과 스냅 정착을 `gesture` release의 `preserve` 예외로 유지하며, 진행 중 설정 변경도 정착을 끊지 않습니다. proximity·두 축·세로 쓰기 모드의 정착은 브라우저에 유지합니다.

  `ocGesture.createSnap(initial, target)`은 DOM에 의존하지 않는 순수 계산으로 `durationMs`와 누적 시간 기반 `sample(elapsedMs)`를 제공합니다. 기존 자유 관성 및 Modal·PositionSnap의 모션 계약은 유지합니다.

  관성 스냅은 release 위치 이전으로 되돌아가지 않도록 WebKit의 방향 정책을 반영합니다. 멈춘 뒤 놓기는 가까운 스냅을 유지합니다. 첫 RAF의 공통 프레임 시각이 release 시각보다 이른 경우에도 음수 경과 시간 오류 없이 진행하도록 수정하며, 관성과 CSS 스냅 해제가 중간에 남는 문제를 방지합니다. Native Comparison Storybook에서 입력과 프레임 위치를 로컬 JSON으로 비교할 수 있습니다.

  스냅은 `inertia` 옵션과 무관하게 놓는 속도를 반영합니다. 옵션은 스냅 없는 자유 관성만 제어합니다. 누른 채 잠시 기다린 뒤 짧게 플릭해도 속도가 유실되지 않도록 눌림 중 위치를 프레임별로 측정하며, 방향 반전은 이전 플릭 방향을 대체합니다.

  스냅 감속의 마지막 0.5 CSS px은 즉시 목표에 정착시켜 한 픽셀만 뒤늦게 움직이는 꼬리를 제거합니다. 순수 `ocGesture.createSnap`의 수학적 표본 계약은 유지합니다.

- React ref 조합, 사용자 모션 설정 구독, 자유 플링 실행 유틸을 공개합니다.
  - `react/refs`의 `mergeRefs`로 React 19 callback cleanup을 보존하며 ref 결합
  - `react/motion`의 `usePrefersReducedMotion`으로 SSR 초기값과 설정 변경 구독 지원
  - `utils/fling`의 `createFlingAnimator`로 자유 감속, 경계 clamp/spring 복귀, 중단·재개 지원
  - 용도별 공개 경로, 네이밍 원칙, 입력·접근성 가이드 추가

  ### Migration Notes
  - 기존 공개 API 제거는 없습니다. `MotionExpand`는 `matchMedia` 미지원 환경에서 모션을 축소하며 SSR/hydration 초기 선호값은 `true`입니다.
  - Modal·PositionSnap·스크롤 정책은 변경하지 않습니다. 신규 플링 실행기의 DOM·입력·reduced-motion 처리는 호출부 책임입니다.

- ModalContent에 드래그 없이 Popup을 중앙·상하좌우·모서리에 배치하는 `position` 옵션과 `ModalPosition` 타입을 추가합니다.
  - 기본값은 `center`이며 viewport 여백을 유지합니다
  - 활성 드래그 스냅은 기존 `snapPositions`와 `defaultSnapPosition`을 우선합니다
  - `bottom`과 `full` 배치는 변경하지 않습니다

  ### Migration Notes
  - 없음

- TextArea에 `variant='underlined'`를 추가합니다. TextInput과 밑줄 스타일 및 모션을 공유하며, 여러 줄 입력과 minRows/maxRows 자동 높이 조절을 유지합니다. root에 `data-oc-variant`를 노출합니다.

  ### Migration Notes
  - 기본값은 기존 외형인 `outlined`로 유지되어 기존 사용 코드 변경은 필요하지 않습니다.
  - 밑줄형 여러 줄 입력은 `TextArea variant='underlined'`를 사용합니다. 세로 Field 안의 underlined TextArea는 floating 라벨이 기본입니다. 외부 라벨이 필요하면 Field에 `labelPlacement="outside"`를 명시합니다.

### Patch Changes

- 키보드가 열린 bottom 모달을 닫을 때 퇴장 높이와 위치가 바뀌는 문제를 수정합니다. 실제 닫힘에서 그림자와 백드롭이 함께 사라지며, 낮은 snap과 peek 상태에서는 그림자를 유지합니다.

  스냅 포인트가 있는 bottom 모달은 관성에 따라 여러 단계를 건너 이동합니다. 상위 스냅에서 아래로 내리면 최하단 스냅까지 이동하고, 최하단에서 다시 내릴 때 닫힘을 평가합니다.

  ### Migration Notes
  - 스냅이 있는 bottom 모달의 상위 스냅에서 한 번의 드래그로 바로 닫히던 동작이 최하단 스냅으로 이동하도록 바뀝니다. 닫기 버튼과 backdrop의 기존 닫힘 정책은 유지됩니다.
  - 공개 props 변경은 없습니다.

- 모달에서 키보드를 드래그로 내린 뒤 원위치로 복귀할 때 최종 본문 높이를 기준으로 스크롤을 복원해, 키보드 여백 제거 순간 본문이 튀는 현상을 수정합니다.

  ### Migration Notes
  - 없음

- TextArea의 높이 갱신을 통합하여 폼 초기화, fluid 글자 치수 및 보조 콘텐츠 크기 변경을 반영합니다. underlined outside Field의 음수 margin을 제거하고 라벨 간격과 입력 상단 padding을 분리합니다. 헬퍼 텍스트 간격은 유지합니다.

  ### Migration Notes
  - 사용 코드 변경은 필요하지 않습니다. TextArea에 비표시 `sizing-probe` 내부 슬롯이 추가됩니다.
  - underlined outside 라벨 간격은 `item-gap-micro`를 직접 사용하므로 viewport에 따라 기존 보정 방식과 소폭 차이가 있습니다.

- Field와 InputGroup의 헤딩 색상을 label-alternative로 유지합니다.
  - 포커스 및 invalid 상태에서 outside와 올라간 floating 라벨의 기본 색상 유지
  - underlined의 내려온 floating 라벨에만 invalid 오류 색상 적용
  - 포커스 테두리와 오류 테두리·메시지 색상 유지

  ### Migration Notes
  - 별도 코드 변경 없음
  - 포커스·오류 상태의 헤딩 색상에 의존하는 시각 커스터마이징 확인 필요

- 제스처 유틸의 조합 예시와 입력 세션·취소·reduced-motion·브라우저 줌 정책 가이드를 추가합니다.

  ### Migration Notes
  - 런타임 API와 기존 컴포넌트 동작은 변경하지 않습니다.
  - 커스텀 팬 표면 구현 시 가이드의 좌표계와 수명주기 계약을 참고하세요.

- bottom Modal의 viewport 레이어를 화면 아래 끝에 앵커해, iOS Safari가 툴바를 접고 펼치는 동안 시트가 늦게 따라오며 아래에 페이지가 비쳐 보이던 틈을 없앱니다. 키보드 예약 높이 기억을 viewport 너비뿐 아니라 높이로도 구분해, 툴바가 접힌 상태(더 큰 layout viewport)에서 측정한 키보드 높이가 툴바가 펼쳐진 다음 세션의 시트를 40px 더 크게 만들던 문제를 수정합니다.

  ### Migration Notes
  - 없음

- Modal 스냅 핸들에서 시트 표면으로 포인터 캡처를 넘길 때 드래그가 조기에 종료되는 문제를 수정합니다. 키보드를 닫는 드래그는 실제 포인터를 놓을 때까지 확장 높이를 유지합니다.

  ### Migration Notes
  - 없음

- bottom Modal에서 입력 포커스 해제로 키보드를 닫을 때 모달 높이 복원을 함께 시작합니다. 스크롤 보호용 키보드 여백은 뷰포트 복구와 모달 및 본문 스크롤 애니메이션이 끝난 뒤 제거해 마지막 입력란에서의 갑작스러운 스크롤 이동을 방지합니다.

  ### Migration Notes
  - 없음

- 콘텐츠 높이를 따르는 bottom Modal은 소프트 키보드가 열릴 때 기존 콘텐츠 높이에 키보드 높이를 더해 입력 공간을 확보합니다. 상단 여백과 최대 높이 및 snap 상한을 유지하며, 키보드 예약 여백을 콘텐츠 증가로 다시 측정하지 않습니다.

  `drag="content"`와 `drag="handle"`에서 실제 시트 드래그가 시작되면 입력 포커스를 해제해 키보드를 닫습니다. 작은 터치와 본문 스크롤은 기존 동작을 유지하며, 드래그 중에는 키보드 예약 여백을 유지해 높이 변경을 미룹니다.

  제어형 스냅 값은 키보드 확장과 복원 중에도 유지합니다. 키보드 회피 중 핸들의 탭·키보드 스냅 순환은 차단하고, 드래그 입력은 유지합니다.

  ### Migration Notes
  - 키보드 회피 중 드래그 가능한 스냅 핸들은 native `disabled` 대신 `aria-disabled="true"`와 `tabIndex="-1"`를 사용합니다. 핸들의 비활성 스냅 상태를 커스터마이즈하는 경우 `aria-disabled`도 확인하세요.

- 다른 Modal 안에 중첩해 렌더링한 Modal·Alert의 backdrop이 표시되지 않던 문제를 수정합니다.
  - 중첩 dialog가 형제로 배치한 경우와 같이 자기 backdrop을 렌더링해 부모 surface까지 dim합니다.
  - 부모 Modal이 `backdrop="hidden"`이어도 중첩 Alert의 dim이 표시되며, 부모 backdrop이 보이는 경우 dim이 한 겹 더 쌓입니다.
  - 중첩 dialog backdrop의 터치·포인터가 부모 Modal의 드래그로 이어지지 않습니다.
  - 위에 쌓인 dialog가 닫히는 퇴장 전환 동안 backdrop이 아래 Modal 뒤로 내려가지 않고 dialog와 함께 사라집니다.

  ### Migration Notes
  - Alert backdrop을 보이게 하려고 Alert를 `ModalContent` 밖 형제로 옮겼다면 다시 안쪽에 두어도 같은 결과입니다.
  - 중첩 dialog 아래 부모 Modal의 dim이 이전보다 진해질 수 있습니다. 공개 props 변경은 없습니다.

- 큰 스냅 요소 사이에서 드래그를 놓을 때 자유 이동 범위의 가장자리 대신 CSS `scroll-snap-align` 위치로 정착하도록 수정합니다. 큰 요소 내부의 자유 스크롤과 관성은 유지합니다.

  ### Migration Notes

  API 변경 없이 적용됩니다. 큰 요소의 `start`, `center`, `end` 정렬은 소비자가 지정한 CSS를 따릅니다.

- 첫 마우스 드래그에서 프레임 샘플이 지연되면 놓는 속도가 0으로 사라지던 문제를 수정합니다. `ocGesture.createVelocityTracker`에 선택적 `interpolateWindowBoundary`를 추가하고 드래그 스크롤에서 활성화합니다. 공용 계산기의 기본값과 멈춘 뒤 놓기의 정지 판정은 유지합니다.

  ### Migration Notes

  기존 사용법 변경은 없습니다. 직접 속도 계산기를 사용하는 경우 `interpolateWindowBoundary: true`로 드문 샘플의 구간 경계 보간을 사용할 수 있습니다.

- Bottom 모달의 기본 닫힘 거리 기준을 50%로 조정하고 같은 경계를 사용하는 관성 닫힘을 유지합니다. 마우스·펜은 핸들이 있는 헤더에서만 시트 드래그를 시작하며 본문에서는 세로·가로 텍스트 선택을 유지합니다. 터치 본문 제스처는 유지됩니다.

  ### Migration Notes
  - 기존 bottom 닫힘 경계가 필요하면 `closeThreshold={0.35}`를 지정하세요. Popup 기본값은 변경되지 않습니다.
  - 마우스·펜으로 시트를 조작하려면 Header 또는 Navigation 핸들을 표시하세요. `handle={false}`인 chrome에서는 마우스·펜 드래그가 시작되지 않습니다. 모든 입력의 드래그를 막으려면 `drag={false}`를 사용하세요.

- 클라이언트에서 처음 마운트되는 Tabs가 불필요한 pre-hydration 스크립트를 렌더링하지 않도록 수정합니다.

  ### Migration Notes
  - 공개 API 변경은 없습니다. Modal 등 클라이언트 전용 영역의 Tabs를 위해 `indicatorRenderBeforeHydration` 우회 패치를 적용했다면 이 버전부터 제거할 수 있습니다.

- 모달의 본문 스크롤바가 Footer/ActionArea 배경에 가려지지 않도록 레이어를 조정합니다. 스크롤바 조작 영역은 키보드로 올라온 Footer까지 고려해 버튼 영역 위에서 끝나므로, Footer 좌우 여백이 없어도 버튼 가장자리 클릭을 가리지 않습니다. Bottom 모달을 끝까지 드래그해 추가 이동 없이 닫을 때도 그림자가 자연스럽게 사라지며, 끝을 넘겨 내린 시트가 위로 되돌아오지 않습니다.

  ### Migration Notes

  소비자 변경은 필요하지 않습니다. 본문 콘텐츠는 Footer 아래에 유지되며 모달의 커스텀 스크롤바만 Footer 배경 위에 표시됩니다.

- Modal과 FloatingWindow을 함께 사용할 때 backdrop과 surface의 stacking order가 역전되던 문제를 수정합니다.
  - Modal, ModalWindow, unmanaged FloatingWindow이 하나의 global owner surface stack 순서를 공유합니다.
  - React tree 중첩이나 sibling portal 배치에서도 나중에 열린 owner surface의 backdrop이 이전 surface 위에 유지됩니다.
  - 퇴장 전환 중 stack slot을 유지해 닫히는 backdrop이 아래 surface로 내려가지 않습니다.

  ### Migration Notes
  - 기존 공개 props를 변경하지 않습니다.
  - Manager 밖에서 `stackLevel`을 사용하는 경우 값은 자동 global depth에 더해지는 수동 offset으로 적용됩니다.

- iOS가 같은 키보드 높이에서 visual viewport 크기를 385/384.984375처럼 소수점 오차로 번갈아 보고해도 Modal이 콘텐츠 높이 재측정과 키보드 추격 모션을 다시 시작하지 않도록 수정합니다.

  ### Migration Notes
  - 없음

- Modal의 탭 전환, Popup 드래그 복귀 및 Bottom 진입 애니메이션을 보완합니다.
  - `ModalBody` 안의 `TabsPanel` 전환에서 새 높이가 먼저 노출된 뒤 이전 높이로 돌아가던 현상을 수정합니다. `keepMounted` 및 제어형 탭 전환을 지원합니다.
  - Popup 손잡이의 hover/pressed 애니메이션이 복귀 스프링을 중단하지 않도록 하고, 복귀 중 실제 크기나 위치 경계가 바뀌면 진행 중인 스프링의 목표를 갱신합니다.
  - 드래그 닫기를 차단한 Bottom 모달도 화면 아래에서 진입하도록 진입 이동과 드래그 범위 제한을 분리합니다.

  ### Migration Notes
  - 없음

- TextArea의 초기 높이와 입력값·행 수 변경에 따른 높이를 부모 레이아웃 측정 전에 확정합니다. Modal의 단계 전환에서 TextArea가 늦게 커지면서 표면 높이가 되돌아가는 현상을 방지합니다.

  ### Migration Notes
  - 없음

- 라벨 없는 underlined 입력은 floating 여백을 예약하거나 placeholder를 숨기지 않도록 개선합니다. 컨트롤 교체 시 소유 Field에 남는 측정값을 정리하고, TextArea의 내용과 레이아웃 조건이 같은 재렌더에서 불필요한 높이 재측정을 생략합니다.

  ### Migration Notes
  - 없음

- Field 공통 자동완성 스타일에서 브라우저 기본 글자색 대신 테마 라벨 색상을 적용합니다. TextInput, TextArea, Select의 자동완성 및 비활성 상태 글자색을 유지합니다.

  Safari 자동완성 기본 배경색을 content box로 제한하여 둥근 모서리에 밝은 테두리처럼 비치는 현상을 방지합니다. 기존 입력 라운드, `oc-border` 라운드와 두께는 유지합니다.

  ### Migration Notes
  - 없음

- 가로 스크롤바에서 트랙패드의 작은 세로 입력 때문에 가로 이동이 느려지거나 반전되는 문제를 수정합니다. 휠 이벤트의 픽셀·행·페이지 단위를 반영하고, 실제 이동을 처리했을 때만 기본 스크롤을 차단합니다.

  ### Migration Notes

  소비자 코드 변경은 필요하지 않습니다. 스크롤바 끝에서는 네이티브 스크롤 연결을 유지하고 Ctrl+휠 확대/축소를 가로 이동으로 변환하지 않습니다.

## 1.18.0

### Migration Notes

- 기존 컴포넌트 사용 코드의 필수 변경은 없습니다.
- `ocGesture`는 `@orioncactuscorp/ui/utils/gesture`에서 가져옵니다. 속도는 px/s, 시간은 ms이므로 기존 px/ms 계산을 교체할 때 단위를 변환하세요.
- Modal handle bar는 이제 `handle-area`의 자식이며 Interaction을 포함합니다. handle의 직계 자식 구조나 의사 요소에 의존하는 커스텀 스타일을 확인하세요.
- ModalHeader의 자체 영역 탭은 body를 맨 위로 스크롤합니다. 제외할 콘텐츠는 `data-oc-modal-no-drag` 또는 header `onClick`의 `preventDefault()`를 사용하세요.
- 키보드 포커스 필드는 header 아래로 정렬됩니다. 별도 포커스 스크롤 보정이 있다면 중복 여부를 확인하세요.
- iOS bottom sheet에서는 키보드 툴바 ▲(이전)가 비활성화되는 제한이 있습니다. 이전 필드는 body를 스크롤해 탭할 수 있습니다.

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.17.0..HEAD`_

#### Documentation

- `d358fd0` docs(changeset): complete release migration notes

#### Other

- `f5d87e5` Gradient Mask 스토리 스크롤 오류 수정 (#289)
- `56ade11` BackgroundIconButton 원형 키보드 포커스 개선 (#290)
- `c6e3f7b` Modal bottom sheet 핀치 줌 geometry 오인 수정 (#293)
- `c80a504` Modal 키보드 세션 시트 안정화 및 포커스 필드 정렬 (#292)
- `3f75e6f` Modal 키보드 모듈 개념별 분리 리팩토링 (#299)
- `9ef1278` Modal 키보드 reveal 스크롤 정수 픽셀 쓰기 (#300)
- `cfac798` Modal handle 드래그 hit 영역 확장 및 hover 피드백 개선 (#294)
- `a824aac` ocGesture 제스처 계산 유틸 공개 및 경계 저항 공통화 (#298)
- `f383ddb` Modal header 탭으로 body 맨 위 스크롤 (#301)
- `9a71706` Modal 키보드 툴바 포커스 이동 시 시트 흔들림 수정 (#302)
- `116ad0b` Modal 키보드 툴바 이동 preventScroll 포커스 통일 및 ▲ 한계 문서화 (#303)
- `878c50d` Modal 시트 성장 e2e 정지 구간 한도 CI 지터 여유 확보 (#304)
<!-- generated:end -->

### Minor Changes

- a824aac: `utils/gesture`의 `ocGesture` 진입점을 추가합니다. 경계 저항, 마찰 감속과 투사, px/s 기반 속도 추적기를 제공하며 Modal·PositionSnap의 rubber band 계산을 공통화합니다. 기존 스냅·닫기·속도 측정 정책은 유지합니다.

  ### Migration Notes
  - 기존 컴포넌트 소비자의 필수 변경은 없습니다.
  - 제스처 유틸은 `@orioncactuscorp/ui/utils/gesture`에서 `ocGesture`로 가져옵니다.
  - 속도는 px/s, 시간은 ms입니다. 기존 px/ms 기반 구현을 교체할 때 단위를 변환하세요.
  - 감속 기본값은 normal(0.998)이며 fast(0.99)는 `{ rate: ocGesture.decelerationRates.fast }`로 지정합니다.

- f383ddb: `ModalHeader`의 자체 영역(title, 빈 공간, handle-area)을 탭하면 body가 sheet 모션 spring으로 맨 위로 스크롤됩니다. iOS status bar 탭이 페이지를 맨 위로 보내는 것과 같은 보조 제스처이며, header 안의 컨트롤 클릭과 `data-oc-modal-no-drag` 콘텐츠(drag 시작을 막는 기준과 동일), 소비자 `onClick`의 `preventDefault`, drag 뒤의 click, body가 이미 맨 위인 경우는 제외됩니다. reduced-motion에서는 즉시 이동합니다. 키보드 필드 reveal과 header 탭 스크롤은 모달당 하나의 스크롤러를 공유해 새 이동이 진행 중인 이동을 이어받습니다.

  ### Migration Notes
  - 기존 소비자의 필수 코드 변경은 없습니다. header의 자체 콘텐츠에서 맨 위 스크롤을 제외하려면 `data-oc-modal-no-drag`를 지정하거나 header `onClick`에서 `preventDefault()`를 호출하세요.

### Patch Changes

- 116ad0b: Modal bottom sheet에서 iOS 키보드 툴바 ▼(다음)가 켜진 채 이동하지 않거나 이동 뒤 시트가 흔들리던 문제를 수정합니다. iOS는 포커스 시점에 ▲▼ 상태를 스냅샷하고 누르는 시점에 이웃 필드의 중심이 가려지지 않았는지 다시 판정하므로, 탭 가로채기와 툴바 이동 모두 필드를 최종 위치(header 바로 아래)에 둔 채 `preventScroll`로 포커스해 스냅샷과 최종 레이아웃을 같게 하고 WebKit의 visual viewport pan을 없앱니다. ▲(이전)는 이전 필드가 항상 header 뒤에 놓여 iOS가 이동 대상으로 보지 않으므로 bottom sheet에서는 꺼진 상태로 유지됩니다.

  ### Migration Notes
  - 기존 소비자의 필수 코드 변경은 없습니다. iOS bottom sheet에서는 이전 필드가 header 뒤에 놓여 키보드 툴바 ▲(이전)가 비활성화되는 제한이 있습니다. 이전 필드로 돌아가려면 body를 스크롤해 해당 필드를 탭하세요.

- 9a71706: Modal bottom sheet에서 iOS 키보드 툴바의 ▲▼(또는 Tab, 프로그램 포커스)로 다음 입력 필드로 이동할 때 시트가 흔들리던 문제를 수정합니다. WebKit이 스스로 옮기는 포커스는 visual viewport를 pan하므로, 이전 필드의 `focusout`이 다음 필드를 알려주는 시점에 그 이동을 이어받아 탭 가로채기와 같은 경로(최종 위치에 임시로 둔 채 `preventScroll` 포커스, 원위치 복귀, sheet 모션 spring reveal)로 처리합니다. WebCore는 handler가 포커스를 옮기면 자기 이동을 버리므로 pan이 일어나지 않습니다.

  ### Migration Notes
  - 없음

- cfac798: `drag='handle'` 또는 `drag='content'` Modal에서 handle을 잡기 쉽도록 `ModalHeader` handle 구조를 확장합니다. 32×4px bar `data-oc-part="handle"`은 그대로 두고 `data-oc-part="handle-area"`로 감싸며, 두 drag 모드에서 `data-oc-draggable="true"`인 공통 pointer 영역을 사용합니다. fine pointer에서는 surface 좌우 끝까지 닿는 16px 상단 strip, coarse pointer에서는 중앙 72×44px pad가 pointer를 받습니다. fine pointer의 full-width strip은 header control과 겹치지 않도록 compact header에서도 상단 clearance를 보장합니다. hover 가능 기기에서는 strip hover 시 bar가 제자리에서 1.1배로 커지고(`expand` smooth spring) bar 안의 `Interaction`(light)이 hover/active tint를 표시하며, 누르는 동안 drag hook이 handle-area에 `data-oc-state="pressed"`를, release 후 pointer가 area 위에 남아 있으면 `data-oc-state="hover"`를 내보내 브라우저 `:hover` 공백 동안에도 확대 상태가 끊기지 않습니다. `drag='content'`에서는 handle-area와 header 전체가 같은 chrome drag arbitration을 사용하고, `drag='handle'`에서는 handle-area만 drag를 시작합니다. reduced-motion에서는 scale 없이 tint만 남습니다. `ModalNavigationSection` handle의 동작은 바뀌지 않습니다.

  ### Migration Notes
  - `[data-oc-part="handle"]`은 이제 `[data-oc-part="handle-area"]`의 자식이며 `Interaction` 자식을 가집니다. bar 시각 커스터마이즈는 기존처럼 `[data-oc-part="handle"]`을 대상으로 하되, `::before`/`::after`나 자식 구조에 의존하는 override가 있으면 확인하세요.

- c80a504: Modal bottom sheet의 소프트 키보드 대응을 개선합니다. 키보드 세션 동안 `resize="content"` 시트의 높이를 고정해 키보드 예약 공간이 콘텐츠 높이로 읽혀 시트 상단이 위로 밀리던 문제를 해결하고, 포커스된 입력 필드를 키보드 경계에 최소한으로 붙이는 대신 ModalHeader 바로 아래(scroll-padding 시작 edge)로 정렬합니다. 필드가 키보드에서 멀리 놓이므로 WebKit이 visual viewport를 pan하거나 배경 페이지를 스크롤할 이유가 사라져 시트 떨림이 줄고, 활성 필드 아래의 다음 필드가 함께 드러납니다. 이미 정렬된 필드는 키보드에 가려질 때만 다시 정렬합니다. 키보드 높이 메모리는 viewport 폭과 키패드 종류(text/numeric, `inputmode` 우선)별로 기록해 숫자 키패드와 QWERTY가 서로를 잘못 seed하지 않으며, `readOnly` 필드와 `inputmode="none"` 필드는 키보드 회피 세션을 시작하지 않습니다. 정렬 앵커는 필드 바로 위의 라벨(`labels`, `aria-labelledby`)까지 포함하고, 정렬은 focus 이벤트 안에서 동기적으로 실행되며, 터치 환경(coarse pointer)에서는 키보드 높이를 측정하기 전인 첫 포커스에서도 정렬합니다. 정렬은 콘텐츠 끝(키보드 예약 공간 포함)을 넘지 않아 마지막 필드는 rest와 같은 간격으로 footer 위에 놓입니다. 터치 환경에서는 편집 가능한 필드에 대한 탭을 가로채 WebKit이 포커스 rect를 읽는 동안만 필드를 최종 위치에 두고(paint 없이) `preventScroll`로 포커스한 뒤 원위치로 돌려 iOS의 visual viewport pan 자체를 없애고, 이어서 sheet 모션 spring으로 부드럽게 스크롤해 드러내며(reduced motion에서는 즉시), 탭 위치의 caret을 복원합니다. 라벨을 탭해 필드가 포커스되는 경우도 같은 경로를 탑니다. 키보드 세션 중 body 스크롤이 끝에 닿아도 visual viewport pan으로 이어지지 않도록 overscroll을 억제하며, footer와 pan 보정의 chase 시간을 iOS 키보드 애니메이션(약 0.25초)에 맞춰 줄였습니다. 키보드가 닫힐 때 footer는 blur 시점부터 iOS 키보드 해제 choreography(약 0.5초)에 맞춘 sheet 모션으로 내려가고(viewport 레이어에 `data-oc-modal-keyboard-closing="true"` 방출), pan 보정은 복원 샘플을 그대로 따르며, 세션 동안 footer 높이 측정값을 고정해 safe-area inset 변화로 body 끝 여백이 줄어들며 콘텐츠가 밀리는 현상을 막습니다. 이전 세션이 닫히는 동안 다른 필드를 포커스해도 rest baseline을 이어받아 시트 shell이 키보드 높이로 접히지 않습니다.

  ### Migration Notes
  - 기존 소비자의 필수 코드 변경은 없습니다. 키보드가 열린 동안 입력 필드는 header 아래로 정렬되므로, 소비자가 별도로 구현한 포커스 스크롤 보정과의 중복 여부를 확인하세요.

- c6e3f7b: Modal bottom sheet가 핀치 줌으로 줄어든 visual viewport를 소프트 키보드로 오인해 스냅 높이와 시트 크기를 매 프레임 재계산하던 문제를 수정합니다. `visualViewport.scale`이 1이 아니면 layout viewport 기준 geometry를 유지하므로 줌 중에도 시트 크기와 위치가 고정되고, popup snap 위치 재동기화도 줌 중에는 건너뜁니다. bottom sheet surface의 `touch-action`이 `pan-y`에서 `pan-y pinch-zoom`으로 바뀌어 시트 위에서도 핀치 줌이 시작됩니다.

  드래그 핸들에서도 핀치 줌을 허용하고, 단일 터치 드래그 중 멀티터치로 전환하면 드래그와 스크롤 잠금을 해제하고 시작 위치로 복귀합니다.

  ### Migration Notes
  - 없음

- 9ef1278: Modal 키보드 reveal 스크롤이 프레임마다 정수 픽셀을 쓰도록 바꿔, 소수 스크롤 위치를 버림 처리하는 Safari에서 이동 끝에 1px이 튀어 오르던 현상을 제거합니다.

  ### Migration Notes
  - 없음

- 56ade11: BackgroundIconButton의 키보드 포커스 링이 작은 사각형 본체 대신 실제 원형 배경 바깥을 따라 표시되도록 수정합니다. 버튼 크기와 터치 영역은 유지합니다.

  ### Migration Notes
  - 없음

## 1.17.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.16.0..HEAD`_

#### Other

- `d27d025` Modal 본문 끝 ActionArea 자동 여백 보정 (#282)
- `35d3f23` Badge variant 전환 및 border 계약 개선 (#284)
- `757780c` Modal popup 콘텐츠 전환 플래시 및 footer 크롬 플립 개선 (#285)
- `cae0595` BackgroundIconButton disabled 전환 오버슈트 수정 (#286)
<!-- generated:end -->

### Minor Changes

- 35d3f23: Badge의 canonical 기본 variant인 `default`를 추가하고, `label-strong` 배경과 `background-normal-normal` 라벨 색을 적용합니다. 기존 `normal` variant는 `label-alternative` 라벨과 `fill-normal` 배경을 유지합니다. Badge 배경 전환을 variant별 opacity 레이어로 분리하고, `oc-border` 기반의 `--oc-badge-border-width` 및 `--oc-badge-border-color` contract를 제공합니다.

  Migration Notes:
  - `variant`를 생략한 Badge의 `data-oc-variant` 값이 `normal`에서 `default`로 변경됩니다. 해당 selector를 직접 커스터마이즈하는 소비자는 `default`를 기준으로 업데이트하세요.
  - `variant='default'`는 `label-strong` 배경과 `background-normal-normal` 라벨 색을 사용합니다.
  - 기존 `variant='normal'`은 `label-alternative` 라벨과 `fill-normal` 배경을 유지합니다.
  - Badge border는 기본적으로 투명하며, `--oc-badge-border-color`와 선택적인 `--oc-badge-border-width` override로 표시할 수 있습니다.

- 757780c: `ModalRoot`에 open/close transition이 끝난 뒤 호출되는 `onOpenChangeComplete(open)` 콜백을 추가합니다. depth navigation처럼 exit 동안 유지해야 하는 view 상태를 닫힘 완료 후 초기화할 때 사용합니다.

  ### Migration Notes
  - 없음

### Patch Changes

- 757780c: 렌더링할 액션, caption, extraContent가 없는 `ActionArea`는 `data-oc-empty="true"`를 방출하고 자체 padding과 background를 접습니다. `ModalFooter`와 `FloatingWindowFooter`의 직속 빈 `ActionArea`는 footer 예약을 `0`으로 만들어 body는 기본 하단 여백만 유지합니다.

  ### Migration Notes
  - 빈 `ActionArea`로 하단 여백을 만들던 경우 명시적 spacer로 바꾸세요.
  - depth navigation에서 root depth에 액션이 없어도 `ModalFooter`와 `ActionArea`를 계속 마운트해 두면 root에서는 예약이 접히고 다음 depth부터 버튼 높이가 예약됩니다.

- d27d025: ModalBody 마지막 직속 ActionArea가 본문 여백과 중복되지 않도록 자동 보정합니다.

  ### Migration Notes
  - 기존 ModalBody 마지막 ActionArea에 지정한 중복 여백 override는 제거해도 됩니다.
  - 이 조합에서는 desktop action group의 기본 max width가 `none`이 되며, standalone ActionArea의 `--oc-atomic-width-content` 기본값은 유지됩니다.
  - 의도적으로 다른 간격을 사용하는 경우에는 기존 `--oc-action-area-*` override를 유지할 수 있습니다.

- 757780c: WebKit에서 `Fieldset`이 첫 레이아웃 때 legend 높이만큼 더 크게 그려졌다가 내부 재배치 시점에 줄어들던 문제를 수정합니다. legend를 float로 배치해 모든 엔진에서 같은 높이로 그려집니다.

  ### Migration Notes
  - `FieldLegend` 다음 콘텐츠와의 간격이 `.content`의 시작 margin에서 legend의 끝 margin으로 옮겨졌습니다. 간격 값은 동일하며, legend와 콘텐츠 사이 간격을 직접 덮어쓰던 CSS가 있다면 legend 쪽으로 옮기세요.

- 757780c: Modal popup 콘텐츠 전환이 `navigationDepth` 변경을 명시적 교체 신호로 사용해 목적지 레이아웃 플래시 없이 이전 높이에서 새 높이로 전환합니다. 전환 중 header/footer 측정값이 늦게 반영되면 목표 높이를 재타겟하고, footer 스크롤 크롬은 목적지 scrollport 기준으로 판정해 전환 중 깜빡이지 않습니다. `ModalFooter`를 언마운트해도 측정된 footer 높이가 body 여백에 남지 않습니다.

  ### Migration Notes
  - depth view 교체에 높이 전환을 기대하는 popup은 `ModalRoot`의 `navigationDepth`를 view와 같은 커밋에서 갱신하세요. 신호 없는 콘텐츠 변화는 기존처럼 안착 후 best-effort로 전환되며, 큰 교체는 한 프레임 동안 목적지 레이아웃이 먼저 보일 수 있습니다.
  - 내부 attribute `data-oc-modal-sheet-resizing`이 `data-oc-modal-resizing`으로 바뀌었습니다. 공개 selector 계약은 아니지만 이 attribute를 참조하던 CSS가 있다면 갱신하세요.
  - Reduced motion에서 popup 높이 전환은 즉시 완료되며 `data-oc-content-transition-state="changing"` 구간이 없습니다.

- 757780c: bottom sheet의 depth 전환이 끊기던 문제를 수정합니다. `navigationDepth`가 `0`보다 커서 drag 닫기가 차단된 상태에서는 canvas settle의 시작 translate가 gesture rubber-band 한계로 clamp되어 sheet가 먼저 튀어오른 뒤 멈췄다가 남은 거리만 움직였습니다. canvas settle은 gesture 범위 밖의 programmatic geometry로 취급해 clamp하지 않고, backdrop dim은 목적지 rest 값을 유지해 전환 중 1에서 내려갔다 돌아오지 않습니다. 또한 depth 변경 커밋에서 콘텐츠를 즉시 다시 재어 같은 프레임에 settle을 시작하고, body content를 border-box로 관찰해 header/footer 예약 반영 시 진행 속도를 이어받아 재타겟합니다.

  ### Migration Notes
  - 없음

- cae0595: BackgroundIconButton disabled 전환이 중간에 밝게 튀었다가 되돌아오던 문제를 수정합니다.
  - disabled fill을 컴포넌트 루트의 불투명 레이어로 분리하고 `opacity`만 교차 페이드합니다. 장식 레이어(`backdrop-filter`, `::before` multiply, `::after` plus-lighter)는 전환 중 그대로 유지됩니다.
  - 결과 합성이 두 끝 렌더링의 선형 보간(`(1−p)·enabled + p·disabled`)이 되어 blend/clipping 비선형성과 무관하게 오버슈트가 발생하지 않습니다.
  - disabled fill 색을 `--oc-background-icon-button-disabled-background-color`로 노출합니다. 기본값은 `--oc-color-theme-interaction-disable`입니다.

  Migration Notes
  - disabled 상태에서 `--oc-background-icon-button-background-color` 값이 더 이상 보이지 않습니다. 기존에는 이 override가 disabled 배경에도 적용됐습니다. disabled 배경을 조정하려면 `--oc-background-icon-button-disabled-background-color`를 사용하세요.
  - 컴포넌트 루트가 `::after` 의사 요소를 사용합니다. oc-ui 컴포넌트 루트에 직접 `::after`를 선언하던 소비자 CSS는 충돌할 수 있습니다.
  - public export, prop, `data-oc-*` selector 계약은 변경되지 않았습니다.

## 1.16.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.15.1..HEAD`_

#### Maintenance

- `ae8346e` ci: add Tailscale runner bootstrap (#266)
- `a0e7438` chore(ci): remove shared runner maintenance assets

#### Other

- `637157e` ActionArea padding override 안정성 보완 (#270)
- `5bd2c37` PositionSnap CI 테스트 안정화 (#271)
- `8304b7a` Modal bottom sheet 관성 dismiss 개선 (#273)
- `56a7b39` ScrollArea 오버레이 스크롤 잠금 경합 제거 (#275)
- `8d6971b` Modal 이미지 wrapper 스크롤 판정 보완 (#268)
- `211ec69` Public component contract 변수 cascade 안정화 (#274)
- `49583d9` fluidClamp 호환 API 제거 (#276)
- `92e6a4e` ScrollArea 모바일 스크롤바 표시 개선 (#277)
- `f523460` Interaction 터치 영역 커스터마이징 추가 (#278)
- `f704606` Modal 본문 끝 ActionArea 예시 추가 (#279)
<!-- generated:end -->

### Minor Changes

- 49583d9: 더 이상 사용되지 않는 SCSS `fluidClamp()` 호환 함수를 제거합니다.

  ### Migration Notes
  - `fluidClamp($from, $bp, $anchor, $to)` 호출을 `oc-fluid($from, $to, $bp, $anchor)`로 변경합니다.
  - `fluidClamp(toRem(16), 375px, to, toRem(20))`은 `oc-fluid(toRem(16), toRem(20), 375px)`로 변경합니다.
  - `oc-fluid()`를 사용하려면 `@orioncactuscorp/ui/scss/mixins/fluid`를 불러옵니다. `toRem()`과 `stripUnit()`은 기존처럼 `@orioncactuscorp/ui/scss/mixins/utils`에서 사용할 수 있습니다.

- 92e6a4e: 터치 기기의 `ScrollArea`가 커스텀 scrollbar 대신 운영체제의 native scrollbar indicator를 표시하도록 수정하고, 스크롤 동작을 유지한 채 indicator를 모든 환경 또는 터치 환경에서만 숨길 수 있는 `scrollbarVisibility="hidden"`, `scrollbarVisibility="hidden-on-touch"` 옵션을 추가합니다.

  Migration Notes:
  - 모든 환경에서 scrollbar indicator를 숨기려면 `scrollbarVisibility="hidden"`, 터치 환경에서만 숨기려면 `scrollbarVisibility="hidden-on-touch"`를 지정하세요.

- f523460: Interaction의 기존 시각·상태 계약을 유지하면서 44px 터치 대상 foundation과 host별 최소 hit area 커스터마이징을 추가합니다. Button, TextButton, IconButton, BackgroundIconButton, interactive Badge와 선택 컨트롤은 기본 44px 영역을 사용하며 `--oc-interaction-touch-target-min`으로 재정의할 수 있습니다. custom host는 `touchTarget` prop으로 hit layer를 선택할 수 있으며, semantic direct host의 iOS Safari native tap highlight와 accidental text selection은 Interaction feedback으로 대체됩니다. 링크의 long-press context menu와 브라우저 gesture는 유지합니다. 확장 영역이 host 바깥에서도 동작하도록 Button, padding Badge, Switch의 내부 overflow clipping은 제거됩니다.

  ### Migration Notes
  - 기존 컴포넌트 사용 코드는 변경할 필요가 없습니다. 기본 44px 터치 영역이 레이아웃과 겹치는 경우 `--oc-interaction-touch-target-min` 또는 custom host의 `touchTarget` prop을 조정하세요.

### Patch Changes

- 637157e: `ActionArea`의 기본 padding을 property fallback으로 제공해 소비처의 `--oc-action-area-padding-*` override가 CSS chunk 순서와 무관하게 적용되도록 개선합니다.

  ### Migration Notes
  - 없음

- 56a7b39: Root `ScrollArea`가 mount/unmount 중 `document.body.style.overflow`를 임시로 변경하지 않도록 수정해, 같은 초기 렌더에서 열린 Modal 또는 Menu를 닫은 뒤 페이지 스크롤 잠금이 남는 문제를 해결합니다.

  Migration Notes:
  - 없음 — `ScrollArea` 공개 API와 selector 계약 변경 없이 body scroll-lock 소유권 경합을 제거합니다.

- 211ec69: 공개 component contract CSS 변수의 기본값을 property fallback과 internal default로 제공해 per-component CSS가 consumer CSS보다 나중에 로드되어도 override가 유지되도록 개선합니다.

  ### Migration Notes
  - 없음

- 8304b7a: Modal bottom sheet가 짧고 빠른 하향 드래그의 release velocity를 예상 도착점에 반영해 네이티브 sheet처럼 닫히도록 개선합니다.

  ### Migration Notes
  - 없음

- 8d6971b: 모바일 BottomSheet에서 `overflow: hidden` 이미지 wrapper가 스크롤 컨테이너로 오인되지 않도록 콘텐츠 스크롤 경계 판정을 보완합니다.

  ### Migration Notes
  - 없음

## 1.15.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.15.0..HEAD`_

#### Other

- `827e751` Menu divider radius 제거 (#263)
<!-- generated:end -->

### Patch Changes

- 827e751: MenuItem 구분선을 focus ring용 모서리 반경과 분리하고 MenuSeparator를 메뉴 surface 끝까지 확장해 Cell 간격 기준에 맞춰 항상 직선으로 표시합니다.

  Migration Notes
  - 없음

### Migration Notes

- 없음

## 1.15.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.14.0..HEAD`_

#### Documentation

- `c368e6e` docs(storybook): add scrollable anchor window example

#### Maintenance

- `4153d0c` chore(deps): bump actions/checkout from 7.0.0 to 7.0.1 (#233)

#### Other

- `908a248` 채워진 컨트롤 색상 계약 추가 (#250)
- `58ee8ed` Interaction 강도 커스터마이즈 개선 (#249)
- `b27a713` 중첩 오버레이 스태킹 개선 (#251)
- `5ffc130` Changesets v3 릴리스 파이프라인 마이그레이션 (#247)
- `479ef83` iOS Safari Modal 키보드 viewport 보정 (#248)
- `38834bb` Interaction 상태 레이어 색 계약 정리 (#253)
- `227bb35` Modal 키보드 회피 내부 구조 정리 (#252)
- `f5087ae` Progress Indicator 컴포넌트 추가 (#254)
- `ac7c17a` Easing gradient·mask 공용 유틸 추가 (#255)
- `5afca2d` oc-fluid SCSS helper 추가 (#257)
- `f4395d5` PositionSnap 공용 스냅 프리미티브 추가 (#256)
- `5e2ad3e` Safari BackgroundIconButton 원형 렌더링 보정 (#260)
- `f65d9c2` Alert 반복 거부 피드백 재생 보완 (#261)
<!-- generated:end -->

### Minor Changes

- f5087ae: 알려진 범위의 작업 및 단계 진행률을 표시하는 `ProgressIndicator`를 추가합니다. `value`/`max`, 세 가지 선 두께, 접근 가능한 이름, semantic color와 oc-motion 기반 길이 전환을 지원합니다. `ModalHeader bottomContent`로 진행률이나 navigation chrome을 배치하면 Modal이 측정된 header 높이와 size별 body 시작 간격을 자동으로 예약하며, 직계 `ProgressIndicator`는 header edge에 맞춰 radius를 제거합니다.

  Migration Notes: 없음

- f4395d5: Button 같은 임의의 콘텐츠를 viewport 또는 element 경계의 논리 방향 위치로 드래그하고 안착시킬 수 있는 `PositionSnap` compound component를 추가합니다. controlled/uncontrolled position, content/handle drag, spring release, RTL 방향을 지원하며 Modal popup은 같은 geometry와 release 정책을 재사용합니다.

  Migration Notes:
  - 기존 Modal `snapPositions`, `snapPosition`, `defaultSnapPosition`, `onSnapPositionChange` API와 물리 방향 position 이름은 변경되지 않습니다.
  - Modal이 아닌 콘텐츠에는 `PositionSnap.Root`, `PositionSnap.Positioner`, 선택적인 `PositionSnap.Handle`을 조합하고 논리 방향 position 이름을 사용하세요.

- ac7c17a: 색 변화율에 smoothstep easing을 적용하는 `oc-easing-gradient` 함수와 시작·끝 fade 길이 및 전체 content 길이를 CSS 변수로 조정할 수 있는 `oc-gradient-mask` mixin을 추가합니다. 2D scroll content는 `oc-gradient-mask-edges`로 상하좌우 fade를 독립적으로 조정하고 block·inline mask를 교차 합성할 수 있습니다. Tabs overflow mask는 동일한 scroll·RTL·`oc-motion` 동작을 유지하면서 새 easing gradient를 사용합니다.

  Migration Notes: 기존 Tabs 사용 코드는 변경할 필요가 없습니다. 새 helper는 `@orioncactuscorp/ui/scss/mixins/gradient`에서 import합니다.

- 58ee8ed: Interaction 강도를 host 범위에서 선택할 수 있는 `data-oc-interaction-variant="light|normal|strong"` selector와 `--oc-interaction-opacity-factor` CSS 변수 계약을 추가합니다. 커스텀 host 타입에는 공개된 `InteractionHostProps`를 재사용할 수 있고, Button, ActionArea, Alert, form control, Menu portal을 포함한 합성 경로에서도 같은 계약이 적용되며 기존 `Interaction variant`와 `--oc-interaction-opacity-*` 출력값은 유지됩니다.

  Migration Notes:
  - 기존 사용 변경 없음
  - 색을 커스텀한 컴포넌트 또는 합성 영역의 Interaction 강도를 함께 바꾸려면 host에 `data-oc-interaction-variant`를 설정하세요.

- 5afca2d: `oc-fluid()` SCSS helper를 추가해 최소값, 최대값, 기준 viewport, anchor를 조합한 fluid length 값을 생성할 수 있도록 합니다.
  - `anchor` 기본값은 `to`이며 `$breakpoint-md` 같은 Sass breakpoint 변수와 `375px` 같은 직접 viewport 값을 지원합니다.
  - 기존 `fluidClamp()` 호출은 호환성을 위해 유지합니다.
  - Migration Notes: 신규 커스텀 fluid 값은 `scss/mixins/fluid`의 `oc-fluid()`를 사용합니다.

### Patch Changes

- 908a248: Checkbox, Radio, Switch, BackgroundIconButton의 채워진 배경색과 전경색을 component contract CSS 변수로 노출합니다. 기본 색상은 유지하면서 consumer가 내부 상태 selector를 복제하지 않고 두 색을 함께 재정의할 수 있습니다.
- b27a713: Modal과 FloatingWindow 안의 Menu·Tooltip이 가장 가까운 surface를 portal boundary로 사용하도록 overlay stacking을 개선합니다. MenuContent와 TooltipContent에 명시적 container override를 추가하고 z-index 의미 단계와 중첩 규칙을 문서화합니다.

  Migration Notes:
  - Modal 또는 FloatingWindow 안의 Menu·Tooltip portal DOM이 document body가 아니라 owner surface 아래에 배치됩니다. body 직계 자식 selector에 의존한 consumer CSS는 `data-oc-*` selector 또는 명시적 `container` prop으로 전환해야 합니다.

- 227bb35: Modal 키보드 회피 세션 해제를 고정 지연 대신 실행 중인 transform transition 감지 기반으로 전환합니다. `--oc-motion-*` 토큰으로 chase 모션이 느려져도 키보드 정리 시점에 스냅이 생기지 않으며, `getAnimations` 미지원 환경은 기존 fallback 지연으로 동작합니다. 내부적으로 키보드 세션 상태 전이가 순수 reducer 모듈로 정리되었고 공개 API 변경은 없습니다.

  Migration Notes:
  - 없음 — Modal 공개 API와 selector 계약 변경 없이 키보드 세션 해제 타이밍을 개선합니다.

- 38834bb: `--oc-interaction-color`를 host와 하위 Interaction의 공개 상태 레이어 색 계약으로 문서화합니다. 전역 theme token이 아닌 host-scoped override 경계를 명시하고, Button의 기본 fallback을 `label-normal`로 정리하면서 solid/outlined와 variant별 기존 렌더링 결과는 유지합니다.
- f65d9c2: Alert의 바깥 배경 닫기 거부 피드백이 반복 입력에서도 다시 재생되도록 보완합니다.
- 479ef83: 모바일(iOS Safari/Chrome, Android Chrome)에서 소프트 키보드가 열리고 닫힐 때 Modal bottom sheet의 키보드 대응을 개선합니다. 키보드 geometry를 sheet motion으로 추격해 footer와 컨테이너가 끊김 없이 이동하고, footer 배경이 키보드 위 브라우저 chrome 영역까지 채워지며, 직전 실측 키보드 높이로 포커스 필드를 선제 노출해 배경 페이지 스크롤/pan과 흔들림을 방지합니다. blur 없이 키보드만 닫는 경우(Android back 제스처 등)에도 하단 예약 공간이 해제됩니다. viewport 레이어에 내부 지향 상태 attribute `data-oc-modal-keyboard-avoiding="true"`가 추가됩니다.

  Migration Notes:
  - 없음 — 기존 Modal API 변경 없이 키보드가 표시된 모바일 viewport 배치와 전환 품질을 개선합니다.

- 5e2ad3e: Safari에서 `BackgroundIconButton` 배경 레이어가 네모로 렌더링될 수 있는 경우에도 원형 반지름 fallback을 유지합니다.

  Migration Notes:
  - 없음

### Migration Notes

- Modal 또는 FloatingWindow 안의 Menu·Tooltip portal DOM이 document body가 아니라 owner surface 아래에 배치됩니다. body 직계 자식 selector에 의존한 consumer CSS는 `data-oc-*` selector 또는 명시적 `container` prop으로 전환해야 합니다.
- Modal이 아닌 콘텐츠에는 `PositionSnap.Root`, `PositionSnap.Positioner`, 선택적인 `PositionSnap.Handle`을 조합하고 논리 방향 position 이름을 사용하세요. 기존 Modal snap API와 물리 방향 position 이름은 변경되지 않습니다.
- 새 fluid/gradient helper를 사용하는 consumer는 `@orioncactuscorp/ui/scss/mixins/fluid`의 `oc-fluid()`와 `@orioncactuscorp/ui/scss/mixins/gradient`를 import하세요. 기존 `fluidClamp()`와 Tabs 사용 코드는 변경할 필요가 없습니다.
- 색을 커스텀한 컴포넌트 또는 합성 영역의 Interaction 강도를 함께 바꾸려면 host에 `data-oc-interaction-variant`를 설정하세요. 기존 사용에는 변경이 없습니다.

## 1.14.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.13.0..HEAD`_

#### Other

- `0f92eea` FloatingWindow 컴포넌트 추가 (#235)
- `e44c0e4` 모달 초기 포커스 정책 개선 (#236)
- `95cca4e` 0 duration 모션 즉시 완료 처리 (#234)
- `a94819d` FloatingWindow 다중 창 관리자 추가 (#237)
- `3582939` Modal·FloatingWindow 프레젠테이션 일원화 (#238)
<!-- generated:end -->

### Minor Changes

- e44c0e4: Modal과 ModalWindow가 DOM상 첫 control 대신 등록된 title을 기본 초기 focus로 사용하도록 개선하고, `auto`, `title`, `first-interactive` focus preset을 추가합니다. modeless FloatingWindow는 열릴 때 현재 focus를 유지합니다.

  Migration Notes:
  - 기본 Modal/ModalWindow 초기 focus가 Header close button에서 title로 변경됩니다. 첫 tabbable 요소가 필요한 경우 `initialFocus="first-interactive"`를 지정하세요.
  - `initialFocus="content"`는 호환용으로 유지되지만 신규 구현은 `title` 또는 구체적인 ref/function을 우선하세요.

- 0f92eea: trigger/명시적 anchor 기준 collision-aware 배치, 자유 drag 전환, viewport 경계 보정을 지원하는 `FloatingWindow`와 동일 geometry에 Modal 기본 presentation, popup scale/fade motion 및 focus trap을 연결하는 `ModalWindowRoot`를 추가합니다. ModalWindow backdrop은 기본적으로 표시하지 않으며 명시적으로 활성화할 수 있습니다.

  Migration Notes:
  - 없음

- a94819d: 다중 FloatingWindow의 등록, 활성화 순서, modality 우선순위, 최상단 dismissal과 modal focus handoff를 조정하는 `FloatingWindowManager`를 추가합니다.

  FloatingWindow의 modeless와 modal Root가 동일한 Modal popup surface 진입·종료 모션을 사용하도록 motion ownership을 surface로 일원화하고, Header와 NavigationSection을 대체형 top chrome 계약으로 명확히 합니다.

  `ModalWindowRoot`는 Modal과 동일하게 backdrop을 기본 표시해 배경 pointer 입력을 차단합니다.

  비활성 modeless window의 Close는 창을 최상단으로 올리지 않고 기존 stack 위치에서 종료 모션을 실행합니다.

  FloatingWindowContent에 Modal과 동일한 `resize="fixed"` surface와 body scroll state 연동을 추가하고, Footer의 ActionArea 조합이 scroll 경계에 맞춰 동작하도록 개선합니다.

  Migration Notes:
  - 다중 창을 사용할 때 `FloatingWindowManager`로 root들을 감싸고 각 root에 고유한 `windowId`를 지정합니다.
  - `FloatingWindowHeader`와 `FloatingWindowNavigationSection`은 함께 사용하지 않고 필요한 top chrome 하나를 선택합니다.
  - 단일 창과 Manager 밖의 기존 사용법은 변경되지 않습니다.

### Patch Changes

- 95cca4e: motion duration 또는 duration factor가 `0`일 때 Accordion과 Modal의 런타임 spring을 시작하지 않고 최종 상태로 즉시 완료하도록 수정합니다. 음수, 비유한 값, 잘못된 CSS multiplier 형식은 runtime 설정 오류로 명확히 거부합니다.
- 3582939: Modal surface가 header의 overlay positioning과 stacking을 명시적으로 소유하도록 우선순위를 보강해, CSS Module 주입 순서와 무관하게 FloatingWindow의 header, body, footer가 같은 열에 정렬되고 header drag가 유지되도록 수정합니다.

  FloatingWindowClose에 custom render 구성을 추가해 ActionArea 같은 임의의 버튼도 Root의 기본 dismiss 및 exit lifecycle을 유지하며 창을 닫을 수 있습니다.

  Migration Notes:
  - 없음

### Migration Notes

- 기본 Modal/ModalWindow 초기 focus가 Header close button에서 title로 변경됩니다. 첫 tabbable 요소가 필요한 경우 `initialFocus="first-interactive"`를 지정하세요.
- `initialFocus="content"`는 호환용으로 유지되지만 신규 구현은 `title` 또는 구체적인 ref/function을 우선하세요.
- 다중 창을 사용할 때 `FloatingWindowManager`로 root들을 감싸고 각 root에 고유한 `windowId`를 지정합니다.
- `FloatingWindowHeader`와 `FloatingWindowNavigationSection`은 함께 사용하지 않고 필요한 top chrome 하나를 선택합니다.
- 단일 창과 Manager 밖의 기존 사용법은 변경되지 않습니다.

## 1.13.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.12.2..HEAD`_

#### Other

- `c35682c` npm 패키지 리소스 링크 자동화 (#230)
- `a120226` Badge size 명명 표준화 (#231)
<!-- generated:end -->

### Minor Changes

- a120226: Badge의 작은 named size를 표준 size scale에 맞춰 `tiny`에서 `xsmall`로 정규화하고 TypeScript prop, 런타임 class, `data-oc-size` selector 계약을 일치시킵니다.

  Migration Notes
  - `<Badge size='tiny'>`를 `<Badge size='xsmall'>`로 변경
  - `[data-oc-component='badge'][data-oc-size='tiny']` selector를 `[data-oc-component='badge'][data-oc-size='xsmall']`로 변경

### Patch Changes

- c35682c: npm package README에서 공개 Storybook, 버전 고정 Changelog, UI Documentation, 의견 전달 경로를 바로 확인할 수 있도록 추가하고, 릴리즈 버전 변경 시 UI와 Icons의 jsDelivr 리소스 URL을 각 package manifest 버전에 맞춰 자동 갱신·검증합니다. publish 직전에는 README가 가리키는 리소스가 실제 tarball에 포함되는지 확인하고, Storybook 빌드에서는 README deep-link의 story ID를 검증합니다.

  Migration Notes
  - 없음

- Updated dependencies [c35682c]
  - @orioncactuscorp/icons@1.13.0

### Migration Notes

- `<Badge size='tiny'>`를 `<Badge size='xsmall'>`로 변경
- `[data-oc-component='badge'][data-oc-size='tiny']` selector를 `[data-oc-component='badge'][data-oc-size='xsmall']`로 변경

## 1.12.2

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.12.1..HEAD`_

#### Documentation

- `d8eb4eb` docs(release): document icon version alignment (#228)

#### Other

- `e442fed` npm 패키지 릴리즈 노트 포함 (#227)
<!-- generated:end -->

### Patch Changes

- e442fed: npm package tarball에 누적 릴리즈 노트인 `CHANGELOG.md`를 포함하고, publish 전에 실제 pack 결과를 검증합니다.

  Migration Notes
  - 없음

- Updated dependencies [e442fed]
  - @orioncactuscorp/icons@1.12.2

### Migration Notes

- 없음

## 1.12.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.12.0..HEAD`_

#### Other

- `7315336` Storybook Foundation 레퍼런스 개선 (#220)
- `395c06e` Interaction radius 전달 방식 일원화 (#221)
- `8ea0a4d` 컴포넌트 prop 명명 계약 문서화 (#223)
- `268a64c` 컴포넌트 API 명명 컨벤션 공개 문서화 (#225)
<!-- generated:end -->

### Patch Changes

- 268a64c: `variant`, `appearance`, `size` prop의 역할과 명명 규칙을 설명하는 공개 API 컨벤션 문서를 추가합니다.

### Migration Notes

- 없음

## 1.12.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.11.0..HEAD`_

#### Maintenance

- `561a104` chore(deps): bump actions/setup-node from 6.4.0 to 7.0.0 (#208)
- `93a65e7` build(ui): exclude story helpers from declarations

#### Other

- `b13d6a9` npm 패키지 페이지 문서 링크 깨짐 수정 (#209)
- `104c187` 명시적 light theme cascade 우선순위 수정 (#213)
- `9c945d5` 네이티브 UI 테마 일치 (#214)
- `45b3453` 색상·타이포그래피 Foundation 문서화 (#216)
- `555f73a` Tooltip·ScrollArea z-index 계약 수정 (#217)
- `f80506b` Foundation reference 스토리 시각 마감 보강 (#218)
<!-- generated:end -->

### Minor Changes

- 9c945d5: light/dark 테마 범위에 `color-scheme`을 선언해 네이티브 브라우저 UI를 테마와 일치

  Migration Notes: dark 테마에서 네이티브 form control, scrollbar 등 브라우저 UI가 dark color scheme으로 렌더링됨. 기존 light 렌더링을 유지해야 하는 소비자는 package CSS import 이후 해당 범위의 `color-scheme`을 override해야 함

### Patch Changes

- 45b3453: semantic color와 typography foundation의 역할 가이드, light/dark·responsive 기본값 표, Storybook 전체 token matrix 추가

  Migration Notes: 런타임 token과 컴포넌트 API 변경 없음. 기존 consumer는 변경 없이 업데이트할 수 있으며, 새 문서에서 theme·typography override 경로를 확인할 수 있음

- 104c187: OS dark mode에서 명시적 light theme가 system preference에 덮이던 문제 수정

  Migration Notes: `<html data-theme="light">`처럼 light theme를 명시한 소비자는 업데이트 후 OS 설정과 무관하게 의도한 light token이 적용됨

- 555f73a: Tooltip과 ScrollArea가 정의되지 않은 `--oc-z-index-floating` 변수에 의존하던 문제를 수정합니다.

  Migration Notes
  - Tooltip은 기본적으로 Modal보다 높은 `--oc-zindex-5` 레이어에 렌더링됩니다.
  - 특수 stacking context에서 Tooltip layer 조정이 필요하면 `--oc-tooltip-z-index`를 사용합니다.
  - ScrollArea scrollbar는 외부 floating layer가 아닌 ScrollArea 내부 로컬 stacking context에 유지됩니다.

- b13d6a9: npm 패키지 페이지에서 깨지던 README 문서 링크 수정
  - README의 `docs/` 상대 링크 15개를 버전 고정 jsDelivr 절대 URL(`https://cdn.jsdelivr.net/npm/@orioncactuscorp/ui@<version>/docs/*.md`)로 교체. npm 패키지 페이지는 README만 렌더링하고 tarball 내부 파일 경로를 해석하지 못해, 기존 상대 링크가 `https://www.npmjs.com/package/@orioncactuscorp/docs/*.md`로 잘못 풀리며 깨져 있었음
  - Documentation 섹션의 웹 열람 안내를 unpkg에서 jsDelivr로 통일
  - 링크 버전은 `bun run agent:sync-version`이 릴리스마다 stamp하고 `agent:check-version`이 릴리스 게이트에서 검증
  - 런타임 코드 변경 없음

### Migration Notes

- dark 테마에서 네이티브 form control, scrollbar 등 브라우저 UI가 dark color scheme으로 렌더링됩니다. 기존 light 렌더링을 유지해야 하는 소비자는 package CSS import 이후 해당 범위의 `color-scheme`을 override하세요.
- `<html data-theme="light">`처럼 light theme를 명시한 소비자는 업데이트 후 OS 설정과 무관하게 의도한 light token이 적용됩니다.
- Tooltip은 기본적으로 Modal보다 높은 `--oc-zindex-5` 레이어에 렌더링됩니다.
- 특수 stacking context에서 Tooltip layer 조정이 필요하면 `--oc-tooltip-z-index`를 사용하세요.
- ScrollArea scrollbar는 외부 floating layer가 아닌 ScrollArea 내부 로컬 stacking context에 유지됩니다.
- 런타임 token과 컴포넌트 API 변경 없음. 기존 consumer는 변경 없이 업데이트할 수 있으며, 새 문서에서 theme·typography override 경로를 확인할 수 있습니다.

## 1.11.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.10.0..HEAD`_

#### Other

- `5ee56c3` Popup 콘텐츠 전환의 자체 애니메이션 콘텐츠 경쟁 수정 (#193)
- `06a0fc5` 소비자 문서 패키지 동봉 및 README 문서 허브화 (#195)
- `909c113` 토큰 인덱스 생성기 추출 로직 공용화 및 단위 테스트 추가 (#196)
- `417e28b` 미테스트 컴포넌트 테스트 보강 및 onCheckedChange 계약 고정 (#197)
- `54c51bf` ref 병합 로직 공유 유틸(mergeRefs)로 통합 (#198)
- `eb69148` 복합 위젯 키보드 APG 동작 테스트 추가 (#199)
- `1eb5ffb` focus-ring 토큰 도입 및 :focus-visible 표현 중앙집중화 (#200)
- `dcc2791` Tabs 컴포넌트 추가 (#204)
- `8ace1d4` foundations.css + per-component 주입 권장화 (#205)
- `da890ab` Modal snap 테스트 안정화 (#206)
<!-- generated:end -->

### Minor Changes

- 1eb5ffb: 키보드 포커스 ring foundation 도입 및 :focus-visible 표현 중앙집중화
  - 신규 public 토큰: `--oc-focus-ring-width`(2px), `--oc-focus-ring-offset`(2px), `--oc-color-theme-focus-ring`(기본 `--oc-color-theme-primary-normal` alias, light/dark 대응)
  - 신규 SCSS 믹스인 `oc-focus-ring` (`@orioncactuscorp/ui/scss/mixins/focus`)
  - reset 레이어가 `button`, `a[href]`, `summary`, `[tabindex]`의 `:focus-visible`에 ring을 전역 기본값으로 제공 (기존: `button:focus-visible { outline: none }`으로 전역 제거)
  - 모든 focusable 컴포넌트(버튼류, Cell, Menu, Accordion, Tooltip trigger, Modal 내비게이션)가 키보드 포커스 시 ring 표시. Interaction tint(면 피드백)는 보조로 유지
  - 선택 컨트롤(Checkbox/Radio/Switch/CheckMark)의 하드코딩 outline을 토큰 경유로 교체 (시각 결과 동일)
  - Field 계열(TextInput/TextArea/Select)은 기존 `:focus-within` border 강조 유지, Modal surface/Menu popup 같은 프로그램 포커스 표면은 ring 미적용
  - ring은 `outline` 기반이라 요소 border-radius를 자동 추종하고 forced-colors(고대비) 모드에서도 유지됨

  Migration Notes
  - 기존 reset의 outline 제거에 의존하던 소비자 UI는 키보드 포커스 시 ring이 새로 표시됩니다 (포인터 인터랙션은 변화 없음). 특정 요소에서 원치 않으면 해당 요소에 `outline: none`을 선언하세요 — 전역 규칙은 `:where()`(specificity 0)라 어떤 로컬 선언이든 우선합니다.
  - ring 색/두께는 `--oc-color-theme-focus-ring`, `--oc-focus-ring-width`, `--oc-focus-ring-offset` override로 리테마할 수 있습니다.
  - `all: unset`을 사용하는 focusable 요소는 전역 ring도 함께 제거되므로 `@include oc-focus-ring`으로 재적용이 필요합니다.

- dcc2791: Tabs 컴포넌트 추가
  - `TabsRoot`, `TabsList`, `TabsTab`, `TabsPanel` compound API 추가
  - controlled/uncontrolled 선택, 자동·수동 키보드 활성화, RTL, disabled, keep-mounted panel 지원
  - size, full-width, logical padding, trailing slot, indicator, overflow edge fade 커스터마이즈 계약 추가
  - tab 상하 padding을 large/medium은 `--oc-space-item-padding-mini`, small은 `--oc-space-item-padding-tiny`에 매핑
  - tab inline padding을 Interaction의 외부 확장으로 전환하고 확장값 2배의 gap 적용
  - 외부 Interaction을 pointer hit area로 사용하고 `padding=true`에서 viewport 좌우 여백 적용
  - Interaction 배경을 transparent로 유지해 label 색 기반 상태 피드백 제공
  - indicator에 max radius 기본값과 `--oc-tabs-indicator-radius` 재정의 계약 추가
  - `TabsList` typography를 large `headline2`, medium `body1`, small `body2` bold로 매핑하고 각 tab item의 상속·소비자 CSS 재정의 지원
  - overflow edge mask가 부드럽게 나타나고 사라지는 transition 추가
  - 선택 tab을 edge mask 안쪽으로 스크롤하고 reduced motion에서는 smooth scroll 제거
  - tab 관계와 키보드 탐색에 필요한 ARIA, role, panel id/hidden 속성 보호

  Migration Notes
  - 없음

### Patch Changes

- 06a0fc5: 소비자 문서를 npm 패키지에 동봉하고 README를 문서 허브로 재구성
  - `docs/`를 패키지 `files`에 추가: selector contract 공개본, SCSS helpers 가이드(`oc-border` 전체 시그니처, `oc-alpha`, `typo`, `respond-to`, `fluidClamp`), semantic motion/spring 가이드, responsive foundation profile, `--oc-*` token reference(자동 생성), stability policy, editor setup
  - README에 Documentation 색인, Customization(`data-oc-*`) 섹션, 브라우저 지원 기준(`color-mix()` 기준선), Exports 설명 표(`foundations/*.css`, `utils/breakpoints`, `scss/index.scss` 문서화) 추가
  - 런타임 코드 변경 없음

  Migration Notes
  - 없음

- 8ace1d4: CSS 소비 경로 정리 — `foundations.css` + per-component 자동 주입을 기본 경로로 문서화
  - 권장 경로를 `foundations.css`(토큰 + reset) 1회 import + 컴포넌트 자동 주입으로 재정의. 사용한 컴포넌트 CSS만 로드되어 styles.css 전량 import 대비 번들 절감(examples/nextjs 실측 −57%)
  - `styles.css`는 "CSS Modules 번들러가 없는 환경"용 단일 파일 대안으로 강등 문서화. `styles.css`에는 파운데이션이 내장되어 있어 `foundations.css`와 병행 import하면 이중 로드됨을 명시
  - per-component 주입 무결성을 지키는 빌드 후 검사(`check:css-injection`) 추가: 모든 컴포넌트 chunk가 자기 CSS를 주입하고 고아 CSS가 없음을 보장

  Migration Notes
  - 기존 `styles.css` import 경로는 계속 동작합니다. breaking change 아님
  - 컴포넌트 자동 주입은 CSS Modules를 처리하는 번들러(Next.js, Vite 등)를 전제로 합니다. 해당 환경이 아니면 `styles.css`를 사용하세요
  - 주입되는 컴포넌트 CSS는 cascade layer 밖(unlayered)입니다. `[data-oc-*]` selector로 개별 property를 override할 때는 selector contract대로 consumer CSS가 컴포넌트 CSS보다 나중에 로드되도록 유지하세요(`--oc-*` 변수 override는 로드 순서와 무관하게 동작)

- 54c51bf: ref 병합 로직을 공유 유틸(mergeRefs)로 통합하고 React 19 callback-ref cleanup 지원
  - 10개 파일에 중복되던 인라인 ref 병합 로직을 내부 `mergeRefs` 유틸로 통합 (public export 아님)
  - ref를 받는 컴포넌트(TextInput, TextArea, Select, Checkbox, Cell, Accordion, ActionAreaLayout, ScrollArea, Modal 하위 slot, MotionExpand)에 소비자가 cleanup을 반환하는 callback ref를 전달하면 이제 React 19 시맨틱대로 detach 시 cleanup이 호출됨 (기존: cleanup이 무시되고 null로 재호출)
  - cleanup을 반환하지 않는 callback ref와 object ref의 동작은 기존과 동일

  Migration Notes
  - 없음

- 5ee56c3: Popup(`resize='content'`)에서 NavigationSection을 접거나 펼칠 때 surface 높이가 조금만 움직이다가 전환이 끝나는 순간 실제 높이로 낙하하던 문제를 수정합니다. 콘텐츠 블록 전환 훅이 불연속 스왑을 전제로 첫 프레임의 비행 중인 중간 높이를 목표로 고정하고 이후 변화를 잠갔던 것이 원인입니다. 이제 ResizeObserver 전달 시점과 다음 프레임 사이에 크기가 계속 움직이는 자체 애니메이션 콘텐츠(예: NavigationSection의 expand motion)를 감지하면 개입하지 않고 자연 추종하며, 한 번에 바뀌는 불연속 콘텐츠 교체는 기존대로 부드럽게 전환합니다.

  Migration Notes
  - 없음

### Migration Notes

- 기존 reset의 outline 제거에 의존하던 소비자 UI는 키보드 포커스 시 ring이 새로 표시됩니다 (포인터 인터랙션은 변화 없음). 특정 요소에서 원치 않으면 해당 요소에 `outline: none`을 선언하세요 — 전역 규칙은 `:where()`(specificity 0)라 어떤 로컬 선언이든 우선합니다.
- ring 색/두께는 `--oc-color-theme-focus-ring`, `--oc-focus-ring-width`, `--oc-focus-ring-offset` override로 리테마할 수 있습니다.
- `all: unset`을 사용하는 focusable 요소는 전역 ring도 함께 제거되므로 `@include oc-focus-ring`으로 재적용이 필요합니다.
- 기존 `styles.css` import 경로는 계속 동작합니다. breaking change 아님
- 컴포넌트 자동 주입은 CSS Modules를 처리하는 번들러(Next.js, Vite 등)를 전제로 합니다. 해당 환경이 아니면 `styles.css`를 사용하세요
- 주입되는 컴포넌트 CSS는 cascade layer 밖(unlayered)입니다. `[data-oc-*]` selector로 개별 property를 override할 때는 selector contract대로 consumer CSS가 컴포넌트 CSS보다 나중에 로드되도록 유지하세요(`--oc-*` 변수 override는 로드 순서와 무관하게 동작)

## 1.10.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.9.2..HEAD`_

#### Breaking Changes

- `80bb9d0` Bottom sheet backdrop을 snap 임계 기반 modality로 재정의 (#191)

#### Other

- `a63b87e` 콘텐츠 높이 전환 중 footer 위치·scroll 배경 안정화 (#190)
<!-- generated:end -->

### Minor Changes

- 80bb9d0: Bottom sheet의 backdrop을 modality 신호로 재정의합니다. iOS `largestUndimmedDetentIdentifier` 모델을 따라, 안착 snap 기준 이진(dim 0 또는 1) 상태와 경계 구간 보간으로 동작합니다.
  - `ModalContent`에 `backdropFrom?: ModalSnapPoint` prop을 추가합니다. 지정한 snap 미만의 detent에 안착하면 backdrop이 없고 non-modal(배경 상호작용 가능, 포커스 트랩 해제, backdrop pointer 통과)이며, 해당 snap 이상 detent에 안착하면 완전한 dim과 modal 상태가 됩니다. backdrop opacity는 가장 큰 undimmed snap과 `backdropFrom` snap 사이를 이동하는 동안에만 보간됩니다. 값은 `snapPoints` 멤버여야 하며 아니면 개발 모드 경고와 함께 무시됩니다.
  - dim 상태에서 backdrop을 탭하면 dismiss가 불가하거나 peek로 접히던 시트는 가장 큰 undimmed snap으로 collapse합니다. dismiss 가능한 비peekable 시트는 기존대로 dismiss합니다.
  - non-modal 안착 상태의 backdrop 레이어는 `data-oc-modal-backdrop-passthrough="true"`를 노출합니다.
  - elevation shadow는 dimmer의 보완 관계(`shadow = 1 − dim`)를 모든 상태에서 유지합니다. dim이 있는 안착에서는 shadow가 없고, undimmed 안착(non-modal)에서는 shadow가 시트를 배경과 분리하며, 경계 구간 이동 중에는 둘이 크로스페이드됩니다.
  - `snapPoints`가 있고 `backdropFrom`이 없는 경우의 기본 동작이 변경됩니다: 기존에는 backdrop opacity가 시트 가시 높이에 비례했지만, 이제 모든 snap detent에서 1로 유지되고 최저 snap 아래 진입/이탈/peek 구간에서만 페이드됩니다.

  Migration Notes
  - `snapPoints`를 사용하는 bottom sheet의 중간 snap에서 backdrop이 부분 투명(가시 높이 비례)이던 동작이 제거되고 모든 snap에서 완전한 dim(1)이 됩니다. 이전처럼 낮은 snap에서 배경을 덜 가리려면 `backdropFrom`으로 dim이 시작될 snap을 지정하세요. 예: `snapPoints={[0.36, 0.72, 0.92]} backdropFrom={0.92}`.
  - `backdropFrom` 미만 snap에 안착한 시트는 non-modal로 전환되어 포커스 트랩이 해제되고 배경이 상호작용 가능해집니다. 배경 클릭이 시트를 닫지 않으므로(outside-press 무시), 이 상태에서 닫기가 필요하면 명시적 닫기 UI를 제공하세요.

### Patch Changes

- a63b87e: Bottom sheet 콘텐츠 높이 전환(depth/탭 이동) 중 footer(ActionArea)가 한 프레임에 아래로 튕겼다가 스프링으로 복귀하거나(확장), 내려갔다가 커밋 시점에 위로 스냅되던(축소) 문제를 수정합니다. 단일 축 canvas 전환은 시트 상단 연속성만 보장하고 surface 물리 하단은 live translate를 따라 움직이는데, footer가 물리 하단에 고정되어 있어 전환 내내 함께 흔들렸습니다. 이제 canvas settle 동안 `data-oc-modal-sheet-resizing` 상태로 footer를 시트의 보이는 하단(커밋 후 안착 지점)에 앵커해 매 스프링 프레임 제자리에 유지합니다.

  Migration Notes
  - 없음

- a63b87e: Bottom sheet 콘텐츠 높이 전환(depth/탭 이동) 중 footer(ActionArea)의 scroll 배경 gradient가 잠깐 나타났다가 사라지던 깜빡임을 수정합니다. 전환 동안 scrollport가 프레임 단위로 이전 크기에서 목표 크기로 움직이는 사이, 이미 최종 크기로 스왑된 콘텐츠와 비교되어 "일시적으로 스크롤 가능" 상태가 잘못 보고되던 문제입니다. 이제 canvas settle 동안 스크롤 상태를 목적지 scrollport 높이와 콘텐츠 실측 높이 기준으로 평가해 최종 상태와 일치시키고, settle 중의 과도 상태 보정은 opacity 전환 없이 스냅되어 화면에 드러나지 않습니다. 실제로 스크롤이 필요한 목적지에서는 gradient가 기존 scale 전환으로 부드럽게 등장합니다.

  Migration Notes
  - 없음

### Migration Notes

- `snapPoints`를 사용하는 bottom sheet의 중간 snap에서 backdrop이 부분 투명(가시 높이 비례)이던 동작이 제거되고 모든 snap에서 완전한 dim(1)이 됩니다. 이전처럼 낮은 snap에서 배경을 덜 가리려면 `backdropFrom`으로 dim이 시작될 snap을 지정하세요. 예: `snapPoints={[0.36, 0.72, 0.92]} backdropFrom={0.92}`.
- `backdropFrom` 미만 snap에 안착한 시트는 non-modal로 전환되어 포커스 트랩이 해제되고 배경이 상호작용 가능해집니다. 배경 클릭이 시트를 닫지 않으므로(outside-press 무시), 이 상태에서 닫기가 필요하면 명시적 닫기 UI를 제공하세요.

## 1.9.2

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.9.1..HEAD`_

#### Other

- `4acf4e8` Modal size padding 변수 추가 (#188)
<!-- generated:end -->

### Patch Changes

- 4acf4e8: Modal size별 width와 padding CSS 변수를 추가하고, header/body/footer padding이 container padding contract를 기본으로 공유하도록 개선합니다.

  Migration Notes
  - 없음

### Migration Notes

- 없음

## 1.9.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.9.0..HEAD`_

#### Fixes

- `7481fe6` fix(modal): arbitrate mouse body drags against text selection (#185)
- `5254c1e` fix(modal): sync settle scrollport to the sheet frame by frame (#186)

#### Other

- `0018769` Bottom sheet 콘텐츠 전환 단일 축 재구성 (#184)
<!-- generated:end -->

### Patch Changes

- 7481fe6: Bottom sheet 본문을 마우스로 드래그할 때 텍스트 선택과 시트 조작을 중재합니다. 기존에는 본문 마우스 드래그가 시트를 움직이지 않고 브라우저 텍스트 선택으로 흘러, 위로 끌면 선택 오토스크롤이 본문 스크롤 위치를 맨 위로 되감는 문제가 있었습니다. 이제 제스처가 명확히 수직(12px 이상, 수직 우세)이면 시트 드래그로 승격하고, 수평 우세면 텍스트 선택에 양보합니다. 드래그 시작 시점에 이미 활성 선택이 있으면 기존처럼 선택 조작을 보호합니다.

  Migration Notes
  - 없음

- 5254c1e: Bottom sheet를 드래그 후 릴리즈해 위 snap으로 안착할 때 본문 스크롤이 한 프레임에 확 당겨지던 문제를 수정합니다. 릴리즈 settle이 visible scrollport를 목표 크기로 즉시 고정해 시트가 시각적으로 도착하기 전에 브라우저 스크롤 클램프가 발생했습니다. 이제 릴리즈/스냅 settle은 드래그와 동일하게 scrollport를 스프링 프레임마다 시트에 동기하고, entrance settle만 기존처럼 목표를 미리 고정해 footer 스크롤 상태 깜빡임을 방지합니다.

  Migration Notes
  - 없음

- 0018769: Bottom sheet의 콘텐츠 높이 전환을 단일 축으로 재구성합니다. 기존에는 height transition(메인 스레드)과 transform transition(컴포지터)을 함께 애니메이션해 메인 스레드 부하 시 두 클럭이 어긋나며 시트가 흔들렸습니다. 이제 전환 동안 surface를 두 크기를 모두 덮는 canvas 높이에 고정하고 translate 하나만 스프링으로 움직인 뒤, 도착 프레임에서 실제 높이로 교체(화면 밖 영역이라 시각적 no-op)합니다. inline height 소유권을 drag hook으로 단일화해 React 렌더 커밋이 보상 프레임보다 먼저 높이를 페인트하던 문제도 함께 제거했습니다.

  Migration Notes
  - 없음

### Migration Notes

- 없음

## 1.9.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.8.0..HEAD`_

#### Other

- `d3edc13` Border와 버튼 sizing contract 확장 (#154)
- `600c887` 릴리스 문서화와 버전 일관성 CI 게이트 추가 (#156)
- `0e3af18` Modal BottomSheet 안착 스크롤포트 안정화 (#157)
- `eed2a62` PR CI 경량화(webkit 스코프 축소·문서 변경 스킵) (#158)
<!-- generated:end -->

### Minor Changes

- 0e3af18: `ModalContent`에 콘텐츠 교체 시 surface 높이 변화를 전환하는 `contentTransition` contract를 추가합니다. 기본값 `auto`는 content-resize popup/bottom sheet에서 depth navigation처럼 본문이 바뀌는 경우 높이 변화를 부드럽게 처리하고, snap이 있는 bottom sheet는 snap geometry가 높이 전환을 계속 소유합니다.

  Bottom sheet는 콘텐츠 높이 변경이나 viewport resize 이후에도 마지막 rest state를 의미 단위(default snap, 특정 snap, expanded, custom)로 보존하도록 개선합니다. 짧은 탭에서 긴 탭으로 바로 이동해도 사용자가 확장하지 않았다면 1차 snap에 머무릅니다.

  Migration Notes
  - `ModalContent`의 `contentTransition` 기본값은 `auto`입니다. 콘텐츠 교체 시 높이 전환이 필요 없거나 자체 animation을 사용하는 경우 `contentTransition="none"`을 지정하세요.

- 0e3af18: `ModalContent`에 `snapPoints`를 줄 때 `resize='content'`(기본)이면 시트가 콘텐츠 높이에 맞춰 hug하면서 snap 지점을 detent로 사용하도록 개선합니다. 콘텐츠가 가장 작은 snap보다 짧으면 그 높이로 hug하고, 길면 `defaultSnapPoint`에서 열린 뒤 handle을 끌어 상위 snap으로 확장하며 본문을 스크롤합니다. 시트를 항상 가장 큰 snap 높이로 고정하려면 `resize='fixed'`를 사용합니다.

  Migration Notes
  - `snapPoints` + `resize='content'`(기본)에서 시트 높이가 "항상 최대 snap 고정"에서 content-hug로 바뀝니다. 기존처럼 최대 snap 높이로 고정하려면 `resize='fixed'`로 전환하세요.

### Patch Changes

- 0e3af18: Modal bottom sheet의 content height transition을 sheet geometry 레이어에서 처리하도록 개선합니다.

  Migration Notes:
  - 없음

- 0e3af18: BottomSheet가 확장 상태에서 peeked 상태로 안착하는 동안 visible scrollport가 먼저 줄어들지 않도록 수정합니다.

  Migration Notes:
  - `Modal` BottomSheet의 settle transition 중 body scrollport는 도착 전까지 현재 보이는 영역을 유지합니다.
  - 추가 마이그레이션은 필요하지 않습니다.

- 0e3af18: Bottom sheet의 1차 snap 상태에서 Modal body scrollport를 실제로 보이는 sheet 높이에 맞추고, viewport 높이 변경 시 snap metric과 expanded 상태를 안정적으로 보존하도록 개선합니다.

  ScrollArea가 애니메이션 중인 scrollport와 track geometry를 안정적으로 재측정해, 콘텐츠 전환 직후에도 scrollbar thumb 크기를 실제 viewport에 맞게 갱신합니다.

- 0e3af18: `ModalHeader`에 tab/버튼처럼 한 줄보다 큰 커스텀 콘텐츠를 넣어 헤더가 기본 한 줄(`2rem` row) 높이보다 커질 때, body가 정적 예약 높이(`2rem + padding`)만 확보해 콘텐츠 상단이 헤더에 가려지던 문제를 수정합니다. 측정된 실제 헤더 높이(`--oc-modal-header-height`)를 surface에 반영해 body 예약 공간이 헤더 높이를 따라가도록 합니다.

  Migration Notes
  - 없음

- 0e3af18: `ModalContent`의 `backdrop="hidden"` 상태에서 dimmer/backdrop 레이어를 최종 제거하고, visible/compact에서 hidden으로 바뀔 때는 opacity exit transition을 유지하도록 수정합니다.

  Migration Notes:
  - `data-oc-modal-backdrop="hidden"` 상태는 `modal-content`에 유지되며, settled hidden 상태에서는 `data-oc-component="modal-backdrop"` 요소가 렌더링되지 않습니다.
  - visible/compact에서 hidden으로 전환되는 동안에는 `data-oc-component="modal-backdrop"` 요소가 opacity transition 종료 시점까지 임시 유지될 수 있습니다.
  - hidden backdrop 상태의 모달 그림자는 backdrop opacity와 연동해 fade되지 않고 surface elevation으로 유지됩니다.
  - hidden backdrop 요소에 의존한 스타일, 레이아웃, hit test 커스터마이징은 `modal-content` 또는 `surface` 레이어 기준으로 이전해야 합니다.

- 0e3af18: BottomSheet를 초기 `peeked` 상태(`presentationState="peeked"` 또는 `defaultPresentationState="peeked"`)로 열 때, mount 시점에 Base UI가 popup ref를 붙이기 전에 entrance settle이 실행되어 시트가 접히지 않고 visible 위치에 그대로 남던 문제를 수정합니다. surface 노드가 마운트되면 entrance settle이 다시 실행되어 navigation만 걸친 docked panel이 정상적으로 표시됩니다.

  Migration Notes
  - 없음

- 0e3af18: Bottom Modal의 content-hug snap 높이 변경 시 sheet height와 translate 기준을 동기화해 탭 전환 중 튀거나 접히는 전환을 방지하고, height transition을 추가합니다. 부분 snap 상태에서는 터치 본문 제스처가 내부 스크롤보다 sheet 확장을 먼저 처리하도록 조정하고, `ScrollArea` thumb가 viewport 크기 변화에 맞춰 다시 계산되도록 개선합니다.

  Migration Notes
  - 없음

- d3edc13: `oc-border` mixin이 `1px solid top outer var(--stroke)` 같은 CSS-like shorthand를 지원하도록 확장하고, Button/TextButton/Accordion/Modal의 아이콘 sizing을 `oc-icon-box` mixin으로 통일합니다.

  Migration Notes
  - `oc-border`의 기존 호출 방식은 유지됩니다.
  - 아이콘 sizing이 `oc-icon-box` mixin으로 통일됩니다. `block-size`만 line box(`1lh`) 기준으로 잡고 `inline-size: auto`로 두어 SVG viewBox 비율을 보존합니다. 정사각으로 강제되던 비정사각 아이콘은 이제 원본 비율로 렌더링됩니다.
  - `--oc-*-icon-size` 직접 override는 유지되며, 의미가 "정사각 박스 크기"에서 "아이콘 높이(너비는 viewBox 비율로 결정)"로 바뀝니다. `--oc-*-icon-padding-block`으로 line box에서 뺄 여백을 조정할 수 있습니다.
  - Accordion/Modal disclosure indicator의 `*-size-reduction` contract는 `*-padding-block`으로 대체됩니다.
  - Button/TextButton/Accordion/Modal의 기본 아이콘 렌더링 크기는 유지됩니다(모던 브라우저 기준 ±1px 이내).
  - `1lh` 미지원(pre-2023) 브라우저 fallback은 `--oc-*-icon-padding-block` 기반 `1.5em - padding-block*2`로 자동 근사되며, 모던 브라우저 결과에는 영향이 없습니다.

- 0e3af18: `ScrollArea` scrollbar 위치를 조정할 수 있는 inset CSS 변수 contract를 추가합니다. `Modal` bottom sheet는 이 contract를 사용해 부분 snap 상태의 visible 영역에 맞춰 scrollbar track 높이를 조정합니다.

  Migration Notes
  - 없음

### Migration Notes

- `ModalContent`의 `contentTransition` 기본값은 `auto`입니다. 콘텐츠 교체 시 높이 전환이 필요 없거나 자체 animation을 사용하는 경우 `contentTransition="none"`을 지정하세요.
- `snapPoints` + `resize='content'`(기본)에서 시트 높이가 "항상 최대 snap 고정"에서 content-hug로 바뀝니다. 기존처럼 최대 snap 높이로 고정하려면 `resize='fixed'`로 전환하세요.
- `data-oc-modal-backdrop="hidden"` 상태는 `modal-content`에 유지되며, settled hidden 상태에서는 `data-oc-component="modal-backdrop"` 요소가 렌더링되지 않습니다. hidden backdrop 요소에 의존한 스타일, 레이아웃, hit test 커스터마이징은 `modal-content` 또는 `surface` 레이어 기준으로 이전해야 합니다.
- 아이콘 sizing이 `oc-icon-box` mixin으로 통일됩니다. `--oc-*-icon-size` 직접 override는 유지되지만 의미가 "정사각 박스 크기"에서 "아이콘 높이(너비는 viewBox 비율로 결정)"로 바뀝니다.
- Accordion/Modal disclosure indicator의 `*-size-reduction` contract는 `*-padding-block`으로 대체됩니다.

## 1.8.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.7.0..HEAD`_

#### Other

- `f5e9a43` 디스클로저 인디케이터 정렬 개선 (#151)
- `0f2414f` Modal 고정 높이와 fill layout 추가 (#152)
<!-- generated:end -->

### Minor Changes

- 0f2414f: Modal의 `resize` 값을 `content | fixed`로 정리하고, `resize="fixed"`에서 `--oc-modal-fixed-block-size`, `--oc-modal-fixed-max-block-size`, `--oc-modal-popup-fixed-max-block-size` CSS 변수로 surface 높이와 popup 상한을 조정할 수 있도록 개선합니다. `ModalBody`에는 `layout="fill"`을 추가해 header/footer reserve를 유지하면서 iframe, 지도, 에디터 같은 임베드 콘텐츠가 남은 body 영역을 채울 수 있도록 지원합니다.

  Migration Notes
  - `ModalContent resize="hug"`를 `resize="content"`로 변경
  - 고정 높이 Modal은 `resize="fixed"`와 `--oc-modal-fixed-block-size` CSS 변수 사용
  - iframe, 지도, 에디터처럼 body 남은 영역을 채워야 하는 콘텐츠는 `ModalBody layout="fill"` 사용

### Patch Changes

- f5e9a43: Accordion과 Modal navigation의 disclosure indicator를 `1lh` frame 안에서 중앙 정렬하도록 개선하고, `--oc-accordion-disclosure-indicator-size`, `--oc-accordion-disclosure-indicator-size-reduction`, `--oc-modal-navigation-indicator-size`, `--oc-modal-navigation-indicator-size-reduction` CSS 변수로 소비자 커스터마이징을 지원합니다. Accordion의 기본 indicator size reduction은 `0.25em`으로 조정합니다.

  Migration Notes
  - 없음

### Migration Notes

- `ModalContent resize="hug"`를 `resize="content"`로 변경
- 고정 높이 Modal은 `resize="fixed"`와 `--oc-modal-fixed-block-size` CSS 변수 사용
- iframe, 지도, 에디터처럼 body 남은 영역을 채워야 하는 콘텐츠는 `ModalBody layout="fill"` 사용

## 1.7.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.6.0..HEAD`_

#### Maintenance

- `3be611c` chore(deps): bump changesets action
- `7c01a10` chore(deps): bump checkout action
- `0bf573e` chore(deps): bump actions/checkout from 6.0.3 to 7.0.0 (#141)

#### Other

- `dd8ac62` Cell·Accordion 구분선 피드백 개선 (#140)
- `310a737` Menu z-index와 placement API 정리 (#142)
- `479eeac` 비활성 버튼 인터랙션 피드백 정리 (#143)
- `8fd7fa2` cssvar 자동완성 설정 문서 보완 (#144)
- `dbe4c71` Skeleton 컴포넌트 추가 (#145)
- `928e01e` cssvar 자동완성 설정 보완 (#146)
- `fcd4576` ambient와 continuous 모션 계약 분리 (#147)
- `299376a` 모달 내비게이션 스냅 및 스크롤 안정화 (#148)
- `bf54089` 논리 방향 contract 정리 (#149)
<!-- generated:end -->

### Minor Changes

- dbe4c71: Skeleton 컴포넌트를 추가합니다.

  Migration Notes
  - 신규 `Skeleton` export를 사용할 수 있습니다.
  - `data-oc-component="skeleton"` 및 `data-oc-part="fill"` selector contract가 추가됩니다.

- bf54089: 방향성 spacing 및 alignment contract를 logical direction 기준으로 정리합니다.

  Migration Notes
  - `ActionArea` CSS 변수명이 logical direction으로 변경됩니다.
    - `--oc-action-area-padding-x` -> `--oc-action-area-padding-inline`
    - `--oc-action-area-padding-y` -> `--oc-action-area-padding-block`
    - `--oc-action-area-padding-top` -> `--oc-action-area-padding-block-start`
    - `--oc-action-area-padding-bottom` -> `--oc-action-area-padding-block-end`
  - `ActionAreaLayout` CSS 변수명이 logical direction으로 변경됩니다.
    - `--oc-action-area-layout-action-area-padding-y` -> `--oc-action-area-layout-action-area-padding-block`
    - `--oc-action-area-layout-body-padding-bottom` -> `--oc-action-area-layout-body-padding-block-end`
  - `Modal` CSS 변수명이 logical direction으로 변경됩니다.
    - `--oc-modal-bottom-top-clearance` -> `--oc-modal-sheet-block-start-clearance`
    - `--oc-modal-padding-x` -> `--oc-modal-padding-inline`
    - `--oc-modal-padding-y` -> `--oc-modal-padding-block`
    - `--oc-modal-header-padding-x` -> `--oc-modal-header-padding-inline`
    - `--oc-modal-header-padding-y` -> `--oc-modal-header-padding-block`
    - `--oc-modal-container-padding-x` -> `--oc-modal-container-padding-inline`
    - `--oc-modal-container-padding-y` -> `--oc-modal-container-padding-block`
    - `--oc-modal-container-padding-top` -> `--oc-modal-container-padding-block-start`
    - `--oc-modal-container-padding-bottom` -> `--oc-modal-container-padding-block-end`
    - `--oc-modal-footer-padding-x` -> `--oc-modal-footer-padding-inline`
    - `--oc-modal-footer-padding-y` -> `--oc-modal-footer-padding-block`
  - safe-area section padding CSS 변수명이 logical direction으로 변경됩니다.
    - `--oc-space-section-padding-viewport-x-safe-left` -> `--oc-space-section-padding-viewport-inline-safe-start`
    - `--oc-space-section-padding-viewport-x-safe-right` -> `--oc-space-section-padding-viewport-inline-safe-end`
    - `--oc-space-section-padding-viewport-y-safe-top` -> `--oc-space-section-padding-viewport-block-safe-start`
    - `--oc-space-section-padding-viewport-y-safe-bottom` -> `--oc-space-section-padding-viewport-block-safe-end`
  - `Skeleton`의 `align` prop 값이 `left`/`right`에서 `start`/`end`로 변경됩니다. `center`는 유지됩니다.

- 299376a: ModalNavigationSection 컴포넌트를 추가합니다.

  Migration Notes
  - 신규 `ModalNavigationSection` export와 `Modal.NavigationSection` compound를 사용할 수 있습니다.
  - `data-oc-component="modal-navigation-section"`, `modal-navigation`, `modal-navigation-panel` selector contract가 추가됩니다.
  - collapsed 상태에서 panel은 `aria-hidden` 및 `inert`로 비활성화됩니다.
  - snapped popup은 `drag="handle"`에서도 handle 기반 9방향 snap을 사용할 수 있습니다.
  - snapped popup drag dismiss는 현재 snap 위치의 top, bottom, center-row 기준을 따릅니다.

### Patch Changes

- fcd4576: ambient motion timing을 ease-in-out로 조정하고 continuous motion intent를 추가합니다.

  Migration Notes
  - `--oc-motion-timing-ambient` 기본값이 `ease-in-out`로 변경됩니다.
  - spinner 회전, progress sweep, marquee처럼 일정 속도 반복이 필요한 motion은 신규 `continuous` intent와 `--oc-motion-duration-continuous`, `--oc-motion-timing-continuous` token을 사용합니다.

- dd8ac62: Cell과 Accordion divider border-color feedback transition을 공통 surface contract로 정리하고, touch active 상태에서도 divider hide feedback이 적용되도록 수정합니다.

  Migration Notes
  - 없음

- dd8ac62: Cell과 Accordion divider border-color feedback duration을 짧게 조정합니다.

  Migration Notes
  - 없음

- 928e01e: VS Code CSS variable 자동완성 설정에서 generated token index 단일 사용, node_modules 기본 ignore 해제, `phoenisx.cssvar` trigger 사용법, completion popup 표시 설정 안내를 추가합니다.

  Migration Notes
  - `phoenisx.cssvar` 확장을 사용하는 consumer는 `.vscode/settings.json`의 `cssvar.files`에 `./node_modules/@orioncactuscorp/ui/dist/vscode/oc-ui-vars.css`를 추가할 때, `cssvar.ignore`에서 `**/node_modules/**` 제외를 제거해야 설치된 oc-ui token index를 읽을 수 있습니다.
  - `@orioncactuscorp/ui/scss/foundations/*` source file은 `color.theme.light.scss`와 `color.theme.dark.scss`처럼 같은 semantic token 이름을 theme별 값으로 다시 선언하므로, 자동완성 설정에는 generated token index만 추가해야 합니다.
  - oc-ui source repository에서는 compiled `styles.css`, `foundations.css`, per-foundation CSS, raw foundation source를 `cssvar.ignore`에 두어 generated token index와 중복 스캔되지 않게 합니다.
  - `phoenisx.cssvar` completion은 빈 CSS value 위치가 아니라 `padding: --` 또는 `padding: var(--`처럼 `--` token을 입력했을 때 표시됩니다.
  - VS Code Insiders 또는 Copilot inline suggestion 환경에서 completion popup 대신 회색 inline suggestion만 보이면 `editor.quickSuggestions`, `editor.suggestOnTriggerCharacters`, `editor.inlineSuggest.suppressSuggestions`를 함께 설정해야 합니다.

- 8fd7fa2: VS Code CSS variable 자동완성 설정 문서를 보완합니다.

  Migration Notes
  - `phoenisx.cssvar` 확장을 사용하는 consumer는 `.vscode/settings.json`의 `cssvar.files`에 `./node_modules/@orioncactuscorp/ui/dist/vscode/oc-ui-vars.css`를 추가하면 설치된 oc-ui 버전의 foundation `--oc-*` token 자동완성을 사용할 수 있습니다.

- 479eeac: IconButton, BackgroundIconButton, TextButton, Badge의 disabled 상태에서 active/focus/hover feedback이 노출되지 않도록 수정하고 disabled 전환을 feedback motion으로 맞춥니다.

  Migration Notes
  - 없음

- 310a737: Menu z-index 기본값을 foundation z-index 토큰으로 정리하고 `placement` 기반 12방향 배치 API를 추가합니다.

  Migration Notes
  - Menu가 더 이상 정의되지 않은 `--oc-z-index-floating` 변수나 숫자 fallback에 의존하지 않습니다.
  - 특수 stacking context에서 Menu layer 조정이 필요하면 `--oc-menu-z-index`를 사용합니다.
  - `MenuContent`의 `placement` prop으로 `topLeft`, `rightTop`, `bottomRight` 등 12방향 선호 배치를 지정할 수 있습니다.

- 299376a: Fixed ModalNavigationSection이 접힐 때 popup surface 높이가 콘텐츠 자연 높이로 커지지 않도록 보정하고, fixed 및 max-height에 닿은 hug 상태에서 panel content가 정상 스크롤되도록 개선합니다. 또한 기본 disclosure indicator를 Accordion과 공통화하고 Safari에서 custom-size SVG가 0 크기로 렌더링되지 않도록 보정합니다. top/bottom popup snap 상태에서는 surface 높이가 바뀌어도 해당 edge를 기준으로 유지되도록 개선합니다. ModalNavigationSection panel scroll 영역은 ModalBody와 동일하게 ScrollArea를 사용하도록 정렬합니다.

  Migration Notes
  - 없음

- 299376a: ModalNavigationSection이 있는 snapped popup의 navigation row drag와 top/bottom collapse anchoring을 보정합니다.

  Migration Notes
  - 없음

### Migration Notes

- `ActionArea`, `ActionAreaLayout`, `Modal`, safe-area section padding CSS 변수명이 logical direction 기준으로 변경됩니다.
- `Skeleton`의 `align` prop 값이 `left`/`right`에서 `start`/`end`로 변경됩니다. `center`는 유지됩니다.
- 신규 `Skeleton`, `ModalNavigationSection`, `Modal.NavigationSection` export를 사용할 수 있습니다.
- `Skeleton`, `ModalNavigationSection` 관련 `data-oc-*` selector contract가 추가됩니다.
- `--oc-motion-timing-ambient` 기본값이 `ease-in-out`로 변경되며, 일정 속도 반복 motion에는 신규 `continuous` intent와 관련 token을 사용합니다.
- Menu가 정의되지 않은 `--oc-z-index-floating` 변수나 숫자 fallback에 의존하지 않습니다. 특수 stacking context 조정은 `--oc-menu-z-index`를 사용합니다.
- `MenuContent`의 `placement` prop으로 12방향 선호 배치를 지정할 수 있습니다.
- VS Code `phoenisx.cssvar` 자동완성 설정에서 generated token index를 사용하고, `cssvar.ignore`의 `**/node_modules/**` 제외를 제거해야 설치된 oc-ui token index를 읽을 수 있습니다.

## 1.6.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.5.1..HEAD`_

#### Breaking Changes

- `7d6e60f` ActionArea footer gradient 개선 (#135)

#### Other

- `c26137e` Radio 아이콘 패딩 조정 (#136)
<!-- generated:end -->

### Minor Changes

- 7d6e60f: Modal CSS 변수 naming을 padding contract로 정리합니다.

  Migration Notes
  - Modal CSS 변수 `--oc-modal-space-x`, `--oc-modal-space-y`를 `--oc-modal-padding-x`, `--oc-modal-padding-y`로 변경
  - Modal CSS 변수 `--oc-modal-header-space-x`, `--oc-modal-header-space-y`를 `--oc-modal-header-padding-x`, `--oc-modal-header-padding-y`로 변경
  - Modal CSS 변수 `--oc-modal-container-space-x`, `--oc-modal-container-space-y`, `--oc-modal-container-space-top`, `--oc-modal-container-space-bottom`을 `--oc-modal-container-padding-x`, `--oc-modal-container-padding-y`, `--oc-modal-container-padding-top`, `--oc-modal-container-padding-bottom`으로 변경
  - Modal CSS 변수 `--oc-modal-footer-space-x`, `--oc-modal-footer-space-y`를 `--oc-modal-footer-padding-x`, `--oc-modal-footer-padding-y`로 변경

### Patch Changes

- 7d6e60f: ActionArea footer gradient와 scroll body reserve를 분리합니다.

  Migration Notes
  - standalone ActionArea는 `background=true` 상태에서도 상단 padding을 유지함
  - Modal footer와 ActionAreaLayout footer 안의 ActionArea는 상단 padding을 scroll body reserve로 이전함
  - Modal footer와 ActionAreaLayout footer는 내부 ActionArea gradient를 중복 렌더링하지 않고 owner overlay로 background를 표시함
  - footer overlay gradient는 ActionArea content 시작점까지 `padding-y * 2` 범위로 표시됨

- 7d6e60f: Modal과 ActionAreaLayout에서 ActionArea footer의 상단 여백 이동을 scrollable 상태에만 적용하도록 수정합니다.

  Migration Notes
  - 별도 마이그레이션은 필요하지 않습니다.
  - 짧은 본문처럼 스크롤이 필요 없는 Modal과 ActionAreaLayout에서는 ActionArea의 기본 상단 padding이 유지됩니다.
  - 스크롤 가능한 본문에서는 기존처럼 ActionArea 상단 padding을 body reserve로 이동해 footer gradient와 마지막 콘텐츠 간격을 유지합니다.

- c26137e: Radio checked icon의 SVG padding을 조정합니다.

  Migration Notes
  - 없음

### Migration Notes

- Modal CSS 변수 `--oc-modal-space-x`, `--oc-modal-space-y`를 `--oc-modal-padding-x`, `--oc-modal-padding-y`로 변경
- Modal CSS 변수 `--oc-modal-header-space-x`, `--oc-modal-header-space-y`를 `--oc-modal-header-padding-x`, `--oc-modal-header-padding-y`로 변경
- Modal CSS 변수 `--oc-modal-container-space-x`, `--oc-modal-container-space-y`, `--oc-modal-container-space-top`, `--oc-modal-container-space-bottom`을 `--oc-modal-container-padding-x`, `--oc-modal-container-padding-y`, `--oc-modal-container-padding-top`, `--oc-modal-container-padding-bottom`으로 변경
- Modal CSS 변수 `--oc-modal-footer-space-x`, `--oc-modal-footer-space-y`를 `--oc-modal-footer-padding-x`, `--oc-modal-footer-padding-y`로 변경
- standalone ActionArea는 `background=true` 상태에서도 상단 padding을 유지함
- Modal footer와 ActionAreaLayout footer 안의 ActionArea는 상단 padding을 scroll body reserve로 이전함
- Modal footer와 ActionAreaLayout footer는 내부 ActionArea gradient를 중복 렌더링하지 않고 owner overlay로 background를 표시함
- footer overlay gradient는 ActionArea content 시작점까지 `padding-y * 2` 범위로 표시됨

## 1.5.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.5.0..HEAD`_

#### Other

- `9beed64` Modal 드래그 및 Storybook 동작 개선 (#131)
- `3343dcf` ActionArea 배경 패딩 안정화 (#132)
<!-- generated:end -->

### Patch Changes

- 3343dcf: ActionArea background가 활성화될 때 상단 gradient와 content 사이에 추가 padding이 끼지 않도록 조정합니다.

  Migration Notes
  - ActionAreaLayout과 Modal footer 안의 ActionArea는 background 상태와 무관하게 상단 padding을 제거해 scroll-state 임계점에서 footer 높이가 흔들리지 않도록 유지함
  - standalone ActionArea는 `background=true`일 때 상단 padding을 제거함

- 9beed64: Modal footer 안의 ActionArea가 md 이상에서도 footer 폭을 기본으로 꽉 채우도록 max width override를 추가합니다.

  Migration Notes
  - 없음

- 9beed64: Modal drag 시작 시 진행 중인 snap settle animation을 현재 위치에서 interrupt해 새 포인터/터치 입력이 즉시 제어권을 갖도록 보정합니다.

  Migration Notes
  - 없음

- 9beed64: Modal의 마우스 드래그 핸들 조작 중 브라우저 native text selection과 drag가 함께 시작되지 않도록 보정합니다.

  Migration Notes
  - 없음

### Migration Notes

- ActionAreaLayout과 Modal footer 안의 ActionArea는 background 상태와 무관하게 상단 padding을 제거해 scroll-state 임계점에서 footer 높이가 흔들리지 않도록 유지함
- standalone ActionArea는 `background=true`일 때 상단 padding을 제거함

## 1.5.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.4.1..HEAD`_

#### Other

- `75a53da` CI self-hosted runner 전환 테스트 (#126)
- `609c21b` Fade 모션 intent 추가 (#127)
- `01bc705` Modal 반응형 스냅 전환 개선 (#128)
<!-- generated:end -->

### Minor Changes

- 609c21b: 일반 content show/hide에 사용할 수 있는 `fade` motion intent를 추가합니다.

  Migration Notes
  - 새 `fade` intent는 `@include oc-motion(opacity, fade)` 형태로 사용합니다.
  - `fade`는 non-spring opacity transition이며 reduced-motion에서도 짧은 opacity fade를 유지합니다.
  - `--oc-motion-duration-fade`, `--oc-motion-timing-fade` token이 추가됩니다.
  - 기존 `feedback`, `disclosure`, `surface`, `sheet`, `expand`, `move`, `gesture`, `ambient` intent의 동작은 변경되지 않습니다.

### Patch Changes

- 01bc705: Modal이 bottom sheet와 snapped popup 사이를 전환할 때 bottom 전용 fill, backdrop opacity, overshoot fill inline 상태가 남지 않도록 정리합니다. hidden backdrop을 사용하는 snapped popup에서는 배경 영역 상호작용을 허용하고, bottom 전환 후 popup으로 돌아와도 마지막 snap position을 유지합니다.

  Migration Notes
  - 없음

### Migration Notes

- 새 `fade` intent는 `@include oc-motion(opacity, fade)` 형태로 사용합니다.
- `fade`는 non-spring opacity transition이며 reduced-motion에서도 짧은 opacity fade를 유지합니다.
- `--oc-motion-duration-fade`, `--oc-motion-timing-fade` token이 추가됩니다.
- 기존 `feedback`, `disclosure`, `surface`, `sheet`, `expand`, `move`, `gesture`, `ambient` intent의 동작은 변경되지 않습니다.

## 1.4.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.4.0..HEAD`_

#### Fixes

- `3f67339` fix(modal): remove bottom surface opacity motion (#123)

#### Other

- `62bf9cc` ActionAreaLayout footer overlay 개선 (#124)
<!-- generated:end -->

### Patch Changes

- 62bf9cc: ActionAreaLayout footer gradient를 layout-owned overlay로 전환해 스크롤 끝단에서 opacity와 scaleY로 자연스럽게 사라지도록 개선합니다. md 이상에서 ActionArea actions slot의 최대 너비를 content width로 제한합니다.

  Migration Notes
  - 기존 ActionAreaLayout 사용처의 API 변경은 없음
  - `--oc-action-area-layout-gradient-overlap`, `--oc-action-area-layout-gradient-size`, `--oc-action-area-layout-background-color`로 footer overlay 범위와 배경색 조정 가능
  - `--oc-action-area-container-max-width`로 md 이상 actions slot 최대 너비 조정 가능

- 3f67339: Modal bottom variant의 surface motion에서 opacity fade를 제거하고 translate motion만 유지합니다.

### Migration Notes

- 없음

## 1.4.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.3.0..HEAD`_

#### Features

- `3c2da27` feat(ui): support link icon buttons

#### Fixes

- `0f245d6` fix(button): align loading indicator to content height (#120)

#### Documentation

- `d02538f` docs(agents): clarify compound composition boundary

#### Other

- `e66ca98` ActionArea 레이아웃 추가 (#121)
<!-- generated:end -->

### Minor Changes

- e66ca98: ActionAreaLayout을 추가해 스크롤 본문과 하단 ActionArea footer를 하나의 layout owner에서 구성할 수 있도록 합니다.

  Migration Notes
  - 신규 opt-in API이므로 기존 사용처 변경은 필요 없음

- 3c2da27: IconButton과 BackgroundIconButton이 `href`를 받으면 anchor로 렌더링하도록 지원합니다.

  Migration Notes
  - 없음

### Patch Changes

- 0f245d6: Button 로딩 인디케이터가 label/content 영역 기준으로 정렬되도록 수정하고, Loading 내부 SVG part를 `indicator`로 변경해 Button icon slot과 충돌하지 않도록 개선합니다.

  ### Migration Notes
  - `Loading` 내부 SVG를 selector로 커스터마이즈했다면 `[data-oc-part='icon']` 대신 `[data-oc-part='indicator']`를 사용하세요.

### Migration Notes

- `Loading` 내부 SVG를 selector로 커스터마이즈했다면 `[data-oc-part='icon']` 대신 `[data-oc-part='indicator']`를 사용하세요.

## 1.3.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.2.0..HEAD`_

#### Features

- `5f154f7` feat(motion): add extra bounce override (#106)
- `9ff2f9b` feat(storybook): add foundation profile toolbar

#### Fixes

- `0922662` fix(modal): keep bottom fill in sheet opacity layer
- `7cf2bfe` fix(select): apply icon styling to indicator
- `1eda9f5` fix(modal): keep close button visible by default
- `a99a706` fix(ui): make row interactions self-driven
- `f884992` fix(ui): default row dividers to neutral
- `1910da6` fix(ui): preserve cell activation through interaction layer
- `bf96c94` fix(ui): avoid duplicate cell control activation

#### Documentation

- `908e824` docs(agent): update figma agent setup guidance
- `2069560` docs(ui): rely on cell default divider in stories

#### Other

- `2916a70` Motion phase 스토리 추가 (#100)
- `4da6f5f` motion factor 토큰명 정리 (#102)
- `9d67d6f` Atomic radius factor 추가 (#103)
- `858fe7b` Figma foundation sync 문서화 (#105)
- `eae3c17` Modal 레이어 계약 정리 (#107)
- `c0f6de5` Accordion summary 표면 계약 개선 (#108)
- `63b2615` 모션 시맨틱 계약 정리 (#109)
- `952bc13` 모션 reveal 계약 제거 (#110)
- `a0c700d` Badge 인터랙션 렌더링 추가 (#111)
- `510ed36` 선택 컨트롤 크기 계약 정리 (#112)
- `8bdd955` ActionArea priority 계약 정리 (#113)
- `f6dc9c9` Switch RTL 대응 및 라벨 정렬 개선 (#114)
- `42dab32` 모달 BottomSheet 러버밴드 보정 (#115)
- `3de755e` Modal 여백 및 hidden backdrop 닫힘 정책 개선 (#116)
- `4849f41` 아이콘 생성 및 Figma 동기화 도구 개선 (#117)
<!-- generated:end -->

### Minor Changes

- 8bdd955: ActionAreaButton의 action hierarchy contract를 `priority` prop으로 정리하고 동등 선택지를 위한 `equal` priority를 추가합니다.

  Migration Notes
  - `ActionAreaButton variant` prop 제거, `priority` prop으로 교체 필요
  - `ActionAreaButton variant="main"`은 `priority="main"`으로 변경 필요
  - `ActionAreaButton variant="alternative"`는 `priority="alternative"`로 변경 필요
  - `ActionAreaButton variant="sub"`는 `priority="sub"`로 변경 필요
  - 동등한 선택지를 표시할 때는 `priority="equal"` 사용 필요
  - `data-oc-action-area-button-variant` selector 제거, `data-oc-action-area-button-priority` selector 사용 필요
  - `ActionAreaButton priority="alternative"`는 기존과 동일하게 outlined secondary Button으로 렌더링됨
  - `ActionAreaButton priority="equal"`은 outlined primary Button으로 렌더링됨
  - `ActionArea`는 strong에서 위→아래 `main` → `equal` → `alternative` → `sub`, neutral/compact에서 inline-start→inline-end 기준 `sub` → `alternative` → `equal` → `main` 순서로 action을 정렬함
  - `Button appearance="outlined" variant="secondary"`의 content 색상은 primary를 유지하고 interaction만 label-normal 기준으로 변경됨

- 9d67d6f: atomic radius token과 component-local radius 값을 조정할 수 있는 radius factor를 추가합니다.

  Migration Notes
  - `--oc-atomic-radius-factor` token 추가
  - `--oc-atomic-radius-*` token이 radius factor를 반영하도록 변경
  - `oc-radius($radius, $factor-token)` Sass helper 추가
  - `Badge`, `Menu`, `Alert`, `Tooltip`, `TextButton`, `Checkbox`의 component-local radius 기본값이 radius factor를 반영하도록 변경
  - `BackgroundIconButton` interaction clip radius가 `--oc-atomic-radius-max`를 반영하도록 변경
  - 기존 `--oc-atomic-radius-*` token 이름은 유지되며 consumer rename은 필요 없음
  - consumer가 radius를 전역으로 줄이거나 제거해야 하면 `--oc-atomic-radius-factor`를 override

- 5f154f7: oc-motion의 spring-backed motion에서 extra bounce override를 지원합니다.

  Migration Notes
  - SCSS `oc-motion(...)`과 `@include oc-motion(...)`에 `$extra-bounce` 인자 추가
  - TS runtime `ocMotion.resolve(...)`와 `MotionExpand`에 `extraBounce` option 추가
  - non-spring motion에서 extra bounce override를 넘기면 에러 발생

- 4da6f5f: motion과 typo의 runtime multiplier token vocabulary를 `factor` 기준으로 정리합니다.

  Migration Notes
  - `--oc-typo-scale`을 `--oc-typo-size-factor`로 변경
  - `--oc-motion-duration-scale*`을 `--oc-motion-duration-factor*`로 변경
  - `--oc-motion-scale*` amplitude token을 `--oc-motion-scale-factor*`로 변경
  - `--oc-motion-distance-scale*`을 `--oc-motion-distance-factor*`로 변경
  - SCSS `oc-motion(...)`, `oc-motion-duration(...)`의 `$duration-scale` 인자를 `$duration-factor`로 변경
  - SCSS `oc-motion-duration(...)`의 `$duration-scale-token` 인자를 `$duration-factor-token`으로 변경
  - SCSS `oc-motion-scale(...)`의 `$scale-token` 인자를 `$scale-factor-token`으로 변경
  - SCSS `oc-motion-distance(...)`의 `$distance-token` 인자를 `$distance-factor-token`으로 변경
  - React/runtime motion option과 result의 `durationScale` field를 `durationFactor`로 변경
  - React/runtime motion result의 `paceScale` field를 `paceFactor`로 변경
  - 기존 `scale` token alias는 제공하지 않음

- 63b2615: motion intent vocabulary를 `disclosure`, `surface`, `sheet`, `expand`, `release` 중심으로 확장하고 Menu, Tooltip, Modal, Accordion motion contract를 새 intent에 맞게 정리합니다.

  Migration Notes
  - 기존 `reveal` motion intent는 제거됩니다. Menu/Tooltip은 `disclosure`, Popup Modal은 `surface`, Bottom Modal은 `sheet`, layout expand motion은 `expand`를 사용해야 합니다.
  - `MotionReveal` runtime primitive는 `MotionExpand`로 이름이 변경됩니다. 기본 `data-oc-component`도 `motion-reveal`에서 `motion-expand`로 변경됩니다.
  - `--oc-motion-duration-reveal`, `--oc-motion-duration-reveal-exit`, `--oc-motion-timing-reveal`, `--oc-motion-timing-reveal-exit` token은 제거됩니다.
  - `--oc-motion-scale-factor-reveal`, `--oc-motion-distance-factor-reveal` token은 `--oc-motion-scale-factor-spatial`, `--oc-motion-distance-factor-spatial`로 변경됩니다.
  - Menu/Tooltip은 `disclosure`, Popup Modal은 `surface`, Bottom Modal은 `sheet`, Accordion은 `expand` motion intent를 사용합니다.
  - Menu/Tooltip의 `disclosure exit`은 `0.14s`와 `cubic-bezier(0.8, 0, 1, 1)` 기준의 non-spring accelerate motion을 사용합니다.
  - Popup Modal의 surface exit은 smooth `0.24` 기준입니다.
  - Bottom Modal의 sheet enter는 smooth `0.26`, sheet exit/release는 smooth `0.33` 기준입니다.
  - Popup drag release는 `gesture release`, Bottom drag release는 `sheet release`를 사용합니다.
  - Reduced-motion에서 Accordion chevron은 상태 회전을 보존하고 panel content는 opacity fade를 유지하며, Loading은 fade와 360도 회전만 유지합니다.

### Patch Changes

- c0f6de5: Cell item surface SCSS contract를 분리해 Accordion summary와 공유하고, Accordion hover divider 및 details opacity expand motion을 Cell/oc-motion 정책에 맞춥니다.

  Migration Notes
  - 없음

- a0c700d: Badge에 self-driven Interaction을 켤 수 있는 `interactive` prop과 link rendering을 추가합니다.

  Migration Notes
  - 기존 Badge 사용에는 영향 없음
  - command 역할의 Badge는 `interactive` prop으로 button 렌더링 가능
  - navigation 역할의 Badge는 `href` prop으로 anchor 렌더링 가능

- a99a706: Cell item과 Accordion summary interaction을 self-driven mode로 전환해 fillWidth=false에서 확장된 interaction 영역도 hover/active 상태를 받을 수 있게 합니다.

  Migration Notes
  - 없음

- bf96c94: Cell 안의 Checkbox, Radio, Switch control surface 클릭이 native label activation과 Cell proxy activation으로 중복 처리되지 않도록 수정합니다.

  Migration Notes
  - 없음

- 0922662: Modal bottom sheet의 rubber-band fill layer가 닫힘 opacity motion과 함께 합성되도록 수정합니다.

  Migration Notes
  - 없음

- 42dab32: Modal BottomSheet의 rubber-band 감쇠 기준에 viewport 비율 cap을 적용합니다.

  Migration Notes
  - 없음

- 1eda9f5: Modal Header의 기본 닫기 버튼이 viewport와 placement에 관계없이 표시되도록 변경합니다.

  Migration Notes
  - `ModalHeader`의 `closeButton` 기본값이 실제 UI에서도 일관되게 반영됨
  - 닫기 버튼을 숨겨야 하는 경우 `closeButton={false}`를 명시하세요.

- 3de755e: Modal popup에서 시각적 backdrop이 hidden 상태일 때 배경 클릭으로 닫히지 않도록 변경합니다.

  Migration Notes
  - `ModalContent`의 resolved backdrop이 `hidden`이면 backdrop click과 outside press dismissal이 무시됨
  - 배경 클릭으로 닫히는 popup이 필요하면 `backdrop="visible"`을 명시하세요.

- eae3c17: Modal.Content의 public CSS variable contract가 motion/layout layer까지 도달하도록 수정하고, Modal surface focus ring 기본 표시를 제거합니다.

  Migration Notes
  - `Modal.Content` `className`은 motion layer, visual surface layer, bottom fill layer에 함께 적용됨
  - `Modal.Content` `style`의 CSS custom property는 motion layer와 bottom fill layer에도 전달되어 `--oc-modal-bottom-top-clearance`, `--oc-modal-width` 같은 layout contract override 가능
  - `--oc-modal-bottom-top-clearance` 기본값을 `3rem`으로 변경하고 consumer override 값을 그대로 사용
  - `initialFocus="content"` 사용 시 Modal/Alert surface 전체 focus ring은 기본 표시되지 않음

- f884992: Cell과 Accordion의 기본 divider 색상을 neutral로 맞춥니다.

  Migration Notes
  - 기본 Cell, Accordion divider가 `alternative`에서 `neutral`로 변경됨

- 7cf2bfe: Select indicator 아이콘을 ChevronUpDown으로 바꾸고, 아이콘 슬롯과 맞는 padding 및 sizing contract를 사용하도록 정리합니다.

  Migration Notes
  - 없음

- 510ed36: Checkbox, Radio, CheckMark에 `small`/`medium` size contract를 정렬합니다.

  Migration Notes
  - `Checkbox`, `Radio`, `CheckMark`의 기본 size는 `medium`으로 유지됨
  - root export에서 `CheckboxSize`, `RadioSize`, `CheckMarkSize` type을 제공함
  - `small`은 `body2` 높이 기준, `medium`은 `body1` 높이 기준으로 control 크기와 label typography를 정렬함
  - selection control container padding을 `0.125em`으로 통일함
  - 작은 selection control이 필요한 consumer는 `size="small"` 지정 필요

- f6dc9c9: Switch의 checked thumb 이동을 RTL direction에서 반대로 적용합니다.

  Migration Notes
  - `dir="rtl"` 환경에서 `Switch` checked thumb가 inline-start 방향으로 이동함
  - public API 변경 없음

- f6dc9c9: Switch 라벨 typography와 content alignment를 SelectionControl 공통 size contract에 맞춥니다.

  Migration Notes
  - `Switch size="medium"` 라벨은 body1 기준, `size="small"` 라벨은 body2 기준으로 정렬됨
  - public API 변경 없음

- Updated dependencies [4849f41]
- Updated dependencies [4849f41]
  - @orioncactuscorp/icons@1.3.0

### Migration Notes

- `ActionAreaButton variant` prop 제거, `priority` prop으로 교체 필요
- `data-oc-action-area-button-variant` selector 제거, `data-oc-action-area-button-priority` selector 사용 필요
- `--oc-atomic-radius-factor` token 추가, `--oc-atomic-radius-*` token은 radius factor를 반영하도록 변경
- SCSS `oc-radius($radius, $factor-token)` helper 추가
- SCSS `oc-motion(...)`, `@include oc-motion(...)`, React/runtime motion API에 extra bounce 및 factor 기반 option 추가
- `--oc-typo-scale`은 `--oc-typo-size-factor`로 변경
- `--oc-motion-duration-scale*`, `--oc-motion-scale*`, `--oc-motion-distance-scale*` token은 각각 `factor` 기준 이름으로 변경
- 기존 `reveal` motion intent와 `MotionReveal` runtime primitive 제거, `disclosure`, `surface`, `sheet`, `expand`, `MotionExpand` 사용 필요
- reveal 관련 motion duration/timing/scale/distance token 제거 또는 spatial/factor 기준 token으로 변경
- `Badge`는 `interactive` prop과 `href` prop으로 interactive rendering 지원
- `ModalHeader` 닫기 버튼 기본 표시가 실제 UI에 일관되게 반영되며 숨길 때는 `closeButton={false}` 명시 필요
- `ModalContent`의 resolved backdrop이 `hidden`이면 backdrop click과 outside press dismissal이 무시됨
- `Modal.Content` `className`/`style`은 motion layer, visual surface layer, bottom fill layer에 함께 적용됨
- `--oc-modal-bottom-top-clearance` 기본값을 `3rem`으로 변경
- 기본 Cell, Accordion divider가 `alternative`에서 `neutral`로 변경
- `Checkbox`, `Radio`, `CheckMark`에 `small`/`medium` size contract 정렬 및 관련 size type root export 추가
- `Switch`는 `dir="rtl"` 환경에서 checked thumb 이동 방향을 반대로 적용
- `Switch size="medium"` 라벨은 body1 기준, `size="small"` 라벨은 body2 기준으로 정렬됨

## 1.2.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.1.0..HEAD`_

#### Fixes

- `7722704` fix(storybook): exclude library plugins from static build

#### Documentation

- `b43c650` docs(agent): document release workflow skill

#### Other

- `8555c47` SCSS inset border helper 추가 (#89)
- `7a359c1` montage-icons upstream sync command 추가 (#90)
- `4a9e6e4` Storybook 테마와 모션 툴바 개선 (#91)
<!-- generated:end -->

### Minor Changes

- 8555c47: SCSS inset border helper를 `oc-border`로 교체합니다.

  ### Migration Notes
  - `inset-stroke` mixin을 제거합니다.
  - 기존 `@include inset-stroke(...)` 사용처는 `@include oc-border(...)`로 변경해야 합니다.
  - `@include oc-border`는 `1px currentColor` inset border를 출력하고, `@include oc-border(black)`은 `1px black` inset border를 출력합니다.
  - `1.5px`, `2.5px`, `3.5px` 같은 half-pixel px inset border는 WebKit/DPR 보정을 적용합니다.

### Migration Notes

- `inset-stroke` mixin을 제거합니다.
- 기존 `@include inset-stroke(...)` 사용처는 `@include oc-border(...)`로 변경해야 합니다.
- `@include oc-border`는 `1px currentColor` inset border를 출력하고, `@include oc-border(black)`은 `1px black` inset border를 출력합니다.
- `1.5px`, `2.5px`, `3.5px` 같은 half-pixel px inset border는 WebKit/DPR 보정을 적용합니다.

## 1.1.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@1.0.0..HEAD`_

#### Features

- `68e4f3a` feat(alert): add content message props (#83)

#### Fixes

- `3b84e25` fix(release): avoid existing tag output

#### Documentation

- `50d960c` docs: refine public package documentation
- `14a7162` docs(ui): document foundation customization
- `89effa7` docs(ui): split install commands by manager
- `ae16b1c` docs(ui): expand motion documentation
- `d7d9802` docs(ui): simplify runtime motion example

#### Maintenance

- `db95a78` chore(release): fix public release tag creation

#### Other

- `81de07e` npm OIDC 배포 전환 (#79)
- `8e6fbbd` Field control stroke paint 보정 (#82)
- `fe0db9d` Modal 드래그 정착 CSS fallback 제거 (#84)
- `cb2f8da` RSC 클라이언트 경계 보존 (#85)
- `5174d57` 내부 visual layer stacking 격리 (#86)
- `17e6057` Modal 그림자 및 backdrop 정책 개선 (#87)
<!-- generated:end -->

### Minor Changes

- 17e6057: atomic foundation에 Figma shadow effect style과 대응되는 shadow token을 추가합니다.

  Migration Notes
  - 신규 shadow token을 사용할 수 있으며, 기존 shadow token과 component API는 유지됩니다.

- 17e6057: ModalContent에 backdrop 표시 정책을 추가하고, snapped popup과 peeked bottom sheet의 auto backdrop을 숨김 처리합니다.

  Migration Notes
  - `ModalContent`에서 backdrop 표시를 직접 고정해야 하는 경우 새 backdrop policy를 명시할 수 있습니다.
  - snapped popup과 peeked bottom sheet에서 auto backdrop에 의존하던 consumer style은 더 이상 표시되지 않습니다.

### Patch Changes

- 68e4f3a: AlertContent에 `heading`, `description` prop 기반 메시지 API를 추가합니다.

  Migration Notes
  - 기존 AlertHeading, AlertDescription compound API는 유지됩니다.
  - 정형 Alert 메시지는 AlertContent의 `heading`, `description` prop으로 작성할 수 있습니다.

- 8e6fbbd: Field control surface에 stacking context 격리를 추가해 Modal body 스크롤 중 TextInput, TextArea, Select stroke가 Modal header 위로 paint되지 않도록 보정합니다.

  Migration Notes
  - consumer repo에서 Modal body scope에 추가했던 Field control isolation 우회 스타일은 제거할 수 있습니다.

- cb2f8da: React Server Components 환경에서 root barrel import가 interactive component의 client boundary를 잃지 않도록 `use client` directive 보존과 RSC boundary 검증을 추가합니다.

  Migration Notes
  - Next App Router Server Component에서 `@orioncactuscorp/ui` root barrel로 interactive component를 import하는 경우 leaf client boundary가 유지됩니다.
  - Server Component에서 `onClick` 같은 function prop을 interactive component에 직접 전달하는 사용 방식은 React Server Components 제약상 Client Component로 분리해야 합니다.

- 5174d57: Badge, ActionArea, Checkbox, Radio, CheckMark의 내부 visual layer에 stacking context 격리를 추가해 외부 chrome과 z-index가 경쟁하지 않도록 보정합니다.

  Migration Notes
  - 없음

### Migration Notes

- `ModalContent`에서 backdrop 표시를 직접 고정해야 하는 경우 새 backdrop policy를 명시할 수 있습니다.
- snapped popup과 peeked bottom sheet에서 auto backdrop에 의존하던 consumer style은 더 이상 표시되지 않습니다.
- consumer repo에서 Modal body scope에 추가했던 Field control isolation 우회 스타일은 제거할 수 있습니다.
- Next App Router Server Component에서 `@orioncactuscorp/ui` root barrel로 interactive component를 import하는 경우 leaf client boundary가 유지됩니다.
- Server Component에서 `onClick` 같은 function prop을 interactive component에 직접 전달하는 사용 방식은 React Server Components 제약상 Client Component로 분리해야 합니다.

## 1.0.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.11.0..HEAD`_

#### Maintenance

- `afc7780` chore(release): prepare npm public publish bootstrap

#### Other

- `4ea5168` Public package 배포 준비 (#73)
<!-- generated:end -->

### Major Changes

- 4ea5168: Public package 배포를 위한 metadata, license, documentation을 정리합니다.
  - `@orioncactuscorp/ui`와 `@orioncactuscorp/icons` package metadata를 MIT license, public publish access, homepage, author, support email 기준으로 정리합니다.
  - `@orioncactuscorp/ui` public package tarball에서 내부 `agent/*` artifact를 제외합니다.
  - README와 `docs/agent-setup.md`에 public-safe Agent 초기 세팅 prompt를 추가합니다.
  - GitHub Packages private 설치 안내를 public package 설치 안내로 교체합니다.

  Migration Notes
  - `node_modules/@orioncactuscorp/ui/agent/*`를 직접 읽던 consumer Agent setup은 README 또는 `docs/agent-setup.md`의 복붙 prompt 기반으로 전환해야 합니다.
  - runtime component, CSS, SCSS, icon import 사용성은 변경되지 않습니다.

### Patch Changes

- Updated dependencies [4ea5168]
  - @orioncactuscorp/icons@1.0.0

### Migration Notes

- 없음

## 0.11.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.10.0..HEAD`_

#### Other

- `a489fc4` 아이콘 패키지 분리 (#69)
- `a3224b8` Montage 아이콘 패키지 추가 (#70)
- `0b897e8` BackgroundIconButton 블렌드 QA 정리 (#72)
<!-- generated:end -->

### Minor Changes

- a489fc4: `@orioncactuscorp/icons` package를 추가하고 `orioncactus` first-party icon set을 `@orioncactuscorp/ui`에서 분리합니다.
  - `SvgIcon`, `IconProps`, `orioncactus` icon set을 `@orioncactuscorp/icons`로 이동합니다.
  - `SvgIcon`은 비상호작용 시각 SVG primitive로 정리하고 `title`, `desc`, `aria-*` 접근성 metadata를 지원합니다.
  - `@orioncactuscorp/ui`는 내부 component indicator icon을 `@orioncactuscorp/icons` dependency에서 가져옵니다.
  - `@orioncactuscorp/ui/icons/orioncactus`, `@orioncactuscorp/ui/icons/material-rounded`, `@orioncactuscorp/ui/icons/montage` export를 제거합니다.
  - `@orioncactuscorp/ui` root barrel의 `IconDefault` export를 제거합니다.
  - `material-rounded` placeholder와 `montage` derived icon set은 새 icons package에 포함하지 않습니다.

  Migration Notes
  - 앱 코드에서 icon을 직접 사용하는 경우 import 경로를 `@orioncactuscorp/icons`로 변경해야 합니다.
  - 기존 `import { IconDefault } from '@orioncactuscorp/ui'`는 `import { IconDefault } from '@orioncactuscorp/icons'`로 변경합니다.
  - 기존 `import { IconClose } from '@orioncactuscorp/ui/icons/orioncactus'`는 `import { IconClose } from '@orioncactuscorp/icons'`로 변경합니다.
  - `@orioncactuscorp/ui` component만 사용하는 경우 `Checkbox`, `Radio`, `Select`, `Accordion`, `ModalClose` 등의 내부 icon 표시는 그대로 동작합니다.
  - GitHub Actions에서 private package를 설치하는 consumer repository는 GitHub Packages의 `ui`, `icons` package settings에 모두 `Manage Actions access: Read` 권한이 필요합니다.
  - icon 자체에 `onClick`, `tabIndex`, `role='button'`을 부여한 consumer 코드는 부모 `button`, `a`, `IconButton`으로 interaction을 옮겨야 합니다.

### Patch Changes

- 0b897e8: BackgroundIconButton normal variant의 blend layer를 Figma IconButtonBackground 구조에 맞춰 조정합니다.
  - 기본 아이콘은 static black 43% opacity로 낮추고, WebKit에서는 cool neutral 50 61% opacity와 `plus-darker` blend를 적용합니다.
  - 배경 slot에 white `plus-lighter` 35% layer와 black 8% `multiply` 보정 layer를 분리 적용합니다.
  - BackgroundIconButton에서 blend opacity 기본값을 관리하고, Background surface 안에서는 WebKit 전용 black 보정 layer에 4%를 추가합니다.
  - alternative variant는 cool neutral 30 61% 배경과 static white 88% 아이콘 계약으로 고정합니다.
  - WebKit normal variant는 `brightness(200%)` backdrop-filter와 black `multiply` 20% layer를 사용하고, Background surface 내부에서는 4%를 추가 보정합니다.
  - WebKit과 Chromium에서 흰색, 회색, 검정, 이미지, Modal header 환경을 검증하는 Storybook QA story와 Playwright 테스트를 추가합니다.

  Migration Notes
  - 없음

- Updated dependencies [a489fc4]
  - @orioncactuscorp/icons@0.11.0

### Migration Notes

- 앱 코드에서 icon을 직접 사용하는 경우 import 경로를 `@orioncactuscorp/icons`로 변경해야 함
- 기존 `import { IconDefault } from '@orioncactuscorp/ui'`는 `import { IconDefault } from '@orioncactuscorp/icons'`로 변경
- 기존 `import { IconClose } from '@orioncactuscorp/ui/icons/orioncactus'`는 `import { IconClose } from '@orioncactuscorp/icons'`로 변경
- icon 자체에 `onClick`, `tabIndex`, `role='button'`을 부여한 consumer 코드는 부모 `button`, `a`, `IconButton`으로 interaction 이동
- GitHub Actions에서 private package를 설치하는 consumer repository는 GitHub Packages의 `ui`, `icons` package settings에 모두 `Manage Actions access: Read` 권한 필요

## 0.10.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.9.0..HEAD`_

#### Other

- `e6e8fad` 컴포넌트 선택자 우선순위 개선 (#43)
- `0a3f53f` GitHub Actions Node 24 런타임 전환 (#44)
- `cb47d90` Reduced Motion 대응 기준 및 모달 동작 개선 (#46)
- `5a24604` motion helper 도입 (#49)
- `62c16c9` CI 실행 시간 단축 (#50)
- `2de4e1d` oc-motion 전환 완료 (#51)
- `4b3017a` Modal stacking contract 정리 (#52)
- `7fcc0ae` Modal 중첩 닫기 정책 추가 (#54)
- `e15258f` TextButton inherit variant 정리 (#55)
- `535a5ba` motion duration scale 토큰명 정리 (#56)
- `b9c9ad7` Field 가로 배치 지원 (#58)
- `cf56dc8` Alert 컴포넌트 추가 (#57)
- `e33af8b` TextButton 색상 계약 정리 (#59)
- `99c3aed` import 경로 기준 정리 (#60)
- `a5a67c6` 주석 정책 정리 (#61)
- `7ad3583` Cell 인터랙션 구조 개선 (#63)
- `2c31da4` oc-motion 피드백 및 amplitude token 개선 (#65)
- `adea6a1` 런타임 모션 Accordion 추가 (#64)
- `619f771` 모션 및 Storybook 상태 개선 (#66)
- `40641ca` Bottom Modal 드래그 관성 개선 (#67)
- `1a7a01a` 팝업 스냅 드래그 관성 개선 (#68)
<!-- generated:end -->

### Minor Changes

- b9c9ad7: Field에 horizontal orientation과 label width contract를 추가합니다.

  Migration Notes
  - `Field`가 `orientation="horizontal"`과 `labelWidth` prop을 지원합니다.
  - `labelWidth`의 number 값은 `16px = 1rem` 기준 rem CSS length로 변환됩니다.
  - `FieldControl`은 stable wrapper slot인 `data-oc-component="field-control"` 및 `data-oc-part="control"`을 렌더링합니다.
  - horizontal Field의 helper/error message는 control column 시작 위치에 정렬됩니다.

- 2c31da4: Motion scale amplitude token을 추가합니다.

  Migration Notes
  - `oc-motion-scale($scale, $intent)` helper 추가
  - `--oc-motion-scale-feedback`, `--oc-motion-scale-reveal` foundation token 추가
  - Button, TextButton, IconButton, BackgroundIconButton, Cell, Checkbox, Menu, Tooltip, Modal, Motion story의 scale feedback/reveal 값을 `oc-motion-scale(...)` 경유로 변경
  - Radio dot의 고정 시각 크기 scale은 motion amplitude가 아니므로 `--oc-radio-icon-scale` component contract로 분리
  - 기본 token 값은 `1`이므로 기존 scale 값은 유지되며, consumer가 token을 `0` 또는 `0.5` 등으로 override해 scale 효과를 제거하거나 약하게 조정 가능

- 2c31da4: `oc-motion`에 거부된 시도를 표현하는 `reject` intent를 추가합니다.

  Migration Notes
  - `oc-motion(..., reject)`는 닫기, 전환, 입력 같은 사용자 시도가 거부되었음을 알리는 transform feedback에 사용
  - `reject` intent는 일반 환경에서 smooth spring-backed transform transition을 제공
  - `--oc-motion-duration-reject`, `--oc-motion-timing-reject` foundation token 추가 및 smooth spring 기반 기본값 제공

- cf56dc8: Alert compound component를 추가합니다.

  Migration Notes
  - `Alert`, `AlertRoot`, `AlertContent`, `AlertHeading`, `AlertDescription`, `AlertActionArea`, `AlertAction` root export 추가
  - `AlertContent`는 `Modal`의 popup/hug overlay contract를 재사용하며 기본 `role="alertdialog"`와 heading/description 접근성 연결 제공
  - Alert body layout은 `data-oc-part="container"` 아래 `message`와 `actions` slot을 sibling으로 배치함
  - `AlertRoot`는 기본적으로 backdrop/outside dismissal을 막고, 정보성 alert에서만 `outsideDismissible`로 허용 가능
  - `AlertHeading`과 `AlertDescription`은 `data-oc-part="message"` slot으로 그룹화됨
  - `AlertActionArea`는 기본적으로 action에 autofocus를 주입하지 않으며, destructive confirm 등에서 `initialFocus="least-destructive"`를 명시해 사용할 수 있음
  - `AlertAction`은 `normal`, `assistive`, `negative` variant를 제공하며 기본 클릭 시 Alert를 닫음
  - Alert width는 `--oc-alert-width` contract var로 조정 가능하며 Modal surface에는 `--oc-modal-width`로 전달됨
  - `ModalContent`는 Base UI Dialog initial focus를 제어하는 `initialFocus` prop과 popup 자체를 가리키는 `"content"` 값을 지원함

- e15258f: TextButton 기본 스타일을 Figma의 assistive medium 계약에 맞추고, 부모 색상과 타이포를 따르는 `inherit` variant/size 조합을 명시합니다.

  Migration Notes
  - `TextButton` 기본값이 `variant="assistive"`, `size="medium"`으로 변경됨
  - 기존 `variant="normal"`은 제거되며, 부모 색상을 상속해야 하는 경우 `variant="inherit"` 사용
  - 부모 타이포를 상속해야 하는 경우 기존처럼 `size="inherit"` 사용

- 7fcc0ae: Modal에 nested navigation dismissal 정책을 추가합니다.
  - `ModalRoot`에 `navigationDepth`와 `dismissBehavior` prop 추가
  - `navigationDepth > 0`의 `auto` 정책에서 drag dismissal과 background pointer dismissal 기본 차단
  - `dismissBehavior`의 reason별 `allow`/`block` override 지원

  Migration Notes
  - 기존 Modal은 `navigationDepth` 기본값이 `0`이므로 동작 변경 없음
  - 중첩 화면 Modal에서 back stack 우회 방지가 필요하면 `navigationDepth`를 현재 depth로 전달
  - 중첩 화면에서도 drag 또는 backdrop 닫기를 허용해야 하면 `dismissBehavior={{ drag: 'allow', backdrop: 'allow' }}` 사용

- 7ad3583: Cell에 interactive row, fill width, leading/content/trailing slot, divider variant contract를 추가하고 MenuItem이 개선된 Cell primitive를 재사용하도록 정리합니다.

  Migration Notes
  - Cell은 `divider="normal|neutral|alternative|none"`을 지원하며 기존 `dividerColor` prop은 제거
  - CellItem은 `interactive`, `fillWidth`, `verticalAlign`, `leading`, `trailing`, `content`, `description`, `divider` prop과 `data-oc-*` selector contract를 제공
  - CellItem의 `leading`, `trailing`에 직접 전달한 Icon은 `size`가 없으면 Cell slot icon size를 따름
  - `interactive` CellItem은 `data-oc-cell-control`로 opt-in한 내부 control에만 cell click activation을 전달
  - MenuItem은 CellItem 기반으로 렌더링되며 기존 `data-oc-component="menu-item"` contract는 유지
  - MenuItem에 `leading`, `trailing`, `content`, `fillWidth`, `divider` prop 추가
  - Menu는 기존 `size="small|medium"`에 따른 typography와 em 기반 item padding을 유지

- 1a7a01a: Modal Popup에 `snapPositions`와 `defaultSnapPosition`을 추가해 가운데, 좌우, 상하, 모서리 위치로 드래그 후 스냅할 수 있도록 개선합니다.

  Migration Notes
  - 기존 BottomSheet `snapPoints` 사용 방식 변경 없음
  - Popup snap이 필요한 경우 `variant="popup"`과 `snapPositions`를 함께 지정

- adea6a1: TS runtime `oc-motion` layer와 Accordion compound component를 추가합니다.

  Migration Notes
  - `@orioncactuscorp/ui/utils/motion` subpath 추가
  - `@orioncactuscorp/ui/react/motion` subpath 추가
  - `ocMotion.resolve(...)`는 SCSS `oc-motion`과 같은 intent, phase, pace, reduced-motion policy, duration scale token vocabulary 사용
  - `MotionReveal` runtime wrapper 추가
  - `MotionReveal`은 `block-size` reveal을 low-level `ocSpring` animator에 연결하고 reduced-motion에서 non-feedback reveal motion 즉시 완료
  - `Accordion`, `AccordionItem`, `AccordionSummary`, `AccordionDetails`, `AccordionDescription`, `AccordionContent` compound export 추가
  - Accordion details reveal은 CSS grid 대신 `MotionReveal` 사용
  - Accordion selector contract 추가
  - `IconChevronDownTight` export 추가

- 5a24604: motion duration scale token과 `oc-motion(...)` SCSS helper를 추가해 transition duration, pace, reduced-motion 정책을 공통 contract로 관리합니다.

  Migration Notes
  - `--oc-motion-*` foundation token 추가
  - `@include oc-motion($properties, $intent, $phase, $pace, $duration-scale, $reduced)` mixin 추가
  - `transition: oc-motion(...)`, `oc-motion-duration(...)`, `oc-motion-timing(...)` SCSS function 추가
  - `$duration-token` escape hatch 추가. 단 spring-backed motion에서는 compile error 처리
  - `$pace`는 `quick | normal | slow` semantic preset만 허용
  - 숫자 duration 보정은 `$duration-scale` escape hatch로 분리
  - `reveal` motion은 일반 환경에서 spring profile을 사용하며 transform에는 extra-bounce를 적용
  - `--oc-motion-pace-*`, `--oc-motion-duration-scale`, `--oc-motion-duration-scale-reduced`, `--oc-motion-duration-scale-preserve`는 unitless multiplier로 사용
  - spring-backed `oc-motion` duration도 `--oc-motion-duration-scale`과 `--oc-motion-pace-*` multiplier를 적용
  - unknown phase, pace, reduced policy와 음수 `$duration-scale`은 compile error 처리
  - `$reduced: preserve`는 `--oc-motion-duration-scale-preserve`를 사용
  - `Interaction`, `Button`, `IconButton`, `TextButton`, `BackgroundIconButton`, `CheckMark`, `Checkbox`, `Radio`, `Switch`, `ScrollArea`, `Field`, `Tooltip`, `Menu`, `Modal` transition을 motion helper 기반으로 전환
  - `Menu`, `Tooltip`, `Modal` reveal 계열은 reduced-motion에서 helper duration token을 사용하고 scale/translate motion을 제거
  - `Switch` thumb처럼 상태 이해에 필요한 motion은 `$reduced: preserve`로 명시
  - `Loading`은 reduced-motion에서 반복 animation을 멈추고 static indicator로 대체
  - `docs/oc-motion.md`와 README motion 섹션 추가

- 2c31da4: Motion scale/distance amplitude parent token과 `oc-motion-distance(...)` helper를 추가합니다.

  Migration Notes
  - `--oc-motion-scale` parent token 추가
  - `--oc-motion-scale-feedback`, `--oc-motion-scale-reveal`이 기본적으로 `--oc-motion-scale`을 참조하도록 변경
  - `--oc-motion-distance-scale`, `--oc-motion-distance-scale-reject`, `--oc-motion-distance-scale-reveal` token 추가
  - `oc-motion-distance($distance, $intent)` SCSS helper 추가
  - Menu reveal translate와 Modal reject shake 거리가 motion distance token을 사용
  - Storybook toolbar에서 전체 scale/distance와 intent별 override 조정 가능

### Patch Changes

- adea6a1: Accordion chevron rotation이 bouncy spring-backed `oc-motion`을 사용하도록 조정합니다.

  Migration Notes
  - Cell/Accordion icon slot size contract `--oc-cell-icon-size`가 shared Cell contract default에서 `1.375rem`으로 정렬됨
  - `oc-motion(transform, feedback, $phase: settle)`가 bouncy spring-backed timing을 사용함
  - Accordion 기본 chevron rotation은 `feedback + settle` phase에 1.5 duration scale을 적용하고 토글마다 시계방향 180deg씩 누적 회전함
  - Accordion icon slot은 Cell과 같은 `--oc-cell-icon-size` block-size contract를 유지하며 inline axis는 강제하지 않음

- adea6a1: Cell과 Accordion disabled 시각 상태를 opacity contract로 정리합니다.

  Migration Notes
  - Cell disabled 상태는 `--oc-cell-disabled-opacity` contract var를 통해 내부 visual slot에만 기본 `0.28` opacity로 표현됨
  - Accordion disabled item도 Cell과 같은 `--oc-cell-disabled-opacity` contract를 내부 summary/details visual slot에 적용함
  - 기존 disabled label color token 기반 표현 대신 content opacity가 적용되며 divider border는 흐려지지 않음

- 4b3017a: Modal이 여러 개 동시에 열릴 때 `--oc-zindex-4` modal band 안에서 열린 순서대로 자동 stacking되도록 개선합니다.

  Migration Notes
  - Modal backdrop과 viewport가 각각 `--oc-modal-backdrop-z-index`, `--oc-modal-viewport-z-index` contract var를 통해 z-index를 계산
  - 중첩 Modal은 내부 stack offset으로 순서를 조정하며, 닫힌 뒤 다시 열린 Modal은 가장 위에 배치
  - Tooltip, Toast 등 더 높은 floating layer를 위해 Modal viewport의 고정 `--oc-zindex-5` 사용 제거
  - Modal public prop 추가 없음

- e33af8b: TextButton 텍스트 색상을 `--oc-text-button-color` component contract var로 노출하고, Interaction 색상은 텍스트 현재 색상을 따르도록 정리합니다.

  Migration Notes
  - TextButton의 `primary`, `assistive`, `inherit` 색상은 `--oc-text-button-color`로 제어됨
  - TextButton root class에서 색상을 바꾸는 consumer CSS는 `color` 대신 `--oc-text-button-color` override를 우선 권장
  - 예: `Header`의 logo link, inquiry list의 `loadMoreButton`처럼 `TextButton`에 직접 className을 붙이는 경우
  - 부모나 slot에서 `color`를 상속받는 기존 `variant="inherit"` 사용은 계속 동작함

- e6e8fad: 컴포넌트 modifier selector specificity를 낮춰 소비자 커스텀 class의 component contract var override가 더 쉽게 적용되도록 개선합니다.

  Migration Notes
  - Button, IconButton, TextButton, BackgroundIconButton, Interaction, Badge의 root modifier selector를 `:where()` 기반으로 조정
  - BackgroundIconButton background slot 스타일 기준을 CSS Module hash class에서 `data-oc-part="background"` contract로 정리
  - Agent selector contract와 convention metadata에 low-specificity modifier authoring 정책 추가
  - CSS Module hash class 직접 타겟은 여전히 public customization contract가 아님

- cb47d90: Reduced motion 환경에서 motion intent 기준을 적용하도록 주요 컴포넌트의 transition 동작을 조정합니다.

  Migration Notes
  - Menu와 Tooltip은 `prefers-reduced-motion: reduce`에서 scale, translate, spring motion 대신 인지 가능한 opacity-only transition 사용
  - Button, Interaction, CheckMark, Checkbox, Radio, ScrollArea, Switch는 reduced-motion에서도 opacity/color/background feedback transition 유지
  - Bottom Modal은 reduced-motion에서도 공간 모델을 전달하기 위한 짧은 non-spring slide transition 유지
  - Modal drag dismissal은 reduced-motion에서도 CSS에 정의된 transition duration이 있으면 해당 duration을 사용
  - Popup Modal은 기본 환경에서 scale transition을 유지
  - Popup/full Modal은 reduced-motion에서 transform motion 없이 인지 가능한 opacity transition 중심으로 동작
  - Modal content는 `surface-motion` 레이어와 `surface` 레이어를 분리해 transform/opacity motion과 visual clipping/layout 책임을 분리
  - Modal visual customization은 `data-oc-part="surface"` 또는 component contract var 기준 권장
  - ModalContent `className`/`style`은 visual surface 레이어에 적용
  - Loading은 reduced-motion에서 반복 animation을 멈추고 static indicator로 대체

- 2c31da4: Alert background 클릭이 닫기 차단 상태일 때 popup surface에 거부 피드백을 표시합니다.

  Migration Notes
  - `AlertRoot` 기본값처럼 background dismissal이 차단된 상태에서 backdrop을 클릭하면 popup surface가 reject motion으로 응답
  - Modal motion layer가 닫기 시도 거부 중 `data-oc-modal-feedback="reject"` transient state selector를 노출
  - 거부 피드백 거리는 `--oc-modal-reject-distance` contract var로 조정 가능

- 2c31da4: Scale 기반 active feedback이 `oc-motion` helper를 거치도록 누락된 컴포넌트를 정리합니다.

  Migration Notes
  - `TextButton` active scale feedback이 `oc-motion(transform, feedback)` transition을 사용
  - `BackgroundIconButton` active scale feedback이 `oc-motion(transform, feedback)` transition을 사용
  - public prop 또는 selector 변경 없음

- 619f771: Bottom Modal의 open motion을 runtime spring 기반으로 전환하고 drag release, peek/snap settle, backdrop opacity를 sheet translate와 같은 프레임에서 보간합니다.

  Migration Notes
  - `reveal` spring은 opacity에 smooth profile, transform에 snappy profile과 extra bounce를 적용
  - `move`, `ambient loop` motion의 SCSS/TS spring profile 동기화
  - `gesture settle` duration token을 `0.52s`로 조정하고 Safari drag release 체감을 위해 token easing 유지
  - Bottom Modal은 reduced-motion에서도 sheet translate와 drag settle motion을 유지
  - Bottom Modal backdrop opacity가 open/peek/snap/drag settle 중 sheet motion과 함께 보간

### Migration Notes

- `TextButton` 기본값이 `variant="assistive"`, `size="medium"`으로 변경되며, 기존 `variant="normal"`은 제거됨
- `Cell`의 기존 `dividerColor` prop은 제거되고 `divider="normal|neutral|alternative|none"` contract로 대체됨
- `Field`는 `orientation="horizontal"`과 `labelWidth`를 지원하며, horizontal helper/error message 정렬이 control column 기준으로 변경됨
- `ModalRoot`는 nested navigation dismissal 제어를 위해 `navigationDepth`와 `dismissBehavior`를 지원함
- `Alert`, `Accordion`, `MotionReveal`, motion utility subpath 및 motion foundation token이 추가됨
- scale, distance, reject, reduced-motion 관련 motion token과 helper가 추가되어 consumer override 지점이 확장됨

## 0.9.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.8.0..HEAD`_

#### Other

- `6c77a77` 자동완성 필드 표면 보정 (#33)
- `fc17cf4` iOS Spring 모션 유틸리티 추가 (#34)
- `514564f` Atomic foundation 토큰 정리 (#36)
- `4467c24` Spring Storybook 개선 (#37)
- `dfa8e89` Spring transition API 개선 (#38)
- `2047b3e` Spring 런타임 개선 (#39)
<!-- generated:end -->

### Minor Changes

- fc17cf4: iOS spring motion을 CSS와 TS에서 사용할 수 있는 utility를 추가합니다.
  - `@orioncactuscorp/ui/scss/spring`의 `oc-spring(...)`, `oc-spring-timing(...)`, `oc-spring-settle-duration(...)`, `oc-spring-duration-scale(...)` 추가
  - `@orioncactuscorp/ui/utils/spring`의 `ocSpring` runtime utility 추가
  - `--oc-spring-smooth-*`, `--oc-spring-snappy-*`, `--oc-spring-bouncy-*` preset token 추가

  Migration Notes
  - 신규 spring API의 `duration`은 iOS와 같은 perceptual duration 기준입니다.
  - CSS에 출력되는 transition duration은 spring 감쇠가 안정되는 settling duration입니다.
  - TS runtime 결과에서는 실제 CSS duration을 `settlingDuration`, `settlingDurationSeconds`로 명확히 구분합니다.
  - CSS token을 직접 사용할 때는 `--oc-spring-*` token을 사용하고, SCSS에서는 `oc-spring(...)` 사용을 권장합니다.

- 2047b3e: React에서 spring runtime을 사용할 수 있는 hook subpath를 추가합니다.
  - `@orioncactuscorp/ui/react/spring` export 추가
  - `useSpringAnimator`로 React lifecycle에 맞춘 animator 생성/정리 지원
  - `useSpringValue`로 value, velocity, target frame state와 retarget setter 제공
  - `useSpringTarget`으로 React state target을 따라가는 controlled spring value 지원
  - Storybook runtime drag 예제에 hook 기반 사용 예시 추가

  Migration Notes
  - 기존 `@orioncactuscorp/ui/utils/spring` API는 그대로 유지됩니다.
  - React component에서 spring value가 React state target을 따라가야 하면 `useSpringTarget` 사용을 권장합니다.
  - 직접 retarget setter, spring 변경, jump 제어가 필요하면 `useSpringValue` 사용을 권장합니다.
  - DOM write를 직접 제어하는 고빈도 gesture에는 `useSpringAnimator` 또는 기존 `createSpringAnimator` 사용을 권장합니다.

- 2047b3e: TS spring runtime animator를 추가하고 static spring sampling과 같은 Apple Spring 모델을 공유하도록 정리합니다.
  - `createSpringAnimator`와 `ocSpring.createAnimator` 추가
  - runtime animator에서 number, number array, numeric object 값 지원
  - `setTarget()` retarget 시 현재 position과 velocity를 이어받는 persistent spring 동작 추가
  - `setSpring()` 및 `blendDuration` 기반 spring parameter blending 지원
  - `ocSpring.*` 결과에 `response`와 `evaluate({ time })` 추가
  - Storybook에 WWDC 2023 2D drag spring 예제 추가

  Migration Notes
  - 기존 `ocSpring.*.transition()`, `settlingDuration`, `timingFunction` 사용법은 그대로 유지됩니다.
  - gesture, drag, interrupt가 중요한 런타임 상호작용은 `createSpringAnimator` 사용을 권장합니다.
  - object value를 animator에 전달할 때는 초기 value, target, velocity의 numeric key shape가 같아야 합니다.

- dfa8e89: SCSS `oc-spring(...)`에서 여러 transition property와 property별 spring 설정을 지원합니다.
  - `oc-spring((opacity, transform), 0.3s, snappy)`처럼 동일 spring 설정을 여러 property에 적용할 수 있습니다.
  - `oc-spring((opacity: (0.3s, snappy), transform: (0.3s, snappy, 0.1)))`처럼 property별 duration, preset, extra bounce를 지정할 수 있습니다.
  - `oc-spring((opacity: (duration: 0.3s, preset: snappy, delay: 50ms)))`처럼 property별 고급 옵션은 named map으로 지정할 수 있습니다.
  - Menu transition은 opacity와 transform spring 설정을 분리해 open/close transition 대상이 유지되도록 개선합니다.

  Migration Notes
  - 기존 `oc-spring(transform, 0.3s, snappy)` 단일 property 사용법은 그대로 유지됩니다.
  - property별 설정 tuple은 `(duration, preset, extra-bounce, delay, samples)` 순서입니다.
  - property별 physical spring이나 `bounce`, `initial-velocity` 같은 고급 옵션은 named map을 사용해야 합니다.

- 514564f: foundation `element` token을 `atomic`과 `motion`으로 재구성합니다.
  - `@orioncactuscorp/ui/scss/foundations/element`를 제거하고 `atomic`, `motion` foundation으로 분리
  - `--oc-element-radius-*`, `--oc-element-width-*`, `--oc-element-blur-*` token을 `--oc-atomic-*` token으로 변경
  - `--oc-spring-*` preset token을 `motion` foundation에서 발행
  - `--oc-element-header-height`, `--oc-element-overlay-*`, `--oc-element-ease-spring-*` token 제거
  - `Badge` accent override contract를 `--oc-element-accent-color`에서 `--oc-badge-accent-color`로 변경

  Migration Notes
  - `@orioncactuscorp/ui/scss/foundations/element` import를 `@orioncactuscorp/ui/scss/foundations/atomic`으로 변경하세요.
  - spring preset CSS token이 필요하면 `@orioncactuscorp/ui/scss/foundations/motion`도 함께 import하세요.
  - `--oc-element-radius-*`는 `--oc-atomic-radius-*`로 변경하세요.
  - `--oc-element-width-*`는 `--oc-atomic-width-*`로 변경하세요.
  - `--oc-element-blur-*`는 `--oc-atomic-blur-*`로 변경하세요.
  - `--oc-element-header-height`는 제거되었습니다. 앱 또는 Header 레벨에서 정의하세요.
  - `--oc-element-overlay-*`는 제거되었습니다. `Interaction` 컴포넌트의 `--oc-interaction-opacity-hover`, `--oc-interaction-opacity-focus`, `--oc-interaction-opacity-active` contract를 사용하세요.
  - `--oc-element-ease-spring-*`는 제거되었습니다. `--oc-spring-*` 또는 SCSS `oc-spring(...)` API를 사용하세요.
  - `--oc-element-accent-color`는 제거되었습니다. `Badge` accent color override에는 `--oc-badge-accent-color`를 사용하세요.

### Patch Changes

- 6c77a77: iOS 자동완성 상태에서 Field 기반 TextInput, TextArea, Select의 radius와 stroke surface가 유지되도록 개선합니다.

### Migration Notes

- 없음

## 0.8.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.7.1..HEAD`_

#### Other

- `d6adfe1` Divider 여백 제어 개선 (#30)
- `cdca65e` Field 컨트롤 터치 영역 개선 (#31)
- `8410cfe` 사이트 아키텍처 Agent 문서 추가 (#32)
<!-- generated:end -->

### Minor Changes

- d6adfe1: Divider에 `spacing` prop을 추가합니다.

  Migration Notes
  - `spacing='normal'`은 기존 기본 여백을 유지합니다.
  - `spacing='none'`으로 Divider 외부 여백을 제거할 수 있습니다.
  - `spacing`에 CSS variable 문자열 또는 number 값을 전달해 orientation에 맞는 여백을 조정할 수 있습니다.
  - 기존 `--oc-divider-margin-block`, `--oc-divider-margin-inline` contract는 `--oc-divider-spacing`으로 대체됩니다.

### Patch Changes

- cdca65e: TextInput, TextArea, Select의 네이티브 컨트롤 터치 영역과 slot 레이아웃 동작을 개선합니다.

### Migration Notes

- Divider의 기존 `--oc-divider-margin-block`, `--oc-divider-margin-inline` contract는 `--oc-divider-spacing`으로 대체됩니다.
- 기존 기본 여백은 `spacing='normal'`에서 유지됩니다.
- Divider 외부 여백 제거는 `spacing='none'`, 사용자 지정 여백은 CSS variable 문자열 또는 number 값으로 지정할 수 있습니다.

## 0.7.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.7.0..HEAD`_

#### Fixes

- `ba2a2c0` fix(agent): align migration manifest version

#### Documentation

- `a8a8282` docs: require agent manifest version checks
<!-- generated:end -->

### Patch Changes

- 0.7.0 package artifact의 agent migration manifest version mismatch를 보정합니다.

  Migration Notes
  - `packages/ui/agent/migration-manifest.json.packageVersion`을 package version과 동일하게 유지
  - consumer Agent는 `0.7.1`부터 package artifact 내부 manifest version을 신뢰 가능

### Migration Notes

- 없음

## 0.7.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.6.8..HEAD`_

#### Refactors

- `b2188a4` refactor(field): consolidate field control styles

#### Documentation

- `b95b5a1` docs: update component documentation
- `9b18a90` docs: add public surface checklist

#### Other

- `dc64ffb` ActionArea 추가 및 모달 액션 영역 개선 (#25)
- `ac3e340` 필드 컨트롤 콘텐츠 슬롯 추가 (#26)
- `234f2a1` 컴포넌트 마이너 개선 (#27)
- `f84fb2a` Montage 아이콘 세트 추가 (#28)
- `afdd3d3` 필드 컨트롤 surface 클릭 동작 개선 (#29)
<!-- generated:end -->

### Minor Changes

- dc64ffb: ActionArea와 ActionAreaButton을 추가하고 ModalFooter의 ActionArea spacing contract를 정리합니다.

  Migration Notes
  - Modal 하단 버튼 조합은 ModalFooter 내부에서 ActionArea를 사용하는 방식 권장
  - Modal slot별 x spacing CSS 변수 추가: `--oc-modal-header-space-x`, `--oc-modal-container-space-x`, `--oc-modal-footer-space-x`
  - ModalFooter 내부 ActionArea에 `--oc-action-area-padding-x`, `--oc-action-area-padding-y`, `--oc-action-area-padding-bottom` 주입

- f84fb2a: montage 보조 아이콘 세트를 추가합니다.

  Migration Notes
  - montage 아이콘은 `@orioncactuscorp/ui/icons/montage` subpath에서 사용
  - 기본 icon set은 `orioncactus` 유지
  - montage 아이콘은 루트 barrel export에 포함하지 않음

- f84fb2a: SvgIcon과 공통 IconProps를 non-interactive visual primitive 계약으로 정리합니다.

  Migration Notes
  - `SvgIcon`과 아이콘 컴포넌트의 직접 `onClick` 사용 제거
  - 클릭 가능한 아이콘은 `IconButton`, `Button` icon prop 또는 상위 interactive 컴포넌트 사용
  - 의미 있는 아이콘은 `role="img"`와 `aria-label` 또는 `aria-labelledby` 사용
  - 기본 아이콘 크기 `24px` 유지

### Patch Changes

- ac3e340: TextInput, TextArea, Select의 content slot primitive와 field control slot 사용 예시를 보강합니다.

  Migration Notes
  - TextInputContent public primitive 추가
  - TextInput leading/trailing slot에서 TextInputContent 사용 권장
  - TextInput leading/trailing slot selector를 `leading-content`, `trailing-content`로 정리
  - SelectContent public primitive 및 Select leading/trailing slot 추가
  - TextAreaContent public primitive 및 TextArea leading/trailing slot 추가
  - TextInputContent, SelectContent, TextAreaContent icon variant padding 추가
  - TextInputContent, SelectContent, TextAreaContent icon variant `aria-hidden` 기본값 추가
  - TextArea `className`, `style`은 native textarea에 적용되며 wrapper 커스터마이징은 `containerClassName`, `containerStyle` 사용
  - TextArea leading/trailing content는 TextArea content surface 내부에서 column layout으로 배치
  - 기존 TextInput `leading`, `trailing`, `trailingInteractive` API 유지

- afdd3d3: TextInput, TextArea, Select의 content surface 클릭이 native control focus로 위임되도록 개선합니다.

  Migration Notes
  - TextInput, TextArea, Select의 content surface 클릭 시 내부 native control focus 보장
  - interactive trailing content, native button/link/control, disabled control은 focus delegation 대상에서 제외
  - Select는 브라우저가 `showPicker`를 지원하는 경우 content surface 클릭으로 native picker 열기 시도

- 234f2a1: TextInput, TextArea, Select의 field control surface contract를 통합합니다.

  Migration Notes
  - TextInput, TextArea, Select의 stroke/background/outline 내부 CSS 변수를 `--oc-field-control-*`로 통합
  - invalid 기본 stroke에 1.5px inset stroke와 WebKit DPR 보정 적용
  - invalid focus 상태는 기존 2.5px focus stroke contract 유지

- 234f2a1: Modal, Cell, Button의 기본 시각 contract를 보완합니다.

  Migration Notes
  - Modal과 Cell의 상속 텍스트 색상에 `--oc-color-theme-label-normal` 적용
  - Button icon-only 상태에 정사각 control size 적용
  - Button icon-only와 fullWidth 조합은 fullWidth contract 우선 유지

- 234f2a1: TextInput invalid 상태의 stroke 색상 투명도를 조정합니다.

  Migration Notes
  - TextInput invalid stroke에 `--oc-color-theme-status-negative` alpha 35 적용
  - TextInput invalid focus outline 색상은 기존 negative 원색 유지

### Migration Notes

- 없음

## 0.6.8

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.6.7..HEAD`_

#### Other

- `5d403b0` 모달 바텀시트 터치 스크롤 보정 (#23)
<!-- generated:end -->

### Patch Changes

- 5d403b0: Modal BottomSheet의 scrollable body가 top에서 시작한 touch drag-dismiss 제스처 동안에만 rubber-band로 함께 움직이지 않도록 overscroll을 차단합니다.

  Migration Notes
  - 없음

### Migration Notes

- 없음

## 0.6.7

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.6.6..HEAD`_

#### Other

- `4ed1bc7` 모달 터치 스크롤 handoff 보정 (#22)
<!-- generated:end -->

### Patch Changes

- 4ed1bc7: Modal BottomSheet의 touch content drag가 scrollTop 0에서 native body overscroll을 먼저 차단하고, 내부 스크롤에서 sheet drag로 넘어갈 때 handoff 기준점을 재설정하도록 보정합니다. React passive touchmove 위임을 우회하기 위해 open bottom sheet에 non-passive native touchmove listener를 사용합니다.

  Migration Notes
  - 기존 Modal API 변경 없음
  - touch device에서 scrollable Modal body를 아래로 끌 때 body rubber-band보다 sheet drag가 우선됨
  - scrolled body는 내부 스크롤을 우선하며 top 도달 후 sheet drag로 전환됨

### Migration Notes

- 없음

## 0.6.6

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.6.5..HEAD`_

#### Other

- `6a0151c` 모달 터치 드래그 닫기 보정 (#21)
<!-- generated:end -->

### Patch Changes

- 6a0151c: Modal BottomSheet가 실제 touch 입력에서 pointer cancel 이후에도 header/handle 및 scrollTop 0 content drag-dismiss를 처리하도록 보정합니다.

  Migration Notes
  - 기존 Modal API 변경 없음
  - `canCloseAttempt`/`onCloseAttempt` drag-dismiss guard 의미 유지
  - mobile/touch content drag는 body scroll이 top인 경우 sheet drag로 전환되며, scrolled body는 내부 scroll을 우선

## 0.6.5

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.6.4..HEAD`_

#### Other

- `9bce29e` 컴포넌트 selector contract 정리 (#19)
- `130ba90` 모달 바텀시트 드래그 개선 (#20)
<!-- generated:end -->

### Patch Changes

- 9bce29e: Legacy compatibility selector 목록과 제거 정책을 Agent artifact로 문서화합니다.

  Migration Notes
  - `agent/selector-contract.md`를 추가해 consumer customization selector, provider-owned 예외 attr, legacy compatibility attr replacement를 정리합니다.
  - legacy attr은 호환 출력으로만 유지하며 새 consumer styling target으로 사용하지 않습니다.
  - legacy attr 제거는 patch/minor에서 진행하지 않고, 명시적으로 승인된 breaking/major migration 후보로만 다룹니다.

- 130ba90: Modal bottom sheet drag now applies resistant downward movement when close guards prevent drag dismissal.

  Migration Notes
  - `canCloseAttempt`가 `reason: 'drag-dismiss'`를 차단하는 BottomSheet는 drag 중 닫힘 거리까지 그대로 따라가지 않고 제한된 overshoot로 반응함
  - drag-dismiss 허용 여부는 drag 세션 중 한 번 미리 확인되며, `onCloseAttempt`는 실제 release 또는 dismiss 경로에서만 호출됨

- 130ba90: ModalRoot now supports `canCloseAttempt` for side-effect-free close guards, and drag dismiss checks use it before release instead of calling `onCloseAttempt` during movement.

  Migration Notes
  - drag 중 close 가능 여부를 미리 제한해야 하는 consumer는 `onCloseAttempt`와 같은 조건을 `canCloseAttempt`에도 전달
  - `onCloseAttempt`는 drag move 중에는 호출되지 않고 release 또는 실제 dismiss 경로에서만 호출

- 9bce29e: Modal bottom placement now uses `--oc-modal-bottom-top-clearance` to reserve top viewport space before sizing the sheet.

  Migration Notes
  - bottom Modal의 상단 여백 기준이 `--oc-space-section-padding-viewport-y`에서 `--oc-modal-bottom-top-clearance`로 변경됨
  - 기본값은 `4rem`이며, 앱 header 높이를 반영해야 하는 consumer는 `--oc-modal-bottom-top-clearance: max(4rem, var(--app-header-height));` 형태로 override 가능

- 9bce29e: Agent artifact와 source guard가 component-owned selector의 `data-oc-*` namespace 정책을 명시합니다.

  Migration Notes
  - consumer customization은 `data-oc-component`, component-owned `data-oc-*` visual/state selector, `data-oc-part` 조합을 기준으로 합니다.
  - CSS Module hash class, legacy compatibility attr, 취약한 DOM depth selector에 의존하지 않도록 agent artifact를 갱신합니다.
  - component-owned selector attr과 고정 accessibility attr이 consumer rest props로 덮이지 않도록 source authoring 규칙을 명시합니다.
  - Base UI attr(`data-side`, `data-starting-style`, `data-ending-style`)와 foundation `data-theme`는 예외 계약으로 유지합니다.

- 130ba90: Modal bottom sheet content drag now follows pointer-specific targets: touch can drag from content, while mouse and pen input drag from the sheet header or handle.

  Migration Notes
  - desktop/fine pointer에서 `drag="content"` BottomSheet의 body content 영역 드래그가 더 이상 sheet drag를 시작하지 않음
  - mobile/touch에서는 기존 content drag를 유지하며, body scroll이 top이 아닐 때는 내부 스크롤을 우선함
  - header/handle에서 시작한 drag는 body scroll lock 상태와 관계없이 sheet drag로 처리됨

- 9bce29e: Public component root elements expose stable `data-oc-component` selectors alongside existing `data-oc-part` slot selectors.

  Migration Notes
  - 신규 `data-oc-component` selector contract 추가
  - 기존 API, className, `data-oc-part` contract 변경 없음

- 9bce29e: Public 컴포넌트가 size, variant, appearance, viewport, invalid 상태 같은 시각 prop을 안정적인 `data-oc-*` selector로 노출합니다.

  Migration Notes
  - `Button`, `Badge`, `TextButton`, `Divider`, `Loading`, `IconButton`, `BackgroundIconButton`, `Checkbox`, `Radio`, `Switch`, `Background`, `SectionHeader`, `MenuContent`, `ModalContent`가 `data-oc-size`, `data-oc-variant`, `data-oc-appearance`, `data-oc-viewport` 같은 시각 prop selector와 관련 상태 selector를 노출합니다.
  - `TextInput`, `TextArea`, `Select`가 invalid 상태일 때 `data-oc-invalid="true"`를 노출합니다.
  - `Checkbox`, `TextInput`, `ScrollArea`가 `data-oc-indeterminate`, `data-oc-interactive`, `data-oc-scroll`, `data-oc-scroll-container`, `data-oc-orientation`, `data-oc-state` 같은 namespaced internal selector를 노출하며 기존 호환 attr은 유지합니다.
  - `Loading`의 `role="status"`와 `aria-live="polite"` 기본 접근성 의미는 consumer prop으로 덮이지 않도록 유지합니다.
  - 기존 className, `data-oc-component`, `data-oc-part`, legacy `SectionHeader` `data-size` / `data-viewport` 계약은 유지합니다.

### Migration Notes

- 없음

## 0.6.4

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.6.3..HEAD`_

#### Other

- `e35c0bf` 선택 컨트롤 드래그 방지 및 Modal 여백 정리 (#17)
<!-- generated:end -->

### Patch Changes

- e35c0bf: CheckMark, Checkbox, Radio 라벨의 WebKit 텍스트 선택을 방지합니다.

  Migration Notes
  - 없음

- e35c0bf: Modal body container의 세로 여백 contract를 `--oc-modal-space-y`, `--oc-modal-container-space-y`, `--oc-modal-container-space-top`, `--oc-modal-container-space-bottom`으로 분리하고 footer가 있을 때 container 하단 여백을 제거합니다.

  Migration Notes
  - Modal body container 기본 상단 여백이 header 높이만 반영하도록 변경됨
  - footer가 있는 Modal body container의 하단 여백이 footer 영역으로 이관됨

### Migration Notes

- 없음

## 0.6.3

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.6.2..HEAD`_

- 생성할 commit log 없음
<!-- generated:end -->

### Patch Changes

- Agent migration artifact의 package version metadata를 실제 배포 버전과 동기화합니다.

  Migration Notes
  - 없음

### Migration Notes

- 없음

## 0.6.2

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.6.1..HEAD`_

#### Other

- `6acb6e4` Mobile-first SCSS 규칙 문서화 (#16)
- `5c3eb69` VS Code CSS 변수 자동완성 artifact 추가 (#15)
- `b252e2e` responsive foundation stops 분리 (#14)
<!-- generated:end -->

### Patch Changes

- b252e2e: responsive.config에서 typography와 spacing의 active stop range를 별도로 설정할 수 있도록 `$oc-responsive-typo-stops`, `$oc-responsive-space-stops` 옵션을 추가했습니다. spacing에는 두 mode Figma Viewport를 대응할 수 있는 `$oc-responsive-space-profile` stepped-points profile도 추가했습니다.

  Migration Notes
  - 기존 `$oc-responsive-stops`만 사용하는 consumer는 변경 없음
  - typography 또는 spacing만 다른 responsive stop range가 필요하면 foundation별 stops 옵션 사용
  - spacing token의 base/media point 출력이 필요하면 `$oc-responsive-space-profile` 사용
  - `$oc-space-overrides`에서 stop 값을 `null`로 지정하면 해당 stop은 정의되지 않은 것으로 취급

- 5c3eb69: VS Code CSS variable 자동완성을 위한 `dist/vscode/oc-ui-vars.css` package artifact를 추가합니다.

  Migration Notes
  - `phoenisx.cssvar` 확장을 사용하는 consumer는 `.vscode/settings.json`의 `cssvar.files`에 `./node_modules/@orioncactuscorp/ui/dist/vscode/oc-ui-vars.css`를 추가하면 설치된 oc-ui 버전의 foundation `--oc-*` token 자동완성을 사용할 수 있음

### Migration Notes

- 기존 `$oc-responsive-stops`만 사용하는 consumer는 변경 없음
- typography 또는 spacing만 다른 responsive stop range가 필요하면 foundation별 stops 옵션 사용
- spacing token의 base/media point 출력이 필요하면 `$oc-responsive-space-profile` 사용
- `$oc-space-overrides`에서 stop 값을 `null`로 지정하면 해당 stop은 정의되지 않은 것으로 취급
- `phoenisx.cssvar` 확장을 사용하는 consumer는 `.vscode/settings.json`의 `cssvar.files`에 `./node_modules/@orioncactuscorp/ui/dist/vscode/oc-ui-vars.css`를 추가하면 설치된 oc-ui 버전의 foundation `--oc-*` token 자동완성을 사용할 수 있음

## 0.6.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.6.0..HEAD`_

#### Documentation

- `c44b9fb` docs(skill): add ui release workflow
- `c9ced18` docs(release): align agent artifact versions
<!-- generated:end -->

### Patch Changes

- Agent artifact version metadata를 package version과 동기화하고 consumer migration 예시 버전을 placeholder로 명확히 정리합니다.

  Migration Notes
  - 없음

### Migration Notes

- 없음

## 0.6.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.5.3..HEAD`_

#### Documentation

- `2e5ca55` docs: update SCSS grouping guidelines

#### Maintenance

- `db2c070` ci(release): gate release workflow by commit prefix

#### Other

- `e2774e5` Storybook 다크 모드 문서 테마 동기화 (#12)
- `844ed2e` SectionHeader 컴포넌트 추가 (#11)
- `282fabb` Modal 컴포넌트 추가 및 BottomSheet 인터랙션 정리 (#13)
<!-- generated:end -->

### Minor Changes

- 282fabb: `Modal` compound component를 추가합니다.

  Migration Notes
  - 신규 API: `Modal`, `ModalRoot`, `ModalTrigger`, `ModalContent`, `ModalHeader`, `ModalBody`, `ModalFooter`, `ModalClose`
  - 신규 close guard API: `ModalRoot`의 `onCloseAttempt`는 닫기 버튼, backdrop, outside press, escape key, drag dismiss 같은 닫힘 시도를 하나의 contract로 전달하며 `false`를 반환하면 닫힘을 막습니다.
  - 신규 `data-oc-*` contract: `data-oc-part="backdrop|viewport|bottom-fill|surface|header|handle|header-inner|header-leading|header-title|header-trailing|close|body|body-container|footer"`
  - 신규 CSS 변수 contract: `--oc-modal-header-height`, `--oc-modal-footer-height`, `--oc-modal-peek-height`, `--oc-modal-sheet-height`, `--oc-modal-translate-y`, `--oc-modal-overshoot-fill-height`, `--oc-modal-backdrop-opacity`
  - `variant="adaptive"`는 모바일에서 BottomSheet, 데스크톱에서 Popup 형태로 동작합니다.
  - BottomSheet는 `md` 이하에서 size와 무관하게 full width로 표시되고, `min md` 이상에서는 Popup과 동일한 size별 max-width를 사용합니다.
  - `ModalContent`의 기본 drag 동작은 `content`이며, BottomSheet에서 본문 영역을 드래그해 이동할 수 있습니다.
  - BottomSheet의 `presentationState="peeked"`는 modal trap을 해제한 docked panel 상태이며, 실제 닫힘은 `open={false}`입니다. `peekable`을 켠 경우에만 닫기 전에 peeked 상태로 걸치며, `peekHeight`를 생략하면 Header 높이를 peek 높이로 사용합니다.
  - BottomSheet는 최대로 열린 상태에서 위로 드래그하거나 peeked 상태에서 아래로 드래그하면 저항감 있는 overshoot를 제공하고, release 시 유효한 snap 위치로 복귀합니다.
  - BottomSheet overshoot fill은 BottomSheet surface와 동일한 size별 width를 따릅니다.
  - BottomSheet drag 중 backdrop opacity는 inline `opacity`가 아니라 `--oc-modal-backdrop-opacity`로 제어되어 close ending transition을 덮지 않습니다.
  - BottomSheet를 짧게 빠르게 아래로 드래그하면 닫히지 않고 원위치로 복귀하며, 닫힘 거리까지 내려간 경우에는 하단으로 settle한 뒤 닫힙니다.
  - `onCloseAttempt`가 BottomSheet drag dismiss를 막으면 닫히지 않고 기존 위치로 복귀합니다. `disablePointerDismissal`을 켜면 drag dismiss를 close 후보로 보지 않고 아래쪽 resistant overshoot로 처리합니다.
  - BottomSheet에 `snapPoints`가 있으면 빠른 drag release는 기본적으로 방향 기준 인접 snap point로 이동하되, drag 위치가 여러 snap point를 지나친 경우 가장 멀리 지나친 snap point로 이동합니다.
  - BottomSheet drag release transition은 vaul drawer와 동일한 `0.5s cubic-bezier(0.32, 0.72, 0, 1)` easing을 사용합니다.
  - Popup surface의 닫힘 transition은 `0.2s ease-in`을 사용하며, backdrop과 BottomSheet motion은 기존 easing을 유지합니다.
  - Header는 content 위에 overlay되고, Background의 `strong` variant와 `elevated-normal` back color를 사용해 compact backdrop blur를 제공합니다.
  - `Body` ScrollArea vertical scrollbar는 Header overlay 아래에서 시작합니다.
  - Header handle은 BottomSheet placement에서 `drag="handle"` 또는 `drag="content"`일 때만 렌더링됩니다.
  - `Footer`는 향후 ActionArea 도입을 위한 하단 액션 슬롯으로 `Body` 외부에 렌더링됩니다.

- 844ed2e: `SectionHeader` 컴포넌트를 추가합니다.
  - `size`: `large` | `medium` | `small` | `xsmall` (기본값: `medium`)
  - `viewport`: `auto` | `mobile` | `desktop` (기본값: `auto`) — md 브레이크포인트 기준 자동 반응형, 또는 고정 모드
  - `as`: `h1`~`h6` heading 태그 override (size별 기본값: large→h2, medium→h3, small→h4, xsmall→h5)
  - `headingSlot`: 제목 옆 슬롯 (max-height를 heading line-height에 맞춰 자동 정렬)
  - `trailingSlot`: 우측 슬롯 (동일)
  - `description`: 부가 설명 (`xsmall`에서는 렌더링되지 않음)

### Migration Notes

- `Modal`, `SectionHeader` 신규 public API가 추가됩니다.
- `ModalRoot`의 `onCloseAttempt`, `ModalContent`의 BottomSheet 관련 prop, Modal CSS 변수와 `data-oc-*` slot contract를 consumer에서 사용할 수 있습니다.
- 기존 API 제거 또는 필수 consumer 수정 사항은 없습니다.

## 0.5.3

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.5.2..HEAD`_

#### Fixes

- `f7a0ea1` fix(fieldset): align layout spacing with content slot
<!-- generated:end -->

### Patch Changes

- f7a0ea1: FieldsetContent를 추가하고 Fieldset의 기본 layout spacing을 Field와 같은 label/control gap contract로 정렬합니다.

  Migration Notes
  - `FieldsetContent`를 public slot으로 추가합니다.
  - `Fieldset`은 native `fieldset`/`legend` 렌더링과 Safari 호환성을 유지하면서 legend 이후 children을 content slot으로 감싸 `Field`와 동일한 `--oc-space-item-gap-xsmall` spacing contract를 사용합니다.

### Migration Notes

- `FieldsetContent`를 public slot으로 추가합니다.
- `Fieldset`은 native `fieldset`/`legend` 렌더링과 Safari 호환성을 유지하면서 legend 이후 children을 content slot으로 감싸 `Field`와 동일한 `--oc-space-item-gap-xsmall` spacing contract를 사용합니다.

## 0.5.2

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.5.1..HEAD`_

#### Fixes

- `64ade6f` fix(fieldset): align legend label styling
<!-- generated:end -->

### Patch Changes

- 64ade6f: FieldLegend의 시각 스타일을 FieldLabel과 같은 label contract로 정렬합니다.

  Migration Notes
  - `FieldLegend`는 semantic element로 `<legend>`를 유지하지만, CSS Module slot class는 FieldLabel과 같은 `label` 스타일을 사용합니다.
  - 기존 `FieldLegend`의 typography weight와 label color가 `FieldLabel`과 동일하게 바뀝니다.

### Migration Notes

- 없음

## 0.5.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.5.0..HEAD`_

#### Other

- `4f920c3` oc-website 마이그레이션 지원 컴포넌트 정리 (#10)
<!-- generated:end -->

### Patch Changes

- 4f920c3: ScrollArea의 root/window 스크롤 호환성을 개선하고 터치 디바이스 fallback을 안정화합니다.

  Migration Notes
  - 기존 ScrollArea API 변경 없음
  - root 모드에서 container overflow가 window 스크롤을 가로막지 않도록 조정
  - ScrollArea scrollbar selector는 legacy `[data-label='scrollbar']`가 아니라 `[data-oc-part='scrollbar-vertical']`, `[data-oc-part='scrollbar-horizontal']` contract를 기준으로 갱신 필요

- 4f920c3: 배포 산출물에서 React client component directive가 유지되도록 빌드 후처리를 추가합니다.

  Migration Notes
  - 없음

- 4f920c3: FieldLegend에 required 표시 contract를 추가합니다.

  Migration Notes
  - `FieldLegend`는 `required` prop을 받아 `[data-oc-part='required-mark']` slot으로 필수 표시를 렌더링합니다.
  - 여러 control을 하나의 필수 그룹으로 표현하는 경우 `FieldLabel`이 아니라 `Fieldset`과 `FieldLegend required`를 사용해야 합니다.
  - 실제 native validation 의미는 각 필수 control의 `required` attribute로 전달해야 합니다.

- 4f920c3: FieldLabel에 required 표시 contract를 추가합니다.

  Migration Notes
  - `FieldLabel`은 `required` prop을 받아 `[data-oc-part='required-mark']` slot으로 필수 표시를 렌더링합니다.
  - 실제 native validation 의미는 기존처럼 `TextInput`, `TextArea`, `Select` 같은 control의 `required` attribute로 전달해야 합니다.

### Migration Notes

- 없음

## 0.5.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.4.2..HEAD`_

#### Features

- `a4a3db5` feat(tokens): add SCSS theme selection config

#### Other

- `13ab787` website 공용 컴포넌트 승격 (#7)
- `bd6ef71` SCSS 테마 selection config 대응 (#8)
<!-- generated:end -->

### Minor Changes

- 13ab787: website 공용 UI 후보를 package component surface로 확장합니다.
  - `Badge`, `Background`, `Divider`, `Loading`, `Cell`, `CellItem` 추가
  - `Field`, `FieldLabel`, `FieldControl`, `FieldMessage`, `FieldErrorMessage` 추가
  - `Fieldset`, `FieldLegend`, `FieldGroup` 추가
  - `Checkbox`, `CheckMark`, `Radio`, `Switch`, `TextInput`, `TextArea`, `Select` 추가
  - `MenuRoot`, `MenuTrigger`, `MenuContent`, `MenuItem`, `MenuSeparator` 추가
  - `TooltipProvider`, `TooltipRoot`, `TooltipTrigger`, `TooltipContent` 추가
  - `ScrollArea`, `ScrollAreaContainer` 추가
  - `Background`의 `frontColor`, `backColor`, `Cell`의 `padding`, `Divider`의 `variant` prop 추가
  - `Divider`는 `variant`만 public appearance prop으로 제공합니다.
  - `Loading`의 `small`, `medium`, `large`, `custom` size contract 추가
  - `Checkbox`의 `indeterminate` 시각 상태가 `checked`보다 우선하도록 보정
  - `Switch` track을 `Checkbox`와 같은 body1-height control slot 기준으로 정렬
  - `Switch` interaction layer를 track 크기에 맞추고 thumb stacking과 pointer event 처리를 보정
  - `TextInput`, `TextArea`, `Select` stroke와 focus outline을 inset box-shadow 기반으로 보정
  - `IconCaretDown`, `IconCaretUp`을 추가하고 `Select` indicator를 caret icon slot 구조로 보정
  - `inset-stroke` SCSS mixin을 추가하고 fractional surface stroke 보정을 중앙화
  - `Cell`, `MenuItem`의 인접 item separator를 structural border 기반으로 보정
  - `TextField`는 `TextInput`, `TextareaField`는 `TextArea`, `SelectField`는 `Select`로 component/export 이름 확정
  - `Button`에 `loading` prop 추가 및 loading 중 activation 차단
  - `Button` loading indicator의 색상, 크기, 중앙 정렬을 버튼 state/size contract에 맞게 보정
  - `Button` anchor loading 중 middle-click activation 차단
  - `FieldControl`의 ARIA 연결이 실제 렌더링된 label/message만 참조하도록 보정
  - `MenuTrigger`가 기본 trigger 렌더링에서도 `nativeButton` prop을 전달하도록 보정
  - `ScrollArea`의 global scrollbar style cleanup을 multi-instance 기준으로 보정
  - `@base-ui-components/react`를 runtime dependency로 추가

  ### Migration Notes
  - website 원본의 layered background, badge overlay, loading stroke animation, custom scrollbar, touch tooltip 동작을 package component contract로 유지합니다.
  - `Loading` 기본 크기는 website 원본과 같은 `large`이며, `large=48px`, `medium=24px`, `small=16px`입니다.
  - `Loading`은 기본적으로 `currentColor`를 따르며, `Button` 내부 loading indicator는 버튼 size와 disabled state contract를 따릅니다.
  - `Checkbox`는 `checked`와 `indeterminate`가 동시에 참일 때 mixed 표시를 우선합니다.
  - `CheckMark`는 indeterminate 상태가 없는 check-only checkbox control입니다.
  - `Switch` label은 `Checkbox`와 같은 `data-oc-part="content"` 내부에 렌더링되며 control은 body1-height 기준으로 정렬됩니다.
  - `Switch`의 interaction layer는 track과 같은 크기이며, thumb는 interaction 위에 렌더링되지만 pointer event를 가로채지 않습니다.
  - `TextInput`, `TextArea`, `Select`는 border 대신 inset `box-shadow`로 기본 stroke와 active outline을 표현합니다.
  - `Checkbox`, `Radio`의 1.5px surface stroke는 `inset-stroke` SCSS mixin을 통해 WebKit/DPR 보정을 적용합니다.
  - `Cell`, `MenuItem`의 item 사이 separator는 `box-shadow`가 아니라 인접 item의 `border-block-start`로 표현합니다.
  - `TextField`, `TextareaField`, `SelectField` 이름은 제공하지 않습니다. 각각 `TextInput`, `TextArea`, `Select`를 사용해야 합니다.
  - `Divider`의 선 색상 강도는 `variant`를 사용해야 합니다.
  - `FieldControl`은 `FieldLabel`, `FieldMessage`, `FieldErrorMessage`가 실제 렌더링된 경우에만 해당 id를 ARIA로 연결합니다.
  - website의 `InputGroup`, `CheckboxGroup`, `RadioGroup`은 canonical API로 승격하지 않습니다.
  - 단일 control label/helper/error 연결은 `Field` compound family를 사용해야 합니다.
  - checkbox/radio/switch option 묶음은 `Fieldset` 또는 migration alias인 `FieldGroup`을 사용해야 합니다.
  - 기존 `TextInput` wrapper는 `Field`와 `TextInput` 또는 `TextArea` 조합으로 치환해야 합니다.
  - `Menu`와 `Tooltip`은 Base UI 기반이지만 Base UI 타입을 consumer API로 직접 노출하지 않습니다.

- a4a3db5: color theme 선택 SCSS 설정 추가

  `foundations/color.config` 모듈을 추가해 SCSS 빌드 단에서 light/dark theme emit 여부와 `prefers-color-scheme` 미디어쿼리 사용 여부를 선택할 수 있도록 한다.
  - `$oc-color-themes` (`!default`: `(light, dark)`) — 둘 중 하나만 두면 해당 theme의 `:root`/`[data-theme]` ruleset만 emit. 빈 값이거나 `light`/`dark` 외 값이 들어오면 `@error`.
  - `$oc-color-system-preference` (`!default`: `true`) — `false`로 설정하면 `@media (prefers-color-scheme: dark)` ruleset이 빠지고 attribute 토글만 남음. `themes`가 `(dark)` 단독이면 `:root`가 곧장 dark이므로 이 옵션은 무시됨.

  기존 consumer는 변경 없음. 사용 예:

  ```scss
  @use '@orioncactuscorp/ui/scss/foundations/color.config' with (
    $oc-color-themes: (
      light,
    )
  );
  @use '@orioncactuscorp/ui/scss/index';
  ```

  ### Migration Notes
  - 없음

## 0.4.2

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.4.0..HEAD`_

#### Fixes

- `bd6fadb` fix(tokens): compile alpha theme variables
<!-- generated:end -->

### Patch Changes

- Button primary interaction overlay를 `0.3.1` 동작에 맞춥니다.

  ### Migration Notes
  - 없음

- Agent migration manifest의 package version 표기를 `0.4.2`로 맞춥니다.

  ### Migration Notes
  - 없음

## 0.4.1

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.4.0..HEAD`_

- 생성할 commit log 없음
<!-- generated:end -->

### Patch Changes

- Foundation color theme CSS에서 `oc-alpha(...)` Sass helper가 raw CSS 함수처럼 남지 않도록 컴파일합니다.

  ### Migration Notes
  - 없음

- Agent migration manifest의 package version 표기를 `0.4.1`로 맞춥니다.

  ### Migration Notes
  - 없음

## 0.4.0

### Changes

<!-- generated:start -->

_Commit range: `@orioncactuscorp/ui@0.3.1..HEAD`_

#### Features

- `60b738e` feat(button): add Figma solid and outlined variants
- `a47fa46` feat(button): add default surface
- `fc1f090` feat(typo): add default font family token
- `b30d374` feat(tokens): add global color palette
- `3d99493` feat(tokens): refine theme label colors
- `310a7c5` feat(tokens): add accent global color steps
- `a5e4766` feat(tokens): add accent and inverse theme colors
- `44b7d17` feat(tokens): add static transparent tokens

#### Fixes

- `8d97f6e` fix(button): expose default variant

#### Refactors

- `de21eca` refactor(typo): make font family token configurable
- `56fcd31` refactor(tokens): migrate theme color aliases
- `ce5e2fc` refactor(tokens): align status theme aliases
- `36625a1` refactor(scss): add alpha color helper
- `e5c6664` refactor(button): align button family prop contracts

#### Documentation

- `1dd9b2a` docs: document responsive foundation profiles (#5)
- `8ba6ba9` docs: remove completed todo items
- `d6f3b5c` docs: organize component expansion TODOs
- `bb2d6eb` docs(figma): document design translation pipeline
- `d3044ed` docs(figma): add semantic DOM mapping guidance
- `b56f087` docs(agent): define consumer convention migration
- `3e8a298` docs(agent): ship consumer convention artifacts
- `e33580f` docs(agent): link consumer convention workflow
- `99e0984` docs(agent): add consumer instruction prompts
- `ed018b1` docs(agent): add component audit guidance
- `779acb0` docs(storybook): show Button source examples
- `b8511d3` docs(agent): add Figma token guardrails
- `2a65e90` docs(todo): note Button loading follow-up
- `9ccda7e` docs(agent): add montage reference priority
- `7216df4` docs(tokens): update color token migration guidance
- `e7e9a69` docs(agents): document release changelog phases
- `a65971e` docs(tokens): prune completed color token notes
- `ae28782` docs(agent): clarify component reference priority
- `593d51d` docs(agents): document PR changeset policy
- `9db0656` docs(agents): document component API contracts

#### Maintenance

- `0576874` chore(release): generate changelog during version bump
- `b7ab8f1` chore(stylelint): align SCSS namespace rule

#### Other

- `8512578` 소비자 시나리오 프리뷰 추가 (#6)
<!-- generated:end -->

### Patch Changes

- Button, TextButton, IconButton, BackgroundIconButton props contract를 native element attribute 기반으로 정리합니다. React 19+ ref prop contract에 맞춰 button family의 forwardRef wrapper를 제거합니다.

### Migration Notes

- `0.3.1`에서 `0.4.0`으로 업데이트할 때는 color token contract 변경을 확인해야 합니다.
- `Button`에 `appearance`, `variant`, `size`, `fullWidth`, `leadingIcon`, `trailingIcon`, `icon` prop이 추가되었습니다.
- `Button`의 기본 `variant`는 `primary`가 아니라 `default`입니다. 기존 primary surface가 필요하면 `variant='primary'`를 명시해야 합니다.
- `Button`의 `variant='secondary'`는 `appearance='solid'`에서 `primary`로 fallback되고, `appearance='outlined'`에서 secondary outlined surface로 동작합니다.
- `Button`의 `children`은 optional이 되었고 icon-only 사용이 가능합니다. `icon`만 사용하는 경우 `aria-label` 또는 `aria-labelledby`를 함께 제공해야 합니다.
- `href`가 있는 disabled `Button`은 anchor에 `aria-disabled='true'`와 `tabIndex={-1}`를 적용하고 click 기본 동작을 막습니다.
- `href`가 있는 Button은 anchor native attribute를, 없는 Button은 button native attribute를 기준으로 타입 검사합니다.
- TextButton은 `as` 값에 맞는 anchor/button/span native attribute를 기준으로 타입 검사합니다.
- IconButton과 BackgroundIconButton은 button native attribute를 기준으로 타입 검사합니다.
- button family ref는 React 19+의 function component ref prop으로 전달합니다.
- `--oc-color-theme-accent-blue` 참조는 `--oc-color-theme-accent-background-blue`로 교체해야 합니다.
- `--oc-color-theme-dimmer` 참조는 `--oc-color-theme-material-dimmer`로 교체해야 합니다.
- `--oc-color-theme-status-positive`, `--oc-color-theme-status-cautionary`, `--oc-color-theme-status-negative`는 accent background alias를 기준으로 정렬되었습니다. 상태 색상을 직접 override하는 consumer는 신규 accent background token과 함께 의도한 값이 유지되는지 확인해야 합니다.
- 신규 accent background/foreground theme token, inverse theme token, global color palette, accent global color step, static transparent token이 추가되었습니다.
- PR #6의 consumer scenario preview 추가는 package runtime migration을 요구하지 않습니다.

## 0.3.1

- responsive foundation의 stepped emitter 전환 지점 계산을 수정했습니다.

## 0.2.0

- `TextButton`, `BackgroundIconButton` 컴포넌트 추가
- `orioncactus` icon set 전체 제공 및 `@orioncactuscorp/ui/icons/orioncactus` subpath export 추가
- root barrel은 기본 API surface 유지를 위해 `IconDefault`만 유지
- `IconButton`, `BackgroundIconButton`의 icon `viewBox` 보존 동작 개선

## 0.1.1

- `Interaction` self-driven overlay 정리 및 keyboard active feedback 보강
- CSS module build artifact 정리 순서 개선
- website consumer 검증을 위한 GitHub Packages patch release

## 0.1.0

- `@orioncactuscorp/ui` 초기 private package 릴리스
- Foundation tokens, reset, SCSS mixins, responsive typography pipeline 추가
- `Button`, `IconButton`, `SvgIcon`, `Interaction`, `IconDefault` 제공
- `orioncactus` 기본 icon set 및 `material-rounded` placeholder subpath 추가
- Storybook, Vitest, Playwright, Next.js example 기반 검증 구성
