/* ═══════════════════════════════════════════════════════════════
 * BPack.Components Layout · BPackCore Design Guide (shell.css) 이식
 *
 * 구조: [header] / [snb(nav) | tree-menu | page] / [footer]
 *  - 높이 : grid-template-rows
 *    · footer 없음: var(--bp-layout-header) 1fr
 *    · footer 있음: var(--bp-layout-header) 1fr var(--bp-layout-statusbar)
 *  - 반응형 (≤lg · 1024 px): NavMenu 는 드로어, TreeMenu 숨김
 *
 * 모든 수치는 --bp-* 토큰 참조. 하드코딩 금지.
 * ═══════════════════════════════════════════════════════════════ */

html, body { height: 100%; }

/* ── Wrap (전체 프레임) · viewport 고정 ──────────────────── */
.bp-wrap {
    height: 100vh;       /* 100% 뷰포트 고정 — 내부 스크롤만 허용 */
    /* 모바일 주소창 높이 변화 흡수. 미지원 브라우저는 위 100vh 로 남는다.
       미디어쿼리 밖에 두는 이유 — dvh 는 "지금 보이는 viewport" 라 UI 가 접히지 않는
       환경에서는 vh 와 **같은 값**이다(1440×900 Chrome 실측 900 = 900). 반대로 1024px 를
       넘는 태블릿 가로(iPad 1366 등)도 주소창이 접히므로, 폭으로 자르면 그 환경이 빠진다. */
    height: 100dvh;
    min-height: 0;
    display: grid;
    /* 헤더 행은 데스크톱 값을 그대로 둔다(고정 --bp-layout-header).
       ≤lg 에서만 auto 로 되받는다 — 아래 미디어쿼리 참조.
       ⚠️ 여기서 auto 로 두면 .bp-gnb 가 아닌 **custom Header** 를 넣은 호스트의
       ≥1025px 헤더 높이가 내용 크기로 바뀐다(R2 중간-1). */
    grid-template-rows: var(--bp-layout-header) 1fr;
    background: var(--bp-bg-page);
    color: var(--bp-text-primary);
    font-family: var(--bp-font-ui);
    font-size: var(--bp-size-small);
    overflow: hidden;    /* 외부 스크롤 차단 — Footer 를 viewport 하단에 고정 */
}
.bp-wrap.has-footer {
    grid-template-rows: var(--bp-layout-header) 1fr var(--bp-layout-statusbar);
}

.bp-container {
    display: contents;
}

/* ── Header (GNB) · shell.css §Header ─────────────────── */
.bp-gnb {
    height: var(--bp-layout-header);
    background: var(--bp-bg-surface);
    border-bottom: 1px solid var(--bp-border-light);
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    padding: 0 var(--bp-space-4);
    gap: var(--bp-space-4);
    position: sticky;
    top: 0;
    z-index: var(--bp-z-header);
    min-width: 0;
}

.bp-gnb .bp-gnb-left {
    display: flex;
    align-items: center;
    gap: var(--bp-space-3);
    min-width: 0;
}

.bp-gnb .bp-gnb-box {
    display: flex;
    align-items: center;
    gap: var(--bp-space-2);
    min-width: 0;
}


/* 폴백 로고 래퍼(ServiceLogo 슬롯 미지정 시). 크기를 고정하는 이유 — 스킨이 기본 img 를
   --bp-brand-default-display:none 으로 끄면 래퍼가 크기를 잃어, inset:0 인 스킨 마크가
   0 크기가 되어 사라진다. img 와 같은 크기로 박아 둔다. */
.bp-gnb .bp-gnb-service-logo {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--bp-space-2);
    width: var(--bp-h-md);
    height: var(--bp-h-md);
    flex-shrink: 0;
}
.bp-gnb .bp-gnb-sl {
    width: var(--bp-h-md);
    height: var(--bp-h-md);
    display: grid;
    place-items: center;
}

/* 기본 ServiceLogo (BPack mark) — ServiceLogo 파라미터 미지정 시 렌더.
   F06: 스킨이 --bp-brand-default-display:none 으로 이것을 끄고
   --bp-brand-mark 로 자기 마크를 올린다. 기본값 block 이라 무변화. */
.bp-gnb .bp-gnb-service-logo-img {
    width: var(--bp-h-md);
    height: var(--bp-h-md);
    display: var(--bp-brand-default-display, block);
}
/* 헤더의 스킨 마크. --bp-brand-mark 는 **글리프**(투명 배경) 라는 계약이다 —
   로딩에서는 회전 사각형 위에 얹히고, 여기서는 이 규칙이 그리는 바탕 위에 얹힌다.
   그래서 자산 하나로 두 자리를 다 쓴다. 바탕은 기본 transparent 라 스킨이 없으면 무변화. */
.bp-gnb .bp-gnb-brand-mark {
    position: absolute;
    inset: 0;
    padding: 20%;
    background-color: var(--bp-brand-mark-bg, transparent);
    background-image: var(--bp-brand-mark, none);
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    background-origin: content-box;
    border-radius: var(--bp-radius-md);
    pointer-events: none;
}

.bp-gnb .bp-gnb-logo-light { display: block; }
.bp-gnb .bp-gnb-logo-dark  { display: none; }
[data-theme="dark"] .bp-gnb .bp-gnb-logo-light { display: none; }
[data-theme="dark"] .bp-gnb .bp-gnb-logo-dark  { display: block; }

.bp-gnb .bp-gnb-title {
    font-size: var(--bp-size-small);
    font-weight: var(--bp-weight-bold);
    color: var(--bp-text-primary);
    letter-spacing: var(--bp-tracking-tight);
    white-space: nowrap;
    margin-right: var(--bp-space-2);
}

/* ── Breadcrumb · shell.css §Header breadcrumb ──────── */
.bp-gnb-steps {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--bp-size-small);
    overflow: hidden;
    white-space: nowrap;
    min-width: 0;
}
.bp-gnb-breadcrumb i {
    font-size: 12px;
    color: var(--bp-text-tertiary);
}
.bp-gnb-page {
    padding: 2px 6px;
    border-radius: var(--bp-radius-sm);
    background: transparent;
    color: var(--bp-text-secondary);
    text-decoration: none;
    font-weight: var(--bp-weight-medium);
    transition: color var(--bp-duration-fast);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 240px;
}
a.bp-gnb-page:hover {
    color: var(--bp-text-brand);
}
.bp-gnb-page.current,
.bp-gnb-steps > .bp-gnb-page:last-child {
    background: transparent;
    color: var(--bp-accent-fg);
    font-weight: var(--bp-weight-semibold);
}
/* shell.css §Breadcrumb — 구분자는 슬래시 텍스트 */
.bp-gnb-steps > .sep {
    color: var(--bp-text-tertiary);
    font-weight: var(--bp-weight-regular);
    padding: 0 2px;
    user-select: none;
}

