/* v3 전용 글로벌 Shell 스타일입니다.
   색상은 v3 토큰만 참조합니다.
   Shell의 정적 마크업과 배치만 정의합니다. */

/* 계정 메뉴는 헤더 오른쪽에 놓고 모바일에서도 너비를 제한한다. */
.__v3sh_auth { position: relative; flex: 0 0 auto; min-width: 0; }
.__v3sh_authmenu button {
  font: inherit; color: var(--v3-text-main); background: var(--v3-bg-panel);
  border: 1px solid var(--v3-border-default); border-radius: var(--v3-radius-sm);
  padding: 6px 8px; cursor: pointer;
}
/* 점은 작게, 투명 패딩을 포함한 탭 영역은 헤더 아이콘과 같은 44px로 둔다. */
.__v3sh_authchip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; padding: 17.5px; background: transparent; border: none;
  border-radius: var(--v3-radius-md); cursor: pointer;
}
.__v3sh_authchip::before {
  content: ''; width: 9px; height: 9px; flex-shrink: 0; border-radius: 50%; background: currentColor;
}
.__v3sh_authchip_loggedin { color: var(--v3-accent); }
.__v3sh_authchip_loggedout { color: var(--v3-text-dim); }
.__v3sh_authchip:focus-visible { outline: 2px solid var(--v3-accent); outline-offset: 2px; }
.__v3sh_authmenu button:hover { color: var(--v3-accent); }
.__v3sh_authmenu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: var(--v3-z-overlay);
  width: max-content; max-width: min(260px, 80vw); padding: 8px;
  color: var(--v3-text-main); background: var(--v3-bg-panel); border: 1px solid var(--v3-border-default);
  border-radius: var(--v3-radius-sm);
}
.__v3sh_authmenu [role='status'] { color: var(--v3-text-muted); font-size: 12px; }
.__v3sh_authmenu .__v3sh_authprofile {
  width: 100%; text-align: left; margin-bottom: var(--v3-space-2);
  overflow-wrap: anywhere;
}
.__v3sh_authmenu .__v3sh_authname { display: block; }
.__v3sh_authmenu .__v3sh_authname[hidden] { display: none; }
.__v3sh_authmenu .__v3sh_authid { display: block; color: var(--v3-text-dim); }
.__v3sh_authmenu button:focus-visible { outline: 2px solid var(--v3-accent); outline-offset: 2px; }
.__v3sd_textagepicker { position: relative; display: inline-block; }
.__v3sd_textagepicker > .__v3sd_textage {
  padding: 0; vertical-align: middle; background: transparent; border: 0; cursor: pointer;
}
.__v3sd_textagepicker > .__v3sd_textage:focus-visible,
.__v3sd_textagemenu a:focus-visible { outline: 2px solid var(--v3-accent); outline-offset: 2px; }
.__v3sd_textagemenu { left: 0; right: auto; top: calc(100% + 4px); }
.__v3sd_textagemenu[hidden] { display: none; }
.__v3sd_textagemenu a {
  display: block; padding: 6px 8px; color: var(--v3-text-main); text-decoration: none; white-space: nowrap;
}
.__v3sd_textagemenu a:hover { color: var(--v3-accent); }

*, *::before, *::after {
  box-sizing: border-box;
}

body {
  font-family: var(--v3-font-sans);
  background: var(--v3-bg-page);
  color: var(--v3-text-main);
  margin: 0;
}

/* 🔴 iOS 자동 확대 방지 — 폼 요소의 computed font-size 가 **16px 미만이면** 사파리가 포커스 때
   페이지를 통째로 확대하고, 손으로 되돌리기 전까지 풀리지 않는다(실기 확인, 2026-09-17).
   16px 은 「확대되지 않는 최솟값」이라 더 키울 이유가 없다.
   🔴 개별 클래스 규칙이 이것을 덮는다(클래스 > 요소 선택자). **새 인풋을 만들 때 16px 미만을 주지 마라** —
   이 기준선은 font-size 를 아예 안 적은 인풋만 받아낸다.
   🔴 **현재 v3 의 폼 요소는 넷이다**(2026-09-20 세션 56 갱신 — 종전 「둘」은 S3-15d-2 전 값이다):
   `.__v3sh_search` · `.__v3c_searchbox` 는 자기 규칙에서 16px 을 명시하고,
   **`.__v3c_wknum`(연습곡 ☆범위 input) · `.__v3c_wksel`(연습곡 드롭박스 — `__v3c_wksub`·`__v3c_wkparent` 포함)은
   `components.css` 에서 11px 을 명시한다.** 그 둘은 아래 승격 규칙이 모바일에서 되돌린다.
   ⚠️ 그 둘의 **배색도 `components.css` 가 든다**(2026-09-20 사용자 결정으로 **어둡게** 갔다) —
   여기서는 **글꼴 크기만** 다룬다. 색을 이 파일로 끌어오지 마라. */
