/* =========================================================
   더샵 커스텀 스타일 — Phoenix 테마 보조

   테마 자체(theme.css)는 건드리지 않고 우리 도메인 규칙만 여기에 둔다.
   색은 반드시 Phoenix 변수(--phoenix-*)로 — 다크모드가 같이 따라온다.
   커스텀은 최소한만 — Phoenix 유틸리티/컴포넌트 클래스 우선.
   ========================================================= */

/* ═══ 본문 폰트 — Pretendard 로 교체 ═════════════════════════════════════
   테마는 "Nunito Sans"(구글 폰트) → 시스템 폰트 순으로 잡아 두는데, 우리는 CDN 을
   안 써서(CSP) 늘 시스템 폰트로 떨어진다. 그러면 **한글**이 맑은 고딕으로 가고,
   맑은 고딕에는 400·700 두 굵기뿐이라 CSS 규칙상 600 이 700 으로 올라간다 —
   사이드바·fw-semibold 가 전부 볼드로 보이던 원인이다(중간 굵기 실종).
   Pretendard 가변 폰트를 맨 앞에 두어 45~920 을 제 굵기로 그리게 한다.
   등록(@font-face)은 vendors/pretendard/pretendard.css, 여기서는 스택만 갈아 끼운다.

   이 변수 하나만 바꾸면 된다 — 테마가 --phoenix-body-font-family 를 거쳐
   body 부터 전 컴포넌트까지 이 값을 쓴다. theshop.css 가 theme.min.css 뒤에
   실리므로 같은 :root 라도 이쪽이 이긴다.
   폰트를 못 받았을 때를 대비해 뒤쪽 폴백에 한글 폰트(애플 SD 산돌고딕·맑은 고딕)를
   명시해 둔다 — 테마 원본에는 한글 폰트가 아예 없다. */
:root {
  --phoenix-font-sans-serif: "Pretendard Variable", Pretendard, -apple-system,
    BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
    "Apple SD Gothic Neo", "Malgun Gothic", Arial, sans-serif,
    "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

/* 달력 모양 날짜 칩(월/일 두 칸) — Phoenix 원본 user.css 에서 가져왔다.
   테마의 user.css 는 빌드를 거쳐 user.min.css 가 되는 구조인데 이 프로젝트에는
   그 빌드가 없어 로드되지 않는다(layout.html 은 user.min.css 를 부른다).
   그래서 이런 조각은 전부 여기(theshop.css)에 둔다. */
.calendar-monthday {
  width: 3.125rem;
  line-height: 1;
  display: flex;
  flex-direction: column;
  text-align: center;
  font-family: var(--phoenix-font-sans-serif);
  border-radius: 0.375rem;
}
.calendar-monthday .calendar-month {
  background-color: var(--phoenix-danger);
  color: #fff;
  border-radius: 0.375rem 0.375rem 0 0;
  padding: 0.25rem;
  font-weight: 600;
}
.calendar-monthday .calendar-day {
  font-size: 1.728rem;
  padding: 0.25rem;
  border: 0.125rem solid rgba(var(--phoenix-danger-rgb), 0.3);
  border-top: 0;
  border-radius: 0 0 0.375rem 0.375rem;
  color: var(--phoenix-body-color);
  font-weight: 700;
}

/* 브랜드 로고 무지개 흐름 — 상단바 브랜드 텍스트 */
.rainbow-text {
  background: linear-gradient(to right, #ff0000, #ff7f00, #ffff00, #00ff00, #0000ff, #4b0082, #9400d3);
  background-size: 200% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: rainbow-flow 5s linear infinite;
}
@keyframes rainbow-flow {
  to { background-position: -200% center; }
}

/* 회차권 진행 점(dot) 시각화: 완료=채움(primary), 미완료=회색 */
.session-dot {
  display: inline-block;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  background-color: var(--phoenix-secondary-bg);
}
.session-dot.done {
  background-color: var(--phoenix-primary);
}

/* 고객 상세 · 회차 행 고정 폭 컬럼(행마다 들쑥날쑥하지 않게 정렬) */
.session-col-order   { width: 3.2rem; flex-shrink: 0; }
.session-col-content { width: 7rem;   flex-shrink: 0; }   /* 가이드 글자 — 실제 관리 칸(조각 4)에 자리를 내줬다 */
.session-col-pick    { width: 8.6rem; flex-shrink: 0; }
.session-col-date    { width: 8.6rem; flex-shrink: 0; }
.session-col-note    { flex: 1 1 10rem; min-width: 8rem; }
.session-col-actions { width: 8.6rem; flex-shrink: 0; margin-left: auto; }

/* 고객 상세 · 정액권 사용 내역 행 — 회차 행과 같은 방식 */
.use-col-date    { width: 8.6rem; flex-shrink: 0; }
.use-col-name    { flex: 1 1 8rem; min-width: 7rem; }
.use-col-amount  { width: 6.5rem; flex-shrink: 0; }
.use-col-note    { flex: 1 1 8rem; min-width: 7rem; }
.use-col-actions { width: 8.6rem; flex-shrink: 0; margin-left: auto; }

/* 이력 카드(관리·예약) 타임라인 스크롤 영역 높이 */
.history-body-height {
  max-height: 21rem;
  overflow-y: auto;
}

/* 관리 사진 모달 — 썸네일 그리드(정사각 잘라내기) + 우상단 삭제 버튼 */
.photo-thumb {
  width: 6rem;
  height: 6rem;
  object-fit: cover;
}
.photo-del {
  position: absolute;
  top: 0.15rem;
  right: 0.15rem;
  padding: 0 0.35rem;
  line-height: 1.4;
}
/* 등록 대기(아직 업로드 전) 미리보기 — 점선 테두리, [등록]을 눌러야 저장 */
.photo-thumb.photo-pending {
  border: 2px dashed var(--phoenix-primary);
  opacity: 0.85;
}

/* 좌측 회차권 목록 — 선택 표시.

   기본 list-group active(진한 파랑 채움)를 쓰지 않는다: 그 위에 얹히는
   상태 배지(진행중=연한 초록 등)가 파란 바탕에 묻혀 글자가 안 읽힌다.
   대신 옅은 파랑 바탕 + 왼쪽 굵은 선으로 선택을 표시하면
   배지·본문 색을 그대로 두고도 어느 것을 골랐는지 분명하다. */
#pkg-list .list-group-item.active {
  background-color: var(--phoenix-primary-bg-subtle);
  color: var(--phoenix-emphasis-color);
  border-color: var(--phoenix-border-color);
  box-shadow: inset 3px 0 0 0 var(--phoenix-primary);
}
#pkg-list .list-group-item.active .text-body-tertiary {
  color: var(--phoenix-body-secondary-color) !important;
}

/* =========================================================
   예약 캘린더(FullCalendar) — 도메인 규칙만 보정
   (테마 스킨은 Phoenix theme.css 가 담당, 여기서는 우리 규칙만)
   ========================================================= */

/* 주/일 보기 30분 슬롯 높이 확대 — FullCalendar v6 는 CSS 를 런타임 주입하므로 !important */
.fc .fc-timegrid-slot {
  height: 2.5rem !important;
}

/* 월 보기 날짜 숫자 — 한국어 로케일은 '26일'이라 좁은 칸에서 '26'과 '일'이 갈라진다 */
.fc .fc-daygrid-day-number {
  white-space: nowrap;
}

/* 일요일 = 휴무(영업은 월~토) — 옅은 붉은 배경.
   background-image(그라디언트)라 '오늘' 강조 배경 위에도 겹쳐 보인다 */
.fc .fc-daygrid-day.fc-day-sun,
.fc .fc-timegrid-col.fc-day-sun {
  background-image: linear-gradient(
    rgba(230, 55, 87, 0.06), rgba(230, 55, 87, 0.06));
}
.fc .fc-col-header-cell.fc-day-sun .fc-col-header-cell-cushion {
  color: var(--phoenix-danger);
}

/* 토요일 — 같은 방식으로 옅은 푸른 배경 */
.fc .fc-daygrid-day.fc-day-sat,
.fc .fc-timegrid-col.fc-day-sat {
  background-image: linear-gradient(
    rgba(44, 123, 229, 0.06), rgba(44, 123, 229, 0.06));
}
.fc .fc-col-header-cell.fc-day-sat .fc-col-header-cell-cushion {
  color: var(--phoenix-primary);
}

/* 공휴일(외부 캘린더) — 이름 라벨. 바탕색은 피드마다 정한 색(ExternalCalendar.color)을
   FullCalendar 가 인라인 style 로 칠하므로 여기서는 기본색만 두고 !important 를 쓰지 않는다(09-06) */
.fc .holiday-label,
.fc .holiday-label:hover {
  background-color: var(--phoenix-warning);
  border-color: var(--phoenix-warning);
  color: #fff !important;
}
.fc .holiday-label .fc-event-main,
.fc .holiday-label .fc-event-title {
  color: #fff !important;
}

