/* =========================================================
   AquaLine Components  —  문서: 디자인/02-components.md
   순서: 셸 / 버튼 / 폼 / 카드 / 배지 / 스텝 / 예약 / 서명 / 티켓 / 표 / 오버레이
   ========================================================= */

/* ============ 1. 앱 셸 ============ */
.topbar {
  position: sticky; top: 0; z-index: var(--z-topbar);
  height: var(--h-topbar);
  background: rgba(255, 255, 255, .82);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--c-line);
}
.topbar--deep {
  background: rgba(var(--c-deep-rgb), .72);
  border-bottom-color: rgba(255, 255, 255, .12);
}
.topbar__in { display: flex; align-items: center; gap: var(--sp-6); height: 100%; }
.topbar__nav { display: flex; align-items: center; gap: var(--sp-5); }
.topbar__nav a {
  color: var(--c-muted); font-size: var(--fs-sm); font-weight: var(--fw-md);
  text-decoration: none; transition: color var(--t-fast) var(--ease);
}
.topbar__nav a:hover { color: var(--c-ink); }
.topbar__nav a.is-on { color: var(--c-primary); font-weight: var(--fw-sb); }

/* ---- 1.3b 메뉴 묶음 (플랫폼 / 이 풀장) ----
   상단바 한 줄에 **소속이 다른 두 축**이 섞여 있었다 — 대시보드·전체 풀장·마이페이지는
   PoolPass 것이고 풀장 홈·예약하기·강사·단체는 보고 있는 풀장 것인데, 순서가
   플랫폼·풀장·풀장·플랫폼·플랫폼·풀장으로 번갈아 놓여 위계가 보이지 않았다(2026-09-18 신고).
   실제로 풀장 항목만 `?pool=` 이 붙어 동작도 다른데 그 차이가 화면에 없었다.

   묶어서 세로선으로 가르고, **뒤 묶음에만** 이름을 붙인다 — 앞 묶음의 정체는 왼쪽 로고가
   이미 말하고 있어서, 둘 다 붙이면 좁은 줄에 라벨만 둘이 된다. */
.topbar__navgrp { display: flex; align-items: center; gap: var(--sp-5); }
.topbar__navgrp + .topbar__navgrp { margin-left: var(--sp-5); }
.topbar__navgrp + .topbar__navgrp::before {
  content: ''; width: 1px; align-self: stretch; margin-right: var(--sp-5);
  background: var(--c-line);
}
.topbar__navlbl {
  font-size: var(--fs-cap); font-weight: var(--fw-sb); color: var(--c-muted-2);
  white-space: nowrap; letter-spacing: .01em;
}
/* ⚠️ 묶음 라벨과 세로선이 들어오면서 폭이 모자란 구간(1024px 등)에서 로고가 줄어
   워드마크가 '대시보드' 위로 겹쳤다(2026-09-23 실측: 필요 1,066px · 가진 폭 1,009px).
   그 구간은 아래 1100px 경계에서 서랍으로 넘기고, 넓은 화면에서는 **로고만** 줄지 않게 한다.
   ⚠️ 메뉴 글자에 nowrap 을 걸지 않는다 — 영어·강사 계정(배지 'Active instructor')은 1101~1400px 에서
      한 줄에 안 들어가, 걸면 상단바가 화면 밖으로 밀려 **페이지 전체가 가로로 흔들린다**
      (같은 날 검토 실측: 1101 → 1193). 모자라면 메뉴가 두 줄로 접히는 편이 낫다.
   ⚠️ 로고 고정을 좁은 화면까지 걸지 않는다 — 글자 로고 풀장('블루레인 다이브센터')이 휴대폰에서
      줄지 못해 서랍 버튼이 화면 밖으로 나간다(375 → 383).
   ⚠️ **이미지 로고(.logo--img)만** 고정한다. 겹침은 워드마크 이미지에서만 났고, 글자 로고는 영어로
      바뀌면('Blue Lane Dive Center') 1101~1280px 에서 줄지 못해 가로 넘침을 만들었다(같은 날 재검토). */
@media (min-width: 1101px) {
  .topbar:not(.topbar--admin) .logo--img { flex: none; }
}
@media (max-width: 1240px) {
  .topbar:not(.topbar--admin) .topbar__in { gap: var(--sp-4); }
  .topbar__nav, .topbar__navgrp { gap: var(--sp-4); }
  .topbar__navgrp + .topbar__navgrp { margin-left: var(--sp-1); }
  .topbar__navgrp + .topbar__navgrp::before { margin-right: var(--sp-3); }
}

/* ---- 1.4 좁은 화면의 내비게이션 (.topbar__burger + .mnav) ----
   720px 이하에서 .topbar__nav 를 hide-sm 으로 숨겨 놓고 **대체 메뉴가 없었다.**
   휴대폰에서는 로고 말고 누를 것이 없어 대시보드·전체 풀장·마이페이지·예약·강사
   어디로도 갈 수 없었고, 로그아웃 버튼은 화면 밖으로 65px 밀려나 있었다
   (마이페이지에도 로그아웃이 없어 로그아웃할 방법 자체가 없었다).

   경계를 1100px 로 잡는다. 처음에는 900 이었다 — 768(태블릿 세로)에서 메뉴 + 언어 + 이름 +
   배지 + 로그아웃이 다 나오면 상단바가 94px 넘쳐서였다. 2026-09-18 에 메뉴를 소속별로 묶어
   라벨·세로선이 들어오자 1024(태블릿 가로·작은 노트북)에서도 넘쳤다(§1.3b 주석의 실측).
   ⚠️ app.js 의 WIDE(matchMedia) 와 **같은 값**이어야 한다 — 어긋나면 서랍이 열린 채 햄버거가 사라진다.
   ============================================================ */
.topbar__burger {
  display: none;                                  /* 900 초과에서는 존재하지 않는다 */
  align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: none;          /* 터치 타깃 44 */
  padding: 0; border: 1px solid var(--c-line); border-radius: var(--r-sm);
  background: var(--c-bg); color: var(--c-ink); cursor: pointer;
}
.topbar__burger:hover { background: var(--c-bg-soft); }
.topbar__burger span,
.topbar__burger span::before,
.topbar__burger span::after {
  display: block; width: 17px; height: 2px; border-radius: 2px;
  background: currentColor; content: "";
}
.topbar__burger span { position: relative; }
.topbar__burger span::before { position: absolute; top: -5px; }
.topbar__burger span::after  { position: absolute; top: 5px; }
/* 처리할 일이 있으면 점을 찍는다 — 메뉴를 열어야만 보이는 배지를 대신한다 */
.topbar__burger[data-dot="1"]::after {
  content: ""; position: absolute; margin: -18px 0 0 24px;
  width: 7px; height: 7px; border-radius: var(--r-full);
  background: var(--c-danger); border: 2px solid var(--c-bg);
}
.topbar--deep .topbar__burger { border-color: rgba(255, 255, 255, .3); background: rgba(255, 255, 255, .1); color: #fff; }

/* 메뉴 서랍 — 오른쪽에서 나온다. 상세용 .drawer(520px)와 쓰임이 달라 따로 둔다:
   이쪽은 '어디로 갈지', 저쪽은 '무엇을 볼지'다. */
.mnav {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: var(--z-drawer);
  width: min(320px, 86vw); background: var(--c-bg);
  box-shadow: var(--sh-4); display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform var(--t-slow) var(--ease-out);
  visibility: hidden;                             /* 닫혔을 때 탭 순서에서 빠진다 */
}
.mnav.is-open { transform: none; visibility: visible; }
.mnav__hd {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--c-line);
}
.mnav__bd { flex: 1 1 auto; overflow-y: auto; padding: var(--sp-4) var(--sp-3) var(--sp-6); }
.mnav__ft { padding: var(--sp-4) var(--sp-5); border-top: 1px solid var(--c-line); background: var(--c-bg-soft); }

.mnav__i {
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: 48px; padding: 0 var(--sp-4); border-radius: var(--r-sm);
  font-size: var(--fs-body); font-weight: var(--fw-md); color: var(--c-ink-2);
  text-decoration: none;
}
.mnav__i:hover { background: var(--c-bg-soft); color: var(--c-ink); text-decoration: none; }
.mnav__i[aria-current="page"] { background: var(--c-primary-soft); color: var(--c-primary-ink); font-weight: var(--fw-sb); }
.mnav__i .badge { margin-left: auto; }
.mnav__sep { height: 1px; margin: var(--sp-3) var(--sp-4); background: var(--c-line-2); }
.mnav__lbl { padding: 0 var(--sp-4) var(--sp-2); font-size: var(--fs-cap); color: var(--c-muted-2); }

@media (max-width: 1100px) {
  /* 관리자 화면은 상단바가 통째로 관리 메뉴(.anav)이고 이미 접혀서 돈다 — 건드리지 않는다 */
  .topbar:not(.topbar--admin) .topbar__nav,
  .topbar:not(.topbar--admin) .topbar__acct > .langsw,
  .topbar:not(.topbar--admin) .topbar__acct > .btn { display: none; }
  .topbar:not(.topbar--admin) .topbar__burger { display: inline-flex; position: relative; }
  .topbar__in { gap: var(--sp-3); }
}

/* ---- 1.5 관리자 상단 메뉴 (.topbar--admin + .anav) ----
   관리자 화면은 '읽는 화면'이 아니라 '쓰는 화면'이다. 메뉴를 본문 안에 두면
   매번 스크롤해서 찾아야 하므로 로고 바로 옆, 화면 최상단에 고정한다.
   본문은 한 번에 한 패널만 보여준다.
   상단바만 wrap(1120)이고 본문이 wrap--wide(1320)면 로고와 본문 왼쪽 끝이
   어긋나 보인다 — 관리자 상단바는 본문과 같은 폭을 쓴다(마크업에서 wrap--wide 를 함께 준다). */
.anav {
  display: flex; align-items: center; gap: var(--sp-5);
  min-width: 0; overflow-x: auto;
  scrollbar-width: none;                      /* 메뉴가 넘칠 때만 밀어서 본다 */
  /* ⚠️ 휴대폰(375px)에서는 메뉴 10개 중 6개가 화면 밖이다(2026-08-24 실측). 밀면 닿지만
     스크롤바를 감춰 놔서 '넘친다' 는 신호가 없다. **mask-image 로 가장자리를 흐리지 말 것** —
     mask 는 내용을 잘라내므로 §1.5 에서 일부러 안쪽으로 뒤집어 살린 포커스 링이 다시 잘린다.
     대신 admin.html 의 renderMenu() 가 활성 항목을 scrollIntoView 로 끌어온다 —
     ?tab= 딥링크에서 활성 밑줄과 심사 대기 배지가 화면 밖에 그려지던 것을 그렇게 없앴다. */
}
.anav::-webkit-scrollbar { display: none; }

/* 좁은 화면에서는 그룹 사이 간격을 줄인다.
   6개로 접고도 375px 에서 10px 이 모자라 마지막 '설정' 이 살짝 잘렸다(2026-08-26 실측).
   간격만 줄이면 스크롤 없이 전부 들어간다 — 글자 크기는 건드리지 않는다. */
@media (max-width: 720px) {
  .anav { gap: var(--sp-3); }
}

.anav__i {
  position: relative; flex: none;
  display: inline-flex; align-items: center; gap: 6px;
  height: var(--h-topbar); padding: 0 2px;
  font-size: var(--fs-sm); font-weight: var(--fw-md); color: var(--c-muted);
  white-space: nowrap; cursor: pointer;
  transition: color var(--t-fast) var(--ease);
}
.anav__i:hover { color: var(--c-ink); }
/* ⚠️ .anav 는 overflow-x:auto 라 overflow-y 도 auto 가 된다(둘 중 하나만 visible 일 수 없다).
   그래서 바깥으로 나가는 장식은 잘린다 — 밑줄은 상자 안(bottom:0)에 두고,
   포커스는 전역 링(outline-offset:2px, 바깥)을 **안쪽으로 뒤집어** 쓴다.
   포커스 표시를 없애는 것이 아니라, 잘리지 않는 형태로 바꾼 것이다. */
.anav__i[aria-current="page"] { color: var(--c-primary); font-weight: var(--fw-sb); }
.anav__i[aria-current="page"]::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 2px; background: var(--c-primary); border-radius: 2px 2px 0 0;
}

/* ---------- 관리 메뉴 그룹(펼침) ----------
   항목이 11개가 되면서 좁은 화면에서 대부분이 스크롤 밖으로 나갔다. 비슷한 것끼리
   6개 그룹으로 접어 375px 에서도 다 닿게 한다.

   ⚠️ **펼침 패널은 position:fixed 다.** .anav 가 overflow-x:auto 라 overflow-y 도
      auto 가 되어(둘 중 하나만 visible 일 수 없다) 안쪽에 그리면 잘린다.
      좌표는 admin.html 의 openDrop() 이 버튼 위치를 재서 넣는다. */
.anav__g { position: relative; flex: none; display: inline-flex; }

.anav__cv {
  width: 0; height: 0; margin-left: 2px;
  border-left: 3.5px solid transparent; border-right: 3.5px solid transparent;
  border-top: 4px solid currentColor;
  transition: transform var(--t-fast) var(--ease);
}
.anav__i--g[aria-expanded="true"] { color: var(--c-ink); }
.anav__i--g[aria-expanded="true"] .anav__cv { transform: rotate(180deg); }

.anav__d {
  /* 상단바(--z-topbar 200)보다 위, 모달(400)보다 아래 */
  position: fixed; z-index: 250;
  min-width: 168px; padding: 6px;
  /* ⚠️ `--c-surface` 라는 토큰은 이 저장소에 없다. 정의되지 않은 변수는 **투명**이 되어
     떠 있는 패널 뒤로 본문이 비친다(2026-08-26 실측). 카드와 같은 `--c-bg` 를 쓴다. */
  background: var(--c-bg); border: 1px solid var(--c-line);
  border-radius: var(--r-md); box-shadow: var(--sh-3);
}
.anav__d[hidden] { display: none; }

.anav__di {
  display: block; width: 100%; text-align: left;
  padding: 9px 10px; border-radius: var(--r-sm);
  font-size: var(--fs-sm); font-weight: var(--fw-md); color: var(--c-ink-2);
  white-space: nowrap; cursor: pointer;
}
.anav__di:hover { background: var(--c-bg-soft); color: var(--c-ink); }
.anav__di[aria-current="page"] { color: var(--c-primary); font-weight: var(--fw-sb); background: var(--c-primary-soft); }
.anav__i:focus-visible {
  outline: 2px solid var(--c-focus); outline-offset: -3px; border-radius: var(--r-xs);
}
/* 처리할 일 개수. 0이면 아예 렌더하지 않는다 — '0' 은 읽는 사람을 멈춰 세운다.
   숫자이므로 마크업에 .t-num 을 함께 붙인다(디자인 절대 규칙 ③). */
.anav__n {
  min-width: 18px; height: 18px; padding: 0 var(--sp-1); border-radius: var(--r-full);
  background: var(--c-danger); color: #fff;
  font-size: var(--fs-cap); font-weight: var(--fw-bd); line-height: 18px;
}

/* 한 줄에 안 들어가면 메뉴를 둘째 줄로 내린다.
   분기점 1260px 은 실측값이다 — 플랫폼 총관리자 기준 한 줄 최소폭:
     메뉴 8개 601px(심사 대기 배지가 뜨면 625px) + 로고 102 + 풀장 선택기 173
     + 계정 블록 214 + topbar__in gap 4×24=96 + .wrap 좌우 여백 40  ≈ 1,250px.
   ⚠️ 예전에 1100px 로 잡았더니 1,101~1,245px 구간(예: 1152×864, 최대화하지 않은 창)에서
      '설정' 이 통째로 잘렸다. 스크롤바를 숨겨 놨으므로 **잘렸다는 사실 자체가 안 보인다.**
      메뉴 라벨을 늘리면 이 임계도 같이 오르니 그때 다시 재라.
   .topbar__nav 처럼 hide-sm 으로 숨기는 선택지는 없다 — 관리자의 유일한 내비다. */
@media (max-width: 1260px) {
  .topbar--admin { height: auto; }
  .topbar--admin .topbar__in {
    flex-wrap: wrap; height: auto;
    padding-block: var(--sp-3); row-gap: var(--sp-2); column-gap: var(--sp-4);
  }
  .topbar--admin .anav {
    order: 9; width: 100%; gap: var(--sp-4);
    border-top: 1px solid var(--c-line); padding-top: var(--sp-2);
  }
  /* ⚠️ --btn-h 는 .btn 안에서만 선언된 지역 변수라 여기서는 무효다. 값을 직접 쓴다.
     44px 은 터치 타깃 최소치(00-principles.md)이고 4px 그리드 밖이라 대체 토큰이 없다. */
  .topbar--admin .anav__i { height: 44px; }
}

/* 폰 — 첫 줄(로고·풀장·계정)이 또 접히면 상단바가 3줄이 되어 화면을 다 먹는다.
   관리 화면에서 없어도 되는 것부터 덜어 2줄로 유지한다:
   역할 배지(관리자 화면에 있다는 사실이 이미 역할을 말한다)와 로고 글자. */
@media (max-width: 720px) {
  .topbar--admin .topbar__nav,
  .topbar--admin .logo__txt,
  .topbar--admin .badge { display: none; }
  /* .spacer 는 남은 공간을 전부 먹어 계정 블록을 셋째 줄로 밀어낸다 */
  .topbar--admin .spacer { display: none; }
  .topbar--admin .select { max-width: 34vw; }
}

.logo { display: inline-flex; align-items: center; gap: 9px; text-decoration: none; }
.logo:hover { text-decoration: none; }
.logo__mark {
  width: 26px; height: 26px; border-radius: 8px;
  background: var(--grad-accent);
  display: grid; place-items: center; flex: none;
  box-shadow: 0 2px 8px rgba(var(--c-brand-rgb), .35);
}
.logo__mark svg { width: 15px; height: 15px; }
.logo__txt {
  font-size: 16.5px; font-weight: var(--fw-bd); letter-spacing: -.03em; color: var(--c-ink);
}
.logo__txt em { font-style: normal; color: var(--c-primary); }

