/* =============================================================
   Haber 공통 보정 스타일

   Keen 번들(style.bundle.css)은 건드리지 않는다. 테마를 올릴 때
   덮어써지기 때문이다. 우리가 더하는 규칙은 전부 이 파일에 둔다.
   ============================================================= */

/* -------------------------------------------------------------
   모달 하단 버튼 — 줄이 바뀔 때의 간격

   버튼들은 `me-3`(가로 여백)만 두르고 컨테이너는 block 이라, 좁은
   화면에서 줄이 바뀌면 아랫줄 버튼이 윗줄에 그대로 붙었다(간격 0px,
   모바일 390px 에서 실측). 손가락으로 누르는 화면에서 버튼이 맞붙으면
   옆 버튼을 잘못 누른다.

   61개 화면이 같은 마크업을 쓰고 있어 개별로 고치지 않는다. 버튼을
   직접 자식으로 가진 가운데 정렬 블록을 flex 로 바꾸고 gap 을 준다.
   gap 이 가로·세로를 함께 처리하므로 me-3 는 중복이라 걷어낸다.
   ------------------------------------------------------------- */
.modal .text-center:has(> .btn) {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.75rem;
}

.modal .text-center:has(> .btn) > .btn {
	margin-right: 0 !important;
}

/* -------------------------------------------------------------
   대시보드 탭 카드 — 손가락으로 넘기기

   좁은 화면에서는 화살표가 작아 정확히 누르기 어렵다. 옆으로 쓸어
   넘기는 동작을 함께 받는다(page.js bindTabSwipe).

   가로로 쓸 때 브라우저가 뒤로가기 제스처를 가로채지 않도록 카드
   본문에서만 세로 스크롤을 브라우저에 넘긴다.
   ------------------------------------------------------------- */
[data-tab-body],
[data-tab-pane] {
	touch-action: pan-y;
}

/* -------------------------------------------------------------
   목록 화면 하단 — 좁은 화면에서의 배치

   DataTables 가 그리는 하단은 세 덩어리다: 한 쪽에 몇 줄을 볼지 고르는
   셀렉트, "28개 중 1부터 5까지" 안내, 쪽 이동. 넓은 화면에서는 한 줄에
   나란히 서지만 390px 에서는 서로 밀려 셀렉트가 왼쪽 끝에 붙고 쪽 이동이
   컨테이너 밖으로 6px 넘쳤다(실측).

   좁을 때는 세 덩어리를 세로로 쌓고 가운데로 모은다. 위아래로 읽는 편이
   좁은 화면에서 자연스럽고, 무엇보다 서로 밀지 않는다.
   ------------------------------------------------------------- */
@media (max-width: 767.98px) {
	.dt-container > .row {
		flex-direction: column;
		align-items: center;
		gap: 0.75rem;

		/* 표 아래로 띄운다.

		   Bootstrap 이 gutter 보정으로 margin-top: -6px 를 주는데, 넓은
		   화면에서는 표와 하단이 한 줄 간격으로 떨어져 있어 드러나지 않는다.
		   좁아지면 표가 가로 스크롤되면서 스크롤바가 생기고, 그 바로 아래에
		   줄 수 셀렉트가 달라붙어 <b>스크롤바와 셀렉트가 한 덩어리로</b>
		   보였다(간격 -6px, 실측). */
		margin-top: 0 !important;
		padding-top: 1rem;
	}

	.dt-container > .row > * {
		width: auto !important;
		max-width: 100%;
		text-align: center;
	}

	/* 쪽 번호가 많으면 줄을 바꾼다. 가로로 넘치면 화면 밖으로 나가 누를 수
	   없지만, 줄이 바뀌면 아래로 조금 길어질 뿐이다. */
	.dt-container .pagination {
		flex-wrap: wrap;
		justify-content: center;
		row-gap: 0.5rem;
	}

	/* 손가락으로 누르는 크기. 30px 짜리 사각형은 옆 번호를 잘못 누르기 쉽다.
	   가로는 번호가 많을 때를 생각해 최소치만 키운다. */
	.dt-container .page-link,
	.modal .text-center:has(> .btn) > .btn {
		min-height: 38px;
	}

	.dt-container .page-link {
		min-width: 38px;
		display: inline-flex;
		align-items: center;
		justify-content: center;
	}

	/* 한 쪽 줄 수 셀렉트. 좁은 화면에서 67px 은 손가락으로 고르기에 작다. */
	.dt-container select.form-select {
		min-height: 38px;
		min-width: 84px;
	}

	/* 줄 수 셀렉트와 "1개 중 1부터 1까지 표시" 는 한 칸(.dt-toolbar) 안에
	   함께 들어 있어, 바깥을 세로로 쌓아도 이 둘은 여전히 나란히 선다.
	   간격이 9px 뿐이라 셀렉트에 글자가 달라붙어 보였다.

	   좁을 때는 이 칸도 세로로 쌓는다. 셀렉트는 고르는 것이고 안내는 읽는
	   것이라, 붙여 둘 이유가 없다. */
	.dt-container .dt-toolbar {
		flex-direction: column;
		gap: 0.5rem;
	}
}