/* ── Header right · 알림 / 테마 / 아바타 ─────────────── */
.bp-gnb .bp-gnb-right {
    display: flex;
    align-items: center;
    gap: var(--bp-space-2);
    justify-self: end;
}
.bp-gnb .bp-gnb-right .bp-gnb-box {
    display: flex;
    align-items: center;
    gap: 4px;
}

/* 우측 버튼 공통 — 겉모양과 **세로 맞춤**만. 가로는 아래 「아이콘 전용」이 정한다.
   ⚠ 여기에 width·display:grid 를 두면 자식이 여럿인 버튼(계정 트리거 등)이
     .bp-btn 의 overflow:hidden 과 겹쳐 **첫 자식만 남기고 잘린다**(F49 실측 — 기준인
     Docs 의 계정 이름·역할·chevron 이 화면에 아예 없었다). 가로는 내용이 정하게 둔다. */
.bp-gnb .bp-gnb-right .bp-btn {
    height: 36px;
    background: transparent;
    border: 0;
    border-radius: var(--bp-radius-md);
    color: var(--bp-text-secondary);
    cursor: pointer;
    transition: background-color var(--bp-duration-fast), color var(--bp-duration-fast);
    font-size: var(--bp-control-icon-md);
    position: relative;
}
.bp-gnb .bp-gnb-right .bp-btn:hover {
    background: var(--bp-bg-muted);
    color: var(--bp-text-primary);
}

/* 아이콘 전용 헤더 버튼은 **헤더가 크기를 정한다** — tier 클래스를 이긴다(F37 · HR-DGW-003).
   `:has()` 의 특이도가 (0,5,1)이라 `BpButton` 이 늘 방출하는 tier 규칙
   (`.bp-btn.bp-sm` 32px · `.bp-btn.bp-md` 40px · (0,4,1))을 이긴다. 그래서 호스트는
   `Size` 를 무엇으로 주든 헤더에서는 36px 를 받는다.
   ⚠ **아이콘 전용에만 건다** — 글자 버튼(`<span class="bp-btn-text">`)도, 자식이 여럿인
     버튼(계정 트리거 등)도 걸리지 않는다. 그쪽은 폭이 내용을 따른다(F49). */
.bp-gnb .bp-gnb-right .bp-btn:has(> i:first-child:last-child) {
    width: 36px;
    height: 36px;
    min-width: 36px;
    padding: 0;
    display: grid;
    place-items: center;
}

/* 뱃지가 붙어도 아이콘 버튼이다 — `<i>` 의 형제가 생겨 위 조건(`:last-child`)에 안 걸린다.
   같은 크기 계약을 선택자 하나로 더 받는다. (0,4,0) 이고, 경쟁 상대인 tier 규칙
   `.bp-btn.bp-sm:has(i:first-child:last-child)` 는 **뱃지가 있으면 애초에 매칭되지 않으므로**
   이 특이도로 충분하다. 높이는 공통 규칙이 이미 준다. */
.bp-gnb .bp-gnb-right .bp-btn.bp-header-icon-btn {
    width: 36px;
    min-width: 36px;
    padding: 0;
    display: grid;
    place-items: center;
}

/* 아이콘 크기는 **자식 수와 무관하게** 같다.
   ⚠ 기본값이 `.bp-btn i { font-size: 24px }`(bp-variables.css)라, 20px 로 되돌리는 규칙을
     아이콘 전용에만 걸면 **뱃지 달린 알림 버튼만 24px** 가 된다(F49 실측). 여기서 전부 잡는다.
   (0,3,1) — `.bp-btn i`(0,1,1)와 tier 규칙 `.bp-btn.bp-md i`(0,2,1)를 모두 이긴다. */
.bp-gnb .bp-gnb-right .bp-btn > i {
    font-size: var(--bp-control-icon-md);
}

/* ⛔ 호스트가 트리거를 BpButton 으로 쓰면(raw <button> 은 page-composition §3 금지)
   tier 클래스가 늘 따라온다 — `.bp-btn.bp-md`(0,2,0)의 `padding: 0 16px` 이
   `.bp-header-user-trigger`(0,1,0)를 이겨 트리거가 벌어진다(실측 141 → 157px).
   헤더 안에서는 헤더가 정한다. */
.bp-gnb .bp-gnb-right .bp-btn.bp-header-user-trigger {
    padding: var(--bp-space-1) var(--bp-space-2);
}

/* 계정 트리거의 chevron 만 예외 — 보조 표시라 작다. (0,4,0) 으로 위 규칙을 이긴다. */
.bp-gnb .bp-gnb-right .bp-header-user-trigger > .bp-header-user-chevron {
    font-size: 12px;
}

/* ⛔ 헤더 우측 규칙은 **헤더 바**를 겨냥한다 — 그 안에서 열리는 드롭다운 **메뉴 안은 바가 아니다.**
   호스트는 raw <button> 을 쓸 수 없으므로(page-composition §3) 메뉴 항목을 BpButton 으로 만드는데,
   그러면 `.bp-btn` 이 붙어 위 규칙에 걸려 **글자 20px · 아이콘 20px · 높이 36px** 가 된다.
   같은 메뉴의 <a> 항목(14px·32px)과 나란히 놓여 그것만 커 보인다 —
   `BPack.DataGateway` 가 raw <button> 을 BpButton 으로 바꾸다 실제로 겪었다(TSK-M07-010).
   ⚠ 아이콘만 있는 메뉴 항목은 위 「아이콘 전용」 규칙(0,5,1)에도 걸려 36×36 정사각이 되므로
     폭까지 함께 되돌린다. `:has(> i)` 를 붙인 쪽도 **(0,5,1) 로 동률**이고
     (`:has()` 는 인자 중 가장 특이한 것 = `i:first-child:last-child` = (0,2,1)),
     **파일에서 뒤에 오기 때문에** 이긴다 — 이 블록을 위로 옮기지 않는다. */
.bp-gnb .bp-gnb-right .bp-dropdown-menu .bp-btn.bp-header-user-menu-item,
.bp-gnb .bp-gnb-right .bp-dropdown-menu .bp-btn.bp-header-user-menu-item:has(> i) {
    width: auto;
    min-width: 0;
    height: auto;
    padding: var(--bp-space-2) var(--bp-space-3);
    display: flex;
    place-items: initial;
    align-items: center;
    justify-content: flex-start;
    font-size: var(--bp-size-small);
}

.bp-gnb .bp-gnb-right .bp-dropdown-menu .bp-btn.bp-header-user-menu-item > i {
    font-size: 14px;
}