/* 풀장 자체 로고 — 이미지 잠금(app.js logoHTML).
   ⚠️ 높이로만 크기를 정하고 폭은 auto 다. 원본 비율이 풀장마다 다르므로 폭을 고정하면
      로고가 눌린다. width/height 속성은 로드 전 자리를 잡는 용도로만 넣는다.
   ⚠️ 배경이 흰 이미지라 **딥오션 상단바에는 쓰지 않는다**(logoHTML 이 걸러 낸다). */
.logo--img { gap: 8px; }
.logo__img { height: 26px; width: auto; display: block; flex: none; }
.logo__word { height: 19px; width: auto; display: block; flex: none; }

/* 아주 좁은 화면에서는 글자 부분을 접는다 — 마크만으로도 어느 풀장인지 안다.
   (aria-label 이 <a> 에 있으므로 이름은 화면낭독기에 그대로 남는다) */
@media (max-width: 400px) {
  .logo__word { display: none; }
}

.footer {
  background: var(--c-deep-1); color: var(--c-on-deep-2);
  padding-block: var(--sp-12) var(--sp-8); font-size: var(--fs-sm);
}
.footer a { color: var(--c-on-deep); }
.footer__grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: var(--sp-8); }
@media (max-width: 720px) { .footer__grid { grid-template-columns: minmax(0, 1fr); } }

/* ============ 2. 버튼 ============ */
.btn {
  --btn-h: 44px;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: var(--btn-h); padding-inline: var(--sp-5);
  border-radius: var(--r-sm);
  font-size: var(--fs-body); font-weight: var(--fw-sb); letter-spacing: var(--ls-normal);
  white-space: nowrap; text-decoration: none;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
  border: 1px solid transparent;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn.is-off { opacity: .45; pointer-events: none; }

.btn--primary { background: var(--c-primary); color: #fff; box-shadow: 0 2px 10px rgba(var(--c-brand-rgb), .28); }
.btn--primary:hover { background: var(--c-primary-ink); }
/* 다크 서피스에서는 --c-primary 가 밝은 청록으로 바뀌므로 글자를 어둡게 뒤집는다.
   (밝은 청록 + 흰 글자는 대비 1.9:1 로 읽히지 않는다) */
.on-deep .btn--primary { background: var(--c-accent); color: var(--c-deep-1); box-shadow: 0 2px 14px rgba(var(--c-accent-rgb), .3); }
.on-deep .btn--primary:hover { background: var(--c-on-deep-3); }
.btn--line { background: var(--c-bg); color: var(--c-ink); border-color: var(--c-line); }
.btn--line:hover { border-color: var(--c-muted-2); background: var(--c-bg-soft); }
.btn--soft { background: var(--c-primary-soft); color: var(--c-primary-ink); }
.btn--soft:hover { background: var(--c-primary-soft-2); }
.btn--ghost { background: transparent; color: var(--c-muted); }
.btn--ghost:hover { background: var(--c-bg-soft); color: var(--c-ink); }
.btn--danger { background: var(--c-danger); color: #fff; }
.btn--danger:hover { filter: brightness(.94); }
.btn--dangerline { background: var(--c-bg); color: var(--c-danger); border-color: #EBC7C3; }
.btn--dangerline:hover { background: var(--c-danger-soft); }

.btn--lg { --btn-h: 54px; padding-inline: var(--sp-8); font-size: 16px; border-radius: var(--r-md); }
.btn--sm { --btn-h: 34px; padding-inline: var(--sp-3); font-size: var(--fs-sm); border-radius: var(--r-xs); }
.btn--block { display: flex; width: 100%; }
.btn--icon { width: var(--btn-h); padding-inline: 0; }

/* ============ 3. 폼 ============ */
.field { display: block; }
.field__label {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--fs-sm); font-weight: var(--fw-sb); color: var(--c-ink-2);
  margin-bottom: 7px;
}
.field__label .req { color: var(--c-danger); font-weight: var(--fw-bd); }
.field + .field { margin-top: var(--sp-5); }

.input, .select, .textarea {
  width: 100%; height: 46px; padding: 0 14px;
  background: var(--c-bg);
  border: 1px solid var(--c-line); border-radius: var(--r-sm);
  color: var(--c-ink);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.textarea { height: auto; min-height: 108px; padding: 12px 14px; line-height: 1.62; resize: vertical; }
.input::placeholder, .textarea::placeholder { color: var(--c-muted-2); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--c-line-3); }
/* ⚠️ 여기에 outline:none 을 두지 않는다. (0,2,0) 이라 전역 :focus-visible (0,1,0) 을 이겨서
   **폼 필드에서만 포커스 링이 사라졌다** — 회원가입·명단 입력처럼 필드만 있는 화면은
   키보드로 어디에 있는지 전혀 알 수 없게 된다.
   테두리 색 + 안쪽 글로우(--sh-focus)는 마우스 클릭에도 반응하는 '지금 입력 중' 표시이고,
   포커스 링은 그 바깥에 별도로 그려진다. 둘은 역할이 다르므로 함께 둔다. */
.input:focus, .select:focus, .textarea:focus {
  border-color: var(--c-primary); box-shadow: var(--sh-focus);
}
.input[readonly], .input[disabled] { background: var(--c-bg-sink); color: var(--c-muted); }
.input.is-bad, .select.is-bad { border-color: var(--c-danger); }

.select {
  appearance: none; padding-right: 38px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' stroke='%235C7681' stroke-width='1.6' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center;
}

.help { margin-top: 6px; font-size: var(--fs-cap); color: var(--c-muted); }
.help--bad { color: var(--c-danger); }

.check { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; }
.check input { flex: none; width: 19px; height: 19px; margin: 1px 0 0; accent-color: var(--c-primary); cursor: pointer; }
.check__txt { font-size: var(--fs-sm); color: var(--c-ink-2); }

/* 선택 칩 — 종목 · 인원 · 역할 */
.chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 38px; padding-inline: 14px;
  border: 1px solid var(--c-line); border-radius: var(--r-full);
  background: var(--c-bg); color: var(--c-ink-2);
  font-size: var(--fs-sm); font-weight: var(--fw-md);
  /* ⚠️ transition:all 이 아니다 — all 은 **outline 까지** 애니메이션한다.
     그러면 Tab 을 옮길 때마다 포커스 링이 120ms 동안 번져 들어왔다 나간다(2026-08-22 실측).
     예약 흐름의 컨트롤은 키보드로 가장 빨리 훑는 곳이라 잔상이 그대로 보인다. */
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.chip:hover { border-color: var(--c-muted-2); }
.chip.is-on {
  background: var(--c-primary); border-color: var(--c-primary); color: #fff;
  font-weight: var(--fw-sb); box-shadow: 0 2px 8px rgba(var(--c-brand-rgb), .25);
}

/* 선택 카드 — 회원 유형 · 결제수단 */
.pick { display: grid; gap: var(--sp-3); }
.pick__item {
  position: relative; display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-4) var(--sp-5);
  border: 1.5px solid var(--c-line); border-radius: var(--r-md);
  background: var(--c-bg); cursor: pointer; text-align: left;
  /* transition:all 금지 — outline 이 같이 번진다(.chip 주석 참고) */
  transition: background var(--t-base) var(--ease), border-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease);
}
.pick__item:hover { border-color: var(--c-line-3); background: var(--c-bg-soft); }
.pick__item.is-on {
  border-color: var(--c-primary); background: var(--c-primary-soft);
  box-shadow: 0 0 0 1px var(--c-primary) inset;
}
.pick__item.is-on .pick__radio { border-color: var(--c-primary); }
.pick__item.is-on .pick__radio::after { transform: scale(1); }
/* 아직 못 고르는 수단 — 라벨에 이유를 적고(예: '카드결제 (추후 예정)') 이 클래스를 준다.
   ⚠️ 스타일이 없으면 **고를 수 있는 것처럼 보이는데 눌러도 아무 일이 없다**(2026-08-27 검토).
      비활성은 disabled 가 아니라 .is-off + 라벨로 알린다(디자인/04-writing.md). */
.pick__item.is-off { opacity: .5; cursor: not-allowed; }
.pick__item.is-off:hover { border-color: var(--c-line); background: var(--c-bg); }
.pick__radio {
  flex: none; width: 20px; height: 20px; margin-top: 2px;
  border: 2px solid var(--c-line); border-radius: 50%;
  display: grid; place-items: center;
  transition: border-color var(--t-fast) var(--ease);
}
.pick__radio::after {
  content: ""; width: 10px; height: 10px; border-radius: 50%;
  background: var(--c-primary); transform: scale(0);
  transition: transform var(--t-base) var(--ease-out);
}
.pick__ico {
  flex: none; width: 42px; height: 42px; border-radius: var(--r-sm);
  background: var(--c-primary-soft); color: var(--c-primary);
  display: grid; place-items: center; font-size: 20px;
}
/* 사진 썸네일형 선택 카드 (예약 종목) */
.pick__thumb {
  flex: none; width: 60px; height: 46px; border-radius: var(--r-xs); overflow: hidden;
  background: var(--grad-deep); display: grid; place-items: center;
}
.pick__thumb img { width: 100%; height: 100%; object-fit: cover; }

/* 파일 업로더 — 자격증 이미지 */
.uploader {
  border: 1.5px dashed var(--c-line); border-radius: var(--r-md);
  background: var(--c-bg-soft);
  padding: var(--sp-8) var(--sp-5); text-align: center;
  /* transition:all 금지 — outline 이 같이 번진다(.chip 주석 참고) */
  transition: background var(--t-base) var(--ease), border-color var(--t-base) var(--ease); cursor: pointer;
}
.uploader:hover { border-color: var(--c-primary); background: var(--c-primary-soft); }
.uploader__ico {
  width: 48px; height: 48px; margin: 0 auto var(--sp-3);
  border-radius: var(--r-sm); background: #fff; color: var(--c-primary);
  display: grid; place-items: center; box-shadow: var(--sh-2); font-size: 22px;
}
.uploader.has-file { border-style: solid; border-color: var(--c-ok); background: var(--c-ok-soft); }

.thumb {
  position: relative; border-radius: var(--r-md); overflow: hidden;
  border: 1px solid var(--c-line); background: var(--c-bg-sink);
  aspect-ratio: 4 / 3;
}
.thumb img { width: 100%; height: 100%; object-fit: cover; }

/* ---------- 펼치는 목록 행 `.certrow` ----------
   회원이 등록한 자격증처럼 **요약은 짧게, 세부는 필요할 때** 보여야 하는 목록에 쓴다.
   신고(2026-08-26): 자격증을 올린 뒤 항목을 눌러도 세부사항을 볼 수 없었다 —
   행이 클릭 대상이 아니었고 만료일·올린 이미지를 볼 길이 아예 없었다.

   ⚠️ **네이티브 <details>/<summary> 를 쓴다.** 열림 상태를 JS 로 들고 있지 않아도 되고,
      키보드(Enter/Space)와 화면낭독기가 기본으로 동작한다. 직접 만든 아코디언은
      그 둘을 늘 다시 구현해야 한다. */
.certrow {
  border: 1px solid var(--c-line); border-radius: var(--r-md);
  background: var(--c-bg);
}
.certrow + .certrow { margin-top: var(--sp-2); }

.certrow__hd {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  cursor: pointer; list-style: none;
}
/* 사파리는 기본 삼각형을 ::-webkit-details-marker 로 그린다 — 우리 것과 겹친다 */
.certrow__hd::-webkit-details-marker { display: none; }
.certrow__hd:hover { background: var(--c-bg-soft); border-radius: var(--r-md); }

.certrow__cv {
  flex: none; width: 0; height: 0;
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 5px solid var(--c-muted);
  transition: transform var(--t-fast) var(--ease);
}
.certrow[open] .certrow__cv { transform: rotate(180deg); }
.certrow[open] .certrow__hd { border-bottom: 1px solid var(--c-line); border-radius: var(--r-md) var(--r-md) 0 0; }

.certrow__bd { padding: var(--sp-4); }
/* 자격증은 세로가 긴 사진이 많다 — 잘라내지 않고 전체가 보이게 둔다 */
.certrow__bd .thumb { height: auto; aspect-ratio: 4 / 3; }
.certrow__bd .thumb img { object-fit: contain; background: var(--c-bg-soft); }
.thumb__del {
  position: absolute; top: 8px; right: 8px; width: 28px; height: 28px;
  border-radius: 50%; background: rgba(var(--c-shadow-rgb), .62); color: #fff;
  display: grid; place-items: center; font-size: 13px;
}

/* ============ 4. 카드 · 면 ============ */
/* 면은 '선으로 그린 상자' 가 아니라 '바닥에서 떠 있는 판' 으로 읽혀야 한다.
   경계선 + 아주 옅은 그림자 + 안쪽 위 하이라이트 한 줄. 세 개가 같이 있어야
   가장자리가 빛을 받은 것처럼 보인다 — 그림자만 키우면 탁해진다. */
.card {
  background: var(--c-bg); border: 1px solid var(--c-line);
  border-radius: var(--r-md);
  box-shadow: var(--sh-1), inset 0 1px 0 rgba(255, 255, 255, .9);
  transition: box-shadow var(--t-base) var(--ease), border-color var(--t-base) var(--ease);
}
.card--flat { box-shadow: none; }
.card--raised { box-shadow: var(--sh-3); border-color: transparent; }
.card--soft { background: var(--c-bg-soft); border-color: transparent; box-shadow: none; }
.card--deep { background: var(--grad-deep); border-color: transparent; color: var(--c-on-deep); }
.card__hd {
  padding: var(--sp-5) var(--sp-6); border-bottom: 1px solid var(--c-line-2);
  display: flex; align-items: center; gap: var(--sp-3);
}
.card__bd { padding: var(--sp-6); }
.card__bd--tight { padding: var(--sp-4) var(--sp-5); }
.card__ft {
  padding: var(--sp-4) var(--sp-6); border-top: 1px solid var(--c-line-2);
  background: var(--c-bg-soft); border-radius: 0 0 var(--r-md) var(--r-md);
}
/* 누를 수 있는 카드는 손이 닿으면 한 단 떠오른다.
   경계선도 같이 진해져야 '떠오름' 이 그림자 흐림이 아니라 상태 변화로 읽힌다. */
.card--link { transition: box-shadow var(--t-base) var(--ease), transform var(--t-base) var(--ease),
                          border-color var(--t-base) var(--ease); }
.card--link:hover { box-shadow: var(--sh-3); border-color: var(--c-line-3); transform: translateY(-2px); }

/* 안내 · 경고 블록 */
.note {
  display: flex; gap: 10px; align-items: flex-start;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-sm);
  background: var(--c-bg-soft); color: var(--c-ink-2);
  font-size: var(--fs-sm); border-left: 3px solid var(--c-line);
}
.note--info   { background: var(--c-info-soft);   border-left-color: var(--c-info); }
.note--warn   { background: var(--c-warn-soft);   border-left-color: var(--c-warn); }
.note--danger { background: var(--c-danger-soft); border-left-color: var(--c-danger); }
.note--ok     { background: var(--c-ok-soft);     border-left-color: var(--c-ok); }
.note__ico { flex: none; font-size: 15px; line-height: 1.5; }

/* 빈 상태 */
.empty { padding: var(--sp-14) var(--sp-5); text-align: center; color: var(--c-muted); }
.empty__ico { font-size: 34px; opacity: .4; margin-bottom: var(--sp-3); }