input, textarea, select {
  font-size: 16px;
}

/* 🔴 모바일 승격 — v1 `styles.css:2891-2892` 계승 (S3-15d-2).
   **v1 연습곡 패널의 실제 화면값은 「PC 11px / 모바일 16px」이다** — 인라인 `font-size:11px`(`recFolder.js:258`)을
   v1 의 이 미디어쿼리가 **덮는다**(author `!important` 는 inline normal 을 이긴다).
   🔴 **인라인 리터럴이 아니라 *화면값* 을 옮기는 것이 이관의 계약이다** — S3-15d-2 가 리터럴만 보고
   전 폭 11px 로 냈다가 §6.2 회귀 검토 4차가 잡았다. 위 iOS 금지(`:19-20`)를 스스로 뚫고 있었다.
   🔴 **`!important` 가 *필요하다*.** `index.html` 이 `tokens → styles → components` 순으로 로드해
   이 파일이 **먼저** 온다 — `@media` 는 특이도를 안 올리므로, 여기에 `.__v3c_wknum` 을 써도
   `components.css` 의 (0,1,0) 을 **순서로 못 이긴다.** v1 이 `!important` 를 쓴 것과 같은 이유다.
   🔴 **여기에 `display` 를 적지 마라** — `recs.css.test.mjs` 의 R-14 ②는 `components.css` **한 파일만** 읽어
   이 규칙을 못 본다. ⚠️ **이 파일의 `__v3c_` 셀렉터는 여전히 0건이다**(승격은 요소 선택자다 —
   §6.2 회귀 5차가 실측으로 정정했다. 종전 문안 「이제 1건이다」는 **거짓**이었다). 그래도 이 규칙은
   `__v3c_wknum`·`__v3c_wksel` 의 **computed 값을 바꾸므로** R-14 ②의 사각에 있다 ⇒ **R-15 가 지킨다.**
   ⚠️ 전환점은 **768px** 이고 v1 과 같은 값이다. v3 의 다른 전환점(600·480·900)과 섞지 마라 —
   이것은 레이아웃이 아니라 **iOS 폼 확대 방지**라 기준이 다르다. */
@media (max-width: 768px) {
  input, textarea, select { font-size: 16px !important; }
}

.__v3sh_header {
  position: sticky;
  top: 0;
  z-index: var(--v3-z-header);
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: var(--v3-space-5);
  padding: calc(var(--v3-space-4) + env(safe-area-inset-top, 0px)) var(--v3-space-7) var(--v3-space-4);
  background: var(--v3-bg-page);
  border-bottom: 1px solid var(--v3-border-default);
}

.__v3sh_menubtn {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: var(--v3-radius-md);
  color: var(--v3-text-secondary);
  cursor: pointer;
}

.__v3sh_menubtn:hover {
  color: var(--v3-text-strong);
}

.__v3sh_menubtn:focus-visible,
.__v3sh_modebtn:focus-visible {
  outline: 2px solid var(--v3-accent);
  outline-offset: 2px;
}

/* __v3sh_root 는 id 다 — 클래스 셀렉터로 쓰면 조용히 안 걸린다. */
#__v3sh_root[data-v3sh-menu-open="true"] .__v3sh_menubtn {
  color: var(--v3-accent);
}

.__v3sh_searchbox {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 420px;
  position: relative;
}