/* -------------------------------------------------------------
   확인 팝업(SweetAlert2) — 좁은 화면에서의 버튼

   "네, 해결되었습니다"(137px)와 "아니오, 전문 엔지니어에게…"(273px)는
   글자 수가 달라 폭이 두 배 차이 났다. 세로로 쌓이는 좁은 화면에서
   길이가 들쭉날쭉하면 어느 쪽이 기본 선택인지 읽기 어렵다.

   좁을 때는 둘 다 전체 폭으로 세운다. 위아래로 나란히 서면 길이가
   아니라 순서와 색이 구분을 맡는다.
   ------------------------------------------------------------- */
@media (max-width: 767.98px) {
	.swal2-actions {
		flex-direction: column;
		width: 100%;
		gap: 0.5rem;
	}

	.swal2-actions > .btn {
		width: 100%;
		margin: 0 !important;
		min-height: 44px;
		/* 긴 문구가 한 줄에 안 들어가면 줄을 바꾼다. 잘리면 무엇을 고르는
		   것인지 알 수 없다. */
		white-space: normal;
	}
}

/* -------------------------------------------------------------
   목록 화면 상단 버튼 — 좁은 화면에서 글자가 쳐지지 않게

   [필터] [Excel 출력] [조회] 는 `d-flex justify-content-end` 안에 나란히
   선다. flex 자식은 자리가 모자라면 <b>줄어들면서</b> 안쪽 내용을 줄바꿈
   하는데, 그래서 319px 화면에서 아이콘이 위·글자가 아래로 갈라지고
   "필터" 마저 "필/터" 로 쪼개졌다(높이 40 → 80px, 실측).

   버튼 안 글자는 줄을 바꾸지 않는다. 대신 버튼들이 한 줄에 못 들어가면
   버튼 단위로 줄을 바꾼다 — 쪼개야 할 것은 글자가 아니라 버튼 묶음이다.
   ------------------------------------------------------------- */
.d-flex > .btn {
	flex-shrink: 0;
	white-space: nowrap;
}

@media (max-width: 767.98px) {
	/* 버튼이 넘치면 줄을 바꾼다. 가로로 넘치면 화면 밖이라 누를 수 없다. */
	.card-header .d-flex,
	.card-body > .d-flex.justify-content-end,
	.d-flex.justify-content-end:has(> .btn) {
		flex-wrap: wrap;
		gap: 0.5rem;
	}

	/* gap 이 간격을 맡으므로 me-* 는 중복이다. 두면 gap 과 더해져 벌어진다. */
	.d-flex.justify-content-end:has(> .btn) > .btn {
		margin-right: 0 !important;
	}
}

/* -------------------------------------------------------------
   로그인·초대 화면 — 좁은 화면에서 하단이 바닥에 붙게

   넓은 화면에서는 `flex-lg-row-fluid` 가 좌우를 채우지만, 좁아져 세로로
   쌓이면 <b>아무도 남는 높이를 차지하지 않는다.</b> 화면 946px 중 367px
   에서 내용이 끝나고 아래 609px 가 비어, 저작권 표기가 화면 중반에 떠
   있었다(실측).

   md 이하에서만 늘린다. 넓은 화면의 좌우 비율(w-lg-50)에는 손대지
   않는다 — flex-grow 를 전역으로 주면 50% 를 넘어설 수 있다.
   ------------------------------------------------------------- */
@media (max-width: 991.98px) {
	.auth-body {
		flex-grow: 1;
	}

	.auth-form {
		flex-grow: 1;
	}
}