/* ============ 5. 배지 · 상태 ============ */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  height: 24px; padding-inline: 9px; border-radius: var(--r-xs);
  font-size: var(--fs-cap); font-weight: var(--fw-sb); letter-spacing: 0;
  background: var(--c-bg-sink); color: var(--c-ink-2);   /* muted 는 이 배경에서 4.4 라 상태가 흐리게 읽힌다 */
  white-space: nowrap;
}
.badge--ok     { background: var(--c-ok-soft);     color: var(--c-ok); }
.badge--wait   { background: var(--c-info-soft);   color: var(--c-info); }
.badge--warn   { background: var(--c-warn-soft);   color: var(--c-warn); }
.badge--danger { background: var(--c-danger-soft); color: var(--c-danger); }
.badge--brand  { background: var(--c-primary-soft); color: var(--c-primary-ink); }
.badge--solid  { background: var(--c-primary); color: #fff; }
.badge--lg { height: 28px; padding-inline: 11px; font-size: var(--fs-sm); }
.badge__dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* 진행 점 — 면책동의서 N/M */
.dots { display: inline-flex; gap: 4px; }
.dots i { width: 7px; height: 7px; border-radius: 50%; background: var(--c-line); }
.dots i.is-on { background: var(--c-ok); }

.bar { height: 6px; border-radius: var(--r-full); background: var(--c-line-2); overflow: hidden; }
.bar > i { display: block; height: 100%; border-radius: inherit; background: var(--grad-accent); transition: width var(--t-slow) var(--ease-out); }

/* ============ 6. 스텝퍼 · 탭 ============ */
.steps { display: flex; align-items: center; gap: var(--sp-2); }
.steps__i { display: flex; align-items: center; gap: 8px; color: var(--c-muted-2); font-size: var(--fs-sm); }
.steps__n {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--c-bg-sink); color: var(--c-muted);
  font-size: var(--fs-cap); font-weight: var(--fw-bd);
  /* transition:all 금지 — outline 이 같이 번진다(.chip 주석 참고) */
  transition: background var(--t-base) var(--ease), color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease);
}
.steps__i.is-on { color: var(--c-ink); font-weight: var(--fw-sb); }
.steps__i.is-on .steps__n { background: var(--c-primary); color: #fff; box-shadow: 0 0 0 4px var(--c-primary-soft); }
.steps__i.is-done .steps__n { background: var(--c-ok); color: #fff; }
.steps__i.is-done { color: var(--c-ink-2); }
.steps__line { flex: 1 1 auto; height: 1px; background: var(--c-line); min-width: 12px; }
/* 모바일에서는 라벨만 접는다. 번호 원(.steps__n)은 항상 남긴다 */
@media (max-width: 720px) {
  .steps__i > span:not(.steps__n) { display: none; }
  .steps__i.is-on > span:not(.steps__n) { display: inline; }
}

.tabs { display: flex; gap: var(--sp-5); border-bottom: 1px solid var(--c-line); }
.tab {
  position: relative; padding: 0 2px var(--sp-3);
  font-size: var(--fs-body); font-weight: var(--fw-md); color: var(--c-muted);
  transition: color var(--t-fast) var(--ease);
}
.tab:hover { color: var(--c-ink); }
.tab.is-on { color: var(--c-primary); font-weight: var(--fw-sb); }
.tab.is-on::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px;
  height: 2px; background: var(--c-primary); border-radius: 2px 2px 0 0;
}
.tab__cnt {
  margin-left: 6px; padding: 1px 6px; border-radius: var(--r-full);
  background: var(--c-bg-sink); color: var(--c-muted);
  font-size: 11px; font-weight: var(--fw-bd);
}
.tab.is-on .tab__cnt { background: var(--c-primary-soft); color: var(--c-primary-ink); }

/* ============ 7. 예약 — 달력 · 시간 슬롯 · 요약 ============ */
.cal__hd { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-4); }
.cal__nav {
  width: 34px; height: 34px; border-radius: var(--r-xs); border: 1px solid var(--c-line);
  display: grid; place-items: center; color: var(--c-ink-2);
  /* transition:all 금지 — outline 이 같이 번진다(.chip 주석 참고) */
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.cal__nav:hover { background: var(--c-bg-soft); border-color: var(--c-muted-2); }
.cal__dow, .cal__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.cal__dow { margin-bottom: 8px; }
.cal__dow span { text-align: center; font-size: var(--fs-cap); font-weight: var(--fw-sb); color: var(--c-muted); }
.cal__dow span:first-child { color: var(--c-danger); }
.cal__dow span:last-child { color: var(--c-info); }
.cal__d {
  /* 넓은 화면에서 셀이 과하게 커지지 않도록 정사각 비율에 상한을 둔다 */
  position: relative; aspect-ratio: 1 / 1; max-height: 54px; min-height: 42px;
  border-radius: var(--r-sm);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  font-size: var(--fs-sm); font-weight: var(--fw-md); color: var(--c-ink-2);
  border: 1px solid transparent;
  /* transition:all 금지 — outline 이 같이 번진다(.chip 주석 참고) */
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}
.cal__d:hover:not(.is-off) { background: var(--c-primary-soft); }
.cal__d.is-off { color: var(--c-muted-2); opacity: .5; pointer-events: none; text-decoration: line-through; }
.cal__d.is-blank { pointer-events: none; }
.cal__d.is-today { border-color: var(--c-primary); }
.cal__d.is-on { background: var(--c-primary); color: #fff; font-weight: var(--fw-bd); box-shadow: 0 4px 12px rgba(var(--c-brand-rgb), .3); }
.cal__d small { font-size: 10px; font-weight: var(--fw-md); color: var(--c-muted); line-height: 1; }

/* ---------------------------------------------------------
   섹션 탭 — 풀장 홈처럼 한 페이지 안을 앵커로 오가는 화면의 길잡이.

   ⚠️ **배너 안에 두지 않는다.** 예전에는 히어로 안에 칩으로 있어서, 앵커로 내려간 뒤
      메뉴를 다시 보려면 맨 위까지 올라가야 했다(2026-08-28 신고). 상단바 바로 아래에
      붙여 스크롤 내내 손에 닿게 한다.
   ⚠️ `top` 은 상단바 높이다. 두 sticky 가 겹치면 탭이 상단바 뒤로 숨는다.
   ⚠️ z-index 는 상단바보다 **낮게** 둔다 — 상단바의 사용자 메뉴·펼침이 탭 위로 열려야 한다.
   ⚠️ `.anav` 와 같은 가로 스크롤 함정을 `.sectabs__list` 가 그대로 물려받는다:
      overflow-x:auto 면 overflow-y 도 auto 라 바깥 장식이 잘린다. 밑줄은 상자 안(bottom:0)에
      둔다. mask-image 로 가장자리를 흐리지 말 것 — 포커스 링이 잘린다.
   --------------------------------------------------------- */
.sectabs {
  position: sticky; top: var(--h-topbar); z-index: var(--z-sticky);
  background: rgba(255, 255, 255, .92);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--c-line);
}
.sectabs__in { display: flex; align-items: center; gap: var(--sp-3); }
/* ⚠️ **탭 줄만** 가로로 흐른다. 버튼까지 이 스크롤 안에 넣으면 좁은 화면에서 버튼이
   화면 밖으로 밀려, 옆으로 쓸어야 나오는 것을 아무도 모른다 — 첫 행동이 사라진다
   (2026-08-28 실측 375px: 예약하기가 329~405px, 바 폭은 343px). */
.sectabs__list {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: var(--sp-5);
  overflow-x: auto; scrollbar-width: none;
}
.sectabs__list::-webkit-scrollbar { display: none; }
.sectabs__i {
  position: relative; flex: none;
  display: inline-flex; align-items: center;
  height: 46px; padding: 0 2px;
  font-size: var(--fs-sm); font-weight: var(--fw-md); color: var(--c-muted);
  white-space: nowrap; text-decoration: none;
  transition: color var(--t-fast) var(--ease);
}
.sectabs__i:hover { color: var(--c-ink); }
.sectabs__i[aria-current="true"] { color: var(--c-primary); font-weight: var(--fw-sb); }
.sectabs__i[aria-current="true"]::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--c-primary); border-radius: 2px 2px 0 0;
}
/* 오른쪽 끝에 붙는 행동 버튼 — 탭을 옆으로 밀어도 예약하기는 제자리에 남는다 */
.sectabs__cta { flex: none; }

/* ⚠️ 앵커로 이동할 때 상단바+탭 높이만큼 가려지지 않게 한다.
   이 값이 없으면 섹션 제목이 탭 뒤에 숨어 '엉뚱한 데로 갔다' 고 느낀다. */
[id="intro"], [id="guide"], [id="notices"], [id="directions"], .ph-sec[id] {
  scroll-margin-top: calc(var(--h-topbar) + 46px + 8px);
}

/* 집계를 담는 달력 — 관리자 예약 캘린더. 셀 하나에 날짜·인원·매출 세 줄이 들어간다.
   ⚠️ 이 규칙은 클래스 **둘**(.cal--data .cal__d)이라 명시도(0,2,0)로 기본 .cal__d(0,1,0)를
      이긴다 — 순서에 기대지 않는다. `.modal__box--media` 처럼 **클래스 하나짜리 변형**은
      반대로 순서가 유일한 승부라 반드시 기본 규칙 뒤에 둬야 한다. 둘을 헷갈리지 말 것.
   ⚠️ 예약 달력(booking)의 셀은 '고를 수 있는 날' 이고 여기 셀은 '읽는 값' 이다.
      그래서 정사각을 풀고 내용 높이에 맡긴다 — 매출 자릿수는 날마다 다르다. */
.cal--data .cal__d {
  aspect-ratio: auto; max-height: none; min-height: 62px;
  justify-content: flex-start; gap: 2px;
  padding: var(--sp-2) 4px;
  background: var(--c-bg); border-color: var(--c-line);
}
.cal--data .cal__d.is-blank { background: transparent; border-color: transparent; }
/* 예약이 없는 날은 숫자만 — 0 을 세 줄로 적으면 있는 날이 눈에 안 띈다 */
.cal--data .cal__d.is-empty { background: var(--c-bg-soft); border-color: transparent; color: var(--c-muted-2); }
.cal--data .cal__n { font-size: var(--fs-cap); font-weight: var(--fw-sb); line-height: 1.1; }
.cal--data .cal__v { font-size: 11px; line-height: 1.2; font-weight: var(--fw-sb); color: var(--c-primary); }
.cal--data .cal__v2 { font-size: 10px; line-height: 1.2; color: var(--c-muted); }
/* 결제 전이 섞인 날 — 매출이 아직 확정이 아니라는 표시(디자인 절대 규칙 ④) */
.cal--data .cal__d.has-pending .cal__v::after { content: '*'; color: var(--c-warn); }

@media (max-width: 560px) {
  /* 좁은 화면에서는 금액을 접고 인원만 남긴다 — 7칸에 만 단위 숫자가 들어가지 않는다 */
  .cal--data .cal__d { min-height: 52px; }
  .cal--data .cal__v2 { display: none; }
}
.cal__d.is-on small { color: rgba(255, 255, 255, .85); }
.cal__d.is-full { background: var(--c-bg-sink); color: var(--c-muted-2); pointer-events: none; }

.slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: var(--sp-2); }
.slot {
  position: relative;
  height: 62px; border-radius: var(--r-sm); border: 1px solid var(--c-line);
  background: var(--c-bg); display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px;
  /* transition:all 금지 — outline 이 같이 번진다(.chip 주석 참고) */
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
/* 회차 부가 표기 (예: 선수 훈련 병행) */
.slot__note {
  position: absolute; top: -7px; left: 50%; transform: translateX(-50%);
  padding: 1px 7px; border-radius: var(--r-full); white-space: nowrap;
  background: var(--c-warn-soft); color: var(--c-warn);
  font-size: 10px; font-weight: var(--fw-sb); font-style: normal;
}
.slot.is-on .slot__note { background: var(--c-warn); color: #fff; }
.slot b { font-size: 15px; font-weight: var(--fw-sb); letter-spacing: -.01em; }
.slot small { font-size: 11px; color: var(--c-muted); }
.slot:hover:not(.is-full) { border-color: var(--c-primary); background: var(--c-primary-soft); }
.slot.is-on { background: var(--c-primary); border-color: var(--c-primary); color: #fff; box-shadow: 0 4px 12px rgba(var(--c-brand-rgb), .26); }
.slot.is-on small { color: rgba(255, 255, 255, .82); }
.slot.is-full { background: var(--c-bg-sink); color: var(--c-muted-2); pointer-events: none; }

/* 인원 스테퍼 */
.qty { display: inline-flex; align-items: center; gap: var(--sp-2); }
.qty__btn {
  width: 40px; height: 40px; border-radius: var(--r-sm);
  border: 1px solid var(--c-line); background: var(--c-bg);
  display: grid; place-items: center; font-size: 18px; color: var(--c-ink-2);
  /* transition:all 금지 — outline 이 같이 번진다(.chip 주석 참고) */
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}
.qty__btn:hover:not([disabled]) { border-color: var(--c-primary); color: var(--c-primary); }
.qty__btn[disabled] { opacity: .35; pointer-events: none; }
.qty__n { min-width: 56px; text-align: center; font-size: 19px; font-weight: var(--fw-bd); font-variant-numeric: tabular-nums; }

/* 명단 입력 행 */
.roster { display: grid; gap: var(--sp-2); }
.roster__row { display: flex; align-items: center; gap: var(--sp-2); }
.roster__no {
  flex: none; width: 30px; height: 30px; border-radius: 50%;
  background: var(--c-bg-sink); color: var(--c-muted);
  display: grid; place-items: center; font-size: var(--fs-cap); font-weight: var(--fw-bd);
}
.roster__row.is-me .roster__no { background: var(--c-primary); color: #fff; }

/* 금액 요약 */
.sum { font-size: var(--fs-sm); }
.sum__row { display: flex; justify-content: space-between; gap: var(--sp-4); padding-block: 7px; }
.sum__row span { color: var(--c-muted); }
.sum__row b { font-weight: var(--fw-md); color: var(--c-ink-2); font-variant-numeric: tabular-nums; }
.sum__total {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--c-line);
}
.sum__total span { font-size: var(--fs-body); font-weight: var(--fw-sb); }
.sum__total b { font-size: 24px; font-weight: var(--fw-bd); color: var(--c-primary); letter-spacing: -.02em; font-variant-numeric: tabular-nums; }

/* 라벨-값 표 */
.info { display: grid; gap: 0; }
.info__r { display: flex; gap: var(--sp-4); padding-block: 11px; border-bottom: 1px solid var(--c-line-2); font-size: var(--fs-sm); }
.info__r:last-child { border-bottom: 0; }
.info__r > dt { flex: none; width: 92px; color: var(--c-muted); }
.info__r > dd { flex: 1 1 auto; margin: 0; color: var(--c-ink); font-weight: var(--fw-md); }

/* ============ 8. 면책동의서 · 서명 ============ */
.doc {
  max-height: 300px; overflow-y: auto;
  padding: var(--sp-5); border: 1px solid var(--c-line); border-radius: var(--r-sm);
  background: var(--c-bg-soft); font-size: var(--fs-sm); line-height: 1.78; color: var(--c-ink-2);
}
.doc h4 { font-size: var(--fs-sm); font-weight: var(--fw-bd); color: var(--c-ink); margin-top: var(--sp-4); }
.doc h4:first-child { margin-top: 0; }
.doc p + p { margin-top: 8px; }
.doc ol { list-style: decimal; padding-left: 18px; }
.doc ol li + li { margin-top: 5px; }
.doc strong { color: var(--c-danger); font-weight: var(--fw-sb); }

.sigpad {
  position: relative; border: 1.5px dashed var(--c-line); border-radius: var(--r-md);
  background: var(--c-bg); overflow: hidden;
}
.sigpad canvas { display: block; width: 100%; height: 190px; touch-action: none; cursor: crosshair; }
.sigpad__ph {
  position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--c-muted-2); font-size: var(--fs-sm); pointer-events: none;
}
.sigpad__line {
  position: absolute; left: var(--sp-6); right: var(--sp-6); bottom: 42px;
  border-bottom: 1px solid var(--c-line); pointer-events: none;
}
.sigpad.has-ink { border-style: solid; border-color: var(--c-primary); }
.sigpad.has-ink .sigpad__ph { display: none; }

/* 동행자 서명 현황 */
.people { display: grid; gap: var(--sp-2); }
.person {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); border: 1px solid var(--c-line); border-radius: var(--r-sm);
  background: var(--c-bg);
}
.person__av {
  flex: none; width: 34px; height: 34px; border-radius: 50%;
  background: var(--c-bg-sink); color: var(--c-muted);
  display: grid; place-items: center; font-size: var(--fs-sm); font-weight: var(--fw-bd);
}
.person.is-done { border-color: #CDE7DC; background: #F6FBF8; }
.person.is-done .person__av { background: var(--c-ok); color: #fff; }
.person.is-me .person__av { background: var(--c-primary); color: #fff; }

/* ============ 9. 예약 완료 카드(티켓) ============ */
.ticket {
  position: relative; border-radius: var(--r-lg); overflow: hidden;
  background: var(--grad-deep); color: var(--c-on-deep); box-shadow: var(--sh-4);
}
.ticket::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(120% 80% at 90% -10%, rgba(var(--c-accent-rgb), .35) 0%, transparent 55%);
  pointer-events: none;
}
.ticket__hd { position: relative; padding: var(--sp-6) var(--sp-6) var(--sp-5); }
.ticket__body { position: relative; padding: 0 var(--sp-6) var(--sp-5); }
.ticket__rip {
  position: relative; height: 22px; margin-block: var(--sp-2);
  display: flex; align-items: center;
}
.ticket__rip::before, .ticket__rip::after {
  content: ""; position: absolute; width: 22px; height: 22px; border-radius: 50%;
  background: var(--c-bg-soft);
}
.ticket__rip::before { left: -11px; }
.ticket__rip::after { right: -11px; }
.ticket__rip i {
  flex: 1 1 auto; margin-inline: 16px;
  border-top: 1.5px dashed rgba(255, 255, 255, .3);
}
.ticket__code {
  position: relative; background: #fff; color: var(--c-ink);
  margin: 0 var(--sp-5) var(--sp-5); padding: var(--sp-5);
  border-radius: var(--r-md); text-align: center;
}
.qr { width: 168px; height: 168px; margin: 0 auto; }
.qr rect { shape-rendering: crispEdges; }
.barcode { display: flex; align-items: flex-end; gap: 1.5px; height: 46px; margin-top: var(--sp-4); justify-content: center; }
.barcode i { width: 2px; background: var(--c-ink); border-radius: .5px; }
.barcode i.w { width: 4px; }
.ticket__no {
  margin-top: 10px; font-size: var(--fs-sm); font-weight: var(--fw-bd);
  letter-spacing: .22em; font-variant-numeric: tabular-nums; color: var(--c-ink-2);
}
.ticket__meta { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-4) var(--sp-5); }
.ticket__meta dt { font-size: 11px; color: var(--c-on-deep-2); letter-spacing: .06em; margin-bottom: 3px; }
.ticket__meta dd { margin: 0; font-size: 15px; font-weight: var(--fw-sb); color: #fff; }

/* QR 수명 표시 — 남은 시간을 줄어드는 바로 보여준다 */
.qr-life {
  height: 3px; margin-top: 10px; border-radius: var(--r-full);
  background: var(--c-line-2); overflow: hidden;
}
.qr-life > i {
  display: block; height: 100%; width: 100%;
  background: var(--grad-accent); border-radius: inherit;
  transition: width 1s linear;
}

/* 입장권 캡처 억제.
   ⚠️ OS 스크린샷은 웹에서 막을 수 없다. 길게눌러 저장·드래그·선택만 차단하고,
      실제 방어는 짧은 수명의 회전 QR 이 담당한다. 문서: docs/01-api.md */
.ticket, .ticket * {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}
.ticket img, .ticket svg { pointer-events: none; }

/* ============ 10. 표 (관리자) ============ */
.tbl { font-size: var(--fs-sm); }
.tbl th {
  text-align: left; padding: 11px var(--sp-4);
  background: var(--c-bg-soft); color: var(--c-muted);
  font-size: var(--fs-cap); font-weight: var(--fw-sb); letter-spacing: .02em;
  border-bottom: 1px solid var(--c-line); white-space: nowrap;
}
.tbl th:first-child { border-radius: var(--r-xs) 0 0 0; }
.tbl th:last-child { border-radius: 0 var(--r-xs) 0 0; }
.tbl td { padding: 13px var(--sp-4); border-bottom: 1px solid var(--c-line-2); vertical-align: middle; }
.tbl tbody tr { transition: background var(--t-fast) var(--ease); }
.tbl tbody tr:hover { background: var(--c-bg-soft); cursor: pointer; }
.tbl tbody tr.is-on { background: var(--c-primary-soft); }
.tbl__u { display: flex; align-items: center; gap: 10px; }

/* 행 전체가 눌리는 표(회원·자격 심사)의 **키보드 경로**.
   <tr onclick> 만 두면 초점이 오지 않아 키보드로는 상세를 열 길이 없다 —
   이름 칸을 진짜 <button> 으로 만들고, 보기에는 그냥 칸처럼 둔다.
   행 클릭은 마우스 편의로 남아 있다. */
.tbl__open {
  display: block; width: 100%; text-align: left;
  font: inherit; color: inherit; letter-spacing: inherit;
  background: none; border: 0; padding: 0; cursor: pointer;
}
.tbl__av {
  width: 32px; height: 32px; border-radius: 50%; flex: none;
  background: var(--grad-accent); color: #fff;
  display: grid; place-items: center; font-size: var(--fs-cap); font-weight: var(--fw-bd);
}
.tbl-scroll { overflow-x: auto; }

/* ---- 표가 가로로 넘칠 때 ----
   .tbl-scroll > table 은 min-width 720px 이라 휴대폰(375px)에서는 **항상** 가로 스크롤이다.
   그 자체는 의도지만, 그동안 두 가지가 빠져 있었다:

   ① **넘친다는 신호가 없었다.** 표가 화면에 꽉 차 보여 옆으로 밀 수 있다는 것을 알 수 없다.
      좌우 가장자리에 그림자를 두되 `background-attachment: local` 로 스크롤 위치에 따라
      나타나고 사라지게 한다 — 끝까지 밀면 그쪽 그림자가 사라져 '더 없음' 을 알린다.
   ② **조작 열이 화면 밖에 갇혔다.** 관리자가 휴대폰에서 [입금 확인] 을 누를 수 없다고
      신고했다(2026-08-24). 실측: 표 폭 720px · 보이는 폭 293px · 버튼 left 670px —
      화면(375px) 밖 427px 지점이라, 옆으로 밀 수 있다는 것을 모르면 영영 못 누른다.
      마지막 열이 조작 열인 표에 `.tbl--pin` 을 붙여 **오른쪽에 고정**한다.
      고정 칸은 스크롤되는 내용 위에 뜨므로 배경이 불투명해야 하고, 행 상태(hover·is-on)를
      따라가야 한다 — 안 그러면 밑의 글자가 겹쳐 보인다. */
.tbl-scroll {
  background:
    linear-gradient(to right, var(--c-bg), rgb(255 255 255 / 0)) 0 0 / 22px 100% no-repeat,
    linear-gradient(to left, var(--c-bg), rgb(255 255 255 / 0)) 100% 0 / 22px 100% no-repeat,
    radial-gradient(farthest-side at 0 50%, rgba(var(--c-shadow-rgb), .13), rgb(255 255 255 / 0)) 0 0 / 11px 100% no-repeat,
    radial-gradient(farthest-side at 100% 50%, rgba(var(--c-shadow-rgb), .13), rgb(255 255 255 / 0)) 100% 0 / 11px 100% no-repeat;
  background-attachment: local, local, scroll, scroll;
}

/* 좁은 화면에서만 고정한다. 넓은 화면은 표가 다 보이므로 고정할 이유가 없고,
   되돌리는 규칙을 쓰면(position:static 재지정) 상속이 꼬인다 — 애초에 안 건다. */
@media (max-width: 720px) {
  .tbl--pin th:last-child,
  .tbl--pin td:last-child {
    position: sticky; right: 0; z-index: 1;
    background: var(--c-bg);
    box-shadow: -10px 0 10px -10px rgba(var(--c-shadow-rgb), .28);
  }
  .tbl--pin th:last-child { background: var(--c-bg-soft); }
  .tbl--pin tbody tr:hover td:last-child { background: var(--c-bg-soft); }
  .tbl--pin tbody tr.is-on td:last-child { background: var(--c-primary-soft); }
}

/* ---- 편집표는 좁은 화면에서 카드로 접는다 (.tbl--stack) ----
   조작 열을 고정하는 것(.tbl--pin)으로 충분한 표는 '읽고 한 번 누르는' 표다.
   회차 편집표는 다르다 — 정원·금액·메모를 **직접 고치는** 것이 목적인데,
   그 입력란들이 표 가운데 있어 오른쪽으로 밀어야 닿는다(실측: left 373·485·627px).
   행을 카드로 세우고 열 이름을 라벨로 앞에 붙인다. <td data-label="정원"> 이 그 이름이다.
   ⚠️ DOM 구조(tbody > tr > td > [data-k])는 그대로 둔다 — readDayRows() 가 그것을 읽는다.
      display 만 바꾸는 CSS 재배치인 이유가 이것이다. */
@media (max-width: 720px) {
  .tbl-scroll > .tbl--stack { min-width: 0; }
  .tbl--stack thead { display: none; }
  .tbl--stack, .tbl--stack tbody, .tbl--stack tr, .tbl--stack td { display: block; width: auto; }
  .tbl--stack tr {
    border: 1px solid var(--c-line); border-radius: var(--r-sm);
    padding: var(--sp-3); margin-bottom: var(--sp-3);
  }
  /* 카드는 누르는 대상이 아니다 — 표에서 물려받은 hover 배경·손가락 커서를 끈다 */
  .tbl--stack tbody tr:hover { background: var(--c-bg); cursor: auto; }
  .tbl--stack td {
    border: 0; padding: var(--sp-2) 0;
    display: grid; grid-template-columns: minmax(0, 34%) minmax(0, 1fr);
    align-items: center; gap: var(--sp-3);
  }
  .tbl--stack td::before {
    content: attr(data-label);
    color: var(--c-muted); font-size: var(--fs-cap); font-weight: var(--fw-sb);
  }
  /* 데스크톱 표를 좁히려고 넣은 인라인 width(80·110px)를 카드에서 되돌린다 */
  .tbl--stack td .input { width: 100% !important; }
  /* 라벨이 없는 칸(조작)은 한 줄을 다 쓴다 */
  .tbl--stack td:not([data-label]) { grid-template-columns: minmax(0, 1fr); }
}

/* 스크롤 상자 안의 요소로 Tab 이 들어오면 브라우저가 그 요소를 가장자리에 **딱 맞춰**
   스크롤한다 — 그러면 바깥 5px 에 그려지는 포커스 링이 잘린다.
   scroll-padding 으로 6px 를 남겨 링이 들어갈 자리를 만든다.
   (.anav 는 세로로도 좁아 이 방법이 안 통해서 링 자체를 안쪽으로 뒤집었다 — §1.5) */
.mnav__bd, .tbl-scroll, .drawer__bd, .modal__box, .doc, .pmap__pd { scroll-padding: 6px; }
.tbl-scroll > table { min-width: 720px; }

/* 통계 타일 */
.stat { padding: var(--sp-5); border: 1px solid var(--c-line); border-radius: var(--r-md); background: var(--c-bg); }
.stat__k { font-size: var(--fs-cap); color: var(--c-muted); font-weight: var(--fw-md); }
.stat__v { margin-top: 6px; font-size: 28px; font-weight: var(--fw-bd); letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.stat__d { margin-top: 4px; font-size: var(--fs-cap); }

/* ---- 본문 바로가기(skip link) ----
   상단바 메뉴가 9개인 관리자 화면은 매 화면 Tab 13번을 눌러야 본문에 닿았다.
   ⚠️ display:none 이나 visibility:hidden 으로 숨기면 **초점 자체를 못 받아** 무용지물이다.
   화면 위로 밀어 두고 초점이 오면 제자리로 데려온다.
   흰 알약인 이유는 어디 위에 뜰지 모르기 때문이다 — 개발 중에는 딥색 데모바 위,
   배포본에서는 밝은 상단바 위에 온다. 포커스 링도 그래서 안쪽으로 넣는다(면 위 9.86:1). */
.skip {
  position: fixed; top: var(--sp-2); left: var(--sp-2); z-index: calc(var(--z-topbar) + 1);
  transform: translateY(calc(-100% - var(--sp-4)));
  padding: var(--sp-3) var(--sp-5); border-radius: var(--r-sm);
  background: var(--c-bg); color: var(--c-primary-ink);
  border: 1px solid var(--c-line-3); box-shadow: var(--sh-3);
  font-size: var(--fs-sm); font-weight: var(--fw-sb);
  transition: transform var(--t-fast) var(--ease);
}
.skip:focus-visible { transform: none; outline-offset: -4px; }
.skip:hover { text-decoration: none; }

/* ============ 11. 오버레이 — 드로어 · 모달 · 토스트 ============ */
.scrim {
  position: fixed; inset: 0; z-index: var(--z-drawer);
  background: rgba(var(--c-shadow-rgb), .48); backdrop-filter: blur(2px);
  opacity: 0; pointer-events: none; transition: opacity var(--t-base) var(--ease);
}
.scrim.is-open { opacity: 1; pointer-events: auto; }

/* ⚠️ 닫힘 상태는 화면 밖(translateX)일 뿐 **탭 순서에는 그대로 남는다.**
   transform 도 opacity 도 요소를 순차 포커스에서 빼지 않는다 — visibility 만 뺀다.
   그대로 두면 심사 드로어를 닫은 뒤에도 화면 오른쪽 밖의 '승인'·'반려' 버튼에
   Tab 이 닿고, 아무것도 안 보이는 자리에서 Enter 를 누르면 자격증이 실제로 승인된다.
   .mnav 가 같은 이유로 이미 visibility 를 쓰고 있다(§1.4).
   전환에 `visibility 0s linear var(--t-slow)` 를 얹어야 나가는 애니메이션이 끊기지 않는다 —
   닫을 때는 미끄러짐이 끝난 뒤 숨고, 열 때는 .is-open 의 transition-delay:0 으로 즉시 보인다. */
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: var(--z-drawer);
  width: min(520px, 100%); background: var(--c-bg);
  box-shadow: var(--sh-4); display: flex; flex-direction: column;
  transform: translateX(100%); visibility: hidden;
  transition: transform var(--t-slow) var(--ease-out), visibility 0s linear var(--t-slow);
}
.drawer.is-open { transform: none; visibility: visible; transition-delay: 0s; }
.drawer__hd { padding: var(--sp-5) var(--sp-6); border-bottom: 1px solid var(--c-line); display: flex; align-items: center; gap: var(--sp-3); }
.drawer__bd { flex: 1 1 auto; overflow-y: auto; padding: var(--sp-6); }
.drawer__ft { padding: var(--sp-4) var(--sp-6); border-top: 1px solid var(--c-line); background: var(--c-bg-soft); display: flex; gap: var(--sp-2); }

/* ⚠️ .drawer 와 같은 이유로 visibility 가 필요하다. opacity:0 + pointer-events:none 은
   마우스만 막을 뿐 탭 순서는 그대로다 — 마이페이지에서는 닫힌 모달 4개 안의 입력·버튼
   22개가 보이지 않는 탭 스톱으로 남아, 본문을 다 지난 사용자가 아무것도 보이지 않는
   구간을 22번 지나야 했다(2026-08-22 실측: 닫힌 #popupModal 의 자손 2개가 실제로
   focus() 를 받았고, 같은 조건의 .mnav 는 9개 중 0개였다). */
.modal {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: grid; place-items: center; padding: var(--gutter);
  opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity var(--t-base) var(--ease), visibility 0s linear var(--t-base);
}
.modal.is-open { opacity: 1; pointer-events: auto; visibility: visible; transition-delay: 0s; }
.modal__bg { position: absolute; inset: 0; background: rgba(var(--c-shadow-rgb), .5); }
.modal__box {
  position: relative; width: min(440px, 100%); background: var(--c-bg);
  border-radius: var(--r-lg); box-shadow: var(--sh-4); padding: var(--sp-8) var(--sp-6) var(--sp-6);
  transform: translateY(10px) scale(.98); transition: transform var(--t-slow) var(--ease-out);
  /* 입력이 많은 모달은 작은 화면에서 화면보다 길어진다. 스크롤을 안 주면
     제출 버튼이 화면 밖으로 나가 손이 닿지 않는다 (375×667 에서 실제로 그랬다). */
  max-height: calc(100dvh - var(--gutter) * 2);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.modal.is-open .modal__box { transform: none; }

/* 이미지가 올라가는 모달 — 사진이 상자 위를 **모서리까지** 채운다.
   ⚠️ **반드시 `.modal__box` 뒤에 둔다.** 클래스 하나끼리는 명시도가 같아서
      순서가 이긴다 — 앞에 두면 기본 padding 이 이 규칙을 덮어 사진 둘레에
      흰 여백이 남는다(2026-08-28 실측). @media(pointer:coarse) 블록을 파일 끝에
      두는 것과 같은 이유다.
   ⚠️ 기본 .modal__box 는 위쪽 여백이 크다(--sp-8). 그 안에 사진을 넣으면 허옇게 뜬
      액자처럼 보인다. 이 변형은 위 여백을 걷고 사진이 직접 모서리에 닿게 한다.
   ⚠️ 비율을 고정하지 않고 max-height 로만 막는다 — 세로로 긴 포스터를 억지로 잘라
      글자가 날아가는 것보다, 조금 작게 들어가는 편이 낫다.
   ⚠️ **`object-fit` 은 반드시 `contain` 이다.** 예전에는 주석이 위와 같은데 선언이
      `cover` 였다 — 말과 코드가 서로 반대였고, 실제로 세로로 긴 포스터가 위아래로
      잘려 글자가 날아갔다(2026-09-09 신고: "업로드하면 계속 화면이 잘려서 나온다").
      `cover` 는 상자를 채우려고 이미지를 자르고, `contain` 은 이미지를 다 보이게
      맞춘다. 남는 자리는 `.popup__fig` 의 배경이 받는다. */
.modal__box--media {
  padding-top: 0; padding-inline: 0; overflow: hidden;
  /* 상자 폭은 **그림 비율에 따라 바뀐다** — 가로로 긴 포스터를 420px 에 넣으면
     세로가 150px 밖에 안 돼 글자가 안 읽힌다. 스크립트(`fitPopupBox`)가
     `--popup-w` 를 바꾸고, 좁은 화면에서는 100% 가 이긴다.
     ⚠️ 기본 `.modal__box` 의 `width: min(440px, 100%)` 를 여기서 덮는다 —
        클래스 하나끼리는 명시도가 같아 **뒤에 오는 이 규칙이 이긴다**. */
  width: min(var(--popup-w, 420px), 100%);
}
.modal__box--media > .card__bd { padding: var(--sp-6); }
.popup__fig {
  margin: 0;
  background: var(--c-bg-soft);
  border-bottom: 1px solid var(--c-line);
  line-height: 0;                          /* inline 이미지 아래 생기는 틈을 없앤다 */
}
.popup__fig > img {
  /* **잘라내지 않는다.** 원본 비율 그대로 상자 안에 넣는다.
     ⚠️ 예전에는 `width: 100%` + `object-fit: cover` 였다 — 주석은 '맞춘다' 고
        적혀 있었는데 선언은 위아래를 **잘라냈다**(2026-09-09 신고: 세로 포스터를
        올리면 계속 잘려 나왔다).
     ⚠️ `contain` 만으로도 부족했다. `width: 100%` 면 <img> 상자가 늘 폭을 다
        차지해, 600×1400 그림이 420 상자에서 185px 로 그려지고 좌우에 235px 짜리
        빈 띠가 남았다(같은 날 실측). 폭·높이를 auto 로 두면 **상자 자체가 그림
        크기로 줄어든다** — 남는 자리는 `.popup__fig` 배경이 받는다.
     세로로 긴 포스터도 글자가 살아 있어야 하므로 화면의 60%까지 내준다. 상자가
     `max-height: calc(100dvh - gutter*2)` + `overflow-y:auto` 라 넘쳐도 버튼이
     화면 밖으로 밀리지 않는다. */
  /* ⚠️ 가운데 정렬은 블록 + `margin-inline: auto` 로 한다. 액자를 플렉스로 만들면
        그림이 플렉스 항목이 되어 폭이 확정되고, 그러면 max-height 가 폭을 다시
        계산하지 못한다 — 비율이 깨질 수 있는 길을 열 이유가 없다. */
  display: block; width: auto; height: auto;
  margin-inline: auto;
  max-width: 100%;
  max-height: min(60vh, 460px);
}


.toasts { position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%); z-index: var(--z-toast); display: grid; gap: 8px; }
.toast {
  display: flex; align-items: center; gap: 9px;
  padding: 12px var(--sp-5); border-radius: var(--r-full);
  background: rgba(var(--c-shadow-rgb), .93); color: #fff; font-size: var(--fs-sm); font-weight: var(--fw-md);
  box-shadow: var(--sh-4); animation: toast-in var(--t-slow) var(--ease-out);
}
@keyframes toast-in { from { opacity: 0; transform: translateY(12px); } }

/* ============ 12. 히어로 · 장식 ============ */
.hero { position: relative; background: var(--grad-deep); color: var(--c-on-deep); overflow: hidden; }
.hero__wave { position: absolute; left: 0; right: 0; bottom: -1px; pointer-events: none; }
.hero__glow {
  position: absolute; width: 620px; height: 620px; border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--c-accent-rgb), .3) 0%, transparent 62%);
  top: -220px; right: -160px; pointer-events: none;
}
.hero__in { position: relative; padding-block: var(--sp-24) var(--sp-18); }
@media (max-width: 720px) { .hero__in { padding-block: var(--sp-14) var(--sp-12); } }

/* ---- 12.1 요금표 — 풀장 홈 '이용안내 · 요금' ----
   ⚠️ 예전 .price-card 는 position/overflow 두 줄뿐이었다. 배경·테두리·패딩이 없어
   section--soft 위에서 카드가 아니라 글 덩어리로 흘렀다:
   "스쿠버다이빙 15,000원 프리다이빙 20,000원 …".
   종목마다 면을 세우면 네 면이 서로 경쟁해 비교가 안 된다. 답이 하나(요금)면
   면도 하나여야 한다 — 한 판 위에 실선으로 나눈 칸으로 둔다. */