.__v3sh_search {
  width: 100%;
  padding: 5px var(--v3-space-6);
  background: var(--v3-bg-surface);
  border: 1px solid var(--v3-border-default);
  border-radius: var(--v3-radius-md);
  color: var(--v3-text-main);
  /* 🔴 13px 이었다 — iOS 가 포커스 때 확대했다(위 「iOS 자동 확대 방지」). 16px 미만으로 되돌리지 마라.
     높이는 line-height 로 묶어 둔다: 16 + 5*2(padding) + 1*2(border) = 28px 로, 13px 시절 27px 에서 1px 만 는다. */
  font-size: 16px;
  line-height: 1;
  font-family: inherit;
}

.__v3sh_searchsummary {
  display: none;
}

.__v3sh_searchsummary[hidden] {
  display: none;
}

.__v3sh_search:focus {
  outline: none;
  border-color: var(--v3-accent);
}

.__v3sh_search::placeholder {
  color: var(--v3-text-dim);
}

.__v3sh_search::-webkit-search-cancel-button {
  display: none;
}

/* 검색 드롭다운 — 옵션 5행만 보이고 나머지는 스크롤(최근 본 유저 최대 20명 · 세션 99 사용자 요청). */
:root { --v3sh-search-option-h: 40px; }
.__v3sh_searchlist { max-height: calc(var(--v3sh-search-option-h) * 5); overflow-y: auto; overscroll-behavior: contain; }

.__v3sh_searchpopover {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: var(--v3-z-sticky);
  /* 스크롤은 목록(.__v3sh_searchlist)이 한다 — 라벨은 고정, 옵션만 5행(세션 99 사용자 요청). */
  background: var(--v3-bg-panel);
  border: 1px solid var(--v3-border-default);
  border-radius: var(--v3-radius-md);
  box-shadow: var(--v3-shadow-popover);
}

.__v3sh_searchpopover[hidden] {
  display: none;
}

.__v3sh_searchstatus {
  padding: var(--v3-space-6) var(--v3-space-7);
  color: var(--v3-text-muted);
  font-size: 12px;
}

/* 매칭이 있을 때는 문구가 비므로, 빈 상태 칸이 목록 위에 여백을 만들지 않게 한다. */
.__v3sh_searchstatus:empty {
  display: none;
}

/* 🔴 행 높이를 못 박아야 「5행」이 된다 — 목록 max-height 가 이 변수 × 5 다. 바꾸려면 변수 하나만 바꿔라. */
.__v3sh_searchoption {
  box-sizing: border-box;
  height: var(--v3sh-search-option-h);
  padding: var(--v3-space-6) var(--v3-space-7);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--v3-space-6);
  color: var(--v3-text-main);
  cursor: pointer;
}

.__v3sh_searchoption:hover {
  background: var(--v3-bg-surface-hover);
}

.__v3sh_searchoption[data-v3sh-active="true"] {
  background: var(--v3-bg-surface);
  color: var(--v3-text-strong);
}

.__v3sh_searchoption_name {
  color: inherit;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.__v3sh_searchoption_id {
  color: var(--v3-text-dim);
  font-family: var(--v3-font-mono);
}

/* Grid "기억하기"로 고정된 유저 표시. 토글 UI 는 Grid 단계에서 붙는다. */
.__v3sh_searchoption_pin {
  flex-shrink: 0;
  padding: 0 var(--v3-space-4);
  border-radius: var(--v3-radius-sm);
  background: var(--v3-accent-soft);
  color: var(--v3-accent);
  font-size: 11px;
}

.__v3sh_scrim {
  position: fixed;
  inset: 0;
  /* 🔴 서랍(--v3-z-overlay)보다 **한 칸 아래**다. 같은 값으로 되돌리지 마라 —
     동률이면 DOM 순서(sidebar 42 < scrim 58)가 이겨 scrim 이 메뉴 위를 덮고
     항목 클릭이 전부 「메뉴 닫기」로 먹힌다(2026-09-20 실기 사고). 모달보다 아래인 것은 그대로다(정본 §1.2 C6). */
  z-index: var(--v3-z-scrim);
  background: var(--v3-scrim);
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--v3-duration-dialog) var(--v3-ease-default), visibility var(--v3-duration-dialog) var(--v3-ease-default);
}

#__v3sh_root[data-v3sh-menu-open="true"] .__v3sh_scrim {
  visibility: visible;
  opacity: 1;
}

