/* 공용 로딩 표시 · 팝업 (js/ui.js). 차분한 업무용 움직임: 들어올 땐 감속, 나갈 땐 가속, 큰 튐 없음 */
:root { --ui-ease-out: cubic-bezier(0.2, 0, 0, 1); --ui-ease-in: cubic-bezier(0.3, 0, 1, 1); }

/* 1) 맨 위 진행 막대: 서버에 요청하는 동안 */
.ui-bar { position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 300; pointer-events: none; overflow: hidden;
  opacity: 0; transition: opacity 200ms var(--ui-ease-in); }
.ui-bar.on { opacity: 1; transition-duration: 120ms; }
.ui-bar::before { content: ""; position: absolute; inset: 0; background: var(--color-primary); opacity: 0.18; }
.ui-bar::after { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 40%; border-radius: 0 3px 3px 0;
  background: linear-gradient(90deg, transparent, var(--color-primary) 40%, var(--color-primary));
  animation: ui-bar-run 1.1s linear infinite; }
@keyframes ui-bar-run { from { transform: translateX(-100%); } to { transform: translateX(250%); } }

/* 2) 오래 걸릴 때 로딩 화면 (첫 화면 준비 중 + 1.2초 넘는 요청). 누르기도 잠깐 막아 두 번 보내기를 막는다 */
.ui-wait { position: fixed; inset: 0; z-index: 290; display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--color-canvas) 62%, transparent); backdrop-filter: blur(2px);
  animation: ui-fade-in 220ms var(--ui-ease-out) both; }
.ui-wait.boot { background: var(--color-canvas); backdrop-filter: none; animation: none; }
.ui-wait.out { animation: ui-fade-out 160ms var(--ui-ease-in) both; }
.ui-wait-card { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 24px 28px; min-width: 180px;
  border-radius: 16px; background: var(--color-surface); border: 1px solid var(--color-hairline);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12); animation: ui-pop-in 280ms var(--ui-ease-out) both; }
.ui-wait.boot .ui-wait-card { background: none; border: 0; box-shadow: none; }
.ui-wait-text { margin: 0; font-size: 14px; color: var(--color-ink-secondary); text-align: center; }
.ui-wait-sub { margin: -6px 0 0; font-size: 12px; color: var(--color-ink-faint); min-height: 1em; text-align: center; }
/* 도는 고리 + 가운데 숨 쉬는 점 (주 움직임 + 잔잔한 배경 움직임) */
.ui-spin { position: relative; width: 36px; height: 36px; }
.ui-spin::before { content: ""; position: absolute; inset: 0; border-radius: 50%;
  border: 3px solid color-mix(in srgb, var(--color-primary) 18%, transparent); border-top-color: var(--color-primary);
  animation: ui-rot 0.8s linear infinite; }
.ui-spin::after { content: ""; position: absolute; inset: 13px; border-radius: 50%; background: var(--color-primary);
  animation: ui-breathe 1.6s ease-in-out infinite; }
.ui-wait.boot .ui-spin { width: 44px; height: 44px; }
.ui-wait.boot .ui-spin::after { inset: 16px; }
@keyframes ui-rot { to { transform: rotate(360deg); } }
@keyframes ui-breathe { 0%, 100% { transform: scale(0.6); opacity: 0.45; } 50% { transform: scale(1); opacity: 1; } }

/* 3) 팝업 (알림·확인) */
.ui-dlg { position: fixed; inset: 0; z-index: 310; display: flex; align-items: center; justify-content: center; padding: 16px;
  background: rgba(0, 0, 0, 0.42); animation: ui-fade-in 200ms var(--ui-ease-out) both; }
.ui-dlg.out { animation: ui-fade-out 140ms var(--ui-ease-in) both; }
.ui-dlg-card { width: min(400px, 100%); padding: 22px 22px 18px; border-radius: 16px; background: var(--color-surface); color: var(--color-ink);
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.22); animation: ui-pop-in 300ms var(--ui-ease-out) both; }
.ui-dlg.out .ui-dlg-card { animation: ui-pop-out 140ms var(--ui-ease-in) both; }
.ui-dlg-card h3 { margin: 0 0 8px; font-size: 17px; font-weight: 700; }
.ui-dlg-card p { margin: 0 0 20px; font-size: 14px; line-height: 1.55; color: var(--color-ink-secondary); white-space: pre-line; word-break: keep-all; }
.ui-dlg-actions { display: flex; justify-content: flex-end; gap: 8px; }
.ui-dlg-actions button { min-height: 40px; padding: 0 16px; border-radius: 10px; font: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
  border: 1px solid var(--color-hairline-strong); background: var(--color-surface); color: var(--color-ink);
  transition: background-color 120ms var(--ui-ease-out), transform 120ms var(--ui-ease-out); }