/* 좁은 폭 접기 토글 — **기본은 없다.** 분기점 아래에서만 나온다(아래 @media).
   .bp-gnb-right 는 패널을 띄울 기준점이 되어야 하므로 position 을 준다. */
.bp-gnb .bp-gnb-right {
    position: relative;
}

.bp-gnb .bp-gnb-right .bp-gnb-actions-btn {
    display: none;
}

/* 묶음 구분자 — 제품 고유 버튼과 공통 버튼을 가른다.
   버튼 자신에 테두리를 붙이지 않는다(그 버튼만 좌우 여백이 달라져 간격이 어긋난다).
   마크업: <span class="bp-header-divider" aria-hidden="true"></span> */
.bp-gnb .bp-gnb-right .bp-header-divider {
    width: 1px;
    height: 20px;
    background: var(--bp-border-default);
    margin: 0 var(--bp-space-1);
    flex: none;
}
.bp-gnb .bp-gnb-right .bp-btn[data-attr]::after {
    content: attr(data-attr);
    min-width: 16px;
    height: 16px;
    background: var(--bp-accent-500);
    color: var(--bp-neutral-0);
    font-size: 10px;
    font-weight: var(--bp-weight-bold);
    position: absolute;
    top: 4px;
    right: 4px;
    z-index: 1;
    border-radius: var(--bp-radius-pill);
    padding: 0 4px;
    display: grid;
    place-items: center;
    border: 2px solid var(--bp-bg-surface);
}

/* 테마 토글 (헤더 전용 래퍼) */
.bp-header-theme-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 0 6px;
    color: var(--bp-text-secondary);
    font-size: var(--bp-control-icon-sm);
}

.bp-gnb .bp-gnb-avatar {
    width: 32px;
    height: 32px;
    border-radius: var(--bp-radius-circle);
    background: linear-gradient(135deg, var(--bp-primary-500), var(--bp-primary-700));
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border: 0;
    color: var(--bp-neutral-0);
    font-size: 12px;
    font-weight: var(--bp-weight-bold);
    letter-spacing: -0.3px;
}

/* ── Main grid (Nav | Tree | Page) · 자식 스크롤 위임 ──── */
.bp-main {
    position: relative;    /* .bp-snb-resizer(절대배치) 기준 */
    display: grid;
    grid-template-columns: var(--bp-layout-sidebar) 1fr;
    min-height: 0;
    min-width: 0;
    overflow: hidden;      /* 자체 스크롤 차단 — Nav · Page 각자 스크롤 */
    background: var(--bp-bg-page);
    transition: grid-template-columns var(--bp-duration-base) var(--bp-ease-out);
}
.bp-main.has-tree {
    grid-template-columns: var(--bp-layout-sidebar) var(--bp-layout-tree-menu) 1fr;
}

html[data-snb-collapsed="true"] .bp-main {
    grid-template-columns: var(--bp-layout-sidebar-sm) 1fr;
}
html[data-snb-collapsed="true"] .bp-main.has-tree {
    grid-template-columns: var(--bp-layout-sidebar-sm) var(--bp-layout-tree-menu) 1fr;
}

/* ── NavMenu 를 주지 않은 화면 — 240px 열을 만들지 않는다 ──────────────
   BpLayout.razor 는 `NavMenu == null` 을 명시적으로 다루는데(nav·리사이저·scrim 을
   조건부 렌더) 위 열 규칙만 따라오지 않아, **본문이 240px 열에 갇히고 1fr 이 비었다**
   (HR-LIC-002 · pin 0.2.3 실측: `.bp-main` `240px 1545px` · `.bp-page` 실폭 240px).
   `.bp-main` 이 `overflow: hidden` 이라 **가로 넘침이 0 으로 보여** 호스트의 넘침
   측정으로는 잡히지 않았다.

   판별은 `.bp-snb-resizer` 로 한다 — **BpLayout 자신이 `NavMenu != null` 일 때만**
   렌더하므로 호스트가 무엇을 넘기든 정확하다(`.bp-snb` 은 BpNavMenu 를 쓸 때만 생긴다).
   BpAppShell 이 0.1.43 에서 `.bp-app-nav-slot` 으로 한 것과 같은 방식이다.

   ⚠️ 접힘 규칙은 `html[...] .bp-main` (0,2,1) 이라 `.bp-main:not(:has(...))` (0,2,0)
      보다 세다. 그래서 접힘 변형도 함께 되받아야 한다(0,3,1). */
.bp-main:not(:has(.bp-snb-resizer)) {
    grid-template-columns: 1fr;
}
.bp-main.has-tree:not(:has(.bp-snb-resizer)) {
    grid-template-columns: var(--bp-layout-tree-menu) 1fr;
}
html[data-snb-collapsed="true"] .bp-main:not(:has(.bp-snb-resizer)) {
    grid-template-columns: 1fr;
}
html[data-snb-collapsed="true"] .bp-main.has-tree:not(:has(.bp-snb-resizer)) {
    grid-template-columns: var(--bp-layout-tree-menu) 1fr;
}

/* ── SNB 드래그 리사이저 — 좌측 메뉴 오른쪽 경계 ── */
.bp-snb-resizer {
    position: absolute;
    top: 0;
    bottom: 0;
    left: var(--bp-layout-sidebar);   /* 그리드 col1 경계 · 폭 변경 시 함께 이동 */
    width: 3px;
    transform: translateX(-1.5px);    /* 경계 중앙에 정렬 */
    cursor: col-resize;
    z-index: 5;
    background: transparent;
    transition: background var(--bp-duration-fast) var(--bp-ease-out);
}
.bp-snb-resizer:hover,
.bp-snb-resizer.bp-dragging {
    background: var(--bp-border-brand);
}
/* 접힘(64px) 상태에선 리사이즈 비활성 */
html[data-snb-collapsed="true"] .bp-snb-resizer {
    display: none;
}
/* 드래그 중에는 그리드/메뉴 전환 애니메이션을 꺼 즉각 반응하게 한다 */
html.bp-resizing .bp-main,
html.bp-resizing .bp-snb {
    transition: none;
}

/* ── Side Nav (SNB) · shell.css §Nav menu ─────────────── */
.bp-snb {
    background: var(--bp-bg-surface);
    border-right: 1px solid var(--bp-border-light);
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
    transition: width var(--bp-duration-base) var(--bp-ease-out);
}

.bp-tree-menu {
    background: var(--bp-bg-surface);
    border-right: 1px solid var(--bp-border-light);
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

/* Nav header : 검색 박스 + 접기 버튼 · shell.css §Nav header (48px) */
.bp-snb .bp-nav-header,
.bp-tree-menu .bp-nav-header {
    /* 콘텐츠 상단 바(.bp-page-bar)와 같은 --bp-h-md — 두 줄의 하단 구분선이 한 선에 선다.
       --bp-layout-toolbar(48px)를 쓰지 않는 이유: 그 토큰은 BpPageToolbar 도 함께 쓴다. */
    height: var(--bp-h-md);
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--bp-space-2);
    align-items: center;
    padding: 0 var(--bp-space-2);
    border-bottom: 1px solid var(--bp-border-light);
    flex-shrink: 0;
}