/* -------------------------------------------------------------
   대시보드 첫 조회 — "불러오는 중"

   대시보드는 한 번의 API 로 카드 열몇 개를 채운다. 그 응답이 오기 전까지
   카드가 전부 비어 있어, 사용자는 <b>고장인지 기다리는 중인지 알 수 없다.</b>

   내용을 지우지 않고 위에 덮는다. 지우면 두 번째 조회부터 화면이 비었다가
   다시 차오르는데 그 사이가 고장처럼 보인다. 30초 폴링에는 붙지 않는다 —
   이미 값을 보고 있는 사람에게 30초마다 깜빡이는 것은 알림이 아니라 방해다
   (설계서 10번 §4.1).
   ------------------------------------------------------------- */
.card.dashboard-loading {
	position: relative;
}

.dashboard-loading-veil {
	position: absolute;
	inset: 0;
	z-index: 5;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;

	/* 카드 배경색을 그대로 쓴다. 회색 판을 덮으면 카드가 비활성으로 보인다. */
	background: var(--bs-card-bg, var(--bs-body-bg));

	/* 살짝 비쳐 아래에 무언가 있다는 것이 보이게 한다. */
	opacity: 0.92;
	border-radius: inherit;
}

/* -------------------------------------------------------------
   뱃지 글자색 — 밝은 테마에서 읽히게

   Keen 팔레트는 옅은 배경에 원색 글자를 얹는다. 다크 테마에서는 배경이
   어두워 문제가 없지만, 라이트 테마에서는 대비가 WCAG 기준(4.5:1)에
   한참 못 미친다. 노란 계열은 1.58 로 사실상 읽히지 않았다(실측).

   배경은 그대로 두고 <b>글자만</b> 어둡게 한다. 배경을 바꾸면 뱃지가
   화면에서 튀어 "이 값이 특별한가" 하는 오해를 준다 — 뱃지는 보조 표기다.

   원색의 색상(hue)은 유지한 채 명도만 낮춰 4.5:1 을 막 넘는 지점을 골랐다.
   더 어둡게 하면 뱃지가 본문 글자와 구분되지 않는다.

     badge-light-primary  #3E97FF → #2D6FBC   2.65 → 4.56
     badge-light-success  #50CD89 → #317F54   1.88 → 4.57
     badge-light-warning  #F6C000 → #896B00   1.58 → 4.73
     badge-light-danger   #F1416C → #C53558   3.29 → 4.67
     badge-light-info     그대로              5.59 (이미 통과)

   다크 테마는 건드리지 않는다 (설계서 6번 §1.5).
   ------------------------------------------------------------- */
[data-bs-theme="light"] .badge-light-primary,
:root:not([data-bs-theme="dark"]) .badge-light-primary {
	color: #2D6FBC;
}

[data-bs-theme="light"] .badge-light-success,
:root:not([data-bs-theme="dark"]) .badge-light-success {
	color: #317F54;
}

[data-bs-theme="light"] .badge-light-warning,
:root:not([data-bs-theme="dark"]) .badge-light-warning {
	color: #896B00;
}

[data-bs-theme="light"] .badge-light-danger,
:root:not([data-bs-theme="dark"]) .badge-light-danger {
	color: #C53558;
}

/* -------------------------------------------------------------
   확인 팝업은 언제나 맨 위에 온다

   AI 기술지원 상세는 채팅 드로어를 z-index 2000 으로 끌어올린다(상세 조각의
   인라인 style). SweetAlert 는 기본이 1060 이라 그대로 두면 드로어 뒤로
   깔린다.

   종전에는 스크립트가 "드로어가 열려 있으면" 그때만 2100 으로 올렸다.
   그 판정(KTDrawer.getInstance(...).isShown())이 어긋나는 순간 팝업이 뒤로
   숨어 <b>아무것도 누를 수 없게 된다</b> — 모바일에서 실제로 그랬다.

   판정에 기대지 않는다. 확인 팝업은 사용자의 답을 받아야 진행되는 것이라
   언제나 맨 앞이어야 한다. 값 하나로 정해 두면 어긋날 자리가 없다.
   ------------------------------------------------------------- */
.swal2-container {
	z-index: 2100;
}