/* 가로로 눕는 이벤트는 **칸 폭을 넘지 않는다** — 월 보기의 날짜 칸과
   시간표(주/일)의 '종일' 줄이 둘 다 .fc-daygrid-event 다. 넘치면 … 로 줄이고,
   잘린 전체는 마우스를 올리면 보인다(title — 캘린더 스크립트가 붙인다).
   글자 크기를 줄이는 쪽은 근본 해결이 아니다 — 공휴일 이름은 외부 피드가 정하는
   값이라 더 긴 것이 언제든 온다('대체공휴일(광복절)'처럼). */
.fc .fc-daygrid-event { max-width: 100%; }
.fc .fc-daygrid-event .fc-event-main,
.fc .fc-daygrid-event .fc-event-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 자르고 나면 이번엔 **보이는 글자가 너무 적다** — 날짜 칸 하나는 100px 도 안 된다.
   그래서 글자가 아니라 **장식**을 줄인다: 테마가 넣는 앞의 점은 색이 늘 같아
   (--phoenix-primary) 이벤트를 구별해 주지 않으면서 15px 를 먹고,
   좌우 여백 0.5rem 도 이 폭에서는 사치다. 둘을 걷으면 두세 글자가 더 산다.
   세로로 서는 시간표 이벤트(.fc-v-event)는 폭이 넉넉하니 그대로 둔다. */
.fc .fc-daygrid-event { padding-left: 0.35rem !important; padding-right: 0.35rem !important; }
.fc .fc-daygrid-event .fc-event-main { padding-left: 0; }
.fc .fc-daygrid-event .fc-event-main::after { content: none; }

/* 모바일 월 보기: 칸이 더 좁으니 글자도 한 단계 작게
   ('외 +N' 더보기 링크도 같은 크기) */
@media (max-width: 575.98px) {
  .fc .fc-dayGridMonth-view .fc-daygrid-event,
  .fc .fc-dayGridMonth-view .fc-daygrid-more-link {
    font-size: 0.6rem;
  }
}

/* 검색창 지우기(×) 버튼 — 값이 있을 때만 입력칸 우측에 나타난다(공용 스크립트가 삽입).
   브라우저 기본 지우기 아이콘은 크롬 계열에서만 보이고 모양도 제각각이라 직접 그린다. */
.search-box .search-clear {
  position: absolute;
  top: 50%;
  right: 0.5rem;
  transform: translateY(-50%);
  z-index: 3;
  /* 테두리·배경 없이 × 글자만 — 테마의 버튼 스타일이 얹히지 않게 명시적으로 지운다 */
  -webkit-appearance: none;
  appearance: none;
  border: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  line-height: 1;
  padding: 0.25rem;
  color: var(--phoenix-quaternary-color);
}
.search-box .search-clear:hover,
.search-box .search-clear:focus {
  color: var(--phoenix-body-secondary-color);
  outline: none;
}
/* 지우기 버튼과 글자가 겹치지 않도록 입력칸 오른쪽 여백 확보 */
.search-box .search-input.has-clear {
  padding-right: 2rem;
}
/* 크롬 계열의 기본 지우기 아이콘은 숨김(우리 버튼과 중복) */
.search-box input[type="search"]::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}

/* 고객 상세 구간 이동 내비(scrollspy) — 스크롤해도 상단에 붙어 있게.
   상단바(navbar-top) 아래에 고정되도록 top 을 그 높이만큼 준다. */
.detail-scrollspy-nav {
  position: sticky;
  top: var(--phoenix-navbar-top-height, 3.5rem);
  z-index: 1010;
}
.detail-scrollspy-nav .nav-link.active {
  color: var(--phoenix-primary) !important;
  border-bottom: 2px solid var(--phoenix-primary);
}
/* 앵커(#sec-care 등)로 건너뛸 때 구간 제목이 상단바·구간 내비 뒤로 숨지 않게.
   회차를 저장하면 그 구간으로 되돌아오는데(뷰의 _care_redirect) 이 여백이 없으면
   제목이 가려져 어디로 온 건지 알아보기 어렵다. */
#sec-profile, #sec-history, #sec-care, #sec-purchase {
  scroll-margin-top: 7rem;
}
/* 문자 리포트의 카드 앵커 — 홈의 '소진 임박 › 모두 보기'로 들어오거나, 카드의
   필터(7일/3개월/2회 이하)를 눌러 그 카드로 되돌아올 때 쓴다(원장 09-17 — 앵커가
   없어 필터를 누를 때마다 맨 위로 튀었다). 이 화면은 구간 내비가 없어 상단바만
   피하면 되므로 위보다 작다. */
#sec-recent, #sec-lapsed, #sec-expiring {
  scroll-margin-top: 5rem;
}

/* 통계 페이지 ECharts 캔버스 기본 높이 */
.stat-chart {
  height: 320px;
}

/* 점 분포도 — 320px 에서는 점이 세로로 뭉쳐 층이 안 갈린다(고객 수가 많을수록 심하다) */
.stat-chart-tall {
  height: 420px;
}

/* 장부 — 카드 실입금 입력칸이 테이블 안에서 과도하게 넓어지지 않게 */
.deposit-input {
  width: 6.5rem;
}

/* 고객 자동완성 결과 목록(구매 등록) — 검색창 바로 아래 떠 있는 드롭다운 */
.cust-search-wrap {
  position: relative;
}
.cust-search-wrap .search-box {
  width: 100%;
}
.cust-results {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 1056;
  margin: 0.25rem 0 0;
  padding: 0;
  list-style: none;
}
.cust-results .list-group-item {
  cursor: pointer;
}

/* 참고: Phoenix 의 hover-actions(행 hover 시 버튼 노출)는 테이블 행에는 쓰지 않는다.
   tr 의 position:relative 해석이 브라우저마다 달라 버튼이 행 밖으로 나가고,
   터치 기기에서는 첫 탭이 hover 만 발동시켜 클릭이 먹지 않는다. */

/* ── 구매 등록 본문(purchase_create.html) ────────────────────────────
   PC: 좌(고객 · ①청구 금액) / 우(구매 품목 · ②실제 결제) **독립된 두 열**.
       품목을 계속 추가해도 오른쪽만 길어지고 ①청구 금액은 제자리에 있어야 한다
       (Bootstrap row 로 2×2 를 만들면 같은 줄끼리 높이가 묶여 아래로 밀린다).
   폰: 한 줄로 풀어 **고객 → 구매 품목 → ①청구 → ②실제 결제** 순으로 쌓는다.
       래퍼를 display:contents 로 없애 네 카드를 같은 흐름에 올리고 order 로 세운다. */
.purchase-body {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.purchase-body > .purchase-col {
  display: contents;
}
.purchase-body .pg-customer { order: 1; }
.purchase-body .pg-items { order: 2; }
.purchase-body .pg-bill { order: 3; }
.purchase-body .pg-pay { order: 4; }
/* [저장]도 순서를 매겨야 한다. display:contents 로 래퍼가 사라지면 저장 버튼도
   같은 흐름의 형제가 되는데, order 를 안 주면 기본값 0 이라 카드(1~4)보다
   **앞**으로 올라간다. PC 와 똑같이 맨 아래에 두려면 마지막 번호가 필요하다. */
.purchase-body .pg-submit { order: 5; }

@media (min-width: 1200px) {
  .purchase-body {
    flex-direction: row;
    align-items: flex-start;   /* 열끼리 높이를 맞추지 않는다 */
  }
  .purchase-body > .purchase-col {
    display: flex;
    flex-direction: column;
    gap: 1rem;
  }
  .purchase-body > .purchase-col-left {
    flex: 0 0 25%;
    max-width: 25%;
    /* 오른쪽(품목·결제)이 길어져도 고객·청구 금액은 화면에 붙여 둔다.
       샘플 apps/crm/deal-details.html 의 .sticky-leads-sidebar 와 같은 방식.
       왼쪽이 화면보다 길면 그만큼은 같이 밀렸다가 멈춘다(sticky 의 정상 동작).
       align-self:flex-start 가 없으면 열이 세로로 늘어나 sticky 가 먹지 않는다. */
    position: sticky;
    top: calc(var(--phoenix-navbar-top-height) + 1.5rem);
    align-self: flex-start;
  }
  .purchase-body > .purchase-col-right {
    flex: 1 1 auto;
    min-width: 0;              /* 표가 넘칠 때 열이 밀려나지 않게 */
  }
  /* 열 안에서는 DOM 순서 그대로 — 폰용 order 를 되돌린다 */
  .purchase-body .pg-customer,
  .purchase-body .pg-items,
  .purchase-body .pg-bill,
  .purchase-body .pg-pay,
  .purchase-body .pg-submit {
    order: 0;
  }
}

/* 결제수단 금액 칸 — 칸 안 오른쪽에 지우기(✕) 버튼.
   기본 수단(계좌이체)에는 결제할 금액이 자동으로 들어가므로 다른 수단으로 받았을 때
   지울 수단이 필요하다. 칸이 좁아(4열) 버튼을 옆에 두면 숫자가 안 보인다. */
.pay-cell {
  position: relative;
}
.pay-cell .form-control {
  padding-right: 1.6rem;
}
.pay-clear {
  position: absolute;
  right: 0.15rem;
  top: 50%;
  transform: translateY(-50%);
  width: 1.3rem;
  height: 1.3rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--phoenix-quaternary-color);
  font-size: 0.7rem;
  line-height: 1;
}
.pay-clear:hover,
.pay-clear:focus-visible {
  background: var(--phoenix-secondary-bg);
  color: var(--phoenix-body-color);
}

