/*
 * 기능성 CSS. 화면 꾸미기가 아니라 **동작**에 필요한 것만 둔다.
 * (Tailwind 도입은 T16 에서 별도로 한다)
 */

/*
 * 검색 창 — 고른 종류에 따라 입력칸과 카테고리 선택을 갈아 끼운다.
 *
 * 구 시스템은 React 상태로 둘 중 하나만 그렸다 (SearchButton.jsx:110-137).
 * :has() 로 같은 일을 하면 JS 가 0줄이다.
 *
 * ★ display:none 이면 그 안의 입력값은 폼 전송에 **그대로 실린다**.
 *   서버가 searchType 을 보고 필요한 값만 쓰므로 문제되지 않는다.
 *   대신 required 는 걸면 안 된다 — 감춰진 required 는 제출을 막고
 *   브라우저가 "보이지 않는 요소" 라며 오류만 낸다.
 */
#search-form:has(#st-category:checked) .search-keyword { display: none; }
#search-form:not(:has(#st-category:checked)) .search-category { display: none; }

/* 검색어 경고. 서버가 ?searchError=short 로 되돌려보냈을 때만 보인다. */
.search-error { color: #b91c1c; font-size: 0.8125rem; }

/*
 * 이미지 모아보기의 벽돌쌓기.
 *
 * ★ 커스텀 엘리먼트는 기본이 `display: inline` 이다. 그대로 두면 clientWidth 가
 *   거의 0이라 열 너비가 4px 로 계산되고 배치가 통째로 무너진다. 실제로 겪었다.
 *
 * ★ 여기 있는 것은 **배치가 의존하는 기하**뿐이다. 모양(테두리·그림자·둥근 모서리)은
 *   T16 의 디자인 작업에서 온다.
 */
image-grid { display: block; width: 100%; }
image-grid a { display: block; }
image-grid img { display: block; width: 100%; height: auto; }

/*  열 컨테이너. JS 가 <a> 를 가장 짧은 열에 담고, 배치는 flex 가 한다.
    절대 배치를 쓰지 않으므로 감시자는 그냥 목록 아래에 놓인다. */
.masonry-cols { display: flex; gap: 8px; align-items: flex-start; }
.masonry-col  { flex: 1 1 0; display: flex; flex-direction: column; gap: 8px; min-width: 0; }

/*
 * 편집기. 구 시스템은 스켈레톤 높이가 460px 였고(PostEdit.jsx:104), 실제 편집
 * 영역도 그만큼 잡혔다. 지정하지 않으면 한 줄 높이로 뜬다.
 */
.ck-editor__editable { min-height: 460px; }

/*  <ime-input> 은 감싸는 요소다. 커스텀 엘리먼트 기본값(inline)으로 두면
    안쪽 입력칸의 width:100% 가 먹지 않는다. */
ime-input { display: block; width: 100%; }

/* ─────────────────────────────────────────────────────────
 * 애니메이션 재현 (결정 13 · T16g)
 *
 * 구 시스템은 Radix 의 `data-[state=open|closed]` 에 tailwindcss-animate 를
 * 물려 썼다. 그 상태 속성은 Radix 가 붙이는 것이라 여기엔 없다.
 * 브라우저 기본 상태(`[open]`, `:popover-open`)에 같은 전환을 건다.
 *
 * ★ 퇴장 애니메이션에는 세 가지가 다 필요하다:
 *     @starting-style        — 진입 시작값 (없으면 나타날 때 애니메이션이 없다)
 *     transition-behavior    — display/overlay 처럼 원래 전환 안 되는 속성까지
 *     display, overlay 포함  — 이게 없으면 닫힐 때 **즉시 사라진다**
 *   셋 중 하나만 빠져도 "열릴 때만 부드럽고 닫힐 때 툭 사라지는" 상태가 된다.
 *
 * ★ 움직임을 원치 않는 사용자는 그대로 둔다 (prefers-reduced-motion).
 * ───────────────────────────────────────────────────────── */

dialog {
  /*  구 시스템 duration-200 · zoom-95 · top-[48%] 에서 시작 */
  opacity: 0;
  transform: translateY(-8px) scale(0.95);
  transition: opacity 200ms ease, transform 200ms ease,
              display 200ms allow-discrete, overlay 200ms allow-discrete;
}
dialog[open] {
  opacity: 1;
  transform: translateY(0) scale(1);
}
@starting-style {
  dialog[open] {
    opacity: 0;
    transform: translateY(-8px) scale(0.95);
  }
}

dialog::backdrop {
  background: rgb(0 0 0 / 0.5);
  opacity: 0;
  transition: opacity 200ms ease, display 200ms allow-discrete, overlay 200ms allow-discrete;
}
dialog[open]::backdrop { opacity: 1; }
@starting-style {
  dialog[open]::backdrop { opacity: 0; }
}

/*  팝오버(글 작성자 메뉴). 구 시스템 DropdownMenuContent 의 zoom + fade. */
[popover] {
  opacity: 0;
  transform: scale(0.95);
  transition: opacity 150ms ease, transform 150ms ease,
              display 150ms allow-discrete, overlay 150ms allow-discrete;
}
[popover]:popover-open {
  opacity: 1;
  transform: scale(1);
}
@starting-style {
  [popover]:popover-open {
    opacity: 0;
    transform: scale(0.95);
  }
}

/*  모바일 메뉴는 **시트**다 — 확인창과 애니메이션이 다르다.
 *
 *  구 시스템은 확인창(DialogContent)과 시트(SheetContent)에 서로 다른 것을 걸었다.
 *  위의 일반 `dialog` 규칙은 확인창 것(zoom + fade)이라, 시트에 그대로 쓰면
 *  아래에서 올라오지 않고 가운데서 뿅 나타난다.
 *
 *  운영에서 직접 재온 값이다 (2026-08-19, 모바일 폭으로 열어 computed style 확인):
 *
 *    시트   translateY(100%) → 0   열림 500ms · **닫힘 300ms**   cubic-bezier(.4,0,.2,1)
 *    배경   opacity 0 → 1          150ms
 *
 *  ★ 열림과 닫힘의 길이가 **다르다.** 구 시스템의
 *    `data-[state=open]:duration-500 data-[state=closed]:duration-300` 이다.
 *    닫을 때 더 빠른 편이 답답하지 않다 — 이미 볼 것을 다 본 뒤라서다.
 *
 *  ★ 시트는 **페이드하지 않는다.** enter 키프레임의 opacity 가 1 이다
 *    (`var(--tw-enter-opacity,1)`). 그래서 opacity 를 1 로 되돌려 놓는다 —
 *    안 그러면 위의 일반 규칙이 준 `opacity: 0` 이 남아 슬라이드하면서 흐려진다.
 */
#mobile-menu {
  opacity: 1;
  transform: translateY(100%);
  transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1),
              display 300ms allow-discrete, overlay 300ms allow-discrete;
}
#mobile-menu[open] {
  transform: translateY(0);
  /*  ★ 여는 쪽만 500ms. 닫힐 때는 [open] 이 빠지므로 위의 300ms 가 쓰인다. */
  transition-duration: 500ms;
}
@starting-style {
  #mobile-menu[open] { transform: translateY(100%); }
}
#mobile-menu::backdrop {
  transition: opacity 150ms ease, display 150ms allow-discrete, overlay 150ms allow-discrete;
}