.price-table {
  display: grid;
  /* 종목 수는 풀장마다 다르다(블루레인 2 · 아쿠아라인 4). auto-fit 이면 몇 개든
     줄바꿈으로 받는다. 한 줄 고정 + 가로 스크롤은 넘친 종목이 힌트 없이 사라져
     '그 종목이 없는' 것처럼 읽힌다. 200px 하한은 배지가 안 잘리는 최소폭. */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.price-card { display: flex; flex-direction: column; padding: var(--sp-5) var(--sp-6); }
.price-card + .price-card { border-inline-start: 1px solid var(--c-line-2); }

/* 이름은 '찾는 열쇠', 금액은 '답'. 이름을 낮춰야 숫자가 주인공이 된다 */
.price-card__k { font-size: var(--fs-sm); font-weight: var(--fw-sb); color: var(--c-muted); }

/* ⚠️ 예전 .price-card__tag 는 우상단 절대배치 + background:var(--c-primary);color:#fff 였다.
   .badge--warn 과 특정도가 같은데 뒤에 있어 경고색을 통째로 덮었다 — 화면의
   '가정값 · 확인 필요' 가 브랜드색 흰 글씨 리본, 즉 '추천!' 같은 홍보 라벨로 렌더됐다.
   마크업은 규칙 ④를 지키는데 시각적으로는 배신하고 있었다. 색·배치를 걷어내면
   .badge--warn 이 제 색을 낸다. */
/* 배지는 금액 바로 위에 붙되, 금액을 밀어내지 않는다(아래 정렬 주석 참고) */
.price-card__tag { align-self: start; margin-top: auto; margin-bottom: var(--sp-2); }

/* 금액은 칸 바닥에 정렬한다 — 이름이 두 줄로 접히거나 배지가 있는 칸만 금액이
   내려앉으면 가로 비교가 끊긴다. 이 컴포넌트의 존재 이유가 그 비교다. */
.price-card__v {
  margin-top: auto;
  font-size: var(--fs-h1); line-height: var(--lh-h1);
  font-weight: var(--fw-bd); letter-spacing: var(--ls-tight);
  color: var(--c-ink); font-variant-numeric: tabular-nums;
}
/* ⚠️ 금액에 padding-top 을 주면 배지 있는 칸과 없는 칸의 금액이 어긋난다(실측 8px).
   여백은 위 요소(이름·배지)의 margin-bottom 으로만 준다 — 그래야 두 경우 모두
   금액 상자의 위가 곧 글자의 위라 바닥 정렬이 그대로 글자 정렬이 된다.
   auto 마진이 둘이면 남는 공간을 나눠 가지므로 배지 뒤 금액은 auto 를 끈다. */
.price-card__k { margin-bottom: var(--sp-4); }
.price-card__tag + .price-card__v { margin-top: 0; }
.price-card__v small {
  font-size: var(--fs-sm); font-weight: var(--fw-md);
  color: var(--c-muted); letter-spacing: var(--ls-normal);
}
.pricing__note { max-width: 68ch; }

@media (max-width: 900px) {
  /* 휴대폰에서는 칸이 아니라 줄이다 — 이름 왼쪽 / 금액 오른쪽.
     금액이 오른쪽에 모이면 tabular-nums 로 자릿수가 세로로 맞아 비교가 끝난다. */
  .price-table { grid-template-columns: minmax(0, 1fr); }
  .price-card {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    align-items: baseline; row-gap: var(--sp-2); column-gap: var(--sp-4);
    padding: var(--sp-4) var(--sp-5);
  }
  .price-card + .price-card { border-inline-start: 0; border-top: 1px solid var(--c-line-2); }
  .price-card__v   { grid-column: 2; grid-row: 1; margin-top: 0; padding-top: 0; text-align: right; }
  .price-card__tag { grid-column: 2; grid-row: 2; margin-top: 0; justify-self: end; }
}

/* ---- 섹션 위계: 요금(뜬 면) → 운영시간(구조) → 수칙(글) → 예약 ----
   아래로 갈수록 작아지되 **흐려지지 않는다**. 수칙에 취소 규정이 들어 있어
   대비를 낮추면 '안전·금액 정보는 보여준다'(00-principles)를 어긴다. */
.pricing__ttl   { margin-top: var(--sp-2); }
.pricing__table { margin-top: var(--sp-6); }
.pricing__tail {
  margin-top: var(--sp-10);
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr);
  gap: var(--sp-8); align-items: start;
}
/* 720px — .grid-2(560px)를 안 쓰는 이유다. 561~760px 에서 열이 좁아지면
   .info 의 dt(92px) + dd 가 무너진다. */
@media (max-width: 720px) { .pricing__tail { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); } }
.pricing__box > * + * { margin-top: var(--sp-3); }
.pricing__lbl  { font-size: var(--fs-sm); font-weight: var(--fw-sb); color: var(--c-ink); }
.pricing__lead { max-width: 56ch; color: var(--c-ink-2); }
/* .info 의 구분선(--c-line-2)은 section--soft 위에서 사라진다 */
.pricing__box .info__r { border-bottom-color: var(--c-line); }
.pricing__box .info__r > dt { width: auto; min-width: 92px; }   /* '주말·공휴일' 이 92px 를 넘는다 */
/* base 리셋이 list-style:none 이라 지금 수칙 목록은 들여쓰기만 있고 점이 없다 */
.pricing__rules { max-width: 56ch; color: var(--c-ink-2); list-style: disc; padding-inline-start: var(--sp-5); }
.pricing__rules li + li { margin-top: var(--sp-2); }
.pricing__rules li::marker { color: var(--c-muted-2); }
.pricing__cta { margin-top: var(--sp-10); }
@media (max-width: 560px) { .pricing__cta .btn { display: flex; width: 100%; } }

/* ============ 13. 사진 ============ */
/* 원본이 최대 966px 이라 확대 배치를 피한다. 문서: 디자인/05-brand.md §3 */
.media {
  position: relative; overflow: hidden;
  border-radius: var(--r-md); background: var(--c-bg-sink);
}
.media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.media--16x9 { aspect-ratio: 16 / 9; }
.media--4x3  { aspect-ratio: 4 / 3; }
.media--1x1  { aspect-ratio: 1 / 1; }
.media--3x4  { aspect-ratio: 3 / 4; }
.media--tall { aspect-ratio: 4 / 5; }
/* 사진 위에 글자를 올릴 때는 반드시 이 그라디언트를 깐다 */
.media__veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(var(--c-deep-rgb), 0) 30%, rgba(var(--c-deep-rgb), .82) 100%);
}
.media__cap {
  position: absolute; left: var(--sp-4); right: var(--sp-4); bottom: var(--sp-4);
  color: #fff;
}
.media__tag {
  position: absolute; top: var(--sp-3); left: var(--sp-3);
  background: rgba(var(--c-deep-rgb), .66); color: #fff;
  padding: 4px 10px; border-radius: var(--r-full);
  font-size: var(--fs-cap); font-weight: var(--fw-sb);
  backdrop-filter: blur(6px);
}
.credit { font-size: 11px; color: var(--c-muted-2); }

/* 사진 히어로 */
.hero--photo { background: var(--c-deep-1); }
.hero__bg { position: absolute; inset: 0; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; opacity: .55; }
.hero__bg::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(105deg, rgba(var(--c-deep-rgb), .94) 0%, rgba(var(--c-deep-rgb), .72) 46%, rgba(var(--c-deep-rgb), .3) 100%),
    linear-gradient(180deg, rgba(var(--c-deep-rgb), .5) 0%, transparent 30%, rgba(var(--c-deep-rgb), .55) 100%);
}

/* ---- 슬라이드 히어로 (.hero--slides) ----
   왜 가로로 미는 슬라이드가 아니라 교차 페이드인가:
   미는 방식은 전환 중 두 사진이 반씩 걸쳐 보인다. 그러면 왼쪽 타이틀 뒤의 밝기가
   매 프레임 달라져 글자가 읽히다 말다 한다. 겹쳐 놓고 투명도만 바꾸면
   .hero__bg::after 오버레이가 늘 같은 자리에 있어 전환 내내 대비가 일정하다.

   타이밍의 진실은 --hero-hold 한 곳이다. JS(heroSlides)가 이 값을 읽어 다음 장으로
   넘기고, 아래 진행 막대도 같은 값으로 찬다 — 두 군데에 7초를 적어 두면 반드시 어긋난다. */
.hero--slides { --hero-hold: 7000ms; }

/* .hero__bg img 의 opacity:.55 를 이겨야 하므로 선택자를 한 단계 더 준다 */
.hero--slides .hero__bg > img {
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity var(--t-vslow) var(--ease);
}
.hero--slides .hero__bg > img.is-on {
  opacity: .55;                       /* 단일 사진 히어로와 같은 농도를 유지한다 */
  /* 아주 느린 축소. 페이드 시간만큼 더 돌려야 다음 장으로 넘어가는 순간 멈춰 보이지 않는다 */
  animation: hero-drift calc(var(--hero-hold) + var(--t-vslow)) var(--ease-out) both;
}
@keyframes hero-drift { from { transform: scale(1.07); } to { transform: scale(1); } }

/* 진행 막대 — 몇 장 중 몇 번째인지, 언제 넘어가는지를 같이 보여준다.
   막대는 4px 지만 버튼은 44px 이다(터치 타깃). i 가 실제 요소인 이유는
   JS 가 이 요소의 animationend 로 다음 장을 넘기기 때문 — 마우스를 올려
   애니메이션이 멈추면 넘김도 같이 멈춘다. 타이머를 따로 두면 이게 안 맞는다. */
.hero__dots { position: relative; display: flex; gap: var(--sp-2); margin-top: var(--sp-8); }
.hero__dot {
  position: relative; width: 34px; height: 44px;
  padding: 0; border: 0; background: none; cursor: pointer;
  transition: width var(--t-base) var(--ease);
}
.hero__dot::before, .hero__dot i {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 4px; margin-top: -2px; border-radius: var(--r-full);
}
.hero__dot::before { background: rgba(255, 255, 255, .3); }
.hero__dot:hover::before { background: rgba(255, 255, 255, .5); }
.hero__dot i { background: var(--c-accent); transform-origin: left; transform: scaleX(0); }
.hero__dot[aria-current="true"] { width: 64px; }
.hero__dot[aria-current="true"] i { animation: hero-fill var(--hero-hold) linear forwards; }
@keyframes hero-fill { to { transform: scaleX(1); } }

/* 마우스를 올리거나 키보드 포커스가 들어오면 멈춘다. 읽는 중에 사진이 갈리면
   방해가 되고, 접근성 기준(자동 전환에는 멈출 수단이 있어야 한다)도 여기서 만족한다. */
.hero--slides.is-held .hero__bg > img.is-on,
.hero--slides.is-held .hero__dot i { animation-play-state: paused; }

/* 사진 출처. .credit 을 쓰지 않는 이유는 --c-muted-2 가 딥오션 위에서 거의 안 보여서다 */
.hero__credit {
  position: absolute; right: var(--gutter); bottom: var(--sp-3);
  font-size: 11px; color: rgba(255, 255, 255, .5);
}

@media (prefers-reduced-motion: reduce) {
  /* 애니메이션을 끄면 animationend 가 오지 않아 자동 넘김 자체가 서지 않는다.
     점은 그대로 눌러서 넘길 수 있다 — 다만 진행 막대는 채워 둬야 현재 장이 보인다. */
  .hero--slides .hero__bg > img.is-on { animation: none; }
  .hero__dot[aria-current="true"] i { animation: none; transform: scaleX(1); }
}

/* 입체 히어로 타이틀 — 시설명 전용. 물속에서 떠오르는 인상을 노린다.
   text-shadow 를 얇게 여러 겹 쌓아 압출(extrude)하고, 마지막 두 겹으로 접지 그림자와
   아쿠아 글로우를 얹는다. background-clip:text 는 쓰지 않는다 —
   글자 속이 투명해지면 아래 압출 그림자가 비쳐 보여 입체감이 도로 무너진다. */
.hero__title {
  position: relative;
  font-size: clamp(38px, 8.2vw, 88px);
  line-height: 1.04;
  font-weight: 800;
  letter-spacing: -.035em;
  color: #FFFFFF;
  text-shadow:
    0 1px 0 rgba(210, 246, 250, .78),
    0 2px 0 rgba(var(--c-accent-rgb), .52),
    0 4px 0 rgba(var(--c-brand-rgb), .40),
    0 7px 0 rgba(var(--c-deep-rgb), .34),
    0 14px 30px rgba(0, 0, 0, .46),
    0 0 52px rgba(var(--c-accent-rgb), .30);
}
.hero__title em { font-style: normal; color: var(--c-accent); }

/* 글자 뒤 수중광 — 배경 사진과 타이틀 사이의 대비를 벌려 준다 */
.hero__title::before {
  content: ""; position: absolute; z-index: -1;
  left: -6%; right: 22%; top: -18%; bottom: -22%;
  background: radial-gradient(ellipse at 30% 50%, rgba(var(--c-accent-rgb), .26) 0%, transparent 70%);
  pointer-events: none;
}

@media (max-width: 720px) {
  .hero__title { letter-spacing: -.03em; }
  /* 작은 화면에서 6겹은 뭉친다 — 압출을 절반으로 줄인다 */
  .hero__title {
    text-shadow:
      0 1px 0 rgba(210, 246, 250, .7),
      0 3px 0 rgba(var(--c-brand-rgb), .38),
      0 8px 18px rgba(0, 0, 0, .45),
      0 0 34px rgba(var(--c-accent-rgb), .26);
  }
}