.ui-dlg-actions button:hover { background: var(--color-canvas-soft); }
.ui-dlg-actions button:active { transform: scale(0.97); }
.ui-dlg-actions button.ok { border-color: var(--color-primary); background: var(--color-primary); color: #fff; }
.ui-dlg-actions button.ok:hover { background: var(--color-primary-active); }
.ui-dlg-actions button.danger { border-color: var(--color-danger); background: var(--color-danger); color: var(--color-canvas); }
.ui-dlg-actions button:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.ui-dlg.shake .ui-dlg-card { animation: ui-shake 320ms ease-in-out; }   /* 바깥을 눌러도 안 닫히는 확인창: 살짝 흔들어 알림 */

/* 4) 짧은 알림 (토스트): 페이지에 따로 없을 때만 */
.ui-toasts { position: fixed; right: 16px; bottom: 16px; z-index: 320; display: flex; flex-direction: column; gap: 8px; max-width: calc(100vw - 32px); }
.ui-toast { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-radius: 12px; font-size: 14px;
  background: var(--color-surface); color: var(--color-ink); border: 1px solid var(--color-hairline); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14);
  animation: ui-toast-in 260ms var(--ui-ease-out) both; }
.ui-toast.out { animation: ui-toast-out 160ms var(--ui-ease-in) both; }
.ui-toast i { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--color-success); }
.ui-toast.err i { background: var(--color-text-orange); }

@keyframes ui-fade-in { from { opacity: 0; } }
@keyframes ui-fade-out { to { opacity: 0; } }
@keyframes ui-pop-in { from { opacity: 0; transform: translateY(10px) scale(0.97); } }
@keyframes ui-pop-out { to { opacity: 0; transform: translateY(4px) scale(0.98); } }
@keyframes ui-toast-in { from { opacity: 0; transform: translateY(12px); } }
@keyframes ui-toast-out { to { opacity: 0; transform: translateX(12px); } }
@keyframes ui-shake { 20%, 60% { transform: translateX(-8px); } 40%, 80% { transform: translateX(8px); } }

/* 움직임 줄이기: 도는 것·흔들기 대신 정지 표시, 나타나기는 짧은 페이드만 */
@media (prefers-reduced-motion: reduce) {
  .ui-bar::after { animation: none; width: 100%; opacity: 0.7; }
  .ui-spin::before { animation-duration: 2.4s; }
  .ui-spin::after { animation: none; transform: scale(0.8); }
  .ui-wait-card, .ui-dlg-card, .ui-toast, .ui-dlg.out .ui-dlg-card, .ui-toast.out { animation-name: ui-fade-in; }
  .ui-dlg.out .ui-dlg-card, .ui-toast.out { animation-name: ui-fade-out; }
  .ui-dlg.shake .ui-dlg-card { animation: none; }
}

/* 첫 화면 준비 중: 반쯤 그려진 화면 대신 로딩 화면만 */
html.ui-booting body > :not(.ui-wait):not(.ui-dlg) { visibility: hidden; }

/* 5) 뼈대 화면: 목록을 불러오는 동안 회색 줄 (살짝 빛이 지나감) */
.ui-skel-box { display: flex; flex-direction: column; gap: 14px; padding: 12px 4px; }
.ui-skel-row { display: flex; align-items: center; gap: 12px; }
.ui-skel-row span { flex: 1; display: flex; flex-direction: column; gap: 8px; }
.ui-skel { display: block; border-radius: 6px; background: var(--color-canvas-soft);
  background-image: linear-gradient(90deg, transparent, color-mix(in srgb, var(--color-surface) 70%, transparent), transparent);
  background-size: 200% 100%; background-repeat: no-repeat; animation: ui-skel-shine 1.4s ease-in-out infinite; }
.ui-skel-av { width: 32px; height: 32px; border-radius: 50%; flex: none; }
.ui-skel-l1 { height: 12px; width: 55%; }
.ui-skel-l2 { height: 10px; width: 85%; opacity: 0.7; }
.ui-skel-row:nth-child(3n+2) .ui-skel-l1 { width: 40%; }
.ui-skel-row:nth-child(3n) .ui-skel-l2 { width: 65%; }
@keyframes ui-skel-shine { from { background-position: 150% 0; } to { background-position: -50% 0; } }
@media (prefers-reduced-motion: reduce) { .ui-skel { animation: none; background-image: none; } }