.__v3sh_sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  width: min(280px, 80vw);
  z-index: var(--v3-z-overlay);
  display: flex;
  flex-direction: column;
  background: var(--v3-bg-panel);
  border-right: 1px solid var(--v3-border-default);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-top: calc(var(--v3-space-7) + env(safe-area-inset-top, 0px));
  padding-bottom: calc(var(--v3-space-7) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-105%);
  visibility: hidden;
  transition: transform var(--v3-duration-dialog) var(--v3-ease-default), visibility var(--v3-duration-dialog) var(--v3-ease-default);
}

#__v3sh_root[data-v3sh-menu-open="true"] .__v3sh_sidebar {
  transform: none;
  visibility: visible;
}

.__v3sh_menulist {
  list-style: none;
  margin: 0;
  padding: 0;
}

.__v3sh_menulist_end {
  margin-top: auto;
  padding-top: var(--v3-space-5);
  border-top: 1px solid var(--v3-border-subtle);
}

.__v3sh_menuitem {
  /* min-height 로 터치 타깃을 확보하므로 block 이면 글자가 위로 쏠린다 — flex 로 세로 가운데 정렬한다. */
  display: flex;
  align-items: center;
  width: 100%;
  text-align: left;
  padding: var(--v3-space-6) var(--v3-space-9);
  min-height: 44px;
  background: transparent;
  border: none;
  color: var(--v3-text-secondary);
  font-size: 14px;
  font-family: inherit;
  cursor: pointer;
  transition: color var(--v3-duration-base), background var(--v3-duration-base);
}

.__v3sh_menuitem:hover {
  color: var(--v3-text-strong);
  background: var(--v3-bg-surface-hover);
}

.__v3sh_menuitem:focus-visible {
  outline: 2px solid var(--v3-accent);
  outline-offset: -2px;
}

@media (prefers-reduced-motion: reduce) {
  .__v3sh_scrim,
  .__v3sh_sidebar {
    transition: none;
  }
}

.__v3sh_modetoggle {
  display: inline-flex;
  overflow: hidden;
  flex-shrink: 0;
  border: 1px solid var(--v3-border-default);
  border-radius: var(--v3-radius-xl);
}

.__v3sh_modebtn {
  padding: 5px var(--v3-space-7);
  background: transparent;
  border: none;
  color: var(--v3-text-disabled);
  font-size: 13px;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  transition: color var(--v3-duration-base), background var(--v3-duration-base);
}

.__v3sh_modebtn:hover {
  color: var(--v3-text-secondary);
}

.__v3sh_modebtn[aria-pressed="true"] {
  color: var(--v3-text-strong);
  background: var(--v3-accent);
}

/* 🔴 메인 여백은 `--v3-main-pad` 하나로 정한다 — 탭줄·서브탭·필터바·본문의 full-bleed 음수 마진
   (`components.css` `.__v3c_pdtabs`·`.__v3c_pdbody`·`.__v3c_pdfilter`·`.__v3c_pdsubtabs`)이 같은 변수를 상쇄한다.
   변수를 main 에 두어 자손이 상속받는다 — 모바일에서 값만 바꾸면 상쇄도 같이 따라간다(`playdata.css.test.mjs`). */
.__v3sh_main {
  --v3-main-pad: var(--v3-space-9);
  max-width: var(--v3-content-max);
  margin: 0 auto;
  padding: var(--v3-main-pad);
}

/* 모바일은 메인 여백 2px(2026-09-28 세션 112, 사용자 요청: 「안 그래도 좁은데 마진 때문에 더 좁다」).
   ⚠️ 전환점 600px 은 아래 헤더 모바일 규칙과 같은 값이다. */
@media not all and (min-width: 900px) {
  @media not all and (min-width: 600px) and (pointer: fine) {
  .__v3sh_main { --v3-main-pad: var(--v3-space-1); }
  }
}

/* 프로필 화면은 main 여백 없이 가장자리까지 쓴다(2026-09-25 사용자 요청). */
.__v3sh_main[data-v3sh-page="profile"] {
  padding: 0;
}

.__v3sh_brand {
  text-align: center;
  padding: 64px var(--v3-space-9);
}