/* 종목 카드 — 사진 + 요금 */
.prog {
  display: block; overflow: hidden; text-decoration: none; color: inherit;
  border-radius: var(--r-md); background: var(--c-bg);
  border: 1px solid var(--c-line);
  transition: box-shadow var(--t-base) var(--ease), transform var(--t-base) var(--ease);
}
.prog:hover { text-decoration: none; box-shadow: var(--sh-3); transform: translateY(-3px); }
.prog:hover .prog__img img { transform: scale(1.04); }
/* span 으로 감싸도 비율이 먹도록 display 를 명시한다 */
.prog__img { display: block; position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--c-bg-sink); }
.prog__img img { width: 100%; height: 100%; object-fit: cover; transition: transform var(--t-slow) var(--ease); }
.prog__bd { display: block; padding: var(--sp-4) var(--sp-5) var(--sp-5); }
/* 사진이 없는 종목 — 다른 종목 사진으로 채우지 않고 자리표시자를 둔다 */
.prog__ph {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  width: 100%; height: 100%; background: var(--grad-deep); color: var(--c-on-deep-2);
}
.prog__price { font-size: 21px; font-weight: var(--fw-bd); letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.prog__price small { font-size: 13px; font-weight: var(--fw-md); color: var(--c-muted); }

/* ============ 14. 계단식 수심 다이어그램 ============ */
/* 수심은 숫자 세 개로 읽으면 감이 안 온다. 옆에서 자른 그림에 사람을 하나 세워 두면
   "1.2m 는 발이 닿고 5m 는 못 닿는다" 가 한눈에 온다.
   입체감은 가짜 3D 가 아니라 **층**으로 만든다 — 원근을 주면 깊이가 왜곡돼
   오히려 읽기 어렵다. 물 그라디언트 + 1m 눈금 + 빛줄기 + 바닥 안쪽 그림자.
   렌더러는 assets/js/depthchart.js 한 곳이다. */
.depth {
  position: relative; border-radius: var(--r-md); overflow: hidden;
  background: var(--grad-deep);
  box-shadow: var(--sh-2), inset 0 1px 0 rgba(255, 255, 255, .12);
}
.depth svg { display: block; width: 100%; height: auto; }

.depth__water   { fill: url(#dcWater); }
.depth__floor   { stroke: var(--c-on-deep-3); stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
.depth__inner   { stroke: var(--c-deep-1); stroke-width: 14; stroke-linejoin: round; fill: none; opacity: .5; }
.depth__surface { stroke: var(--c-on-deep-3); stroke-width: 2.5; stroke-linecap: round; }
.depth__grid    { stroke: #fff; stroke-width: 1; opacity: .10; }
.depth__drop    { stroke: var(--c-on-deep-3); stroke-width: 1; stroke-dasharray: 3 4; opacity: .55; }
.depth__tick    { fill: var(--c-on-deep-2); font-size: 10.5px; letter-spacing: .04em; font-variant-numeric: tabular-nums; }
.depth__m       { fill: #fff; font-size: 20px; font-weight: var(--fw-bd); letter-spacing: -.5px; font-variant-numeric: tabular-nums; }
.depth__lb      { fill: var(--c-on-deep); font-size: 12px; font-weight: var(--fw-sb); }
.depth__nt      { fill: var(--c-on-deep-2); font-size: 11px; }
/* 사람은 크기 기준이지 주인공이 아니다 — 흰색이되 살짝 물러난다 */
.depth__person circle { fill: #fff; opacity: .78; }
.depth__person path   { stroke: #fff; stroke-width: 2.4; opacity: .78; }
.depth__board rect    { fill: var(--c-on-deep); opacity: .85; }

/* 치수 — 단면도가 말하지 못하는 값(가로·레인)을 옆에 붙인다 */
.depth__specs { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-4); }
.depth__spec {
  display: inline-flex; align-items: baseline; gap: 6px;
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-full);
  background: var(--c-bg); border: 1px solid var(--c-line);
  box-shadow: var(--sh-1);
}
.depth__spec dt { font-size: var(--fs-cap); color: var(--c-muted); }
.depth__spec dd { font-size: var(--fs-sm); font-weight: var(--fw-sb); color: var(--c-ink); }

@media (max-width: 560px) {
  .depth__m  { font-size: 16px; }
  .depth__lb { font-size: 10.5px; }
  .depth__nt { display: none; }        /* 좁으면 설명이 서로 겹친다 — 숫자와 이름만 남긴다 */
}

/* 데모 전용 — 목업 안내 리본 */
.demobar {
  background: var(--c-deep-2); color: var(--c-on-deep); font-size: var(--fs-cap);
  padding: 7px var(--gutter); text-align: center; letter-spacing: .01em;
}
.demobar b { color: var(--c-on-deep-3); font-weight: var(--fw-sb); }
.demobar a { color: var(--c-on-deep-3); text-decoration: underline; }

/* ============ 15. 대시보드 · 차트 ============
   문서: 디자인/02-components.md §15
   색은 --dv-* 토큰만 쓴다. 종목 배지 색을 차트에 끌어오지 않는다(토큰 주석 참고). */

/* 깊이감은 원근 왜곡이 아니라 **표면의 층**으로 만든다.
   막대를 비스듬히 세우면 길이가 값과 어긋나 데이터가 거짓말을 한다. */
.dash { display: grid; gap: var(--sp-5); }
/* 그리드 아이템의 기본 min-width 는 auto 다 — 안쪽 콘텐츠(히트맵 min-width:460px)가
   컨테이너보다 넓으면 축소되지 않고 조상까지 밀어 올린다. 좁은 화면이 통째로 가로 스크롤된다. */
.dash > *, .dash__row > *, .chart > *, .chart__bd > * { min-width: 0; }
.dash .grid { align-items: start; }
/* 인라인 style 로는 미디어 쿼리를 못 건다. 행 배치는 클래스로 둔다. */
/* ⚠️ align-items 를 start 로 두면 같은 행의 두 카드가 **각자 제 높이**만 차지해
   오른쪽이 들쭉날쭉해진다(2026-09-03 실측: 320 대 200, 428 대 286). 늘려 맞추고,
   안쪽 그림은 남는 자리 가운데에 둔다 — 위로 몰리면 아래가 빈 상자로 보인다. */
.dash__row { display: grid; grid-template-columns: 1.55fr 1fr; gap: var(--sp-5); align-items: stretch; }
.dash__row > .chart { display: flex; flex-direction: column; }
.dash__row > .chart > .chart__bd { flex: 1; display: flex; flex-direction: column; justify-content: center; }
.dash__row > .chart > .chart__bd > * { width: 100%; }
@media (max-width: 980px) { .dash__row { grid-template-columns: minmax(0, 1fr); } }

.dash__hero {
  background: var(--grad-deep); border-radius: var(--r-lg);
  padding: var(--sp-6) var(--sp-6) var(--sp-5);
  position: relative; overflow: hidden;
  box-shadow: 0 18px 40px rgba(var(--c-deep-rgb), .28), 0 2px 0 rgba(255, 255, 255, .06) inset;
}
.dash__hero::after {                       /* 우상단 수중광 */
  content: ""; position: absolute; width: 420px; height: 420px; border-radius: 50%;
  top: -230px; right: -120px; pointer-events: none;
  background: radial-gradient(circle, rgba(var(--c-accent-rgb), .26) 0%, transparent 65%);
}
.dash__heroGrid { position: relative; display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-6); }
.dash__heroGrid > div { min-width: 0; }
@media (max-width: 860px) { .dash__heroGrid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-5); } }

.kpi__k { font-size: var(--fs-cap); color: var(--c-on-deep-2); letter-spacing: .02em; }
.kpi__v {
  margin-top: 6px; font-size: 30px; font-weight: var(--fw-bd); color: #fff;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums; line-height: 1.1;
}
.kpi__v small { font-size: 15px; font-weight: var(--fw-md); color: var(--c-on-deep-2); margin-left: 3px; }
/* 밝은 면(흰 카드) 위의 큰 숫자.
   ⚠️ `.kpi__v` 는 **딥오션 히어로 전용**이라 글자가 흰색이다. 흰 카드에 그대로 쓰면
      숫자가 배경에 묻혀 **아무것도 안 보인다** — 회원 대시보드의 포인트 잔액이 실제로
      그랬다(2026-09-07 실측: 24,000P 가 'P' 로만 보였다. DOM 에는 있는데 화면에 없어
      더 찾기 어려웠다).
   ⚠️ 클래스 하나끼리는 명시도가 같아 **순서가 이긴다** — 반드시 `.kpi__v` 뒤에 둔다
      (`.modal__box--media` 와 같은 이유). */
.kpi__v--ink { color: var(--c-ink); }
.kpi__v--ink small { color: var(--c-muted); }
.kpi__d { margin-top: 5px; font-size: var(--fs-cap); font-weight: var(--fw-sb); display: inline-flex; gap: 4px; }
.kpi__d--up { color: var(--c-on-deep-3); }
.kpi__d--down { color: var(--c-danger-deep); }
.kpi__d--flat { color: var(--c-on-deep-2); }
.kpi__spark { display: block; width: 100%; height: 26px; }
/* 스파크라인은 값이 아니라 '흐름'이다. 높이를 고정하지 않으면 SVG 가 패널 밖으로 흘러나온다. */
.kpi__sparkBox { margin-top: 10px; height: 26px; overflow: hidden; }

/* 차트 카드 */
.chart { background: var(--c-bg); border: 1px solid var(--c-line); border-radius: var(--r-md); box-shadow: var(--sh-1); }
.chart__hd { display: flex; align-items: baseline; gap: var(--sp-3); padding: var(--sp-5) var(--sp-5) 0; }
.chart__hd h3 { font-size: var(--fs-h3); font-weight: var(--fw-sb); letter-spacing: var(--ls-tight); }
.chart__sub { font-size: var(--fs-cap); color: var(--c-muted); }
.chart__bd { padding: var(--sp-4) var(--sp-5) var(--sp-5); position: relative; }
.chart__svg { display: block; width: 100%; overflow: visible; }

.dv-grid line { stroke: var(--dv-grid); stroke-width: 1; }
.dv-axis text { fill: var(--dv-axis); font-size: 11px; }
.dv-line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.dv-dot { r: 4.5; }

/* ---------- 수지 그래프 · 깊이 도넛 (charts.js budgetBars · donutDepth) ----------
   ⚠️ 위의 `.dv-grid line` 은 **그룹에 클래스가 붙은** 형태다. 수지 그래프는 요소마다
      직접 붙이므로 선택자를 따로 둔다 — 안 두면 눈금과 축 글자가 기본색으로 나온다.
   ⚠️ 입체감은 **면의 층**으로만 낸다(charts.js 머리말). 원근으로 눕히지 않는다 —
      길이가 값이기 때문이다. 여기서 하는 일은 그림자와 하이라이트뿐이다. */
line.dv-grid { stroke: var(--dv-grid); stroke-width: 1; }
text.dv-axis { fill: var(--dv-axis); font-size: 11px; }
.dv-zero { stroke: var(--dv-axis); stroke-width: 1.5; stroke-dasharray: 4 3; opacity: .8; }
.dv-net {
  fill: none; stroke: var(--c-ink); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; opacity: .75;
}
.dv-svg { display: block; width: 100%; overflow: visible; }
.dv-donut { max-width: 220px; margin: 0 auto; }
.dv-donut__v { fill: var(--c-ink); font-size: 22px; font-weight: 700; }

/* 수지 요약 3칸 — 수입·지출·순이익 */
.budget-kpi { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); }
.budget-kpi__c {
  padding: var(--sp-4); border-radius: var(--r-md);
  background: var(--c-bg-soft); border: 1px solid var(--c-line);
}
.budget-kpi__k { font-size: var(--fs-cap); color: var(--c-muted); }
.budget-kpi__v { margin-top: 4px; font-size: var(--fs-h3); font-weight: var(--fw-bd); }
.budget-kpi__c--in .budget-kpi__v { color: var(--dv-cat-1); }
.budget-kpi__c--out .budget-kpi__v { color: var(--dv-cat-3); }
/* 순이익이 음수면 색으로 먼저 알린다 — 숫자 앞의 마이너스는 놓치기 쉽다 */
.budget-kpi__c--net.is-minus .budget-kpi__v { color: var(--c-danger); }

@media (max-width: 560px) {
  .budget-kpi { grid-template-columns: 1fr; }
}

/* 마우스를 올린 지점 */
.dv-cross { stroke: var(--c-muted-2); stroke-width: 1; stroke-dasharray: 3 3; }
.dv-hit { fill: transparent; cursor: crosshair; }

.dv-tip {
  position: absolute; pointer-events: none; z-index: 5;
  background: rgba(var(--c-shadow-rgb), .95); color: #fff;
  padding: 8px 11px; border-radius: var(--r-xs);
  font-size: var(--fs-cap); line-height: 1.5; white-space: nowrap;
  box-shadow: var(--sh-3); transform: translate(-50%, -115%);
  opacity: 0; transition: opacity var(--t-fast) var(--ease);
}
.dv-tip.is-on { opacity: 1; }
.dv-tip b { color: var(--c-on-deep-3); font-variant-numeric: tabular-nums; }

.dv-empty { padding: var(--sp-8) var(--sp-4); text-align: center; }
.dv-empty__m { font-size: var(--fs-sm); font-weight: var(--fw-sb); color: var(--c-muted); }
.dv-empty__h { font-size: var(--fs-cap); color: var(--c-mute2, var(--c-muted-2)); margin-top: 6px; }

/* 100% 누적 막대 — 부분과 전체 */
.dv-share { display: flex; height: 34px; border-radius: var(--r-xs); overflow: hidden; gap: 2px; }
.dv-share > i { display: block; height: 100%; transition: filter var(--t-fast) var(--ease); }
.dv-share > i:hover { filter: brightness(1.12); }
.dv-legend { display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5); margin-top: var(--sp-4); }
.dv-legend__i { display: inline-flex; align-items: center; gap: 7px; font-size: var(--fs-sm); color: var(--c-ink-2); }
.dv-legend__sw { width: 11px; height: 11px; border-radius: 3px; flex: none; }
.dv-legend__v { color: var(--c-muted); font-variant-numeric: tabular-nums; }

.dv-rank { display: grid; gap: 10px; margin-top: var(--sp-5); }
.dv-rank__r { display: grid; grid-template-columns: 92px 1fr auto; align-items: center; gap: var(--sp-3); }
.dv-rank__k { font-size: var(--fs-sm); color: var(--c-ink-2); }
.dv-rank__t { display: block; height: 12px; background: var(--c-bg-sink); border-radius: var(--r-full); overflow: hidden; }
.dv-rank__f { display: block; height: 100%; border-radius: var(--r-full); }
.dv-rank__v { font-size: var(--fs-cap); color: var(--c-muted); font-variant-numeric: tabular-nums; min-width: 64px; text-align: right; }

/* 히트맵 — 요일 × 회차.
   열이 12개(평일 8 + 주말 4 합집합)라 좁은 화면에서는 들어가지 않는다.
   페이지 전체를 가로로 밀지 말고 **자기 안에서만** 스크롤시킨다. */
.dv-heatWrap { overflow-x: auto; padding-bottom: 4px; }
.dv-heat { min-width: 460px; display: grid; gap: 3px; font-variant-numeric: tabular-nums; }
.dv-heat__cell { aspect-ratio: 1 / .62; border-radius: 4px; cursor: default; transition: transform var(--t-fast) var(--ease); }
.dv-heat__cell:hover { transform: scale(1.08); }
.dv-heat__lab { font-size: 10.5px; color: var(--dv-axis); text-align: center; }
.dv-heat__row { font-size: 10.5px; color: var(--dv-axis); display: grid; place-items: center end; padding-right: 6px; }

/* ⚠️ 막대의 트랙과 채움은 <span>·<i> 라 **display: block 이 반드시 있어야** 한다.
   인라인 요소에는 width·height 가 먹지 않아 아무것도 안 보인다 (.prog__img 와 같은 함정).

   예약 흐름 — 풀의 계단식 단면을 그대로 쓴다 (로고·수심 다이어그램과 같은 형태 언어) */
.dv-flow { display: grid; gap: var(--sp-2); }
.dv-flow__r { display: grid; grid-template-columns: 96px 1fr auto; align-items: center; gap: var(--sp-3); }
.dv-flow__k { font-size: var(--fs-sm); color: var(--c-ink-2); }
.dv-flow__t { display: block; height: 26px; background: var(--c-bg-sink); border-radius: var(--r-xs); overflow: hidden; }
.dv-flow__f { display: block; height: 100%; border-radius: var(--r-xs); box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset; }
.dv-flow__v { font-size: var(--fs-sm); font-weight: var(--fw-sb); font-variant-numeric: tabular-nums; min-width: 42px; text-align: right; }

/* 표 보기 — 색을 못 읽는 경우의 대안. 모든 차트에 딸린다. */
.dv-tableToggle { background: none; border: 0; color: var(--c-muted); font-size: var(--fs-cap); cursor: pointer; text-decoration: underline; }
.dv-tableToggle:hover { color: var(--c-ink); }
.dv-table { margin-top: var(--sp-4); font-size: var(--fs-sm); width: 100%; border-collapse: collapse; }
.dv-table th, .dv-table td { padding: 7px 10px; border-bottom: 1px solid var(--c-line); text-align: left; }
.dv-table td:not(:first-child), .dv-table th:not(:first-child) { text-align: right; font-variant-numeric: tabular-nums; }

@media (forced-colors: active) {
  .dv-share > i, .dv-heat__cell, .dv-flow__f { forced-color-adjust: none; border: 1px solid CanvasText; }
}

/* 공지 목록 — 히어로 바로 아래에 오므로 세로로 길게 늘어지지 않게 2열로 편다.
   한 줄짜리 제목이 화면 폭을 다 쓰면 '중요한 안내' 가 아니라 '목록' 으로 읽힌다. */
.notice-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
@media (max-width: 720px) { .notice-grid { grid-template-columns: 1fr; } }

/* ============================================================
   16. 전국 지도 — 다이빙풀 위치 (Leaflet + OpenStreetMap)
   지도 엔진은 self-host 한 Leaflet(mockup/assets/vendor/leaflet/)이고,
   여기서는 **핀과 팝업의 옷만** 입힌다. leaflet.css 를 고치지 않는다 —
   버전을 올리면 통째로 덮어써야 하므로 손댄 것이 사라진다.
   회원풀장은 크고 특별하게, 나머지는 작은 점으로 — '어디에 있고 그중
   어디가 우리인지' 가 한눈에 읽혀야 한다.
   ============================================================ */
.pmap {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 320px);
  gap: var(--sp-10); align-items: stretch;
}
@media (max-width: 860px) { .pmap { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); } }

/* 지도는 높이를 명시해야 한다 — Leaflet 컨테이너가 0높이면 타일이 아예 안 뜬다 */
.pmap__map {
  height: 480px; min-height: 320px;
  position: relative;                /* .pmap__hint 의 기준면 */
  border-radius: var(--r-md); overflow: hidden;
  border: 1px solid var(--c-line); background: var(--c-bg-sink);
  z-index: 0;                        /* 상단바(--z-topbar) 위로 타일이 올라오지 않게 */
}
@media (max-width: 860px) { .pmap__map { height: 360px; } }

.pmap__fallback { display: grid; place-items: center; height: 100%; padding: var(--sp-6); text-align: center; }

/* ---- 확대 안내 오버레이 ----
   페이지 한가운데 있는 지도라 맨 휠을 먹으면 스크롤이 갇힌다. 그래서 확대는
   Ctrl(⌘) + 휠로만 받고, 그냥 스크롤하면 **왜 확대가 안 되는지**를 여기 띄운다.
   예전에는 '지도를 한 번 클릭하면 휠 확대가 켜진다' 였는데, 그 사실을 알 방법이
   화면 어디에도 없어 사실상 +/− 버튼(중앙 기준)만 쓰게 됐다(2026-09-18 신고).

   ⚠️ `pointer-events: none` 이 필수다 — 지도 위를 덮으므로 클릭·드래그를 먹으면
      핀을 누를 수 없다. z-index 는 Leaflet 컨트롤(1000) 위로 올린다. */
.pmap__hint {
  position: absolute; inset: 0; z-index: 1200;
  display: grid; place-items: center;
  background: rgba(var(--c-shadow-rgb), .42);
  color: #fff; font-size: var(--fs-sm); font-weight: var(--fw-md);
  text-align: center; padding: var(--sp-6);
  pointer-events: none;
  opacity: 0; transition: opacity var(--t-base) var(--ease);
}
.pmap__hint.is-on { opacity: 1; }
/* 손가락으로 쓰는 화면은 두 손가락 확대가 되므로 안내가 필요 없다 */
@media (pointer: coarse) { .pmap__hint { display: none; } }

/* ---- 핀 ----
   Leaflet DivIcon 은 위치만 잡아 주고 모양은 우리가 그린다.
   .leaflet-div-icon 의 기본 흰 사각형 테두리를 지우는 것이 먼저다. */
.pmap__pin { background: none; border: 0; }
.pmap__pin span { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); border-radius: var(--r-full); display: block; }

/* 그 밖의 다이빙풀 — 있다는 사실만 알리면 된다 */
.pmap__odot { width: 9px; height: 9px; background: var(--c-muted-2); box-shadow: 0 0 0 2px var(--c-bg); }
.pmap__pin--o:hover .pmap__odot { background: var(--c-ink-2); }

/* 회원풀장 — 크고, 브랜드색이고, 번져 나가는 테를 두른다.
   **크기로 먼저 가른다.** 색만으로 가르면 핀이 작을수록 안 읽힌다. */