/* Menu search · shell.css §Nav search · NavMenu + TreeMenu 공용 */
.bp-snb .bp-nav-search,
.bp-tree-menu .bp-nav-search {
    display: grid;
    grid-template-columns: 16px 1fr auto;
    gap: var(--bp-space-2);
    align-items: center;
    padding: 0 10px;
    /* 40px 줄 안에서 위아래 4px 씩 남기는 sm 등급. md 로 두면 줄을 꽉 채워
       입력 테두리가 줄의 하단 구분선과 겹쳐 두 줄로 보인다. */
    height: var(--bp-h-sm);
    border: 1px solid var(--bp-border-default);
    border-radius: var(--bp-radius-md);
    background: var(--bp-bg-muted);
    transition: border-color var(--bp-duration-fast), background-color var(--bp-duration-fast), box-shadow var(--bp-duration-fast);
    cursor: text;
    min-width: 0;
}
.bp-snb .bp-nav-search:hover,
.bp-tree-menu .bp-nav-search:hover { background: var(--bp-bg-surface); }
.bp-snb .bp-nav-search:focus-within,
.bp-tree-menu .bp-nav-search:focus-within {
    background: var(--bp-bg-surface);
    border-color: var(--bp-primary-500);
    box-shadow: var(--bp-focus-ring);
}
.bp-snb .bp-nav-search .search-icon,
.bp-tree-menu .bp-nav-search .search-icon {
    width: 16px;
    height: 16px;
    color: var(--bp-text-tertiary);
    display: grid;
    place-items: center;
    font-size: 14px;
}
.bp-snb .bp-nav-search input,
.bp-tree-menu .bp-nav-search input {
    width: 100%;
    min-width: 0;
    border: 0;
    background: transparent;
    outline: none;
    color: var(--bp-text-primary);
    font-family: inherit;
    font-size: var(--bp-size-small);
    padding: 0;
}
.bp-snb .bp-nav-search input::placeholder,
.bp-tree-menu .bp-nav-search input::placeholder { color: var(--bp-text-tertiary); }
/* type=search 네이티브 클리어(X)·데코레이션 제거 — 빈 상태에서도 잡히던 우측 여백을 없애
   긴 placeholder(영문 "Search menu...")가 끝까지 보이게 한다. (입력 시 뜨던 네이티브 X도 사라짐) */
.bp-snb .bp-nav-search input,
.bp-tree-menu .bp-nav-search input {
    -webkit-appearance: none;
    appearance: none;
}
.bp-snb .bp-nav-search input::-webkit-search-cancel-button,
.bp-tree-menu .bp-nav-search input::-webkit-search-cancel-button,
.bp-snb .bp-nav-search input::-webkit-search-decoration,
.bp-tree-menu .bp-nav-search input::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
    display: none;
}

/* Collapse button · shell.css §Nav collapse btn · NavMenu + TreeMenu 공용 */
.bp-snb .bp-nav-collapse-btn,
.bp-tree-menu .bp-nav-collapse-btn {
    /* 검색창과 같은 등급 — 한 줄 안에서 높이가 어긋나지 않게. */
    width: var(--bp-h-sm);
    height: var(--bp-h-sm);
    display: grid;
    place-items: center;
    border: 1px solid var(--bp-border-default);
    border-radius: var(--bp-radius-md);
    background: var(--bp-bg-surface);
    color: var(--bp-text-brand);
    cursor: pointer;
    font-size: var(--bp-control-icon-lg);
    font-weight: var(--bp-weight-bold);
    line-height: 1;
    transition: background-color var(--bp-duration-fast), color var(--bp-duration-fast), border-color var(--bp-duration-fast);
}
.bp-snb .bp-nav-collapse-btn:hover,
.bp-tree-menu .bp-nav-collapse-btn:hover {
    background: var(--bp-primary-50);
    border-color: var(--bp-primary-500);
    color: var(--bp-primary-fg);
}
.bp-snb .bp-nav-collapse-btn > i,
.bp-tree-menu .bp-nav-collapse-btn > i {
    transition: transform var(--bp-duration-base) var(--bp-ease-out);
}
html[data-snb-collapsed="true"] .bp-nav-collapse-btn > i {
    transform: rotate(180deg);
}

/* Collapsed : 검색 박스 숨김 — 접기 버튼만 남아 겹침 방지 */
html[data-snb-collapsed="true"] .bp-nav-search { display: none; }
html[data-snb-collapsed="true"] .bp-nav-header {
    grid-template-columns: 1fr;
    justify-items: center;
}

/* Collapsed : 카테고리 라벨·아이템 라벨 숨기고 아이콘만 */
html[data-snb-collapsed="true"] .bp-snb-menu .bp-snb-category { display: none; }
html[data-snb-collapsed="true"] .bp-snb-menu ul .bp-snb-base {
    grid-template-columns: 1fr;
    justify-items: center;
    padding: 0;
}
html[data-snb-collapsed="true"] .bp-snb-menu ul .bp-snb-base > p { display: none; }
html[data-snb-collapsed="true"] .bp-snb-menu ul .bp-snb-base.bp-active::before {
    left: 0;
    top: 4px;
    bottom: 4px;
}
html[data-snb-collapsed="true"] .bp-snb-settings {
    justify-content: center;
    padding: 0;
}
html[data-snb-collapsed="true"] .bp-snb-settings > p { display: none; }

/* Collapsed : Nav footer (Site Switcher) — 아이콘만 남김 */
html[data-snb-collapsed="true"] .bp-nav-footer {
    padding: var(--bp-space-2) 0;
}
html[data-snb-collapsed="true"] .bp-nav-footer .bp-site-switcher {
    grid-template-columns: 1fr;
    justify-items: center;
    padding: 6px 0;
}
html[data-snb-collapsed="true"] .bp-nav-footer .bp-site-switcher .meta,
html[data-snb-collapsed="true"] .bp-nav-footer .bp-site-switcher .chevron {
    display: none;
}

/* ─────────────────────────────────────────────────────────────
 * Collapsed : BpTreeMenu — Leaf 만 평면 아이콘 표시.
 * - 부모 행([data-leaf="false"]) 숨김
 * - leaf 행: chevron / label 숨기고 indent 0, 아이콘 가운데 정렬
 * - children 컨테이너는 indent/border 제거 + 강제 펼침 (펼침 상태 무관)
 * - 옵션 Title 행도 숨김
 * ───────────────────────────────────────────────────────────── */