/* 남은 금액 넣기 — 결제수단 칸에 포커스하면 떠서 한 번에 채운다.

   칸 **아래**에 붙인다. 칸 안(오른쪽)은 ✕ 자리라 겹치면 둘 다 누르기 어렵고,
   칸 위는 그 수단의 라벨('카드')이 있어 무슨 칸인지 가려 버린다.
   아래는 다음 줄 입력칸을 잠깐 덮지만, 포커스가 빠지면 바로 사라진다. */
.pay-fill {
  position: absolute;
  top: calc(100% + 0.25rem);
  right: 0;
  z-index: 5;
  white-space: nowrap;
  /* 크기는 유틸리티 클래스로 흩지 않고 여기서 잡는다(등록·수정 두 화면 공용).
     폰에서 손가락으로 누르는 버튼이라 높이를 넉넉히 준다. */
  padding: 0.3rem 0.7rem;
  font-size: 0.8rem;
  line-height: 1.25;
  border-radius: 0.375rem;
  box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.12);
}

/* 도움말 [?] — 아이콘을 감싸는 요소. data-help 툴팁과 포커스를 여기서 받는다.
   아이콘 span 은 Font Awesome(SVG 방식)이 <svg> 로 갈아 끼우므로 거기에 걸면 안 된다. */
.help-tip {
  cursor: help;
  color: var(--phoenix-quaternary-color);
}
.help-tip:hover,
.help-tip:focus-visible {
  color: var(--phoenix-body-secondary-color);
}

/* 매출 사다리(_sales_ladder.html) — 장부·대시보드·매출 통계 공용.
   라벨과 금액을 오른쪽으로 붙여 자릿수가 세로로 맞게 한다(금액 칸 고정 폭).
   합계 줄 위에 선을 그어 "여기까지 더하고 뺐다"를 선으로 보여 준다 — 설명 문구 대신. */
/* 사다리 블록은 오른쪽에 붙되 **내용 폭만큼만** 차지한다 —
   구분선이 카드 전체를 가로지르면 왼쪽 빈 곳까지 줄이 그어져 산만하다.
   라벨보다 조금 앞(padding-left)에서 선이 시작하게 여유를 준다. */
.sales-ladder {
  width: fit-content;
  max-width: 100%;
  margin-left: auto;
}
/* 라벨·금액을 함께 오른쪽으로 몬다 — 구분선은 카드 폭 전체를 가로지른다.
   금액 칸은 고정 폭 + tabular-nums 라 자릿수가 세로로 맞는다. */
.sl-row {
  display: flex;
  justify-content: flex-end;
  align-items: baseline;
  gap: 1.5rem;
  padding: 0.35rem 0 0.35rem 2rem;   /* 왼쪽 여유 = 구분선이 라벨보다 앞서 시작하는 폭 */
}
/* 라벨 칸은 왼쪽 정렬 + 최소 폭 — 라벨끼리 시작점이 맞는다.
   더 긴 라벨은 왼쪽으로 늘어나고, 금액 칸은 폭이 고정이라 오른쪽 끝은 항상 그대로다. */
.sl-label {
  min-width: 7rem;
  text-align: left;
  font-size: 0.8rem;
  color: var(--phoenix-body-secondary-color);
}
.sl-amount {
  min-width: 8rem;
  text-align: right;
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;   /* 자릿수 폭을 고정해 세로로 맞춘다 */
}
.sl-sum {
  border-top: 1px solid var(--phoenix-border-color);
}
.sl-sum .sl-label,
.sl-sum .sl-amount {
  font-weight: 600;
  color: var(--phoenix-body-emphasis-color);
}
/* 순매출액 — 세무 기준 매출. 이 사다리의 결론이라 가장 크고 진하게 */
.sl-key .sl-label {
  color: var(--phoenix-primary);
}
.sl-key .sl-amount {
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--phoenix-primary);
}
/* 현금 조정 구간 머리 — 여기부터 기준이 다르다(통장). 굵은 선으로 사다리(청구
   기준)와 끊고 구간 이름 줄을 단다. 글자 스타일은 마크업의 유틸리티 클래스로 */
.sl-section {
  border-top: 2px solid var(--phoenix-border-color);
  margin-top: 0.25rem;
}
.sl-section .sl-label {
  font-size: 0.75rem;
}

/* ── 예약 목록 행(appointment_list.html) ──────────────────────────────
   표(table) 대신 flex 로 짠다. 진짜 표는 열이 많아 폰에서 가로 스크롤이 생기고,
   그러면 시각·이름이 화면 밖으로 밀려 나간다.

   PC: 시각 · 이름 · 관리내용(+회차권/신규 배지)은 왼쪽, 60분 · [완료] · 문자는 오른쪽.
       시각·이름 폭을 rem 으로 고정해 행끼리 줄을 맞춘다 — Bootstrap col-*(화면 폭 퍼센트)로
       맞추면 넓은 화면에서 필드 사이가 과하게 벌어진다.
   폰: [시각 이름 상태 … 문자] 윗줄 / [관리내용 배지] 아랫줄.
       문자 버튼은 이름과 같은 줄에 있어야 누르기 쉽고, 상태를 내리면 행이 세 줄이 된다. */
.appt-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
.appt-row > .appt-name { order: 1; }
/* 전화번호 — 동명이인을 가리는 값이라 이름 바로 뒤에 붙인다.
   폰에서는 템플릿이 뒤 네 자리만 그려 윗줄이 밀리지 않는다. */
.appt-row > .appt-phone { order: 2; white-space: nowrap; }
.appt-row > .appt-time { order: 3; }
.appt-row > .appt-status { order: 4; }
.appt-row > .appt-sms { order: 5; margin-left: auto; }
.appt-row > .appt-care { order: 6; width: 100%; }
.appt-row > .appt-dur { display: none; }  /* 소요시간은 폰에서 숨긴다 */

@media (min-width: 768px) {
  .appt-row {
    flex-wrap: nowrap;
    gap: 0.75rem;
  }
  .appt-row > .appt-name { order: 1; width: 8.5rem; }  /* 아바타(2rem) + 이름 */
  .appt-row > .appt-phone { order: 2; width: 7rem; }   /* 01012341234 = 11자리 */
  .appt-row > .appt-time { order: 3; width: 3.5rem; }
  /* 관리내용이 남는 폭을 먹어 뒤쪽(60분·상태·문자)이 오른쪽에 붙는다.
     회차권/신규 배지는 관리내용 안에 붙어 있어 관리명 바로 옆에 온다. */
  .appt-row > .appt-care { order: 4; flex: 1 1 auto; min-width: 0; }
  .appt-row > .appt-dur { order: 5; display: block; width: 3.5rem; text-align: right; }
  .appt-row > .appt-status { order: 6; width: 3.5rem; text-align: right; }
  .appt-row > .appt-sms { order: 7; width: 2.5rem; text-align: right; margin-left: 0; }
  /* 구매 등록 바로가기 — 문자 버튼 옆(맨 끝). 폰에서는 아예 감춘다(d-none d-md-inline-block) */
  .appt-row > .appt-buy { order: 8; width: 2.5rem; text-align: right; }
  /* 폭 고정이라 긴 이름은 잘라 낸다(폰에서는 줄바꿈되므로 자르지 않는다).
     .appt-name 은 아바타를 담은 flex 라 자르기는 안쪽 이름 span 에 건다 */
  .appt-row > .appt-name > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* ── 소요시간 슬라이더(예약 등록/수정) ───────────────────────────────
   Phoenix noUiSlider 위에 눈금 라벨만 손본다.
   좁은 폰에서 8개(10~120분) 라벨이 붙지 않도록 작게, 눈금은 눌러서도 고를 수 있게. */
#dur-slider .noUi-value {
  font-size: 0.7rem;
  cursor: pointer;
}

/* 상단바 샵 로고 — 올린 그림의 가로세로가 제각각이라 높이만 맞추고 폭은 제한한다
   (가로로 긴 로고가 검색창을 밀어내지 않게) */
.shop-logo {
  max-width: 8rem;
  object-fit: contain;
}

/* ── 사이드바 줄 끝 [+] (예약 목록 → 예약 등록) ─────────────────────
   nav-link 이 <a> 라서 그 안에 링크를 넣을 수 없다 — 형제 링크를 줄 오른쪽 끝에
   겹쳐 둔다. 색은 Phoenix 사이드바 변수라 다크모드가 저절로 따라온다. */
.nav-quick-add {
  position: absolute;
  top: 0;
  right: 0.5rem;
  height: 100%;
  z-index: 2;
  display: flex;
  align-items: center;
  padding: 0 0.5rem;          /* 폰에서 누를 자리 확보 */
  font-size: 0.8rem;
  color: var(--phoenix-navbar-vertical-link-color);
  opacity: 0.6;
}
.nav-quick-add:hover,
.nav-quick-add:focus-visible {
  color: var(--phoenix-primary);
  opacity: 1;
}
/* 사이드바를 접으면(아이콘만 남는 폭) 아이콘 위에 겹치므로 감춘다 */
html.navbar-vertical-collapsed .nav-quick-add {
  display: none;
}