.pmap__halo { width: 26px; height: 26px; background: var(--c-primary); opacity: .18; transition: opacity var(--t-base) var(--ease); }
.pmap__dot  { width: 17px; height: 17px; background: var(--c-primary); box-shadow: 0 1px 3px rgba(var(--c-shadow-rgb), .4); }
.pmap__core { width: 6px; height: 6px; background: #fff; }
.pmap__pin--m:hover .pmap__halo,
.pmap__pin--m:focus-visible .pmap__halo { opacity: .4; }

/* ---- 팝업 ---- */
.pmap__popup .leaflet-popup-content-wrapper {
  border-radius: var(--r-md); box-shadow: var(--sh-4); padding: 0;
  background: var(--c-bg); color: var(--c-ink);
}
.pmap__popup .leaflet-popup-content { margin: 0; padding: var(--sp-4) var(--sp-5); line-height: inherit; }
.pmap__popup .leaflet-popup-tip { background: var(--c-bg); box-shadow: var(--sh-2); }

/* Leaflet 기본 강조색(#0078A8 · rgba(51,181,229))이 팔레트 밖 청록이다.
   leaflet.css 는 고치지 않는다(버전 올릴 때 덮어써진다) — 여기서 덮는다. */
.pmap .leaflet-container a { color: var(--c-primary); }
.pmap .leaflet-container { -webkit-tap-highlight-color: rgba(var(--c-brand-rgb), .35); }
.pmap .leaflet-container a.leaflet-active,
.pmap .leaflet-bar a:focus-visible { outline: 2px solid var(--c-focus); outline-offset: -2px; }
/* 저작권 줄은 지도 바닥에 붙어 있고, Leaflet 이 자기 컨테이너에 건 overflow:hidden
   (leaflet.css §.leaflet-container)에 바깥 링의 아랫변이 잘린다 — 실측 여유 2px.
   확대/축소 버튼과 같게 링을 안쪽으로 뒤집는다. leaflet.css 는 고치지 않는다. */
.pmap .leaflet-control-attribution a:focus-visible { outline: 2px solid var(--c-focus); outline-offset: -2px; }

.pmap__pop-t { font-size: var(--fs-h3); font-weight: var(--fw-bd); color: var(--c-ink); letter-spacing: var(--ls-tight); }
.pmap__pop-b { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-top: var(--sp-2); }

/* 라벨-값 — .info 와 같은 얼개지만 팝업 폭(300)에 맞춰 라벨을 좁힌다 */
/* 내용이 길어도 팝업이 지도보다 길어지면 안 된다 — 아래 버튼이 잘려
   '풀장 홈' 으로 갈 방법이 사라진다. 표만 접히고 버튼은 늘 보이게 한다. */
.pmap__pd { margin-top: var(--sp-3); display: grid; gap: 5px; max-height: 210px; overflow-y: auto; }
.pmap__pr { display: grid; grid-template-columns: 58px minmax(0, 1fr); gap: var(--sp-3); align-items: baseline; }
.pmap__pr dt { font-size: var(--fs-cap); color: var(--c-muted); }
.pmap__pr dd { font-size: var(--fs-sm); color: var(--c-ink-2); margin: 0; word-break: keep-all; }

.pmap__pop-a { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-4); }
/* 확인 안 된 값이라는 사실을 팝업 안에서 다시 말한다(디자인 절대 규칙 ④) */
.pmap__pop-n {
  margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--c-line-2);
  font-size: 11px; line-height: 1.5; color: var(--c-muted);
}

/* ---- 옆 패널 ---- */
.pmap__side { display: flex; flex-direction: column; justify-content: center; }
.pmap__legend { list-style: none; display: grid; gap: var(--sp-2); margin-top: var(--sp-5); }
.pmap__legend li {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-sm); color: var(--c-ink-2);
}
.pmap__key { flex: none; border-radius: var(--r-full); }
.pmap__key--m {
  width: 15px; height: 15px; background: var(--c-primary);
  box-shadow: 0 0 0 5px var(--c-primary-soft);
}
.pmap__key--o { width: 8px; height: 8px; background: var(--c-muted-2); margin-inline: 3px 4px; }

.pmap__list { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-5); }
.pmap__item {
  display: inline-flex; align-items: baseline; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-4); border: 1px solid var(--c-line);
  border-radius: var(--r-full); background: var(--c-bg); text-decoration: none;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.pmap__item:hover { border-color: var(--c-primary); background: var(--c-primary-soft); text-decoration: none; }
.pmap__item-n { font-size: var(--fs-sm); font-weight: var(--fw-sb); color: var(--c-ink); }
.pmap__item-r { font-size: var(--fs-cap); color: var(--c-muted); }

/* ============================================================
   15. 사용설명서 — 긴 글을 순서대로 따라 읽는 화면
   장식이 아니라 가독성이 목적이다. 한 줄 길이를 제한하고,
   목차는 옆에 고정해 지금 어디를 보는지 알 수 있게 한다.
   ============================================================ */
.guide { display: grid; grid-template-columns: 216px minmax(0, 1fr); gap: var(--sp-10); align-items: start; }
/* ⚠️ 1fr 이 아니라 minmax(0, 1fr) 이다. 그리드 트랙의 최소폭 기본값은 auto(=콘텐츠
   최소폭)라, 본문에 min-width:720px 인 .tbl 이 하나 있으면 트랙이 608px 로 벌어져
   페이지가 통째로 248px 넘쳤다. 0 을 최소로 못박아야 .tbl-scroll 이 제 역할을 한다. */
@media (max-width: 900px) { .guide { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); } }

/* 목차 — 데스크톱에서만 따라온다 */
.guide__toc { position: sticky; top: 84px; display: grid; gap: 2px; }
@media (max-width: 900px) { .guide__toc { position: static; } }
.guide__toc a {
  display: block; padding: 7px 10px; border-radius: var(--r-xs);
  font-size: var(--fs-sm); color: var(--c-ink-2); text-decoration: none;
}
.guide__toc a:hover { background: var(--c-bg-soft); color: var(--c-ink); }
.guide__toc a.is-on { background: var(--c-primary-soft); color: var(--c-primary-ink); font-weight: var(--fw-sb); }

.guide__body { max-width: 68ch; }
.guide__sec + .guide__sec { margin-top: var(--sp-12); padding-top: var(--sp-10); border-top: 1px solid var(--c-line); }
.guide__sec h2 { font-size: var(--fs-h2); font-weight: var(--fw-bd); color: var(--c-ink); scroll-margin-top: 96px; }
.guide__sec p { margin-top: var(--sp-3); font-size: var(--fs-body); line-height: 1.8; color: var(--c-ink-2); }
.guide__sec .note { margin-top: var(--sp-4); }
.guide__sec .tbl-scroll { margin-top: var(--sp-4); }

/* 순서대로 하는 동작 — 번호가 손을 이끈다 */
.guide__steps { margin-top: var(--sp-4); display: grid; gap: var(--sp-3); counter-reset: gstep; }
.guide__steps li {
  position: relative; padding-left: 38px; font-size: var(--fs-body);
  line-height: 1.75; color: var(--c-ink-2);
}
.guide__steps li::before {
  counter-increment: gstep; content: counter(gstep);
  position: absolute; left: 0; top: 1px;
  width: 26px; height: 26px; border-radius: var(--r-full);
  display: grid; place-items: center;
  background: var(--c-primary); color: #fff;
  font-size: var(--fs-cap); font-weight: var(--fw-bd); font-variant-numeric: tabular-nums;
}

/* ============ 16. 언어 전환 ============
   상단바 우측 상단. 문서: 디자인/02-components.md §16 */
/* ⚠️ overflow:hidden 을 쓰지 않는다 — 안쪽 버튼의 포커스 링은 바깥 5px(offset 2 + 굵기 3)에
   그려지는데, 버튼이 컨테이너를 꽉 채우고 있어 링이 **통째로 잘렸다**(2026-08-22 실측).
   hidden 은 is-on 배경을 알약 모양으로 자르려던 것인데, 양 끝 버튼에 반경을 직접 주면
   같은 그림이 되고 링은 살아난다. */
.langsw {
  display: inline-flex; flex: none;
  border: 1px solid var(--c-line); border-radius: var(--r-full);
  background: var(--c-bg);
}
.langsw__b:first-child { border-radius: var(--r-full) 0 0 var(--r-full); }
.langsw__b:last-child  { border-radius: 0 var(--r-full) var(--r-full) 0; }
.langsw__b {
  appearance: none; border: 0; background: transparent; cursor: pointer;
  padding: 0 10px; height: 30px;
  font-size: 11.5px; font-weight: var(--fw-sb); letter-spacing: .04em;
  color: var(--c-muted);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.langsw__b + .langsw__b { border-left: 1px solid var(--c-line); }
.langsw__b:hover { background: var(--c-bg-soft); color: var(--c-ink); }
.langsw__b.is-on { background: var(--c-primary); color: #fff; }
/* 다크 상단바(관리자 모드)에서도 읽히게 */
.topbar--admin .langsw { border-color: rgba(255, 255, 255, .22); background: rgba(255, 255, 255, .06); }
.topbar--admin .langsw__b { color: var(--c-on-deep-2); }
.topbar--admin .langsw__b + .langsw__b { border-left-color: rgba(255, 255, 255, .22); }
.topbar--admin .langsw__b.is-on { background: var(--c-accent); color: var(--c-deep-1); }
@media (max-width: 560px) { .langsw__b { padding: 0 7px; font-size: 11px; } }

/* ============================================================
   18. 풀장 홈 프리미엄 — .ph-*  (문서: 디자인/02-components.md §18)
   서버가 pool.home 을 준 풀장의 홈(pool.html)만 쓴다. 지금은 패스나인 하나다.
   토큰만 읽으므로 테마([data-pool-theme])가 없어도 깨지지 않는다 — 색은 테마가, 모양은 여기가.

   입체감의 주재료는 움직임이 아니라 **겹친 그림자(--sh-lift)와 윗면 하이라이트**다.
   기울기·시차·떠오르기는 reduced-motion 에서 전부 끄고, 끌 때는 최종 모양으로 멈춘다
   (01-foundation 모션 절).
   ============================================================ */

/* ---- 18.1 히어로 — 사진 위 영문 세리프 + 금빛 유리 카드 ---- */
.ph-hero {
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; align-items: center;
  /* 첫 화면 아래 끝에 섹션 탭(46px)이 걸쳐 보이게 — '아래에 더 있다' 는 신호다 */
  min-height: max(560px, min(calc(100vh - var(--h-topbar) - 46px), 860px));
  background: var(--c-deep-1); color: var(--c-on-deep);
  --c-focus: var(--c-on-deep-3);
}
/* 시차 스크롤 — JS 가 --ph-par 만 바꾼다(레이아웃을 건드리지 않는다). 위아래로 넉넉히
   키워 둬야 움직여도 가장자리가 드러나지 않는다. */
.ph-hero__bg {
  position: absolute; inset: -10% 0; z-index: -2;
  transform: translate3d(0, var(--ph-par, 0px), 0);
}
/* 채도를 조금 뺀다 — 물속 사진은 원래 파랗다. 그대로 두면 화면 전체가 다시 '바다색 일색' 이 되고
   금빛 카드가 푸른 유리로 보인다(운영자 요청: 파랑·청록만 쓰지 말 것). */
.ph-hero__bg img { width: 100%; height: 100%; object-fit: cover; object-position: 62% 50%; filter: saturate(.62) contrast(1.06); }
.ph-hero::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(96deg, rgba(var(--c-deep-rgb), .94) 0%, rgba(var(--c-deep-rgb), .80) 36%,
      rgba(var(--c-deep-rgb), .28) 70%, rgba(var(--c-deep-rgb), .12) 100%),
    linear-gradient(180deg, rgba(var(--c-deep-rgb), .50) 0%, transparent 24%,
      transparent 68%, rgba(var(--c-deep-rgb), .88) 100%);
}
/* 브라스 광원 — 왼쪽 아래에서 번지는 빛. 금색을 면으로 칠하지 않고 빛으로만 둔다 */
.ph-hero::after {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  width: 760px; height: 760px; left: -280px; bottom: -420px; border-radius: 50%;
  background: radial-gradient(circle, rgba(var(--c-accent-rgb), .24) 0%, transparent 64%);
}
.ph-hero__in {
  width: 100%;
  display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr);
  gap: var(--sp-12); align-items: center;
  padding-block: var(--sp-24) var(--sp-18);
}
.ph-kicker {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-size: var(--fs-cap); font-weight: var(--fw-sb);
  letter-spacing: .28em; text-transform: uppercase; color: var(--c-on-deep-3);
}
.ph-kicker::before { content: ""; width: 36px; height: 1px; background: currentColor; }
.ph-display {
  margin-top: var(--sp-6);
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(48px, 7.4vw, 100px); line-height: .96; letter-spacing: -.025em;
  color: var(--c-ink);
}
.ph-display span { display: block; }
.ph-display em { font-style: italic; color: var(--c-on-deep-3); }
.ph-hero__name {
  display: flex; align-items: center; gap: var(--sp-4);
  margin-top: var(--sp-8);
}
.ph-hero__name::before { content: ""; width: 48px; height: 1px; background: var(--c-accent); flex: none; }
.ph-hero__name h1 {
  font-size: var(--fs-h1); line-height: var(--lh-h1); font-weight: var(--fw-bd);
  letter-spacing: var(--ls-tight); color: var(--c-ink);
}
.ph-hero__lead { margin-top: var(--sp-3); max-width: 46ch; font-size: 17px; line-height: 1.6; color: var(--c-ink-2); }
.ph-hero__cta { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-10); }
/* 사진 위의 두 번째 버튼 — 유리. 첫 행동(브라스)과 무게가 겹치지 않게 테두리만 */
.btn--glass {
  background: rgba(255, 255, 255, .06); color: #fff;
  border-color: rgba(255, 255, 255, .30);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.btn--glass:hover { background: rgba(255, 255, 255, .12); border-color: rgba(255, 255, 255, .5); }

/* 금빛 유리 카드 더미 — 원근(perspective) 안에서 카드마다 깊이(translateZ)가 다르다.
   포인터를 따라 --ph-tx/--ph-ty 만큼 더 기운다(JS, 마우스일 때만). */
.ph-stack { perspective: 1400px; justify-self: end; width: min(100%, 380px); }
.ph-stack__in {
  display: grid; gap: var(--sp-4);
  transform-style: preserve-3d;
  transform: rotateY(calc(-18deg + var(--ph-tx, 0deg))) rotateX(calc(8deg + var(--ph-ty, 0deg)));
  transition: transform var(--t-slow) var(--ease-out);
}
.ph-stat {
  position: relative;
  display: grid; grid-template-columns: minmax(3.4ch, auto) 1fr; align-items: center; gap: var(--sp-5);
  padding: var(--sp-5) var(--sp-6);
  border-radius: var(--r-lg);
  /* 뒤 사진의 색을 끌어올리지 않는다(saturate 를 낮게) — 올리면 푸른 사진 위에서 카드가 파랗게 뜬다 */
  background: linear-gradient(135deg, rgba(255, 255, 255, .13) 0%, rgba(var(--c-deep-rgb), .34) 100%);
  border: 1px solid rgba(var(--c-accent-rgb), .40);
  backdrop-filter: blur(18px) saturate(80%); -webkit-backdrop-filter: blur(18px) saturate(80%);
  box-shadow: var(--sh-lift-deep);
  transform: translateZ(calc(var(--i, 0) * 34px)) translateX(calc(var(--i, 0) * -20px));
}
/* 윗면 하이라이트 — 빛이 위에서 온다. 이것이 '떠 있다' 는 인상의 절반이다 */
.ph-stat::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, .16) 0%, transparent 42%);
}
.ph-stat__v {
  font-family: var(--font-display); font-size: 50px; line-height: 1;
  color: var(--c-on-deep-3); white-space: nowrap;
}
/* 숫자가 아닌 값은 영어일 때만 한 단 작게 — '해수' 두 글자가 'Seawater' 여덟 글자가 되어
   카드를 밀어낸다. 한국어·중국어는 글자 수가 그대로라 줄이지 않는다(i18n.js 가 html lang 을 바꾼다). */
html[lang="en"] .ph-stat__v--word { font-size: 34px; }
.ph-stat__v small { margin-left: 3px; font-family: var(--font); font-size: 15px; font-weight: var(--fw-sb); color: var(--c-on-deep-2); }
.ph-stat__k { font-size: var(--fs-sm); font-weight: var(--fw-md); line-height: 1.45; color: var(--c-on-deep); word-break: keep-all; }

/* 스크롤 안내 — 가는 선 하나가 아래로 흐른다 */
.ph-cue {
  position: absolute; left: 50%; bottom: var(--sp-6); transform: translateX(-50%);
  display: grid; justify-items: center; gap: var(--sp-2);
  font-size: 10px; letter-spacing: .3em; color: var(--c-on-deep-2);
}
.ph-cue i { position: relative; width: 1px; height: 40px; overflow: hidden; background: rgba(255, 255, 255, .18); }
.ph-cue i::after {
  content: ""; position: absolute; left: 0; top: -40%; width: 1px; height: 40%;
  background: var(--c-on-deep-3); animation: ph-cue 2.2s var(--ease) infinite;
}
@keyframes ph-cue { to { top: 100%; } }

@media (max-width: 900px) {
  .ph-hero { min-height: 0; }
  .ph-hero__in { grid-template-columns: minmax(0, 1fr); gap: var(--sp-10); padding-block: var(--sp-18) var(--sp-14); }
  /* 좁은 화면에서는 기울이지 않는다 — 폭이 모자라 기운 카드가 화면 밖으로 삐져나간다 */
  .ph-stack { justify-self: stretch; width: 100%; perspective: none; }
  .ph-stack__in { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-2); transform: none; }
  .ph-stat { grid-template-columns: minmax(0, 1fr); gap: var(--sp-1); padding: var(--sp-4) var(--sp-3); transform: none; text-align: center; }
  .ph-stat__v { font-size: 34px; }
  html[lang="en"] .ph-stat__v--word { font-size: 18px; line-height: 1.9; }
  .ph-stat__v small { font-size: 12px; }
  .ph-stat__k { font-size: var(--fs-cap); }
  .ph-cue { display: none; }
}

/* ---- 18.2 섹션 뼈대 ---- */
/* ⚠️ 가로로 잘라 둔다 — 카드 뒤 빛(::after)이 wrap 밖으로 번져 페이지 전체에 가로 스크롤이
   생겼다(2026-09-23 실측: 1024px 화면에서 문서 폭 1070). clip 은 스크롤 상자를 만들지 않는다. */
.ph-sec { position: relative; padding-block: var(--sp-24); overflow-x: hidden; overflow-x: clip; }
.ph-sec--ivory { background: var(--c-bg-soft); }
.ph-sec--deep { background: var(--grad-deep); color: var(--c-on-deep); --c-focus: var(--c-on-deep-3); }
@media (max-width: 720px) { .ph-sec { padding-block: var(--sp-18); } }