/* -------------------------------------------------------------
   AI 채팅 드로어 — 상세 모달 위로

   드로어는 상세 모달(부트스트랩 1055) 안에서 열린다. Keen 기본값 110 으로는
   모달 뒤로 깔려 보이지 않는다.

   종전에는 이 두 줄이 상세 조각(support/detail.html)의 인라인 style 에 있었다.
   쌓임 순서는 화면 하나의 사정이 아니라 <b>여러 층이 겹치는 규칙</b>이라, 한
   조각 안에 숨어 있으면 다른 층을 손볼 때 보이지 않는다. 실제로 확인 팝업이
   이 값 뒤로 숨는 문제를 찾는 데 시간이 걸렸다.

     1055  상세 모달 (부트스트랩)
     1999  드로어 덮개
     2000  드로어
     2100  확인 팝업 (위 §)
   ------------------------------------------------------------- */
#kt_drawer_chat {
	z-index: 2000;
}

.drawer-overlay {
	z-index: 1999;
}

/* -------------------------------------------------------------
   드로어는 화면보다 넓을 수 없다

   폭은 CSS 가 아니라 KTDrawer 가 정한다. 좁은 화면에서 채팅 드로어가 전체
   폭인 것은 채팅이 한 번에 한 가지 일만 하는 화면이라 뒤를 보일 이유가 없기
   때문이고, 그 값은 `layout.html` 의 `data-kt-drawer-width` 에 있다. `data-kt-drawer-width` 의 중단점을 <b>초기화 시점의
   창 너비로 한 번 계산해</b> 인라인 style 에 `!important` 로 박는다. 그래서
   그 값이 실제 화면과 어긋나면 스타일시트로는 되돌릴 수 없다 — 같은 속성에
   `!important` 를 붙여도 인라인이 이긴다.

   어긋나면 이렇게 된다. 채팅 드로어는 `right: 0` 에 붙으므로, 390px 화면에
   500px 가 박히면 <b>왼쪽으로 110px 뚫고 나간다.</b> 화면 밖이라 스크롤로
   따라갈 수도 없다.

   `max-width` 는 인라인에 없으므로 여기서 이길 수 있다. 폭 계산이 언제
   어긋나든 상자는 화면 안에 남는다. `100vw` 가 아니라 `100%` 인 이유는,
   고정 위치 요소의 백분율은 스크롤바를 뺀 너비로 풀리기 때문이다 —
   `100vw` 는 스크롤바까지 세어 데스크톱에서 그만큼 넘친다.
   ------------------------------------------------------------- */
.drawer {
	max-width: 100%;
}

/* -------------------------------------------------------------
   채팅 — 마지막 말풍선과 입력창 사이

   대화 한 덩어리는 `mb-10`(30px)으로 다음 덩어리와 떨어진다. 그 여백이
   <b>마지막 덩어리에도 남아</b>, 바닥까지 내려도 말풍선 아래에 30px 이
   비고 본문 여백 24px 이 더해져 55px 이 빈다(실측).

   넓은 화면에서는 눈에 띄지 않는다. 휴대폰에서 자판이 올라와 대화 영역이
   174px 까지 줄면 그 55px 이 보이는 자리의 <b>3분의 1</b>이라, 바닥에
   붙어 있는데도 방금 온 답이 안 보인다.

   여백은 덩어리 <b>사이</b>에 필요한 것이지 마지막 뒤에 필요한 것이 아니다.
   ------------------------------------------------------------- */
#div_chat > *:last-child {
	margin-bottom: 0 !important;
}

/* -------------------------------------------------------------
   채팅 — 폼은 고정하고 가운데만 스크롤한다

   머리말과 입력창은 제자리에 있고, 대화만 그 사이에서 스크롤한다.

   <b>이 높이를 JS 로 계산하지 않는다.</b> 종전에는 KTScroll 이 창 높이에서
   머리말·바닥글을 빼 픽셀로 구한 뒤 인라인 style 에 박았다. 계산이 한 박자
   늦게 오는 방식이라 세 가지가 함께 어긋났다.

     · 자판이 올라와 화면이 낮아지면 200ms 뒤에야 높이가 따라온다
     · 마크다운이 나중에 그려져 대화가 길어져도 높이는 그대로다
     · 재진입할 때 그리는 순서에 따라 값이 갈린다

   남는 자리를 재는 일은 CSS 가 늘 하는 일이다. 사슬을 flex 로 잇고
   `flex: 1` 하나로 넘긴다. 계산도, 시점도 없다.

   <b>`min-height: 0` 이 없으면 동작하지 않는다.</b> flex 항목의 최소 크기는
   기본이 내용 크기라, 대화가 길어지면 상자가 줄지 않고 <b>부모를 밀어내
   입력창이 화면 밖으로 나간다.</b>
   ------------------------------------------------------------- */