/* ═══ 구매 등록 · 품목 줄 카드 — templates/shop/purchase_create.html ═══
   유형(회차권·정액권·제품)마다 쓰는 칸이 달라 **표(고정 열)를 버렸다** —
   제품은 6칸 중 2칸만 써서 죽은 칸이 많았다. 줄마다 자기 칸만 그리면
   죽은 칸이 없고, 폭이 좁아져도 표처럼 옆으로 밀리지 않는다.
   설계: doc/design-purchase-v2.md §4 */
/* 줄을 상자로 감싸지 않는다 — 예전 표처럼 **위아래 선으로만** 나눈다.
   상자를 씌우면 줄마다 테두리가 생겨 여러 개 쌓였을 때 시끄럽다.
   맨 위 선은 컨테이너가, 줄 사이·맨 아래 선은 각 줄이 낸다(gap 0 이라 붙는다) */
.pi-rows {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--phoenix-border-color);
  /* 컨테이너 쿼리 기준 — 아래 3층 쌓기가 '화면'이 아니라 '이 상자' 폭을 본다.
     폰 화면과 캘린더 사이드 패널(약 300px)이 같은 규칙으로 접힌다 */
  container-type: inline-size;
}

/* 한 줄 = [배지] [칸들…] [✕]. wrap 이라 좁아지면 아래로 접힌다(폰에서 안 깨진다) */
.pi-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.25rem;
  border-bottom: 1px solid var(--phoenix-border-color);
}

/* 종류 배지 — 셀렉트가 사라진 자리. 어떤 [+] 로 넣었는지를 알려 주는 유일한 표시 */
.pi-kind {
  flex: none;
  min-width: 4.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--phoenix-body-secondary-color);
  white-space: nowrap;
}
/* 유형마다 색을 달리해 여러 줄이 섞여 있어도 한눈에 갈린다.
   정액권은 초록·파랑을 쓰지 않는다 — 완료 체크(초록)·회차권(파랑)과 겹쳐 헷갈린다.
   유형별 [+] 버튼도 같은 색(회차권 primary·정액권 purple·제품 warning) —
   "이 버튼 = 이 줄"이 색으로 이어진다 */
.pi-kind[data-kind="single"]  { color: var(--phoenix-success); }
.pi-kind[data-kind="package"] { color: var(--phoenix-primary); }
.pi-kind[data-kind="prepaid"] { color: var(--phoenix-purple); }
.pi-kind[data-kind="product"] { color: var(--phoenix-warning); }

/* 정액권 [+] — 테마에 btn-phoenix-purple 이 없어 같은 방식(버튼 CSS 변수)으로
   만든다. btn-phoenix-secondary 와 겹쳐 써서 배경·테두리(라이트/다크 대응)는
   그대로 물려받고 글자색만 보라로 덮는다 */
.btn-phoenix-purple {
  --phoenix-btn-color: var(--phoenix-purple);
  --phoenix-btn-hover-color: var(--phoenix-purple);
  --phoenix-btn-active-color: var(--phoenix-purple);
}

/* 정렬 규칙 — 줄마다 쓰는 칸이 달라도 **결제액은 늘 같은 자리**에 서야 한다
   (세로로 훑는 값이라서). 그래서 뒤쪽(결제액·부가)은 폭을 고정하고,
   앞쪽(카탈로그·이름)만 flex-grow 로 남는 폭을 흡수하게 둔다.

     회차권  [카탈로그 <->][관리명 <->][결제액][오늘 완료]
     정액권  [명칭 <-------------------->][결제액][충전액  ]
     제품    [제품 <->][품목명 <------->][결제액][        ]

   정액권처럼 앞쪽 칸이 하나뿐이면 그 하나가 남는 폭을 다 가져간다 — 합이 같아
   결제액의 x 가 흔들리지 않는다. */
.pi-f { flex: 0 0 auto; }
/* basis 는 min 과 같게 둔다 — flex-wrap 은 min 이 아니라 basis(희망 폭) 합으로
   줄을 접기 때문에, basis 가 크면 좁은 태블릿에서 들어갈 수 있는데도 접힌다.
   남는 폭은 grow 로 가져간다(카탈로그 2 : 이름 1 — 카탈로그 라벨이 길다) */
.pi-f-plan, .pi-f-product, .pi-f-treatment { flex: 2 1 9rem; min-width: 9rem; }
.pi-f-name   { flex: 1 1 7rem; min-width: 7rem; }
/* 결제액 + 충전액 묶음 — 뜻이 짝이라(10만 결제 → 12만 충전) 바로 옆에 붙고,
   줄이 접힐 때도 같이 움직인다. **묶음 폭 고정**이라 결제액의 x 도, 뒤 오늘 완료
   열도 모든 줄에서 같은 자리에 선다. 충전액이 없는 줄(회차권·제품)은 결제액이
   자라 묶음을 통째로 채운다 — 빈 자리를 남기지 않는다(원장 스케치):
     회차권/제품  [   결제액        ]
     정액권       [[결제액][충전액]] */
/* 16rem — 한 줄 최소 폭이 아이패드 세로(768px대)에 들어가는 크기.
   더 키우면 태블릿이 한 줄 배치를 못 받는다(아래 3층 쌓기 기준과 한 쌍) */
.pi-pay { display: flex; flex: 0 0 16rem; align-items: center; gap: 0.5rem; }
.pi-f-amount { flex: 1 1 8rem; min-width: 0; }
/* 결제액과 같은 flex — 정액권 줄에서 두 칸이 묶음을 정확히 반씩 나눈다 */
.pi-f-charge { flex: 1 1 8rem; min-width: 0; }
/* 상태 열 — 아이콘 한 벌(스피너=진행중 · 체크=오늘 완료), 뜻은 title 툴팁.
   회차권만 누르면 토글되는 버튼이고 정액권·제품은 표시만. 모든 줄이 자리를 잡는다 */
/* 체크박스는 빼고 늘린다 — 넣으면 체크박스가 칸 폭만큼 늘어난다 */
.pi-f input:not([type="checkbox"]), .pi-f select { width: 100%; }

/* 휴지통(줄 빼기)은 늘 오른쪽 끝 — 줄이 접혀도 자리가 안 흔들린다. 색은 늘 빨강 */
.pi-remove { margin-left: auto; flex: none; }

/* 좁은 폭(폰 화면·캘린더 사이드 패널)에서는 품목 줄을 3층으로 쌓는다
   (원장 스케치, 2026-08-19) — flex order 로 시각 순서만 바꾼다(DOM·폼셋 그대로):
     [배지 ──────────── 상태아이콘 휴지통]   ← 머리줄
     [카탈로그(전폭)]                        ← 회차권·제품만
     [이름][결제액]                          ← 정액권은 명칭 전폭 + [결제액][충전액]
   되는 대로 접히던 wrap 을 층으로 고정해 어느 줄이든 같은 모양이 된다.
   기준은 화면이 아니라 .pi-rows 컨테이너 폭 — 데스크톱의 좁은 패널도 걸린다.
   688px = 한 줄 최소 폭(배지+카탈로그·이름 최소+결제액 묶음 16rem+상태+휴지통)
   바로 위 — 한 줄이 안 들어가면 곧장 3층이라, 어중간하게 접히는 구간이 없다.
   아이패드 세로(768px대)는 한 줄(PC 와 동일)로 들어간다(원장 확인, 2026-08-19) */
@container (max-width: 688px) {
  .pi-remove  { order: 2; margin-left: 0; }
  /* 머리줄과 입력줄 사이를 **강제로 끊는다** — 폭 0 짜리 전폭 가상요소.
     정액권 카탈로그는 40% 라 그냥 두면 배지·상태와 한 줄에 딸려 올라간다.
     order 가 휴지통과 같아(2) DOM 순서상 그 뒤에 서고, 다음 order(3)부터 새 줄. */
  .pi-row::after { content: ''; flex-basis: 100%; height: 0; order: 2; }
  .pi-f-plan, .pi-f-product, .pi-f-treatment { order: 3; flex-basis: 100%; }
  .pi-f-name  { order: 4; flex: 1 1 40%; }
  .pi-pay     { order: 5; flex: 1 1 40%; }
  .pi-err     { order: 6; }
  /* 정액권 — 입력 칸이 넷(카탈로그·명칭·결제액·충전액)이라 전폭으로 쌓으면
     입력만 세 줄이 된다. **카탈로그와 명칭을 한 쌍으로 묶어** 다른 종류와 똑같이
     '머리줄 + 입력 두 줄'로 맞춘다(원장 확인, 2026-08-20):
       [배지 ──── 상태 휴지통] / [카탈로그][명칭] / [결제액][충전액] */
  .pi-kind[data-kind="prepaid"] ~ .pi-f-plan { flex: 1 1 40%; flex-basis: 40%; }
  .pi-kind[data-kind="prepaid"] ~ .pi-f-name { flex: 1 1 40%; }
  .pi-kind[data-kind="prepaid"] ~ .pi-pay    { flex-basis: 100%; }
}

