# Overlay Stacking

oc-ui의 `--oc-zindex-*` 토큰은 그림자·블러·radius로 표현하는 시각적 elevation이 아니라 브라우저 paint order를 위한 단계입니다. Material elevation의 상대적 계층 개념처럼, 자식 overlay는 전역 숫자만 높이는 대신 자신을 소유한 surface의 stacking context 안에서 위로 올라갑니다.

## 단계

| 토큰            | 기본값 | 의미                                                           |
| --------------- | -----: | -------------------------------------------------------------- |
| `--oc-zindex-0` |   `-1` | 명시적으로 뒤로 보내는 장식·비활성 layer                       |
| `--oc-zindex-1` |    `0` | 기본 document flow와 component 내부 base layer                 |
| `--oc-zindex-2` |   `10` | 같은 layout context 안의 docked·raised control                 |
| `--oc-zindex-3` | `1000` | trigger에 연결된 Menu·popover 같은 transient disclosure        |
| `--oc-zindex-4` | `1400` | Modal·dialog·FloatingWindow처럼 작업 맥락을 소유하는 surface   |
| `--oc-zindex-5` | `1800` | Tooltip·toast처럼 현재 맥락 위에서 전달되는 advisory/status UI |

숫자 간격은 각 단계 안에서 component-owned stack offset을 사용할 여유를 둡니다. 새 component가 생겼다는 이유만으로 다음 전역 단계를 추가하거나 큰 정수를 하드코딩하지 않습니다.

## Owner surface global stack

`Modal`과 `FloatingWindow`/`ModalWindow`는 같은 owner surface global stack에 등록됩니다. 따라서 서로 다른 React tree나 portal에 렌더링되어도 같은 `--oc-zindex-4` 단계 안에서 순서를 공유합니다.

- modal과 `trap-focus`는 modeless보다 위 tier에 유지됩니다.
- 같은 tier에서는 open 순서와 활성화 순서로 bottom-to-top depth를 정규화합니다.
- 각 owner surface는 backdrop depth와 surface depth를 한 쌍으로 예약합니다. backdrop은 `base + 2 × depth`, surface는 `+1`입니다.
- 퇴장 중인 surface는 portal이 unmount될 때까지 stack slot을 유지하므로 닫히는 backdrop이 아래 surface로 내려가지 않습니다.
- Manager 밖의 FloatingWindow도 자동으로 stack에 참여합니다. `stackLevel`은 자동 depth에 더하는 unmanaged 수동 offset이며, Manager 안에서는 manager가 계산한 depth가 우선합니다.

이 규칙은 DOM 순서나 portal 생성 순서에 의존하지 않으며, 교차 배치에서는 실제 `elementFromPoint()`와 pointer/focus 동작으로 검증해야 합니다.

## 상대적 overlay boundary

`ModalContent`와 `FloatingWindowContent`는 자신을 가장 가까운 overlay boundary로 제공합니다. 그 안에서 렌더링된 `MenuContent`와 `TooltipContent`는 별도 설정 없이 해당 surface를 portal container로 사용합니다.

```tsx
<ModalRoot>
  <ModalContent>
    <ModalHeader title='설정' />
    <ModalBody>
      <MenuRoot>
        <MenuTrigger>더보기</MenuTrigger>
        <MenuContent>
          <MenuItem>복제</MenuItem>
        </MenuContent>
      </MenuRoot>
    </ModalBody>
  </ModalContent>
</ModalRoot>
```

이때 Menu는 여전히 `--oc-zindex-3`을 사용하지만 Modal의 stacking context 안에 있으므로 Modal backdrop이나 surface 뒤로 내려가지 않습니다. Tooltip도 같은 방식으로 자기 의미인 `--oc-zindex-5`를 유지합니다. 중첩 surface에서는 가장 가까운 boundary가 우선됩니다.

Modal·Alert처럼 화면 맥락을 소유하는 dialog를 다른 Modal 안에 중첩하면 boundary를 공유하지 않고 형제 배치와 같은 modal 단계에 쌓이며, 각 dialog가 자기 backdrop을 렌더링해 아래 surface를 dim합니다.

surface 밖에서 단독으로 사용하면 기존처럼 document body에 portal됩니다. Shadow DOM이나 별도 overlay root가 필요한 경우 `MenuContent`, `TooltipContent`, `ModalContent`, `FloatingWindowContent`의 `container` prop으로 명시적으로 덮어쓸 수 있습니다. 명시적 `container`는 자동 boundary보다 우선하며, focus trap과 `aria-hidden` 범위도 소비자가 함께 책임져야 합니다.

## Component authoring 규칙

- 화면 맥락을 소유하는 새 portaled surface는 전역 z-index를 올리기 전에 기존 `--oc-zindex-*` 의미 단계에 매핑합니다.
- surface 안에서 다시 열리는 disclosure/advisory overlay는 가장 가까운 owner surface를 portal boundary로 사용합니다.
- Modal의 focus trap 밖에 portal host를 두면 overlay가 inert 또는 `aria-hidden` 처리될 수 있으므로, host는 접근성 tree에서도 owner surface 안에 있어야 합니다.
- DOM 중첩, computed z-index만으로 완료를 판단하지 않고 실제 브라우저의 `elementFromPoint()`와 pointer/keyboard interaction으로 paint order를 검증합니다.
- 그림자·블러·radius 같은 시각적 elevation과 `--oc-zindex-*` paint order를 서로 대체하지 않습니다.