.__v3sh_brand h1 {
  margin: 0;
  color: var(--v3-text-strong);
  font-size: 22px;
  font-weight: 700;
}

.__v3sh_brand p {
  margin: var(--v3-space-4) 0 0;
  color: var(--v3-text-muted);
  font-size: 13px;
}

@media not all and (min-width: 900px) {
  @media not all and (min-width: 600px) and (pointer: fine) {
  .__v3sh_header {
    padding-left: var(--v3-space-5);
    padding-right: var(--v3-space-5);
  }

  /* 🔴 모바일 — 검색 드롭다운이 화면 폭을 다 쓴다(2026-09-29 세션 120 사용자 요청: 좁아서 글자가 안 보였다).
     검색박스의 position 을 풀어 팝오버(absolute)의 기준을 sticky 헤더로 올린다 —
     그러면 left:0/right:0 이 헤더(=화면) 양 끝, top:100% 이 헤더 바로 아래가 된다.
     ⚠️ 헤더(.__v3sh_header)가 sticky(= 위치 지정 요소)라서 성립한다. 헤더의 position 을 static 으로 바꾸면 기준이 더 위로 올라가 깨진다. */
  .__v3sh_searchbox {
    max-width: none;
    position: static;
  }

  .__v3sh_searchpopover {
    border-radius: 0;
    border-left: 0;
    border-right: 0;
  }

  .__v3sh_modebtn {
    padding-left: var(--v3-space-6);
    padding-right: var(--v3-space-6);
  }
  }
}