/* 오류는 줄 아래 한 줄 통째로 */
.pi-err { flex: 1 1 100%; }

/* ═══ 캘린더 — templates/shop/appointment_calendar.html ═══
   구조: 월 라벨·모드 토글 / 요일 고정 + 날짜 스트립(월 그리드의 한 줄) / 본문.
   넓은 화면(xl↑)에서는 오른쪽에 고정 사이드 패널을 두고 캘린더를 촘촘하게 그린다 —
   달력을 통째로 보면서 옆에서 예약 업무를 하도록. 색은 전부 --phoenix-* 변수. */

/* 헤더 줄 = [2026년 8월] ······ [오늘] [일정|시간표|월]
   PC 는 한 줄로 충분하지만 **폰 폭에는 다섯 덩어리가 다 안 들어간다**. 좁아지면
   flex 가 버튼을 찌그러뜨리고, 그러면 버튼 안의 한글이 줄바꿈된다 — '시간표'가
   '시간/표'로 쪼개져 버튼 높이가 33px → 49px → 64px 로 늘어난다
   (버튼이 세로로 쌓이는 게 아니라 글자가 접히는 것). */

/* 버튼 글자는 어느 폭에서도 접지 않는다 — 위 증상의 직접 원인 */
.newcal .card-header .btn { white-space: nowrap; }

/* 폰에서는 **보기 토글의 글자를 감추고 아이콘만** 남긴다.
   '일정·시간표·월' 여섯 글자가 빠지면 년월·오늘과 한 줄에 들어간다 —
   월 라벨을 윗줄로 올리던 이전 방식보다 줄을 덜 쓴다(폰에서 세로가 제일 아깝다).
   버튼 여백은 건드리지 않아 PC 와 크기가 같다. 뜻은 title/aria-label 이 지킨다. */
@media (max-width: 575.98px) {
  .newcal .cal-mode-label { display: none; }
}

/* 그래도 안 들어가는 아주 좁은 폰에서는 줄을 나눈다 — 가로로 삐져나가는 것보다 낫다.
   한 줄에 들어갈 때의 모양(justify-content-between)은 그대로다. */
.newcal .card-header > .d-flex { flex-wrap: wrap; }

/* 떠 있는 [+] 등록 버튼(폰 전용) — 상단 제어 줄을 하나 없애려고 화면 밖으로 뺐다.
   오른쪽 아래 고정이라 스크롤해도 따라오고 엄지가 닿는다.
   safe-area-inset — 홈 인디케이터가 있는 아이폰에서 버튼이 가리지 않도록. */
