body {
    margin: 0;
    padding: 0;
    overflow: hidden;
    height: 100%;
    background: var(--color-surface);
    /* 더블탭 확대만 끈다(핀치 확대·스크롤은 유지). 버튼을 빠르게 두 번 누르면 iOS Safari가
       클릭 대신 페이지를 확대해버렸다(뷰어 화면 각도 +/−에서 발견, doc/ui-guide.md §5-6).
       네 페이지(c1080·routes·admin·privacy)가 모두 이 규칙을 쓴다. Cesium 캔버스는 자체
       touch-action:none이라 지도 드래그·핀치에는 영향이 없다. */
    touch-action: manipulation;
  }

  /* [hidden] 속성은 항상 이겨야 한다 — 아래 .탐색영역 등 일부 요소가 자체
     display:flex를 선언하면 동일 특이도의 UA 규칙([hidden]{display:none})을
     소스 순서로 이겨버려 hidden=true인데도 보이는 버그가 생긴다(실측: routes.html
     검색 시 탐색영역이 안 사라짐). !important로 항상 우선하게 고정한다. */
  [hidden] {
    display: none !important;
  }

  #chart {
    display: block; /* ⭐ 블록 요소로 변경하여 하단 미세 여백 제거 */
    width: 100%;
    height: 100%;
    margin: 0;
  }

  #compass {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 120px;
    height: 120px;
    z-index: 999;
    transform-origin: center center;
    pointer-events: none;
  }

  #compass svg {
    width: 100%; /* SVG가 #compass div의 전체 너비를 차지하도록 */
    height: 100%;
    transform-origin: center center;
  }

  /* 좌상단 재생 컨트롤 오버레이(데스크톱/넓은 화면 기본값). 차트 안에 넣지
     않는 이유는 common.js의 경유지 라벨 Y좌표가 216px 차트 높이 기준으로
     튜닝되어 있어, 차트 높이를 줄이는 컨트롤을 넣으면 그 값들을 다시 맞춰야
     하기 때문이다. 모바일 세로 화면에서는 이 오버레이 대신 지도 위가 아닌
     독립된 상단 영역(1:7:2 비율)으로 바뀐다 — c1080.html 인라인 <style>의
     @media (max-width:600px) and (orientation:portrait) 블록 참고(소스 순서
     함정 때문에 이 오버라이드는 style.css가 아니라 그쪽에 있다). */
  #controls {
    position: absolute;
    top: 10px;
    left: 10px;
    z-index: 999;
    display: flex;
    align-items: center;
    gap: 6px;
    /* 나침반(우상단 120px+여백)을 피해 폭이 모자라면 줄을 바꾼다(2026-10-15: 확대·축소가 툴바로 들어와 1100px 이하에서 겹쳤다). */
    flex-wrap: wrap;
    max-width: calc(100% - 160px);
    background: rgba(255, 255, 255, 0.85);
    border-radius: var(--radius-md);
    padding: 6px 10px;
    font-family: sans-serif;
    font-size: var(--font-size-sm);
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  }

  #controls button {
    cursor: pointer;
  }

  #controls button:disabled {
    cursor: not-allowed;
    opacity: 0.5;
  }

  /* 데스크톱 컨트롤 바 정렬 — <a>(routesLink)는 padding+border로 직접 높이가
     정해지지만 <select>/<button>은 브라우저 기본 렌더링에 맡겨져 있어 실측
     19~24px로 제각각이었다(실측: routesLink 23px, playBtn/stopBtn 24px,
     gpxSelect/speedSelect 19px, pitch 버튼 21px). box-sizing:border-box +
     동일 height로 전부 맞춘다. 순수 텍스트(statusText)·슬라이더(scrub)는
     애초에 "박스"가 아니라 대상에서 뺀다.
     테두리·배경·둥글기도 같이 통일한다(2026-09-23) — routesLink만 테두리
     알약 모양이고 나머지는 브라우저 기본이라 줄이 들쭉날쭉해 보였다.
     doc/ui-guide.md §6 "보조 버튼"/"입력칸" 기준(중립 아웃라인: surface +
     --color-border-strong + --radius-md)을 그대로 적용 — 새 토큰 없음. */
  #routesLink,
  #gpxSelect,
  #playBtn,
  #stopBtn,
  #speedSelect,
  #pitchUpBtn,
  #pitchDownBtn,
  #zoomInBtn,
  #zoomOutBtn,
  #dirBtn,
  #likeBtn,
  #routeSearchBtn {
    box-sizing: border-box;
    height: 24px;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
  }

  /* 아이콘(SVG)+라벨 버튼 — 안쪽 좌·우 여백은 브라우저 기본(약 6px)에 맡기면 좁아 보여
     명시한다. 아이콘은 currentColor를 따르므로 글자색을 토큰으로 고정한다. */
  #playBtn,
  #stopBtn,
  #pitchUpBtn,
  #pitchDownBtn,
  #zoomInBtn,
  #zoomOutBtn,
  #dirBtn,
  #likeBtn,
  #routeSearchBtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-4);
    padding: 0 var(--space-8);
    color: var(--color-text);
    font: inherit;
  }

  #pitchUpBtn,
  #pitchDownBtn,
  #zoomInBtn,
  #zoomOutBtn,
  #dirBtn,
  #likeBtn,
  #routeSearchBtn,
  #playBtn,
  #stopBtn {
    min-width: 28px;
    padding: 0 var(--space-4);
  }

  /* 방향 표시(2026-10-15): 흰 배경 그대로, 지금 방향의 화살표만 나침반 북쪽 바늘과 같은 빨강. 정방향 → (위쪽), 역방향 ← (아래쪽).
     색은 #icon-swap 안의 두 path가 --dir-fwd·--dir-rev로 받는다(c1080.html). 예전에는 역방향 켜짐이 초록 배경 + 흰 아이콘이었다(2026-10-16). */
  #dirBtn {
    --dir-fwd: var(--color-direction-active);
    --dir-rev: currentColor;
  }

  #dirBtn[aria-pressed="true"] {
    --dir-fwd: currentColor;
    --dir-rev: var(--color-direction-active);
  }

  #dirBtn[hidden] {
    display: none;
  }

  #routesLink {
    display: inline-flex;
    align-items: center;
    justify-content: center; /* 아이콘만(2026-10-16) */
    min-width: 28px;
    gap: var(--space-4);
    color: inherit;
    text-decoration: none;
    padding: 2px 6px;
    white-space: nowrap;
  }

  #routesLink:hover {
    background: rgba(0, 0, 0, 0.08);
  }

  #statusText {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
  }

  /* 지도 하단 중앙의 축척 바. 지형 피킹이 준비되기 전에는 숨겨둔다(cesium.js의
     축척_갱신이 visibility를 토글한다). */
  /* MapLibre 엔진(maplibre-core.js)이 지도 위에 올리는 진행 마커와 경유지 라벨. */
  .ml-marker {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--color-map-marker);
    border: 1px solid var(--color-map-marker-outline);
    pointer-events: none;
  }

  .ml-hidden {
    display: none;
  }

  .ml-waypoint {
    display: flex;
    flex-direction: column;
    align-items: center;
    pointer-events: none;
  }

  .ml-waypoint-label {
    font-weight: bold;
    line-height: 1.3;
    white-space: nowrap;
    color: var(--color-map-marker);
    /* 글자 테두리(2px) — 위성사진 위에서 읽히도록 네 방향으로 그린다 */
    text-shadow:
      -2px 0 var(--color-map-marker-outline),
      2px 0 var(--color-map-marker-outline),
      0 -2px var(--color-map-marker-outline),
      0 2px var(--color-map-marker-outline);
  }

  /* 재생 중 따로 그리는 코스 주변 이름(봉우리·마을·시설·호수). 경유지 라벨보다 작게. */
  .ml-place-label {
    font-size: var(--font-size-md);
    font-weight: bold;
    line-height: 1.3;
    white-space: nowrap;
    color: var(--color-map-marker);
    pointer-events: none;
    text-shadow:
      -1px 0 var(--color-map-marker-outline),
      1px 0 var(--color-map-marker-outline),
      0 -1px var(--color-map-marker-outline),
      0 1px var(--color-map-marker-outline),
      0 0 3px var(--color-map-marker-outline);
  }

  .ml-waypoint-stem {
    width: 3px;
    height: 30px;
    background: var(--color-map-marker);
  }

  /* MapTiler 지형으로 대체됐을 때만 붙는 로고(무료 계정 조건). */
  .ml-maptiler-logo img {
    display: block;
    height: 20px;
  }

  #scaleBar {
    position: absolute;
    bottom: 12px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 999;
    display: flex;
    flex-direction: column;
    align-items: center;
    pointer-events: none;
    font-family: sans-serif;
    color: var(--color-on-primary);
    text-shadow: 0 0 3px #000, 0 0 3px #000, 0 0 3px #000;
    visibility: hidden;
  }

  #scaleBarLabel {
    font-size: var(--font-size-xs);
    font-weight: bold;
    margin-bottom: 2px;
    white-space: nowrap;
  }

  #scaleBarLine {
    height: 5px;
    border-left: 2px solid var(--color-surface);
    border-right: 2px solid var(--color-surface);
    border-bottom: 2px solid var(--color-surface);
    box-sizing: content-box;
  }

  /* VWorld 3D 푸터의 면책 고지 — 폭 560px 이하가 되면 VWorld가 이 문구를 푸터 밖(위로
     17px)으로 빼내는데, 같은 처지인 #api-mapInfo(높이·각도)에는 반투명 배경을 줬으면서
     이 <p>에는 빠뜨렸다. 그래서 주황 글씨가 위성영상 위에 맨몸으로 얹혀 읽히지 않는다(실측).
     고지를 지우는 게 아니라 VWorld가 제 요소에 쓴 것과 같은 배경만 입혀 읽히게 한다 —
     출처 표시(브이월드·국토교통부 로고)와 고지 내용은 그대로 남는다. 561px 이상에서는
     고지가 푸터 안(static)에 있어 배경이 필요 없다(경계는 5px 단위로 좁혀 실측한 값). */
  @media (max-width: 560px) {
    #footer3d p {
      background: var(--color-overlay);
      padding: 2px 6px;
      border-radius: 3px;
    }
  }

  /* =======================================================================
     경로 목록 화면 (routes.html) — 지도 없이 3단(유형 › 노선 › 구간) 탐색 +
     검색/필터만 제공한다. cesium.js와 무관하게 이 절만 읽는다.
     ======================================================================= */

  body.경로목록-페이지 {
    overflow: auto;
    height: auto;
    min-height: 100%;
    background: var(--color-surface-subtle);
    font-family: sans-serif;
    color: #1a1a1a;
  }

  /* ---- 한화면 앱셸(routes.html 전용) — 헤더/도구모음/상세패널/탐색영역이
     뷰포트 높이 안에 고정되고, 넘치는 내용은 각 박스가 스스로 스크롤로
     흡수한다. privacy.html·admin.html은 긴 문서라 페이지 스크롤이 필요하므로
     .한화면 클래스가 없다 — 반드시 이 클래스가 같이 붙은 경우만 적용된다. */
  body.경로목록-페이지.한화면 {
    height: 100vh; /* dvh 미지원 폴백 */
    height: 100dvh; /* 모바일 주소창 접힘/펼침에 따라 실제 보이는 높이로 */
    overflow: hidden;
    display: flex;
    flex-direction: column;
  }

  .한화면 .목록-헤더,
  .한화면 .목록-도구모음,
  .한화면 .목록-알림 {
    flex: 0 0 auto;
  }

  .한화면 .상세패널 {
    flex: 0 1 auto;
    max-height: clamp(160px, 34vh, 320px);
    overflow-y: auto;
  }

  .한화면 .탐색영역 {
    flex: 1 1 0;
    min-height: 240px;
    align-items: stretch;
  }

  .한화면 .검색결과영역 {
    flex: 1 1 0;
    min-height: 0;
    overflow-y: auto;
  }

  .목록-헤더 {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 16px 20px 8px;
  }

  .목록-헤더 h1 {
    font-size: var(--font-size-xl);
    margin: 0;
  }

  /* 서비스 이름 "3D Road" — 3D와 Road를 다른 색으로(2026-10-15). 색은 tokens.css의 토큰. */
  .brand-3d {
    color: var(--color-brand-3d);
  }

  .brand-road {
    color: var(--color-brand-road);
  }

  .목록-헤더-개수 {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
  }

  .목록-헤더-뷰어링크 {
    margin-left: auto;
    color: var(--color-primary);
    text-decoration: none;
    font-size: var(--font-size-md);
  }

  .목록-헤더-뷰어링크:hover {
    text-decoration: underline;
  }

  .목록-헤더-인증 {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
  }

  .목록-헤더-인증 span {
    white-space: nowrap;
  }

  /* button/a 리셋은 .헤더-버튼 계열과 겹치는 속성(background/border/padding/
     color)을 절대 선언하지 않는다 — .목록-헤더-인증 button은 클래스+엘리먼트
     결합이라 특이도(0,1,1)가 .헤더-버튼-강조 같은 단일 클래스(0,1,0)보다 높아,
     여기서 background 등을 지정하면 pill 스타일이 항상 밀려 무효화된다(실측
     확인 — getComputedStyle에서 배경이 계속 투명으로 나왔다). */
  .목록-헤더-인증 button,
  .목록-헤더-인증 a {
    font: inherit;
    cursor: pointer;
    text-decoration: none;
  }

  .헤더-버튼 {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 5px 10px;
    border-radius: var(--radius-pill);
    font-size: var(--font-size-sm);
    font-weight: bold;
    white-space: nowrap;
  }

  .헤더-버튼-강조 {
    background: var(--color-primary);
    color: var(--color-on-primary);
    border: none;
  }

  .헤더-버튼-강조:hover {
    background: var(--color-primary-strong);
  }

  .헤더-버튼-보조 {
    background: var(--color-surface);
    color: var(--color-primary);
    border: 1px solid var(--color-primary);
  }

  .헤더-버튼-보조:hover {
    background: var(--color-primary-soft);
  }

  .목록-알림 {
    margin: 0 20px 8px;
  }

  .목록-알림-닫기 {
    margin-left: 10px;
    font: inherit;
    border: none;
    background: none;
    color: inherit;
    text-decoration: underline;
    cursor: pointer;
    padding: 0;
  }

  .목록-도구모음 {
    display: flex;
    gap: 8px;
    padding: 0 20px 12px;
    flex-wrap: wrap;
  }

  /* 검색창 왼쪽 ≡ 아이콘: 처음 화면으로 이동(2026-10-16). 검색 입력과 같은 높이로 늘어난다. */
  .홈-버튼 {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    align-self: stretch;
    min-width: 36px;
    box-sizing: border-box;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text);
    text-decoration: none;
  }

  .홈-버튼 svg {
    width: var(--icon-md);
    height: var(--icon-md);
  }

  .홈-버튼:hover {
    background: var(--color-surface-muted);
  }

  .목록-도구모음 input[type="search"] {
    flex: 1 1 260px;
    padding: 7px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-size: var(--font-size-md);
  }

  .목록-도구모음 select {
    padding: 7px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-size: var(--font-size-md);
    background: var(--color-surface);
  }

  /* ---- 탐색 영역: .한화면(body.경로목록-페이지.한화면, 위 앱셸 규칙)이
     탐색영역에 flex:1 1 0(남는 높이 전부)을 주므로, 그 안의 각 컬럼은
     처음부터 확정된 높이를 받는다 — 그래서 .목록-컬럼의 overflow-y:auto는
     화면 폭과 무관하게 기본값으로 둬도 안전하다(예전엔 auto-height 부모
     때문에 overflow-y:auto만 걸면 Chromium이 자식을 스크롤바 두께 수준으로
     찌그러뜨리는 문제가 있어 min-width:900px 전용으로 분리해뒀었다 — 지금은
     min-height:0이 그 High Chromium 버그를 막는 핵심이라 폭 분기가 필요 없다).
     좁은 화면(<900px)의 탭 전환 레이아웃은 아래 @media 블록에서 이 기본값을
     덮어쓴다. */
  .탐색영역 {
    display: flex;
    gap: 12px;
    padding: 0 20px 24px;
    align-items: flex-start;
  }

  .목록-컬럼 {
    flex: 1 1 0;
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
  }

  /* 유형 컬럼 + 근처 경로를 한 열로 세로 스택 (탐색영역의 첫 번째 자식) */
  .탐색영역-좌 {
    flex: 1 1 0;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .탐색영역-좌 > .목록-컬럼 {
    flex: 1 1 0;
  }

  .탐색영역-좌 > .근처경로 {
    flex: 0 1 auto;
    margin: 0;
    min-height: 0;
    max-height: 45%;
    overflow-y: auto;
  }

  /* 좁은 화면 전용 단계 탭 바 — 넓은 화면에서는 숨는다 */
  .탐색-탭 {
    display: none;
  }

  .목록-컬럼제목 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin: 0;
    padding: 10px 12px 6px;
    position: sticky;
    top: 0;
    background: var(--color-surface);
  }

  /* 근처 경로 섹션은 다른 세 컬럼과 달리 제목(.목록-컬럼제목) 대신 탭 2개로
     시작한다 — "근처 경로"/"좋아요 구간"을 토글 버튼 하나(텍스트만 바뀜)로
     두면 위치조회 단계에 따라 버튼 자체가 사라지는 문제가 있었다(본문 안에
     있었을 때). 탭 2개를 상시 노출하면 그 문제 없이 항상 오갈 수 있다.
     스타일은 좁은 화면 전용 .탐색-탭 필박스와 동일한 값을 그대로 재사용해
     시각적으로 통일한다. */
  .근처경로-탭줄 {
    display: flex;
    gap: 4px;
    padding: 6px 6px 0;
    position: sticky;
    top: 0;
    background: var(--color-surface);
  }

  .근처경로-탭 {
    flex: 1 1 auto;
    white-space: nowrap;
    font: inherit;
    font-size: var(--font-size-xs);
    padding: 6px 8px;
    /* 사이트 전체 버튼/select 테두리 통일(2026-09-23, doc/ui-guide.md §6
       "중립 아웃라인"): --color-border-strong + --radius-md로 다른 보조
       버튼·select와 맞춘다(이전엔 --color-border + --radius-lg였음). */
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text-secondary);
    cursor: pointer;
  }

  .근처경로-탭.선택됨 {
    background: var(--color-primary-soft);
    border-color: var(--color-primary-line);
    color: var(--color-primary-strong);
    font-weight: bold;
  }

  .목록-컬럼내용 {
    padding: 0 6px 6px;
  }

  .목록-소제목 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    padding: 8px 6px 2px;
    font-weight: bold;
  }

  .목록-빈상태 {
    padding: 16px 12px;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
  }

  /* 내 주변 코스에 반경 안 코스가 없을 때의 묶음(2026-10-15): 격자(#nearbyContent)의 한 칸이 아니라 전체 폭을 쓰고,
     "가장 가까운 코스" 행은 격자 칸 하나 폭(300px 안팎)을 넘지 않게 한다. */
  .근처-없음 {
    grid-column: 1 / -1;
  }

  .근처-없음 .경로행 {
    max-width: 360px;
  }

  /* ---- 근처 경로 — 유형 컬럼과 함께 .탐색영역-좌 안에 세로로 쌓인다
     (마진은 위 .탐색영역-좌 > .근처경로 규칙이 0으로 덮어쓴다). ---- */
  .근처경로 {
    margin: 0 20px 24px;
    padding: 4px 6px 10px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
  }

  .근처경로-본문 {
    padding: 0 6px;
  }

  .근처경로-본문 .상세-버튼,
  .근처경로-본문 .상세-버튼-보조 {
    margin: 4px 0;
  }

  @media (min-width: 640px) {
    .근처경로-본문 {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
      gap: 6px;
    }
    .근처경로-본문 .경로행 {
      margin: 0;
    }
  }

  .거리-배지 {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: var(--radius-pill);
    background: var(--color-primary-soft);
    border: 1px solid var(--color-primary-line);
    color: var(--color-primary-strong);
    font-size: var(--font-size-xs);
    font-weight: normal;
    vertical-align: middle;
  }

  .목록행 {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    text-align: left;
    padding: 8px 8px;
    border: none;
    background: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: var(--font-size-md);
    font-family: inherit;
    color: inherit;
  }

  .목록행:hover {
    background: var(--color-surface-muted);
  }

  .목록행.선택됨 {
    background: var(--color-primary-soft);
    font-weight: bold;
  }

  .목록행-이름 {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .목록행-부가 {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    white-space: nowrap;
    margin-left: 8px;
  }

  /* ---- 경로(L3) 행: 목록행보다 정보가 많은 카드형 ---- */
  .경로행 {
    display: block;
    width: 100%;
    text-align: left;
    padding: 8px 10px;
    margin: 3px 0;
    border: 1px solid transparent;
    background: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    font-family: inherit;
    color: inherit;
  }

  .경로행:hover {
    background: var(--color-surface-muted);
  }

  .경로행.선택됨 {
    background: var(--color-primary-soft);
    border-color: var(--color-primary-line);
  }

  .경로행-소속 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    margin-bottom: 2px;
  }

  .경로행-이름 {
    font-size: var(--font-size-md);
    font-weight: bold;
    margin-bottom: 3px;
  }

  /* 한 줄 부제 — GPX <trk><desc>를 사람이 직접 채워 넣은 값. 목록 행·상세
     패널 양쪽에서 제목 바로 아래 쓴다. */
  .부제 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    font-style: italic;
    margin: 0 0 6px;
  }

  .경로행-통계 {
    display: flex;
    gap: 10px;
    font-size: var(--font-size-xs);
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
  }

  .경로행-구간 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    margin-top: 2px;
  }

  .경로행-난이도 {
    padding: 0 6px;
    border-radius: var(--radius-sm);
    background: var(--color-surface-muted);
  }

  .난이도-어려움,
  .난이도-매우어려움 {
    background: var(--color-danger-soft);
    color: var(--color-danger);
  }

  .난이도-보통 {
    background: var(--color-warning-soft);
    color: var(--color-warning);
  }

  .난이도-쉬움 {
    background: #e3f3e6;
    color: var(--color-primary);
  }

  /* ---- 상세 패널: 경로 선택 시 검색창 아래 고정 노출 ----
     본문이 flex:1로 남는 공간을 다 차지하면 차트가 패널 오른쪽 끝에
     멀찍이 붙어버린다(실측: 본문 실제 내용 폭은 훨씬 좁은데 그 사이가
     빈 여백으로 벌어짐) — 본문 폭을 내용에 맞게 제한하고 전체를
     가운데 정렬해 본문+차트가 패널 중앙에 한 덩어리로 모이게 한다. */
  .상세패널 {
    display: flex;
    justify-content: center;
    gap: 24px;
    margin: 0 20px 16px;
    padding: 14px 18px;
    background: var(--color-surface);
    border: 1px solid #d7ead9;
    border-radius: var(--radius-lg);
  }

  .상세패널-본문 {
    flex: 0 1 440px;
    min-width: 0;
  }

  @media (max-width: 899px) {
    /* 헤더/도구모음 압축 — 한화면 앱셸에서 이 둘이 164px를 먹으면 남는
       높이가 목록에 너무 적게 돌아간다(실측: 압축 전 구간 컬럼이 86px). */
    .한화면 .목록-헤더 {
      padding: 8px 12px 4px;
      flex-wrap: wrap;
      row-gap: 2px;
    }
    .한화면 .목록-헤더 h1 {
      font-size: var(--font-size-lg);
    }
    .한화면 .목록-도구모음 {
      padding: 0 12px 8px;
      gap: 6px;
    }
    .한화면 .목록-도구모음 input[type="search"] {
      flex: 1 1 calc(100% - 50px); /* 첫 줄: ≡ 버튼(44px)+간격 6px 옆에 검색창, 선택 상자는 다음 줄 */
      min-width: 0;
      padding: 6px 8px;
      font-size: var(--font-size-sm);
    }
    .한화면 .목록-도구모음 select {
      flex: 1 1 0;
      min-width: 0;
      padding: 6px 8px;
      font-size: var(--font-size-sm);
    }
    /* 닉네임이 클릭 가능한 버튼이 되면서 모바일 터치 영역(44px)을 채워야
       한다 — 데스크톱은 다른 헤더 pill 버튼과 높이를 맞추려고 그대로 둔다. */
    .목록-헤더-닉네임 {
      min-height: var(--touch-min);
    }

    .상세패널 {
      flex-direction: column;
      /* .상세패널은 justify-content:center(위 기본 규칙)인데, column
         방향에서 center는 "세로 중앙 정렬"이 된다 — 내용이 max-height를
         넘으면 위쪽이 화면 밖으로 잘려나가고 scrollTop:0에서도 닿지 않는다
         (실측). flex-start로 항상 맨 위(제목)부터 보이게 고정한다. */
      justify-content: flex-start;
      max-height: 34vh;
    }
    /* flex-basis(440px)는 가로 모드 전용 폭 지정이다 — 세로로 쌓이면
       flex-direction:column 때문에 그 440px가 "높이"로 해석돼 본문 아래
       빈 여백이 크게 생긴다(실측). 좁은 화면에서는 내용 높이에 맞게 되돌린다.
       (주의: 이 규칙은 반드시 위 기본 .상세패널-본문 규칙보다 나중에 와야
       한다 — 같은 특이도라 소스 순서상 먼저 나오면 밀려서 무시된다. 이전에
       .목록-컬럼에서 같은 버그를 겪은 적이 있다.) */
    .상세패널-본문 {
      flex: 1 1 auto;
    }

    /* 탐색영역: 4개 박스를 동시에 쌓지 않고, 탭 하나만 남는 높이 전부를
       차지하는 단계 전환 방식(실측: 세로로 4개 다 쌓으면 유형=18px,
       구간=86px로 못 쓴다). */
    .탐색영역 {
      flex-direction: column;
      gap: 8px;
      padding: 0 12px 12px;
      min-height: 200px;
    }
    /* 유형/근처경로를 감싸던 래퍼를 투명화해 둘 다 .탐색영역의 직접
       flex 아이템이 되게 한다 — 그래야 탭 전환 규칙이 똑같이 적용된다. */
    .탐색영역-좌 {
      display: contents;
    }

    .탐색-탭 {
      display: flex;
      gap: 4px;
      flex: 0 0 auto;
      overflow-x: auto;
    }
    .탐색-탭 button {
      flex: 1 1 auto;
      white-space: nowrap;
      font: inherit;
      font-size: var(--font-size-sm);
      padding: 7px 8px;
      border: 1px solid var(--color-border-strong);
      border-radius: var(--radius-md);
      background: var(--color-surface);
      color: var(--color-text-secondary);
      cursor: pointer;
    }
    .탐색-탭 button.선택됨 {
      background: var(--color-primary-soft);
      border-color: var(--color-primary-line);
      color: var(--color-primary-strong);
      font-weight: bold;
    }
    .탐색-탭 button:disabled {
      opacity: 0.4;
      cursor: default;
    }

    /* 활성 탭 하나만 남기고 나머지는 완전히 숨겨, 그 하나가 탐색영역의
       남는 높이를 전부 받는다. */
    .탐색영역 [data-탭]:not(.탭-활성) {
      display: none !important;
    }
    .탐색영역 [data-탭].탭-활성 {
      flex: 1 1 0;
      min-height: 0;
      width: auto;
      max-height: none;
      margin: 0;
      overflow-y: auto;
    }

    /* UI 기준 §5(doc/ui-guide.md): 좁은 화면에서 누를 수 있는 요소는 44×44px 이상.
       글자 크기는 그대로 두고 누르는 영역(min-height)만 넓힌다. */
    .헤더-버튼,
    .목록-헤더-뷰어링크,
    .목록-헤더-인증 a,
    .목록-헤더-인증 button,
    .홈-버튼,
    .한화면 .목록-도구모음 input[type="search"],
    .한화면 .목록-도구모음 select,
    .탐색-탭 button,
    .목록행,
    .근처경로-탭,
    .관리자-탭,
    .stats-seg-btn,
    .data-credit-line,
    .data-credit,
    .상세-버튼,
    .inbox-upload button,
    .inbox-upload input[type="file"],
    .inbox-upload input[type="text"],
    .inbox-force-btn,
    .inbox-list button {
      min-height: var(--touch-min);
      min-width: var(--touch-min);
      box-sizing: border-box;
    }
    /* 출처 표시의 기본 규칙은 이 블록보다 뒤에 있으므로 부모 선택자로 특이도를 높여 이긴다. */
    .상세패널 .data-credit-line {
      display: flex;
      align-items: center;
    }
    /* 코스 출처 링크(#dataCredit, VWorld 전용 지도 안 크레딧)는 터치 44px 그대로 두고 글자에만 불투명 배경 칩을 깐다.
       링크가 position:absolute; z-index가 있어 스택 컨텍스트가 만들어져 z-index:-1이 링크 글자 뒤로 간다.
       출처 표시의 기본 규칙은 이 블록보다 뒤에 있으므로 id+class로 특이도를 높여 이긴다. */
    #dataCredit.data-credit {
      display: inline-flex;
      align-items: center;
      background: none;
    }
    #dataCredit.data-credit::before {
      content: "";
      position: absolute;
      left: 0;
      right: 0;
      top: 50%;
      height: 20px;
      transform: translateY(-50%);
      background: var(--color-surface);
      border-radius: var(--radius-sm);
      z-index: -1;
    }
    .목록-헤더-뷰어링크,
    .목록-헤더-인증 a {
      display: inline-flex;
      align-items: center;
    }
    /* iOS Safari는 16px 미만 입력칸에 포커스하면 화면을 확대한다(§6 입력칸). */
    .한화면 .목록-도구모음 input[type="search"],
    .한화면 .목록-도구모음 select {
      font-size: var(--font-size-lg);
    }
  }

  /* 모바일 가로 모드(뷰포트 높이가 작음) 전용 — .한화면 앱셸(페이지는 안 스크롤되고
     각 박스가 내부 스크롤로 흡수)은 세로 공간이 충분할 때만 성립한다. 가로 모드는
     높이 자체가 360~390px로 너무 작아 상세패널/탐색영역을 강제로 그 안에 욱여넣으면
     (이전 접근: order로 버튼줄을 제목 아래로 당기고 탐색영역을 min-height:90px로
     압축) 탐색영역 쪽이 짜부라진다(실측: 탭을 눌러도 콘텐츠가 화면 맨 아래에서
     거의 즉시 잘려 마치 화면이 고정된 것처럼 안 보였다). 대신 이 모드에서는 body
     자체를 스크롤 가능하게 풀어, 각 박스가 자기 콘텐츠 높이만큼 자연스럽게
     펼쳐지고(상세패널도 order 재배치 없이 세로 모드와 동일한 원래 순서) 사용자가
     페이지를 내려서 원하는 부분에 도달하게 한다. 이 블록은 반드시 위
     @media (max-width: 899px) 블록보다 나중에 와야 한다(동일 특이도, 소스 순서). */
  @media (max-width: 899px) and (max-height: 500px) {
    body.경로목록-페이지.한화면 {
      height: auto;
      min-height: 100dvh;
      overflow-y: auto;
      overflow-x: hidden;
    }

    .한화면 .상세패널 {
      flex: 0 0 auto;
      max-height: none;
      overflow-y: visible;
    }
    .상세패널 {
      /* 위 899px 미만 공통 블록이 건 max-height:34vh를 무효화 — 세로 모드와
         똑같이 자연스러운 높이로 펼쳐지게 한다. */
      max-height: none;
    }

    .한화면 .탐색영역 {
      flex: 0 0 auto;
      min-height: 0;
    }
    .탐색영역 [data-탭].탭-활성 {
      /* flex:1 1 0(flex-basis:0)을 물려받으면 auto-height 부모(.탐색영역,
         위에서 flex:0 0 auto로 바꿈) 안에서 2px로 찌그러지는 Chromium 버그가
         재현된다(실측 — .목록-컬럼에서 이미 한 번 겪었던 것과 동일한 패턴,
         style.css:264-272 주석 참고). flex-basis를 auto로 되돌려 자기
         콘텐츠 높이만큼 펼쳐지게 한다. */
      flex: 0 0 auto;
      min-height: 0;
      overflow-y: visible;
      max-height: none;
    }

    .한화면 .검색결과영역 {
      /* 동일한 flex-basis:0 붕괴 위험 — 검색 결과도 자연스러운 높이로. */
      flex: 0 0 auto;
      overflow-y: visible;
    }
  }

  /* 미니 차트 칼럼 — 지도 없이 오른쪽 여백에 지도모양(위) + 고도 프로필(아래)을
     세로로 쌓는다. 실측: 고도 차트를 패널 전체 폭 띠(14:1)로 늘였더니 실제
     급경사도 완만하게 뭉개져 보였다 — 여기(200px 폭)처럼 좁고 짧은 박스에
     담으면 같은 데이터라도 오르내림이 뚜렷하게 드러난다. */
  .상세패널-차트 {
    flex: 0 0 200px;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  .상세패널-차트 svg {
    width: 100%;
    display: block;
  }

  .상세패널-차트 svg.지도모양 {
    height: 120px;
    /* 경로 왼쪽 끝을 뷰박스 x=0에 붙였으므로 가장 왼쪽 경유지 원·선 굵기가 1~2px 밖으로 나간다 */
    overflow: visible;
  }

  .상세패널-차트 svg.고도 {
    height: 72px;
  }

  /* 모바일 폭(899px 이하)에서는 경로 모양 미리보기/고도 프로필 미니 차트를
     완전히 숨긴다 — .상세패널-본문이 899px 이하에서 flex:1 1 auto로 패널
     전체 폭을 받게 되어 있어(위 .한화면 규칙) 차트를 지워도 레이아웃이
     깨지지 않는다. 이 규칙은 반드시 위 기본 .상세패널-차트 규칙보다 뒤에
     와야 한다 — 같은 특이도라 소스 순서상 먼저 나오면 밀려서 무시된다. */
  @media (max-width: 899px) {
    .상세패널-차트 {
      display: none;
    }
  }

  .상세-소속 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
  }

  .상세-이름 {
    font-size: 18px;
    margin: 2px 0 10px;
  }

  .상세-통계행 {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    margin-bottom: 10px;
  }

  .상세-통계 {
    display: flex;
    flex-direction: column;
  }

  .상세-통계값 {
    font-size: var(--font-size-lg);
    font-weight: bold;
    font-variant-numeric: tabular-nums;
  }

  .상세-통계라벨 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
  }

  .상세-구간 {
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
    margin-bottom: 10px;
  }

  /* 코스 설명 — GPX <trk><desc>(부제)를 상세 패널에서는 본문 글자로 보인다(2026-10-15). 목록 행은 좁아서 작은 이탤릭 .부제 그대로. */
  .상세-설명 {
    font-size: var(--font-size-md);
    color: var(--color-text-secondary);
    line-height: 1.5;
    margin: 0 0 10px;
  }

  /* 긴 안내문 — GPX <trk><cmt>(통제 시기·주의사항 등). 상세 패널에만 두고
     목록 행에는 넣지 않는다(공간이 좁다). */
  .상세-안내 {
    font-size: var(--font-size-xs);
    color: var(--color-warning);
    background: var(--color-warning-soft);
    border: 1px solid #f0e2b0;
    border-radius: var(--radius-md);
    padding: 8px 10px;
    margin-bottom: 10px;
  }

  /* ---- 데이터 출처 표시(OpenStreetMap, ODbL) ----
     OSM 재단 출처 표시 기준(2021-06-25): "OpenStreetMap"을 명시하고 저작권 페이지로 연결,
     조작 없이 읽을 수 있어야 하며 글자 크기·대비는 접근성 기준을 따른다(doc/ui-guide.md). */
  .data-credit-line {
    display: block;
    margin-top: var(--space-8);
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    text-decoration: none;
  }

  /* 3D 뷰어(2026-10-16): 크레딧 줄이 없는 엔진(VWorld)에서만 보이는 지도 안 오른쪽 아래 출처. 엔진 하단 UI 바로 위로 올리는 bottom은
     cesium.js 크레딧_위치_갱신()이 정한다. 고도 차트에는 더는 얹지 않는다. */
  .data-credit {
    position: absolute;
    bottom: var(--space-8);
    right: var(--space-12);
    z-index: 999;
    padding: 0 var(--space-4);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--color-text-secondary);
    font-family: sans-serif;
    font-size: var(--font-size-xs);
    text-decoration: none;
  }

  .data-credit-line:hover,
  .data-credit:hover {
    text-decoration: underline;
  }

  /* flex 정렬은 반드시 이 기본 규칙에 둔다 — 모바일 미디어쿼리 블록(위쪽)에 두면 동일 특이도의
     이 규칙이 소스 순서상 나중이라 이겨버려, 44px 높이에서 <a> 버튼 글자가 위쪽에 붙었다(실측). */
  .상세-버튼 {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 8px 16px;
    background: var(--color-primary);
    color: var(--color-on-primary);
    text-decoration: none;
    border-radius: var(--radius-md);
    font-size: var(--font-size-md);
    font-weight: bold;
  }

  .상세-버튼:hover {
    background: var(--color-primary-strong);
  }

  .상세-버튼줄 {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
  }

  /* [정방향|역방향] [3D 지도] [ARound 앱]이 360px 폰의 상세 패널 한 줄에 들어가도록 이 줄의 버튼 안쪽 여백을 줄인다(2026-10-16). */
  .상세-버튼줄 .상세-버튼 {
    padding: 8px 10px;
  }

  /* 관리자에게만 보이는 표식 — 숨긴 경로도 관리자 목록에는 나오므로 구분이 필요하다. */
  .숨김-배지 {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: var(--radius-pill);
    background: var(--color-surface-muted);
    border: 1px solid var(--color-border-strong);
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-weight: normal;
    vertical-align: middle;
  }

  .좋아요-배지 {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: var(--radius-pill);
    background: #fdeaf0;
    border: 1px solid #f3b8c9;
    color: #c0396b;
    font-size: var(--font-size-xs);
    font-weight: normal;
    vertical-align: middle;
  }

  .상세-버튼-보조 {
    background: var(--color-surface);
    color: var(--color-primary);
    border: 1px solid var(--color-primary);
  }

  .상세-버튼-보조:hover {
    background: var(--color-primary-soft);
  }