html[data-snb-collapsed="true"] .bp-tree-menu .bp-tree-row {
    padding: 0;
    grid-template-columns: 1fr;
    justify-items: center;
}
html[data-snb-collapsed="true"] .bp-tree-menu .bp-tree-row .label,
html[data-snb-collapsed="true"] .bp-tree-menu .bp-tree-row .chevron,
html[data-snb-collapsed="true"] .bp-tree-menu .bp-tree-row .chevron-placeholder {
    display: none;
}
/* 아이콘 열이 없는 트리라도 접힘에서는 슬롯을 다시 보이게 한다 —
   펼침에서 .bp-tree-row-no-icon > .icon 을 display:none 으로 뺐기 때문이다(F03/T03).
   여기 특이도(0,3,1)가 그 규칙(0,3,0)을 이긴다. */
html[data-snb-collapsed="true"] .bp-tree-menu .bp-tree-row .icon {
    display: grid;
}
/* 아이콘 없는 노드의 대체 이니셜을 **접힘에서만** 보이게 한다 (F03).
   위에서 라벨·화살표를 숨기므로 아이콘 슬롯만 남는데, 아이콘이 없으면 그 슬롯이 비어
   행이 통째로 안 보였다. 기본 숨김은 BpTreeMenuNode.razor.css 가 갖는다. */
html[data-snb-collapsed="true"] .bp-tree-menu .bp-tree-initial {
    display: block;
}
html[data-snb-collapsed="true"] .bp-tree-menu .bp-tree-row[data-leaf="false"] {
    display: none;
}
html[data-snb-collapsed="true"] .bp-tree-menu .bp-tree-children {
    margin: 0;
    border-left: none;
}
html[data-snb-collapsed="true"] .bp-tree-menu .bp-tree-node.is-collapsed > .bp-tree-children {
    display: block;
}
html[data-snb-collapsed="true"] .bp-tree-menu .bp-tree-header {
    display: none;
}

.bp-snb-menu {
    flex: 1;
    min-height: 0;          /* flex 자식에 scroll 넘기기 */
    display: flex;
    flex-direction: column;
    overflow-x: hidden;
    overflow-y: auto;
    padding: 0;
    gap: 0;
}
.bp-snb-menu ul {
    list-style: none;
    margin: 0;
    padding: var(--bp-space-2) 0;
    position: relative;
}
.bp-snb-menu ul + ul {
    border-top: 1px solid var(--bp-border-light);
}
.bp-snb-menu ul .bp-snb-category {
    display: block;
    font-size: var(--bp-size-xs);
    font-weight: var(--bp-weight-semibold);
    color: var(--bp-text-brand);
    letter-spacing: var(--bp-tracking-wide);
    text-transform: uppercase;
    padding: var(--bp-space-2) var(--bp-space-4);
    margin: 0;
}

/* 링크 wrapper (a) — underline · visited 색 무력화 (active 색이 li 에 먹히도록) */
.bp-snb-menu a,
.bp-snb-menu a:visited,
.bp-snb-menu a:hover,
.bp-snb-menu a:active {
    display: block;
    text-decoration: none;
    color: inherit;
}

.bp-snb-menu ul .bp-snb-base {
    display: grid;
    grid-template-columns: 20px 1fr;
    gap: var(--bp-space-3);
    align-items: center;
    height: var(--bp-h-md);
    padding: 0 var(--bp-space-4);
    margin: 0;
    border-radius: 0;
    color: var(--bp-text-secondary);
    font-size: var(--bp-size-small);
    font-weight: var(--bp-weight-medium);
    cursor: pointer;
    transition: background-color var(--bp-duration-fast), color var(--bp-duration-fast);
    position: relative;
}
.bp-snb-menu ul .bp-snb-base p {
    margin: 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1;
}
.bp-snb-menu ul .bp-snb-base i {
    font-size: var(--bp-control-icon-md);
    display: grid;
    place-items: center;
    color: inherit;
}
.bp-snb-menu ul .bp-snb-base:hover {
    background: var(--bp-bg-muted);
    color: var(--bp-text-primary);
}
/* 활성 메뉴 — BpTreeMenu 노드·BpGrid/BpTree 행과 동일한 시맨틱 토큰 (--bp-row-active-*).
   토큰이 라이트/다크 양쪽에 정의되어 자동 테마 전환된다. */
.bp-snb-menu ul .bp-snb-base.bp-active {
    background: var(--bp-row-active-bg);
    color: var(--bp-row-active-text);
    font-weight: var(--bp-weight-semibold);
}
.bp-snb-menu ul .bp-snb-base.bp-active::before {
    content: "";
    position: absolute;
    left: 0;
    top: 8px;
    bottom: 8px;
    width: 3px;
    background: var(--bp-row-active-accent);
    border-radius: 0 var(--bp-radius-sm) var(--bp-radius-sm) 0;
}

/* 다크 모드 hover — 라이트 --bp-bg-muted 가 다크 surface 와 거의 같아 안 보이므로
   --bp-active-bg-soft (반투명 primary) 사용. */
[data-theme="dark"] .bp-snb-menu ul .bp-snb-base:hover {
    background: var(--bp-active-bg-soft);
    color: var(--bp-text-primary);
}
/* 다크 active — 위 다크 hover 룰의 specificity (0,4,1) 를 이기도록 동일 prefix 명시.
   active 와 active:hover 모두 row-active 색 유지. */
[data-theme="dark"] .bp-snb-menu ul .bp-snb-base.bp-active,
[data-theme="dark"] .bp-snb-menu ul .bp-snb-base.bp-active:hover {
    background: var(--bp-row-active-bg);
    color: var(--bp-row-active-text);
}

/* 키보드 방향키 커서 — 마우스 hover(중립 배경)보다 뚜렷한 focus 표시.
   시맨틱 active 토큰(브랜드 틴트)으로 채워 라이트/다크 모두 명확히 보이고,
   중립 hover·앰버 선택과 구분된다. 테두리 없이 배경만 사용.
   검색 input 에서 ↑/↓ 이동 시 bp-navigation.js 가 링크(a)에 .bp-kbd-active 를 토글. */
.bp-snb-menu a.bp-kbd-active .bp-snb-base {
    background: var(--bp-active-bg);
    color: var(--bp-active-text);
}

/* Nav Footer · Site Switcher 슬롯 (AppShell shell.css §Nav footer)
   BpNavMenu(.bp-snb) · BpTreeMenu(.bp-tree-menu) 모두 동일 슬롯 사용. */
