/* UB Deck — 공용 UX 레이어 (로컬 ui/ · 클라우드 web/ 공용)
 * 모션 토큰 · 버튼/모달/토스트/진행바/스켈레톤 · 반응형 · 접근성
 * 정본은 ui/ux.css 이며 build.sh 가 web/ 로 복사한다.
 * ------------------------------------------------------------------ */

:root{
  --dur-1: 120ms;   /* 즉각 반응 (누름) */
  --dur-2: 200ms;   /* 기본 전환 */
  --dur-3: 320ms;   /* 등장·퇴장 */
  --dur-4: 520ms;   /* 강조 연출 */
  --ease: cubic-bezier(.22,.61,.36,1);          /* 감속 */
  --ease-spring: cubic-bezier(.34,1.42,.48,1);  /* 살짝 튀는 */
  --ring: 0 0 0 3px rgba(39,118,255,.45);
  --lift: 0 8px 24px rgba(0,0,0,.45);
}

/* 모션 최소화를 켠 사용자에게는 모든 연출을 끈다 (OS 설정 존중) */
@media (prefers-reduced-motion: reduce){
  :root{ --dur-1:1ms; --dur-2:1ms; --dur-3:1ms; --dur-4:1ms; }
  *,*::before,*::after{
    animation-duration:1ms !important; animation-iteration-count:1 !important;
    transition-duration:1ms !important; scroll-behavior:auto !important;
  }
}

/* ── 버튼: 호버 부상 · 누름 · 포커스 링 · 리플 ───────────────── */
button{
  position:relative; overflow:hidden;
  transition:background var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease),
             color var(--dur-2) var(--ease), transform var(--dur-1) var(--ease),
             box-shadow var(--dur-2) var(--ease), opacity var(--dur-2) var(--ease);
}
button:hover:not(:disabled){ transform:translateY(-1px) }
button:active:not(:disabled){ transform:translateY(0) scale(.97); transition-duration:var(--dur-1) }
button:disabled{ cursor:not-allowed }
button:focus-visible, select:focus-visible, input:focus-visible, textarea:focus-visible,
[tabindex]:focus-visible{ outline:none; box-shadow:var(--ring); border-radius:8px }
.ripple{
  position:absolute; border-radius:50%; transform:scale(0); pointer-events:none;
  background:currentColor; opacity:.28; animation:ub-ripple var(--dur-4) var(--ease) forwards;
}
@keyframes ub-ripple{ to{ transform:scale(2.6); opacity:0 } }

/* 버튼 안 스피너 (작업 중) */
.btn-busy{ pointer-events:none; opacity:.75 }
.btn-busy::after{
  content:""; position:absolute; inset:0; margin:auto; width:13px; height:13px;
  border:2px solid currentColor; border-right-color:transparent; border-radius:50%;
  animation:ub-spin .6s linear infinite;
}
.btn-busy > *{ visibility:hidden }
@keyframes ub-spin{ to{ transform:rotate(360deg) } }