/* ---- 코스 상세 참고 링크(2026-10-15) — 일반 방문자는 표시 중인 것만, 관리자는 숨김 포함 전체 + 관리 버튼 ---- */
  .route-links {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--color-border);
  }

  .route-links[hidden] {
    display: none;
  }

  .route-links-title {
    margin: 0 0 8px;
    font-size: var(--font-size-md);
    color: var(--color-text);
  }

  .route-link-list {
    margin: 0 0 8px;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .route-link-item {
    padding: 8px 10px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    overflow-wrap: anywhere;
  }

  /* 숨김 상태(관리자에게만 보인다)는 옅은 배경으로 구분한다. */
  .route-link-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    font-size: var(--font-size-md);
  }

  .route-link-anchor {
    color: var(--color-primary);
    text-decoration: underline;
    word-break: break-all;
  }

  .route-link-desc {
    margin-top: 4px;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
    white-space: pre-wrap;
  }

  .my-request-link,
  .request-link-line {
    font-size: var(--font-size-sm);
    overflow-wrap: anywhere;
  }

  .my-request-link a,
  .request-link-line a {
    color: var(--color-primary);
  }

/* ---- 코스 검색 팝업(2026-10-15) — 뷰어 코스 선택 상자를 누르면 열린다 ---- */
  #routeSearchBtn[hidden] {
    display: none;
  }

  /* 버튼·모달(z-index 999)보다 위. 키보드가 올라오는 모바일에서 입력창이 가려지지 않게 위쪽에 붙인다. */
  /* .모달-배경(z-index 100)이 뒤에서 다시 선언되므로 클래스 두 개로 특이도를 올려야 이긴다. */
  .모달-배경.route-search-backdrop {
    z-index: 2000;
    align-items: flex-start;
  }

  .route-search {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
    max-width: 480px;
    max-height: 85vh;
    padding: 16px;
    background: var(--color-surface);
    border-radius: var(--radius-lg);
  }

  .route-search-input {
    box-sizing: border-box;
    width: 100%;
    min-height: var(--touch-min);
    padding: 7px 12px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font: inherit;
    font-size: var(--font-size-lg);
  }

  .route-search-list {
    flex: 1 1 auto;
    min-height: 0;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    list-style: none;
  }

  .route-search-group {
    position: sticky;
    top: 0;
    padding: 8px 12px 4px;
    background: var(--color-surface);
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    font-weight: bold;
  }

  .route-search-item {
    display: flex;
    flex-direction: column;
    justify-content: center;
    box-sizing: border-box;
    min-height: var(--touch-min);
    padding: 6px 12px;
    border-radius: var(--radius-md);
    font-size: var(--font-size-md);
    color: var(--color-text);
    cursor: pointer;
    overflow-wrap: anywhere;
  }

  .route-search-item.is-current {
    font-weight: bold;
  }

  .route-search-item.is-active {
    background: var(--color-primary-soft);
  }

  .route-search-sub {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
  }

  .route-search-empty {
    padding: 16px 12px;
    color: var(--color-text-muted);
    font-size: var(--font-size-md);
    text-align: center;
  }

  .route-search-close {
    flex: none;
    align-self: flex-end;
    min-height: var(--touch-min);
  }

  /* ---- 관리자 신청 카드의 링크 영역(2026-10-15): 링크 + 오른쪽 끝 [표시] 버튼, 연결 코스 안내, 설명 입력 박스 ---- */
  /* 코스 목록 상세 패널: 방향 전환 버튼(2026-10-15) — 3D 뷰어의 #dirBtn과 같은 한 개의 아이콘 버튼(위 → · 아래 ←).
     버튼 줄(.상세-버튼줄) 맨 왼쪽에 놓인다 — [⇄] [3D 지도] [ARound 앱]. 이름은 title·aria-label("역방향으로 보기"/"정방향으로 보기"),
     지금 방향의 화살표만 나침반 북쪽 바늘과 같은 빨강이고(색만으로 구분하지 않도록 aria-pressed·라벨도 바뀐다) 누르면 방향이 뒤집힌다.
     (2026-10-16에는 [정방향|역방향] 글자 버튼, 2026-10-15 오전에는 [→][←] 두 개였다.) */
  .방향-칸 {
    --dir-fwd: var(--color-direction-active);
    --dir-rev: currentColor;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    width: var(--touch-min);
    min-height: var(--touch-min);
    padding: 0;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text-secondary);
    cursor: pointer;
  }

  .방향-아이콘 {
    display: block;
    width: var(--icon-lg);
    height: var(--icon-lg);
  }

  .방향-칸[aria-pressed="true"] {
    --dir-fwd: currentColor;
    --dir-rev: var(--color-direction-active);
  }

  /* "3D 지도"와 "ARound 앱"은 방향 버튼(44px)을 뺀 남는 폭을 반반 나눠 같은 너비가 된다(2026-10-15, flex-basis 0).
     min-width 94px은 "ARound 앱"(굵은 14px, 글자 약 92px)이 들어가는 값이다 — 두 버튼이 같은 값이라 좁은 폰에서도 같은 폭을 유지하고
     320px(방향 44 + 94×2 + 간격 8 = 240px)까지 한 줄에 들어간다. */
  /* 테두리 두께도 같아야 폭이 같다: ARound 앱(.상세-버튼-보조)은 1px 테두리가 있고 3D 지도는 없어, flex-basis 0의 최소 기준이
     22px 대 20px로 갈려 늘 정확히 2px 차이가 났다(2026-10-15 실측). 3D 지도에도 투명 1px 테두리를 준다. */
  .상세-버튼줄 .상세-버튼 {
    flex: 1 1 0;
    min-width: 94px;
    border: 1px solid var(--color-primary);
  }

  .상세-버튼줄 .상세-버튼:not(.상세-버튼-보조) {
    border-color: transparent;
  }

  /* ---- 코스 표시 관리: 관리자가 직접 붙이는 추가 링크(2026-10-16) ---- */
  .admin-course-links {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--color-border);
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .admin-course-link-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  .admin-course-link-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
  }

  .admin-course-link-text {
    flex: 1 1 200px;
    min-width: 0;
    display: flex;
    flex-direction: column;
  }

  .admin-course-link-url {
    overflow-wrap: anywhere;
    font-size: var(--font-size-sm);
  }

  .admin-course-link-form {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
  }

  .admin-course-link-form input,
  .admin-course-link-item input {
    flex: 1 1 160px;
    min-width: 0;
    min-height: var(--touch-min);
    padding: 0 10px;
    font: inherit;
    font-size: var(--font-size-md);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text);
  }

  .request-register {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    margin: 8px 0;
  }

  .request-register[hidden] {
    display: none;
  }

  .request-link-box {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface-muted);
  }

  .request-link-head {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--font-size-sm);
  }

  .request-link-head strong {
    flex: none;
    white-space: nowrap;
  }

  .request-link-head .request-link-anchor {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--color-primary);
    overflow-wrap: anywhere;
  }

  .request-link-toggle {
    flex: none;
    margin-left: auto;
  }

  .request-link-note {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
  }

  .request-link-box .신청-폼-필드 textarea {
    background: var(--color-surface);
  }

  .request-link-box > button {
    align-self: flex-start;
  }

  /* 코스 표시 관리의 코스 행 아래 "참고 링크 신청" 연결 영역 */
  .admin-link-connect {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-top: 8px;
    border-top: 1px dashed var(--color-border);
  }

  .admin-link-connect-title {
    font-size: var(--font-size-xs);
    font-weight: bold;
    color: var(--color-text-muted);
  }

  .admin-link-connected {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: var(--font-size-sm);
  }

  /* 신청 카드의 "연결 코스" 줄(2026-10-15): 연결됐으면 이름 + [연결 해제], 아니면 코스 검색 입력 + 결과 목록 + [연결] */
  .request-link-connect {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  .request-link-connect-title {
    font-size: var(--font-size-xs);
    font-weight: bold;
    color: var(--color-text-muted);
  }

  .request-link-connect-body {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  .request-link-connected {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    font-size: var(--font-size-sm);
  }

  .request-link-results[hidden] {
    display: none;
  }

  .request-link-search-wrap {
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  .request-link-search {
    box-sizing: border-box;
    width: 100%;
    min-height: var(--touch-min);
    padding: 7px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    font: inherit;
    font-size: var(--font-size-md);
  }

  .request-link-results {
    margin: 0;
    padding: 0;
    max-height: 240px;
    overflow-y: auto;
    list-style: none;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
  }

  .request-link-result {
    display: flex;
    flex-direction: column;
    justify-content: center;
    box-sizing: border-box;
    width: 100%;
    min-height: var(--touch-min);
    padding: 6px 10px;
    border: 0;
    background: none;
    color: var(--color-text);
    font: inherit;
    font-size: var(--font-size-md);
    text-align: left;
    cursor: pointer;
  }

  .request-link-result:hover,
  .request-link-result:focus-visible {
    background: var(--color-primary-soft);
  }

  .request-link-result-sub {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
  }

  /* 링크 박스 맨 아래 저장 줄(2026-10-15): 상태 글자 + [저장]. 변경이 있으면 상태 글자를 강조하고 [저장]을 켠다. */
  .request-link-savebar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
  }

  .request-link-status {
    margin-right: auto; /* 상태 글자가 비어 있어도 [저장]은 늘 오른쪽 */
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
  }

  .request-link-dirty {
    color: var(--color-warning);
    font-weight: bold;
  }

  .request-link-save:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .request-link-empty {
    padding: 10px;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
  }

  /* ---- 검색 결과: 탐색 영역을 대체해 평면 목록으로 표시 ---- */
  .검색결과영역 {
    padding: 0 20px 24px;
    max-width: 720px;
  }

  .검색-개수 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    margin: 0 0 8px;
  }

  /* ---- 모바일 사용법 모달 ---- */
  .사용법-모달 {
    background: var(--color-surface);
    border-radius: 10px;
    padding: 24px;
    width: 100%;
    max-width: 420px;
    max-height: 90vh;
    overflow-y: auto;
  }

  .사용법-모달 h2 {
    margin: 0 0 6px;
    font-size: 18px;
  }

  .사용법-모달-설명 {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin: 0 0 16px;
  }

  .사용법-플랫폼 {
    margin-bottom: 14px;
  }

  .사용법-플랫폼:last-of-type {
    margin-bottom: 0;
  }

  .사용법-플랫폼 h3 {
    margin: 0 0 6px;
    font-size: var(--font-size-md);
    color: var(--color-primary);
  }

  .사용법-플랫폼 ol {
    margin: 0;
    padding-left: 18px;
    font-size: var(--font-size-sm);
    color: var(--color-text);
  }

  .사용법-플랫폼 ol li {
    margin-bottom: 3px;
  }

  /* 닫기 버튼은 가운데에 둔다(2026-10-15). inline-flex 버튼이라 가만히 두면 왼쪽에 붙는다. */
  #mobileGuideCloseBtn {
    display: flex;
    min-height: var(--touch-min);
    margin: 16px auto 0;
  }

  /* 이미 홈 화면에서 standalone으로 실행 중인 사용자에게는 불필요한 안내라 숨긴다. */
  @media (display-mode: standalone) {
    #mobileGuideBtn {
      display: none;
    }
  }

  /* ---- 경로 신청 모달 ---- */
  .모달-배경 {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
    padding: 20px;
  }

  .신청-모달 {
    background: var(--color-surface);
    border-radius: 10px;
    padding: 24px;
    width: 100%;
    max-width: 420px;
    max-height: 90vh;
    overflow-y: auto;
  }

  .신청-모달 h2 {
    margin: 0 0 16px;
    font-size: 18px;
  }

  .신청-안내 {
    margin-bottom: 16px;
  }

  /* 진행 중 신청 한도 줄(2026-10-15). 가득 찼을 때(.가득)는 경고 색. */
  .신청-한도 {
    margin: 0 0 12px;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
  }

  .신청-한도.가득 {
    color: var(--color-warning);
  }

  /* 한도가 가득 차 꺼진 제출 버튼(2026-10-15): 켜진 버튼과 똑같이 보여 눌러도 반응이 없는 이유를 몰랐다(실측). 흐리게 하고 커서로도 알린다. */
  #requestForm button[type="submit"]:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .신청-안내목록 {
    margin: 0;
    padding-left: 18px;
  }

  .신청-안내목록 li {
    margin-bottom: 4px;
  }

  .신청-안내목록 li:last-child {
    margin-bottom: 0;
  }

  .신청-폼 {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  /* display를 주는 규칙이 hidden 속성을 이기지 않게 한다 — 제출 성공 때 폼을 숨긴다(2026-10-14). */
  .신청-폼[hidden],
  .request-done[hidden] {
    display: none;
  }

  /* 제출 성공 안내. 경고(.상세-안내, 노란색)가 아니라 성공 색(주 색의 옅은 배경)을 쓴다. */
  .notice-success {
    margin: 0 0 16px;
    padding: 10px 12px;
    font-size: var(--font-size-md);
    color: var(--color-primary-strong);
    background: var(--color-primary-soft);
    border: 1px solid var(--color-primary-line);
    border-radius: var(--radius-md);
  }

  .request-done-close {
    min-height: var(--touch-min);
  }

  .신청-폼-필드 {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: var(--font-size-sm);
    color: var(--color-text);
  }

  .신청-폼-필수 {
    color: #c0392b;
  }

  .신청-폼-필드 input,
  .신청-폼-필드 textarea {
    padding: 7px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font: inherit;
    font-size: var(--font-size-md);
    resize: vertical;
  }

  .신청-폼-필드 input {
    min-height: var(--touch-min);
  }

  .신청-폼-버튼줄 {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
  }

  /* ---- 내 계정(닉네임 클릭) 모달 ---- */
  .계정-모달 {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    padding: 24px;
    width: 100%;
    max-width: 360px;
    /* 내 신청 목록(2026-10-14)이 들어와 높이가 늘 수 있다 — 낮은 화면(모바일 가로)에서 잘리지 않게 모달 안에서 스크롤한다. */
    max-height: 90vh;
    overflow-y: auto;
  }

  /* ---- 내 신청 현황(계정 모달) ---- */
  .account-section-title {
    margin: 0 0 8px;
    font-size: var(--font-size-md);
  }

  .account-requests {
    margin: 0 0 20px;
  }

  /* 신청 내역: 한 행(신청일·코스·상태) 최대 5개까지 보이고 그 뒤는 스크롤(2026-10-15). 행 44px × 5 + 간격 4px × 4 */
  .my-request-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: calc(var(--touch-min) * 5 + 4px * 4);
    overflow-y: auto;
  }

  .my-request-item {
    flex: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
  }

  .my-request-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 8px;
    min-height: calc(var(--touch-min) - 2px);
    padding: 0 10px;
    font-size: var(--font-size-md);
  }

  button.my-request-row {
    width: 100%;
    border: 0;
    background: none;
    color: inherit;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
  }

  .my-request-date {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    white-space: nowrap;
  }

  .my-request-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 700;
  }

  .my-request-memo-icon {
    margin-left: 6px;
    vertical-align: -2px;
    color: var(--color-text-muted);
  }

  .my-request-row .관리자-상태 {
    white-space: nowrap;
  }

  .my-request-memo {
    padding: 0 10px 8px;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
    overflow-wrap: anywhere;
  }

  .my-request-memo[hidden] {
    display: none;
  }

  .my-request-empty,
  .my-request-note {
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
  }

  .my-request-note {
    margin-top: 8px;
    font-size: var(--font-size-xs);
  }

  .계정-모달-정보 {
    margin: 0 0 20px;
    display: flex;
    align-items: baseline;
    gap: 20px;
    font-size: var(--font-size-md);
  }

  .계정-모달-쌍 {
    display: flex;
    align-items: baseline;
    gap: 8px;
    min-width: 0;
  }

  .계정-모달-닉네임 {
    flex: 1 1 0;
  }

  .계정-모달-쌍:not(.계정-모달-닉네임) {
    flex: none;
  }

  .계정-모달-정보 dt {
    color: var(--color-text-muted);
    white-space: nowrap;
  }

  .계정-모달-정보 dd {
    margin: 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--color-text);
  }

  /* ---- 로그인 선택 창(2026-10-12) ---- */
  .login-modal {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    padding: 24px;
    width: 100%;
    max-width: 360px;
  }

  .login-modal h2 {
    margin: 0 0 8px;
    font-size: var(--font-size-lg);
  }

  .login-modal-desc {
    margin: 0 0 16px;
    font-size: var(--font-size-md);
    color: var(--color-text-secondary);
  }

  .login-modal-buttons {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 16px;
  }

  .login-provider-btn {
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    min-height: var(--touch-min);
    padding: 8px 16px;
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-size: var(--font-size-md);
    font-weight: bold;
    text-decoration: none;
  }

  /* hidden 속성이 display:flex에 지지 않게 한다(제공자 목록에 없는 버튼은 숨긴다). */
  .login-provider-btn[hidden] {
    display: none;
  }

  .login-provider-btn:hover {
    background: var(--color-surface-subtle);
  }

  .login-provider-logo {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
  }

  .login-modal-note {
    margin: 0 0 16px;
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
  }

  .login-modal-close {
    min-height: var(--touch-min);
  }

  .상세-버튼-위험 {
    background: var(--color-surface);
    color: var(--color-danger);
    border: 1px solid var(--color-danger);
  }

  .상세-버튼-위험:hover {
    background: var(--color-danger-soft);
  }

  /* 관리자 버튼의 대기 신청 건수 배지(2026-10-14, auth/me의 pendingRequests). */
  .admin-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    box-sizing: border-box;
    border-radius: var(--radius-pill);
    background: var(--color-danger);
    color: var(--color-on-primary);
    font-size: var(--font-size-xs);
    font-weight: bold;
    line-height: 1;
  }

  .목록-헤더-닉네임 {
    font: inherit;
    font-weight: bold;
    background: none;
    border: none;
    padding: 6px 4px;
    cursor: pointer;
    color: inherit;
  }

  .목록-헤더-닉네임:hover {
    text-decoration: underline;
  }

  /* ---- 관리자: 경로 신청 목록 ---- */
  .관리자-목록 {
    padding: 0 20px 24px;
    max-width: 720px;
    display: flex;
    flex-direction: column;
    gap: 14px;
  }

  .관리자-행 {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .관리자-행-머리 {
    display: flex;
    align-items: baseline;
    gap: 10px;
  }

  .관리자-상태 {
    font-size: var(--font-size-xs);
    padding: 2px 8px;
    border-radius: 10px;
    font-weight: bold;
  }

  .관리자-상태-대기 {
    background: var(--color-warning-soft);
    color: var(--color-warning);
  }

  .관리자-상태-승인 {
    background: var(--color-primary-soft);
    color: var(--color-primary);
  }

  .관리자-상태-등록 {
    background: var(--color-primary);
    color: var(--color-surface);
  }

  .관리자-상태-거절 {
    background: #f7e6e6;
    color: var(--color-danger);
  }

  .관리자-행-메타 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
  }

  .관리자-행-본문 {
    font-size: var(--font-size-sm);
    color: var(--color-text);
    white-space: pre-wrap;
  }

  .관리자-행-버튼줄 {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
  }

  /* ---- 관리자: 탭 + 경로 표시 관리 ---- */
  .관리자-탭줄 {
    display: flex;
    gap: 4px;
    padding: 0 20px;
    margin-bottom: 14px;
    border-bottom: 1px solid var(--color-border);
    /* 탭이 5개로 늘어 좁은 화면에서 다 안 들어갈 수 있다 — 넘치면 가로 스크롤. */
    overflow-x: auto;
  }

  .관리자-탭 {
    /* 줄어들면 좁은 화면(360px)에서 글자가 옆 탭과 겹친다 — 크기를 유지하고 넘치면 탭 줄이 가로로 스크롤된다(2026-10-15). */
    flex: none;
    font: inherit;
    font-size: var(--font-size-md);
    border: none;
    background: none;
    color: var(--color-text-muted);
    cursor: pointer;
    padding: 8px 14px;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    white-space: nowrap;
  }

  .관리자-탭.선택됨 {
    color: var(--color-primary);
    font-weight: bold;
    border-bottom-color: var(--color-primary);
  }

  .관리자-도구모음 {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    padding: 0 20px 12px;
    max-width: 720px;
  }

  .관리자-도구모음 input[type="search"] {
    flex: 1 1 200px;
    min-width: 0;
    padding: 7px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font: inherit;
    font-size: var(--font-size-md);
  }

  /* 코스 표시 관리의 유형·지역/트레일 선택상자(2026-10-15). 코스 목록의 .목록-도구모음 select와 같은 모양. */
  .관리자-도구모음 .admin-filter-select {
    flex: 0 1 auto;
    min-width: 0;
    max-width: 100%;
    padding: 7px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font-size: var(--font-size-md);
    background: var(--color-surface);
    color: var(--color-text);
    text-overflow: ellipsis; /* 긴 이름(해외 트레일 등)은 닫힌 상태에서 "…"로 끝낸다. 열면 전체 이름이 보인다 */
  }

  .관리자-도구모음 .admin-filter-select:disabled {
    color: var(--color-text-muted);
    background: var(--color-surface-muted);
  }

  /* 모바일: 같은 줄의 select·검색칸 높이를 터치 기준으로 맞추고 글자는 16px(포커스 확대 방지, ui-guide §8). */
  @media (max-width: 899px) {
    .관리자-도구모음 .admin-filter-select,
    .관리자-도구모음 input[type="search"] {
      box-sizing: border-box;
      min-height: var(--touch-min);
      font-size: var(--font-size-lg); /* 16px */
    }

    .관리자-도구모음 .admin-filter-select {
      /* 가장 긴 옵션("뚜르 드 몽블랑 (프랑스·이탈리아·스위스) (7)")이 390px 폭에서 끝이 잘렸다(2026-10-15 실측) — 좌우 여백을 줄여 내용 폭을 늘린다 */
      padding-left: 8px;
      padding-right: 4px;
    }
  }

  .관리자-개수 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
  }

  /* 코스 행: [이름·메타] 아래에 [파일명 입력·저장] + 간격 + [숨기기·ARound·GPX 다운로드] 한 줄(2026-10-08).
     폭이 모자라면(모바일 세로) 버튼 묶음만 다음 줄로 내려간다. */
  .관리자-경로행 {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-6);
  }

  .관리자-경로-정보 {
    min-width: 0;
  }

  .admin-route-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    /* 같은 줄일 때 [저장]과 [숨기기] 사이를 벌린다. 줄이 바뀌면 열 간격은 생기지 않는다. */
    column-gap: var(--space-16);
    row-gap: var(--space-6);
  }

  /* 버튼이 5개(3D 보기·GPX 다운로드 포함)라 모바일 세로 팝업(약 340px)에서는 한 줄에 안 들어간다 — 넘치면 아래 줄로 내린다(2026-10-15).
     예전에는 nowrap+flex-shrink:0이라 팝업 밖으로 밀려 가로 스크롤을 해야 했다. */
  .admin-route-actions {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-6);
    min-width: 0;
  }

  .admin-route-actions > * {
    white-space: nowrap;
  }

  .관리자-경로행 button,
  .관리자-경로행 .admin-download-link {
    flex-shrink: 0;
    border: 1px solid var(--color-primary);
    border-radius: var(--radius-md);
    font-size: var(--font-size-sm);
    padding: 6px 12px;
    cursor: pointer;
  }

  /* GPX 다운로드는 <a download>라 버튼과 같은 상자로 맞춘다(2026-10-08, 코스 목록 상세에서 이동) */
  .관리자-경로행 .admin-download-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    line-height: normal;
  }

  .관리자-파일명-편집 {
    display: flex;
    gap: 6px;
    margin-top: 6px;
  }

  .관리자-파일명-입력 {
    flex: 1 1 auto;
    min-width: 0;
    font: inherit;
    font-size: var(--font-size-xs);
    padding: 4px 8px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
  }

  /* 코스 행 안에서는 입력칸이 남는 폭을 차지하되, 220px 아래로 줄어야 하면 버튼 묶음을 다음 줄로 보낸다.
     (GPX 반입 탭의 .관리자-파일명-편집은 건드리지 않는다) */
  .admin-route-controls .관리자-파일명-편집 {
    flex: 1 1 220px;
    margin-top: 0;
  }

  /* 모바일(세로·가로) 터치 영역 44px. 위 기본 규칙보다 뒤에 둬야 이긴다(같은 특이도, 소스 순서). */
  @media (max-width: 899px) {
    .admin-route-controls .관리자-파일명-입력,
    .관리자-경로행 button,
    .관리자-경로행 .admin-download-link {
      min-height: var(--touch-min);
      box-sizing: border-box; /* 패딩·테두리를 44px 안에 포함(아니면 54~58px로 커진다) */
    }
  }

  /* ---- 관리자 코스 신청 표 + 작업 팝업(2026-10-15) ---- */
  .admin-request-table,
  .admin-route-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    font-size: var(--font-size-sm);
  }

  .admin-request-table th,
  .admin-route-table th {
    padding: 8px 10px;
    text-align: left;
    color: var(--color-text-muted);
    font-weight: bold;
    background: var(--color-surface-muted);
    border-bottom: 1px solid var(--color-border);
    white-space: nowrap;
  }

  .admin-request-table td,
  .admin-route-table td {
    box-sizing: border-box;
    height: var(--touch-min);
    padding: 6px 10px;
    border-bottom: 1px solid var(--color-border);
    vertical-align: middle;
  }

  .admin-request-row,
  .admin-route-row {
    cursor: pointer;
  }

  .admin-request-row:hover,
  .admin-request-row:focus-visible,
  .admin-route-row:hover,
  .admin-route-row:focus-visible {
    background: var(--color-primary-soft);
    outline: none;
  }

  .admin-request-row:focus-visible,
  .admin-route-row:focus-visible {
    box-shadow: inset 0 0 0 2px var(--color-primary);
  }

  .admin-request-pending .col-title {
    font-weight: bold;
  }

  .admin-request-table .col-date,
  .admin-request-table .col-done,
  .admin-request-table .col-status {
    white-space: nowrap;
  }

  /* 표가 화면보다 넓어지는 경우를 대비해 목록 영역이 가로로 스크롤된다(좁은 화면에서는 열을 줄여 보통 필요 없다). */
  #adminList {
    max-width: none; /* 카드 목록용 720px 제한을 푼다 — 표는 6열이 들어갈 폭이 필요하다 */
    overflow-x: auto;
  }

  .admin-request-table .col-title,
  .admin-request-table .col-user {
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .admin-request-table .col-route {
    max-width: 280px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  #routeList {
    max-width: none;
    overflow-x: auto;
  }

  .admin-route-table .col-title {
    max-width: 240px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: bold;
  }

  .admin-route-table .col-id,
  .admin-route-table .col-region {
    max-width: 200px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .admin-route-table .col-dist,
  .admin-route-table .col-status,
  .admin-route-table .col-links {
    white-space: nowrap;
  }

  .admin-route-table .col-status .숨김-배지 + .숨김-배지 {
    margin-left: 4px;
  }

  .admin-request-modal {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 12px;
    width: 100%;
    max-width: 760px;
    max-height: 90vh;
    overflow-y: auto;
    padding: 16px;
    background: var(--color-surface);
    border-radius: var(--radius-lg);
  }

  .admin-request-modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }

  .admin-request-modal-head h2 {
    flex: 1 1 auto;
    min-width: 0; /* 긴 제목이 [닫기] 버튼 밑으로 겹치지 않고 줄바꿈되게 한다 */
    margin: 0;
    font-size: var(--font-size-lg);
    overflow-wrap: anywhere;
  }

  .admin-request-modal-head button {
    flex: none;
    min-height: var(--touch-min);
  }

  /* 좁은 화면에서는 신청일시·코스·신청자·상태 네 열만 보이게 한다(경유지·처리시간은 팝업에서 본다). */
  @media (max-width: 899px) {
    .admin-request-table .col-route,
    .admin-request-table .col-done,
    .admin-inbox-table .col-dist,
    .admin-inbox-table .col-warn,
    .admin-route-table .col-id,
    .admin-route-table .col-dist,
    .admin-route-table .col-region {
      display: none;
    }

    .admin-route-table th,
    .admin-route-table td {
      padding-left: 6px;
      padding-right: 6px;
    }

    .admin-route-table .col-title {
      max-width: 160px;
    }

    .admin-request-table .date-year {
      display: none;
    }

    .admin-request-table th,
    .admin-request-table td {
      padding-left: 6px;
      padding-right: 6px;
    }

    .admin-request-table .col-title,
    .admin-request-table .col-user {
      max-width: 96px;
    }
  }

  /* ---- 등록 대기 목록 표 + 등록 절차 팝업(2026-10-15) ---- */
  .admin-inbox-table .col-title {
    max-width: 260px;
  }

  .admin-inbox-table .col-place {
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .admin-inbox-table .col-dist,
  .admin-inbox-table .col-status,
  .admin-inbox-table .col-warn {
    white-space: nowrap;
  }

  .inbox-warn-cell {
    color: var(--color-warning);
    font-weight: bold;
  }

  #inboxList {
    overflow-x: auto;
  }

  /* 업로드 탭의 "등록 대기 목록" 제목이 화면 왼쪽 끝에 붙던 것을 다른 영역과 같은 20px 여백에 맞춘다. */
  #panel반입 .관리자-설정-제목 {
    padding: 0 20px;
  }

  /* 좁은 화면: 위 기본값(260/220px)이 신청 표용 좁은 폭 규칙을 이기므로 여기서 다시 줄인다 — 360px에서 표가 화면을 밀어내던 것(실측). */
  @media (max-width: 899px) {
    .admin-inbox-table .col-title {
      max-width: 90px;
    }

    .admin-inbox-table .col-place {
      max-width: 70px;
    }
  }

  /* 파일명·트랙 제목처럼 공백 없는 긴 글자가 팝업을 화면 밖으로 밀어내지 않게 한다(360px 실측). */
  .inbox-work-modal,
  .inbox-work-modal #inboxWorkBody {
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .inbox-replace-banner {
    padding: 8px 10px;
    font-size: var(--font-size-sm);
    font-weight: bold;
    color: var(--color-primary-strong);
    background: var(--color-primary-soft);
    border: 1px solid var(--color-primary-line);
    border-radius: var(--radius-md);
  }

  .inbox-work-section {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 0;
    border-bottom: 1px solid var(--color-border);
  }

  .inbox-work-heading {
    margin: 0;
    font-size: var(--font-size-md);
  }

  .inbox-warn-lead {
    font-size: var(--font-size-sm);
    font-weight: bold;
    color: var(--color-warning);
  }

  .inbox-review-label {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    min-height: var(--touch-min);
    font-size: var(--font-size-sm);
    cursor: pointer;
  }

  .inbox-review-label input {
    flex: none;
    width: 20px;
    height: 20px;
    margin-top: 2px;
  }

  .inbox-steps {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .inbox-step {
    display: flex;
    gap: 10px;
    align-items: flex-start;
  }

  .inbox-step-icon {
    flex: none;
    width: var(--icon-lg);
    height: var(--icon-lg);
    margin-top: 2px;
    color: var(--color-text-muted);
  }

  .inbox-step-icon.inbox-step-done {
    color: var(--color-primary);
  }

  .inbox-step-main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
  }

  .inbox-step-title {
    font-size: var(--font-size-md);
    font-weight: bold;
  }

  .inbox-step-locked .inbox-step-main {
    opacity: 0.55;
  }

  .inbox-cmd {
    display: flex;
    align-items: flex-start;
    gap: 8px;
  }

  .inbox-cmd-text {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    padding: 8px 10px;
    overflow-x: auto;
    font-size: var(--font-size-xs);
    background: var(--color-surface-muted);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
  }

  .inbox-cmd-copy {
    flex: none;
  }

  .inbox-work-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding-top: 10px;
  }

  /* ---- 관리자: GPX 반입 ---- */
  .inbox-upload {
    padding: 0 20px 16px;
    max-width: 720px;
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .inbox-desc {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin: 0;
  }

  .inbox-upload input[type="text"] {
    padding: 7px 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    font: inherit;
    font-size: var(--font-size-md);
  }

  .inbox-upload button {
    align-self: flex-start;
  }

  .inbox-result,
  .inbox-list {
    padding: 0 20px 16px;
    max-width: 720px;
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .inbox-result-row {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: 12px 14px;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }

  .inbox-badge,
  .inbox-badge-warn,
  .inbox-badge-error {
    display: inline-block;
    align-self: flex-start;
    font-size: var(--font-size-xs);
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    font-weight: bold;
  }

  .inbox-badge {
    background: var(--color-primary-soft);
    color: var(--color-primary);
  }

  .inbox-badge-warn {
    background: var(--color-warning-soft);
    color: var(--color-warning);
  }

  .inbox-badge-error {
    background: var(--color-danger-soft);
    color: var(--color-danger);
  }

  .inbox-result-summary {
    font-size: var(--font-size-sm);
    color: var(--color-text);
  }

  .inbox-result-warnings {
    margin: 0;
    padding-left: 18px;
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
  }

  .inbox-force-btn {
    align-self: flex-start;
    border: 1px solid var(--color-danger);
    border-radius: var(--radius-md);
    color: var(--color-danger);
    background: none;
    font-size: var(--font-size-sm);
    padding: 6px 12px;
    cursor: pointer;
  }

  .inbox-list-row .관리자-파일명-편집 button {
    flex-shrink: 0;
  }

  #panel통계 {
    padding: 0 20px 24px;
    max-width: 720px;
  }

  .stats-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
    margin-bottom: 8px;
  }

  .stats-seg {
    display: flex;
    gap: 4px;
  }

  .stats-seg-btn {
    font: inherit;
    font-size: var(--font-size-xs);
    padding: 6px 12px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text-secondary);
    cursor: pointer;
  }

  .stats-seg-btn.선택됨 {
    background: var(--color-primary-soft);
    border-color: var(--color-primary-line);
    color: var(--color-primary-strong);
    font-weight: bold;
  }

  .관리자-통계-안내 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    margin: 0 0 12px;
  }

  .stats-chart {
    margin-bottom: 8px;
  }

  .stats-chart-svg {
    display: block;
    width: 100%;
    height: 120px;
  }

  .stats-chart-labels {
    display: flex;
    justify-content: space-between;
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    margin-top: 4px;
  }

  #statsBody h3 {
    font-size: var(--font-size-md);
    margin: 24px 0 8px;
  }

  #statsBody h3:first-child {
    margin-top: 0;
  }

  .관리자-통계표 {
    border-collapse: collapse;
    width: 100%;
    font-size: var(--font-size-sm);
  }

  .관리자-통계표 th,
  .관리자-통계표 td {
    border: 1px solid var(--color-border);
    padding: 6px 10px;
    text-align: left;
  }

  /* ---- 관리자: 설정 ---- */
  .관리자-설정 {
    max-width: 640px;
  }

  .관리자-설정-제목 {
    font-size: var(--font-size-lg);
    margin: 0 0 4px;
  }

  .관리자-설정-설명 {
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    margin: 0 0 16px;
  }

  .관리자-설정-선택지 {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 16px;
  }

  .관리자-설정-항목 {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    cursor: pointer;
  }

  .관리자-설정-항목:has(input:checked) {
    border-color: var(--color-primary);
    background: var(--color-primary-soft);
  }

  .관리자-설정-항목 input {
    margin-top: 2px;
    flex-shrink: 0;
  }

  .관리자-설정-항목-본문 {
    display: flex;
    flex-direction: column;
    gap: 2px;
    font-size: var(--font-size-md);
  }

  /* 지도 엔진 목록: 이름 한 줄 + 설명 툴팁(2026-10-16) */
  #engineOptions .관리자-설정-항목 {
    align-items: center;
    min-height: var(--touch-min);
    box-sizing: border-box;
    padding-top: 0;
    padding-bottom: 0;
  }

  #engineOptions .관리자-설정-항목-본문 {
    flex: 1 1 auto;
    min-width: 0;
  }

  .engine-info-btn {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--touch-min);
    height: var(--touch-min);
    margin-right: -10px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--color-text-muted);
    cursor: pointer;
  }

  .engine-info-btn:hover,
  .engine-info-btn[aria-expanded="true"] {
    color: var(--color-primary);
  }

  .engine-info-icon {
    width: var(--icon-lg);
    height: var(--icon-lg);
  }

  .engine-tip {
    position: absolute;
    z-index: 5;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    padding: 10px 12px;
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-float);
    font-size: var(--font-size-sm);
    font-weight: normal;
    line-height: 1.5;
    cursor: default;
  }

  .engine-tip[hidden] {
    display: none;
  }

  .engine-tip.engine-tip-up {
    top: auto;
    bottom: calc(100% + 4px);
  }

  .관리자-설정-항목-설명 {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
  }

  /* 로그인 전 방문자의 지도 엔진 select(2026-10-12). 입력칸 기준(doc/ui-guide.md §6)과 같고,
     16px 글자는 iOS가 포커스할 때 화면을 확대하지 않게 하려는 것이다. */
  .admin-guest-engine {
    box-sizing: border-box;
    width: 100%;
    height: var(--touch-min);
    padding: 0 10px;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: var(--font-size-lg);
  }

  .관리자-통계표 th {
    background: var(--color-surface-subtle);
    font-weight: 600;
  }