.bp-snb .bp-nav-footer,
.bp-tree-menu .bp-nav-footer {
    margin-top: auto;
    padding: var(--bp-space-2);
    border-top: 1px solid var(--bp-border-light);
    flex-shrink: 0;
}
.bp-snb .bp-nav-footer .bp-site-switcher,
.bp-tree-menu .bp-nav-footer .bp-site-switcher,
.bp-snb .bp-nav-footer > .bp-dropdown,
.bp-tree-menu .bp-nav-footer > .bp-dropdown {
    width: 100%;
}
/* 푸터에 놓인 커스텀 드롭다운(예: Docs AppMenu)의 트리거도 폭을 채워
   내부 콘텐츠가 site-switcher 처럼 SNB 폭(드래그 리사이즈)을 따라가게 한다. */
.bp-snb .bp-nav-footer > .bp-dropdown > .bp-dropdown-trigger,
.bp-tree-menu .bp-nav-footer > .bp-dropdown > .bp-dropdown-trigger {
    width: 100%;
}
/* Drop-up chevron 회전 (site switcher 내부에서 직접 DropUp="true" 지원) */

/* SNB 설정 버튼 (푸터, Legacy — Site Switcher 로 이전) */
.bp-snb-settings,
.bp-tree-menu .bp-snb-settings {
    display: flex;
    align-items: center;
    gap: var(--bp-space-3);
    height: var(--bp-h-md);
    margin: var(--bp-space-2);
    padding: 0 var(--bp-space-3);
    border-radius: var(--bp-radius-md);
    border: 1px solid var(--bp-border-light);
    background: var(--bp-bg-muted);
    color: var(--bp-text-secondary);
    font-size: var(--bp-size-small);
    font-weight: var(--bp-weight-medium);
    cursor: pointer;
    transition: background-color var(--bp-duration-fast), color var(--bp-duration-fast), border-color var(--bp-duration-fast);
    flex-shrink: 0;
}
.bp-snb-settings i,
.bp-tree-menu .bp-snb-settings i {
    font-size: var(--bp-control-icon-md);
    color: var(--bp-text-tertiary);
}
.bp-snb-settings p,
.bp-tree-menu .bp-snb-settings p {
    margin: 0;
    line-height: 1;
}
.bp-snb-settings:hover,
.bp-tree-menu .bp-snb-settings:hover {
    background: var(--bp-bg-surface);
    border-color: var(--bp-border-default);
    color: var(--bp-text-primary);
}

/* ── Page (main content) ───────────────────────────────── */
.bp-page {
    min-width: 0;
    min-height: 0;
    background: var(--bp-bg-page);
    color: var(--bp-text-primary);
    padding: var(--bp-space-2);
    font-size: var(--bp-size-small);
    overflow-y: auto;
    /* flex column 으로 자식이 flex:1 로 풀하이트 채울 수 있게.
       block 레이아웃이 필요한 일반 페이지는 자식이 flex 미사용이라 영향 없음. */
    display: flex;
    flex-direction: column;
}

/* ── Page bar (콘텐츠 상단 고정 바) ──────────────────────────
   Breadcrumb·페이지 액션처럼 "지금 콘텐츠의 어디" 를 알리는 줄을 .bp-page 맨 위에 둘 때 쓴다.

   .bp-page 는 padding 을 가진 스크롤 컨테이너라, 그냥 첫 자식으로 넣으면 위로도 8px 떠서
   헤더에서 분리된 카드처럼 보이고, 스크롤하면 그대로 밀려 올라간다.
   이 클래스는 **위쪽 패딩만** 상쇄해 헤더에 붙이고 sticky 로 고정한다.
   좌·우는 상쇄하지 않는다 — 바의 양 끝이 콘텐츠와 같은 선에 서고,
   콘텐츠를 둘러싼 상하좌우 여백이 모두 --bp-space-2 로 같아진다.

   호스트가 음수 마진을 직접 쓰지 않게 하려고 라이브러리가 소유한다 —
   상쇄 값은 .bp-page 의 padding(--bp-space-2)에 묶여 있어 여기서 함께 관리해야 한다.

   z-index 는 --bp-z-sticky(200): 콘텐츠 안의 sticky(그리드 헤더 등 2~3) 위,
   헤더(--bp-z-header 300) 아래.

   사용:
     <div class="bp-page-bar">
         <BpBreadcrumb RouteMap="@_map" />
     </div>
     @Body                                                              */
.bp-page-bar {
    position: sticky;
    top: calc(var(--bp-space-2) * -1);
    z-index: var(--bp-z-sticky);
    display: flex;
    align-items: center;
    gap: var(--bp-space-3);
    flex-shrink: 0;
    /* SNB 검색창과 같은 md 등급(40px) — 두 줄의 높이가 좌우로 맞는다. */
    min-height: var(--bp-h-md);
    /* 위만 상쇄해 헤더에 붙이고, 좌·우·아래는 .bp-page 의 여백을 그대로 둔다.
       → 바의 좌우 끝이 콘텐츠와 같은 선에 서고, 콘텐츠의 상하좌우 여백이 모두 같아진다. */
    margin: calc(var(--bp-space-2) * -1) 0 var(--bp-space-2);
    padding: 0 var(--bp-space-4);
    background: var(--bp-bg-surface);
    border-bottom: 1px solid var(--bp-border-light);
}


/* 내비 스크롤바는 가늘게 — 메뉴 폭이 좁아 기본 스크롤바가 내용을 밀어낸다.
   ⛔ 전역이 아니다. 본문·그리드·모달은 기본 폭을 유지한다(넓은 표를 가로로 끌 때 잡기 어렵다).

   ⚠️ `::-webkit-scrollbar` 를 **함께 쓰지 않는다.** 같은 요소에 `scrollbar-width` 나
      `scrollbar-color` 가 비-auto 면 Chromium 은 webkit 의사요소 규칙을 **통째로 무시한다.**
      실측: 표준+webkit 병기 10px · webkit 만 6px · 병기 상태에서 webkit 규칙은 죽는다.
      표준 속성 하나로 두 엔진을 다 덮는다(Chromium 121+ · Firefox 64+).

   ⚠️ `scrollbar-color` 는 **상속된다**(`scrollbar-width` 는 비상속).
      `.bp-snb` 안에 호스트가 스크롤 영역을 두면 색만 따라간다. 폭은 안 따라간다. */
.bp-snb,
.bp-snb-menu {
    scrollbar-width: thin;
    scrollbar-color: var(--bp-text-tertiary) transparent;
}

.bp-snb:hover,
.bp-snb-menu:hover {
    scrollbar-color: var(--bp-text-secondary) transparent;
}

