/* Bulma 위에 얹는 최소한의 프로젝트 커스텀 스타일 */

/* 폼 검증 에러 표시 (public/js/form-validate.js) - 관리자 화면(admin/_style.php)과 동일한 규칙 */
.input.field-error, .textarea.field-error, select.field-error, .field-error { border-color: #d94141; }
.error-message { display: block; color: #d94141; font-size: 12px; margin: .25rem 0 0; min-height: 14px; }
.error-message:empty { display: none; }

html, body {
  height: 100%;
}

/* home-hero/home-band 풀블리드(전체 폭) 섹션이 100vw 계산 시 가로 스크롤을 만들지 않도록 */
html {
  overflow-x: hidden;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

main {
  flex: 1 0 auto;
}

/* 로그인/회원가입처럼 박스 하나짜리 작은 페이지가 화면 위쪽에 붙어 보이지 않도록
   세로 중앙보다 살짝 위에 오게 배치 (min-height 안에서만 정중앙 정렬하고,
   그 아래 여백을 더 둬서 시각적 중심을 위로 당김) */
.auth-page {
  min-height: 60vh;
  align-items: center;
  padding-bottom: 4rem;
}

/* 로그인/2단계 인증 전용 레이아웃(auth_layout.php) - 사이트 공통 상단메뉴/배너/푸터 없이 로고 +
   박스 하나만 화면 세로 중앙 근처에 둔다(2026-08-11). body는 이미 위에서 display:flex;
   flex-direction:column인데(사이트 공통), 세로 정렬은 justify-content가 아니라 .auth-bare-wrap의
   margin:auto(아래)로 한다 - justify-content:center는 내용이 뷰포트보다 길어지면 위아래 양쪽으로
   똑같이 넘쳐서, 위쪽으로 넘친 부분은 스크롤해도 아예 보이지 않고 잘려버리는 유명한 flexbox
   버그가 있다(2026-08-11, 사용자 피드백: "화면이 줄어들면... 위아래가 짤려"). margin:auto 방식은
   공간이 남을 때는 똑같이 중앙 정렬되지만, 내용이 넘치면 auto margin이 0으로 줄어들면서 자연스럽게
   맨 위에 붙고 그 아래로는 평범한 문서 흐름이 되어 스크롤로 전부 볼 수 있다. */
.auth-bare-page {
  align-items: center;
  /* 수학적으로 완전히 정중앙이면 오히려 살짝 아래로 쏠려 보인다는 피드백(2026-08-11) - 아래쪽
     패딩을 위쪽보다 크게 둬서(margin:auto가 이 패딩을 뺀 나머지 공간 안에서 중앙을 잡으므로)
     콘텐츠가 뷰포트 높이의 대략 10%만큼 위로 치우친 위치에 오게 한다. */
  padding: 2.5rem 1rem calc(2.5rem + 20vh);
  background: #f7f8fa;
}
.auth-bare-wrap { width: 100%; max-width: 440px; margin: auto 0; }
.auth-bare-logo {
  display: flex;
  justify-content: center;
  margin-bottom: 1.75rem;
}
.auth-bare-logo img { height: 2.5rem; width: auto; }
.auth-bare-logo strong { font-size: 1.4rem; font-weight: 800; color: #1b2333; }
.auth-bare-copyright { margin-top: 1.5rem; text-align: center; font-size: .75rem; color: #9aa1b1; }

/* (2026-08-11) 진짜 원인을 찾음 - global.css의 .box{height:100%}가 카드 그리드에서 여러 박스
   높이를 맞추려고 넣은 규칙인데, 여기서는 부모 .auth-bare-wrap의 계산된 높이에 맞춰 박스가
   내용보다 훨씬 크게 늘어나 버려서 마지막 요소(nav 줄) 아래에 100px 넘는 빈 공간이 생기고
   있었다(padding-bottom만 줄인 이전 시도는 원인이 아니라서 효과가 없었음 - 사용자 피드백:
   "이거 되었다고 하지만 되지 않았어"). height를 도로 auto로 풀어서 내용 높이만큼만 차지하게
   한다. 아래쪽 padding도 nav 줄과 겹쳐 보이지 않도록 함께 줄인다. */
.auth-bare-wrap .box { height: auto; padding-bottom: 3rem; }

/* 로그인/아이디찾기/비밀번호찾기/회원가입을 서로 오가는 링크 줄(member/auth/_nav.php) - 박스
   맨 아래, 카피라이트보다는 위에 온다. 지금 보고 있는 화면 자신의 링크는 빠지므로 보통 3개가
   남는데, 가운데로 몰리지 않고 좌/중/우로 퍼지게 한다(2026-08-11, 사용자 피드백: "어차피 3개니까
   좌 중 우 이렇게 해줘"). */
.auth-bare-nav {
  display: flex;
  justify-content: space-between;
  gap: 1.25rem;
  margin-top: .75rem;
  font-size: .8rem;
}

/* 회원가입처럼 내용이 길어서 중앙(위 .auth-bare-page 기본값)에 두면 어색한 화면은 짧든 길든
   항상 위에서부터 시작하게 한다(2026-08-11, "회원가입페이지는 정중앙말고 위에서부터 시작되게"
   요청) - auth_layout.php가 $topAligned를 넘기면 body에 이 클래스가 붙는다. margin:auto를
   0으로 되돌리면 위 .auth-bare-wrap의 중앙 정렬이 그냥 꺼지고 평범한 문서 흐름이 된다. */
.auth-bare-page.is-top-aligned {
  padding: 3rem 1rem 2.5rem;
}
.auth-bare-page.is-top-aligned .auth-bare-wrap { margin: 0; }

/* View::renderBare()/bare_layout.php 전용 - 로고/카피라이트 없이 콘텐츠 하나만 채운다. 아이프레임을
   담는 부모 창(phpdashapi 대화창 오버레이)의 흰 배경(.dash-mail-modal-body)과 같은 색을 써서
   아이프레임 경계가 안 보이게 한다(2026-08-26, "하나의 화면에 내용이 나왔으면" 요청).
   2026-08-27, "가운데 정렬 말고 위에서부터 위치하게 해달라(프로필사진은 위에서 200px 등 구체적
   수치 지정)" 요청으로 세로 가운데 정렬(align-items:center)을 뺐었는데, 위에서부터 고정 여백
   (200px)으로 배치하니 "다른 문제들이 발생"한다는 후속 피드백(2026-08-27 7차)으로 다시
   가운데 정렬로 되돌아왔다 - 다만 완전한 정중앙은 아니고, optical-center 관례(이 프로젝트의
   .auth-bare-page/.auth-bare-wrap와 같은 기법 - 모달/중앙 콘텐츠는 정중앙보다 살짝 위가
   시각적으로 더 안정적으로 보인다는 관례, 기본 오프셋 -4vh)를 그대로 적용했다. 세로 중앙 정렬은
   justify-content:center 대신 자식의 margin:auto(아래 .member-profile-box/.profile-appearance-form
   공통 규칙)로 한다 - justify-content:center는 콘텐츠가 뷰포트보다 커지면 위/아래로 똑같이
   넘쳐서 위쪽 초과분이 스크롤해도 안 보이는 flexbox 버그가 있는데, margin:auto는 공간이
   부족해지면 자동으로 0이 되어 자연히 맨 위부터 시작하는 문서 흐름으로 폴백된다(오프셋도
   함께 꺼짐 - "화면보다 크면 오프셋 끄고 위에서 시작" 관례 그대로).
   -4vh 오프셋 구현: margin:auto(위/아래 반반 분배)로 정확히 중앙에 두는 대신, 이 컨테이너의
   padding-bottom을 위쪽(0)보다 8vh 더 크게 둬서 분배 가능한 공간 자체를 위로 4vh만큼
   치우치게 만든다(무게중심 = (100vh - padding-bottom + padding-top) / 2 계산).
   2026-08-27 11차, "그 그룹을 위쪽으로 30px 정도 더 올라갔으면 좋겠다" 요청 - 무게중심 공식상
   위로 Npx 더 올리려면 padding-bottom을 2×Npx만큼 더 늘리면 된다(반씩 분배되므로) - 8vh에
   60px(30px의 2배)를 추가했다. body.bare-embed-page는 프로필 보기/편집 두 화면이 공유하는
   규칙이라 이 조정도 두 화면에 동일하게 적용된다. */
body.bare-embed-page {
  margin: 0;
  min-height: 100vh;
  padding-bottom: calc(8vh + 60px);
  /* 확대/축소 금지를 메타 viewport의 user-scalable=no 대신 여기서 담당한다(2026-08-28,
     bare_layout.php의 viewport 메타 수정 주석 참고) - pan-x/pan-y는 스크롤(패닝)은 그대로 두고
     핀치줌 제스처만 막는다. */
  touch-action: pan-x pan-y;
}
/* 2026-08-27, "배경이미지가 짤린다" 신고로 body 자신에게 주던 배경을 여기 별도 레이어로
   옮겼다(bare_layout.php 주석 참고) - position:fixed로 항상 현재 뷰포트 전체를 덮게 해서,
   body 높이가 콘텐츠/모바일 키보드에 따라 달라져도 사진이 중간에 끊기지 않는다.
   2026-08-27 후속, "배경이미지가 나와지지 않는다" 재신고 - z-index:-1인 이 레이어는 body보다
   먼저(뒤에) 그려지는데, 정작 body.bare-embed-page 자신이 non-positioned 요소라 "본문 콘텐츠와
   같은 층(negative z-index보다 위)"에서 자기 background:#fff를 칠하고 있어서 그 흰 배경이 이
   레이어를 완전히 덮어버리고 있었다 - 그래서 위 body.bare-embed-page의 background:#fff를
   지웠다(사진/테마색 둘 다 없는 기본 상태는 global.css의 html{background:#fff}가 캔버스 색으로
   그대로 대신 채워준다). */
.bare-embed-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
}

/* 회원 프로필 보기(읽기 전용, member/profile_view.php - MemberProfileController) - 2026-08-26,
   (케밥(⋮) 메뉴는 한때 여기 있었는데 "우측상단으로 자리 이동해줘" 요청으로 phpdashapi
   #dashCorrespondentModal 헤더로 옮겨갔다 - custom.css의 .dash-correspondent-modal-kebab* 참고.)
   참고 스크린샷(카카오톡류 프로필 화면)처럼 아바타 원 + 이름을 가운데 정렬로 보여준다. 실제
   프로필 사진이 없어 이니셜 원으로 대신하는데, phpdashapi 대화창의 발신자 아바타
   (.dash-thread-bubble-avatar)와 같은 톤(진회색 #1c1f24 배경 + 흰 글자)으로 맞춰서 "아바타를
   눌러 프로필로 넘어왔다"는 흐름이 시각적으로도 이어지게 했다. 흰 카드(.box)로 감싸지 않고
   bare-embed-page 배경 위에 그대로 떠 있다(2026-08-26, "카드가 아닌 걸로 해줘" 요청). */
/* 2026-08-27 7차, "정중앙에서 시작되게, 정중앙 기준으로 위쪽으로 약간 올라가게 - 프로필창과
   편집창 모두 같은 수치로" 요청으로 고정 200px 상단 여백을 없애고 위 body.bare-embed-page의
   optical-center 정렬에 맡겼다. 상단 padding은 다시 0으로, 좌우/하단 여백(2rem)만 유지. 세로
   중앙 정렬 자체(margin:auto)는 아래 .profile-appearance-form과 공유하는 규칙에서 함께
   준다 - "같은 수치로"를 두 화면이 정확히 같은 CSS 규칙을 타는 것으로 보장한다: 이 박스는
   profile_view.php에서는 body의 유일한 자식(=flex item)이라 이 margin:auto가 그대로
   중앙정렬로 작동하고, profile_appearance_edit.php에서는 .profile-appearance-form 안에 든
   보통 블록 자식이라 이 규칙 자체는 아무 효과가 없다(그 화면은 .profile-appearance-form 쪽의
   margin:auto가 대신 작동함) - 그래서 같은 선언을 겹쳐 써도 서로 간섭하지 않는다. */
/* position:relative(2026-08-27 8차) - 아래 .profile-appearance-cover-edit-row가
   position:absolute로 이 박스 바로 밑에 붙을 때 기준(containing block)이 된다. */
.member-profile-box { position: relative; text-align: center; padding: 0 2rem 2rem; }
.member-profile-avatar {
  width: 96px;
  height: 96px;
  margin: 0 auto 20px; /* 2026-08-27, 30px→20px로 재조정 */
  border-radius: 50%;
  background: #1c1f24;
  color: #fff;
  font-size: 2.4rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* 프로필사진이 있으면(2026-08-26, "프로필 편집") 이니셜 원 대신 사진을 채운다 - 글자/진회색
   배경은 필요 없어져서 지우고 사진만 원형으로 잘라 보여준다. */
.member-profile-avatar.has-image { background-color: transparent; background-size: cover; background-position: center; }
/* 2026-08-27, "닉네임 텍스트크기는 18px, 상태메시지와의 여백은 20px" 요청. line-height:1.5는
   2026-08-27 9차, "편집창의 .profile-appearance-name-input과 높이를 100% 일치시켜달라" 요청으로
   명시 추가(body의 line-height:1.5를 그냥 상속받던 것과 계산 결과는 같지만, 상속 경로에
   기대지 않고 양쪽에 똑같이 못박아 둔다). */
.member-profile-name { margin: 0 0 10px; font-size: 25px; font-weight: 700; line-height: 1.5; } /* 2026-08-27, 20px→10px로 재조정 */
/* 2026-08-27, "상태메시지 텍스트크기는 16px" 요청. line-height 명시는 위 .member-profile-name과 같은 이유. */
.member-profile-meta { margin: 0; color: #9aa0aa; font-size: 20px; line-height: 1.5; }
/* 배경사진 위에서도 항상 읽히도록 흰색 스트로크(2026-08-26, "사진 밝기 감지보다 텍스트 뒤에
   하얀색 스트로크를 주면 될 것 같다" 요청) - paint-order로 스트로크를 글자 채우기보다 뒤에
   그려서 두꺼워도 글자 모양이 뭉개지지 않는다. 배경사진/테마컬러가 없는 기존 흰 배경에서도
   스트로크가 그대로 있지만 배경이 이미 흰색이라 티가 안 난다(구분해서 처리할 필요 없음). */
.member-profile-name, .member-profile-meta {
  -webkit-text-stroke: 4px #fff;
  paint-order: stroke fill;
}

/* "최근 사진 줄"(2026-08-27, member/profile_view.php - MemberProfileController::recentPhotos()) -
   .member-profile-box 안 마지막 자식으로 두지만, 원래 쓰던 position:absolute; top:100%(그 박스
   바로 아래 붙는 방식)는 .member-profile-box 자체가 화면 세로 중앙정렬(margin:auto 0)이라
   화면 중간쯤에 뜨는 문제가 있었다("슬라이드메뉴가 아래 끝에 붙어 있어야해" 신고, 2026-08-27
   12차) - .profile-appearance-savebar(아래)와 같은 관례로 position:fixed; bottom으로 바꿔서
   프로필 박스 위치와 무관하게 항상 화면(뷰포트) 맨 아래에 붙게 했다. */
.profile-recent-photos {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 15px;
  padding-bottom: env(safe-area-inset-bottom, 0px);
  z-index: 60;
}
/* "최근 5개까지만, 스크롤 없이 나열"(2026-08-27 최종 정리) - 예전엔 photos 전부를 그리고 화면
   폭을 넘는 만큼 가로 스크롤/터치 드래그로 넘겨보는 방식이었는데, PWA(홈 화면에 추가한 독립 앱)
   로 열었을 때 cross-origin iframe 안 가로 스크롤이 iOS에서 깨지는 문제를 여러 차례 시도로도
   못 고쳐서 "우선은 저 부분 빼줘 ... 지금처럼 막 복잡하게 들어가면 나중에 문제가 되더라구
   지금 현재로는 최근 5개까지만 보여줘" 요청으로 스크롤 자체를 없앴다(profile_view.php가 최대
   5장만 그림) - flex-shrink로 화면이 좁아도 5장이 항상 한 줄 안에 다 들어오게 해서 스크롤이
   필요한 상황 자체가 생기지 않는다. "더 보기"가 필요해지면 이 가로 줄이 아니라 세로 스크롤
   목록(별도 화면/오버레이)으로 다시 설계할 예정 - 상세: profile_view.php 주석. */
.profile-recent-photos-grid {
  display: flex;
  justify-content: center;
}
.profile-recent-photo-thumb {
  flex: 0 1 92px;
  min-width: 0;
  aspect-ratio: 1;
  border: none;
  background-color: rgba(255, 255, 255, .15);
  background-size: cover;
  background-position: center;
  cursor: pointer;
  padding: 0;
}

/* "프로필 편집"(2026-08-26, member/profile_appearance_edit.php - ProfileAppearanceController) -
   프로필사진/배경사진 미리보기 + 크롭 오버레이.
   2026-08-26 3차, "프로필화면과 구성을 동일하게" 요청으로 이 화면도 profile_view.php와 완전히
   같은 마크업(.member-profile-box/-avatar/-name/-meta)을 그대로 재사용하게 바뀌었다 - 그래서
   이 화면 전용이었던 흰 카드형 필드 줄(.profile-appearance-row 등)은 지우고, 그 위에 얹는
   알약(pill) 버튼/고정 저장바만 새로 추가한다.
   2026-08-27, "센터 정렬은 그대로 두고 카메라 아이콘 버튼 하나 + 클릭 시 메뉴로" 요청 - 항상
   보이던 알약 버튼 4개(.profile-appearance-pill-*)를 걷어내고, 아바타 모서리 카메라 배지/
   "배경 편집" 버튼 + 공용 팝업 메뉴(.profile-appearance-photo-menu)로 교체했다.
   2026-08-27 후속, "클릭 영역을 사진까지 확대해달라" 요청 - .profile-appearance-avatar-wrap
   자체가 <button>이 되면서 원래 아바타(.member-profile-avatar)가 갖던 바깥 여백(margin: 0 auto
   .9rem, 위 .member-profile-avatar 규칙)을 wrap이 대신 맡는다(안쪽 아바타는 margin 0으로 상쇄).
   2026-08-27 3차, "프로필 화면과 사진 위치가 동일해야" 요청 - wrap을 96x96 고정폭
   display:block으로 명시해서(예전엔 inline-block + 부모 text-align:center로 간접 중앙정렬)
   .member-profile-avatar와 완전히 같은 박스 모델(크기/margin)로 딱 겹치게 했다 - <button>
   기본 스타일(브라우저마다 다른 line-height 등)에 흔들리지 않도록 크기를 직접 못박음. */
/* 2026-08-27 7차, "정중앙에서 시작되게(위쪽으로 약간), 프로필창과 편집창 모두 같은 수치로"
   요청 - body.bare-embed-page의 optical-center 정렬(margin:auto)이 실제로 작동하는 대상은
   이 <form> 자신이다(body의 유일한 자식 = flex item이므로).
   2026-08-27 8차, "두 화면에서 박스 위치가 다르다 - 저 박스 높이는 변하지 않으니 고정해서
   동일하게 만들어달라" 재신고로 원인을 찾음 - 처음엔 .profile-appearance-cover-edit-row(배경
   편집 버튼)도 이 form 안의 보통 흐름(normal flow) 요소라 form의 중앙정렬 높이 계산에 끼어
   있었는데, 그 버튼은 profile_view.php(프로필 보기)엔 아예 없는 요소라서 두 화면의 "중앙정렬
   대상 높이"가 서로 달라져(편집화면 쪽이 버튼 높이+여백만큼 더 큼) 정중앙 정렬 기준점 자체가
   어긋나 있었다 - 같은 -4vh 공식을 써도 대상 높이가 다르면 결과 위치가 달라지는 게 당연했다.
   그래서 .profile-appearance-cover-edit-row를 position:absolute로 흐름에서 완전히 빼고(아래
   규칙), 이 form의 중앙정렬 계산에 들어가는 실제 흐름 콘텐츠를 .member-profile-box 하나만
   남겼다 - 이제 이 form의 중앙정렬 높이가 profile_view.php의 .member-profile-box와 정확히
   같은 값이라, 아바타/이름/상태메시지 부분은 두 화면에서 항상 같은 위치에 나온다("배경 편집"
   버튼은 그 아래에 절대위치로 따라붙을 뿐 중앙정렬 계산과 무관).
   예전에 여기 있던 padding-bottom:96px(고정 저장바에 안 가리게 미리 비워두던 여백)는 위에서
   시작하던 배치에서나 필요했던 것 - 이제 카드가 화면 중앙 근처에 있으니 화면 맨 아래 저장바와는
   자연히 거리가 벌어져 더 이상 필요 없다. .member-profile-box와 같은 margin:auto 0 선언을
   그대로 공유해서 "같은 수치"임을 CSS 규칙 자체로 보장한다. */
.member-profile-box,
.profile-appearance-form {
  margin: auto 0;
}
/* 2026-08-27 10차, "그래도 편집창이 5px 정도 위로 올라간다" 실측 신고 - <input>/<textarea>에
   appearance:none을 줘도(9차) 남는 미세한 높이 차이를 이론으로 더 좇는 대신, 실제로 측정된
   차이만큼 이 화면에서만 시각적으로 5px 내려서 맞춘다. margin이 아니라 position:relative;top을
   쓴 이유 - margin-top을 더하면 위 margin:auto 0의 "중앙정렬 계산"에 그 값이 다시 끼어들어
   센터 자체가 또 틀어지지만(margin은 레이아웃에 영향), top은 자기 자리를 계산한 뒤 그림만
   옮기는 것이라 레이아웃/센터링 계산에는 전혀 영향을 주지 않는다. */
.profile-appearance-form {
  position: relative;
  top: 5px;
}
.profile-appearance-avatar-wrap {
  position: relative;
  display: block;
  width: 96px;
  height: 96px;
  margin: 0 auto 20px; /* 2026-08-27, .member-profile-avatar와 같은 값(30px→20px로 재조정) */
  border: none;
  background: none;
  padding: 0;
  cursor: pointer;
}
.profile-appearance-avatar-wrap .member-profile-avatar { margin: 0; }
.profile-appearance-camera-badge {
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid #fff;
  border-radius: 50%;
  background: rgba(20, 20, 24, .75);
  pointer-events: none; /* 클릭은 이제 wrap(버튼) 전체가 받는다 - 배지는 시각적 표시만 */
}
.profile-appearance-camera-badge img { width: 16px; height: 16px; }

/* position:absolute(2026-08-27 8차, "두 화면 박스 위치가 다르다" 수정) - .member-profile-box의
   흐름(normal flow)에서 완전히 빠져서 그 박스의 중앙정렬 높이 계산에 끼지 않는다(위
   .member-profile-box/.profile-appearance-form 규칙 주석 참고). top:100%가 박스의 padding까지
   포함한 바로 아래 지점이고, margin-top:1.4rem이 예전과 같은 간격을 그대로 재현한다. */
.profile-appearance-cover-edit-row {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  display: flex;
  justify-content: center;
  margin-top: 1.4rem;
}
/* 2026-08-27, "1.5배 정도 크게 - scale이 아니라 실제 수치로" 요청으로 한 차례 키웠다가(gap 10px,
   padding 13px 26px, font-size 20px, 아이콘 24px) "너무 크다"는 후속 피드백으로 font-size:18px,
   gap:8px로 다시 줄임 - padding/아이콘 크기는 그대로 유지. */
.profile-appearance-cover-edit-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 13px 26px;
  border: none;
  border-radius: 999px;
  background: rgba(20, 20, 24, .55);
  color: #fff;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
}
.profile-appearance-cover-edit-btn:hover { background: rgba(20, 20, 24, .7); }
.profile-appearance-cover-edit-btn img { width: 24px; height: 24px; }

/* 사진 편집 메뉴 - 카메라 배지/"배경 편집" 버튼 공용(JS가 클릭한 트리거 위치에 맞춰
   left/top을 직접 지정한다). backdrop은 바깥 클릭으로 닫기 위한 투명 전체화면 레이어. */
.profile-appearance-photo-menu-backdrop {
  position: fixed;
  inset: 0;
  z-index: 65;
  background: transparent;
}
.profile-appearance-photo-menu {
  position: fixed;
  z-index: 70;
  min-width: 180px;
  background: #fff;
  border-radius: 14px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, .28);
  overflow: hidden;
  padding: .3rem 0;
}
.profile-appearance-photo-menu-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  padding: .75rem 1.1rem;
  border: none;
  background: none;
  text-align: left;
  font-size: .95rem;
  color: #1c1f24;
  cursor: pointer;
}
.profile-appearance-photo-menu-item:hover { background: #f2f3f5; }
.profile-appearance-photo-menu-item.is-danger { color: #e53e3e; }
/* "[썸네일] 복구하기"(2026-08-27) - 비우기 직전 사진의 작은 미리보기. 원본 파일을 그대로 축소
   표시한다(별도 썸네일 생성 없이) - 프로필/배경 이미지는 이미 서버에서 512x512·1080x1920로
   리사이즈되어 있어 24px 아이콘 크기로 줄여 써도 무리가 없다. */
.profile-appearance-photo-menu-thumb {
  width: 24px;
  height: 24px;
  border-radius: 6px;
  object-fit: cover;
  flex: 0 0 auto;
}
/* 이름 입력칸 - 2026-08-27, "닉네임 부분을 수정할 수 있게 해달라" 요청으로 읽기전용 <h2>를
   <input>으로 바꿨다. 한때(3차) 프로필 화면과 완전히 같은 순수 텍스트 모양으로 뺐었는데,
   4차 "아까처럼 배경과 라인을 넣어서 영역을 나와지게 해달라" 요청으로 흰 테두리 박스를 다시
   넣었다 - "수정 가능한 칸"이라는 걸 보여주는 게 두 화면 완전 동일보다 우선한다는 판단.
   위치(아바타 중앙정렬 등)는 3차에서 맞춘 걸 그대로 유지한다. */
/* 2026-08-27 6차, "겹치는 현상이 있다 - 박스를 없애고 아래에 그림자 있는 라인을 넣어달라" 요청으로
   흰 테두리 박스(border 전체+배경 채움)를 걷어내고 밑줄(border-bottom)만 남겼다가, 흰 배경에서
   안 보인다는 후속 피드백으로 검정 선+그림자 2겹(box-shadow)을 <input>/<textarea> 자체에
   추가했었다.
   2026-08-27 7차, "input 자체에 라인을 주니 뒤 배경이 꾸물거려 보인다 - 입력칸 배경/라인은
   없애고 밑줄은 별도 요소로 추가해달라" 요청 - <input>/<textarea>는 브라우저마다 기본 UA
   렌더링(포커스 링, 자동완성 하이라이트 등)이 있어서 그 위에 border-bottom+box-shadow를
   얹으면 입력칸 자체의 렌더링과 겹쳐 뒤 배경사진이 미묘하게 뭉개져 보였다 - 입력칸은 완전히
   테두리/배경 없이 텍스트만 그리게 하고, 밑줄(흰 선+검정 선+그림자)은 입력칸 뒤에 오는 별도
   빈 <div>(.profile-appearance-input-underline, member/profile_appearance_edit.php 참고)로
   옮겼다. <input>/<textarea>는 ::before/::after 가상요소를 못 만들어서 별도 형제 요소로 뺄
   수밖에 없었다.
   겹침 버그의 원인도 이 김에 고쳤다: 5차의 margin-top 음수값은 "박스 위/아래 여백을
   프로필화면과 맞춘다"는 계산이었는데, 이름 박스의 margin-bottom(+3.7px)과 상태메시지 박스의
   margin-top(-9.5px)이 인접한 block 형제 요소라 서로 마진이 상쇄(collapse)되어 버려서
   (3.7 + (-9.5) = -5.8px) 두 박스가 실제로는 5.8px만큼 겹쳐 있었다. 지금은 입력칸 자신의
   margin을 없애고(밑줄 요소가 마진을 대신 짊어짐) 이런 혼동 자체가 없다.
   배경이 없어져 사진 위에 텍스트가 직접 얹히므로, 박스 안이라 껐던 흰색 텍스트 스트로크
   (-webkit-text-stroke:0 오버라이드)도 지워서 .member-profile-name/-meta 공용 규칙의 흰 스트로크가
   다시 적용되게 했다(프로필 화면과 동일한 가독성 처리로 복귀). */
/* 2026-08-27 9차, "프로필창/편집창 위치가 약간 틀어진다 - 100% 일치시켜달라" 재신고 - 지금까지
   맞춘 margin/padding/font-size가 전부 같아도, <input>은 브라우저 기본 "네이티브 폼 컨트롤"
   렌더링(appearance) 때문에 border/padding을 전부 0으로 없애도 내부적으로 여전히 약간의 자체
   여백을 갖고 있어서 순수 텍스트인 <h2>(.member-profile-name)보다 미세하게 높이가 더 나갈 수
   있다 - appearance:none으로 그 네이티브 스타일 자체를 꺼서 진짜 "글자만 있는 상자"로 만들고,
   line-height도 상속에만 기대지 않고 .member-profile-name과 똑같이 명시해서 두 요소의 높이
   계산 경로를 완전히 동일하게 맞췄다. */
.profile-appearance-name-input {
  display: block;
  width: 200px;
  max-width: 70%;
  box-sizing: border-box;
  margin: 0 auto;
  padding: 0 .7rem;
  border: none;
  background: none;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  text-align: center;
  font: inherit;
  font-size: 25px;
  font-weight: 700;
  line-height: 1.5;
  color: inherit;
}
.profile-appearance-name-input:focus { outline: none; }

/* 상태메시지 입력칸 - "하단 '프로필 저장하기' 버튼만큼 넓혀달라" 요청은 3차부터 그대로 유지 -
   .member-profile-box의 2rem 패딩과 .profile-appearance-savebar의 1.2rem 패딩 차이(.8rem)만큼
   좌우로 음수 마진을 줘서 그 버튼과 같은 폭(화면 가장자리에서 1.2rem)까지 넓힌다. 밑줄을 별도
   요소로 뺀 이유/겹침 버그 수정/흰 스트로크 복원은 위 이름 입력칸과 같음(2026-08-27 7차).
   appearance:none/line-height 명시(2026-08-27 9차)는 위 이름 입력칸과 같은 이유("100% 일치"
   요청 - <textarea>도 <input>과 같은 네이티브 폼 컨트롤 렌더링을 갖고 있다). */
.profile-appearance-status-input {
  display: block;
  width: calc(100% + 1.6rem);
  box-sizing: border-box;
  margin: 0 -.8rem;
  padding: 0 .9rem;
  border: none;
  background: none;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  resize: none;
  overflow: hidden;
  text-align: center;
  font: inherit;
  font-size: 20px;
  line-height: 1.5;
  color: inherit;
}
.profile-appearance-status-input:focus { outline: none; }
.profile-appearance-status-input::placeholder { color: #e4e6ea; -webkit-text-fill-color: #e4e6ea; }

/* 밑줄 전용 빈 <div> - 흰 선(border-bottom)+검정 선+그림자(box-shadow 2겹, 위 6차 설명과 같음)를
   입력칸이 아니라 여기서 그린다. 너비/좌우 마진은 각 입력칸과 정확히 같게(-name/-status 변형),
   margin-top은 입력칸 텍스트와의 작은 간격, margin-bottom은 원래 .member-profile-name/-meta가
   갖던 값을 그대로 이어받는다(name:10px, status:0). */
.profile-appearance-input-underline {
  height: 0;
  box-sizing: border-box;
  border-bottom: 1.5px solid rgba(255, 255, 255, .9);
  box-shadow: 0 3px 0 -1px rgba(0, 0, 0, .55), 0 4px 5px -3px rgba(0, 0, 0, .45);
}
.profile-appearance-name-underline {
  width: 200px;
  max-width: 70%;
  margin: 4px auto 10px;
}
.profile-appearance-status-underline {
  width: calc(100% + 1.6rem);
  margin: 4px -.8rem 0;
}
/* 하단 고정 "프로필 저장하기" 바(2026-08-26 3차 요청) - 스크롤 위치와 무관하게 항상 화면
   맨 아래 보인다. */
/* 2026-08-27, "저장바 배경 때문에 배경사진이 아래까지 안 깔린다 - 사진이 끝까지 깔리고 그 위에
   버튼만 떠 있게 해달라, 버튼 테두리는 흰색으로" 요청 - 예전엔 이 바 자체가 불투명(거의) 흰
   배경+블러라 배경사진을 가리고 있었다. 바 자신은 배경 없이 버튼 위치만 잡고, 버튼이 반투명
   어두운 배경+흰 테두리로 사진 위에서도 always 잘 읽히게 한다. */
.profile-appearance-savebar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 15px; /* 2026-08-27, 30px→15px로 절반 축소("하단까지 여백을 반절로 줄여달라" 요청, 그 전엔 기존 0에서 30px로 올렸었음) */
  z-index: 60;
  padding: .9rem 1.2rem calc(.9rem + env(safe-area-inset-bottom, 0px));
}
/* 2026-08-27, "반투명하게 하지 말고 그냥 일반 버튼처럼 해달라" 요청 - 배경사진 위에서도 잘
   보이도록 썼던 반투명 채움+흰 테두리(rgba 배경, 1.5px 흰 테두리)를 걷어내고 불투명한 단색
   버튼으로 바꿨다(global.css의 .button.is-link 기본 색 #363636과 같은 톤 - 이 프로젝트
   그레이스케일 색상 기준). */
/* 2026-08-27 6차, "버튼 높이를 지금의 130% 정도로" 요청 - 기본 .button은 padding:.5em 1em(8px
   위아래)+line-height 1.5×font-size 16px(24px 줄박스)=40px 높이라, 그 130%인 52px을
   min-height로 직접 못박았다(스케일 변형이 아니라 실제 수치로, 앞서 "배경 편집" 버튼 때와
   같은 방식) - 패딩은 그대로 두고 .button의 기존 align-items:center로 안의 글자가 계속
   세로 중앙에 오게 했다. */
.profile-appearance-savebar .button {
  font-weight: 700;
  background: #363636;
  color: #fff;
  border: none;
  min-height: 52px;
}
.profile-appearance-savebar .button:hover {
  background: #262626;
}
/* 2026-08-27, "수정할 내역이 있을 때만 저장 버튼이 활성화되게 해달라" 요청 - 비활성 상태를
   눈에 띄게 흐리게(global.css 발췌본에 .button[disabled] 규칙이 없어서 별도로 추가). */
.profile-appearance-savebar .button:disabled {
  opacity: .45;
  cursor: not-allowed;
}
.profile-appearance-savebar .button:disabled:hover {
  background: #363636; /* 비활성일 땐 hover로 진해지지 않게 */
}

/* 비활성 입력칸 배경(2026-09-03, "이메일 아이디 입력칸은 활성화되지 않기때문에 배경을
   비활성화 된것처럼 처리해줘" 요청) - 위 버튼과 같은 이유(global.css 발췌본에 .input[disabled]
   규칙이 없어서 비활성 input이 활성 input과 똑같은 흰 배경으로 보였음, member/account/edit.php의
   "이메일 (아이디)" 필드에서 실제로 발견) - Bulma 기본값과 같은 옅은 회색으로 구분한다. 페이지
   범위를 좁히지 않고 전역 .input[disabled]로 둔다 - 이 프로젝트에서 disabled input은 "정말
   수정 불가"인 경우에만 쓰이므로 다른 화면에서도 같은 처리가 맞다. */
.input[disabled] {
  background-color: #f5f5f5;
  border-color: #f5f5f5;
  color: #7a7a7a;
  cursor: not-allowed;
  box-shadow: none;
}

/* 크롭 오버레이 - 화면 전체를 덮는 어두운 배경 위에 캔버스+컨트롤을 가운데 배치. */
.profile-crop-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: rgba(20, 20, 30, .85);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
/* [hidden] 버그 수정(2026-08-26, "저장소에서 선택해도 아무것도 작동 안 한다" 신고로 발견) -
   위 규칙이 display:flex를 강제로 걸어서, 브라우저 기본 스타일시트의 [hidden]{display:none}
   (author 스타일이 항상 UA 스타일을 이김)을 눌러버렸다 - hidden 속성을 true로 세팅해도 이
   규칙 탓에 계속 화면 전체를 덮은 채로 보이고 있었다(.dash-gallery-modal-edit-btn이 이미
   겪었던 것과 완전히 같은 버그 패턴, dash-home.js 쪽 custom.css 참고). */
.profile-crop-overlay[hidden] { display: none; }
.profile-crop-box { display: flex; flex-direction: column; align-items: center; gap: 1rem; max-width: 100%; }
/* 캔버스 내부 해상도(width/height 속성)는 JS(image-cropper.js)가 목표 출력 크기 그대로
   세팅한다 - 여기 CSS는 화면에 "보이는" 크기만 줄인다(내부 해상도와 무관). */
.profile-crop-canvas {
  max-width: 100%;
  border-radius: 8px;
  touch-action: none;
  cursor: grab;
}
.profile-crop-canvas.is-square { width: 280px; height: 280px; }
.profile-crop-canvas.is-tall { width: 220px; height: auto; aspect-ratio: 1080 / 1920; max-height: 60vh; }
.profile-crop-controls { display: flex; gap: .6rem; }
.profile-crop-control-btn {
  width: 40px;
  height: 40px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, .15);
  color: #fff;
  font-size: 1.1rem;
  cursor: pointer;
}
.profile-crop-control-btn:hover { background: rgba(255, 255, 255, .28); }
.profile-crop-buttons { display: flex; gap: .75rem; }

/* "저장소에서 선택" 그리드 모달(2026-08-26, ProfileStoragePickerController) - 크롭 오버레이와
   같은 전체화면 어두운 배경 관례를 재사용하되, 내용은 흰 카드 + 스크롤 가능한 썸네일 그리드. */
.profile-storage-picker-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: rgba(20, 20, 30, .85);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}
/* [hidden] 버그 수정 - 위 .profile-crop-overlay[hidden]과 완전히 같은 이유. */
.profile-storage-picker-overlay[hidden] { display: none; }
.profile-storage-picker-box {
  background: #fff;
  border-radius: 12px;
  padding: 1.2rem;
  width: 100%;
  max-width: 420px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  gap: .9rem;
}
.profile-storage-picker-header { display: flex; align-items: center; justify-content: space-between; font-weight: 700; }
.profile-storage-picker-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: .5rem;
  overflow-y: auto;
}
.profile-storage-picker-thumb {
  aspect-ratio: 1 / 1;
  border: none;
  border-radius: 8px;
  background-color: #eceef1;
  background-size: cover;
  background-position: center;
  cursor: pointer;
  padding: 0;
}
.profile-storage-picker-empty { color: #9aa0aa; font-size: .9rem; text-align: center; margin: 0; }
/* [hidden] 버그 수정(위 .profile-crop-overlay[hidden]과 같은 원인) - "더 보기" 버튼은 Bulma
   .button 클래스 자체가 display:inline-flex를 강제로 걸고 있어(global.css) hidden 속성만으로는
   안 사라진다. 공용 .button 클래스는 그대로 두고 이 버튼(id)만 좁혀서 덮어쓴다. */
#storagePickerMore[hidden] { display: none; }

/* 소셜 로그인 버튼 - 무채색 원칙의 4번째 예외(frontend-bulma.md 참고). 구글/카카오는
   자기 브랜드 색을 쓰는 게 사용자에게 즉시 인지되는 관용적 UI라 예외로 둔다. */
.social-login-divider { display: flex; align-items: center; text-align: center; color: #999; font-size: .75rem; }
.social-login-divider::before, .social-login-divider::after { content: ""; flex: 1; border-bottom: 1px solid #e0e0e0; }
.social-login-divider span { padding: 0 .75rem; }
.social-login-btn {
  border: 1px solid #dbdbdb;
  font-weight: 600;
  /* 제목("SNS 간편 로그인")-버튼, 버튼-버튼 사이를 각각 10px씩 더 띄운다(2026-09-03 요청).
     첫 버튼에도 똑같이 걸리므로 위쪽 요소(제목/구분선)와의 간격까지 한 규칙으로 처리된다. */
  margin-top: 10px;
  /* 버튼 높이 +5px(위아래 2.5px씩) - global.css의 .button padding(.5em 1em)에 더한다. */
  padding-top: calc(.5em + 2.5px);
  padding-bottom: calc(.5em + 2.5px);
}
.social-login-btn.google { background: #dc4a38; color: #fff; border-color: #dc4a38; } /* 2026-09-01 요청 색상 */
.social-login-btn.google:hover { background: #c73f2e; }
.social-login-btn.kakao { background: #FEE500; color: #191600; border-color: #FEE500; }
.social-login-btn.kakao:hover { background: #f5dc00; }

/* 회원가입 약관동의 - 개별 항목은 접었다 펼 수 있는 <details>로 본문을 보여준다 */
.terms-agreement { padding: 1rem; }
.terms-content summary { cursor: pointer; }
.terms-content-box {
  max-height: 160px;
  overflow-y: auto;
  margin-top: .4rem;
  padding: .6rem .75rem;
  background: #fafafa;
  border: 1px solid #eee;
  border-radius: 4px;
  color: #555;
  line-height: 1.5;
}

.banner-image {
  width: 100%;
  border-radius: 6px;
  margin-bottom: 0.75rem;
}

.comment-item {
  padding: 0.65rem 0;
  border-bottom: 1px solid #f5f5f5;
}

/* 게시글/댓글은 사용자가 입력한 긴 문자열(URL 등)이 그대로 들어올 수 있어
   모바일 폭에서 가로 스크롤이 생기지 않도록 줄바꿈을 강제한다 */
.box, .content, .notification, .modal-card-body {
  overflow-wrap: break-word;
}

/* 게시글 첨부파일 다중 업로드 위젯 (드래그 앤 드롭 + 순서 변경) */
.attachment-dropzone {
  border: 2px dashed #dbdbdb;
  border-radius: 6px;
  padding: 1.5rem;
  text-align: center;
  color: #7a7a7a;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}

.attachment-dropzone.is-dragover {
  border-color: #8a8a8a;
  background: #fafafa;
}

.attachment-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 0.75rem;
}

.attachment-item {
  position: relative;
  width: 96px;
  height: 96px;
  border: 1px solid #dbdbdb;
  border-radius: 6px;
  overflow: hidden;
  cursor: grab;
}

.attachment-item.is-dragging {
  opacity: 0.4;
}

.attachment-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.attachment-item-remove {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 20px;
  height: 20px;
  border: none;
  border-radius: 50%;
  background: rgba(10, 10, 10, 0.6);
  color: #fff;
  line-height: 1;
  cursor: pointer;
}

/* ==========================================================================
   홈페이지 랜딩 디자인 (CLAUDE/index.png 시안 기준)
   브랜드 블루는 이 파일의 home-*/site-footer* 클래스와 네비게이션 CTA 버튼에만
   한정해서 쓴다 - 사이트 전역 버튼(.is-link/.is-primary 등)의 무채색 규칙은 그대로 유지.
   ========================================================================== */
:root {
  --brand: #2557eb;
  --brand-dark: #173fc7;
}

.home-band {
  width: 100vw;
  position: relative;
  left: 50%;
  margin-left: -50vw;
}

.home-band-alt { background: #f7f9fd; }

.home-band-blue {
  background: linear-gradient(120deg, #2557eb 0%, #1b41c4 100%);
  color: #fff;
}

.home-container {
  max-width: 1152px;
  margin: 0 auto;
  padding: 4.5rem 1.5rem;
}

.home-section-head {
  text-align: center;
  margin-bottom: 2.5rem;
}

.home-section-head h2 {
  font-size: 1.75rem;
  font-weight: 800;
  color: #1b2333;
  margin: 0 0 .5rem;
}

.home-section-head p { color: #6b7383; margin: 0; }

.home-stats .home-section-head h2,
.home-stats .home-section-head p { color: #fff; }
.home-stats .home-section-head p { color: rgba(255, 255, 255, .8); }

.home-accent { color: var(--brand); }

.home-section-head-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 2rem;
  flex-wrap: wrap;
}

.home-section-head-row h2 {
  font-size: 1.6rem;
  font-weight: 800;
  color: #1b2333;
  margin: 0 0 .35rem;
}

.home-section-head-row p { color: #6b7383; margin: 0; }

.home-grid { display: grid; gap: 1.5rem; }
.home-grid-4 { grid-template-columns: repeat(4, 1fr); }
.home-grid-3 { grid-template-columns: repeat(3, 1fr); }

@media (max-width: 960px) {
  .home-grid-4, .home-grid-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .home-grid-4, .home-grid-3 { grid-template-columns: 1fr; }
}

.home-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 12px;
  background: #eaf0ff;
  color: var(--brand);
  margin-bottom: 1rem;
}
.home-icon svg { width: 24px; height: 24px; }

/* 히어로 */
.home-hero {
  background: linear-gradient(135deg, #eaf1ff 0%, #dce8ff 55%, #cfe0ff 100%);
  overflow: hidden;
}
.home-hero-inner {
  padding-top: 4rem;
  padding-bottom: 3.5rem;
  display: flex;
  align-items: center;
  gap: 2.5rem;
  flex-wrap: wrap;
}
.home-hero-text { flex: 1 1 380px; min-width: 280px; }
.home-hero-title {
  font-size: 2.75rem;
  line-height: 1.25;
  font-weight: 800;
  color: #1b2333;
  margin: 0 0 1rem;
}
.home-hero-title .home-accent { color: var(--brand); }
.home-hero-desc {
  color: #4b5468;
  font-size: 1.05rem;
  line-height: 1.7;
  margin: 0 0 1.75rem;
  max-width: 32rem;
}
.home-hero-actions { display: flex; gap: .75rem; flex-wrap: wrap; }
.home-hero-media {
  flex: 1 1 320px;
  min-width: 280px;
  min-height: 280px;
  align-self: stretch;
  border-radius: 14px;
  background:
    linear-gradient(160deg, rgba(255, 255, 255, .5), rgba(255, 255, 255, 0) 45%),
    linear-gradient(200deg, #274bc9, #4d78ec 55%, #9fbaf6);
  box-shadow: 0 20px 45px rgba(37, 87, 235, .25);
}
.home-hero-progress {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin-top: 2.5rem;
  color: #5b6479;
  font-size: .85rem;
  font-weight: 700;
}
.home-hero-progress .bar { width: 52px; height: 2px; background: var(--brand); }

/* 버튼 (홈페이지 전용, 사이트 공통 .button.is-link/.is-primary와는 별개) */
.home-btn-primary { background: var(--brand); border-color: transparent; color: #fff; }
.home-btn-primary:hover { background: var(--brand-dark); color: #fff; text-decoration: none; }
.home-btn-outline { background: #fff; border-color: #d7deee; color: #1b2333; }
.home-btn-outline:hover { border-color: var(--brand); color: var(--brand); text-decoration: none; }

.home-link-arrow { color: var(--brand); font-weight: 600; font-size: .85rem; }

/* 가치 카드 */
.home-value-card { text-align: center; }
.home-value-card .home-icon { margin-left: auto; margin-right: auto; }
.home-value-card h3 { font-size: 1.05rem; font-weight: 700; color: #1b2333; margin: 0 0 .5rem; }
.home-value-card p { font-size: .875rem; color: #6b7383; margin: 0; line-height: 1.6; }

/* 서비스 카드 */
.home-service-card { display: flex; flex-direction: column; }
.home-service-media {
  height: 160px;
  display: flex;
  align-items: flex-start;
  padding: 1rem;
}
.home-service-media .home-icon { background: rgba(255, 255, 255, .25); color: #fff; margin: 0; }
.home-service-media-a { background: linear-gradient(135deg, #b9cbf5, #7d9aeb); }
.home-service-media-b { background: linear-gradient(135deg, #8fa9ef, #4f6fdd); }
.home-service-media-c { background: linear-gradient(135deg, #a4bdf2, #5877e2); }
.home-service-card h3 { font-size: 1.05rem; font-weight: 700; color: #1b2333; margin: 0 0 .4rem; }
.home-service-card p { font-size: .875rem; color: #6b7383; margin: 0 0 .75rem; line-height: 1.6; }

/* 통계 밴드 */
.home-stats-grid { text-align: center; }
.home-stat { display: flex; flex-direction: column; align-items: center; gap: .4rem; }
.home-stat .home-icon { background: rgba(255, 255, 255, .15); color: #fff; }
.home-stat strong { font-size: 1.9rem; font-weight: 800; }
.home-stat span { font-size: .85rem; color: rgba(255, 255, 255, .85); }

/* 고객사례 카드 */
.home-case-media { height: 150px; position: relative; }
.home-case-media-1 { background: linear-gradient(135deg, #8ba1d2, #465a86); }
.home-case-media-2 { background: linear-gradient(135deg, #3d5b9e, #1c2c52); }
.home-case-media-3 { background: linear-gradient(135deg, #93aade, #3f5590); }
.home-case-tag {
  position: absolute;
  left: .75rem;
  bottom: .75rem;
  background: rgba(10, 10, 20, .55);
  color: #fff;
  font-size: .7rem;
  padding: .25rem .6rem;
  border-radius: 4px;
}
.home-case-card h3 { font-size: 1rem; font-weight: 700; color: #1b2333; margin: 0 0 .35rem; }
.home-case-card p { font-size: .85rem; color: #6b7383; margin: 0 0 .75rem; }

/* 최신 소식 + CTA */
.home-news-grid { display: grid; grid-template-columns: 1.1fr .9fr; gap: 2rem; }
@media (max-width: 800px) {
  .home-news-grid { grid-template-columns: 1fr; }
}
.home-news-list { list-style: none; margin: 1rem 0 0; padding: 0; }
.home-news-list li {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding: .75rem 0;
  border-bottom: 1px solid #eef0f4;
}
.home-news-list li:last-child { border-bottom: none; }
.home-news-thumb {
  width: 48px;
  height: 48px;
  border-radius: 8px;
  flex: none;
  background: linear-gradient(135deg, #dbe6fb, #aac1f2);
}
.home-news-text { display: flex; flex-direction: column; gap: .15rem; overflow: hidden; }
.home-news-text a {
  color: #1b2333;
  font-weight: 600;
  font-size: .9rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.home-news-text time { color: #9aa1b1; font-size: .75rem; }

.home-cta-card {
  background: linear-gradient(160deg, #1b2333, #12182a);
  color: #fff;
  border-radius: 14px;
  padding: 2.25rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: .75rem;
}
.home-cta-card h3 { font-size: 1.4rem; font-weight: 800; margin: 0; line-height: 1.35; }
.home-cta-card p { color: rgba(255, 255, 255, .75); font-size: .9rem; margin: 0 0 .5rem; }

/* 헤더 CTA 버튼 (layout.php navbar-end, 전 페이지 공통) */
.navbar-item .home-btn-primary { padding: .5em 1.1em; font-size: .85rem; }

/* 데스크톱 상단 메뉴(.navbar-start-pc)와 모바일 햄버거 드로어 전용 메뉴(.navbar-start-mobile)는
   메뉴관리 > 홈페이지메뉴에서 항목별로 PC/모바일 노출을 따로 설정할 수 있어 서로 다른 항목
   구성을 갖는다 - 항상 같은 부모(#main-nav .navbar-menu) 안에 있으므로 화면 폭에 따라 한쪽만
   보이게 감춘다 (global.css의 navbar-menu 반응형 분기점 1024px과 맞춤). */
@media (max-width: 1023px) {
  .navbar-start-pc { display: none !important; }
}
@media (min-width: 1024px) {
  .navbar-start-mobile { display: none !important; }
}

/* 하위 메뉴 항목의 들여쓰기 - layout.php의 $renderDropdownItems가 넘기는 --indent 값을 그대로
   padding-left로 쓴다(데스크톱 드롭다운 기준값). 모바일 드로어는 이 값에 드로어 좌우 여백만큼을
   더 얹어서 쓰므로 아래 미디어쿼리에서 따로 재정의함 - PHP가 계산하는 숫자 자체는 그대로 두고
   컨텍스트(데스크톱/모바일)에 따라 CSS가 다르게 조합하기 위해 인라인 padding-left 대신 커스텀
   프로퍼티로 넘겨받음. **반드시 .navbar-start 안으로 스코프할 것** - 스코프 없이 그냥
   ".navbar-dropdown .navbar-item"으로 두면 계정 드롭다운(.navbar-end 안, 사람 아이콘 클릭 시
   나오는 로그인/회원가입/마이페이지/로그아웃)의 --indent 없는 링크에도 걸려서 padding-left가
   기본값 0으로 깔려버려 텍스트가 왼쪽 끝에 붙는 문제가 있었음(계정 드롭다운은 메뉴관리 트리가
   아니라 --indent 자체를 안 씀). */
.navbar-start .navbar-dropdown .navbar-item { padding-left: var(--indent, 0px); }

/* 모바일 드로어 전용 상단 헤더 - "메뉴" 제목 + 닫기(×) 버튼. 예전엔 이 버튼이 없어서 상단이
   허전했다가, 그 다음엔 별도 버튼을 열린 자리(드로어 안 우측 상단, absolute)에 뒀더니 헤더의
   햄버거가 열렸을 때 ×자로 바뀌는 애니메이션과 겹쳐 ×가 두 개로 보이는 문제가 있었다 - 이번엔
   버튼을 드로어 맨 위의 평범한 헤더 행(일반 흐름, absolute 아님)에 넣고, 그 대신 헤더 햄버거
   쪽의 ×자 변신 애니메이션을 꺼서(아래 .navbar-burger.is-active 참고) 겹쳐 보이는 경우 자체가
   생기지 않게 했다. */
.navbar-drawer-header {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-bottom: .5rem;
  padding-right: .5rem;
  margin-bottom: .25rem;
  border-bottom: 1px solid #eee;
  
}
.navbar-menu-close {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: -.5rem;
  width: 2rem;
  height: 2rem;
  border: none;
  border-radius: 50%;
  background: none;
  color: #363636;
  font-size: 1.35rem;
  line-height: 1;
  cursor: pointer;
  transition: background .15s ease;
}
.navbar-menu-close:hover { background: #eee; }
/* 이 헤더/닫기 버튼은 모바일 드로어 전용 - 데스크톱에서는 숨김. 이 프로젝트의 다른 반응형
   show/hide 토글(.navbar-start-pc/.navbar-start-mobile/.navbar-mobile-account)과 동일하게
   !important를 써서, 나중에 코드 순서가 바뀌어도 우선순위 동률 문제로 깨지지 않게 함 */
@media (min-width: 1024px) {
  .navbar-drawer-header { display: none !important; }
}

/* 헤더의 햄버거는 드로어가 열려도 3줄 모양 그대로 둔다(×자로 안 바뀜) - 닫기는 위 드로어 헤더의
   × 버튼(또는 백드롭 클릭) 하나로 통일하기 위함, 두 개의 ×가 동시에 보이는 걸 원천적으로 방지 */
.navbar-burger.is-active span:nth-child(1),
.navbar-burger.is-active span:nth-child(2),
.navbar-burger.is-active span:nth-child(3) {
  transform: none;
  opacity: 1;
}

/* 모바일 햄버거 드로어 정리 - global.css의 기본 골격(우측에서 슬라이드되는 흰색 패널, 세로로 쌓인
   .navbar-item 목록, position:fixed;right:0 - 이 값을 여기서 다시 선언하지 말 것, 예전에 실수로
   .navbar-menu.is-active에 position:relative를 덮어써서 드로어가 우측 고정 오버레이가 아니라
   문서 흐름 안에 그려지던 버그가 있었음)은 그대로 두고, 다음만 다듬는다:
   (1) 드로어 자체의 좌우 패딩(1.5rem)을 없애고, 그만큼을 각 항목 자신의 padding-left/right로
       옮겨서 hover 배경/구분선이 항목 박스 자체만으로 이미 드로어 끝까지 꽉 차게 만든다(텍스트
       위치는 컨테이너 패딩→항목 패딩으로 옮겨졌을 뿐 최종 위치는 그대로). **이전에는 컨테이너
       패딩은 그대로 두고 각 항목 뒤에 화면 밖으로 삐져나오는 ::before/::after 레이어를 깔아
       배경/구분선만 넓히려 했었는데, 그 레이어가 absolute라 텍스트보다 나중에 페인트되면서(z-index
       auto인 절대배치 요소는 일반 흐름의 텍스트보다 항상 나중에 그려짐) hover 시 글자가 아예 안
       보이는 문제가 있었고, 조상 요소에 따라 삐져나온 만큼이 잘려 보이는 문제도 있어서 이 방식으로
       바꿨다 - 항목 자신의 진짜 padding이라 이런 문제 자체가 생기지 않음.**
   (2) 지금 보고 있는 페이지는 굵게 표시(layout.php의 $renderTopMenu/$renderDropdownItems가
       MenuItem::pathMatches()로 계산해서 붙이는 .is-current 클래스). 색은 프로젝트 전역 무채색
       규칙을 따르고(강조색 없이 굵기만으로 구분), 파란 브랜드컬러는 홈 화면 전용이라 여기서는 안 씀. */
@media (max-width: 1023px) {
  .navbar-menu.is-active { padding: 1.5rem 0; }

  .navbar-menu.is-active .navbar-item:not(.has-dropdown),
  .navbar-menu.is-active .navbar-link {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
  }
  /* 하위 메뉴 항목은 원래 들여쓰기(--indent)에 드로어 좌우 여백(1.5rem)을 더해서 계산 -
     위 규칙과 동일한 클래스(.navbar-item)를 대상으로 하지만 선택자 우선순위가 더 높아서(부모
     .navbar-dropdown까지 포함) 이 값이 이긴다. */
  .navbar-menu.is-active .navbar-dropdown .navbar-item {
    padding-left: calc(var(--indent, 0px) + 1.5rem);
    padding-right: 1.5rem;
  }

  .navbar-start-mobile > .navbar-item { border-bottom: 1px solid #eee; }
  .navbar-start-mobile > .navbar-item:last-child { border-bottom: none; }

  .navbar-menu.is-active .navbar-item.is-current,
  .navbar-menu.is-active .navbar-item.has-dropdown.is-current > .navbar-link {
    color: #1a1a1a;
    font-weight: 700;
  }
  .navbar-menu.is-active .navbar-dropdown .navbar-item { color: #8a8f98; }
  .navbar-menu.is-active .navbar-dropdown .navbar-item.is-current { color: #1a1a1a; font-weight: 700; }
}

/* 모바일 햄버거 드로어(#main-nav)의 메뉴 항목(.navbar-start-mobile)과 로그인/회원가입/
   마이페이지/로그아웃(.navbar-mobile-account)은 메뉴관리가 관리하는 항목과 로그인 여부에 따라
   내용이 달라지는 계정 액션을 구분해서 보여주기 위해 서로 다른 블록으로 나눠져 있다 - 데스크톱은
   똑같은 계정 액션을 .navbar-end의 사람 아이콘 드롭다운으로 이미 제공하므로 그쪽만 남기고
   .navbar-mobile-account는 숨긴다(반대로 모바일에서는 .navbar-end를 숨김). */
@media (max-width: 1023px) {
  .navbar-end { display: none !important; }
}
@media (min-width: 1024px) {
  .navbar-mobile-account { display: none !important; }
}
.navbar-mobile-account-divider { border: none; border-top: 1px solid #eee; margin: .5rem 0; }
.navbar-mobile-account-greeting { color: #8a8f98; font-size: .9rem; }

/* 푸터 (layout.php, 전 페이지 공통) */
.site-footer { background: #12131a; color: rgba(255, 255, 255, .75); padding: 3.5rem 0 0; }
.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr 1.2fr;
  gap: 2rem;
  padding-bottom: 2.5rem;
  border-bottom: 1px solid rgba(255, 255, 255, .1);
}
@media (max-width: 900px) { .footer-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-brand strong { color: #fff; font-size: 1.1rem; }
.footer-brand p { margin: .75rem 0 1.25rem; font-size: .85rem; line-height: 1.7; color: rgba(255, 255, 255, .55); }
.footer-social { display: flex; gap: .6rem; }
.footer-social a {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .08);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
}
.footer-social a:hover { background: var(--brand); text-decoration: none; }
.footer-col h4 { color: #fff; font-size: .85rem; font-weight: 700; margin: 0 0 1rem; }
.footer-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .6rem; }
.footer-col a, .footer-col span { color: rgba(255, 255, 255, .6); font-size: .85rem; }
.footer-col a:hover { color: #fff; text-decoration: none; }
.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
  padding: 1.5rem 0;
  font-size: .75rem;
  color: rgba(255, 255, 255, .45);
}
.footer-bottom a { color: rgba(255, 255, 255, .45); margin-left: 1rem; }
.footer-bottom a:hover { color: #fff; text-decoration: none; }

/* 갤러리 게시판 목록 - 카드 1개당 최소 220px을 유지하며 한 줄에 들어가는 개수만큼
   유동적으로 폭이 늘어나 화면을 꽉 채우고(auto-fit), 화면이 좁아져 한 줄에
   다 안 들어가면 자동으로 다음 줄로 떨어진다 (고정 컬럼 수/고정 폭 방식 아님) */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1.25rem;
}
.gallery-card { display: block; padding: 0.5rem; }
.gallery-card:hover { text-decoration: none; }
.gallery-card figure { background: #f2f2f2; border-radius: 4px; overflow: hidden; }
.gallery-card figure img { object-fit: cover; width: 100%; height: 100%; }
.gallery-card-title { margin-top: 0.5rem; font-weight: 600; }
.gallery-card-meta { font-size: .75rem; color: #7a7a7a; }

/* ==========================================================================
   서브페이지 공통 배너/사이드바 (CLAUDE/img_sub.png 시안 기준)
   board/list, board/view, page/view 등 게시판·콘텐츠페이지가 공유해서 쓴다.
   브랜드 블루는 home-* 클래스와 동일하게 sub-* 클래스에만 한정한다.
   ========================================================================== */
.full-bleed {
  width: 100vw;
  position: relative;
  left: 50%;
  margin-left: -50vw;
}

.sub-banner {
  background: linear-gradient(100deg, #eef3ff 0%, #eef3ff 45%, #cfdcf7 72%, #9fb8ea 100%);
  overflow: hidden;
  position: relative;
}
.sub-banner::after {
  content: "";
  position: absolute;
  inset: 0;
  left: 60%;
  background: repeating-linear-gradient(75deg, rgba(37, 87, 235, .18) 0 10px, rgba(37, 87, 235, .05) 10px 20px);
  pointer-events: none;
}
.sub-banner-inner { position: relative; padding: 2.75rem 1.5rem 2.25rem; }
.sub-banner-title { font-size: 2rem; font-weight: 800; color: #1b2333; margin: 0 0 .75rem; }
.sub-breadcrumb { display: flex; align-items: center; gap: .4rem; font-size: .85rem; color: #5b6479; }
.sub-breadcrumb a { color: #5b6479; }
.sub-breadcrumb a:hover { color: var(--brand); text-decoration: none; }
.sub-breadcrumb .sep { color: #b7c0d4; }
.sub-breadcrumb .is-current { color: #1b2333; font-weight: 600; }

.sub-layout {
  display: flex;
  align-items: flex-start;
  gap: 2rem;
  max-width: 1152px;
  margin: 2.5rem auto;
  padding: 0 1.5rem;
}

.sub-sidebar {
  flex: 0 0 240px;
  width: 240px;
}
/* 헤더의 navbar-burger가 나타나는 지점(global.css)과 맞춰서, 좌측 메뉴는 사라지고
   같은 메뉴 항목은 햄버거 드로어(navbar-menu)로만 노출한다 - 화면에 중복 노출하지 않음 */
@media (max-width: 1023px) {
  .sub-sidebar { display: none; }
}
.sub-sidebar-title {
  font-size: 1.1rem;
  font-weight: 800;
  color: #1b2333;
  margin: 0 0 1rem;
  padding-bottom: 1rem;
  border-bottom: 2px solid #1b2333;
}
.sub-sidebar-list { list-style: none; margin: 0 0 1.5rem; padding: 0; }
.sub-sidebar-list li { border-bottom: 1px solid #eef0f4; }
.sub-sidebar-list a {
  display: block;
  padding: .75rem .25rem;
  color: #5b6479;
  font-size: .9rem;
}
.sub-sidebar-list a:hover { color: var(--brand); text-decoration: none; }
.sub-sidebar-list a.is-active {
  color: var(--brand);
  font-weight: 700;
  border-left: 3px solid var(--brand);
  padding-left: .5rem;
  margin-left: -.25rem;
}
.sub-contact-box {
  display: flex;
  gap: .75rem;
  align-items: flex-start;
  background: #f7f9fd;
  border-radius: 10px;
  padding: 1.25rem;
}
.sub-contact-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: #eaf0ff;
  color: var(--brand);
  flex: none;
}
.sub-contact-icon svg { width: 18px; height: 18px; }
.sub-contact-box strong { display: block; font-size: .85rem; color: #1b2333; }
.sub-contact-phone { font-size: 1.1rem; font-weight: 800; color: #1b2333; margin: .15rem 0; }
.sub-contact-hours { font-size: .75rem; color: #8a92a3; line-height: 1.5; margin: 0; }

.sub-content { flex: 1; min-width: 0; }

.sub-content-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.sub-content-count { font-size: .9rem; color: #5b6479; }
.sub-search { display: flex; gap: .4rem; }
.sub-search select,
.sub-search input {
  border: 1px solid #dbdbdb;
  border-radius: 6px;
  padding: .5em .75em;
  font-size: .85rem;
  color: #363636;
  background: #fff;
}
.sub-search button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.4em;
  border: none;
  border-radius: 6px;
  background: #1b2333;
  color: #fff;
  cursor: pointer;
}
.sub-search button:hover { background: var(--brand); }

/* 서브페이지 안에서만 페이지네이션 현재 페이지를 브랜드 블루로 강조 (다른 화면의 무채색 페이지네이션은 그대로 둠) */
.sub-content .pagination-link.is-current { background: var(--brand); border-color: var(--brand); }

/* 게시판 카테고리 필터 (use_category=1인 게시판의 목록 상단, board/basic·download·faq의 _shared 마크업
   없이 스킨별로 직접 렌더링) - 예전에는 Bulma .tabs를 썼는데 global.css(실사용 클래스만 담은 발췌본)에
   .tabs 스타일 자체가 없어서 그냥 민짜 목록으로 보였다. 알약 모양 필터 칩으로 바꾸고, 선택된 카테고리만
   사이드바 active 링크/페이지네이션 현재 페이지와 같은 규칙으로 브랜드 블루로 강조한다. */
.sub-category-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: 0 0 1.25rem;
}
.sub-category-tabs a {
  display: inline-flex;
  align-items: center;
  padding: .45em 1.1em;
  border-radius: 999px;
  background: #f2f4f8;
  color: #4b5468;
  font-size: .85rem;
  font-weight: 600;
  line-height: 1.4;
}
.sub-category-tabs a:hover { background: #e7ecf7; color: #1b2333; text-decoration: none; }
/* 모니터/화면 설정에 따라 --brand(연한 블루)만으로는 흰 텍스트와 대비가 약해 보일 수 있어서,
   선택된 칩은 더 진한 --brand-dark를 쓰고 살짝 그림자를 더해 눈에 확실히 띄게 한다. */
.sub-category-tabs a.is-active {
  background: #484848;
  color: #fff;
  box-shadow: 0 1px 3px rgba(23, 63, 199, .4);
}

/* 게시글 상세(board/_shared/view.php) 제목 위 카테고리 배지 - 목록의 미선택 카테고리 칩과
   같은 톤(연회색)으로 통일, 클릭 동작이 없는 정적 라벨이라 <a> 대신 <span>으로 둔다 */
.post-category-tag {
  display: inline-flex;
  align-items: center;
  padding: .3em .85em;
  border-radius: 999px;
  background: #f2f4f8;
  color: #4b5468;
  font-size: .75rem;
  font-weight: 600;
}

/* ==========================================================================
   스크롤 등장 애니메이션 (IntersectionObserver, layout.php 하단 스크립트가 처리)
   .reveal 요소는 뷰포트에 들어오는 순간 JS가 is-visible을 붙인다 - JS가 없거나
   IntersectionObserver 미지원 브라우저에서는 스크립트가 즉시 is-visible을 붙여
   콘텐츠가 항상 보이도록 폴백한다.
   ========================================================================== */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .7s cubic-bezier(.16, .84, .44, 1), transform .7s cubic-bezier(.16, .84, .44, 1);
}
.reveal.is-visible { opacity: 1; transform: translateY(0); }

/* 한 줄에 2개씩 짝을 이루는 레이어(히어로 텍스트/이미지, 최신소식/CTA)는 기본(아래→위) 대신 좌우에서 들어온다 */
.reveal.reveal-left { transform: translateX(-48px); }
.reveal.reveal-right { transform: translateX(48px); }
.reveal.reveal-left.is-visible,
.reveal.reveal-right.is-visible { transform: translateX(0); }

.reveal-delay-2 { transition-delay: .15s; }

.home-grid > .reveal:nth-child(1) { transition-delay: 0ms; }
.home-grid > .reveal:nth-child(2) { transition-delay: 90ms; }
.home-grid > .reveal:nth-child(3) { transition-delay: 180ms; }
.home-grid > .reveal:nth-child(4) { transition-delay: 270ms; }

.home-news-list > .reveal:nth-child(1) { transition-delay: 0ms; }
.home-news-list > .reveal:nth-child(2) { transition-delay: 70ms; }
.home-news-list > .reveal:nth-child(3) { transition-delay: 140ms; }
.home-news-list > .reveal:nth-child(4) { transition-delay: 210ms; }
.home-news-list > .reveal:nth-child(5) { transition-delay: 280ms; }

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal.is-visible {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ==========================================================================
   공통 배너 렌더러 (program_banner.md) - fixed/slide/fade/custom 4가지 출력방식 공용 스타일.
   Swiper 자체 UI(화살표/페이지네이션)는 vendor/swiper 번들 CSS가 기본을 제공하고, 여기서는
   이 프로젝트 톤에 맞는 색상/배치만 얹는다.
   ========================================================================== */
.site-banner { position: relative; width: 100%; overflow: hidden; }
.site-banner .swiper,
.banner-fixed-wrap { height: var(--banner-height, auto); }
.site-banner .swiper .banner-item,
.banner-fixed-wrap .banner-item { position: relative; height: 100%; }
@media (max-width: 1199px) {
  .site-banner .swiper, .banner-fixed-wrap { height: var(--banner-height-tablet, var(--banner-height, auto)); }
}
@media (max-width: 767px) {
  .site-banner .swiper, .banner-fixed-wrap { height: var(--banner-height-mobile, var(--banner-height, auto)); }
}

.banner-item picture.banner-image { display: block; width: 100%; height: 100%; }
.banner-item picture.banner-image img { display: block; width: 100%; height: 100%; object-fit: cover; }

.banner-image-link { position: absolute; inset: 0; }

.banner-overlay {
  position: absolute;
  inset: 0;
  background: var(--banner-overlay-color, #000000);
  opacity: var(--banner-overlay-opacity, 0.3);
  pointer-events: none;
}

.banner-inner {
  position: absolute;
  inset: 0;
  display: flex;
  padding: 6% 8%;
}
.banner-inner.position-left-top { justify-content: flex-start; align-items: flex-start; }
.banner-inner.position-left-center { justify-content: flex-start; align-items: center; }
.banner-inner.position-left-bottom { justify-content: flex-start; align-items: flex-end; }
.banner-inner.position-center-top { justify-content: center; align-items: flex-start; }
.banner-inner.position-center-center { justify-content: center; align-items: center; }
.banner-inner.position-center-bottom { justify-content: center; align-items: flex-end; }
.banner-inner.position-right-top { justify-content: flex-end; align-items: flex-start; }
.banner-inner.position-right-center { justify-content: flex-end; align-items: center; }
.banner-inner.position-right-bottom { justify-content: flex-end; align-items: flex-end; }

.banner-content {
  max-width: 36rem;
  color: var(--banner-text-color, #ffffff);
}
.banner-content.align-left { text-align: left; }
.banner-content.align-center { text-align: center; }
.banner-content.align-right { text-align: right; }
.banner-subtitle { font-size: .95rem; font-weight: 600; margin: 0 0 .5rem; opacity: .9; }
.banner-title { font-size: clamp(1.5rem, 4vw, 2.5rem); font-weight: 800; margin: 0 0 .75rem; line-height: 1.25; }
.banner-description { font-size: 1rem; line-height: 1.6; margin: 0 0 1.25rem; }
.banner-buttons { display: flex; gap: .75rem; flex-wrap: wrap; }
.banner-content.align-center .banner-buttons { justify-content: center; }
.banner-content.align-right .banner-buttons { justify-content: flex-end; }
.banner-button {
  display: inline-flex;
  align-items: center;
  padding: .65em 1.4em;
  border-radius: 6px;
  background: var(--brand, #2557eb);
  color: #fff;
  font-weight: 600;
  font-size: .9rem;
}
.banner-button:hover { background: var(--brand-dark, #173fc7); text-decoration: none; }
.banner-button-secondary { background: rgba(255, 255, 255, .15); backdrop-filter: blur(2px); }
.banner-button-secondary:hover { background: rgba(255, 255, 255, .3); }

.banner-html { width: 100%; height: 100%; }
.banner-custom-wrap .banner-custom-item + .banner-custom-item { margin-top: 1rem; }

/* 텍스트 애니메이션 (program_banner.md 11장) - Swiper가 붙이는 swiper-slide-active와,
   고정 배너는 항상 붙어있는 banner-fixed 클래스를 기준으로 재생한다 */
.banner-content .banner-title,
.banner-content .banner-description,
.banner-content .banner-buttons { opacity: 0; }
.banner-content.anim-none .banner-title,
.banner-content.anim-none .banner-description,
.banner-content.anim-none .banner-buttons { opacity: 1; }

.banner-content .banner-title { animation-delay: 0s; }
.banner-content .banner-description { animation-delay: .15s; }
.banner-content .banner-buttons { animation-delay: .3s; }

.swiper-slide-active .banner-content.anim-fade .banner-title,
.swiper-slide-active .banner-content.anim-fade .banner-description,
.swiper-slide-active .banner-content.anim-fade .banner-buttons,
.banner-fixed .banner-content.anim-fade .banner-title,
.banner-fixed .banner-content.anim-fade .banner-description,
.banner-fixed .banner-content.anim-fade .banner-buttons { animation: bannerFade .7s ease forwards; }

.swiper-slide-active .banner-content.anim-fade-up .banner-title,
.swiper-slide-active .banner-content.anim-fade-up .banner-description,
.swiper-slide-active .banner-content.anim-fade-up .banner-buttons,
.banner-fixed .banner-content.anim-fade-up .banner-title,
.banner-fixed .banner-content.anim-fade-up .banner-description,
.banner-fixed .banner-content.anim-fade-up .banner-buttons { animation: bannerFadeUp .7s ease forwards; }

.swiper-slide-active .banner-content.anim-fade-down .banner-title,
.swiper-slide-active .banner-content.anim-fade-down .banner-description,
.swiper-slide-active .banner-content.anim-fade-down .banner-buttons,
.banner-fixed .banner-content.anim-fade-down .banner-title,
.banner-fixed .banner-content.anim-fade-down .banner-description,
.banner-fixed .banner-content.anim-fade-down .banner-buttons { animation: bannerFadeDown .7s ease forwards; }

.swiper-slide-active .banner-content.anim-fade-left .banner-title,
.swiper-slide-active .banner-content.anim-fade-left .banner-description,
.swiper-slide-active .banner-content.anim-fade-left .banner-buttons,
.banner-fixed .banner-content.anim-fade-left .banner-title,
.banner-fixed .banner-content.anim-fade-left .banner-description,
.banner-fixed .banner-content.anim-fade-left .banner-buttons { animation: bannerFadeLeft .7s ease forwards; }

.swiper-slide-active .banner-content.anim-fade-right .banner-title,
.swiper-slide-active .banner-content.anim-fade-right .banner-description,
.swiper-slide-active .banner-content.anim-fade-right .banner-buttons,
.banner-fixed .banner-content.anim-fade-right .banner-title,
.banner-fixed .banner-content.anim-fade-right .banner-description,
.banner-fixed .banner-content.anim-fade-right .banner-buttons { animation: bannerFadeRight .7s ease forwards; }

.swiper-slide-active .banner-content.anim-zoom-in .banner-title,
.swiper-slide-active .banner-content.anim-zoom-in .banner-description,
.swiper-slide-active .banner-content.anim-zoom-in .banner-buttons,
.banner-fixed .banner-content.anim-zoom-in .banner-title,
.banner-fixed .banner-content.anim-zoom-in .banner-description,
.banner-fixed .banner-content.anim-zoom-in .banner-buttons { animation: bannerZoomIn .7s ease forwards; }

@keyframes bannerFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes bannerFadeUp { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
@keyframes bannerFadeDown { from { opacity: 0; transform: translateY(-24px); } to { opacity: 1; transform: translateY(0); } }
@keyframes bannerFadeLeft { from { opacity: 0; transform: translateX(-24px); } to { opacity: 1; transform: translateX(0); } }
@keyframes bannerFadeRight { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: translateX(0); } }
@keyframes bannerZoomIn { from { opacity: 0; transform: scale(.92); } to { opacity: 1; transform: scale(1); } }

@media (prefers-reduced-motion: reduce) {
  .banner-content * { animation: none !important; transition: none !important; opacity: 1 !important; }
}

.swiper-button-prev, .swiper-button-next {
  color: #fff;
  background: transparent;
  border: none;
  padding: 0;
  -webkit-appearance: none;
  appearance: none;
  opacity: .75;
  transition: opacity .2s ease;
}
.swiper-button-prev:hover, .swiper-button-next:hover { opacity: 1; }
.swiper-button-prev:focus-visible, .swiper-button-next:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

/* ==========================================================================
   팝업 (layout.php) - 헤더/바디/푸터가 구분된 모달 카드 대신, 닫기 버튼과
   "오늘 하루 보지 않기" 바를 콘텐츠(이미지) 위에 겹치는 레이어로 표현한다.
   같은 페이지에 팝업이 여러 개 활성화되어 있으면 배경은 하나만(공유) 깔고,
   카드는 전부 화면 정중앙에 겹쳐서 쌓이며, 클릭한 카드가 맨 위로 올라온다
   (layout.php의 popupZCounter/bringPopupToFront). */
.popup-overlay-backdrop {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(10, 10, 10, .6);
}
.popup-modal-wrap {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(480px, calc(100vw - 2rem));
}
.popup-modal-card {
  position: relative;
  width: 100%;
  max-height: calc(100vh - 40px);
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(10, 10, 10, .35);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.popup-close {
  position: absolute;
  top: .625rem;
  right: .625rem;
  z-index: 2;
  width: 2rem;
  height: 2rem;
  border: none;
  border-radius: 50%;
  background: rgba(10, 10, 10, .55);
  color: #fff;
  font-size: 1.375rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.popup-close:hover { background: rgba(10, 10, 10, .75); }
.popup-modal-body { overflow-y: auto; flex: 1 1 auto; }
.popup-modal-text { padding: 1.25rem 1.5rem 2.75rem; }
/* 이미지가 등록된 팝업은 이미지가 "오늘 하루 보지 않기" 바 영역을 제외한 카드 전체를 채우고,
   내용(텍스트)이 있으면 별도 여백 있는 박스 대신 이미지 위에 얹는 레이어로 표현한다.
   글자가 잘리지 않도록 카드 자체에 최소 300x300px을 보장한다. */
.popup-has-image {
  aspect-ratio: 1 / 1;
  min-width: 300px;
  min-height: 300px;
}
.popup-has-image .popup-modal-body { height: 100%; }
.popup-modal-image { display: block; width: 100%; height: 100%; object-fit: cover; }
.popup-modal-overlay-text {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1;
  padding: .75rem 3rem .75rem 1rem;
  background: linear-gradient(to bottom, rgba(10, 10, 10, .65), rgba(10, 10, 10, 0));
  color: #fff;
  font-size: .85rem;
  line-height: 1.4;
}
.popup-modal-footer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .5rem 1rem;
  background: rgba(10, 10, 10, .55);
  color: #fff;
  font-size: .8rem;
}
.popup-modal-footer label { color: #fff; display: flex; align-items: center; gap: .35rem; }
.popup-modal-footer a { color: #fff; text-decoration: underline; }
.swiper-pagination-bullet-active { background: var(--brand, #2557eb); }

/* 모달 안내 문구는 문장마다 줄을 바꿔서 보여준다(2026-09-05 공통 규칙 - _confirm_modal.php의
   renderMessage()가 마침표/물음표/느낌표 뒤에서 <br>로 끊는다). 여기서는 한국어가 단어 중간에서
   잘리지 않게(keep-all) 하고 줄간격만 읽기 좋게 잡는다. */
#uiConfirmModalBody { line-height: 1.65; word-break: keep-all; }
