/* ═══════════ 모션 디테일 공통 (디자인 점검 부장 11-11, 사장님 「작은 디테일 모션을 변태급으로」) ═══════════
   규칙 표·사원용 클래스 규칙: 옵시디언 「Keepr 조직/모션 디테일 규칙 2026-11-11」
   원칙 ① 움직이는 것은 transform·opacity만(레이아웃 값 애니메이션 금지) ② 곡선은 --ease-out 하나가 기본. 예외 둘: 자리 옮기기 --ease-move, 스프링 --spring은 시트 올라옴·스위치 손잡이·완료 체크(버튼 완료·완료 화면·QR 인식)에만
        (11-12 「디자인 최종 확정본」 4절: 모달·라디오·뱃지는 스프링 → 기본 곡선)
        ③ 길이는 --t-micro(0.15s)·--t-base(0.25s)·--t-screen(0.35s)(+--t-move 0.4s), 페이드만 --t-fade ④ 서버 호출 0, 외부 도구 0
   이 파일은 맨 마지막에 읽혀 앞 파일의 모션만 덮어쓴다. 되돌리려면 index.html에서 이 파일과 js/motion.js 두 줄만 빼면 된다. */

/* ── 0. 모션 줄이기: 이동·크기 변화는 즉시, 나타남·사라짐은 0.2초 페이드 ── */
@media (prefers-reduced-motion:reduce){
  :root{--t-micro:0ms;--t-base:0ms;--t-screen:0ms;--t-move:0ms;--t-fade:200ms}
  .view.slide-r,.view.slide-l{animation:fadeIn var(--t-fade) var(--ease) both}
  .view.so-r,.view.so-l{animation:fadeOut var(--t-fade) var(--ease) both}
  .enter>*,.fade-in,.roll-in-up,.roll-in-down,.fl-msg,.err-in{animation:fadeIn var(--t-fade) var(--ease) both;animation-delay:0ms!important}
  .roll-out-up,.roll-out-down{animation:fadeOut var(--t-fade) var(--ease) both}
  .shake,.fl.err,.badge.pop,.tb.pop,.btn.done::after,.done-screen.on .done-moon{animation:none}
  .modal{transform:none}
}
@keyframes fadeOut{to{opacity:0}}

/* ── 1. 눌림: 손 닿는 순간(--t-micro) 작아지고, 떼면 --t-base로 제자리. 버튼·행·탭·칩·스위치는 components/theme에 있음 → 카드만 추가 ── */
.card[data-act].pressing{transform:scale(.98);opacity:.9;transition-duration:var(--t-micro)}

/* ── 2. 스위치: 손잡이가 스프링으로 미끄러짐(넘침 1.5% ≈ 0.3px, 느낌만) ── */
.sw i{transition:transform var(--t-base) var(--spring),width var(--t-base) var(--ease-out)}

/* ── 3. 체크박스(.ck): 켜질 때 체크 선이 그려짐(components.css .done .ck) — aria-checked로 쓰는 줄에도 같은 모션 ── */
[aria-checked="true"]>.ck{background:var(--blue);box-shadow:inset 0 0 0 1.5px var(--blue)}
[aria-checked="true"]>.ck path{stroke-dashoffset:0;transition-delay:40ms}
button.row[aria-checked].pressing .ck{transform:scale(.88);transition-duration:var(--t-micro)}

/* ── 4. 라디오(.rd): 테두리 색이 먼저 바뀌고(--t-micro) 가운데 점이 스프링으로 채워짐(--t-base) ── */
.rd{position:relative;width:24px;height:24px;border-radius:50%;box-shadow:inset 0 0 0 1.5px var(--label-3);flex:none;transition:box-shadow var(--t-micro) var(--ease)}
.rd::after{content:"";position:absolute;inset:6px;border-radius:50%;background:var(--blue);transform:scale(0);transition:transform var(--t-base) var(--ease-out)}
[aria-checked="true"] .rd{box-shadow:inset 0 0 0 1.5px var(--blue)}
[aria-checked="true"] .rd::after{transform:scale(1)}
button.row[aria-checked].pressing .rd{transform:scale(.9);transition:transform var(--t-micro) var(--ease-out)}