/* ── Footer (statusbar) ─────────────────────────────────── */
.bp-footer {
    height: var(--bp-layout-statusbar);
    background: var(--bp-neutral-900);
    color: var(--bp-neutral-400);
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: var(--bp-space-3);
    padding: 0 var(--bp-space-3);
    font-size: 11px;
    font-family: var(--bp-font-mono);
    flex-shrink: 0;
}
.bp-footer .statusbar-left,
.bp-footer .statusbar-center,
.bp-footer .statusbar-right {
    display: flex;
    align-items: center;
    gap: var(--bp-space-2);
    min-width: 0;
}
.bp-footer .statusbar-center {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.bp-footer .status-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--bp-success);
    vertical-align: middle;
    box-shadow: 0 0 8px var(--bp-success);
}
.bp-footer .status-ok { color: var(--bp-success); }

/* 드로어 토글(햄버거) — BpHeader 가 좌측 칸에 렌더한다. ≤lg 에서만 보인다.
   .bp-gnb-right 의 버튼 규칙은 좌측 칸에 닿지 않아 여기서 따로 정의한다. */
.bp-gnb-drawer-btn {
    display: none;
    width: var(--bp-h-sm);
    height: var(--bp-h-sm);
    place-items: center;
    flex-shrink: 0;
    border: 0;
    border-radius: var(--bp-radius-md);
    background: transparent;
    color: var(--bp-text-secondary);
    cursor: pointer;
    font-size: var(--bp-control-icon-sm);
    line-height: 1;
    transition: background-color var(--bp-duration-fast), color var(--bp-duration-fast);
}
.bp-gnb-drawer-btn:hover {
    background: var(--bp-bg-muted);
    color: var(--bp-text-primary);
}
/* <button> 은 전역 :focus-visible 아웃라인 대상이라 링과 겹친다 — 링만 남긴다. */
.bp-gnb-drawer-btn:focus-visible {
    outline: none;
    box-shadow: var(--bp-focus-ring);
}

/* ── 모바일 드로어 막(scrim) ─────────────────────────────
   레이아웃이 항상 렌더하고, ≤lg 에서 드로어가 열렸을 때만 보인다.
   탭하면 닫히고, 열릴 때 포커스를 받아 이후 Tab 이 드로어로 들어간다. */
.bp-nav-scrim {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--bp-scrim-bg);
    z-index: calc(var(--bp-z-modal) - 10);
    cursor: pointer;
    border: 0;
    outline: none;      /* tabindex="-1" programmatic 포커스 — 시각 표시가 필요 없다 */
}