@media (min-width: 900px), (min-width: 600px) and (pointer: fine) {
  .__v3sh_searchbox[data-v3sh-summary-fields='all'] {
    --v3sh-summary-slot: 55%;
  }

  .__v3sh_searchbox[data-v3sh-summary-fields='core'] {
    --v3sh-summary-slot: 35%;
  }

  .__v3sh_searchbox[data-v3sh-summary-visible='true'][data-v3sh-summary-measured='true'] .__v3sh_search {
    padding-right: calc(var(--v3sh-summary-w, 0px) + var(--v3-space-6) + var(--v3-space-6));
  }

  .__v3sh_searchsummary {
    position: absolute;
    right: var(--v3-space-6);
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
    white-space: nowrap;
    overflow: hidden;
    text-align: right;
    width: max-content;
    max-width: var(--v3sh-summary-slot);
    display: block;
  }

  .__v3sh_searchsummary[hidden] {
    display: none;
  }
  /* 🔴 **데스크톱은 상단 가로 메뉴줄이다** (2026-09-19 세션 51, 사용자 지시).
     ⚠️ **종전은 좌측 320px 상시 노출 사이드바였다**(정본 §23 · §23.1 D-2).
     사용자가 「PC 에서 항상 열려 있으니 디자인이 별로」라 해 뒤집었다.
     🔴 **하나만 바꾼다 — 같은 `nav` 요소를 CSS 로 다시 놓는 것이고 마크업은 한 벌이다.**
     항목을 두 벌로 복사하지 마라 — 갈리면 한쪽만 고쳐진다.
     🔴 D-1 은 그대로 유효하다 — **JS 로 화면폭을 감지하지 않는다. CSS 만으로 한다**
     (jsdom 에 `matchMedia` 가 없어 JS 분기를 두면 그 축이 통째로 미시험이 된다).
     🔴 여는 수단(menubtn)을 감춰 `data-v3sh-menu-open` 은 false 인 채로 둔다 —
     그래서 포커스 트랩이 데스크톱에서는 애초에 켜지지 않는다. */
  #__v3sh_root {
    padding-left: 0;
  }

  /* 🔴 **헤더·메뉴줄의 *내용*을 메인과 같은 폭(960px)에 맞춘다**(2026-09-19 세션 51, 사용자 지시).
     종전에는 둘 다 화면 폭을 그대로 먹어 **본문은 가운데 960px 인데 위 두 줄만 끝까지 늘어났다.**
     🔴 **막대 자체를 960px 로 줄이지 않는다** — 배경은 화면 폭 그대로 두고 `padding-inline` 으로
     안쪽만 민다. 줄이면 위아래로 배경이 끊겨 떠 있는 카드처럼 보인다.
     ⚠️ `max()` 라서 좁은 화면에서는 종전 패딩(`--v3-space-7`)이 그대로 이긴다.
     ⚠️ 이렇게 하면 메뉴 글자가 **메인 박스 왼쪽 끝 + 12px** 에 놓여
     PlayData 탭줄(full-bleed + 탭 자신의 12px 패딩)의 첫 글자와 **세로로 맞는다.** */
  .__v3sh_header,
  .__v3sh_sidebar {
    padding-inline: max(var(--v3-space-7), calc((100% - var(--v3-content-max)) / 2));
  }

  /* 🔴 `position: fixed` 를 푸는 순간 **흐름 상의 DOM 순서**가 자리를 결정한다 —
     그래서 `index.html` 에서 이 `nav` 를 **header 바로 뒤 · strip 앞**으로 옮겨 두었다.
     🔴 **sticky 다**(2026-09-19 세션 51, 사용자 지시) — `app.js` 가 이 요소를
     **헤더 다음 줄**로 `stickyTop.register` 하므로 실제 `top` 은 그 모듈이 인라인으로 덮어쓴다.
     여기 `top: 0` 은 그 모듈이 안 돌았을 때의 폴백이다(헤더 뒤로 숨는 것을 막는다).
     ⚠️ 모바일에서는 같은 요소가 `position: fixed` off-canvas 라
     `createStickyTop` 이 **스택에서 자동으로 뺀다**(`sticky-top.js` 의 `isOutOfFlow`).
     그래서 JS 에 화면폭 분기가 없다 — 정본 §23.1 D-1 이 그대로 유효하다. */
  .__v3sh_sidebar {
    position: sticky;
    top: 0;
    z-index: var(--v3-z-sticky);
    inset: auto;
    width: auto;
    flex-direction: row;
    align-items: stretch;
    overflow-y: visible;
    overflow-x: auto;
    border-right: none;
    border-bottom: 1px solid var(--v3-border-default);
    padding-top: 0;
    padding-bottom: 0;
    /* 🔴 높이 32px(테두리 포함) — 바로 아래 Compact Strip(`.__v3c_strip` · 32px)과 맞춘다(2026-09-27 세션 106, 사용자 지시 · 종전 42px).
       항목은 위아래 패딩 없이 이 높이를 채우고(`align-items: stretch`) 글자는 항목의 flex 가 세로 가운데에 둔다. */
    box-sizing: border-box;
    height: 32px;
    transform: none;
    visibility: visible;
  }

  .__v3sh_menulist {
    display: flex;
  }

  .__v3sh_sidebar > .__v3sh_menulist { flex: 0 0 auto; }

  /* 🔴 항목은 `ul > li > button` 이다 — `li` 는 flex 로 줄 높이(32px)까지 늘어나지만 그 안의 버튼은 글자 높이뿐이라
     위에 붙고 강조선이 줄 가운데 떠 보였다(2026-09-27 세션 106 · 32px 로 줄인 뒤 사용자 실기 보고).
     `li` 도 flex 로 만들어 버튼이 늘어나게 한다 — 글자는 버튼 자신의 flex 가 세로 가운데에 둔다. */
  .__v3sh_menulist > li {
    display: flex;
  }
  /* hidden 속성이 있는 메뉴는 가로 메뉴줄에서도 숨긴다 — 위 display:flex 가 hidden 을 덮지 않게. */
  .__v3sh_menulist > li[hidden] {
    display: none;
  }

  /* 설정 묶음 — 세로 리스트에선 아래로 밀렸고 가로에선 오른쪽 끝으로 밀린다. */
  .__v3sh_menulist_end {
    margin-top: 0;
    margin-left: auto;
    padding-top: 0;
    border-top: none;
  }

  /* v1 탭 꼴 — `.__v3c_pdtab`(`components.css`)과 **같은 모양**으로 맞춘다.
     ⚠️ 토큰도 그쪽과 같은 것을 쓴다 — 두 줄이 위아래로 나란히 뜼므로 값이 갈리면 바로 보인다. */
  .__v3sh_menuitem {
    width: auto;
    min-height: 0;
    /* ⚠️ 위아래 패딩 0 — 메뉴줄 32px 높이를 채운다(세션 106). 그래서 PlayData 탭줄(`.__v3c_pdtab`)과 **높이는 갈린다**(좌우 12px·글자·강조선은 같다). */
    padding: 0 var(--v3-space-7);
    font-size: 13px;
    font-weight: 600;
    color: var(--v3-text-dim);
    white-space: nowrap;
    border-bottom: 2px solid transparent;
  }

  .__v3sh_menuitem:hover {
    color: var(--v3-text-muted);
    background: transparent;
  }

  /* 🔴 현재 메뉴 — `app.js` 의 `syncActiveMenu()` 가 라우트마다 붙인다.
     `.__v3c_pdtab[aria-current='page']` 와 같은 꼴이다. */
  .__v3sh_menuitem[aria-current='page'] {
    color: var(--v3-accent);
    border-bottom-color: var(--v3-accent);
  }

  /* 여는 버튼과 뎄은 필요 없다. */
  .__v3sh_menubtn {
    display: none;
  }

  .__v3sh_scrim {
    display: none;
  }
}
/* 계정 메뉴의 언어 선택(한 | 日 | En)은 로그인 상태와 관계없이 표시한다. 현재 언어는 accent 색. */
.__v3sh_authmenu .__v3sh_authlang {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px;
  color: var(--v3-text-dim);
}
.__v3sh_authmenu .__v3sh_authlang button {
  background: none;
  border: 0;
  padding: 2px 4px;
  font: inherit;
  color: var(--v3-text-muted);
  cursor: pointer;
}
.__v3sh_authmenu .__v3sh_authlang button[aria-pressed='true'] {
  color: var(--v3-accent);
  font-weight: 700;
}

