# 메뉴 (GNB · 전체메뉴 · 모바일)

| 항목 | 경로 |
|------|------|
| 데모 | `menu.html` |
| CSS | `css/menu.css` |
| JS | `js/menu.js` (vanilla, 의존성 없음) |
| 이미지 | 없음 |

---

## 복사 패키지

```
css/menu.css
js/menu.js
마크업: menu.html
  - header.a11y-header (로고 + .gnb-nav + .btn-all-menu)
  - #allMenuLayer (전체화면 · #wrap 밖 권장)
```

`css/style.css`에 `@import url(menu.css);` 추가하거나 프로젝트 엔트리에서 import.

---

## 구조

```
.a11y-header
  ├─ .a11y-header__logo
  ├─ nav.gnb-nav          ← PC 주메뉴 (≤959px 숨김)
  │    └─ ul.gnb-list
  │         ├─ li.gnb-item > a.gnb-link
  │         └─ li.gnb-item.has-sub
  │              ├─ button.gnb-toggle[aria-expanded][aria-controls]
  │              └─ ul.gnb-sub[hidden]
  └─ button.btn-all-menu[data-all-menu-open]

#allMenuLayer.all-menu-layer   ← PC 전체메뉴 = 모바일 메뉴
  └─ nav.all-menu-nav
       └─ ul.all-menu-list
            ├─ li > a
            └─ li.has-sub
                 ├─ button.all-menu-toggle
                 └─ ul.all-menu-sub
```

---

## 마크업 요점

### 서브 있는 대메뉴 (disclosure)

```html
<li class="gnb-item has-sub">
  <button type="button" class="gnb-toggle"
    aria-expanded="false" aria-controls="gnb-sub-service">
    서비스
    <span class="gnb-toggle__icon" aria-hidden="true"></span>
  </button>
  <ul class="gnb-sub" id="gnb-sub-service" hidden>
    <li><a href="...">하위1</a></li>
  </ul>
</li>
```

- 페이지 이동이 아닌 **열기/닫기**이므로 `<button>` 사용
- 닫힌 서브는 `hidden` → **Tab 순서에서 제외**
- 열린 뒤에만 하위 링크가 순차 Tab

### 전체메뉴 버튼

```html
<button type="button" class="btn-all-menu"
  data-all-menu-open
  aria-expanded="false"
  aria-controls="allMenuLayer">
  <span class="btn-all-menu__label">전체메뉴</span>
</button>
```

### 전체메뉴 레이어

```html
<div id="allMenuLayer" class="all-menu-layer" hidden
  role="dialog" aria-modal="true"
  aria-labelledby="allMenuTitle" tabindex="-1">
  ...
  <button type="button" data-all-menu-close>닫기</button>
  ...
</div>
```

- `#wrap` **밖**에 두면 열릴 때 `#wrap[aria-hidden="true"]`와 충돌하지 않음
- JS가 포커스 트랩 · Esc · 초점 회귀 처리

---

## 반응형

| 구간 | 동작 |
|------|------|
| ≥960px | PC GNB 표시 + 전체메뉴 버튼(전체화면 사이트맵) |
| ≤959px | `.gnb-nav` 숨김 → **전체메뉴 = 모바일 메뉴** |

모바일에서 전체메뉴를 열면 서브는 기본 **접힘**(아코디언). PC 전체메뉴에서는 기본 **펼침**.

---

## 키보드

| 키 | 동작 |
|----|------|
| Tab | 대메뉴 순차. 서브가 열린 항목만 하위 포함 |
| Enter / Space | 서브·전체메뉴 토글 |
| Esc | 열린 서브 닫기 / 전체메뉴 닫기 |

---

## API (선택)

```js
a11yMenuOpen(openerEl);  // 전체메뉴 열기
a11yMenuClose();         // 닫기
```

---

## 접근성 체크

- [ ] hover만으로 서브 열지 않음
- [ ] 닫힌 서브에 `hidden` (또는 동등한 비표시)로 Tab 제외
- [ ] `aria-expanded` / `aria-controls` 연결
- [ ] 전체메뉴: dialog · 모달 · Esc · 초점 회귀
- [ ] 모바일에서 GNB와 전체메뉴가 이중으로 Tab되지 않음 (GNB `display:none`)
- [ ] 스킵 링크 `href`가 실제 `id`와 일치