/* ── Responsive (≤ lg · 1024 px) ───────────────────────── */
/* 숫자는 --bp-break-lg(1024px) 와 손으로 맞춘다 — @media 는 var() 를 읽지 못한다. */
@media (max-width: 1024px) {
    /* 헤더 행을 auto 로 — ≤lg 에서 헤더가 2줄이 되면 고정 56px 행을 넘쳐
       바로 아래 콘텐츠를 덮는다. .bp-container 가 display:contents 라 .bp-gnb 는
       .bp-wrap 의 그리드 아이템이고, 행이 고정이면 height:auto 를 줘도 stretch 로 늘어난다.
       ⚠️ .bp-wrap.has-footer (0,2,0) 는 .bp-wrap (0,1,0) 을 이긴다 — @media 는 특이도를
       올려주지 않으므로 **변형도 같은 모양으로 한 번 더** 되받는다(error-prevention #26). */
    .bp-wrap {
        grid-template-rows: auto 1fr;
    }
    .bp-wrap.has-footer {
        grid-template-rows: auto 1fr var(--bp-layout-statusbar);
    }

    .bp-main {
        grid-template-columns: 1fr;
    }
    .bp-main.has-tree {
        grid-template-columns: 1fr;
    }

    /* 안전망 — 접힘 속성이 남아 있어도 콘텐츠 열을 지킨다.
       접기는 데스크톱 전용이라 bp-navigation.js 가 좁은 폭에서 속성을 떼지만,
       스크립트가 없거나 실패한 호스트에서는 html[data-snb-collapsed] 규칙(특이도 0,2,0)이
       위 .bp-main(0,1,0)을 이겨 **콘텐츠가 64px 로 찌그러진다.** 같은 특이도로 되받는다.
       (드로어 안 메뉴의 아이콘 전용 표시까지는 여기서 막지 않는다 — 26개 규칙을 전부
        되받는 대신 속성 제거를 정본으로 둔다. 이 규칙은 레이아웃 붕괴만 막는 최소 안전망이다.) */
    html[data-snb-collapsed="true"] .bp-main,
    html[data-snb-collapsed="true"] .bp-main.has-tree {
        grid-template-columns: 1fr;
    }

    /* nav 없는 갈래도 같은 모양으로 되받는다. :not(:has(...)) 가 특이도를 한 단계 올려
       (0,3,0 · 0,4,1) 위의 .bp-main.has-tree(0,2,0)·html[...](0,3,1)을 이기므로,
       되받지 않으면 ≤lg 에서 데스크톱 열 규칙이 그대로 남는다. ≤lg 는 .bp-tree-menu 가
       display:none 이라 트리가 격자에서 빠지고, 자동 배치로 .bp-page 가 첫 열
       (--bp-layout-tree-menu = 300px)에 들어간다 — HR-LIC-002 와 같은 모양의 결함이
       폭만 바꿔 재발한다(실측 390px: `300px 90px` · .bp-page 300px).
       @media 는 특이도를 올려주지 않는다(error-prevention #26). */
    .bp-main:not(:has(.bp-snb-resizer)),
    .bp-main.has-tree:not(:has(.bp-snb-resizer)),
    html[data-snb-collapsed="true"] .bp-main:not(:has(.bp-snb-resizer)),
    html[data-snb-collapsed="true"] .bp-main.has-tree:not(:has(.bp-snb-resizer)) {
        grid-template-columns: 1fr;
    }
    .bp-tree-menu {
        display: none;
    }
    .bp-snb {
        position: fixed;
        top: 0;
        left: 0;
        width: var(--bp-drawer-w);
        max-width: 85vw;
        height: 100vh;
        height: 100dvh;
        transform: translateX(-100%);
        transition: transform var(--bp-duration-base) var(--bp-ease-out);
        z-index: var(--bp-z-modal);
        box-shadow: var(--bp-shadow-lg);
    }

    /* 열림 — 레이아웃 루트의 상태 클래스가 단일 근거다.
       html[data-snb-open] 은 다른 저장소 호스트가 이미 쓰고 있을 수 있어 하위호환으로 병기한다. */
    .bp-wrap.bp-drawer-open .bp-snb,
    html[data-snb-open="true"] .bp-snb {
        transform: translateX(0);
    }

    .bp-wrap.bp-drawer-open .bp-nav-scrim,
    html[data-snb-open="true"] .bp-nav-scrim {
        display: block;
    }

    /* 드로어는 고정 폭이라 리사이저는 의미가 없다.
       접기 버튼은 **숨기지 않는다** — 그 폭에서는 '드로어 닫기' 로 동작하며,
       드로어가 헤더를 덮어 햄버거가 가려지므로 눈에 보이는 유일한 닫기 수단이다.
       (이전 버전은 여기서 숨기려 했으나 .bp-snb .bp-nav-collapse-btn(0,2,0)의
        display:grid 를 (0,1,0)으로 이길 수 없어 애초에 적용되지 않았다.) */
    .bp-snb-resizer {
        display: none;
    }

    /* 손가락 타깃 — md(40) → lg(48). 5-tier 안에서 한 등급만 올린다. */
    .bp-snb-menu ul .bp-snb-base {
        height: var(--bp-h-lg);
    }

    /* 헤더 2줄 — 좌측(로고·햄버거)과 우측(아이콘 묶음)이 윗줄,
       가운데 메뉴가 아랫줄 전폭. 한 줄로 두면 우측 아이콘이 타이틀을 덮는다. */
    .bp-gnb {
        height: auto;
        grid-template-columns: auto auto;
        grid-template-areas:
            "brand actions"
            "menu  menu";
        justify-content: space-between;
        row-gap: var(--bp-space-2);
        padding-top: var(--bp-space-2);
        padding-bottom: var(--bp-space-2);
    }
    /* 좌측은 남는 폭만 쓴다. overflow:hidden 이 없으면 로고·타이틀이 자기 칸을 넘쳐
       우측 아이콘 묶음 위로 겹쳐 그려진다(박스끼리는 안 겹치므로 좌표 측정으로는 안 잡힌다). */
    .bp-gnb > .bp-gnb-left {
        grid-area: brand;
        min-width: 0;
        overflow: hidden;
    }
    .bp-gnb .bp-gnb-left .bp-gnb-box {
        min-width: 0;
        overflow: hidden;
    }
    /* 로고 box 는 줄지 않는다 — 줄어드는 것은 타이틀·Breadcrumb box 뿐이다(HR-REM-001).
       로고 box 도 함께 줄면 320px 에서 로고가 40px 중 33px 만 보였다. */
    .bp-gnb .bp-gnb-left .bp-gnb-box.bp-gnb-logo-box {
        flex-shrink: 0;
    }
    /* 넘치는 내용은 말줄임으로. 자르되 겹치지는 않게 한다. */
    .bp-gnb .bp-gnb-left .bp-gnb-box > * {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    /* ⚠️ 종전에는 로고 이미지가 있으면 타이틀을 **숨겼다.** 근거는 「390px 에서 우측 아이콘
       묶음이 폭을 다 먹으면 타이틀에 10여 px 밖에 안 남아 "B." 조각만 보인다」였다.
       **그 전제가 없어졌다** — 우측이 ⋮ 하나(36px)로 접히므로 좌측이 폭을 받는다
       (390px 실측: 좌측 61 → 175px). 제품명은 모바일에서도 보여야 하므로 숨기지 않는다.
       길면 위 `.bp-gnb-box > *` 의 ellipsis 가 받는다. */
    .bp-gnb > .bp-gnb-right { grid-area: actions; }

    /* ⛔ 우측 버튼이 여럿이면 좌측(로고·타이틀)을 밀어낸다 — 박스는 안 겹치는데 로고가
       `overflow:hidden` 에 잘려 세로 막대만 남는다(F49 실측 360px 에서 좌측 31px).
       그래서 **한 버튼으로 접는다.** 펼침은 바 아래 패널로 띄운다.
       ⚠ 요소는 한 벌이다 — RightContent 를 두 번 렌더하면 컴포넌트가 두 벌 생긴다. */
    .bp-gnb .bp-gnb-right .bp-gnb-actions-btn {
        display: grid;
        place-items: center;
        width: 36px;
        height: 36px;
        min-width: 36px;
        padding: 0;
        background: transparent;
        border: 0;
        border-radius: var(--bp-radius-md);
        color: var(--bp-text-secondary);
        cursor: pointer;
    }

    .bp-gnb .bp-gnb-right .bp-gnb-actions-btn > i {
        font-size: var(--bp-control-icon-md);
    }

    .bp-gnb .bp-gnb-right .bp-gnb-actions-btn[aria-expanded="true"] {
        background: var(--bp-bg-muted);
        color: var(--bp-text-primary);
    }

    .bp-gnb .bp-gnb-right .bp-gnb-box {
        display: none;
        position: absolute;
        top: calc(100% + var(--bp-space-2));
        right: 0;
        z-index: var(--bp-z-dropdown, 1000);
        flex-direction: column;
        align-items: center;
        gap: var(--bp-space-1);
        padding: var(--bp-space-1);
        background: var(--bp-bg-elevated);
        border: 1px solid var(--bp-border-default);
        border-radius: var(--bp-radius-md);
        box-shadow: var(--bp-shadow-lg);
        /* 가로 모드 폰처럼 뷰포트가 낮으면 항목이 화면 밖으로 나간다 — .bp-wrap 이
           overflow:hidden 이라 페이지가 대신 스크롤해 주지 않는다. 패널이 스스로 스크롤한다. */
        max-height: 60dvh;
        overflow-y: auto;
    }

    .bp-gnb .bp-gnb-right .bp-gnb-box.is-open {
        display: flex;
    }

    /* ⚠ 패널은 **아이콘 세로 바**다 — 폭을 늘리지 않는다.
       종전에는 min-width: 180px 에 항목을 width:100% 로 늘려, 36px 짜리 아이콘 오른쪽에
       140px 넘는 빈칸이 남았다(대표 지적 2026-10-04). 폭은 내용이 정한다.
       계정 트리거의 이름·역할은 여기서 숨긴다 — 그것만 폭을 벌리고, 같은 정보가
       눌러서 열리는 메뉴 안에 있다(≤720px 에서 바에 있을 때와 같은 처리다). */
    .bp-gnb .bp-gnb-right .bp-gnb-box.is-open > .bp-dropdown .bp-header-user-meta,
    .bp-gnb .bp-gnb-right .bp-gnb-box.is-open > .bp-dropdown .bp-header-user-chevron {
        display: none;
    }

    .bp-gnb .bp-gnb-right .bp-gnb-box.is-open > .bp-dropdown .bp-header-user-trigger {
        padding: 0;
        width: 36px;
        justify-content: center;
    }

    /* 구분자는 패널에서 가로선이 된다. */
    .bp-gnb .bp-gnb-right .bp-gnb-box.is-open > .bp-header-divider {
        width: 100%;
        height: 1px;
        margin: var(--bp-space-1) 0;
    }
    .bp-gnb > .bp-header-menu { grid-area: menu; min-width: 0; }

    .bp-gnb-drawer-btn {
        display: grid;
    }
}