/* 모바일 하단 바로가기 — 데스크톱 메뉴 전환점의 정확한 부정 조건을 사용한다. */
.__v3sh_bottomnav {
  display: none;
}

@media not all and (min-width: 900px) {
  @media not all and (min-width: 600px) and (pointer: fine) {
    body {
      --v3sh-bottom-nav-height: calc(56px + env(safe-area-inset-bottom, 0px));
    }

    .__v3sh_bottomnav {
      position: fixed;
      left: 0;
      right: 0;
      bottom: 0;
      box-sizing: border-box;
      height: var(--v3sh-bottom-nav-height);
      padding-bottom: env(safe-area-inset-bottom, 0px);
      padding-left: env(safe-area-inset-left, 0px);
      padding-right: env(safe-area-inset-right, 0px);
      display: grid;
      grid-template-columns: repeat(5, minmax(0, 1fr));
      z-index: var(--v3-z-header);
      background: var(--v3-bg-panel);
      border-top: 1px solid var(--v3-border-default);
      margin: 0;
    }

    .__v3sh_bottomnav .__v3sh_bottomitem {
      padding: 4px 0;
      min-width: 0;
      min-height: 44px;
      height: 100%;
      box-sizing: border-box;
      flex-direction: column;
      justify-content: center;
      gap: 2px;
      font-size: 11px;
      line-height: 14px;
      text-align: center;
    }

    .__v3sh_bottomnav .__v3sh_bottomitem [data-v3sh-menu-label] {
      white-space: nowrap;
    }

    .__v3sh_bottomnav .__v3sh_bottomitem svg {
      width: 20px;
      height: 20px;
      flex-shrink: 0;
    }

    .__v3sh_bottomnav .__v3sh_bottomitem[aria-current='page'] {
      color: var(--v3-accent);
      background: var(--v3-bg-accent-soft);
    }

    .__v3sh_bottomnav .__v3sh_bottomitem:focus-visible {
      outline: 2px solid var(--v3-accent);
      outline-offset: -2px;
    }

    #__v3sh_main {
      padding-bottom: calc(var(--v3-main-pad) + var(--v3sh-bottom-nav-height));
    }

    html {
      scroll-padding-bottom: calc(56px + env(safe-area-inset-bottom, 0px) + 8px);   /* html 은 body 의 변수를 상속받지 못한다 */
    }

    #__v3sh_toast {
      bottom: calc(40px + var(--v3sh-bottom-nav-height));
    }

    #__v3sh_root:has(#__v3sh_search:focus) .__v3sh_bottomnav {
      display: none;
    }
  }
}