/* ── 5. 입력 칸: 포커스 링은 --t-micro, 오류는 색 + 4px 살짝 흔들림 + 메시지가 아래서 떠오름(「입력 UI 시안 11-10」) ── */
:root{--danger-ring:rgba(185,58,50,.18)}  /* --danger 색 자체는 base.css 한 곳에서 정함(11-12) */
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--danger-ring:rgba(255,138,128,.2)}}
:root[data-theme="dark"]{--danger-ring:rgba(255,138,128,.2)}
.fl-in{transition:box-shadow var(--t-micro) var(--ease-out),background-color var(--t-micro) var(--ease)}
.fl-lb{transition:transform var(--t-base) var(--ease-out),color var(--t-micro) var(--ease)}
.fl.err .fl-in,.fl.err .fl-in:-webkit-autofill{box-shadow:inset 0 0 0 1.5px var(--danger)}
.fl.err .fl-in:focus{box-shadow:inset 0 0 0 1.5px var(--danger),0 0 0 4px var(--danger-ring)}
.fl.err .fl-lb{color:var(--danger)}
.fl.err{animation:nudge var(--t-screen) var(--ease-out)}
@keyframes nudge{20%{transform:translateX(-4px)}45%{transform:translateX(3px)}70%{transform:translateX(-2px)}}
.fl-msg{display:flex;align-items:flex-start;gap:6px;margin:6px 4px 0;font:400 13px/19px var(--font);color:var(--danger);word-break:keep-all;animation:fadeDown var(--t-base) var(--ease-out) both}
.fl-msg svg{flex:none;width:16px;height:16px;margin-top:1.5px;stroke-width:2}
.fl-msg.ok{color:var(--label-2)}
.fl-msg.ok svg{color:var(--blue)}
.fl-msg.wait{color:var(--label-3)}
.fl-msg:empty{display:none}
.err-in{animation:fadeDown var(--t-base) var(--ease-out) both}
@keyframes fadeDown{from{opacity:0;transform:translateY(-4px)}}
/* 맞음 표시: 칸 오른쪽 체크가 스프링으로 톡 */
.fl-ic{position:absolute;right:16px;top:18px;width:20px;height:20px;color:var(--blue);opacity:0;transform:scale(.6);pointer-events:none;transition:opacity var(--t-micro) var(--ease),transform var(--t-base) var(--spring)}
.fl.ok .fl-ic{opacity:1;transform:none}

/* ── 6. 버튼 로딩 → 완료: .busy(글자 사라지고 스피너, components.css) → .done(체크가 스프링으로 톡, 0.9초 뒤 원래대로 — KM.busy) ── */
.btn.done .lbl,.btn.done .spinner{opacity:0}
.btn.done::after{content:"";position:absolute;left:50%;top:50%;width:22px;height:22px;margin:-11px 0 0 -11px;background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E") center/contain no-repeat;
  animation:popIn var(--t-base) var(--spring) both}
@keyframes popIn{from{transform:scale(.5);opacity:0}}
.btn.shake{animation:shake var(--t-screen) var(--ease)}

/* ── 7. 뱃지: 개수가 늘 때 한 번 톡(KM.badge / KM.pop). 0이면 숨김 ── */
.badge:empty,.tb:empty{display:none}
.badge.pop,.tb.pop{animation:pop var(--t-base) var(--ease-out)}
@keyframes pop{from{transform:scale(.6)}}

/* ── 8. 순차 등장(.enter): 40ms 간격·앞 8개까지만 떠오르고, 9번째부터는 같은 시점에 페이드(겹침·늘어짐 방지) ── */
.enter>:nth-child(n+9){animation:fadeIn var(--t-base) var(--ease) both;animation-delay:280ms!important}

/* ── 9. 완료 체크 바운스: 완료 화면 달과 QR 인식 뱃지만(작게, 완료 때만) ── */
.done-screen.on .done-moon{animation:pop var(--t-screen) var(--spring) both}
.cam-feed.got .got-badge{transition:opacity var(--t-micro) var(--ease),transform var(--t-base) var(--spring)}

/* ── 10. 숫자 바뀜: .roll 상자 안에서 옛 숫자가 밀려 나가고 새 숫자가 들어옴(KM.roll). .stp .v와 같은 구조 ── */
.roll{position:relative;display:inline-grid;overflow:hidden;vertical-align:bottom}
.roll>span{grid-area:1/1}
/* 낙관적 업데이트 중(서버 답 전) 반투명 표시 — 서버가 거절하면 KM.optimistic이 되돌리고 토스트 */
.pending{opacity:.55;transition:opacity var(--t-base) var(--ease)}