#kt_drawer_chat_messenger {
	display: flex;
	flex-direction: column;
	height: 100%;
}

#kt_drawer_chat_messenger_header,
#kt_drawer_chat_messenger_footer {
	flex: 0 0 auto;
}

#kt_drawer_chat_messenger_body {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	min-height: 0;
}

#div_chat {
	flex: 1 1 auto;
	min-height: 0;
	overflow-y: auto;

	/* 아래에서부터 쌓기 — 아래 § */
	display: flex;
	flex-direction: column;
}

/* -------------------------------------------------------------
   채팅 — 대화는 아래에서부터 쌓인다

   메신저(카카오톡·슬랙)와 같은 방식이다. 대화가 짧아 자리가 남으면 <b>빈 자리를
   위에 두고</b> 말풍선은 입력창 바로 위에 붙는다.

   빈 자리 자체는 없앨 수 없다 — 대화 영역은 머리말과 입력창을 뺀 높이를 통째로
   차지하므로(390x844 에서 598px), 인사말 하나뿐이면 460px 이 남는다. 정할 수
   있는 것은 <b>어디를 비울지</b>다.

   아래를 채우는 쪽이 맞다. 방금 주고받은 말과 입력창 사이가 화면 절반만큼
   벌어지면, 쓰는 사람은 자기 말이 어디로 갔는지 눈으로 잇지 못한다. 위쪽은
   지나간 대화가 있던 자리라 비어 있어도 읽는 데 방해가 되지 않는다.

   <b>`justify-content: flex-end` 를 쓰지 않는다.</b> 스크롤되는 flex 상자에 그것을
   주면 넘치는 내용이 위로 잘려 나가 <b>손이 닿지 않는다.</b> 첫 덩어리의
   `margin-top: auto` 는 남는 자리가 있을 때만 밀고, 넘칠 때는 아무 일도 하지
   않는다.
   ------------------------------------------------------------- */
#div_chat > *:first-child {
	margin-top: auto;
}

/* -------------------------------------------------------------
   한글은 낱말 가운데서 끊지 않는다

   기본 줄바꿈은 글자 단위라 "다시 로그인해 주 / 세요." 처럼 낱말 한가운데가
   갈린다. 짧은 안내문일수록 눈에 띄고, 읽는 사람은 그 줄에서 한 번 멈춘다.

   `keep-all` 은 낱말을 통째로 다음 줄로 넘긴다. 다만 띄어쓰기 없이 긴
   덩어리(URL·시리얼·참조번호)는 넘길 자리가 없어 상자를 넘치므로,
   `break-word` 로 그런 것만 예외로 끊는다.

   <b>화면 문구에 `<br/>` 을 박지 않는다.</b> 폭은 화면마다 다르다. 390px 에
   맞춰 넣은 줄바꿈은 데스크톱에서 어색한 자리에 남는다. 문장을 나누어 두면
   폭에 맞춰 저절로 나뉜다 (설계서 6번 §5.8.2).
   ------------------------------------------------------------- */
body {
	word-break: keep-all;
	overflow-wrap: break-word;
}

/* -------------------------------------------------------------
   세션 만료 알림 — 여닫기와 덮개

   부트스트랩의 `d-none`/`d-flex` 로 여닫지 않는다. 둘 다 `!important` 라
   서로 이기지 못하고, 스타일시트에 늦게 나오는 `d-flex` 가 항상 이겨
   <b>모달이 늘 떠 있게 된다.</b> 전용 클래스로 여닫는다.

   덮개 색은 두 단계다. 만료 <b>임박</b>에는 뒤가 비치는 검은 막을 씌워
   "아직 쓰던 화면이 있다"를 남기고, 만료가 <b>확정</b>되면 테마 배경색으로
   완전히 덮어 뒤 내용을 보이지 않게 한다 — 세션이 끝난 화면이다.

   색을 직접 적지 않고 `--bs-body-bg` 를 쓴다. 종전에는 `#F9F9F9` 를 박아
   두어 다크 테마에서 이 팝업만 흰 판이 되었다.
   ------------------------------------------------------------- */
#session_timeout_modal {
	display: none;
	z-index: 99999;
	background: rgba(0, 0, 0, 0.5);
}

#session_timeout_modal.is-open {
	display: flex;
	align-items: center;
	justify-content: center;
}

#session_timeout_modal.is-expired {
	background: var(--bs-body-bg);
}