/*  알림 항목이 사라질 때. 구 시스템은 opacity-0 scale-95 를 300ms 동안 줬다
    (NotificationList.removeItem 의 setTimeout 300 과 같은 값). */
[data-notifications] [data-noti] {
  transition: opacity 300ms ease-out, transform 300ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
  dialog, dialog::backdrop, [popover], [data-notifications] [data-noti] {
    transition-duration: 1ms;
  }
  /*  ★ 모바일 시트는 **따로 적어야 한다.** 위 `dialog` 규칙보다 `#mobile-menu[open]`
   *    의 명시도가 높아서, 그 규칙의 `transition-duration: 500ms` 가 그대로 이긴다.
   *    실제로 움직임을 끈 사람에게도 시트만 500ms 동안 올라오고 있었다.
   *  ★ 진행 막대는 전환이 아니라 **애니메이션**이라 duration 으로 안 잡힌다.
   *    막대 자체는 남겨야 한다 — 느린 이동을 알리는 유일한 표시라 지우면 정보가
   *    사라진다. 차오르는 움직임만 없애고 폭을 고정한다. */
  #mobile-menu, #mobile-menu[open], #mobile-menu::backdrop {
    transition-duration: 1ms;
  }
  #page-progress.on {
    animation: none;
    width: 60%;
  }
}

/*
 * 댓글의 답글·수정 폼.
 *
 * 여는 스위치는 <details name> 이고(결정 11 · 가족 4 — 배타 동작이 공짜),
 * 폼은 본문 아래 따로 있다. 좁은 버튼 줄 안에서 펼치면 레이아웃이 밀리기 때문이다.
 *
 * ★ 그래서 "그 details 가 열렸을 때만 그 폼을 보여준다" 를 CSS 로 잇는다.
 *   :has() 가 지원되는 브라우저에서만 동작하지만, 안 되더라도 폼이 늘 보일 뿐
 *   기능은 그대로다 (열고 닫는 편의만 사라진다).
 */
.comment-form { display: none; }
li:has(details[name="comment-reply"][open]) > form[id^="reply-"] { display: flex; }
li:has(details[name="comment-edit"][open])  > form[id^="edit-"]  { display: flex; }

/* ─────────────────────────────────────────────────────────
 * 화면 이동 진행 표시 (구 next-nprogress-bar)
 *
 * 구 설정 그대로: 높이 3px · 색 #6B21A8 · 스피너 없음.
 *
 * ★ **실제 진행률이 아니다.** 전체 페이지 이동에서는 "다음 문서를 얼마나
 *   받았는가" 를 지금 페이지가 알 수 없다. 시간에 따라 92%까지 완만히 차오르다
 *   멈춘다 — 100%는 영영 안 된다. 새 문서가 오면 이 막대는 옛 페이지와 함께
 *   통째로 사라진다. 구 시스템의 nprogress 도 같은 방식이었다.
 *
 * ★ 앞이 빠르고 뒤가 느린 곡선이다. 대부분의 대기가 "첫 바이트까지" 라서,
 *   초반에 눈에 띄게 움직여야 "먹혔다" 는 느낌을 준다.
 * ───────────────────────────────────────────────────────── */
#page-progress {
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  width: 0;
  background: #6B21A8;
  z-index: 9999;
  pointer-events: none;
  opacity: 0;
}
#page-progress.on {
  opacity: 1;
  animation: page-progress 8s linear forwards;
}
/*  ★ 실제 대기는 대개 **0.3~2초**다. 12초 곡선으로 뒀더니 0.9초에 24%밖에 안 차서
 *    기어가는 느낌이었다 (실측). 그 구간에서 눈에 띄게 움직이도록 앞을 당겼다.
 *      0.4초 → 35%   ·   1.6초 → 60%   ·   4초 → 80%   ·   그 뒤 92%로 수렴 */
@keyframes page-progress {
  0%   { width: 0; }
  5%   { width: 35%; }
  20%  { width: 60%; }
  50%  { width: 80%; }
  100% { width: 92%; }
}