/* ── 11. 바텀시트: 올라올 때 스프링(넘침 1.5% ≈ 5~8px), 내려갈 때는 이즈 아웃. 손잡이 끌어 닫기는 nav.js에 있음 ── */
.sheet{transition:transform var(--t-screen) var(--spring)}
.sheet-root.closing .sheet{transition:transform var(--t-screen) var(--ease-out)}

/* ── 12. 모달(되돌리기 어려운 확인 — 퇴사 처리·서류 확정·결제): 가운데서 0.9→1 스프링 확대 + 페이드, 닫힐 때 0.96으로 줄며 페이드 ── */
.modal-root{position:absolute;inset:0;z-index:96;display:grid;place-items:center;padding:16px;visibility:hidden}
.modal-root.on{visibility:visible}
.modal-root .scrim{transition:opacity var(--t-fade) var(--ease)}
.modal-root.open .scrim{opacity:1}
.modal{position:relative;width:min(290px,100%);border-radius:var(--r-card,24px);overflow:hidden;background:var(--cell-sheet);color:var(--label);box-shadow:0 12px 40px rgba(0,0,0,.18);
  opacity:0;transform:scale(.95);transition:transform var(--t-base) var(--ease-out),opacity var(--t-fade) var(--ease)}
.modal-root.open .modal{opacity:1;transform:none}
.modal-root.closing .modal{opacity:0;transform:scale(.96);transition:transform var(--t-base) var(--ease-out),opacity var(--t-fade) var(--ease)}
.modal-t{margin:0;padding:20px 20px 0;font:600 17px/24px var(--font);text-align:center;word-break:keep-all}
.modal-s{margin:0;padding:4px 20px 0;font:400 13px/19px var(--font);color:var(--label-2);text-align:center;text-wrap:balance;word-break:keep-all}
.modal-s[hidden]{display:none}
.modal-acts{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;margin-top:20px;border-top:.5px solid var(--sep)}
.modal-acts.stack{grid-auto-flow:row}
.modal-acts button{display:flex;align-items:center;justify-content:center;flex-direction:row;padding:0;text-align:center;height:44px;font:400 17px/24px var(--font);color:var(--blue);transition:background-color var(--t-micro) var(--ease)}
.modal-acts button+button{border-left:.5px solid var(--sep)}
.modal-acts.stack button+button{border-left:0;border-top:.5px solid var(--sep)}
.modal-acts button.modal-ok{font-weight:600} /* base.css의 .main(행 안 글줄 칸)과 이름이 겹쳐 확인 버튼이 왼쪽·세로로 어긋나던 것(11-12 사장님 신고) */
.modal-acts button.danger{color:var(--danger)}
.modal-acts button.pressing{transform:none;opacity:1;background:var(--press);transition-duration:var(--t-micro)}

/* ── 13. 스낵바(되돌리기 버튼이 붙은 확인 — 직원 삭제·메시지 삭제): 아래서 16px 떠오르며 페이드, 5초 뒤 내려감(KM.snack) ── */
/* 11-12: 폰은 떠 있는 탭바(높이 56, 아래 --tb-bottom) 위 12에 놓는다. 전에는 옛 탭바 기준(49+16)이라 탭바와 3px 겹쳤음 */
.snack{position:absolute;left:16px;right:16px;bottom:calc(var(--tb-bottom,12px) + 56px + 12px);z-index:94;display:flex;align-items:center;gap:8px;min-height:52px;padding:4px 4px 4px 16px;border-radius:var(--r-in,16px);
  background:var(--toast);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);color:var(--on-navy);font:400 15px/22px var(--font);box-shadow:0 4px 16px rgba(0,0,0,.12);
  opacity:0;transform:translateY(16px);transition:transform var(--t-base) var(--ease-out),opacity var(--t-fade) var(--ease);pointer-events:none}