.cal-fab {
  position: fixed;
  right: 1rem;
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  z-index: 1030;              /* 오프캔버스 패널(1045)보다는 아래 — 패널을 가리지 않는다 */
}
.cal-fab > .btn {
  width: 3.25rem;             /* 폰에서 누르기 편한 최소 크기(48px 권장) 이상 */
  height: 3.25rem;
  padding: 0;
  font-size: 1.1rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 스트립 한 줄 = [‹] 요일·날짜 그리드 [›] */
.cal-strip-row {
  display: flex;
  align-items: stretch;
}
.cal-cols { flex: 1 1 auto; min-width: 0; }
.cal-nav {
  flex: none;
  align-self: stretch;          /* 날짜 칸과 같은 높이 — 접히면 한 줄, 펼치면 그만큼 */
  width: 2.25rem;
  margin: 0.35rem 0;            /* 위아래 살짝 띄워 눌렀을 때 모양이 뜬다 */
  border: 0;
  border-radius: 0.5rem;
  background: transparent;
  color: var(--phoenix-tertiary-color);
  font-size: 0.85rem;
}
.cal-nav:hover { color: var(--phoenix-primary); background: var(--phoenix-secondary-bg); }

.cal-weekdays,
.cal-strip {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

/* 월 보기에서는 스트립을 접는다 — 바로 아래 월 그리드가 요일과 날짜를 다시 그리므로
   요일 줄이 두 번 나오고, 스트립이 먹는 높이만큼 마지막 주가 잘린다.
   남기는 것은 양옆 ‹ › 뿐 — 달을 넘기는 자리가 모드마다 바뀌지 않게(근육 기억). */
.newcal.is-month .cal-weekdays,
.newcal.is-month .cal-strip,
.newcal.is-month .cal-handle { display: none; }
.cal-weekdays {
  padding: 0.4rem 0.5rem 0;
  font-size: 0.85rem;
  text-align: center;
  color: var(--phoenix-tertiary-color);
}
.cal-strip {
  gap: 2px;
  padding: 0.25rem 0.5rem;
  touch-action: pan-y;          /* 좌우 스와이프는 우리가 처리, 세로는 브라우저에 */
}

.cal-day {
  border: 0;
  background: transparent;
  border-radius: 0.5rem;
  padding: 0.4rem 0;            /* 손가락으로 짚을 자리 */
  line-height: 1.15;
  color: var(--phoenix-body-color);
}
.cal-day-num { display: block; font-size: 1.1rem; }
.cal-dots {
  display: block;
  height: 0.7rem;
  font-size: 1rem;
  line-height: 0.7rem;
  color: var(--phoenix-primary);
}
.cal-day.is-other { color: var(--phoenix-quaternary-color); }
/* 공휴일은 색을 바꾸지 않는다 — 빨강=일요일, 파랑=토요일로 뜻을 하나만 둔다.
   공휴일은 일정 목록의 주황 배지·시간표의 주황 라벨로 알린다(정보 표시) */
.cal-day.is-today .cal-day-num { font-weight: 700; color: var(--phoenix-primary); }
.cal-day.is-cursor {
  background: var(--phoenix-primary);
  color: #fff;
}
.cal-day.is-cursor .cal-day-num,
.cal-day.is-cursor .cal-dots { color: #fff; }
.cal-day:hover:not(.is-cursor) { background: var(--phoenix-secondary-bg); }

/* 손잡이 — 내리면 월간이 펼쳐진다 */
.cal-handle {
  display: block;
  width: 100%;
  border: 0;
  background: transparent;
  padding: 0.35rem 0 0.5rem;
}
.cal-handle-bar {
  display: block;
  width: 2.5rem;
  height: 4px;
  margin: 0 auto;
  border-radius: 2px;
  background: var(--phoenix-border-color);
}
.cal-handle:hover .cal-handle-bar { background: var(--phoenix-primary); }

/* ── 일정(목록) ── */
/* 하루 = 한 덩어리. 예약이 없으면 날짜 아래가 빈 공간으로 남는다(팀즈 방식).
   최소 높이는 JS 가 넣는다 — 폰은 한 화면에 7일, 넓은 화면은 48px.
   **배경은 시간표(FullCalendar)와 똑같이** 칠한다 — 두 모드를 오갈 때 색이
   달라지면 같은 날인지 헷갈린다. 평일은 격자 바탕(`--phoenix-secondary-bg`
   = 풀캘린더 .fc-timegrid-body 와 같은 값), 그 위에 일/토 tint 를 얹는다. */
.cal-day-block {
  min-height: var(--cal-day-min, 3rem);
  border-top: 1px solid var(--phoenix-border-color-translucent);
  /* 하루의 **몸통은 흰 바탕** — 예약이 있든 없든 같은 면이라 줄이 들쭉날쭉하지 않다.
     요일 색(평일 회색 / 토 파랑 / 일·공휴일 빨강)은 위 날짜 줄이 맡는다. */
  background-color: var(--phoenix-emphasis-bg);
}
.cal-day-head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  min-height: 2.6rem;
  padding: 0.4rem 0.85rem;
  font-size: 1.05rem;
  /* 날짜 줄은 하루 칸과 **같은 색**이어야 하루가 한 덩어리로 보인다.
     다만 sticky 라 불투명해야 한다(아래 내용이 비쳐 지나가면 못 읽는다). */
  background-color: var(--phoenix-secondary-bg);
}
.cal-day-head.is-sun {
  background-image: linear-gradient(
    rgba(230, 55, 87, 0.06), rgba(230, 55, 87, 0.06));
}
.cal-day-head.is-sat {
  background-image: linear-gradient(
    rgba(44, 123, 229, 0.06), rgba(44, 123, 229, 0.06));
}
.cal-day-head.is-today { background-color: var(--phoenix-primary-bg-subtle); }
/* 주말·공휴일 — 스트립, 시간표 머리줄과 같은 색 규칙(일·공휴일 빨강 / 토 파랑).
   요일 글자는 text-body-tertiary 가 붙어 있어 클래스 3개로 이겨 낸다 */
.cal-day-head.is-sun .cal-date,
.cal-day-head.is-sun .cal-wd { color: var(--phoenix-danger); }
.cal-day-head.is-sat .cal-date,
.cal-day-head.is-sat .cal-wd { color: var(--phoenix-primary); }
.cal-item {
  display: flex;
  align-items: center;
  width: 100%;
  border: 0;
  /* 예약 줄은 **흰 바탕**으로 띄운다 — 회색 하루 칸 위에 얹힌 카드처럼 보여
     '이 날에 무엇이 있다'가 바로 눈에 들어온다(시간표의 예약 블록과 같은 역할).
     색은 테마 변수라 다크모드에서는 어두운 면으로 자동 전환된다. */
  background: var(--phoenix-emphasis-bg);
  color: var(--phoenix-emphasis-color);
  text-align: left;
  padding: 0.7rem 0.85rem;
  font-size: 1rem;
}
.cal-item + .cal-item { border-top: 1px solid var(--phoenix-border-color-translucent); }
.cal-item:hover { background: var(--phoenix-body-highlight-bg); }
/* 달력 아이콘은 **날짜 줄에 하나**만 둔다 — 예약 줄마다 붙이면 몇 건만 있어도
   화면이 복잡해진다(그렇게 해 보고 걷어냈다). 날짜 글자(요일 색)와 다투지 않게
   흐린 색으로. */
.cal-day-icon {
  margin-right: 0.45rem;
  color: var(--phoenix-tertiary-color);
  font-size: 0.9rem;
}
.cal-item-time {
  width: 4.75rem;
  flex: none;
  font-size: 0.95rem;
  /* 검정(본문색) — 파랑은 토요일 날짜 색과 같아서 시각인지 날짜인지 헷갈렸다 */
  color: var(--phoenix-emphasis-color);
  font-weight: 600;
}
.cal-item-body { min-width: 0; flex: 1 1 auto; }

/* 예약 한 줄은 **두 줄짜리**다 — 예약 목록 화면과 같은 정보를 담는다.
   윗줄: 이름·전화·배지 / 아랫줄: 관리명 · 남은 회차(잔액) · 소요시간 */
.cal-item-avatar {
  flex: none;
  width: 2rem;
  height: 2rem;
  margin-right: 0.6rem;
  object-fit: cover;              /* 세로 사진이 찌그러지지 않게 */
}
.cal-item-top {
  display: flex;
  align-items: center;
  flex-wrap: wrap;                /* 배지가 많아도 이름을 밀어내지 않고 아래로 */
  gap: 0.35rem;
  line-height: 1.3;
}
.cal-item-sub {
  display: block;
  margin-top: 0.15rem;
  /* 관리명이 길어도 줄을 늘리지 않는다 — 하루 칸 높이가 들쭉날쭉해지면
     스크롤할 때 커서(맨 위 날짜)가 튄다. 전체는 눌러서 패널에서 본다 */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 전화번호는 **동명이인을 가리는 표시**다 — 좁은 화면에서는 자리를 많이 먹으니
   숨긴다(누르면 패널에 전체가 나온다) */
@media (max-width: 575.98px) {
  .cal-item-phone { display: none; }
}

/* ── 넓은 화면: 촘촘하게(달력 전체가 한눈에) ── */
@media (min-width: 1200px) {
  .newcal .fc {
    --fc-small-font-size: 0.75rem;
    font-size: 0.8rem;
  }
  .newcal .fc .fc-timegrid-slot { height: 1.35rem; }   /* 기본 1.5rem → 촘촘 */
  .newcal .fc .fc-col-header-cell-cushion {
    padding: 0.55rem 0.25rem;
    font-size: 1rem;
    font-weight: 600;
  }
  .cal-weekdays { font-size: 0.85rem; }
  .cal-day-num { font-size: 1.25rem; }
  .cal-day { padding: 0.5rem 0; }
}

/* 본문만 스크롤 — 월 라벨·스트립은 늘 보이게 고정한다.
   **높이는 JS 가 화면을 재서 넣는다**(모니터마다 다르므로 calc 어림값을 쓰지 않는다).
   여기서는 최소 높이만 잡아 JS 가 늦게 붙어도 화면이 무너지지 않게 한다. */
.cal-scroll {
  position: relative;           /* 안쪽 offsetTop 기준 */
  overflow-y: auto;
  overflow-x: hidden;           /* 가로로 늘린 '지금 시각' 선을 카드 끝에서 자른다 */
  min-height: 15rem;
}

/* 아래 모서리 손잡이 — 끌어서 달력 높이 조절(두 번 누르면 화면에 맞춤) */
.cal-resize {
  height: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: ns-resize;
  border-top: 1px solid var(--phoenix-border-color-translucent);
  touch-action: none;           /* 끌 때 페이지가 같이 움직이지 않게 */
}
.cal-resize > span {
  width: 2.5rem;
  height: 4px;
  border-radius: 2px;
  background: var(--phoenix-border-color);
}
.cal-resize:hover > span,
.cal-resize.is-dragging > span { background: var(--phoenix-primary); }

/* 고른 보기만 글자를 파랗게 — 어느 보기에 있는지가 한눈에 읽혀야 한다.
   버튼을 btn-phoenix-secondary(검정 글자)로 바꾸고 나니 선택 표시가 배경 한 톤
   차이(#f5f7fa → #e3e6ed)뿐이라 약했다. 글자·아이콘만 primary 로 올린다 —
   배경은 테마가 주는 그대로 두고 색 하나만 얹는 것.
   아이콘은 fill="currentColor" 라 color 만 바꾸면 같이 따라온다.

   hover 도 예외로 두지 않는다 — 테마의 hover 배경(#e3e6ed)이 활성 배경과 같아
   어차피 배경으로는 아무 변화가 없는데, 파란색만 빠지면 마우스를 올렸을 때
   선택이 풀린 것처럼 보인다. !important 없이 이기도록 클래스 넷으로 받는다. */
.newcal .card-header .btn.active,
.newcal .card-header .btn.active:hover,
.newcal .card-header .btn.active .cal-mode-label {
  color: var(--phoenix-primary);
}

/* 시간표의 요일 머리줄(8. 9. (일)) — 어느 요일을 보는지가 먼저 읽혀야 한다.
   폰(하루 보기)에도 같은 규칙, 넓은 화면은 아래 미디어쿼리에서 한 단계 더 크게.

   nowrap — 한국어 라벨 '8. 20. (목)'은 공백이 들어 있어 칸이 조금만 좁아도
   '8. 20.' / '(목)' 로 갈라져 머리줄만 두 줄이 된다. 글자(70px)보다 칸(88px)이
   넓은데도 갈라지는 건 FullCalendar 가 남는 픽셀을 칼럼마다 다르게 나눠 주기
   때문이라 폭을 넉넉히 잡는 것으로는 못 막는다. 월 보기 날짜('26일')에 건 것과
   같은 처방이다(위 .fc-daygrid-day-number 참고) */
.newcal .fc .fc-col-header-cell-cushion {
  padding: 0.4rem 0.25rem;
  font-size: 0.9rem;
  font-weight: 600;
  white-space: nowrap;
}

/* 지금 시각 선 — 시간표에서 '어디까지 왔나'가 한눈에 보이게 굵고 붉게.
   FullCalendar 기본선은 **오늘 칸 안에만** 그어지고 얇아서 눈에 안 띈다.
   좌우로 크게 늘려 그리드 전체를 가로지르게 하고(넘치는 부분은 .cal-scroll 이 자른다),
   폰(하루 보기)에서도 그대로 한 줄이 된다. */
/* 칸 안쪽으로 잘라 내는 상자를 풀어 줘야 선이 칸 밖으로 나간다 */
.newcal .fc .fc-timegrid-now-indicator-container { overflow: visible; }
.newcal .fc .fc-timegrid-now-indicator-line {
  border-color: var(--phoenix-danger);
  border-top-width: 2px;
  left: -100vw;
  right: -100vw;
  z-index: 4;                   /* 예약 블록 위로 */
}
/* 왼쪽 축의 화살촉은 숨긴다 — 선이 이미 축까지 가로지르므로 겹쳐 보인다.
   현재 시각 숫자도 넣어 봤지만 뺐다: 축의 '오전 1시' 같은 정각 라벨과 겹친다. */
.newcal .fc .fc-timegrid-now-indicator-arrow { display: none; }

/* 사이드 패널(고정) — 스크롤해도 옆에 붙어 있다 */
.cal-side {
  position: sticky;
  top: 5rem;
}

/* 좁은 화면의 오프캔버스 — 기본 400px 는 폰에서 화면 밖으로 넘친다 */
#cal-panel { width: min(22rem, 88vw); }


/* 장부 머리줄 — 글자는 본문 크기, 높이로 띠를 세운다(합계 줄과 짝).
   테마의 .table-sm 패딩 규칙이 더 구체적이라 셀렉터를 그만큼 세운다 */
.table > .ledger-head > tr > th {
  padding-top: 1.1rem;
  padding-bottom: 1.1rem;
}

/* 카드 정산 — 저장 직후 갈아끼운 행(htmx)에 초록 깜빡임. 저장됐음을 눈으로 알린다 */
@keyframes settle-flash {
  from { background-color: var(--phoenix-success-bg-subtle); }
  to   { background-color: transparent; }
}
.settle-flash { animation: settle-flash 1.5s ease-out; }

/* 캘린더 사이드 패널 — 인라인 예약 등록이 열리면 바깥 카드 껍데기를 벗긴다.
   폼 조각 안에 고객·예약 정보 **카드가 또** 들어 있어 그대로 두면 이중 액자가 된다 —
   등록 중에는 그 두 카드만 세로로 놓이게 배경·테두리·머리글을 걷는다. */
.cal-side.is-booking {
  background: transparent;
  border: 0;
  box-shadow: none;
}
.cal-side.is-booking > .card-header { display: none; }
.cal-side.is-booking > .card-body { padding: 0; }

/* 휴무/개인 일정 — 고객 예약(파스텔 순환색)과 달력에서 한눈에 갈리게 **회색 빗금**.
   색만 다르게 두면 파스텔 사이에서 묻힌다 — '예약을 받지 않는 시간'이라는 뜻을
   무늬로 읽히게 한다. 색은 테마 변수라 다크 모드도 따라온다(캘린더 공용). */
.fc .event-timeoff {
  background-image: repeating-linear-gradient(
    -45deg,
    transparent 0 9px,
    var(--phoenix-border-color) 9px 11px);
}

/* 캘린더 사이드 패널 — 내용이 길어도(인라인 구매 등록 등) 페이지를 늘리지 않는다.
   페이지가 스크롤되면 왼쪽 캘린더(화면을 재서 높이를 잡는다)가 밀려 잘린다 —
   패널 안에서만 스크롤한다. 최대 높이는 캘린더처럼 JS(fitHeight)가 잰다. */
.cal-side { overflow-y: auto; }

/* 미수금 — 회수 이력 행은 옅은 바탕으로 대표(구매) 행과 가른다.
   부트스트랩 표는 셀 배경이 표 변수로 깔려서 tr 배경이 안 비친다 — td 에 직접 준다. */
.unpaid-history > td {
  background-color: var(--phoenix-body-highlight-bg);
}

/* ═══ 동의서 서명 — templates/shop/agreement_*.html ═══════════════════════
   **고객 손의 패드에서 열리는 화면**이라 일반 화면과 규칙이 다르다:
   글자를 크게(읽는 문서다) · 누를 것을 크게(손가락이다) · 갈 곳을 주지 않는다.
   설계: doc/design-agreement.md §4·§4-b */
.ag-page {
  max-width: 46rem;          /* 읽기 좋은 폭 — 패드 가로에서도 한 줄이 안 길어진다 */
  margin: 0 auto;
  padding: 1.25rem 1rem 3rem;
}
.ag-head { margin-bottom: 1rem; }
.ag-title { font-size: 1.35rem; font-weight: 700; margin: 0; }
.ag-meta { font-size: 0.85rem; color: var(--phoenix-body-secondary-color); }
.ag-sub {
  font-size: 0.95rem;
  font-weight: 700;
  margin: 0 0 0.5rem;
}
/* 두 번째 이후 제목(대개 '선택')은 앞 그룹과 떨어뜨린다 — 붙어 있으면 필수 줄이
   어디서 끝났는지 안 보여서, 선택 항목까지 켜야 하는 줄 알고 누른다.
   **여기서 정한다** — 위 `margin` 이 단축 속성이라 마크업에 `mt-2` 를 달아도
   특정도가 같아 나중에 로드되는 이 파일이 이긴다(조용히 안 먹는다). */
.ag-items .ag-sub:not(:first-child) { margin-top: 1.6rem; }
.ag-note {
  font-size: 0.8rem;
  color: var(--phoenix-body-tertiary-color);
  margin-top: 0.5rem;
}

/* 본문 — 종이 문서. 스크롤해서 읽는다. 높이를 묶어 두는 이유는 아래 동의 항목과
   서명이 화면 밖으로 밀리지 않게 하기 위함이다(패드 세로에서 특히) */
.ag-doc {
  max-height: 22rem;
  overflow-y: auto;
  padding: 1rem 1.1rem;
  border: 1px solid var(--phoenix-border-color);
  border-radius: 0.5rem;
  background: var(--phoenix-body-bg);
  font-size: 0.92rem;
  line-height: 1.7;
}
.ag-doc h3 { font-size: 1.05rem; font-weight: 700; margin: 1.2rem 0 0.5rem; }
.ag-doc h3:first-child { margin-top: 0; }
.ag-doc blockquote {
  margin: 0.75rem 0;
  padding: 0.6rem 0.9rem;
  border-left: 3px solid var(--phoenix-warning);
  background: var(--phoenix-warning-bg-subtle);
}

/* 발급 모달의 QR — 패드 카메라로 찍는다. 흰 바탕은 다크모드에서도 읽히게
   하려는 것이고(카메라는 명암 대비로 읽는다), 폭을 묶는 이유는 SVG 가
   scalable 이라 상자만큼 커지기 때문이다 */
.ag-qr { width: 12.5rem; max-width: 100%; }
.ag-qr svg { display: block; width: 100%; height: auto; }

/* 체결본 모달의 문안 전문 — 같은 글을 그리지만 '읽으라고 건네는 문서'가
   아니라 '확인하러 펼쳐 보는 기록'이라 테두리 없이 접힘 안에 눕는다 */
.ag-snapshot { line-height: 1.7; }
.ag-snapshot h3 { font-size: 0.95rem; font-weight: 700; margin: 1rem 0 0.4rem; }
.ag-snapshot h3:first-child { margin-top: 0; }
.ag-snapshot blockquote {
  margin: 0.6rem 0;
  padding: 0.5rem 0.75rem;
  border-left: 3px solid var(--phoenix-warning);
  background: var(--phoenix-warning-bg-subtle);
}

/* 동의 항목 — 손가락으로 누르는 줄이라 넉넉하게 */
.ag-items { margin-top: 1.25rem; }
.ag-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.7rem 0.2rem;
  border-bottom: 1px solid var(--phoenix-border-color-translucent, var(--phoenix-border-color));
  font-size: 0.92rem;
}
.ag-item input[type="checkbox"],
.ag-item input[type="radio"] { flex: none; margin: 0; }
.ag-required { cursor: pointer; font-weight: 600; }
.ag-item-label { flex: 1 1 auto; }
/* 동의/비동의는 **명시적으로 고른다** — 체크박스면 무응답과 비동의가 안 갈린다 */
.ag-choice { display: flex; gap: 0.9rem; flex: none; }
.ag-choice label {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  cursor: pointer;
  white-space: nowrap;
}

/* 서명란 — 캔버스. touch-action:none 이 없으면 그리는 동안 화면이 스크롤된다 */
.ag-sign { margin-top: 1.5rem; }
.ag-canvas {
  display: block;
  width: 100%;
  height: 11rem;
  border: 1px dashed var(--phoenix-border-color);
  border-radius: 0.5rem;
  background: #fff;          /* 서명은 흰 종이 위에 — 다크모드에서도 그대로 */
  touch-action: none;
  cursor: crosshair;
}

#ag-submit { margin-top: 1.5rem; }

/* 완료 화면 */
.ag-done { text-align: center; padding-top: 2rem; }
/* 완료 표시 — 이 셸은 FontAwesome 을 싣지 않아 인라인 SVG 로 그린다.
   width/height 를 주는 이유가 그것이다(폰트 아이콘이면 font-size 로 됐다).
   색은 currentColor 가 받아 간다 */
.ag-done-icon {
  width: 3rem;
  height: 3rem;
  color: var(--phoenix-success);
}
.ag-done-items {
  margin: 1.5rem 0;
  text-align: left;
  font-size: 0.9rem;
}
.ag-done-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 0.2rem;
  border-bottom: 1px solid var(--phoenix-border-color);
}
/* 창 닫기 + 남은 시간 — 항목 목록에서 떨어뜨린다. 고객이 마지막에 보는 자리라
   버튼을 손가락 크기로 두되(패드), 완료 안내보다 튀지 않게 secondary 로 둔다 */
.ag-done-close { margin-top: 2rem; }
.ag-done-close .btn { min-width: 10rem; padding-block: 0.6rem; }
.ag-done-close .ag-note { margin-top: 0.6rem; }

/* 날짜 칸(flatpickr) — 네이티브 date 칸처럼 오른쪽에 달력 아이콘.
   flatpickr 전환으로 type=text 가 되며 브라우저 아이콘이 사라져 배경으로 되살린다.
   아이콘 자리를 눌러도 input 클릭이라 flatpickr 달력이 열린다. */
input.shopdatepickr {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512' fill='%23525b75'%3E%3Cpath d='M152 24c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40L64 64C28.7 64 0 92.7 0 128l0 16 0 48L0 448c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-256 0-48 0-16c0-35.3-28.7-64-64-64l-40 0 0-40c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40L152 64l0-40zM48 192l352 0 0 256c0 8.8-7.2 16-16 16L64 464c-8.8 0-16-7.2-16-16l0-256z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 0.85em 0.85em;
  padding-right: 2.3rem;
}
[data-bs-theme=dark] input.shopdatepickr {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512' fill='%239fa6bc'%3E%3Cpath d='M152 24c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40L64 64C28.7 64 0 92.7 0 128l0 16 0 48L0 448c0 35.3 28.7 64 64 64l320 0c35.3 0 64-28.7 64-64l0-256 0-48 0-16c0-35.3-28.7-64-64-64l-40 0 0-40c0-13.3-10.7-24-24-24s-24 10.7-24 24l0 40L152 64l0-40zM48 192l352 0 0 256c0 8.8-7.2 16-16 16L64 464c-8.8 0-16-7.2-16-16l0-256z'/%3E%3C/svg%3E");
}
/* 폰에서 flatpickr 가 만드는 네이티브 입력(OS 선택기)은 그대로 — 아이콘 안 겹치게 */
input.shopdatepickr.flatpickr-mobile { background-image: none; padding-right: 0.75rem; }

/* 고객 아바타의 성별 테두리 — 여=분홍 · 남=파랑 · 미지정=없음
   (원장 지시 2026-08-28. 사정과 마크업은 base/customer_avatar.html)

   `border` 가 아니라 `box-shadow` 로 두른다 — border 는 이미지 상자를 그만큼
   키워 옆 글자와의 간격이 아바타마다 달라진다. box-shadow 는 자리를 안 먹는다.

   두께 1px — 2px → 1.5px → 1px 로 두 번 줄였다(원장 지시 2026-08-28). 성별은
   **거들 뿐**이라 선이 굵으면 이름·별점보다 먼저 눈에 든다. 상세(avatar-3xl
   이상)는 아바타가 커서 같은 두께면 되레 흐려 보이므로 1.5px.

   색은 **변수 두 개로 모아 둔다** — 다크 모드에서 갈아 끼워야 하기 때문이다.
   테마의 `--phoenix-pink`(#d63384)는 어두운 자홍이라 **다크 배경 + 사진 아바타**
   위에서 사진에 묻힌다(원장 지적 2026-08-28, 김민정 아바타). 다크에서는 한 단계
   밝은 분홍으로 바꾼다. 파랑(#3874ff)은 양쪽에서 잘 갈려 그대로 둔다.
   짙은 남색을 안 쓰는 이유도 같다 — 다크 배경에 묻힌다. */
:root {
  --theshop-gender-female: var(--phoenix-pink);
  --theshop-gender-male: var(--phoenix-blue);
}
[data-bs-theme=dark] {
  --theshop-gender-female: #ff7ab2;
}

/* 두 가지 마크업을 다 받는다 — 공용 조각은 `.avatar > img` 꼴이지만, JS 가
   그리는 아바타(캘린더 일정 줄·고객 카드)는 **img 자체**에 클래스를 붙인다. */
.avatar-gender-female > img,
img.avatar-gender-female { box-shadow: 0 0 0 1px var(--theshop-gender-female); }
.avatar-gender-male > img,
img.avatar-gender-male { box-shadow: 0 0 0 1px var(--theshop-gender-male); }

.avatar-3xl.avatar-gender-female > img,
.avatar-4xl.avatar-gender-female > img { box-shadow: 0 0 0 1.5px var(--theshop-gender-female); }
.avatar-3xl.avatar-gender-male > img,
.avatar-4xl.avatar-gender-male > img   { box-shadow: 0 0 0 1.5px var(--theshop-gender-male); }

/* 홈 '오늘 예약' — 예약이 많아도 이 칸만 길어지지 않게 안에서 스크롤.
   한 줄에 함께 선 옆 카드가 h-100 이라 여기가 늘면 옆이 통째로 따라 늘어났다
   (원장 지적 2026-08-28). 스크롤바 모양은 테마의 `.scrollbar` 가 준다.

   **넓은 화면에서만 높이를 잡는다** — 테마의 `.to-do-list-body` 와 같은 기준
   (min-width:1200px). 폰은 카드가 세로로 쌓여 옆이 없으므로 길어져도 되고,
   좁은 칸에 또 스크롤을 만들면 페이지 스크롤과 겹쳐 손이 걸린다. */
@media (min-width: 1200px) {
  /* 한 줄이 약 3.2rem — 넷쯤 보이는 높이로 잡는다(원장 지시 2026-08-28).
     옆 카드(오늘 매출·매출·신규 고객)의 원래 높이와 맞아 줄이 가지런하다. */
  .today-appt-list, .today-list { max-height: 13rem; }   /* 홈 첫 줄 오늘 목록 셋(예약·관리·구매) */
}

/* 고객 수 차트의 '활성 기준' 슬라이더 — 손잡이를 활성선·활성 고객수 카드와 같은
   주황(warning)으로. 부트스트랩 form-range 는 손잡이 색을 변수로 안 열어 두어
   엔진별 가상요소에 직접 준다(원장 지시 2026-08-29) */
.growth-active-range::-webkit-slider-thumb { background-color: var(--phoenix-warning); }
.growth-active-range::-moz-range-thumb { background-color: var(--phoenix-warning); }
.growth-active-range:focus::-webkit-slider-thumb {
  box-shadow: 0 0 0 1px var(--phoenix-body-bg), 0 0 0 .25rem rgba(var(--phoenix-warning-rgb), .25);
}
.growth-active-range:focus::-moz-range-thumb {
  box-shadow: 0 0 0 1px var(--phoenix-body-bg), 0 0 0 .25rem rgba(var(--phoenix-warning-rgb), .25);
}

/* 홈 오늘 목록의 설명(관리 내용·구매 품목·예약 설명) — 폰에서는 이름 옆에 잘리지 않게
   **아랫줄로 내린다**(원장 09-05). sm 이상은 이름 뒤 오른쪽 정렬 그대로 */
@media (max-width: 575.98px) {
  .today-desc { flex-basis: 100%; text-align: left !important; }
}

/* 고객 상세 요약 '마지막 방문' — 값이 길어(날짜 + 경과) 폰에서 라벨이 갈라졌다(원장 09-10).
   폰에서는 날짜·경과를 두 줄로 세우되 글자를 줄이고 줄 간격을 좁혀 **다른 줄(아이콘 1.75rem)과
   같은 높이** 안에 넣는다. sm 이상은 한 줄 그대로 */
@media (max-width: 575.98px) {
  .last-visit-value { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.1; }
  .last-visit-value .fw-bold { font-size: .8rem; }
  .last-visit-value .fs-9 { font-size: .64rem !important; }
}


/* 감사 로그 상세 — 긴 글의 바뀐 구간(diff). 칸 바탕(bg-*-subtle)보다 한 단계 진하게 */
.audit-diff mark.diff-del { background: var(--phoenix-danger-bg-subtle); color: var(--phoenix-danger-text-emphasis); text-decoration: line-through; padding: 0; filter: saturate(1.6); }
.audit-diff mark.diff-add { background: var(--phoenix-success-bg-subtle); color: var(--phoenix-success-text-emphasis); padding: 0; filter: saturate(1.6); }
.audit-diff td .v { white-space: pre-wrap; word-break: break-word; }

/* showcase 메뉴판 — 상단 띠(combo-nav)·필터 열(products-filter)·격자(grid-with-title)·슬라이더(gallery-slider) 전부 테마
   마크업·클래스 그대로라 여기엔 규칙이 거의 없다(원장 09-15: 다른 CSS 없이). 남은 것은 셸 틀과 슬라이드 크기뿐. */
.sc-page { max-width: none; margin: 0; padding: 0; }
/* 슬라이더 보기 장 크기 — 테마 gallery-slider 는 34.81rem(557px) 을 !important 로 못 박아 아이패드 미니 가로(744px)에서
   첫 줄의 썸네일이 50px 넘쳐 잘린다(원장 09-15: 이미지를 살짝 줄이자). 비율은 테마 그대로(활성 : 비활성 = 34.81 : 28.125,
   가로 폭 50rem) 에 0.89 를 곱한 값 — 제목·슬라이드·썸네일이 가로 화면 한 장에 들어온다. 유일한 예외 규칙 */
.sc-page .swiper-slider-gallery .theme-slider .swiper-wrapper { height: 31rem; }
.sc-page .swiper-slider-gallery .theme-slider .swiper-wrapper .swiper-slide { height: 25rem !important; }
.sc-page .swiper-slider-gallery .theme-slider .swiper-wrapper .swiper-slide.landscape { max-width: 44.5rem; }
.sc-page .swiper-slider-gallery .theme-slider .swiper-wrapper .swiper-slide-active { height: 31rem !important; }
/* 격자 보기 왼쪽 '메뉴' 열(테마 .phoenix-offcanvas-filter) — 테마는 lg 이상에서 top:1rem !important(상단바 없는 페이지 기준)라
   fixed 상단 띠(4rem) 밑으로 들어간다. top 은 첫 자리와 같은 6rem(.content 의 위 여백 = 띠 4rem + 2rem — 다르면 스크롤을 시작할 때
   열이 그 차이만큼 살짝 움직인다, 원장 09-16), 높이는 화면 끝 1rem 위까지. 테마 데모는 인라인 top 인데 !important 에 진다 */
@media (min-width: 992px) { .sc-page .phoenix-offcanvas-filter { top: 6rem !important; height: calc(100vh - 7rem); } }
/* 설정 › 패키지/제품 폼 — 지금 사진(사진 칸 위) */
.sc-form-thumb { width: 8rem; height: 8rem; object-fit: cover; border-radius: .75rem; border: 1px solid var(--phoenix-border-color); display: block; }