.ph-head { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-6); align-items: start; margin-bottom: var(--sp-12); }
/* 섹션 번호 — 장식이다(aria-hidden). 밝은 면에서 브라스는 2.3:1 이라 글자로 읽히면 안 되는 자리에만 */
.ph-num {
  font-family: var(--font-display); font-style: italic; font-size: 60px; line-height: .85;
  color: var(--c-accent);
}
.ph-head .t-eyebrow { color: var(--c-accent-ink); letter-spacing: .22em; }
.ph-title {
  margin-top: var(--sp-2);
  font-size: clamp(28px, 3.4vw, 40px); line-height: 1.2; font-weight: var(--fw-bd);
  letter-spacing: var(--ls-tight); color: var(--c-ink);
}
.ph-sub { margin-top: var(--sp-4); max-width: 62ch; color: var(--c-muted); }
.ph-head--split { grid-template-columns: auto minmax(0, 1fr) auto; }
.ph-head__side { align-self: end; display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: flex-end; }
@media (max-width: 720px) {
  .ph-head, .ph-head--split { grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); margin-bottom: var(--sp-8); }
  .ph-num { font-size: 44px; }
  .ph-head__side { justify-content: flex-start; margin-top: var(--sp-3); }
}

/* 스크롤하면 떠오른다 — JS 가 .ph-armed 를 걸었을 때만 숨긴다.
   ⚠️ JS 가 안 돌면(오류·검색 봇·인쇄) 처음부터 보여야 한다. 숨김을 기본값으로 두지 않는다. */
@media (prefers-reduced-motion: no-preference) {
  .ph-armed .ph-reveal { transition: opacity var(--t-vslow) var(--ease-out), transform var(--t-vslow) var(--ease-out); }
  .ph-armed .ph-reveal:not(.is-in) { opacity: 0; transform: translateY(28px); }
}
/* 인쇄는 스크롤이 없다 — 아직 안 떠오른 블록이 빈칸으로 찍히지 않게 전부 연다 */
@media print {
  .ph-armed .ph-reveal { opacity: 1 !important; transform: none !important; }
}

/* ---- 18.3 두 개의 풀 — 사진 위로 겹쳐 올라온 카드 ---- */
.ph-worlds { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-8); align-items: stretch; }
.ph-world { position: relative; display: flex; flex-direction: column; }
.ph-world__fig {
  position: relative; margin: 0; aspect-ratio: 4 / 3;
  border-radius: var(--r-xl); overflow: hidden; background: var(--c-bg-sink);
  box-shadow: var(--sh-lift);
}
/* 히어로보다 약하게 채도를 뺀다 — 물속 사진이 여러 장 모이면 화면이 다시 파랑 일색이 된다 */
.ph-world__fig img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.85); transition: transform var(--t-vslow) var(--ease-out); }
.ph-world:hover .ph-world__fig img { transform: scale(1.045); }
.ph-world__tag {
  position: absolute; left: var(--sp-5); top: var(--sp-5);
  padding: 6px var(--sp-3); border-radius: var(--r-full);
  font-size: 11px; font-weight: var(--fw-bd); letter-spacing: .2em; color: #fff;
  background: rgba(var(--c-deep-rgb), .55); border: 1px solid rgba(255, 255, 255, .22);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.ph-world__panel {
  position: relative; flex: 1;
  display: flex; flex-direction: column;
  margin: calc(var(--sp-18) * -1) var(--sp-6) 0;
  padding: var(--sp-8);
  border-radius: var(--r-lg); background: var(--c-bg);
  border: 1px solid var(--c-line-2);
  box-shadow: var(--sh-lift);
  transition: transform var(--t-slow) var(--ease-out);
}
.ph-world:hover .ph-world__panel { transform: translateY(-6px); }
.ph-world__panel::before {
  content: ""; position: absolute; left: var(--sp-8); top: -1px;
  width: 44px; height: 2px; background: var(--c-accent);
}
.ph-world__title { font-size: var(--fs-h2); line-height: var(--lh-h2); font-weight: var(--fw-bd); letter-spacing: var(--ls-tight); }
.ph-world__text { margin-top: var(--sp-3); color: var(--c-muted); }
.ph-points { display: grid; gap: var(--sp-2); margin-top: var(--sp-5); padding: 0; list-style: none; }
.ph-points li { display: flex; align-items: baseline; gap: var(--sp-3); font-size: var(--fs-sm); color: var(--c-ink-2); }
.ph-points li::before { content: ""; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--c-accent); transform: translateY(-2px); }
.ph-world__act { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: auto; padding-top: var(--sp-6); }
@media (max-width: 820px) {
  .ph-worlds { grid-template-columns: minmax(0, 1fr); gap: var(--sp-10); }
  .ph-world__panel { margin: calc(var(--sp-12) * -1) var(--sp-3) 0; padding: var(--sp-6); }
  .ph-world__panel::before { left: var(--sp-6); }
}

/* ---- 18.4 둘러보기 — 벤토 격자 ---- */
.ph-gallery {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: 230px; gap: var(--sp-4);
}
.ph-shot {
  position: relative; margin: 0; overflow: hidden;
  border-radius: var(--r-lg); background: var(--c-deep-2);
  box-shadow: var(--sh-lift-deep);
}
.ph-shot--lg { grid-column: span 2; grid-row: span 2; }
.ph-shot--wide { grid-column: span 2; }
.ph-shot img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.85); transition: transform var(--t-vslow) var(--ease-out); }
.ph-shot:hover img { transform: scale(1.05); }
.ph-shot figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: var(--sp-10) var(--sp-5) var(--sp-4);
  font-size: var(--fs-sm); font-weight: var(--fw-sb); color: #fff;
  background: linear-gradient(180deg, transparent 0%, rgba(var(--c-deep-rgb), .86) 100%);
}
.ph-credit { margin-top: var(--sp-5); font-size: var(--fs-cap); color: var(--c-on-deep-2); }
@media (max-width: 720px) {
  .ph-gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 150px; gap: var(--sp-2); }
  .ph-shot figcaption { padding: var(--sp-8) var(--sp-3) var(--sp-3); font-size: var(--fs-cap); }
}

/* ---- 18.5 요금 · 회차 ---- */
.ph-price { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: var(--sp-10); align-items: start; }
.ph-fares { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); }
.ph-fare {
  position: relative; padding: var(--sp-8) var(--sp-6) var(--sp-6);
  border-radius: var(--r-lg); background: var(--c-bg);
  border: 1px solid var(--c-line-2); box-shadow: var(--sh-lift);
}
.ph-fare__k { font-size: var(--fs-sm); font-weight: var(--fw-sb); color: var(--c-muted); }
.ph-fare__v { margin-top: var(--sp-3); white-space: nowrap; font-size: 40px; line-height: 1; font-weight: var(--fw-bd); letter-spacing: -.02em; color: var(--c-ink); }
.ph-fare__v small { margin-left: 2px; font-size: 16px; font-weight: var(--fw-sb); }
.ph-fare__u { margin-top: var(--sp-2); font-size: var(--fs-cap); color: var(--c-muted); }
/* 강조 카드 — 한 화면에 하나. 딥 면 위 브라스 금액 */
.ph-fare--hi { background: var(--grad-deep); border-color: transparent; box-shadow: var(--sh-lift-deep); transform: translateY(-10px); }
.ph-fare--hi .ph-fare__k, .ph-fare--hi .ph-fare__u { color: var(--c-on-deep-2); }
.ph-fare--hi .ph-fare__v { color: var(--c-on-deep-3); }
.ph-fares__note { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--c-muted); }
.ph-fares__rows { grid-column: 1 / -1; }

/* 하루 회차 — 운영시간 막대 위에 섹션 구간을 놓는다(막대는 그림이라 aria-hidden, 읽는 것은 아래 목록) */
.ph-sessions { padding: var(--sp-8); border-radius: var(--r-lg); background: var(--c-bg); border: 1px solid var(--c-line-2); box-shadow: var(--sh-lift); }
.ph-sessions__hd { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; }
.ph-sessions__hd b { font-size: var(--fs-h3); }
.ph-bar { position: relative; height: 10px; margin-top: var(--sp-6); border-radius: var(--r-full); background: var(--c-bg-sink); }
.ph-bar i { position: absolute; top: 0; bottom: 0; border-radius: var(--r-full); background: linear-gradient(90deg, var(--c-primary) 0%, rgba(var(--c-brand-rgb), .78) 100%); }
.ph-bar__ends { display: flex; justify-content: space-between; margin-top: var(--sp-2); font-size: var(--fs-cap); color: var(--c-muted); }
.ph-slots { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-2); margin-top: var(--sp-6); padding: 0; list-style: none; }
.ph-slot { padding: var(--sp-3); border-radius: var(--r-md); background: var(--c-bg-soft); }
.ph-slot__n { font-size: 11px; font-weight: var(--fw-bd); letter-spacing: .12em; color: var(--c-accent-ink); }
.ph-slot__t { margin-top: 2px; font-size: var(--fs-h3); font-weight: var(--fw-bd); }
.ph-slot__e { font-size: var(--fs-cap); color: var(--c-muted); }
.ph-sessions__ft { margin-top: var(--sp-5); font-size: var(--fs-sm); color: var(--c-muted); }

/* 장비 · 추가 — 영수증처럼 점선으로 이름과 금액을 잇는다 */
.ph-extras { display: grid; gap: var(--sp-3); margin-top: var(--sp-6); padding: 0; list-style: none; }
.ph-extra { display: grid; grid-template-columns: auto minmax(var(--sp-6), 1fr) auto; align-items: baseline; gap: var(--sp-3); }
.ph-extra::after { content: ""; order: 1; border-bottom: 1px dotted var(--c-line-3); transform: translateY(-4px); }
.ph-extra__n { order: 0; font-weight: var(--fw-sb); }
.ph-extra__n small { display: block; font-weight: var(--fw-reg); font-size: var(--fs-cap); color: var(--c-muted); }
.ph-extra__p { order: 2; font-weight: var(--fw-bd); }

@media (max-width: 900px) {
  .ph-price { grid-template-columns: minmax(0, 1fr); gap: var(--sp-8); }
}
@media (max-width: 520px) {
  .ph-fare { padding: var(--sp-6) var(--sp-4) var(--sp-5); }
  .ph-fare__v { font-size: 26px; }
  .ph-fare__v small { font-size: 13px; }
  .ph-sessions { padding: var(--sp-5); }
  .ph-slots { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* 이용 규정 — 번호가 붙은 네 장 */
.ph-rules { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); margin-top: var(--sp-12); }
.ph-rule {
  position: relative; padding: var(--sp-6) var(--sp-6) var(--sp-6) calc(var(--sp-6) + 44px);
  border-radius: var(--r-lg); background: var(--c-bg); border: 1px solid var(--c-line-2);
}
.ph-rule__i {
  position: absolute; left: var(--sp-6); top: var(--sp-5);
  font-family: var(--font-display); font-style: italic; font-size: 28px; line-height: 1; color: var(--c-accent);
}
.ph-rule__t { font-weight: var(--fw-bd); }
.ph-rule__d { margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--c-muted); }
.ph-guide__cta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); margin-top: var(--sp-10); }
.ph-guide__cta p { flex: 1 1 320px; font-size: var(--fs-sm); color: var(--c-muted); }
@media (max-width: 720px) { .ph-rules { grid-template-columns: minmax(0, 1fr); } }

/* ---- 18.6 교육 · 대관 — 장부처럼 한 줄씩 ---- */
.ph-lessons { border-top: 1px solid var(--c-ink); }
.ph-lesson {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--sp-6);
  padding: var(--sp-6) var(--sp-3);
  border-bottom: 1px solid var(--c-line);
  transition: background var(--t-base) var(--ease);
}
.ph-lesson:hover { background: var(--c-bg-soft); }
.ph-lesson__n { font-size: var(--fs-h3); font-weight: var(--fw-bd); }
.ph-lesson__d { margin-top: var(--sp-1); font-size: var(--fs-sm); color: var(--c-muted); }
.ph-lesson__p { font-size: var(--fs-h3); font-weight: var(--fw-bd); text-align: right; white-space: nowrap; }
.ph-lesson__p--ask {
  padding: 6px var(--sp-3); border-radius: var(--r-full);
  font-size: var(--fs-cap); font-weight: var(--fw-sb); letter-spacing: .04em;
  color: var(--c-accent-ink); border: 1px solid var(--c-accent);
}
@media (max-width: 560px) {
  .ph-lesson { grid-template-columns: minmax(0, 1fr); gap: var(--sp-2); padding-inline: 0; }
  .ph-lesson__p { text-align: left; white-space: normal; justify-self: start; }
}

/* ---- 18.7 찾아가기 — 딥 면 위 주소와 떠 있는 유리 판 ---- */
.ph-visit { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: var(--sp-12); align-items: center; }
.ph-visit__addr { font-size: clamp(22px, 2.6vw, 30px); line-height: 1.35; font-weight: var(--fw-bd); color: var(--c-ink); }
.ph-visit__more { margin-top: var(--sp-3); font-size: var(--fs-sm); color: var(--c-muted); }
.ph-visit__act { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-8); }
.ph-visit__ch { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-4); margin-top: var(--sp-6); font-size: var(--fs-sm); color: var(--c-muted); }
.ph-visit__ch a { color: var(--c-primary); text-decoration: underline; text-underline-offset: 3px; }
.ph-visit__panel {
  position: relative; isolation: isolate;
  padding: var(--sp-8); border-radius: var(--r-xl);
  background: linear-gradient(135deg, rgba(255, 255, 255, .10) 0%, rgba(255, 255, 255, .03) 100%);
  border: 1px solid rgba(var(--c-accent-rgb), .36);
  box-shadow: var(--sh-lift-deep);
}
.ph-visit__panel::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, .10) 0%, transparent 40%);
}
/* 판 뒤에서 번지는 브라스 빛 — 판이 면에서 떠 보이게 */
.ph-visit__panel::after {
  content: ""; position: absolute; z-index: -1; inset: -30% -20%; pointer-events: none;
  background: radial-gradient(closest-side, rgba(var(--c-accent-rgb), .20), transparent);
}
.ph-hours { display: grid; margin-top: var(--sp-3); }
.ph-hours > div { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-4); padding-block: var(--sp-4); border-bottom: 1px solid var(--c-line); }
.ph-hours > div:last-child { border-bottom: 0; padding-bottom: 0; }
.ph-hours dt { font-size: var(--fs-sm); color: var(--c-muted); }
.ph-hours dd { font-size: var(--fs-h3); font-weight: var(--fw-bd); color: var(--c-ink); text-align: right; }
@media (max-width: 820px) { .ph-visit { grid-template-columns: minmax(0, 1fr); gap: var(--sp-10); } }
@media (max-width: 520px) { .ph-visit__panel { padding: var(--sp-6); } }

/* 움직임을 끄면 기울기·떠오르기·확대를 전부 멈추고 **최종 모양**으로 둔다 */
@media (prefers-reduced-motion: reduce) {
  .ph-hero__bg { transform: none; }
  .ph-stack__in { transition: none; transform: rotateY(-18deg) rotateX(8deg); }
  .ph-world__fig img, .ph-shot img, .ph-world__panel { transition: none; }
  .ph-world:hover .ph-world__fig img, .ph-shot:hover img, .ph-world:hover .ph-world__panel { transform: none; }
  .ph-cue i::after { animation: none; top: 30%; }
}
@media (prefers-reduced-motion: reduce) and (max-width: 900px) { .ph-stack__in { transform: none; } }

/* ============================================================
   99. 터치 화면의 최소 타깃 — **파일 맨 끝이어야 한다**
   손가락은 마우스 커서가 아니다. 34px 짜리 .btn--sm 과 30px 짜리 언어 버튼은
   화면에서는 멀쩡해 보여도 휴대폰에서 옆 것이 눌린다. 저장소 기준은 44px 다
   (.anav 주석에도 같은 값이 적혀 있다).

   화면 폭이 아니라 **포인터 종류**로 가른다. 좁은 창으로 줄인 데스크톱은
   여전히 마우스라 촘촘한 편이 낫고, 큰 태블릿은 넓어도 손가락이다.
   ⚠️ 미디어쿼리는 명시도를 올리지 않는다. 앞쪽에 두면 뒤에 오는 같은 명시도의
   .btn--sm(--btn-h:34px)·.langsw__b(height:30px)에 그대로 덮인다 — 실제로 그랬다.
   ============================================================ */
@media (pointer: coarse) {
  .btn--sm { --btn-h: 44px; }
  .chip { height: 44px; }
  .langsw__b { height: 44px; }
  .cal__nav { width: 44px; height: 44px; }   /* 달 넘기기 — 옆 날짜가 눌리면 예약일이 틀어진다 */
  /* 밑줄 링크 모양이라 높이를 주면 모양이 무너진다 — 위아래 여백으로만 넓힌다 */
  .dv-tableToggle { padding: 12px 4px; }
  /* .tab 은 밑줄 메뉴라 높이가 아니라 여백으로 늘린다 — 밑줄 위치가 바뀌면 안 된다 */
  .tab { padding-top: var(--sp-3); }
}

/* 설명서의 화면 그림 — 문서: 디자인/02-components.md §17 */
.guide__shot {
  margin: var(--sp-5) 0 0;
  border: 1px solid var(--c-line); border-radius: var(--r-md);
  overflow: hidden; background: var(--c-bg);
  box-shadow: var(--sh-1);
}
.guide__shot img { display: block; width: 100%; height: auto; }
.guide__shot figcaption {
  padding: 10px var(--sp-4);
  border-top: 1px solid var(--c-line); background: var(--c-bg-soft);
  font-size: var(--fs-cap); color: var(--c-muted);
}
.guide__shot figcaption b { color: var(--c-ink-2); }
/* 좁은 화면에서 글자가 뭉개지면 그림이 아니라 얼룩이다 — 가로 스크롤로 원본 폭을 지킨다 */
@media (max-width: 620px) {
  .guide__shot { overflow-x: auto; }
  .guide__shot img { width: 620px; max-width: none; }
}