.snack.on{opacity:1;transform:none;pointer-events:auto}
.snack span{flex:1;word-break:keep-all}
.snack button{position:relative;flex:none;height:44px;padding:0 12px;border-radius:var(--r-btn,12px);font:600 15px/22px var(--font);color:var(--brand-gold);transition:background-color var(--t-micro) var(--ease)}
.snack button.pressing{transform:none;opacity:1;background:rgba(255,255,255,.12)}
#app.tab-hidden .snack{bottom:calc(var(--sb) + 136px)}
#app:has(.snack.on) .toast{bottom:calc(var(--tb-bottom,12px) + 56px + 12px + 52px + 12px)}
#app.tab-hidden:has(.snack.on) .toast{bottom:calc(var(--sb) + 136px + 64px)}
/* 11-12 대리 소 편차 1: 넓은 화면에서는 화면 전체가 아니라 본문 영역(옆 메뉴 오른쪽)의 가운데 — 토스트·오프라인 띠와 같은 기준 */
@media (min-width:600px){.snack{left:calc(var(--side,0px) + (100% - var(--side,0px)) / 2);right:auto;bottom:calc(var(--sb) + 24px);width:min(420px,calc(100% - 32px));transform:translate(-50%,16px)}.snack.on{transform:translate(-50%,0)}
  #app:has(.snack.on) .toast{bottom:calc(var(--sb) + 24px + 52px + 12px)}}

/* 눌리는 범위 44 이상(모양은 그대로): 스낵바 되돌리기 */
.snack button::after{content:"";position:absolute;inset:0 -4px}

/* ── 15. 마우스 호버·키보드 포커스 (11-12 「디자인 최종 확정본」 5절 2~4: 웹앱이라 PC 마우스·키보드에서도 상태가 보여야 함) ──
   호버는 마우스가 있는 기기에서만(@media hover:hover). 폰에는 영향 없음. 눌림(.pressing)이 호버보다 뒤에 와서 누르면 눌림 모양이 이긴다 */
@media (hover:hover){
  .btn:not(:disabled):not(.pressing):hover,.gate-btn:not(:disabled):not(.pressing):hover{opacity:.9}
  .btn.sec:not(:disabled):not(.pressing):hover{opacity:1;background:color-mix(in srgb,var(--blue) 18%,transparent)}
  .btn.plain:not(:disabled):not(.pressing):hover{opacity:1;background:color-mix(in srgb,var(--blue) 8%,transparent)}
  .chip:not([aria-pressed="true"]):hover{background:color-mix(in srgb,var(--blue) 18%,transparent)}
  .chip[aria-pressed="true"]:hover{opacity:.9}
  div.row[data-act]:hover,.ck-row:hover{background:var(--press)}
  .card[data-act]{cursor:pointer}
  .stp button:not(:disabled):hover,.weekbar button:hover,.dp-nav:hover,.dp-d:not(.sel):not(:disabled):hover,.modal-acts button:hover{background:var(--press)}
  .snack button:hover{background:rgba(255,255,255,.12)}
  .sheet-x:hover span,.sheet-back:hover span{background:color-mix(in srgb,var(--label) 16%,transparent)}
  .nav-back:hover,.nav-act:hover{filter:brightness(.96)}
  .gate-link:hover,.auth-link:hover{text-decoration:underline;text-underline-offset:3px}
}
@media (hover:hover) and (min-width:600px){.tab:not(.on):hover{background:var(--press)}}
/* 포커스 링: 묶음(.group)·시트·모달·세그먼트 안은 바깥이 잘리므로 안쪽으로 그린다 */
.group :focus-visible,.sheet-body .row:focus-visible,.seg button:focus-visible,.modal-acts button:focus-visible,.stp button:focus-visible{outline-offset:-2px}
/* 행 안 입력칸: 상자 테두리 대신 로그인 입력칸과 같은 안쪽 1.5px 선 */
.field:focus-visible{outline:none;box-shadow:inset 0 0 0 1.5px var(--blue)}

/* ── 16. 툴팁(js/motion.js 맨 아래): 아이콘만 있는 버튼 이름. 토스트와 같은 어두운 바탕, 13/20, 0.15초 페이드. 누를 수 없고(pointer-events:none) 화면 밖으로 안 나감 ── */
.tip{position:fixed;left:0;top:0;z-index:2000;max-width:240px;padding:4px 8px;border-radius:var(--r-ctl,8px);background:var(--toast);color:var(--on-navy);font:400 13px/20px var(--font);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  pointer-events:none;opacity:0;transition:opacity var(--t-micro) var(--ease)}
.tip.on{opacity:1}