/* ── 상단 전역 진행바 ────────────────────────────────────────── */
#ubProgress{
  position:fixed; top:0; left:0; height:3px; width:0; z-index:9999;
  background:linear-gradient(90deg, var(--accent,#2776FF), #7FB0FF, var(--accent,#2776FF));
  background-size:200% 100%; box-shadow:0 0 12px rgba(39,118,255,.7);
  transition:width var(--dur-3) var(--ease), opacity var(--dur-2) var(--ease);
  opacity:0; pointer-events:none;
}
#ubProgress.on{ opacity:1; animation:ub-flow 1.2s linear infinite }
#ubProgress.err{ background:#E5534B; box-shadow:0 0 12px rgba(229,83,75,.7); animation:none }
@keyframes ub-flow{ to{ background-position:-200% 0 } }

/* ── 토스트: 아이콘 · 실행취소 액션 · 슬라이드 등장 ──────────── */
#toast{
  display:flex !important; align-items:center; gap:10px;
  opacity:0; transform:translate(-50%,14px) scale(.96); pointer-events:none;
  transition:opacity var(--dur-3) var(--ease), transform var(--dur-3) var(--ease-spring);
  box-shadow:var(--lift);
}
#toast.show{ opacity:1; transform:translate(-50%,0) scale(1); pointer-events:auto }
#toast .ico{
  width:20px; height:20px; flex:0 0 20px; border-radius:50%; display:grid; place-items:center;
  font-size:12px; font-weight:700; color:#fff; animation:ub-pop var(--dur-4) var(--ease-spring);
}
#toast.ok  .ico{ background:#2E9E5B } #toast.ok  .ico::before{ content:"✓" }
#toast.err .ico{ background:#E5534B } #toast.err .ico::before{ content:"!" }
#toast.info .ico{ background:var(--accent,#2776FF) } #toast.info .ico::before{ content:"i" }
#toast .msg{ flex:1; min-width:0 }
#toast .act{
  flex:0 0 auto; background:transparent; border:1px solid var(--line,#2A2F39);
  color:var(--accent,#2776FF); font-weight:600; padding:5px 12px; border-radius:8px;
}
@keyframes ub-pop{ 0%{transform:scale(0)} 60%{transform:scale(1.25)} 100%{transform:scale(1)} }

/* ── 모달: 배경 페이드 + 카드 스프링 등장 ───────────────────── */
.modal{ opacity:0; transition:opacity var(--dur-2) var(--ease) }
.modal.on{ opacity:1 }
.modal .card{
  transform:translateY(18px) scale(.97); opacity:0;
  transition:transform var(--dur-3) var(--ease-spring), opacity var(--dur-3) var(--ease);
}
.modal.on .card{ transform:translateY(0) scale(1); opacity:1 }

/* 팝오버 메뉴 등장 */
.popmenu{ transform-origin:top left; animation:ub-pop-in var(--dur-2) var(--ease-spring) }
@keyframes ub-pop-in{ from{ opacity:0; transform:translateY(-6px) scale(.96) } }
.popmenu button{ transition:background var(--dur-1) var(--ease), padding-left var(--dur-2) var(--ease) }
.popmenu button:hover{ padding-left:16px }

/* ── 리스트 항목: 호버 부상 · 순차 등장 ─────────────────────── */
/* 편집기 머리말의 '/' 안내 — 이 메뉴가 있다는 걸 알려면 화면에 보여야 한다 */
.slashhint{ display:inline-block; padding:0 6px; border-radius:5px; font-weight:700;
  background:var(--accent,#2776FF); color:#fff; font-family:var(--mono,monospace) }

.ti{ transition:transform var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease),
     background var(--dur-2) var(--ease); animation:ub-rise var(--dur-3) var(--ease) backwards }
.ti:hover{ transform:translateX(3px); box-shadow:0 4px 14px rgba(0,0,0,.3) }
.ti:nth-child(1){animation-delay:0ms}   .ti:nth-child(2){animation-delay:40ms}
.ti:nth-child(3){animation-delay:80ms}  .ti:nth-child(4){animation-delay:120ms}
.ti:nth-child(5){animation-delay:160ms} .ti:nth-child(n+6){animation-delay:200ms}
@keyframes ub-rise{ from{ opacity:0; transform:translateY(8px) } }

/* ── 슬라이드 썸네일: 선택 강조 · 호버 ──────────────────────── */
.th{ transition:transform var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease),
     border-color var(--dur-2) var(--ease); animation:ub-rise var(--dur-3) var(--ease) backwards }
.th:hover{ transform:translateY(-2px) scale(1.02); box-shadow:0 6px 18px rgba(0,0,0,.45) }
.th.on{ box-shadow:0 0 0 1px var(--accent,#2776FF), 0 6px 20px rgba(39,118,255,.25) }

/* ── 무대(미리보기): 슬라이드 전환 ──────────────────────────── */
#stageInner{ transition:width var(--dur-2) var(--ease), height var(--dur-2) var(--ease) }
.slide-in{ animation:ub-slide-in var(--dur-3) var(--ease) }
.slide-in-rev{ animation:ub-slide-in-rev var(--dur-3) var(--ease) }
@keyframes ub-slide-in{ from{ opacity:0; transform:translateX(26px) } }
@keyframes ub-slide-in-rev{ from{ opacity:0; transform:translateX(-26px) } }

/* ── 스켈레톤 (로딩 자리표시) ───────────────────────────────── */
.skel{ border-radius:8px; background:linear-gradient(90deg,
  rgba(255,255,255,.05) 25%, rgba(255,255,255,.12) 37%, rgba(255,255,255,.05) 63%);
  background-size:400% 100%; animation:ub-shimmer 1.3s ease-in-out infinite }
.skel + .skel{ margin-top:8px }
.skel.row{ height:44px } .skel.line{ height:12px } .skel.card{ height:88px }
@keyframes ub-shimmer{ from{ background-position:100% 0 } to{ background-position:-100% 0 } }

/* ── 드롭존: 맥동 글로우 ────────────────────────────────────── */
#drop.on .box{ animation:ub-breathe 1.6s var(--ease) infinite }
@keyframes ub-breathe{
  0%,100%{ transform:scale(1); box-shadow:0 0 0 0 rgba(39,118,255,.35) }
  50%{ transform:scale(1.02); box-shadow:0 0 0 18px rgba(39,118,255,0) }
}

/* ── 탭 인디케이터 ──────────────────────────────────────────── */
.tabs .tab{ transition:color var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease) }
.tabs .tab:hover{ color:var(--tx,#E6E9EF) }

/* ── 저장 상태 점 ───────────────────────────────────────────── */
.savedot{ display:inline-block; width:7px; height:7px; border-radius:50%; margin-right:6px;
  background:var(--tx-3,#6B7484); transition:background var(--dur-2) var(--ease) }
.savedot.editing{ background:var(--warn,#E4B33C); animation:ub-pulse 1.1s ease-in-out infinite }
.savedot.saved{ background:#2E9E5B }
.savedot.error{ background:var(--err,#E5534B) }
@keyframes ub-pulse{ 50%{ opacity:.35 } }

/* ── 툴바: 그룹 구분 · 오버플로 ─────────────────────────────── */
.tgroup{ display:flex; align-items:center; gap:6px }
.tsep{ width:1px; height:22px; background:var(--line,#2A2F39); margin:0 4px; flex:0 0 1px }
#top button.icon{ padding:7px 9px; font-size:14px; line-height:1 }
#top button.icon .lbl{ margin-left:6px }

/* ── 슬라이드 그리드 전체보기 ───────────────────────────────── */
#gridView{ position:fixed; inset:0; z-index:380; background:rgba(11,13,17,.97);
  display:none; overflow:auto; padding:24px; backdrop-filter:blur(4px) }
#gridView.on{ display:block; animation:ub-fade var(--dur-3) var(--ease) }
#gridView .gv-head{ display:flex; align-items:center; gap:12px; margin-bottom:16px;
  color:var(--tx-2,#9AA4B2); font-size:13px }
#gridView .gv-grid{ display:grid; gap:14px;
  grid-template-columns:repeat(auto-fill, minmax(240px,1fr)) }
#gridView .gv-item{ position:relative; aspect-ratio:16/9; border-radius:8px; overflow:hidden;
  background:#fff; cursor:pointer; border:2px solid transparent;
  transition:transform var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
  animation:ub-rise var(--dur-3) var(--ease) backwards }
#gridView .gv-item:hover{ transform:translateY(-3px) scale(1.02); box-shadow:0 10px 30px rgba(0,0,0,.5) }
#gridView .gv-item.on{ border-color:var(--accent,#2776FF) }
#gridView .gv-item .n{ position:absolute; right:5px; bottom:4px; z-index:3; font-size:11px;
  background:rgba(11,13,17,.8); color:#fff; border-radius:5px; padding:1px 7px }
#gridView .gv-item .l{ position:absolute; left:5px; top:4px; z-index:3; font-size:10px;
  background:rgba(11,13,17,.8); color:#8FB6FF; border-radius:5px; padding:1px 6px }
@keyframes ub-fade{ from{ opacity:0 } }

/* ── 줌 컨트롤 ──────────────────────────────────────────────── */
#zoomBar{ position:absolute; right:14px; bottom:14px; display:flex; align-items:center; gap:6px;
  background:rgba(23,26,32,.9); border:1px solid var(--line,#2A2F39); border-radius:10px;
  padding:4px 6px; opacity:0; transform:translateY(6px);
  transition:opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease); z-index:6 }
#stage:hover #zoomBar, #zoomBar:focus-within{ opacity:1; transform:translateY(0) }
#zoomBar button{ padding:3px 9px; font-size:13px }
#zoomBar .val{ font-size:11px; color:var(--tx-3,#6B7484); min-width:38px; text-align:center }

/* ── 단축키 도움말 ──────────────────────────────────────────── */
#keysHelp .row{ display:flex; align-items:center; gap:12px; padding:7px 0;
  border-bottom:1px solid var(--line,#2A2F39); font-size:12.5px; color:var(--tx-2,#9AA4B2) }
#keysHelp kbd{ font-family:var(--mono,monospace); font-size:11px; background:var(--panel-2,#1E222A);
  border:1px solid var(--line,#2A2F39); border-bottom-width:2px; border-radius:6px;
  padding:2px 7px; color:var(--tx,#E6E9EF); min-width:26px; text-align:center; display:inline-block }
#keysHelp .k{ flex:0 0 190px; display:flex; gap:5px }

/* ── 에디터: 오류 줄 강조 ───────────────────────────────────── */
#ed.flash{ animation:ub-flash var(--dur-4) var(--ease) }
@keyframes ub-flash{ 0%{ background:rgba(229,83,75,.14) } 100%{ background:transparent } }

/* ── 반응형: 좁은 화면 ──────────────────────────────────────── */
@media (max-width: 1400px){
  #right{ width:150px !important; flex-basis:150px !important }
}
@media (max-width: 1180px){
  #right{ display:none }           /* 썸네일 패널 숨김 — 그리드 보기로 대체 */
  #top button .lbl{ display:none } /* 아이콘만 */
}
@media (max-width: 900px){
  #main{ flex-direction:column }
  #left{ width:100% !important; flex:0 0 42% !important; border-right:0;
         border-bottom:1px solid var(--line,#2A2F39) }
  #resizer{ display:none }
}

/* ── UI 글자 크기 (접근성) ──────────────────────────────────── */
/* 편집기는 textarea 와 색입힘 레이어가 '완전히 같은 글자 크기'여야 겹치지 않는다.
   한쪽만 키우면 두 층이 어긋나 글자가 겹쳐 보인다 — 반드시 함께 지정할 것. */
body[data-uiscale="l"]{ font-size:14.5px }
body[data-uiscale="l"] #ed,
body[data-uiscale="l"] .ed-hl,
body[data-uiscale="l"] .ed-gutter{ font-size:14px }
body[data-uiscale="xl"]{ font-size:16px }
body[data-uiscale="xl"] #ed,
body[data-uiscale="xl"] .ed-hl,
body[data-uiscale="xl"] .ed-gutter{ font-size:15.5px }

/* 썸네일 순서 이동 버튼 */
.thmv{ position:absolute; left:4px; top:4px; z-index:4; display:flex; flex-direction:column; gap:2px;
  opacity:0; transition:opacity var(--dur-2) var(--ease) }
.th:hover .thmv{ opacity:1 }
.thmv button{ padding:1px 5px; font-size:9px; line-height:1.3; border-radius:4px;
  background:rgba(15,17,21,.85); color:#8FB6FF; border:1px solid #2A313C }

/* ── 앱 라이트 모드 (슬라이드 테마와 별개인 '작업 화면' 테마) ── */
body.ub-light{
  --bg:#F5F6F8; --panel:#FFFFFF; --panel-2:#F0F2F5; --line:#DDE1E8;
  --tx:#14181F; --tx-2:#5A6472; --tx-3:#8A93A2;
  --lift:0 8px 24px rgba(20,24,31,.12);
  --ring:0 0 0 3px rgba(39,118,255,.30);
}
body.ub-light #banner{ background:#FFF6E0; color:#8A6100; border-bottom-color:#F0DFB4 }
body.ub-light #top,
body.ub-light #left,
body.ub-light #right,
body.ub-light #nav{ background:var(--panel); border-color:var(--line) }
body.ub-light #stage{ background:#EBEDF1 }
body.ub-light #stageInner{ box-shadow:0 8px 32px rgba(20,24,31,.18) }
body.ub-light .th{ border-color:transparent }
body.ub-light #warnbtn{ background:#FFF6E0; color:#8A6100; border-color:#F0DFB4 }
body.ub-light #warnbtn.none{ background:var(--panel-2); color:var(--tx-3); border-color:var(--line) }
body.ub-light .modal{ background:rgba(20,24,31,.42) }
body.ub-light #gridView{ background:rgba(240,242,245,.97) }
body.ub-light #gridView .gv-head{ color:var(--tx-2) }
body.ub-light #drop{ background:rgba(39,118,255,.08) }
body.ub-light .skel{ background:linear-gradient(90deg,
  rgba(20,24,31,.05) 25%, rgba(20,24,31,.10) 37%, rgba(20,24,31,.05) 63%); background-size:400% 100% }
body.ub-light .ti .del{ background:#FFECEA; border-color:#F3C6C1 }
body.ub-light .ti .tag.policy{ background:#E4EDFF; color:#215FCC }
body.ub-light .thmv button{ background:rgba(255,255,255,.92); color:#215FCC; border-color:var(--line) }
body.ub-light .th .no,
body.ub-light #gridView .gv-item .n{ background:rgba(20,24,31,.72) }
body.ub-light #gridView .gv-item .l{ background:rgba(20,24,31,.72) }

/* 편집기: 라이트에서 읽히도록 토큰 색 조정 */
body.ub-light .ed-gutter{ background:var(--panel-2); color:var(--tx-3); border-right-color:var(--line) }
body.ub-light .ed-hl{ color:var(--tx-2) }
body.ub-light .ed-hl .t-h1,
body.ub-light .ed-hl .t-title{ color:#14181F }
body.ub-light .ed-hl .t-meta{ color:#215FCC }
body.ub-light .ed-hl .t-lay{ color:#7A3EA8 }
body.ub-light .ed-hl .t-eyebrow{ color:#1B7A66 }
body.ub-light .ed-hl .t-key{ color:#9A6800 }
body.ub-light .ed-hl .t-num{ color:#B0530F }
body.ub-light .ed-hl .t-hex{ color:#1B7A66 }
body.ub-light .ed-hl .t-pipe,
body.ub-light .ed-hl .t-slide,
body.ub-light .ed-hl .t-cmt{ color:#9AA3B2 }
body.ub-light .ed-hl .ln-cur{ background:rgba(20,24,31,.05) }
body.ub-light .ed-wrap textarea{ caret-color:#14181F }
body.ub-light .ed-wrap textarea::selection{ background:rgba(39,118,255,.22) }

/* 문서 뷰어 */
body.ub-light .mdv code{ background:var(--panel-2); color:#215FCC }
body.ub-light .mdv pre{ background:var(--panel-2) }
body.ub-light .mdv blockquote{ background:var(--panel-2) }
