:root{
    /* 2026-09-21 3차 리빌드(30번 항목 직후): "1순위(가독성/통일성)+3순위(화려함)를 같이"
       요청에 따라 쿨그레이 배경 + 채도를 낮춘 코발트블루 브랜드 컬러로 전면 리빌드.
       --muted/--amber/--line은 WCAG AA 대비율(4.5:1 / 4.5:1 / 시인성 개선)을 계산해서
       확보한 값이다. --steel(브랜드, UI 크롬 전반)과 --pass(합격 상태 전용, 초록 유지)는
       29번 항목에서 처음 분리한 패턴을 그대로 계승 — 브랜드가 바뀌어도 "초록=합격" 관례는
       유지한다. 반경 스케일(--radius-sm/md/lg/pill)도 이번에 추가해 새 컴포넌트(벤토
       카드·글래스 카드)에 일관되게 사용한다. */
    --bg:#F4F5F7;
    --surface:#FFFFFF;
    --ink:#16181D;
    --muted:#5F6473;
    --steel:#3D5A80;
    --steel-dark:#2C4260;
    --steel-soft:#E3E9F1;
    --pass:#2F7350;
    --pass-soft:#E1F0E7;
    --fail:#C4432E;
    --fail-soft:#FBE6E1;
    --amber:#966018;
    --amber-soft:#F5E8D6;
    --line:#BFC4CD;
    --radius:8px;
    --radius-sm:8px;
    --radius-md:12px;
    --radius-lg:18px;
    --radius-pill:999px;
    --card-shadow:0 1px 2px rgba(22,24,29,.05), 0 6px 18px rgba(22,24,29,.06);
    --glass-radius:18px;
  }
  *{box-sizing:border-box;}
  html,body{margin:0;padding:0;}
  /* 2026-09-23(10): 맨 끝까지 스크롤한 뒤 더 당기면 페이지 전체가 튕기며(러버밴드) 상단 고정 바까지 같이
     밀려 움직였다(iOS 사파리, 맥 트랙패드). 문서 전체의 튕김을 끈다 — 모달 안 스크롤은 기존 contain 설정 유지.
     안드로이드 크롬의 "당겨서 새로고침"도 함께 꺼지므로 새로고침은 대시보드의 새로고침 버튼을 쓴다. */
  html,body{overscroll-behavior-y:none;}
  /* 2026-09-23(10): 모바일에서 로그인 입력칸을 누르면 키보드가 올라오며 화면이 밀려, 로그인 화면(고정 레이어)
     아래로 뒤쪽 앱 화면(이중점검 입력칸 등)이 드러났다. 로그인 화면이 떠 있는 동안에는 뒤쪽 앱을 보이지
     않게(visibility — 레이아웃은 유지해서 로그인 직후 탭 표시기 등의 위치 계산에 영향 없음) 하고, 드러나는
     바탕도 로그인 화면과 같은 검정으로 채운다. */
  /* 협력사 공유 화면(share-mode)은 로그인 화면을 .hidden 없이 display:none으로만 숨기므로 제외한다. */
  html:not(.share-mode):has(#loginScreen:not(.hidden)),
  html:not(.share-mode):has(#loginScreen:not(.hidden)) body{background:#07090d !important;}
  html:not(.share-mode) body:has(#loginScreen:not(.hidden)) > *:not(#loginScreen):not(.login-transition-overlay):not(.login-motion):not(#toast){visibility:hidden;}
  /* read-only vendor share view: hide the entire normal app, show only #shareView */
  /* the photo lightbox and the toast live at body level (outside #shareView) but must still
     work on the vendor share page — without these exceptions clicking a photo or copying the
     link would silently do nothing there */
  html.share-mode body > *:not(#shareView):not(#photoLightbox):not(#toast){display:none !important;}
  html.share-mode body{padding-bottom:0;}
  .share-view{min-height:100vh;padding:0 0 40px;}
  .share-view.hidden{display:none !important;}
  .share-view-header{
    display:flex;align-items:center;gap:12px;padding:16px 18px;background:var(--surface);
    border-bottom:1px solid var(--line);position:sticky;top:0;z-index:5;
  }
  .share-logo{width:36px;height:36px;object-fit:contain;flex-shrink:0;}
  .share-header-text{flex:1;min-width:0;}
  .share-brand-title{font-weight:800;font-size:14.5px;color:var(--ink);}
  .share-brand-sub{font-size:11.5px;color:var(--muted);margin-top:1px;letter-spacing:.04em;}
  .share-view-header .modal-x-close{flex-shrink:0;}
  .share-view-body{max-width:640px;margin:0 auto;padding:18px 16px 10px;}
  .share-view-footer-actions{max-width:640px;margin:0 auto;padding:0 16px 30px;}
  .notice-actions{display:flex;gap:8px;margin-bottom:16px;}
  .notice-actions .btn-ghost{
    flex:1;display:flex;align-items:center;justify-content:center;gap:6px;width:auto;
  }
  .notice-actions .btn-ghost svg{width:15px;height:15px;flex-shrink:0;}
  .share-notice{
    background:var(--steel-soft);color:var(--steel);border-radius:12px;padding:10px 14px;
    font-size:12px;font-weight:600;margin-bottom:16px;line-height:1.5;
  }
  .share-state{text-align:center;padding:80px 24px;color:var(--muted);font-size:13.5px;}
  .share-state svg{width:34px;height:34px;margin-bottom:12px;color:#B6BAC4;}

  /* ---------- formal "부적합 발생 통보서" notice document (share-view) ---------- */
  .notice-doc{
    background:#fff;border:1.5px solid var(--ink);border-radius:4px;overflow:hidden;
    box-shadow:var(--card-shadow);
  }
  .notice-head{
    display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1.5px solid var(--ink);
    flex-wrap:wrap;
  }
  .notice-logo{height:26px;width:auto;object-fit:contain;flex-shrink:0;}
  .notice-head-title{
    font-size:17px;font-weight:800;color:var(--ink);letter-spacing:.04em;flex:1;min-width:150px;
  }
  .notice-head-meta{
    display:flex;flex-direction:column;gap:2px;border-left:1px solid var(--line);padding-left:12px;
  }
  .nh-row{display:flex;gap:8px;font-size:11px;color:var(--muted);}
  .nh-row span:first-child{font-weight:700;color:var(--ink);min-width:44px;}
  .notice-table{width:100%;border-collapse:collapse;font-size:12.5px;}
  .notice-table th, .notice-table td{
    border:1px solid var(--line);padding:8px 10px;text-align:left;vertical-align:middle;
  }
  .notice-table th{
    background:var(--surface);color:var(--muted);font-weight:700;width:78px;white-space:nowrap;
  }
  .notice-table td{color:var(--ink);position:relative;}
  .notice-stamp{
    display:inline-block;margin-left:10px;padding:2px 10px;border:2px solid var(--fail);border-radius:4px;
    color:var(--fail);font-weight:800;font-size:11.5px;letter-spacing:.06em;transform:rotate(-4deg);
    vertical-align:middle;
  }
  .notice-stamp.rwk{border-color:var(--amber);color:var(--amber);}
  .notice-defect-types{padding:12px 16px;border-bottom:1px solid var(--line);}
  .ndt-label{display:block;font-size:11px;font-weight:700;color:var(--muted);margin-bottom:8px;}
  .ndt-list{display:flex;flex-wrap:wrap;gap:6px;}
  .ndt-pill{
    padding:4px 10px;border-radius:20px;border:1px solid var(--line);font-size:11.5px;color:var(--muted);
    background:var(--surface);
  }
  .ndt-pill.active{border-color:var(--fail);color:var(--fail);background:var(--fail-soft);font-weight:700;}
  .notice-req{
    padding:10px 16px;font-size:12px;color:var(--ink);background:var(--bg);border-bottom:1px solid var(--line);
    line-height:1.6;
  }
  .notice-content{padding:14px 16px 16px;}
  .notice-content-title{font-size:12.5px;font-weight:800;color:var(--fail);margin-bottom:8px;}
  .notice-content-text{font-size:13px;color:var(--ink);line-height:1.6;white-space:pre-wrap;margin-bottom:10px;}
  .notice-footer{
    padding:10px 16px;font-size:10.5px;color:var(--muted);border-top:1px dashed var(--line);text-align:center;
  }
  .notice-supplement{margin-top:16px;}
  .notice-supplement-title{font-size:12px;font-weight:700;color:var(--muted);margin-bottom:6px;}
  @media (max-width:480px){
    .notice-head{flex-direction:column;align-items:flex-start;}
    .notice-head-meta{border-left:none;border-top:1px solid var(--line);padding-left:0;padding-top:8px;width:100%;}
    .notice-table th{width:64px;font-size:11px;}
  }

  body{
    background:var(--bg);
    color:var(--ink);
    font-family:'Noto Sans KR',system-ui,sans-serif;
    font-size:15px;
    line-height:1.5;
    -webkit-tap-highlight-color:transparent;
    min-height:100vh;
    padding-bottom:78px;
    /* 2026-09-22 추가: 특히 모바일 기기에서 작은 글자(JetBrains Mono 등 고정폭 폰트 혼용
       구간)가 기기별 폰트 렌더러 차이로 흐릿하거나 겹쳐 보이는 문제를 줄이기 위한 전역
       안티앨리어싱 힌트. */
    -webkit-font-smoothing:antialiased;
    -moz-osx-font-smoothing:grayscale;
  }
  .mono{font-family:'JetBrains Mono','Noto Sans KR',monospace;}
  button, input, select, textarea{font-family:inherit;font-size:inherit;color:inherit;}
  button{cursor:pointer;}
  h1,h2,h3{margin:0;font-weight:700;}

  /* ---------- Top bar ---------- */
  .topbar{
    position:sticky;top:0;z-index:20;
    background:var(--surface);
    color:var(--ink);
    border-bottom:1px solid var(--line);
    display:flex;align-items:center;
    padding:12px 112px 12px 18px;
    gap:12px;
  }
  .brand{display:flex;align-items:center;gap:12px;min-width:0;flex:1;}
  .brand > div{min-width:0;}
  .brand-mark{
    height:34px;width:auto;flex-shrink:0;display:block;
    cursor:pointer;transition:transform .12s;border-radius:6px;
  }
  .brand-mark:active{transform:scale(.92);}
  .brand-mark:focus-visible{outline:2px solid var(--steel);outline-offset:2px;}
  .brand-text{font-weight:800;font-size:15.5px;letter-spacing:.01em;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block;}
  .brand-sub{font-size:11.5px;color:var(--muted);font-weight:500;display:block;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
  /* 2026-09-19 후속: 타이틀 옆 시스템 전환 화살표 — 드롭다운 메뉴가 이 줄을 기준으로
     절대위치로 뜨도록 position:relative를 추가(레이아웃에는 영향 없음, 새 포지셔닝 컨텍스트만
     생김). */
  .brand-title-row{position:relative;display:flex;align-items:center;gap:4px;min-width:0;}
  .brand-switch-btn{
    flex-shrink:0;width:20px;height:20px;border:none;background:transparent;color:var(--muted);
    display:flex;align-items:center;justify-content:center;border-radius:6px;cursor:pointer;padding:0;
  }
  .brand-switch-btn svg{width:15px;height:15px;}
  .brand-switch-btn:active{transform:scale(.9);background:var(--steel-soft);}
  .brand-switch-menu{
    position:absolute;top:calc(100% + 8px);left:0;z-index:25;
    background:var(--surface);border:1px solid var(--line);border-radius:12px;
    padding:6px;box-shadow:0 8px 24px rgba(22,24,29,.18);min-width:230px;
  }
  .brand-switch-menu.hidden{display:none;}
  .brand-switch-item{
    display:block;width:100%;text-align:left;padding:9px 10px;border:none;background:transparent;
    color:var(--ink);font-size:12.5px;font-weight:700;border-radius:8px;cursor:pointer;
    white-space:nowrap;
  }
  .brand-switch-item:active{background:var(--steel-soft);}
  .profile-badge{
    position:absolute;top:50%;right:18px;transform:translateY(-50%);
    width:38px;height:38px;border-radius:50%;border:none;background:var(--steel);color:#fff;
    display:flex;align-items:center;justify-content:center;font-weight:700;font-size:13px;
    flex-shrink:0;box-shadow:0 2px 6px rgba(61,90,128,.3);
  }
  #orgChartBtn.profile-badge{ right:64px; }
  .profile-badge svg{width:19px;height:19px;}

  /* ---------- Bottom navigation ---------- */
  /* ---------- Bottom nav — floating "liquid glass" pill (iOS 26 스타일) ----------
     예전엔 화면 하단에 딱 붙는 불투명 바였는데, 화면 위에 살짝 띄워진 반투명 유리 알약
     모양으로 바꿨다. 뒤 콘텐츠가 blur를 통해 살짝 비치고, 위쪽에 은은한 하이라이트를 얹어서
     빛이 유리 표면에 맺힌 느낌을 낸다. 선택된 탭 아래에는 물방울처럼 둥글고 광택이 도는
     인디케이터가 있는데, 이건 고정 위치가 아니라 js(main.js의 positionTabIndicator)가
     현재 활성 탭 버튼의 실제 위치/너비를 측정해서 그 자리로 부드럽게 흘러가듯 이동시킨다 —
     탭 버튼들이 전부 flex:1(균등폭)+min-width:0 이라 폰트 로딩 등으로 폭이 흔들릴 요소가
     없고(이전 조직도 버그처럼 좌표 측정이 타이밍에 흔들리는 구조가 아님), 관리자 전용 탭이
     보였다 안 보였다 해서 폭이 바뀌는 경우까지 ResizeObserver로 자동 재계산한다. */
  .bottom-nav{
    position:fixed;left:50%;bottom:calc(14px + env(safe-area-inset-bottom));z-index:30;
    transform:translateX(-50%);
    width:calc(100% - 28px);max-width:460px;
    display:flex;align-items:center;gap:0;
    padding:7px;border-radius:28px;overflow:hidden;
    background:rgba(255,255,255,.6);
    -webkit-backdrop-filter:blur(22px) saturate(180%);
    backdrop-filter:blur(22px) saturate(180%);
    border:1px solid rgba(255,255,255,.6);
    box-shadow:0 12px 32px rgba(22,24,29,.22), 0 2px 6px rgba(22,24,29,.1), inset 0 1px 0 rgba(255,255,255,.75);
  }
  /* 유리 표면 위쪽에 빛이 스치는 듯한 은은한 광택 오버레이 */
  .bottom-nav::before{
    content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
    background:linear-gradient(180deg, rgba(255,255,255,.4), rgba(255,255,255,0) 45%);
  }
  .tab-indicator{
    position:absolute;top:7px;left:0;bottom:7px;width:0;
    border-radius:20px;z-index:0;pointer-events:none;
    background:linear-gradient(180deg, rgba(255,255,255,.95), rgba(255,255,255,.55));
    box-shadow:0 3px 10px rgba(61,90,128,.25), inset 0 1px 1px rgba(255,255,255,.95), inset 0 -2px 3px rgba(61,90,128,.1);
    transition:transform .4s cubic-bezier(.34,1.56,.64,1), width .4s cubic-bezier(.34,1.56,.64,1);
  }
  .bottom-nav .tab-btn{
    position:relative;z-index:1;
    flex:1 1 0;min-width:0;
    border:none;background:transparent;color:#5F6473;
    display:flex;flex-direction:column;align-items:center;gap:2px;
    padding:8px 2px;font-size:10.5px;font-weight:600;white-space:nowrap;
    border-radius:20px;transition:color .25s;
  }
  .bottom-nav .tab-btn svg{width:20px;height:20px;transition:transform .3s cubic-bezier(.34,1.56,.64,1);}
  .bottom-nav .tab-btn span{overflow:hidden;text-overflow:ellipsis;max-width:100%;}
  .bottom-nav .tab-btn.active{color:var(--steel-dark);}
  .bottom-nav .tab-btn.active svg{transform:scale(1.08);}

  /* 하단 탭이 화면에 붙는 바가 아니라 살짝 띄워진 알약 모양으로 바뀌면서 차지하는 공간이
     늘어난 만큼(패딩+간격+안전영역), 본문이 그 밑에 가려지지 않도록 여백을 넉넉히 잡는다. */
  main{max-width:1100px;margin:0 auto;padding:18px 14px calc(96px + env(safe-area-inset-bottom));}

  /* 2026-09-19 후속: 이중점검 "검사 기록 저장" 하단 플로팅 버튼 — 하단 탭(bottom-nav) 바로
     위에 항상 떠 있다가, 원본 버튼(#submitBtn)이 실제로 화면에 보이면(끝까지 스크롤) 사라진다.
     bottom 값은 js/input-tab.js의 setupFloatingSaveBtn()이 bottom-nav의 실제 높이를 재서
     매번 다시 계산해 인라인 스타일로 넣어준다(여기 기본값은 그 계산이 아직 안 됐을 때의
     폴백). 원본 버튼과 똑같은 색/모양을 쓰되 살짝 떠 있는 느낌을 주기 위해 그림자를 더 준다. */
  .floating-save-btn{
    position:fixed;left:50%;transform:translateX(-50%);
    bottom:calc(14px + env(safe-area-inset-bottom) + var(--nav-h, 66px) + 10px); /* 2026-09-23(5): 탭바(.bottom-nav)와 같은 기준 */
    z-index:29; /* bottom-nav(30)보다 한 단계 아래 — 겹쳐도 하단 탭이 항상 위 */
    width:calc(100% - 28px);max-width:460px;
    /* 2026-09-19 후속(버그 수정): 원래 var(--mono-ink)를 썼는데, 이 커스텀 속성은
       #tab-input.mono-input 안에서만 정의돼 있다(아래 "MONOCHROME INPUT PAGE" 섹션 참고). 이
       버튼은 <nav> 바로 다음, #tab-input 바깥(형제 요소)에 있어서 그 변수를 상속받지 못해
       background가 계산 안 된 채로(투명) 렌더링되고 있었다 — 실제 저장 버튼과 같은 색을 쓰려는
       의도였으니, 변수 참조 대신 같은 값(#3D5A80)을 직접 적어서 위치와 무관하게 항상 보이도록 함. */
    padding:14px;border:none;border-radius:16px;background:#3D5A80;color:#fff;
    font-weight:700;font-size:14.5px;box-shadow:0 10px 26px rgba(22,24,29,.3);
    transition:opacity .18s, transform .18s;
  }
  .floating-save-btn:active{transform:translateX(-50%) scale(.98);}
  .floating-save-btn:disabled{background:#B6BAC4;box-shadow:none;}
  .floating-save-btn.hidden{
    opacity:0;pointer-events:none;transform:translateX(-50%) translateY(10px);
  }

  /* ---------- Desktop: dashboard fills the screen ---------- */
  body.is-desktop main{max-width:none;}
  body.is-desktop #tab-dashboard{max-width:1900px;margin:0 auto;padding:0 10px;}
  body.is-desktop #tab-dashboard.active{
    display:flex;flex-direction:column;gap:16px;
    min-height:calc(100vh - 74px - 32px);
    padding-bottom:18px;
  }
  body.is-desktop #tab-dashboard .stat-row{grid-template-columns:repeat(5,1fr);}
  body.is-desktop #tab-dashboard .panel:last-child{
    flex:1;display:flex;flex-direction:column;min-height:0;margin-bottom:0;
  }
  body.is-desktop #tab-dashboard .panel:last-child .record-list-scroll{
    flex:1;overflow-y:auto;
  }

  /* ---------- Desktop: 좌측 사이드바 레이아웃 (2026-09-21 추가) ----------
     모바일은 기존 상단바 + 하단 플로팅 탭바를 그대로 유지하고(아래 규칙은 전부 body.is-desktop
     스코프 안에만 있어 모바일에는 전혀 적용되지 않음), 데스크탑(포인터가 정밀하고 900px 이상 —
     main.js의 isDesktopEnv())에서만 "왼쪽 사이드바 메뉴 + 상단 우측 프로필"이라는 일반적인
     웹앱 레이아웃으로 전환한다.
     색상: 기존 앱 전역 색상 토큰(:root의 --steel/--fail/--amber 등, 카드/배지/버튼 등 콘텐츠
     내부 색상)은 전혀 건드리지 않는다(지난 세션에 시도했다가 반려된 "포인트 컬러 강화"와는
     무관 — 그건 콘텐츠 색상 자체를 바꾸는 시도였고 이번엔 반려되지 않았음). 대신 이번에 새로
     생기는 "사이드바/데스크탑 상단바"라는 틀(chrome)에만 한정해서 쓰는 별도 톤(연보라 아바던트,
     짙은 잉크 블랙, 차분한 웜그레이 사이드바)을 --dsk-* 변수로 새로 정의해 사용한다 — 기존
     화면 색감은 그대로 두고 "새로 추가되는 틀"만 다른 느낌을 주는 절충. */
  body.is-desktop{
    --dsk-bg:var(--bg);
    --dsk-sidebar-bg:#EEF1F6;
    --dsk-sidebar-border:var(--line);
    --dsk-ink:var(--ink);
    --dsk-muted:var(--muted);
    --dsk-active-bg:var(--steel);
    --dsk-active-ink:#FFFFFF;
    --dsk-avatar-bg:#DCE3EF;
    --dsk-avatar-ink:var(--steel-dark);
    --dsk-sidebar-w:236px;
  }
  body.is-desktop{background:var(--dsk-bg);}

  /* 상단바: 위치/내용(로고, 시스템 전환 화살표, 프로필/조직도 버튼)은 그대로 두고 색감만
     새 톤으로. 이름 라벨(#desktopUserName)이 들어갈 자리만큼 오른쪽 여백을 넓힌다. */
  body.is-desktop .topbar{
    background:var(--dsk-bg);border-bottom:1px solid var(--dsk-sidebar-border);
    padding-right:250px;
  }
  body.is-desktop .brand-text, body.is-desktop h1, body.is-desktop h2{color:var(--dsk-ink);}
  body.is-desktop .profile-badge{background:var(--dsk-avatar-bg);color:var(--dsk-avatar-ink);box-shadow:none;}
  .dsk-topbar-username{display:none;}
  body.is-desktop .dsk-topbar-username{
    display:block;position:absolute;top:50%;right:112px;transform:translateY(-50%);
    font-weight:700;font-size:13.5px;color:var(--dsk-ink);white-space:nowrap;
  }

  .desktop-sidebar{display:none;} /* 모바일: 항상 숨김 */
  body.is-desktop .desktop-sidebar{
    display:flex;flex-direction:column;justify-content:space-between;
    position:fixed;top:74px;left:0;bottom:0;z-index:19;
    width:var(--dsk-sidebar-w);
    background:var(--dsk-sidebar-bg);border-right:1px solid var(--dsk-sidebar-border);
    padding:18px 12px;
  }
  body.is-desktop .dsk-sidebar-nav{display:flex;flex-direction:column;gap:4px;}
  body.is-desktop .dsk-sidebar-nav .tab-btn{
    display:flex;align-items:center;gap:12px;
    border:none;background:transparent;color:var(--dsk-muted);
    padding:11px 14px;border-radius:12px;font-size:14px;font-weight:700;text-align:left;
    transition:background .15s, color .15s;
  }
  body.is-desktop .dsk-sidebar-nav .tab-btn svg{width:19px;height:19px;flex-shrink:0;}
  body.is-desktop .dsk-sidebar-nav .tab-btn span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  body.is-desktop .dsk-sidebar-nav .tab-btn:hover{background:rgba(22,24,29,.06);color:var(--dsk-ink);}
  body.is-desktop .dsk-sidebar-nav .tab-btn.active{background:var(--dsk-active-bg);color:var(--dsk-active-ink);}
  body.is-desktop .dsk-sidebar-bottom{border-top:1px solid var(--dsk-sidebar-border);padding-top:12px;}
  body.is-desktop .dsk-sidebar-logout{
    display:flex;align-items:center;gap:12px;width:100%;
    border:none;background:transparent;color:var(--dsk-muted);
    padding:11px 14px;border-radius:12px;font-size:14px;font-weight:700;text-align:left;
    transition:background .15s, color .15s;
  }
  body.is-desktop .dsk-sidebar-logout svg{width:19px;height:19px;flex-shrink:0;}
  body.is-desktop .dsk-sidebar-logout:hover{background:rgba(196,67,46,.1);color:var(--fail);}

  /* 본문: 사이드바 폭만큼 왼쪽 여백을 주고, 하단 플로팅 탭바를 위해 비워뒀던 아래쪽 여백은
     제거(데스크탑엔 하단 탭바가 없음, 아래 .bottom-nav 규칙 참고). */
  body.is-desktop main{margin-left:var(--dsk-sidebar-w);padding:24px 32px 32px;}
  /* 데스크탑에서는 화면이 넓어 하단 플로팅 탭바(모바일 전용 UX)와 그 위 플로팅 저장 버튼이
     불필요 — 둘 다 숨긴다. floating-save-btn의 위치는 원래 .bottom-nav의 실제 높이를 재서
     계산되는데(js/input-tab.js의 positionFloatBtn), 하단 탭바가 사라지면 그 계산이 화면 밖으로
     튕겨나가는 값을 낼 수 있어 JS 쪽에도 높이 0일 때의 예외 처리를 추가해뒀다(방어적 이중 안전장치). */
  body.is-desktop .bottom-nav{display:none;}
  body.is-desktop .floating-save-btn{display:none !important;}
  .tab-panel{display:none;}
  .tab-panel.active{display:block;}

  /* ---------- Input form (mobile-first) ---------- */
  .input-wrap{max-width:520px;margin:0 auto;}
  .card{
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:var(--glass-radius);
    box-shadow:var(--card-shadow);
    padding:20px;
  }
  .card + .card{margin-top:14px;}
  .form-title{font-size:14px;margin-bottom:1px;}
  .form-sub{color:var(--muted);font-size:11px;margin-bottom:0;}
  .panel-head-icon{display:flex;align-items:center;gap:8px;margin-bottom:12px;}
  .panel-head-icon .icon-badge{width:26px;height:26px;border-radius:8px;}
  .panel-head-icon .icon-badge svg{width:13px;height:13px;}

  .icon-badge{
    flex-shrink:0;width:38px;height:38px;border-radius:11px;
    display:flex;align-items:center;justify-content:center;
    box-shadow:inset 0 1px 0 rgba(255,255,255,.5);
  }
  .icon-badge svg{width:19px;height:19px;}
  .icon-badge.steel{background:linear-gradient(150deg, rgba(22,24,29,.10), rgba(22,24,29,.20));color:var(--steel-dark);}
  .icon-badge.pass{background:linear-gradient(150deg, rgba(47,115,80,.16), rgba(47,115,80,.28));color:var(--pass);}
  .icon-badge.fail{background:linear-gradient(150deg, rgba(196,67,46,.14), rgba(196,67,46,.26));color:var(--fail);}
  .icon-badge.amber{background:linear-gradient(150deg, rgba(150,96,24,.16), rgba(150,96,24,.28));color:var(--amber);}
  .field{margin-bottom:16px;min-width:0;} /* min-width:0 — 부모가 flex 행일 때 내용물 때문에 옆으로 넘치지 않도록 */
  .field label{display:block;font-size:13px;font-weight:600;color:var(--muted);margin-bottom:6px;}
  .field input[type=text], .field input[type=email], .field input[type=password],
  .field input[type=tel], .field input[type=number],
  .field input[type=datetime-local], .field input[type=date], .field textarea{
    width:100%;padding:12px 12px;border:1px solid var(--line);border-radius:12px;
    background:rgba(255,255,255,.75);font-size:16px;box-sizing:border-box;
    box-shadow:inset 0 1px 2px rgba(20,50,90,.05);
  }
  .field input:focus, .field textarea:focus, .field select:focus{outline:2px solid var(--steel);outline-offset:1px;}
  .field textarea{resize:vertical;min-height:70px;}
  .req::after{content:" *";color:var(--fail);}

  .result-row{display:flex;gap:10px;}
  .stamp-btn{
    flex:1;padding:16px 8px;border-radius:50%/12px;border:2px solid rgba(216,220,228,.8);
    background:rgba(255,255,255,.68);font-weight:700;font-size:15px;color:var(--muted);
    display:flex;flex-direction:column;align-items:center;gap:4px;
    box-shadow:0 2px 8px rgba(20,50,90,.06), inset 0 1px 0 rgba(255,255,255,.9);
    transition:transform .1s, border-color .15s, color .15s, background .15s, box-shadow .15s;
  }
  .stamp-btn:active{transform:scale(.97);}
  .stamp-btn .stamp-ico{font-size:20px;line-height:1;}
  .stamp-btn.pass.selected{border-color:var(--pass);color:var(--pass);background:var(--pass-soft);box-shadow:0 4px 14px rgba(47,115,80,.22), inset 0 1px 0 rgba(255,255,255,.9);}
  .stamp-btn.fail.selected{border-color:var(--fail);color:var(--fail);background:var(--fail-soft);box-shadow:0 4px 14px rgba(196,67,46,.22), inset 0 1px 0 rgba(255,255,255,.9);}
  .stamp-btn.person.selected{border-color:var(--steel);color:var(--steel);background:var(--steel-soft);box-shadow:0 4px 14px rgba(22,24,29,.20), inset 0 1px 0 rgba(255,255,255,.9);}

  .inspector-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;}
  .inspector-grid .stamp-btn.person{
    padding:11px 4px;font-size:13px;border-radius:12px;flex:none;
  }

  .link-btn{
    border:none;background:none;color:var(--steel);font-size:12.5px;font-weight:600;
    padding:6px 0;text-decoration:underline;
  }

  .now-row{display:flex;align-items:center;gap:12px;}
  .now-btn{
    flex-shrink:0;width:96px;padding:11px 4px;border-radius:12px;
    border:2px solid rgba(255,255,255,.8);background:linear-gradient(150deg, rgba(236,234,229,.85), rgba(22,24,29,.16));
    color:var(--steel-dark);
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
    font-weight:800;font-size:13px;
    box-shadow:0 6px 18px rgba(22,24,29,.20), inset 0 1px 0 rgba(255,255,255,.9);
    transition:transform .1s, background .15s;
  }
  .now-btn:active{transform:scale(.95);background:var(--steel);color:#fff;}
  .now-btn .now-ico{width:16px;height:16px;}
  .now-display-wrap{flex:1;min-width:0;}
  .now-display{font-size:13.5px;font-weight:700;color:var(--ink);margin-bottom:2px;}
  .dt-manual{width:100%;padding:9px 11px;border:1px solid var(--line);border-radius:12px;background:rgba(255,255,255,.75);font-size:14px;margin-top:8px;}

  .chip-row{display:flex;flex-wrap:wrap;gap:8px;}
  .chip{
    padding:9px 14px;border-radius:20px;border:1.5px solid rgba(216,220,228,.8);background:rgba(255,255,255,.68);
    font-size:13.5px;font-weight:600;color:var(--muted);
    box-shadow:0 1px 4px rgba(20,50,90,.05);
  }
  .chip.selected{border-color:var(--amber);color:var(--amber);background:var(--amber-soft);box-shadow:0 3px 10px rgba(150,96,24,.2);}
  .defect-block{display:none;margin-top:14px;padding-top:14px;border-top:1px dashed var(--line);}
  .defect-block.show{display:block;}
  .hint{font-size:12px;color:var(--muted);margin-top:6px;}
  .hint.warn{color:var(--fail);}

  .photo-add-btn{
    display:flex;align-items:center;justify-content:center;gap:8px;
    width:100%;padding:14px;border:1.5px dashed var(--steel);border-radius:14px;
    background:rgba(230,238,248,.6);color:var(--steel-dark);font-weight:600;font-size:14px;
  }
  .photo-add-btn svg{width:18px;height:18px;}

  /* 바코드 스캔 버튼 — 사진 추가 버튼(점선 테두리, 은은한 배경)과 달리 이 기능은 입력을
     통째로 대신해주는 핵심 기능이라 일부러 꽉 찬 색으로 눈에 띄게 강조한다.
     2026-09-21 3차 리빌드 당시엔 브랜드색(--steel)과 같은 파랑 계열(채도만 높게)을 썼는데,
     그러자 브랜드가 파랑이 된 이후로는 이 버튼도 "그냥 좀 더 진한 브랜드색"처럼 비슷해
     보인다는 피드백을 받음 — 파랑 계열 안에서는 아무리 채도를 올려도 다른 파랑 버튼들과
     구분이 잘 안 됨. 그래서 이번엔 아예 색상군 자체를 바꿔 버건디(와인레드) 계열로 전환 —
     브랜드(파랑)와도, 불합격 색(fail, 주황빛 빨강)과도 확실히 구분되는 세 번째 색상군.
     아이콘 색(#F4C868, 골드)과 버건디의 조합은 클래식한 "와인+골드" 배색이라 잘 어울린다.
     처음엔 배경 그라데이션 자체를 250% 크기로 늘려 background-position을 0%→100%로 계속
     반복시켰는데, 매 루프마다 화면에 "보이는 채로" 100%→0%로 순간이동해버려 뚝뚝 끊기는
     느낌이 났다(대칭 그라데이션이라 양쪽 끝 색은 같아도, 그 사이에 보이는 내용 자체가
     통째로 바뀌어버리는 건 못 숨김). 그래서 지금은 base 배경은 애니메이션 없이 고정해두고,
     글로우만 별도 레이어(::after)로 분리해서 버튼 폭 밖(왼쪽 바깥→오른쪽 바깥)까지 움직이게
     했다 — 루프가 되돌아가는 순간은 글로우가 이미 버튼 밖으로 완전히 빠져나가 안 보일 때라,
     사람 눈에는 계속 한 방향으로 흘러가는 것처럼만 보인다. */
  .scan-btn{
    position:relative;isolation:isolate;overflow:hidden;
    display:flex;align-items:center;justify-content:center;gap:9px;
    width:100%;padding:19px 14px;border:none;border-radius:16px;
    background:linear-gradient(135deg, #3B0F24, #9E2955);
    color:#fff;font-weight:700;font-size:14.5px;
    box-shadow:0 6px 16px rgba(59,15,36,.4);transition:transform .12s, box-shadow .12s;
  }
  /* isolation:isolate로 이 버튼만의 독립된 스태킹 컨텍스트를 만들어두면, z-index:-1인 이
     ::after는 "버튼 자신의 배경(1번)" 바로 위, "아이콘/텍스트(일반 흐름 콘텐츠, 그 다음
     순서)" 바로 아래에 그려진다 — 그래서 아이콘/텍스트를 하나도 안 가리면서 딱 배경과
     글자 사이에서만 글로우가 지나간다. mix-blend-mode:screen이라 지나가는 동안 배경색과
     겹쳐 밝게 빛나 보이고, 배경색만 있는 구간은 원래 색 그대로 유지된다. */
  .scan-btn::after{
    content:'';position:absolute;inset:0;z-index:-1;
    background:linear-gradient(100deg, transparent 35%, rgba(255,205,215,.9) 50%, transparent 65%);
    background-size:50% 100%;background-repeat:no-repeat;background-position:-110% 0;
    mix-blend-mode:screen;
    animation:scanGlowSweep 2.4s linear infinite;
  }
  .scan-btn svg{width:20px;height:20px;color:#F4C868;}
  .scan-btn:active{transform:scale(.98);box-shadow:0 3px 10px rgba(59,15,36,.35);}
  @keyframes scanGlowSweep{
    0%{background-position:-110% 0;}
    100%{background-position:210% 0;}
  }
  @media (prefers-reduced-motion: reduce){
    .scan-btn::after{animation:none;opacity:0;}
  }
  .thumb-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:10px;}
  .thumb{position:relative;aspect-ratio:1/1;border-radius:12px;overflow:hidden;border:1px solid var(--line);box-shadow:0 3px 10px rgba(20,50,90,.08);}
  .thumb img{width:100%;height:100%;object-fit:cover;display:block;}
  .thumb .rm{
    position:absolute;top:3px;right:3px;width:22px;height:22px;border-radius:50%;
    background:rgba(27,34,43,.75);color:#fff;border:none;font-size:13px;line-height:1;
    display:flex;align-items:center;justify-content:center;
  }
  .thumb .edit{
    position:absolute;left:3px;bottom:3px;padding:3px 8px;border-radius:10px;
    background:rgba(27,34,43,.75);color:#fff;border:none;font-size:10.5px;font-weight:600;line-height:1.4;
  }

  /* ---------- spec warning popup + shake ---------- */
  @keyframes qcShakeX{
    10%,90%{transform:translateX(-1px);}
    20%,80%{transform:translateX(2px);}
    30%,50%,70%{transform:translateX(-4px);}
    40%,60%{transform:translateX(4px);}
  }
  .input-shake{animation:qcShakeX .5s;border-color:var(--fail) !important;background:var(--fail-soft) !important;}
  .spec-warning-popup{
    position:fixed;top:10px;left:50%;transform:translateX(-50%);
    background:#fff;color:var(--fail);border:1px solid var(--fail);
    font-size:12px;font-weight:700;padding:7px 16px;border-radius:20px;
    box-shadow:0 6px 18px rgba(196,67,46,.28);
    z-index:200;opacity:0;pointer-events:none;transition:opacity .4s ease;
  }
  .spec-warning-popup.show{opacity:1;}
  .scan-warning-popup{
    position:fixed;top:16px;left:50%;transform:translateX(-50%);
    background:var(--fail-soft);color:var(--fail);border:1px solid var(--fail);
    font-size:14.5px;font-weight:700;padding:14px 22px;border-radius:16px;
    box-shadow:0 10px 28px rgba(196,67,46,.32);
    max-width:88vw;text-align:center;line-height:1.4;
    z-index:220;opacity:0;pointer-events:none;transition:opacity .4s ease;
  }
  .scan-warning-popup.show{opacity:1;}

  /* ---------- photo editor modal ---------- */
  .photo-edit-box{max-width:480px;}
  .pe-canvas-wrap{display:flex;justify-content:center;align-items:center;background:#111114;border-radius:12px;overflow:hidden;margin-top:10px;touch-action:none;}
  .pe-canvas-wrap canvas{display:block;max-width:100%;touch-action:none;}
  .pe-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:12px;}
  .pe-tool-btn{
    display:flex;align-items:center;gap:5px;padding:8px 12px;border-radius:12px;
    border:1.5px solid var(--line);background:var(--bg);color:var(--muted);font-size:12.5px;font-weight:600;
  }
  .pe-tool-btn svg{width:15px;height:15px;}
  .pe-tool-btn.active{border-color:var(--steel);color:var(--steel);background:var(--steel-soft);}
  .pe-color-row{display:flex;gap:6px;margin-left:4px;}
  .pe-color{width:24px;height:24px;border-radius:50%;border:2px solid transparent;box-shadow:inset 0 0 0 1px rgba(0,0,0,.1);}
  .pe-color.selected{border-color:var(--ink);}
  .pe-actions{display:flex;gap:8px;margin-top:10px;}
  .pe-actions .btn-ghost{flex:1;}

  /* ---------- daily closing ---------- */
  .daily-close-wrap{margin-top:20px;display:flex;justify-content:center;padding-bottom:6px;}
  .daily-close-btn{
    display:flex;align-items:center;gap:8px;padding:13px 28px;border-radius:14px;
    border:1.5px solid var(--fail);background:var(--fail-soft);color:var(--fail);
    font-weight:700;font-size:14px;box-shadow:0 3px 10px rgba(196,67,46,.12);
  }
  .daily-close-btn:active{transform:scale(.98);}
  .daily-close-btn svg{width:17px;height:17px;}

  .load-more-btn{
    width:100%;padding:11px;margin-top:10px;border-radius:12px;border:1.5px dashed var(--line);
    background:var(--bg);color:var(--muted);font-weight:600;font-size:12.5px;
  }
  .load-more-btn:active{transform:scale(.99);}

  .submit-btn{
    /* 2026-09-21 3차 리빌드: 기존엔 외곽 그림자 + inset 하이라이트(광택) 2겹이었는데,
       "차분한 톤 + 화려함은 벤토/글래스 쪽에" 요청에 맞춰 이 버튼은 단일 그림자로
       단순화한다(다른 버튼들과 그림자 언어를 통일). */
    width:100%;padding:15px;border:none;border-radius:14px;
    background:linear-gradient(135deg, var(--steel), var(--steel-dark));color:#fff;font-weight:700;font-size:15.5px;margin-top:6px;
    box-shadow:0 6px 18px rgba(61,90,128,.28);
    transition:transform .1s, box-shadow .15s;
  }
  .submit-btn:active{transform:scale(.99);box-shadow:0 3px 10px rgba(61,90,128,.22);}
  .submit-btn:disabled{background:#B6BAC4;box-shadow:none;}

  /* ---------- Dashboard ---------- */
  .dash-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;}
  .period-toggle{display:flex;gap:4px;background:var(--bg);border:1px solid var(--line);border-radius:20px;padding:3px;}
  .spec-info-pill{text-align:center;font-size:12.5px;font-weight:700;letter-spacing:.2px;color:var(--steel);background:var(--steel-soft);border-radius:20px;padding:8px 14px;margin:2px 0 14px;}
  /* 2026-09-21 후속: 품번을 인식하면(입력탭 updateSpecPill, 대시보드 상세보기 specPillHtml 양쪽
     공통) 기존 "RH · 8WP IMS · 88600-NR050" 한 줄 아래에, 회사 품번-표기 엑셀의 "표기"에 해당하는
     옵션 사양(L/S, HTR, VENT 등)을 작은 회색 글씨로 한 줄 더 보여준다 — 기존 파란 글씨(sip-main)와
     또렷이 구분되도록 톤을 낮추고 글자 크기도 줄임. 알약 높이가 늘어나는 만큼만 아래로 살짝 커지게
     패딩을 미세 조정(모양 자체는 계속 완전히 둥근 캡슐 형태 유지).*/
  .spec-info-pill{padding:9px 16px 10px;}
  .spec-info-pill .sip-main{display:block;}
  .spec-info-pill .sip-sub{display:block;margin-top:3px;font-size:10.5px;font-weight:600;letter-spacing:.1px;color:var(--muted);}
  .view-toggle{display:flex;gap:4px;background:var(--bg);border:1px solid var(--line);border-radius:20px;padding:3px;}
  .view-toggle-btn{border:none;background:transparent;padding:5px 13px;border-radius:14px;font-size:11.5px;font-weight:600;color:var(--muted);}
  .view-toggle-btn.active{background:var(--steel);color:#fff;}
  .period-btn, .cpk-period-btn, .proc-period-btn, .prod-cat-btn, .prod-period-btn{border:none;background:transparent;padding:7px 16px;border-radius:16px;font-size:12.5px;font-weight:600;color:var(--muted);}
  .period-btn.active, .cpk-period-btn.active, .proc-period-btn.active, .prod-cat-btn.active, .prod-period-btn.active{background:var(--steel);color:#fff;}
  .panel-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px;}
  .panel-grid-2 .panel{margin-bottom:0;}
  .chart-wrap{position:relative;width:100%;}
  @media(max-width:820px){ .panel-grid-2{grid-template-columns:1fr;} }
  .qsection-divider{display:flex;align-items:center;gap:12px;margin:28px 0 16px;}
  .qsection-divider::before, .qsection-divider::after{content:'';flex:1;height:1px;background:var(--line);}
  .qsection-divider span{font-size:12.5px;font-weight:700;color:var(--muted);white-space:nowrap;}
  .dash-header h1{font-size:25px;font-weight:800;color:var(--ink);letter-spacing:-.01em;}
  .dash-header p{font-size:12.5px;color:var(--muted);font-weight:500;margin-top:2px;}
  .dash-refresh-btn{
    width:44px;height:44px;border-radius:50%;border:none;background:var(--steel);color:#fff;
    display:flex;align-items:center;justify-content:center;flex-shrink:0;box-shadow:0 4px 12px rgba(61,90,128,.28);
    transition:transform .15s;
  }
  .dash-refresh-btn:active{transform:rotate(180deg);}
  .dash-refresh-btn svg{width:19px;height:19px;}

  .dash-toolbar{
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:var(--glass-radius);
    box-shadow:var(--card-shadow);
    padding:10px 14px;margin-bottom:16px;
  }
  .filter-toggle-btn{
    width:100%;display:flex;align-items:center;gap:8px;
    border:none;background:transparent;padding:8px 2px;font-size:14px;font-weight:700;color:var(--ink);
  }
  .filter-toggle-btn svg{width:16px;height:16px;flex-shrink:0;color:var(--steel);}
  .filter-toggle-btn span{white-space:nowrap;}
  .filter-badge{
    background:var(--steel);color:#fff;border-radius:20px;font-size:11px;font-weight:700;
    padding:1px 8px;margin-left:-2px;
  }
  .filter-chevron{margin-left:auto;transition:transform .2s;color:var(--muted) !important;}
  .filter-chevron.open{transform:rotate(180deg);}

  .dash-toolbar-fields{
    display:none;
    grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px;
    padding-top:12px;margin-top:10px;border-top:1px solid var(--line);
  }
  .dash-toolbar-fields.show{display:grid;}
  .dash-toolbar-fields .field{margin-bottom:0;min-width:0;}
  .dash-toolbar-fields label{display:block;font-size:10.5px;font-weight:700;color:var(--muted);margin-bottom:5px;text-transform:uppercase;letter-spacing:.03em;}
  .dash-toolbar-fields select, .dash-toolbar-fields input{
    width:100%;min-width:0;box-sizing:border-box;padding:9px 10px;border:1px solid var(--line);border-radius:20px;background:var(--bg);font-size:13px;color:var(--ink);
  }
  .toolbar-actions{display:flex;align-items:flex-end;gap:8px;grid-column:1/-1;justify-content:flex-end;}
  .btn-ghost{padding:9px 16px;border:1px solid var(--line);background:var(--bg);border-radius:20px;font-size:13px;font-weight:600;color:var(--muted);}

  .share-link-actions{display:flex;gap:8px;}
  .share-link-actions .btn-ghost{flex:1;width:auto;}

  .stat-row{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:16px;}
  .stat-row-4{grid-template-columns:repeat(4,1fr);}
  .stat-row-5{grid-template-columns:repeat(5,1fr);}
  .cpk-side-grid{display:flex;flex-direction:column;gap:16px;margin:12px 0 14px;}
  .cpk-side-title{font-size:12px;font-weight:700;color:var(--muted);letter-spacing:.04em;margin-bottom:8px;text-transform:uppercase;}
  .stat-card{
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:16px;
    box-shadow:var(--card-shadow);
    padding:14px;
    transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease;
  }
  .stat-card .num{font-size:24px;font-weight:800;font-family:'JetBrains Mono',monospace;}
  .stat-card .lbl{font-size:12px;color:var(--muted);font-weight:600;margin-top:2px;}
  .stat-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;}
  .stat-top .icon-badge{width:32px;height:32px;border-radius:9px;}
  .stat-top .icon-badge svg{width:16px;height:16px;}
  .spark{width:56px;height:22px;overflow:visible;}
  .stat-card.pass .num{color:var(--pass);}
  .stat-card.rwk .num{color:var(--amber);}
  .stat-card.fail .num{color:var(--fail);}
  /* 2026-09-20: 마우스 호버 시 살짝 떠오르는 느낌(hover-lift) — 데스크톱에서만, 터치 기기는
     hover 자체가 없으므로 @media(hover:hover)로 한정해 모바일에서 탭 잔상이 남지 않게 함. */
  @media(hover:hover){
    .stat-card:hover, .panel:hover{
      transform:translateY(-2px);
      box-shadow:0 2px 6px rgba(22,24,29,.07), 0 12px 26px rgba(22,24,29,.09);
    }
    .stat-card:hover{border-color:rgba(61,90,128,.28);}
  }

  /* 2026-09-21 3차 리빌드: 벤토박스 레이아웃 + 리퀴드 글래스 확장(1순위 가독성 정리에
     이어 3순위 "화려함" 반영). 대시보드 상단 5개 통계 카드 중 첫 번째(총 검사 건수)를
     2x2 크기의 "히어로" 타일로 키우고, 반투명 브랜드 그라데이션 + backdrop-filter로
     하단 탭바와 같은 유리 재질 언어를 준다. 나머지 4개는 기존 플랫 카드 그대로 둬서
     "히어로만 화려하고 나머지는 차분"한 대비를 만든다. 카드 개수(5개)가 고정된 이
     한 섹션에만 적용하는 전용 레이아웃이라 다른 stat-row(4개/3개 카드)에는 영향 없음. */
  .stat-row.bento-row{
    grid-template-columns:1.3fr 1fr 1fr;
    grid-template-rows:auto auto;
    grid-template-areas:"hero a b" "hero c d";
    gap:10px;
  }
  .stat-row.bento-row .stat-card:nth-child(1){grid-area:hero;}
  .stat-row.bento-row .stat-card:nth-child(2){grid-area:a;}
  .stat-row.bento-row .stat-card:nth-child(3){grid-area:b;}
  .stat-row.bento-row .stat-card:nth-child(4){grid-area:c;}
  .stat-row.bento-row .stat-card:nth-child(5){grid-area:d;}
  .stat-row.bento-row .stat-card:nth-child(1){
    display:flex;flex-direction:column;justify-content:space-between;
    background:linear-gradient(135deg, rgba(61,90,128,.94), rgba(44,66,96,.96));
    -webkit-backdrop-filter:blur(20px) saturate(160%);
    backdrop-filter:blur(20px) saturate(160%);
    border:1px solid rgba(255,255,255,.22);
    box-shadow:0 12px 28px rgba(22,24,29,.22);
    border-radius:var(--radius-lg);
  }
  .stat-row.bento-row .stat-card:nth-child(1) .icon-badge.steel{
    background:rgba(255,255,255,.18);color:#fff;
  }
  .stat-row.bento-row .stat-card:nth-child(1) .num{color:#fff;font-size:32px;}
  .stat-row.bento-row .stat-card:nth-child(1) .lbl{color:rgba(255,255,255,.78);}
  .stat-row.bento-row .stat-card:nth-child(1) .spark{opacity:.85;filter:brightness(0) invert(1);}
  @media(hover:hover){
    .stat-row.bento-row .stat-card:nth-child(1):hover{border-color:rgba(255,255,255,.4);}
  }
  body.is-desktop #tab-dashboard .stat-row.bento-row{
    grid-template-columns:1.3fr 1fr 1fr 1fr 1fr;
    grid-template-rows:auto;
    grid-template-areas:"hero a b c d";
  }
  @media (max-width:760px){
    .stat-row.bento-row{
      grid-template-columns:1fr 1fr;
      grid-template-areas:"hero hero" "a b" "c d";
    }
  }

  /* ---------- 스탯카드 등장 애니메이션 (card-pop-in, 2026-09-20) ----------
     core.js의 playCardEntrance()가 렌더될 때마다 이 클래스를 다시 붙여서 재생한다. 순서대로
     살짝 아래→위로 페이드인 + 스케일업 — animation-delay는 JS에서 카드마다 다르게 준다. */
  @keyframes cardPopIn{
    from{ opacity:0; transform:translateY(10px) scale(.97); }
    to{ opacity:1; transform:translateY(0) scale(1); }
  }
  .card-pop-in{ animation:cardPopIn .42s cubic-bezier(.22,.9,.34,1) both; }
  @media(prefers-reduced-motion: reduce){ .card-pop-in{ animation:none; } }

  .panel{
    background:var(--surface);
    border:1px solid var(--line);
    border-radius:var(--glass-radius);
    box-shadow:var(--card-shadow);
    padding:16px;margin-bottom:16px;
    transition:transform .18s ease, box-shadow .18s ease;
  }
  .panel h3{font-size:14px;margin-bottom:0;}
  .panel-title-row{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap;}
  .panel-title-row .icon-badge{width:32px;height:32px;border-radius:9px;}
  .panel-title-row .icon-badge svg{width:16px;height:16px;}
  .panel-title-row .panel-title-toggle{margin-left:auto;}
  .report-head .panel-title-row{margin-bottom:0;}
  @media(max-width:760px){
    .panel-title-row .panel-title-toggle{margin-left:0;width:100%;margin-top:2px;}
  }

  /* ---------- 탭 상단 브레드크럼 (2026-09-20) ----------
     "홈 > 생산실적"처럼 지금 보고 있는 화면 위치를 짚어주는 가벼운 안내줄. 링크가 아니라 현재
     위치 표시용이라 마지막 항목만 진하게, 앞 항목·구분자는 흐리게 처리. */
  .app-breadcrumb{
    display:flex; align-items:center; gap:6px; margin-bottom:12px;
    font-size:12.5px; color:var(--muted); font-weight:600;
  }
  .app-breadcrumb .crumb-home{display:flex;align-items:center;color:var(--muted);}
  .app-breadcrumb .crumb-home svg{width:14px;height:14px;}
  .app-breadcrumb .crumb-sep{color:#B6BAC4;font-size:11px;}
  .app-breadcrumb .crumb-current{color:var(--ink);font-weight:800;}

  .bar-row{display:grid;grid-template-columns:70px 1fr 34px;align-items:center;gap:10px;margin-bottom:8px;font-size:13px;}
  .bar-label{display:flex;align-items:center;gap:6px;}
  .bar-label .dot{width:7px;height:7px;border-radius:50%;background:var(--amber);flex-shrink:0;}
  .bar-track{background:rgba(216,220,228,.5);border-radius:4px;height:10px;overflow:hidden;}
  .bar-fill{background:var(--amber);height:100%;border-radius:4px;}
  .bar-row .cnt{text-align:right;font-family:'JetBrains Mono',monospace;font-weight:600;}

  .report-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;flex-wrap:wrap;gap:8px;}
  .report-head h3{font-size:14px;}
  .report-actions{display:flex;gap:8px;}
  .btn-action{padding:9px 16px;border-radius:11px;border:1px solid var(--steel);background:linear-gradient(135deg, var(--steel), var(--steel-dark));color:#fff;font-size:13px;font-weight:600;box-shadow:0 4px 12px rgba(22,24,29,.25);display:inline-flex;align-items:center;gap:7px;}
  .btn-action:disabled{opacity:.45;box-shadow:none;filter:grayscale(.3);}
  .btn-action svg{width:15px;height:15px;flex-shrink:0;}
  .btn-action.outline{background:rgba(255,255,255,.75);color:var(--steel);box-shadow:none;}

  .record-list-scroll{}

  /* ---------- record list view toggle + table view ---------- */
  .record-list-toolbar{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px;flex-wrap:wrap;}
  .toolbar-toggles{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}
  .dash-view-toggle{display:inline-flex;background:var(--bg);border-radius:14px;padding:3px;gap:2px;}
  .dvt-btn{border:none;background:transparent;padding:6px 14px;border-radius:11px;font-size:12px;font-weight:700;color:var(--muted);}
  .dvt-btn.active{background:var(--surface);color:var(--ink);box-shadow:0 1px 3px rgba(22,24,29,.12);}
  .record-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--line);border-radius:14px;background:var(--surface);}
  .record-table-wrap.hidden{display:none;}
  .record-list-scroll.hidden{display:none;}
  .record-table{width:100%;border-collapse:collapse;font-size:12.5px;white-space:nowrap;}
  .record-table thead th{
    position:sticky;top:0;background:var(--bg);color:var(--muted);font-size:11px;font-weight:700;
    text-align:left;padding:9px 12px;border-bottom:1px solid var(--line);cursor:pointer;user-select:none;white-space:nowrap;z-index:1;
  }
  .record-table thead th:last-child{cursor:default;}
  .record-table thead th .sort-ind{display:inline-block;width:10px;margin-left:2px;opacity:.35;font-size:10px;}
  .record-table thead th.sorted .sort-ind{opacity:1;color:var(--steel);}
  .record-table tbody td{padding:9px 12px;border-bottom:1px solid rgba(216,220,228,.5);color:var(--ink);}
  .record-table tbody tr{cursor:pointer;}
  .record-table tbody tr:hover{background:var(--bg);}
  .record-table tbody tr:last-child td{border-bottom:none;}
  .record-table td.rt-serial{font-family:'SF Mono','Roboto Mono',monospace;color:var(--muted);}
  .record-table td.rt-result .badge-sm{
    display:inline-block;padding:2px 9px;border-radius:20px;font-size:11px;font-weight:700;
  }
  .record-table td.rt-result .badge-sm.pass{background:var(--pass-soft);color:var(--pass);}
  .record-table td.rt-result .badge-sm.rwk{background:var(--amber-soft);color:var(--amber);}
  .record-table td.rt-result .badge-sm.fail{background:var(--fail-soft);color:var(--fail);}
  .load-more-btn-wrap{padding:0 2px;}
  .record-list{display:flex;flex-direction:column;gap:7px;}
  .record-card{
    display:flex;align-items:center;gap:9px;
    background:var(--surface);border:1px solid var(--line);border-radius:12px;
    padding:9px 12px 9px 0;overflow:hidden;cursor:pointer;
    box-shadow:var(--card-shadow);
    transition:transform .1s, box-shadow .15s;
  }
  .record-card:active{transform:scale(.99);}
  .record-card .stripe{width:4px;align-self:stretch;border-radius:4px;flex-shrink:0;margin-left:-1px;}
  .record-card.pass .stripe{background:var(--pass);}
  .record-card.rwk .stripe{background:var(--amber);}
  .record-card.fail .stripe{background:var(--fail);}
  .record-card .rc-icon{
    width:26px;height:26px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;
  }
  .record-card.pass .rc-icon{background:var(--pass-soft);color:var(--pass);}
  .record-card.rwk .rc-icon{background:var(--amber-soft);color:var(--amber);}
  .record-card.fail .rc-icon{background:var(--fail-soft);color:var(--fail);}
  .record-card .rc-icon svg{width:13px;height:13px;}
  .record-card .rc-body{flex:1;min-width:0;}
  .record-card .rc-top{display:flex;align-items:center;justify-content:space-between;gap:8px;}
  .record-card .rc-title{font-size:12.5px;font-weight:700;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
  .record-card .rc-date{font-size:10px;color:var(--muted);font-weight:600;white-space:nowrap;flex-shrink:0;}
  .record-card .rc-meta{display:flex;flex-wrap:wrap;gap:4px;margin-top:3px;}
  .record-card .rc-meta .tag{padding:1px 7px;font-size:10px;}
  .record-card .rc-note{font-size:11.5px;color:var(--muted);margin-top:4px;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden;line-height:1.35;}
  .record-card .rc-chevron{color:#B6BAC4;flex-shrink:0;align-self:center;}
  .record-card .rc-chevron svg{width:14px;height:14px;}
  /* 2026-09-21 후속(19): 카카오톡 채팅방 날짜 구분선처럼, 세로 기록 목록에서 날짜가 바뀌는
     지점마다 얇은 선+작은 문구를 끼워 넣는다. .record-list가 이미 flex column + gap으로
     카드 사이 간격을 주고 있어서, 구분선도 그냥 같은 목록의 형제 요소로 넣으면 된다 —
     별도 absolute 포지셔닝이나 마진 계산 없이 gap이 위아래 여백을 알아서 맞춰준다. */
  .rc-date-divider{display:flex;align-items:center;gap:10px;margin:4px 2px 0;}
  .rc-date-divider::before,.rc-date-divider::after{content:'';flex:1;height:1px;background:var(--line);}
  .rc-date-divider span{font-size:10.5px;font-weight:700;color:var(--muted);white-space:nowrap;letter-spacing:.01em;}
  .badge{display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border-radius:20px;font-size:12px;font-weight:700;}
  .badge.pass{background:var(--pass-soft);color:var(--pass);}
  .badge.rwk{background:var(--amber-soft);color:var(--amber);}
  .badge.fail{background:var(--fail-soft);color:var(--fail);}
  .badge.steel{background:var(--steel-soft);color:var(--steel);}
  .mismatch-row{background:#fff;border:1px solid var(--line);border-radius:10px;padding:8px 10px;}
  .mismatch-tags{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:5px;}
  .mismatch-tag{display:inline-flex;align-items:center;padding:2px 9px;border-radius:20px;font-size:10.5px;font-weight:700;background:var(--steel-soft);color:var(--steel);letter-spacing:.01em;}
  .mismatch-tag.part{background:var(--surface);color:var(--muted);border:1px solid var(--line);font-family:'SF Mono',Consolas,monospace;font-weight:600;}
  .mismatch-msg{font-size:12.5px;color:var(--ink);line-height:1.5;}
  .mismatch-msg b{color:var(--steel-dark);}
  .worst-rank{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;font-size:11.5px;font-weight:700;background:var(--steel-soft);color:var(--steel);}
  .worst-rank.top{background:var(--fail-soft);color:var(--fail);}
  .cal-total-row td{background:var(--steel-soft);font-weight:700;}
  .pivot-group-row td{background:var(--bg);font-weight:800;color:var(--steel-dark);border-top:1px solid var(--line);}
  .pivot-vendor-row td:first-child{padding-left:26px;color:var(--muted);font-weight:600;}
  .pivot-subtotal-row td{background:#F2EFE6;font-weight:700;border-top:1px dashed var(--line);}
  .pivot-total-row td{background:var(--steel-soft);font-weight:800;color:var(--steel-dark);border-top:1px solid var(--steel);}
  .prod-year-nav{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px;}
  .prod-year-nav-btn{width:30px;height:30px;border-radius:50%;border:1px solid var(--line);background:var(--surface);color:var(--steel);font-size:16px;font-weight:700;line-height:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
  .prod-year-nav-btn:disabled{color:#B6BAC4;border-color:var(--line);opacity:.5;}
  .prod-year-nav-label{font-size:14.5px;font-weight:800;color:var(--ink);min-width:56px;text-align:center;}
  @media(max-width:760px){ .prod-year-nav .hint{flex-basis:100%;order:4;} }

  /* ---------- 차종·품번별 실적(일자별) 표: 고정 셀 너비 + 옅은 점선 세로 구분선 ----------
     자릿수가 늘어난 소계/총계 행 숫자가 옆 셀과 붙어보이지 않도록, 첫 두 열(차종/품번, 폭이
     들쑥날쑥한 텍스트)은 지정한 고정폭으로, 날짜·합계 열은 전부 균일한 고정폭으로 맞춘다. */
  .cal-fixed-table{table-layout:fixed;}
  .cal-fixed-table th, .cal-fixed-table td{
    width:64px; border-right:1px dashed rgba(95,100,115,.35);
    overflow:hidden; text-overflow:ellipsis;
  }
  /* 2026-09-20: 가독성을 위해 표 전체 데이터를 중앙 정렬. 기존 .record-table thead th의
     text-align:left(라인 619 부근)보다 클래스 개수가 많아 우선 적용됨(별도 !important 불필요). */
  .record-table.cal-fixed-table th, .record-table.cal-fixed-table td{ text-align:center; }
  .cal-fixed-table th:last-child, .cal-fixed-table td:last-child{border-right:none;}
  .cal-fixed-table th.cal-col-label, .cal-fixed-table td.cal-col-label{width:80px;}
  /* 2026-09-20: 품번은 "88600-CG722NNB"처럼 14자 안팎까지 나올 수 있어, 다른 라벨 열(생산분류/
     업체/차종은 전부 짧은 한글·영문 코드)보다 훨씬 넓게 잡고 줄바꿈 없이 통으로 보이게 한다.
     ellipsis로 잘리지 않도록 overflow도 visible로 풀어줌 — 이 열은 표의 맨 앞 쪽이라 옆 셀을
     밀어내도 레이아웃이 깨지지 않고, 표 전체는 어차피 가로 스크롤(.record-table-wrap)이 감싸고
     있어 안전하다. */
  .cal-fixed-table th.cal-col-label.mono, .cal-fixed-table td.cal-col-label.mono{
    width:148px; overflow:visible; text-overflow:clip;
    white-space:normal; word-break:break-all; line-height:1.3;
  }
  .cal-fixed-table th.cal-col-edit, .cal-fixed-table td.cal-col-edit{width:70px;text-align:center;}

  /* ---------- 차종·품번별 실적 설정 팝오버 (보이기 옵션 / 항목 수정) ---------- */
  .cal-settings-panel{
    background:var(--bg); border:1px solid var(--line); border-radius:12px; padding:12px 14px;
  }
  .cal-settings-panel.hidden{display:none;}
  .cal-col-toggle-btn{
    border:1px solid var(--line); background:var(--surface); color:var(--muted);
    padding:6px 14px; border-radius:16px; font-size:12px; font-weight:700; cursor:pointer;
  }
  .cal-col-toggle-btn.active{background:var(--steel); color:#fff; border-color:var(--steel);}
  .cal-edit-row-btn{
    border:1px solid var(--steel); background:var(--surface); color:var(--steel);
    padding:4px 10px; border-radius:10px; font-size:11px; font-weight:700; cursor:pointer; white-space:nowrap;
  }
  .cal-edit-row-btn:active{transform:scale(.96);}

  /* ---------- 생산실적 데이터 초기화: 하단 중앙 정렬 + 강한 위험 색상 대비 ---------- */
  .prod-reset-wrap{ text-align:center; margin:20px 0 8px; }
  .prod-reset-btn{
    display:inline-block; width:auto !important; margin-top:8px !important;
    padding:12px 28px !important; background:var(--fail) !important; color:#fff !important;
    border:none !important; font-weight:700 !important;
  }

  /* static (non-clickable) variant of the record table look, used outside the dashboard */
  .record-table-wrap.static-table thead th{cursor:default;}
  .record-table-wrap.static-table tbody tr{cursor:default;}
  .record-table-wrap.static-table tbody tr:hover{background:none;}
  .tag{display:inline-block;padding:2px 8px;border-radius:20px;background:var(--amber-soft);color:var(--amber);font-size:11px;font-weight:600;margin:1px 2px 1px 0;}
  .empty-state{text-align:center;padding:40px 20px;color:var(--muted);}
  .note-cell{max-width:180px;color:var(--muted);}

  /* ---------- Modal ---------- */
  .modal{position:fixed;inset:0;height:100dvh;background:rgba(22,24,29,.45);display:flex;align-items:flex-end;justify-content:center;z-index:50;}
  .modal.hidden{display:none;}
  .modal-box{
    background:var(--surface);
    border:1px solid var(--line);
    width:100%;max-width:560px;max-height:88vh;overflow-y:auto;overscroll-behavior:contain;border-radius:20px 20px 0 0;padding:22px;
    box-shadow:0 -6px 30px rgba(22,24,29,.14);
  }
  @media(min-width:600px){.modal{align-items:center;}.modal-box{border-radius:var(--glass-radius);box-shadow:var(--card-shadow);}}
  /* 2026-09-16 후속: 아이폰(iOS Safari)에서 스캔 모달을 열어 카메라를 켜면 화면이 위로 튀어
     오른다는 실사용 보고(iPhone 17 Pro Max) — 카메라 스트림이 시작되며 브라우저가 배경 페이지
     스크롤/뷰포트 상태를 바꾸는 것이 유력한 원인으로 보인다(실기기로 재현 확인은 못함). 모달이
     떠 있는 동안 배경 페이지 자체를 스크롤 불가능하게 고정해 두면, 그 변화가 일어날 여지가
     없어진다 — iOS 모달에서 흔히 쓰는 표준적인 방어책. */
  body.scan-scroll-lock{position:fixed;left:0;right:0;width:100%;overflow:hidden;}

  /* ---------- Org chart (조직도) — indented accordion list, no measured/drawn lines ----------
     2026-09 재작업: 예전엔 실제 박스 위치를 getBoundingClientRect()로 재서 <svg> 연결선을
     그리는 방식이었는데, 비대칭 트리에서 선이 어긋나 보이는 문제가 계속 발생했다. 지금은 좌표를
     재는 로직 자체가 없다 — 그냥 들여쓰기(padding/margin)와 왼쪽 세로줄(border-left)만으로
     계층을 표현하는 순수 CSS 레이아웃이라, 폰트 로딩/리사이즈/줌 배율과 무관하게 항상 같은
     모양으로 그려진다. 가로 스크롤도 필요 없어 모바일에서 세로로 쭉 읽으면 된다.
  */
  .org-modal-box{max-width:480px;}
  .orgchart-list{display:flex;flex-direction:column;gap:12px;margin-top:6px;}

  .oc-lead-card{
    text-align:center;border-radius:16px;padding:16px 14px;
    background:linear-gradient(135deg, var(--steel), var(--steel-dark));color:#fff;
    box-shadow:var(--card-shadow);
  }
  .oc-lead-card .oc-role{color:#fff;opacity:.82;}
  .oc-lead-card .oc-name{font-size:16px;margin:3px 0;color:#fff;}
  .oc-lead-card .oc-phone{color:#fff;opacity:.92;font-size:12.5px;}

  .oc-team{border:1px solid var(--line);border-radius:16px;overflow:hidden;background:var(--surface);}
  .oc-team-header{
    display:flex;align-items:center;gap:10px;padding:13px 14px;cursor:pointer;
    background:var(--steel-soft);user-select:none;
  }
  .oc-team-header:focus-visible{outline:2px solid var(--steel);outline-offset:-2px;}
  .oc-team-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;}
  .oc-team-header .oc-role{color:var(--steel-dark);}
  .oc-team-header .oc-name{font-size:14px;}
  .oc-team-header .oc-phone{font-size:11.5px;flex-shrink:0;}
  .oc-chevron{width:16px;height:16px;flex-shrink:0;color:var(--steel);transition:transform .2s;}
  .oc-team.collapsed .oc-chevron{transform:rotate(-90deg);}
  .oc-team-body{padding:2px 14px 8px;}
  .oc-team.collapsed .oc-team-body{display:none;}

  /* 들여쓰기는 재귀적으로 중첩된 .oc-member div 자체가 매번 같은 규칙을 적용받아 저절로
     계단식으로 쌓인다 — 깊이(depth)를 따로 세거나 클래스를 나눌 필요가 없다. */
  .oc-member{border-left:2px solid var(--line);padding-left:12px;margin-left:6px;}
  .oc-member-row{
    display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;
    padding:9px 0;border-bottom:1px solid rgba(216,220,228,.5);
  }
  .oc-member-main{display:flex;flex-direction:column;gap:1px;min-width:0;}
  .oc-note{font-size:9.5px;color:var(--fail);margin:-2px 0 6px;line-height:1.3;}

  /* 실제 상하관계가 아니라 같은 역할을 맡는 사람들의 묶음(예: 리어코리아 상주원, 이중검사원,
     HMC 상주원) — .oc-member처럼 재귀적으로 한 단계씩 더 들여쓰지 않고, 묶음 라벨 아래 사람들을
     전부 같은 들여쓰기 단계(동일 선상)로 나란히 보여준다. */
  .oc-section{margin-top:2px;}
  .oc-section-label{font-size:9.5px;font-weight:700;letter-spacing:.3px;color:var(--muted);text-transform:uppercase;padding:8px 0 4px;}
  .oc-section-people{border-left:2px solid var(--line);padding-left:12px;margin-left:6px;}
  .oc-section-person .oc-member-row{border-bottom:1px dashed rgba(216,220,228,.6);}
  .oc-section-person:last-child .oc-member-row{border-bottom:1px solid rgba(216,220,228,.5);}

  .oc-role{font-size:9.5px;font-weight:700;letter-spacing:.3px;color:var(--muted);text-transform:uppercase;white-space:nowrap;}
  .oc-name{font-size:12.5px;font-weight:800;color:var(--ink);white-space:nowrap;}
  .oc-phone{font-size:10.5px;font-family:'Roboto Mono',monospace;color:var(--steel);text-decoration:none;white-space:nowrap;}
  .oc-phone-pending{font-style:italic;color:#8890A0;}

  /* ---------- Production master data (생산처·품번 관리) ---------- */
  .pmv-chip{display:inline-flex;align-items:center;gap:6px;background:var(--steel-soft);color:var(--steel);border-radius:20px;padding:5px 6px 5px 12px;font-size:12.5px;font-weight:600;}
  .pmv-chip-del{width:18px;height:18px;flex:none;border-radius:50%;border:none;background:rgba(255,255,255,.65);color:var(--fail);font-size:12px;line-height:1;cursor:pointer;}
  .pmv-part-del{border:none;background:none;color:var(--fail);cursor:pointer;font-size:12px;padding:4px 6px;}
  .prod-new-item-row{display:flex;align-items:flex-start;gap:8px;font-size:12.5px;line-height:1.4;}
  .prod-new-item-row input[type="checkbox"]{margin-top:3px;flex:none;}
  .prod-new-part-row{background:#fff;border:1px solid var(--line);border-radius:10px;padding:8px 10px;}
  .prod-new-part-fields{display:flex;flex-direction:column;gap:6px;flex:1;min-width:0;}
  .prod-new-part-label{font-family:'SF Mono',Consolas,monospace;font-weight:600;color:var(--ink);word-break:break-all;}
  .prod-new-part-selects{display:flex;flex-wrap:wrap;gap:6px;align-items:center;}
  .prod-new-part-selects select, .prod-new-part-vendor-custom{font-size:12px;padding:4px 8px;border:1px solid var(--line);border-radius:8px;background:var(--bg);color:var(--ink);}
  .prod-new-part-category{font-weight:700;}
  .prod-new-part-vendor-custom{min-width:110px;}

  /* ---------- Account management (계정 관리) ---------- */
  .account-row{background:var(--bg);border:1px solid var(--line);border-radius:12px;padding:12px;margin-bottom:10px;}
  .account-row-head{font-size:13.5px;margin-bottom:10px;display:flex;align-items:center;gap:6px;flex-wrap:wrap;}
  /* 계정 행 안의 입력창들은 일부러 별도 스타일을 안 준다 — "새 계정 추가" 폼과 완전히 같은
     .field/label 마크업을 그대로 재사용해서, 두 영역의 입력창 모양이 항상 저절로 같아지게
     한다(예전엔 이 행만 placeholder만 있고 라벨도 없이 작은 글씨/패딩으로 따로 스타일링돼
     있어서 두 구역이 서로 다르게 보였음). */
  .acct-role-row{display:flex;align-items:center;gap:10px;margin-bottom:12px;}
  .acct-role-label{font-size:12px;font-weight:700;color:var(--muted);}
  .acct-role-toggle{background:var(--surface);}
  .acct-role-btn.active[data-role="admin"]{background:var(--fail-soft);color:var(--fail);box-shadow:none;}

  /* 계정 목록은 이름+권한만 보이는 압축된 행으로 두고, 탭하면 옆으로 슬라이드되는 상세
     패널(.acct-pane 두 번째 칸)에서 회사/부서/연락처 등 나머지 정보를 편집한다 — iOS 설정
     앱의 목록→상세 드릴다운과 같은 구조를, 모달 하나 안에서 폭 200%짜리 flex 슬라이더를
     좌우로 이동시키는 방식으로 구현했다. */
  .acct-modal-box{padding:0;overflow:hidden;position:relative;}
  .acct-modal-box .modal-x-close{position:absolute;top:14px;right:14px;z-index:6;}
  .acct-slider{display:flex;align-items:flex-start;width:200%;transition:transform .32s cubic-bezier(.32,.72,0,1);}
  .acct-slider.show-detail{transform:translateX(-50%);}
  .acct-pane{flex:0 0 50%;width:50%;box-sizing:border-box;max-height:88vh;overflow-y:auto;padding:52px 22px 22px;}

  .account-row-compact{
    display:flex;align-items:center;justify-content:space-between;gap:10px;
    background:var(--bg);border:1px solid var(--line);border-radius:12px;
    padding:12px 14px;margin-bottom:8px;cursor:pointer;transition:background .12s;
  }
  .account-row-compact:active{background:var(--steel-soft);}
  .arc-main{display:flex;align-items:center;gap:8px;min-width:0;flex-wrap:wrap;}
  .arc-name{font-size:13.5px;font-weight:700;color:var(--ink);white-space:nowrap;}
  .arc-id{font-size:11.5px;color:var(--muted);font-family:'Roboto Mono',monospace;}
  .arc-chevron{width:17px;height:17px;color:var(--muted);flex-shrink:0;}

  .acct-back-btn{
    display:flex;align-items:center;gap:5px;background:none;border:none;
    color:var(--steel);font-weight:700;font-size:13.5px;padding:0 0 14px;margin:0;cursor:pointer;
  }
  .acct-back-btn svg{width:17px;height:17px;}
  .acct-back-btn:active{opacity:.6;}
  .modal-box h3{font-size:17px;margin-bottom:14px;}
  .detail-row{display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid rgba(216,220,228,.5);font-size:13.5px;}
  .detail-row span:first-child{color:var(--muted);}
  /* 2026-09-23(9): 검사 상세 그룹 구분 — 기본 정보(일시~시리얼) / 검사 결과(결과~비고). 그룹의 마지막 행은
     얇은 줄을 없애고, 그룹 사이에 굵은 구분선을 둔다. */
  .detail-group{padding:4px 0 6px;}
  .detail-group > .detail-row:last-child,
  .detail-group > .detail-serial-extra:last-child{border-bottom:none;}
  .detail-group + .detail-group{border-top:2px solid var(--line);border-bottom:2px solid var(--line);margin:6px 0 12px;padding-top:8px;}
  /* 시리얼 행: 누르면 ▾가 돌며 바코드 원문(+관리자 수정 버튼)이 아래로 펼쳐진다 */
  button.detail-serial-toggle{
    width:100%;background:none;border:none;border-bottom:1px solid rgba(216,220,228,.5);
    font:inherit;font-size:13.5px;color:inherit;text-align:left;cursor:pointer;align-items:center;
    -webkit-tap-highlight-color:transparent;
  }
  button.detail-serial-toggle:active{background:rgba(61,90,128,.06);}
  .detail-serial-toggle .dst-val{display:inline-flex;align-items:center;gap:4px;color:var(--ink);}
  .detail-serial-toggle .dst-val span.mono{color:var(--ink);}
  .detail-serial-toggle .dst-chev{width:14px;height:14px;color:var(--muted);opacity:.7;transition:transform .18s ease;}
  .detail-serial-toggle.open .dst-chev{transform:rotate(180deg);}
  .detail-serial-extra{
    margin:6px 0 8px;padding:10px 12px;border-radius:10px;background:var(--steel-soft);
    font-size:12.5px;border-bottom:none;
  }
  .detail-serial-extra .dse-label{font-size:11px;font-weight:700;color:var(--muted);margin-bottom:4px;}
  .detail-serial-extra .dse-raw{word-break:break-all;line-height:1.5;color:var(--ink);font-size:12.5px;}
  .detail-serial-extra .dse-ctl{display:inline-block;padding:0 3px;margin:0 1px;border-radius:4px;background:rgba(95,100,115,.18);color:var(--muted);font-size:10px;vertical-align:1px;}
  .detail-serial-extra .dse-empty{color:var(--muted);}
  .detail-serial-extra .dse-edit{display:block;margin:6px 0 0 auto;}

  /* 내 프로필 창의 "가입된 멤버" 목록 — 아이디 행과 계정 관리 버튼 사이. 관리자 전용인
     계정 관리와 달리 로그인한 사람 누구나 볼 수 있다. 이름을 탭하면 그 아래 전화번호 줄이
     펼쳐진다(.pm-member-phone.hidden 토글). */
  .pm-members-section{border-top:1px dashed var(--line);border-bottom:1px dashed var(--line);margin:14px 0;padding:12px 0;}
  .pm-members-title{font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.03em;margin:0 0 8px;}
  .pm-members-list{display:flex;flex-direction:column;gap:2px;max-height:220px;overflow-y:auto;}
  .pm-member-row{padding:6px 2px;}
  .pm-member-main{display:flex;align-items:center;gap:10px;}
  .pm-member-avatar{
    width:30px;height:30px;border-radius:50%;flex-shrink:0;
    background-size:cover;background-position:center;background-color:var(--steel-soft);
  }
  .pm-member-avatar-fallback{display:flex;align-items:center;justify-content:center;color:var(--steel);font-weight:800;font-size:13px;}
  /* 2026-09-19 후속(16), 2026-09-20 후속(17)에서 이모지 → 벡터 아이콘으로 교체: 사진이 없고
     로고(벡터 아이콘)를 골라둔 멤버는 이니셜 대신 그 아이콘(인라인 svg)을 보여준다 — 배경색은
     그 사람이 고른 iconColor(있으면), 없으면 기본 steel-soft. */
  .pm-member-avatar-logo{display:flex;align-items:center;justify-content:center;}
  .pm-member-avatar-logo svg{width:15px;height:15px;}
  .pm-member-name-btn{background:none;border:none;padding:0;font-size:13.5px;font-weight:600;color:var(--ink);cursor:pointer;text-align:left;}
  .pm-member-name-btn:active{opacity:.6;}
  .pm-member-me{color:var(--muted);font-weight:500;}
  .pm-member-phone{margin:5px 0 0 40px;font-size:12.5px;}
  .pm-member-phone a{color:var(--steel);text-decoration:none;font-weight:700;}
  .pm-member-phone.hidden{display:none;}
  .detail-photos{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:14px 0;}
  .detail-photos img{width:100%;aspect-ratio:1/1;object-fit:cover;border-radius:10px;border:1px solid var(--line);cursor:zoom-in;}
  /* 2026-09-19 추가 후속: 수동으로 추가한 사진 — 검사 당시 사진(photoUrls)과 같은 그리드 안에
     나란히 두되, 위에 얹는 파란 표식/삭제 버튼을 위치시키기 위한 래퍼. 원본 사진(<img>가 그리드에
     바로 있는 경우)에는 이 래퍼가 없으므로 표식/삭제 버튼도 없다 — "원본은 못 건드림"이 마크업
     구조 자체로 보장됨. */
  .detail-photo-item{position:relative;}
  .detail-photo-item img{display:block;}
  .detail-photo-badge{
    position:absolute;top:5px;left:5px;z-index:2;
    background:#3B82F6;color:#fff;font-size:10px;font-weight:800;letter-spacing:.02em;
    padding:2.5px 8px;border-radius:999px;box-shadow:0 2px 6px rgba(20,20,30,.28);
    pointer-events:none;
  }
  .detail-photo-del-btn{
    position:absolute;top:4px;right:4px;z-index:2;
    width:22px;height:22px;border-radius:50%;border:none;
    background:rgba(20,20,24,.62);color:#fff;font-size:15px;line-height:1;font-weight:700;
    display:flex;align-items:center;justify-content:center;cursor:pointer;padding:0;
  }
  .detail-photo-del-btn:active{background:rgba(20,20,24,.85);transform:scale(.94);}
  .detail-photo-add-btn{
    width:100%;aspect-ratio:1/1;border-radius:10px;border:1.5px dashed var(--line);
    background:var(--steel-soft);color:var(--muted);cursor:pointer;
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
    font-size:11.5px;font-weight:700;padding:0;
  }
  .detail-photo-add-btn svg{width:20px;height:20px;}
  .detail-photo-add-btn:active{background:var(--steel);color:#fff;}
  .checks-table{width:100%;border-collapse:collapse;margin:6px 0 4px;font-size:12.5px;}
  .checks-table td{padding:8px 6px;border-bottom:1px solid rgba(216,220,228,.5);}
  .checks-table tr:last-child td{border-bottom:none;}
  .checks-table td.ct-label{color:var(--muted);white-space:nowrap;}
  .checks-table td.ct-value{text-align:right;font-weight:600;padding-right:14px;white-space:nowrap;}
  .checks-table td.ct-value .badge{font-size:11px;padding:2px 8px;}

  /* ---------- photo lightbox (zoom / save / close) ---------- */
  .lightbox{position:fixed;inset:0;background:#0a0a0c;z-index:300;display:flex;flex-direction:column;}
  .lightbox.hidden{display:none;}
  .lightbox-top{display:flex;align-items:center;justify-content:space-between;padding:14px 14px calc(10px + env(safe-area-inset-top,0px));flex-shrink:0;}
  .lightbox-count{color:rgba(255,255,255,.75);font-size:12.5px;font-weight:600;}
  .lightbox-actions{display:flex;gap:8px;}
  .lightbox-btn{
    width:38px;height:38px;border-radius:50%;border:none;background:rgba(255,255,255,.14);color:#fff;
    display:flex;align-items:center;justify-content:center;flex-shrink:0;
  }
  .lightbox-btn:active{background:rgba(255,255,255,.24);}
  .lightbox-btn svg{width:18px;height:18px;}
  .lightbox-stage{flex:1;position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;touch-action:none;}
  .lightbox-stage img{max-width:100%;max-height:100%;object-fit:contain;user-select:none;-webkit-user-drag:none;will-change:transform;}
  .lightbox-hint{text-align:center;color:rgba(255,255,255,.5);font-size:11.5px;padding:8px 14px calc(14px + env(safe-area-inset-bottom,0px));flex-shrink:0;}
  .lightbox-nav{
    position:absolute;top:50%;transform:translateY(-50%);width:38px;height:38px;border-radius:50%;
    border:none;background:rgba(255,255,255,.14);color:#fff;display:flex;align-items:center;justify-content:center;
  }
  .lightbox-nav.prev{left:10px;}
  .lightbox-nav.next{right:10px;}
  .lightbox-nav svg{width:18px;height:18px;}
  .lightbox-nav.hidden{display:none;}
  .modal-close{width:100%;padding:12px;border:1px solid var(--line);background:rgba(255,255,255,.7);border-radius:12px;font-weight:600;margin-top:12px;}
  .modal-close-bar{position:sticky;top:0;z-index:5;display:flex;justify-content:flex-end;margin-bottom:-34px;}
  .modal-x-close{width:32px;height:32px;border-radius:50%;border:1px solid var(--line);background:var(--surface);box-shadow:0 2px 10px rgba(22,24,29,.15);display:flex;align-items:center;justify-content:center;color:var(--muted);cursor:pointer;flex:none;}
  .modal-x-close svg{width:16px;height:16px;}
  .modal-x-close:active{transform:scale(.94);}
  .modal-delete{width:100%;padding:12px;border:1px solid var(--fail);background:rgba(255,255,255,.7);color:var(--fail);border-radius:12px;font-weight:600;margin-top:8px;}

  /* ---------- 관리자 품번/시리얼 수정 + 라벨 재-OCR 불일치 안내 ---------- */
  .detail-row-edit input{
    width:150px;padding:6px 9px;border:1px solid var(--steel);border-radius:8px;
    background:#fff;font-size:13px;text-align:right;font-family:'JetBrains Mono','Noto Sans KR',monospace;
  }
  .detail-row-edit input:focus{outline:2px solid var(--steel);outline-offset:1px;}
  .detail-edit-actions{display:flex;gap:8px;margin:10px 0 4px;}
  .detail-edit-actions button{flex:1;padding:10px;border-radius:12px;font-weight:700;font-size:13.5px;}
  .detail-edit-actions .submit-btn{margin-top:0;padding:10px;font-size:13.5px;}
  .ocr-warn-banner{
    display:flex;gap:9px;align-items:flex-start;background:var(--fail-soft);border:1px solid var(--fail);
    color:var(--fail);border-radius:12px;padding:11px 13px;margin:0 0 12px;font-size:12.5px;line-height:1.5;
  }
  .ocr-warn-banner svg{width:18px;height:18px;flex-shrink:0;margin-top:1px;}
  .ocr-warn-banner b{font-weight:800;}
  .ocr-warn-banner .owb-detail{margin-top:4px;font-family:'JetBrains Mono','Noto Sans KR',monospace;font-size:12px;opacity:.9;}

  /* ---------- 추가 특이사항 로그 (상세보기, 삭제 버튼 위) ---------- */
  .followup-notes-box{margin:2px 0 10px;}
  .followup-note-item{
    background:var(--steel-soft);border-radius:10px;padding:9px 11px;margin-bottom:7px;font-size:13px;line-height:1.5;
  }
  .followup-note-item:last-child{margin-bottom:0;}
  .followup-note-meta{font-size:11.5px;color:var(--muted);font-weight:600;margin-bottom:3px;}
  .followup-note-text{white-space:pre-wrap;word-break:break-word;}
  .followup-note-add textarea{
    width:100%;box-sizing:border-box;padding:9px 11px;border:1px solid var(--steel);border-radius:10px;
    background:#fff;font-family:'Noto Sans KR',sans-serif;font-size:13px;resize:vertical;
  }
  .followup-note-add textarea:focus{outline:2px solid var(--steel);outline-offset:1px;}

  /* ---------- Toast ---------- */
  #toast{
    position:fixed;bottom:22px;left:50%;transform:translateX(-50%) translateY(20px);
    background:rgba(22,24,29,.94);
    color:#fff;padding:12px 20px;border-radius:12px;font-size:13.5px;font-weight:600;
    opacity:0;pointer-events:none;transition:opacity .2s, transform .2s;z-index:80;
    box-shadow:0 8px 24px rgba(0,0,0,.25);
  }
  #toast.show{opacity:1;transform:translateX(-50%) translateY(0);}

  /* ---------- Print report (hidden offscreen, used for print + PDF capture) ----------
     Paginated into discrete .rp-page blocks (~20 records each) so both the browser's
     print/Save-as-PDF and our own jsPDF export get clean page breaks, never a row cut
     in half. Visual style mirrors the app itself (steel-green accents, pill badges,
     record-table look) rather than a generic black-on-white printout. */
  #printReport{position:absolute;left:-9999px;top:0;width:780px;background:#fff;color:#16181D;font-family:'Noto Sans KR',sans-serif;}
  #printReport .rp-page{width:780px;min-height:1040px;padding:34px 36px;box-sizing:border-box;background:#fff;page-break-after:always;}
  #printReport .rp-header{display:flex;justify-content:space-between;align-items:flex-start;border-bottom:2px solid #3D5A80;padding-bottom:14px;margin-bottom:16px;}
  #printReport .rp-header-left{display:flex;align-items:center;gap:12px;}
  #printReport .rp-logo{width:38px;height:38px;border-radius:9px;background:#3D5A80;color:#fff;font-weight:800;font-size:15px;display:flex;align-items:center;justify-content:center;letter-spacing:-.5px;}
  #printReport .rp-title{font-size:18px;font-weight:800;margin:0;}
  #printReport .rp-subtitle{font-size:11.5px;color:#5F6473;margin-top:2px;}
  #printReport .rp-header-right{text-align:right;font-size:10.5px;color:#5F6473;line-height:1.6;}
  #printReport .rp-stats{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-bottom:18px;}
  #printReport .rp-stat{background:#F4F5F7;border-radius:10px;padding:10px 6px;text-align:center;}
  #printReport .rp-stat.pass{background:#E1F0E7;}
  #printReport .rp-stat.rwk{background:#F5E8D6;}
  #printReport .rp-stat.fail{background:#FBE6E1;}
  #printReport .rp-stat-num{display:block;font-size:19px;font-weight:800;font-family:'Roboto Mono',monospace;}
  #printReport .rp-stat-lbl{display:block;font-size:10px;color:#474C5A;margin-top:2px;}
  #printReport .rp-table{width:100%;border-collapse:collapse;font-size:10.3px;}
  #printReport .rp-table th{background:#3D5A80;color:#fff;font-weight:700;padding:7px 6px;text-align:left;white-space:nowrap;}
  #printReport .rp-table td{padding:6px;border-bottom:1px solid #BFC4CD;vertical-align:middle;}
  #printReport .rp-table tr:nth-child(even) td{background:#FFFFFF;}
  #printReport .rp-badge{display:inline-block;padding:2px 8px;border-radius:20px;font-size:9.5px;font-weight:700;}
  #printReport .rp-badge.pass{background:#E1F0E7;color:#2F7350;}
  #printReport .rp-badge.rwk{background:#F5E8D6;color:#966018;}
  #printReport .rp-badge.fail{background:#FBE6E1;color:#C4432E;}
  #printReport .rp-thumb{width:30px;height:30px;object-fit:cover;border-radius:4px;display:block;}
  #printReport .rp-pagefoot{text-align:center;font-size:9.5px;color:#8890A0;margin-top:14px;}

  @media print{
    body *{visibility:hidden;}
    #printReport, #printReport *{visibility:visible;}
    #printReport{position:absolute;left:0;top:0;width:100%;}
    #printReport .rp-page{width:100%;min-height:0;}
    #printReport .rp-page:last-child{page-break-after:auto;}
    /* vendor share view: printing shows only the notice document itself, none of the page chrome */
    .notice-doc, .notice-doc *, .notice-supplement, .notice-supplement *{visibility:visible;}
    .notice-doc{position:absolute;left:0;top:0;width:100%;border-color:#000;box-shadow:none;}
    .notice-supplement{position:absolute;left:0;top:297mm;width:100%;}
    .share-view-header, .share-notice, .notice-actions, .share-view-footer-actions{display:none !important;}
  }

  /* ================= MONOCHROME INPUT PAGE ================= */
  #tab-input.mono-input{
    --mono-bg:#F4F5F7;
    --mono-text:#16181D;
    --mono-ink:#3D5A80;
    --mono-muted:#5F6473;
    --mono-card:#FFFFFF;
    --mono-track:#BFC4CD;
    --mono-accent:#C4432E;
    background:var(--mono-bg);
    margin:-18px -14px calc(-96px - env(safe-area-inset-bottom));
    padding:18px 14px calc(84px + env(safe-area-inset-bottom));
    min-height:100vh;
  }
  #tab-input.mono-input .mono-wrap{max-width:460px;margin:0 auto;}
  #tab-input.mono-input .mono-header{margin-bottom:16px;}
  #tab-input.mono-input .mono-header h1{font-size:25px;font-weight:800;color:var(--mono-text);letter-spacing:-.01em;}
  #tab-input.mono-input .mono-header p{font-size:12.5px;color:var(--mono-muted);font-weight:600;margin-top:2px;}
  #tab-input.mono-input .mono-header-row{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;}
  #tab-input.mono-input .mono-header-stats{text-align:right;display:flex;flex-direction:column;gap:4px;padding-top:5px;flex-shrink:0;}
  #tab-input.mono-input .mhs-line{font-size:12px;color:var(--mono-muted);font-weight:600;white-space:nowrap;}
  #tab-input.mono-input .mhs-value{font-size:14px;font-weight:800;color:var(--mono-text);margin-left:3px;}
  #tab-input.mono-input .mhs-unit{font-size:11.5px;color:var(--mono-muted);margin-left:1px;font-weight:600;}

  #tab-input.mono-input .avatar-row{display:flex;gap:14px;overflow-x:auto;padding:2px 2px 8px;margin-bottom:16px;-webkit-overflow-scrolling:touch;}
  #tab-input.mono-input .avatar-item{display:flex;flex-direction:column;align-items:center;gap:6px;flex-shrink:0;}
  #tab-input.mono-input .avatar-circle{
    width:52px;height:52px;border-radius:50%;flex:none;padding:0;border:none;
    background:var(--mono-ink);color:#fff;font-weight:700;font-size:14px;
    display:flex;align-items:center;justify-content:center;box-shadow:none;transition:transform .1s, background .15s;
  }
  #tab-input.mono-input .avatar-circle:active{transform:scale(.94);}
  #tab-input.mono-input .avatar-circle.selected{background:var(--mono-accent);}
  #tab-input.mono-input .avatar-circle.avatar-add{background:#fff;color:var(--mono-text);border:1.5px dashed #B6BAC4;font-size:20px;font-weight:400;}
  #tab-input.mono-input .avatar-label{font-size:10.5px;color:var(--mono-muted);font-weight:600;white-space:nowrap;}
  #tab-input.mono-input .mono-input-field{
    width:100%;padding:12px;border:1px solid #E3E1DC;border-radius:12px;background:#fff;
    font-size:15px;margin-bottom:16px;
  }

  #tab-input.mono-input .mono-card{
    background:var(--mono-card);border-radius:22px;padding:18px 20px;margin-bottom:12px;
    box-shadow:0 1px 2px rgba(20,20,25,.04);
  }
  #tab-input.mono-input .mono-label{font-size:10.5px;font-weight:700;color:var(--mono-muted);letter-spacing:.04em;text-transform:uppercase;}

  #tab-input.mono-input .mono-card{padding:14px 20px;}
  #tab-input.mono-input .logged-in-strip{display:flex;align-items:center;gap:10px;font-size:13px;color:var(--mono-muted);font-weight:500;}
  #tab-input.mono-input .logged-in-strip b{color:var(--mono-text);font-weight:700;}
  #tab-input.mono-input .li-icon-wrap{position:relative;flex-shrink:0;}
  #tab-input.mono-input .li-icon{
    width:30px;height:30px;border-radius:50%;background:var(--steel-soft);color:var(--steel);
    display:flex;align-items:center;justify-content:center;flex-shrink:0;cursor:pointer;
    transition:transform .15s;background-size:cover;background-position:center;
  }
  #tab-input.mono-input .li-icon:active{transform:scale(.92);}
  #tab-input.mono-input .li-icon:focus-visible{outline:2px solid var(--steel);outline-offset:2px;}
  /* #tab-input.mono-input .li-icon svg 하나로 기본 사람 실루엣 svg와 로고(벡터 아이콘) svg가
     모두 15px로 사이징된다(2026-09-20 후속(17)에서 로고가 이모지 텍스트가 아니라 svg가 되면서,
     별도 .li-icon-emoji 폰트크기 규칙 없이 이 규칙 하나로 통일됨). applyProfileIcon()이
     innerHTML을 통째로 로고 svg 또는 원래 사람 실루엣 svg로 교체한다. */
  #tab-input.mono-input .li-icon svg{width:15px;height:15px;}
  /* 사진을 등록해두면 배경 이미지(96x96, object-fit:cover 대신 background-size:cover로 동일한
     효과)로 채워지므로, 안에 있던 사람 실루엣 svg나 로고 svg는 숨겨서 사진 위에 겹쳐 보이지
     않게 한다. */
  #tab-input.mono-input .li-icon.has-photo svg{display:none;}
  /* 인사말 아이콘 팝오버 — 맨 위에 본인 사진을 등록/변경하는 버튼이 먼저 오고, 사진이 이미
     등록돼 있을 때만 "사진 삭제" 버튼이 추가로 보인다. 그 아래 배경 색상(빠른 선택 10가지 +
     전체 색상표 직접 선택)과 로고(벡터 아이콘 20종) 선택이 이어진다.
     2026-09-19 후속(16): 색상은 원래 서버에 저장하지 않는 기기별 개인 취향(localStorage)이었는데,
     "가입된 멤버" 목록에서 다른 사람에게도 보이게 해달라는 요청으로 사진(photoUrl)과 동일하게
     Firestore accounts/{id}에 저장되는 서버 데이터로 승격시켰다 — 새로 추가한 로고(iconGlyph)도
     처음부터 같은 방식. 2026-09-20 후속(17): 로고를 이모지에서 벡터 아이콘(vector-icons.js)으로
     완전 교체 — 이모지의 기기별 렌더링 불일치 문제를 없애기 위함. */
  .li-color-popover{
    position:absolute;top:calc(100% + 8px);left:0;z-index:20;
    background:var(--surface);border:1px solid var(--line);border-radius:14px;
    padding:10px 12px 12px;box-shadow:0 8px 24px rgba(22,24,29,.18);width:200px;
    max-height:min(70vh, 480px);overflow-y:auto;
  }
  .li-color-popover.hidden{display:none;}
  .li-color-title{font-size:11px;font-weight:700;color:var(--muted);margin:0 0 8px;}
  .li-color-divider{border-top:1px dashed var(--line);margin:10px 0 8px;}
  .li-photo-action-btn{
    display:flex;align-items:center;justify-content:center;gap:6px;width:100%;
    padding:9px 10px;margin-bottom:6px;border:1px solid var(--line);border-radius:10px;
    background:var(--bg);color:var(--ink);font-size:12.5px;font-weight:700;cursor:pointer;
  }
  .li-photo-action-btn svg{width:15px;height:15px;flex-shrink:0;}
  .li-photo-action-btn:active{transform:scale(.97);}
  .li-photo-action-btn.li-photo-remove{color:var(--fail);border-color:var(--fail-soft);background:var(--fail-soft);margin-bottom:0;}
  /* display:flex가 hidden 속성의 기본 display:none보다 우선 적용돼버리는 걸 막는다 — 사진이
     없을 때는 "사진 삭제" 버튼이 실제로 안 보여야 함. */
  .li-photo-action-btn[hidden]{display:none;}
  .li-color-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;}
  .li-color-swatch{
    width:26px;height:26px;border-radius:50%;border:2px solid rgba(255,255,255,.9);
    box-shadow:0 0 0 1px var(--line);cursor:pointer;padding:0;transition:transform .1s;
  }
  .li-color-swatch:active{transform:scale(.88);}
  /* 2026-09-19 후속(16): 현재 선택된 색상/로고를 팝오버를 열 때마다 표시(markSelectedSwatches) —
     서버에 저장되는 값이라 다른 기기에서 바꾼 뒤 다시 열어도 지금 값이 어느 것인지 바로 보여야
     한다. 기존 box-shadow(테두리용)에 링을 하나 더 얹는 방식. */
  .li-color-swatch.selected{box-shadow:0 0 0 1px var(--line), 0 0 0 3px var(--steel);}
  /* "빠른 선택" 10가지 외에 전체 스펙트럼에서 직접 고를 수 있는 네이티브 색상 선택기 — 요청한
     "넓은 스펙트럼"은 팔레트 개수를 늘리는 대신 이 방식으로 제공한다(브라우저 기본 색상표라
     추가 라이브러리 없이 모든 색을 다 고를 수 있음). 값이 바뀔 때마다(드래그 중이 아니라 확정
     시점인 change 이벤트에서만) 서버에 저장 — input 이벤트로 하면 드래그 중에 계속 PATCH가
     나가서 낭비가 크다. */
  .li-color-custom-row{
    display:flex;align-items:center;justify-content:space-between;gap:8px;
    margin:10px 0 0;font-size:12px;color:var(--muted);font-weight:600;cursor:pointer;
  }
  .li-color-custom-row input[type=color]{
    width:34px;height:26px;padding:0;border:1px solid var(--line);border-radius:6px;
    background:none;cursor:pointer;flex-shrink:0;
  }
  /* 로고(벡터 아이콘) 그리드 — 20종(2026-09-20 후속(17)에서 이모지 20종을 완전 교체). 색상
     그리드와 같은 5열 배치를 재사용해 팝오버 너비를 그대로 맞췄다. */
  .li-logo-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:6px;margin-bottom:8px;}
  .li-logo-swatch{
    width:28px;height:28px;border-radius:8px;border:1px solid var(--line);background:var(--bg);
    color:var(--ink);display:flex;align-items:center;justify-content:center;
    cursor:pointer;padding:0;transition:transform .1s, background .15s, border-color .15s;
  }
  .li-logo-swatch svg{width:15px;height:15px;}
  .li-logo-swatch:active{transform:scale(.88);}
  .li-logo-swatch.selected{background:var(--steel-soft);border-color:var(--steel);}
  #tab-input.mono-input .today-strip{display:flex;align-items:center;}
  #tab-input.mono-input .strip-item{flex:1;display:flex;align-items:baseline;justify-content:center;gap:7px;}
  #tab-input.mono-input .strip-num{font-size:19px;font-weight:800;color:var(--mono-text);}
  #tab-input.mono-input .strip-label{font-size:12px;color:var(--mono-muted);font-weight:600;}
  #tab-input.mono-input .strip-divider{width:1px;height:22px;background:#E9E7E2;margin:0 6px;}

  #tab-input.mono-input .mono-form-card{background:var(--mono-card);border-radius:22px;padding:20px;box-shadow:0 1px 2px rgba(20,20,25,.04);}
  #tab-input.mono-input .mono-field{margin-bottom:16px;}
  #tab-input.mono-input .mono-field label{display:block;font-size:12px;font-weight:700;color:var(--mono-muted);margin-bottom:7px;}
  #tab-input.mono-input .mono-field input[type=text], #tab-input.mono-input .mono-field input[type=number], #tab-input.mono-input .mono-field textarea{
    width:100%;padding:12px;border:1px solid #E3E1DC;border-radius:12px;background:#FBFAF8;font-size:16px;color:var(--mono-ink);
  }
  #tab-input.mono-input .mono-field input:focus, #tab-input.mono-input .mono-field textarea:focus{outline:2px solid var(--mono-ink);outline-offset:1px;}
  #tab-input.mono-input .mono-field textarea{resize:vertical;min-height:64px;}
  #tab-input.mono-input .req::after{content:" *";color:var(--mono-accent);}

  #tab-input.mono-input .now-row{display:flex;align-items:center;gap:12px;}
  #tab-input.mono-input .now-btn{
    flex-shrink:0;width:88px;padding:11px 4px;border-radius:14px;border:none;
    background:var(--mono-ink);color:#fff;font-weight:700;font-size:13px;
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;box-shadow:none;
  }
  #tab-input.mono-input .now-btn:active{transform:scale(.96);}
  #tab-input.mono-input .now-ico{width:16px;height:16px;}
  #tab-input.mono-input .now-display{font-size:13.5px;font-weight:700;color:var(--mono-text);margin-bottom:2px;}
  #tab-input.mono-input .link-btn{color:var(--mono-ink);text-decoration:underline;font-size:12px;font-weight:600;border:none;background:none;padding:4px 0;}
  #tab-input.mono-input .dt-manual{width:100%;padding:9px 11px;border:1px solid #E3E1DC;border-radius:12px;background:#FBFAF8;font-size:14px;margin-top:8px;}

  #tab-input.mono-input .result-cards-3{grid-template-columns:1fr 1fr 1fr;}
  #tab-input.mono-input .model-btn-group{display:flex;flex-wrap:wrap;gap:8px;}
  #tab-input.mono-input .model-btn{
    padding:10px 20px;border-radius:20px;border:1.5px solid #E9E7E2;background:#FBFAF8;
    font-size:14px;font-weight:700;color:var(--mono-muted);
  }
  #tab-input.mono-input .model-btn.selected{background:var(--mono-ink);border-color:var(--mono-ink);color:#fff;}

  #tab-input.mono-input .check-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px;}
  #tab-input.mono-input .check-all-toggle{display:flex !important;align-items:center;gap:0;position:relative;}
  #tab-input.mono-input .check-all-toggle input{position:absolute;opacity:0;width:0;height:0;pointer-events:none;}
  #tab-input.mono-input .check-list{
    display:flex;flex-direction:column;gap:2px;border:1px solid #E9E7E2;border-radius:14px;
    background:#FBFAF8;overflow:hidden;
  }
  #tab-input.mono-input .check-item{
    display:flex !important;align-items:center;justify-content:space-between;flex-wrap:nowrap;gap:8px;padding:11px 12px;font-size:13px;color:var(--mono-text);
    border-bottom:1px solid #EFEDE7;cursor:pointer;position:relative;
  }
  #tab-input.mono-input .check-item:last-child{border-bottom:none;}
  #tab-input.mono-input .check-item input.check-item-box{position:absolute;opacity:0;width:0;height:0;pointer-events:none;}
  #tab-input.mono-input .check-item .chk-text{
    flex:1;min-width:0;transition:color .15s;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  }
  #tab-input.mono-input .chk-pill{
    display:flex;align-items:center;justify-content:center;gap:3px;flex-shrink:0;white-space:nowrap;
    padding:5px 11px;border-radius:20px;
    border:1.5px solid #D6D9E0;background:#fff;color:var(--mono-muted);font-size:11px;font-weight:700;
    transition:background .15s, border-color .15s, color .15s;
  }
  #tab-input.mono-input .chk-pill svg{width:10px;height:10px;opacity:0;transition:opacity .15s;flex-shrink:0;}
  #tab-input.mono-input .check-item input:checked ~ .chk-pill,
  #tab-input.mono-input .check-all-toggle input:checked ~ .chk-pill{background:var(--pass-soft);border-color:var(--pass);color:var(--pass);}
  #tab-input.mono-input .check-item input:checked ~ .chk-pill svg,
  #tab-input.mono-input .check-all-toggle input:checked ~ .chk-pill svg{opacity:1;}
  #tab-input.mono-input .check-item input:checked ~ .chk-text{color:var(--pass);font-weight:700;}
  #tab-input.mono-input .back-spec-row{margin-top:10px;padding:12px 14px;border:1px solid #E9E7E2;border-radius:14px;background:#FBFAF8;}
  #tab-input.mono-input .back-spec-label{font-size:13px;font-weight:700;color:var(--mono-text);display:block;}
  #tab-input.mono-input .back-spec-value{font-weight:600;color:var(--mono-muted);font-size:12px;}
  #tab-input.mono-input .back-spec-inputs{display:flex;gap:10px;margin-top:8px;}
  #tab-input.mono-input .back-spec-input-wrap{flex:1;}
  #tab-input.mono-input .back-spec-input-wrap label{display:block;font-size:10.5px;font-weight:700;color:var(--mono-muted);margin-bottom:4px;text-transform:uppercase;}
  #tab-input.mono-input .back-spec-input-wrap input{width:100%;padding:9px 10px;border:1px solid #E3E1DC;border-radius:10px;background:#fff;font-size:15px;}
  #tab-input.mono-input .result-cards{display:grid;grid-template-columns:1fr 1fr;gap:10px;}
  #tab-input.mono-input .result-cards-main{display:flex;flex-direction:column;gap:10px;}
  #tab-input.mono-input .result-cards-sub{display:grid;grid-template-columns:1fr 1fr;gap:10px;}
  #tab-input.mono-input .result-card{
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
    padding:14px 8px;border-radius:16px;border:1.5px solid #E9E7E2;background:#FBFAF8;text-align:center;
    transition:background .15s, border-color .15s, opacity .15s;
  }
  #tab-input.mono-input .result-card-pass{width:100%;padding:17px 8px;}
  #tab-input.mono-input .result-card:disabled{opacity:.4;cursor:not-allowed;}
  #tab-input.mono-input .result-card-title{font-size:14.5px;font-weight:800;color:var(--mono-text);}
  #tab-input.mono-input .result-card-sub{font-size:11.5px;color:var(--mono-muted);font-weight:600;}
  #tab-input.mono-input .result-card.pass.selected{background:var(--mono-ink);border-color:var(--mono-ink);}
  #tab-input.mono-input .result-card.pass.selected .result-card-title,
  #tab-input.mono-input .result-card.pass.selected .result-card-sub{color:#fff;}
  #tab-input.mono-input .result-card.rwk.selected{background:var(--amber);border-color:var(--amber);}
  #tab-input.mono-input .result-card.rwk.selected .result-card-title,
  #tab-input.mono-input .result-card.rwk.selected .result-card-sub{color:#fff;}
  #tab-input.mono-input .result-card.fail.selected{background:var(--mono-accent);border-color:var(--mono-accent);}
  #tab-input.mono-input .result-card.fail.selected .result-card-title,
  #tab-input.mono-input .result-card.fail.selected .result-card-sub{color:#fff;}

  #tab-input.mono-input .chip-row{display:flex;flex-wrap:wrap;gap:8px;}
  #tab-input.mono-input .chip{
    padding:9px 14px;border-radius:20px;border:1.5px solid #E9E7E2;background:#FBFAF8;
    font-size:13.5px;font-weight:600;color:var(--mono-muted);
  }
  #tab-input.mono-input .chip.selected{border-color:var(--mono-accent);color:#fff;background:var(--mono-accent);}
  #tab-input.mono-input .defect-block{margin-top:14px;padding-top:14px;border-top:1px dashed #E3E1DC;}
  #tab-input.mono-input .hint{font-size:12px;color:var(--mono-muted);margin-top:6px;}

  #tab-input.mono-input .photo-add-btn{
    display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:14px;
    border:1.5px dashed #B6BAC4;border-radius:14px;background:#FBFAF8;color:var(--mono-ink);font-weight:600;font-size:14px;
  }
  #tab-input.mono-input .photo-add-btn svg{width:18px;height:18px;}
  #tab-input.mono-input .thumb{border-radius:12px;border:1px solid #E9E7E2;box-shadow:none;}

  /* 카드 배경(--mono-card) 위에서도 기본 .scan-btn의 버건디+글로우가 그대로 선명하게
     보이므로 배경은 다시 정의하지 않고, 그림자 톤만 이 카드 배경에 맞게 조금 더 부드럽게. */
  #tab-input.mono-input .scan-btn{
    box-shadow:0 8px 18px rgba(59,15,36,.35);
  }
  #tab-input.mono-input .scan-btn:active{box-shadow:0 4px 10px rgba(59,15,36,.3);}

  #tab-input.mono-input .submit-btn{
    width:100%;padding:16px;border:none;border-radius:16px;background:var(--mono-ink);color:#fff;
    font-weight:700;font-size:15.5px;margin-top:4px;box-shadow:none;
  }
  #tab-input.mono-input .submit-btn:active{transform:scale(.99);background:#000;}
  #tab-input.mono-input .submit-btn:disabled{background:#B6BAC4;}

  /* ---------- Login screen ---------- */
  /* ---------- Barcode scan modal ---------- */
  .scan-video-wrap{position:relative;width:100%;aspect-ratio:4/3;background:#000;border-radius:14px;overflow:hidden;margin-top:4px;}
  .scan-video-wrap video{width:100%;height:100%;object-fit:cover;transform-origin:center center;transition:transform .15s ease;}
  /* 하드웨어 줌이 안 되는 기기에서 화면상으로 확대해 보여주는 대체 수단 — 실제 촬영 프레임은
     그대로지만, OCR 크롭 영역 계산(computeGuideBoxSourceRect)에서 이 배율만큼 보정해서 맞춘다. */
  .scan-video-wrap video.zoomed{transform:scale(var(--css-zoom, 2));}
  .scan-zoom-btn{position:absolute;right:10px;bottom:10px;z-index:2;background:rgba(0,0,0,.55);color:#fff;border:1.5px solid rgba(255,255,255,.7);border-radius:999px;padding:6px 13px;font-size:12.5px;font-weight:700;letter-spacing:.02em;}
  .scan-zoom-btn.off{background:rgba(255,255,255,.15);color:rgba(255,255,255,.8);border-color:rgba(255,255,255,.4);}
  /* 2026-09-19 후속: 손전등 버튼 — 줌 버튼과 같은 톤/모양이지만 반대편(좌하단)에 두고, 지원되는
     기기에서만 표시(기본은 hidden, JS가 getCapabilities().torch 확인 후 보여줌). 켜진 상태는
     눈에 잘 띄는 노란색으로 강조해 "지금 플래시가 켜져 있다"를 한눈에 알 수 있게 함. */
  .scan-flash-btn{position:absolute;left:10px;bottom:10px;z-index:2;background:rgba(0,0,0,.55);color:#fff;border:1.5px solid rgba(255,255,255,.7);border-radius:999px;padding:6px 13px;font-size:12.5px;font-weight:700;letter-spacing:.02em;}
  .scan-flash-btn.on{background:#F4C868;color:#2a2200;border-color:#F4C868;}
  .scan-flash-btn.hidden{display:none;}
  /* 2026-09-22 추가: 근거리 자동초점(manual+focusDistance)이 실기기에서 안 맞을 때 그 자리에서
     가깝게/멀게 조절하는 버튼 — manual+focusDistance를 지원하는 기기에서만 hidden이 풀림
     (js/input-tab.js updateFocusAdjustUI() 참고). 영상 영역 밖(아래)에 둬서 탭-초점 핸들러와
     겹치지 않게 함. */
  .scan-focus-adjust{display:flex;align-items:center;gap:8px;margin-top:8px;}
  .scan-focus-adjust.hidden{display:none;}
  .scan-focus-adjust-label{font-size:12px;color:var(--muted, #6b7280);white-space:nowrap;}
  .scan-focus-adjust-btn{flex:1;background:#EEF1F6;color:var(--steel-dark, #1F2937);border:1.5px solid #D7DCE5;border-radius:10px;padding:7px 10px;font-size:12.5px;font-weight:700;letter-spacing:.01em;}
  .scan-focus-adjust-btn:active{background:#E1E6EF;}
  /* 2026-09-19 후속(15): 인식 성공/중복·실패 순간에 화면 가장자리가 색으로 살짝 번지는
     그라데이션 피드백 — 기존 소리(sound.js)/진동(haptics.js)과 같은 순간에 함께 켜진다.
     modal 전체(화면 전체)를 덮는 고정 오버레이지만, 모달 상자(.modal-box)를 이 안에서만
     position:relative + 더 높은 z-index로 올려서 그 위에 그려지게 한다(position이 걸린
     요소는 CSS 페인트 순서상 항상 static 요소보다 나중에, 즉 위에 그려지므로 DOM 순서만으론
     상자 뒤로 보낼 수 없음) — 그래서 실제로는 상자에 가려지지 않는 화면 가장자리 부분에만
     이 글로우가 보인다. 바텀시트 모달이라 특히 위쪽 가장자리가 넓게 보여서 효과가 잘 드러난다.
     중심은 완전히 투명하게 비워두고 가장자리로 갈수록 색이 번지도록 radial-gradient로 만들어
     "그라데이션"답게 표현했다. */
  .scan-edge-glow{
    position:fixed;inset:0;z-index:1;pointer-events:none;
    opacity:0;transition:opacity .5s ease-out;
  }
  #scanModal .modal-box{position:relative;z-index:2;}
  .scan-edge-glow.show{opacity:1;transition:opacity .12s ease-in;}
  .scan-edge-glow.ok{
    background:radial-gradient(ellipse 120% 90% at 50% 50%,
      rgba(141,198,63,0) 55%,
      rgba(141,198,63,.30) 78%,
      rgba(181,230,90,.62) 100%);
  }
  .scan-edge-glow.fail{
    background:radial-gradient(ellipse 120% 90% at 50% 50%,
      rgba(196,67,46,0) 55%,
      rgba(196,67,46,.26) 78%,
      rgba(217,123,108,.55) 100%);
  }
  /* 탭하여 초점 맞추기 — 탭한 지점에 잠깐 나타났다 사라지는 링. 실제 초점 적용 성공 여부와
     무관하게(iOS 등 미지원 기기에서도) "탭이 인식됐다"는 즉각적 피드백을 준다. */
  .scan-focus-ring{
    position:absolute;width:64px;height:64px;margin-left:-32px;margin-top:-32px;
    border:2px solid #F4C868;border-radius:10px;pointer-events:none;z-index:3;
    opacity:0;transform:scale(1.3);transition:opacity .25s ease-out, transform .25s ease-out;
  }
  .scan-focus-ring.show{opacity:1;transform:scale(1);transition:opacity .18s ease-out, transform .18s ease-out;}
  .scan-frame{position:absolute;inset:14%;border:2.5px solid #fff;border-radius:10px;box-shadow:0 0 0 999px rgba(0,0,0,.35);pointer-events:none;transition:border-color .3s;}
  /* 자동 인식이 진행 중일 때 사각형 테두리가 은은하게 깜빡여서, 셔터 없이도 "지금 계속 시도
     중"이라는 걸 눈으로 알 수 있게 합니다. */
  .scan-frame.scanning{animation:scanPulse 1.4s ease-in-out infinite;}
  @keyframes scanPulse{
    0%, 100%{border-color:#fff;}
    50%{border-color:#82A990;}
  }
  /* 인식된 품번/시리얼 입력칸 — flex 아이템 기본 min-width(auto)가 내용 기준으로 잡히면서
     칸 두 개가 모달 폭을 넘치던 문제 수정. min-width:0 + box-sizing:border-box로 폭을
     강제로 줄어들게 하고, spec-info-pill과 같은 톤(steel-soft 배경의 둥근 알약 모양)으로
     통일해 디자인도 맞춘다. */
  #scanGuessLot, #scanGuessSerial{
    flex:1;min-width:0;width:100%;box-sizing:border-box;
    text-align:center;font-size:14px;font-weight:700;letter-spacing:.2px;
    color:var(--steel);background:var(--steel-soft);border:none;border-radius:14px;
    padding:11px 8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  #scanGuessLot::placeholder, #scanGuessSerial::placeholder{color:var(--muted);font-weight:600;}
  #scanGuessLot:focus, #scanGuessSerial:focus{outline:2px solid var(--steel);outline-offset:1px;background:rgba(255,255,255,.9);}
  /* 이번에 채워진 값이 바코드 직접 해독으로 나온 건지, 기존 OCR(문자 인식) 폴백으로 나온
     건지 눈으로 구분할 수 있는 작은 표시. 개발자 도구를 열 줄 모르는 현장 사용자도 "지금
     바코드로 읽혔는지"를 바로 확인하고 알려줄 수 있게 하기 위함(2026-09 바코드 해독 도입 시
     실사용 피드백을 빠르게 받기 위해 추가). display를 직접 주는 클래스라 [hidden] 재정의가
     필요함(브라우저 기본 [hidden]{display:none}보다 동일 명시도의 author 클래스가 항상 이김).*/
  .scan-source-tag{
    display:inline-flex;align-items:center;gap:5px;margin:0;padding:4px 10px;
    border-radius:999px;font-size:11.5px;font-weight:700;letter-spacing:.01em;
  }
  .scan-source-tag[hidden]{display:none;}
  .scan-source-tag.via-barcode{background:rgba(47,115,80,.14);color:var(--pass);}
  .scan-source-tag.via-ocr{background:var(--steel-soft);color:var(--muted);}

  /* 로그인 화면 기본 틀 — 세부 디자인은 파일 맨 끝 "LOGIN LANDING" 섹션 참고 */
  .login-screen{
    position:fixed;inset:0;z-index:100;background:#050a1a;
    overflow-x:hidden;overflow-y:auto;-webkit-overflow-scrolling:touch;
  }
  .login-screen.hidden{display:none;}
  /* 2026-09-22 추가: 로그인 성공 시 로그인 화면이 곧바로 사라지는 대신, 로고와 같은 브랜드
     블루가 화면 아래에서 위로 서서히 차오른 뒤(다 덮이면 그 밑에서 메인 화면으로 실제 전환이
     일어남) 옅어지며 다음 화면을 드러내는 연출용 오버레이. js/auth.js의 loginBtn 클릭
     핸들러가 로그인 성공 시에만 body에 붙였다 뗀다(세션 복원 시의 applySession()에는
     관여하지 않음 — 새로고침마다 이 연출이 반복되면 오히려 거슬리므로 실제 "로그인" 동작
     에만 한정). */
  /* 2026-09-23(3): 로그인 전환 연출 교체 — 파란 막이 아래에서 차오르던 방식 대신, 로그인 화면과 같은 블랙 톤이
     화면 전체를 흐리게(블러) 덮었다가, 그 밑에서 앱 화면으로 바뀐 뒤 블러가 풀리며 서서히 사라진다.
     .in: 0.5s 동안 어두워지며 블러 0→18px / .out: 0.7s 동안 블러 18px→0, 투명해짐. */
  .login-transition-overlay{
    position:fixed;inset:0;z-index:9999;pointer-events:none;
    background:rgba(7,9,13,0);
    -webkit-backdrop-filter:blur(0px) saturate(1);backdrop-filter:blur(0px) saturate(1);
  }
  .login-transition-overlay.in{animation:loginVeilIn .5s cubic-bezier(.4,0,.2,1) forwards;}

  .login-transition-overlay.out{animation:loginVeilOut .75s cubic-bezier(.3,0,.2,1) forwards;}
  @keyframes loginVeilIn{
    from{background:rgba(7,9,13,0);-webkit-backdrop-filter:blur(0px) saturate(1);backdrop-filter:blur(0px) saturate(1);}
    to{background:rgba(7,9,13,.82);-webkit-backdrop-filter:blur(18px) saturate(.8);backdrop-filter:blur(18px) saturate(.8);}
  }
  @keyframes loginVeilOut{
    from{background:rgba(7,9,13,.82);-webkit-backdrop-filter:blur(18px) saturate(.8);backdrop-filter:blur(18px) saturate(.8);}
    to{background:rgba(7,9,13,0);-webkit-backdrop-filter:blur(0px) saturate(1);backdrop-filter:blur(0px) saturate(1);}
  }
  /* 덮이는 동안 로그인 카드는 살짝 작아지며 물러난다 */
  .login-screen .ll-card-wrap{transition:scale .5s cubic-bezier(.4,0,.2,1);}
  .login-screen.ll-leaving .ll-card-wrap{scale:.96;} /* transform은 등장 애니메이션(llRise)이 쥐고 있어 개별 속성 scale 사용 */
  @media (prefers-reduced-motion: reduce){
    .login-transition-overlay.in,.login-transition-overlay.out{animation-duration:.01s;}
  }

  @media(max-width:760px){
    .stat-row{grid-template-columns:repeat(2,1fr);}
    .stat-row-4{grid-template-columns:repeat(2,1fr);}
    .stat-row-5{grid-template-columns:repeat(2,1fr);}
    .stat-card .lbl{font-size:11px;}
    .brand-text{font-size:14px;}
    .dash-toolbar{padding:8px 12px;}
    .dash-toolbar-fields{grid-template-columns:1fr 1fr;gap:8px;}
    /* iOS Safari squeezes the native date-picker's mm/dd/yyyy segments into overlapping
       text when the input is narrow. Giving each date field its own full-width row
       (instead of squeezing two side by side) is what actually fixes it. */
    .dash-toolbar-fields .field-date{grid-column:1 / -1;}
    .dash-toolbar input[type=date]{
      padding:10px 10px;font-size:15px;width:100%;box-sizing:border-box;min-width:0;
      -webkit-appearance:none;appearance:none;
    }
  }

  /* ==========================================================================
     성적서 발행 탭 (2026-09-21 신규) — js/cert-tab.js가 렌더링하는 마크업 전용 스타일.
     .cert-page 아래는 화면 미리보기와 PDF 캡처(html2canvas)가 동일한 DOM을 쓰므로, 여기서
     보이는 그대로가 곧 PDF 결과물이다 — 실제 검사성적서 양식(테두리 있는 표, □■ 체크박스,
     ①~⑥ 원문자, X̄/R/Cp 통계열)의 느낌을 내되 인쇄 가독성을 우선한다.
     ========================================================================== */
  .cert-part-picker{
    display:flex;flex-wrap:wrap;gap:10px;max-height:260px;overflow-y:auto;padding:2px;
  }
  /* 버튼 크기를 품번/품명 길이에 관계없이 모두 동일하게 고정(2026-09-21, 37번 항목 후속 —
     "버튼 크기는 동일하게"). flex-grow/shrink를 0으로 고정하고 폭·높이를 모두 지정한 뒤,
     내용이 넘칠 때는 말줄임(ellipsis)으로 처리해 카드 크기가 흔들리지 않게 한다.
     2026-09-22 후속: 품번/품명/사양뱃지 세 줄이 일부 기기(특히 모바일)에서 글자가 겹쳐
     보인다는 신고 — 원인은 이 세 span 모두 line-height를 지정하지 않아 기본값인
     line-height:normal로 렌더링되고 있었던 것. `normal`은 스펙상 "폰트가 권장하는 값"이라
     브라우저/기기의 폰트 렌더러마다 실제 계산값이 다르며, 특히 JetBrains Mono(고정폭)처럼
     일반 본문 폰트와 줄간격 메트릭이 다른 폰트를 섞어 쓰면 일부 렌더러에서 줄 사이 간격이
     글자 높이보다 좁게 계산돼 인접한 줄끼리 겹쳐 보일 수 있다. 세 span 모두 명시적
     line-height를 줘서 기기·폰트 로딩 상태와 무관하게 항상 같은 간격이 나오도록 고정하고,
     카드 높이/패딩/줄 간격도 함께 넉넉하게 늘렸다. */
  .cert-part-opt{
    display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:4px;
    padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--surface);
    text-align:left;width:180px;height:74px;flex:0 0 180px;box-sizing:border-box;overflow:hidden;
  }
  .cert-part-opt.selected{border-color:var(--steel);background:rgba(61,90,128,.08);}
  .cert-part-opt-pn{
    font-family:'JetBrains Mono',monospace;font-size:13px;font-weight:700;color:var(--ink);
    line-height:1.3;letter-spacing:.2px;
    max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  }
  .cert-part-opt-name{
    font-size:11px;color:var(--muted);line-height:1.35;
    max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  }
  .cert-part-opt-cat{
    font-size:10px;font-weight:700;color:var(--steel-dark);background:rgba(61,90,128,.12);
    line-height:1.3;padding:1px 7px;border-radius:8px;
  }
  .cert-empty-hint{padding:18px 4px;font-size:13px;color:var(--muted);text-align:center;}

  .cert-selected-list{display:flex;flex-direction:column;gap:8px;}
  .cert-sel-row{
    display:flex;align-items:center;gap:10px;padding:9px 12px;border:1px solid var(--line);
    border-radius:11px;background:var(--surface);
  }
  .cert-sel-info{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0;}
  .cert-sel-pn{font-family:'JetBrains Mono',monospace;font-size:12.5px;font-weight:700;color:var(--ink);}
  .cert-sel-name{font-size:11px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  .cert-sel-qty{
    width:56px;padding:7px 8px;border:1px solid var(--line);border-radius:8px;
    font-size:13px;text-align:center;font-family:'JetBrains Mono',monospace;
  }
  .cert-sel-qty-label{font-size:11px;color:var(--muted);}
  .cert-sel-remove{
    width:26px;height:26px;border-radius:50%;border:1px solid var(--line);background:var(--bg);
    color:var(--muted);font-size:12px;flex-shrink:0;
  }

  .cert-export-btns{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap;}
  .cert-export-btns .btn-ghost:disabled{opacity:.45;}

  .cert-preview-scroll{overflow-x:auto;padding-bottom:6px;}

  .cert-page{
    background:#fff;border:1px solid var(--line);border-radius:4px;padding:16px 18px;
    margin-bottom:22px;min-width:1180px;font-size:11px;color:var(--ink);
  }
  .cert-page-titlebar{
    display:flex;align-items:center;justify-content:center;gap:10px;position:relative;margin-bottom:8px;
  }
  .cert-page-title{
    text-align:center;font-size:14px;font-weight:800;letter-spacing:1px;color:var(--ink);
  }
  /* 원본에 있던 "작성일 :" 메모 — 표 좌상단 바깥, 우측 정렬, 밑줄(원본은 셀 하단 medium
     테두리)로 표시되던 작은 노트. 표 자체의 셀은 아니지만 원본 문서에 실제로 있는 요소라
     동일하게 재현함. */
  .cert-hd-note{
    text-align:right;font-size:9.5px;color:var(--ink);margin-bottom:2px;padding-right:2px;
  }
  .cert-hd-note span{border-bottom:1.5px solid #8A8F99;padding:0 4px 1px;}
  /* 원본 엑셀에 실제로 박혀 있던 DDTZ 로고 — 갑지/을지 각 제목 줄 우측 끝에 원본과 동일한
     위치로 배치(작은 사이즈, 절대위치로 오른쪽 정렬해서 가운데 제목 텍스트와 겹치지 않게 함). */
  .cert-logo{
    position:absolute;right:0;top:50%;transform:translateY(-50%);
    height:30px;width:auto;
  }
  /* 을지 "검사 부위(Sketch)" 열 — 원본과 동일하게 시트/트랙 어셈블리 CAD 참고도 이미지 1장을
     6개 치수 항목 전체 높이에 걸쳐(rowspan) 하나로 배치. */
  .cert-sketch-cell{width:150px;padding:3px;vertical-align:middle;background:#fff;}
  /* 참고도 위에 측정 위치 번호(①~⑤)와 빨간 치수선/화살표를 겹쳐 그림(2026-09-21, 39번 항목
     후속). 래퍼는 원본 그림 그룹의 가로세로 비율(2467028:2612142 EMU)을 그대로 유지해, 안의
     모든 요소를 %로 배치해도 원본과 같은 상대 위치가 나오게 함. */
  .cert-sketch-wrap{position:relative;width:100%;aspect-ratio:246.7028/261.2142;}
  .cert-sketch-img{position:absolute;left:19.78%;top:5.88%;width:80.22%;height:91.33%;display:block;}
  .cert-sk-line-v{position:absolute;width:0;border-left:1px solid #FF0000;}
  .cert-sk-line-h{position:absolute;height:0;border-top:1px solid #FF0000;}
  .cert-sk-tri{position:absolute;width:0;height:0;}
  .cert-sk-tri-left{border-top:3px solid transparent;border-bottom:3px solid transparent;border-right:5px solid #FF0000;transform:translate(0,-3px);}
  .cert-sk-tri-right{border-top:3px solid transparent;border-bottom:3px solid transparent;border-left:5px solid #FF0000;transform:translate(-5px,-3px);}
  .cert-sk-tri-up{border-left:3px solid transparent;border-right:3px solid transparent;border-bottom:5px solid #FF0000;transform:translate(-3px,0);}
  .cert-sk-tri-down{border-left:3px solid transparent;border-right:3px solid transparent;border-top:5px solid #FF0000;transform:translate(-3px,-5px);}
  .cert-sketch-label{
    position:absolute;display:flex;align-items:center;justify-content:center;
    color:#FF0000;font-size:11px;font-weight:600;text-align:center;line-height:1.2;
  }
  .cert-sketch-label-2l{flex-direction:column;gap:2px;}
  .cert-tbl{width:100%;border-collapse:collapse;table-layout:fixed;font-size:10.5px;}
  .cert-tbl th, .cert-tbl td{
    border:1px solid #8A8F99;padding:2px 3px;text-align:center;vertical-align:middle;
    overflow:hidden;text-overflow:ellipsis;
    /* 2026-09-22 추가: line-height를 body 기본값(1.5, 폰트별 계산 편차 존재)에 맡기지 않고
       표 전용으로 명시. white-space는 여기(기본 규칙)에서 nowrap으로 강제하지 않는다 —
       규격(.cert-spec)/소분류(.cert-desc) 칸은 원래 줄바꿈으로 긴 문구를 2줄 이상 표시하는
       중이라, 여기서 nowrap을 걸면 그 칸들의 말줄임(생략) 처리가 되며 오히려 퇴행함. 대신
       아래 측정치류(.cert-val 등, 한 토큰짜리 짧은 값만 들어가는 칸)에만 개별적으로
       white-space:nowrap을 준다 — 그 칸들은 text-overflow:ellipsis가 붙어 있는데
       white-space:nowrap 없이는 ellipsis가 스펙상 아예 동작하지 않고, 수량이 늘어나 칸이
       좁아질 때(수량 10개) 줄바꿈을 시도하며 글자가 눌려 보인다는 신고의 원인으로 추정됨. */
    line-height:1.35;
  }
  /* 원본 엑셀 셀 채우기 색을 그대로 사용(2026-09-21, 37번 항목 후속 — "원문의 노란색 계열을
     그대로 사용"). 원본 파일을 openpyxl로 직접 열어 확인한 실제 색상값:
       - #FFFFCC : 갑지/을지 표 제목행(th) 배경 + 헤더 라벨 셀(승인항목/차종/품번 등, 15개 셀)
       - #FFFF99 : X̄/R/Cp 통계열 제목 셀 전용(더 진한 노랑으로 구분) — 39번 항목에서 열 자체를
         뺐다가 41번 항목("사용하지 않더라도 양식은 있어야해")에서 다시 복원함.
     워크북에 커스텀 인덱스 팔레트가 없어 엑셀 기본 팔레트(인덱스 26/43) 그대로임. */
  .cert-tbl th{background:#FFFFCC;font-weight:700;}
  .cert-tbl th.cert-xrcp-hd{background:#FFFF99;}
  .cert-header-tbl{margin-bottom:8px;table-layout:fixed;}
  .cert-header-tbl .cert-hd-label{background:#FFFFCC;font-weight:700;}
  /* 공급자/수요자 도장란 — 원본은 U6:U8, AB6:AB8처럼 3행 전체 높이의 좁은 칸으로, 별도
     서명자 이름 없이 라벨만 있고 안쪽은 비워 도장을 찍는 자리(2026-09-21, 38번 항목 후속). */
  .cert-header-tbl .cert-approval-tall{writing-mode:vertical-rl;text-orientation:upright;letter-spacing:1px;}
  /* 작성/검토/승인/확인 서명란 — 검토/확인은 값이 없어 빈 칸으로 두고, 작성/승인엔 사용자가
     지정한 이름(김영빈/한상우)을 회색 글자로 채움(2026-09-21, 39번 항목 후속). */
  .cert-header-tbl .cert-approval-sign{background:#fff;}
  .cert-header-tbl .cert-approval-sign-name{color:#8A8F99;font-weight:600;}
  /* 2026-09-22, 44번 항목 후속 — 아래 width 값들은 이제 실제 렌더링에 직접 반영되지 않는다.
     table-layout:fixed에서 열 폭은 thead 1행(colspan이 섞여 있고 폭 지정이 없는 셀이 많음)이
     우선 적용되기 때문에, 지금까지 여기 값을 아무리 바꿔도 실제로는 거의 균등폭으로 렌더링되고
     있었다(Playwright로 실측해 확인). 지금부터 진짜 열 폭은 cert-tab.js의 itemColgroupHtml()/
     dimColgroupHtml()의 <colgroup><col style="width:..."> 값이 결정한다 — 폭을 바꾸려면 거기를
     수정할 것. 아래 값들은 text-align/padding/font 등 폭 이외의 스타일 정의 + 참고용으로 남김. */
  .cert-item-tbl .cert-no{width:34px;white-space:nowrap;}
  .cert-item-tbl .cert-cat{width:52px;white-space:pre-line;font-weight:700;}
  .cert-item-tbl .cert-desc{width:96px;}
  .cert-item-tbl .cert-spec{width:320px;text-align:left;padding-left:6px;}
  .cert-item-tbl .cert-mgmt, .cert-dim-tbl .cert-mgmt{width:30px;font-weight:700;white-space:nowrap;}
  /* 2026-09-22, 44번 항목 후속 — "측정치 칸을 조금 더 정사각형에 가깝게" 요청으로, 실제 열 폭은
     위 주석대로 colgroup이 44px로 정함. 글자가 잘리지 않을 최소 폭(6자리 "430.4" 기준)이 이미
     44px 안팎이라 폭을 더 줄일 순 없어서, 대신 세로 패딩을 늘려 칸 높이를 폭에 가깝게 맞춤
     (2px→11px, 행 높이가 대략 20.75px→38px 정도로 늘어나 폭 44px와 비슷해짐).
     2026-09-22 후속(46번 항목) — "수량 10개 꽉 채우면 글자가 가로로 찌그러진다" 신고로
     white-space:nowrap을 명시 추가. 이 칸들은 짧은 숫자/영문 토큰 하나만 들어가고 줄바꿈이
     필요 없는데, nowrap이 없으면 text-overflow:ellipsis가 애초에 동작하지 않아(스펙상
     nowrap 필수) 칸이 좁아지는 상황(측정치 열 개수가 많을 때)에서 브라우저가 줄바꿈을
     시도하며 기기에 따라 눌린 것처럼 보일 수 있었음 — 아래 짧은-토큰 칸들(값/통계/확인/판정/
     치수번호) 전부에 동일하게 적용. */
  .cert-item-tbl .cert-val, .cert-dim-tbl .cert-val{width:34px;padding:13px 2px;font-family:'JetBrains Mono',monospace;white-space:nowrap;}
  .cert-item-tbl .cert-xrcp, .cert-dim-tbl .cert-xrcp{width:28px;padding:2px 2px;font-family:'JetBrains Mono',monospace;color:var(--muted);white-space:nowrap;}
  .cert-item-tbl .cert-stat, .cert-dim-tbl .cert-stat{width:30px;font-family:'JetBrains Mono',monospace;color:var(--muted);white-space:nowrap;}
  .cert-item-tbl .cert-verdict, .cert-dim-tbl .cert-verdict{width:34px;font-weight:800;color:var(--pass);white-space:nowrap;}
  .cert-dim-tbl .cert-dim-no{width:44px;font-size:13px;font-weight:800;white-space:nowrap;}
  .cert-dim-tbl .cert-spec{width:230px;}
  /* 2026-09-22, 43번 항목 후속 — 빈 채움 행(fillerRowHtml/fillerDimRowHtml)은 내용이 없어
     기본적으로 5px 정도로 찌그러지므로, 일반 행과 비슷한 높이(36px)를 명시해 페이지를 실제로
     채우도록 함(안 그러면 빈 행을 아무리 추가해도 A4 비율에 못 미침). */
  .cert-tbl tr.cert-filler-row td{height:36px;}
  .cert-chk{font-family:'JetBrains Mono',monospace;font-weight:800;}
  .cert-footnote{font-size:9.5px;color:var(--muted);margin:6px 0 0;line-height:1.5;}
  /* 저작권 표시를 페이지 중앙에 두고(2026-09-21, 39번 항목 후속 — "저작권 마크도 동일하게
     중앙에 오도록"), PAGE 번호는 제목줄의 로고와 같은 패턴으로 우측에 절대위치로 붙임. */
  .cert-page-footer{
    display:flex;justify-content:center;align-items:center;position:relative;margin-top:10px;
    font-size:10px;color:var(--muted);
  }
  .cert-page-pageno{position:absolute;right:0;}

  @media(max-width:760px){
    .cert-export-btns{width:100%;margin-left:0;}
  }


/* ============================================================================
   LOGIN LANDING (2026-09-23, 2차) — 로그인 전 첫 화면. 실제 차량 사진 3장 풀스크린 슬라이드
   (js/login-landing.js가 WebGL로 액체처럼 녹아드는 전환 + 포인터 물결), 좌하단 타이틀,
   우측 라이트 글래스 로그인 카드. 모바일은 위 사진 밴드 → 타이틀 → 카드 순서의 1단.
   모든 스타일은 .login-screen 안으로 한정.
   ============================================================================ */
.login-screen{--ll-bg:#07090d;--ll-blue:#1f5fbf;background:var(--ll-bg);color:#fff;}
.login-screen .ll-visual{position:fixed;inset:0;z-index:0;overflow:hidden;background:#0b0d12;}
.login-screen .ll-slides img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;
  transition:opacity 1.4s ease;transform:scale(1.04);}
.login-screen .ll-slides img.active{opacity:1;animation:llKen 9s ease-out both;}
@keyframes llKen{from{transform:scale(1.04);}to{transform:scale(1.1);}}
.login-screen .ll-gl{position:absolute;inset:0;width:100%;height:100%;display:none;}
.login-screen.ll-has-gl .ll-gl{display:block;}
.login-screen.ll-has-gl .ll-slides{visibility:hidden;}
.login-screen .ll-shade{position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(90deg,rgba(7,9,13,.72) 0%,rgba(7,9,13,.25) 38%,rgba(7,9,13,0) 55%,rgba(7,9,13,.35) 78%,rgba(7,9,13,.6) 100%),
    radial-gradient(70% 60% at 0% 0%,rgba(7,9,13,.72) 0%,rgba(7,9,13,.3) 55%,rgba(7,9,13,0) 100%),
    linear-gradient(0deg,rgba(7,9,13,.7) 0%,rgba(7,9,13,0) 30%),
    linear-gradient(180deg,rgba(7,9,13,.45) 0%,rgba(7,9,13,0) 22%);}

.login-screen .ll-layout{position:relative;z-index:2;min-height:100vh;min-height:100dvh;
  display:grid;grid-template-columns:minmax(0,1fr) 392px;gap:48px;
  padding:clamp(28px,6vh,64px) clamp(28px,5.5vw,88px);max-width:1600px;margin:0 auto;}
.login-screen .ll-hero{align-self:stretch;min-width:0;display:flex;flex-direction:column;justify-content:space-between;
  padding:4px 0 6px;animation:llRise 1s cubic-bezier(.2,.8,.2,1) .2s both;}
/* 데스크탑: 타이틀은 좌상단(벽/하늘 쪽 여백) — 사진 하단의 차 범퍼·번호판과 겹치지 않게, 진행바만 좌하단 */
.login-screen .ll-eyebrow{display:flex;align-items:center;gap:14px;font:600 11.5px/1 'Sora','Noto Sans KR',sans-serif;
  letter-spacing:.32em;color:rgba(255,255,255,.72);}
.login-screen .ll-eyebrow::before{content:"";width:36px;height:1px;background:rgba(255,255,255,.55);}
.login-screen .ll-eyebrow span{color:#e2343f;}
.login-screen .ll-title{margin:22px 0 0;font:600 clamp(48px,6.4vw,104px)/.96 'Sora','Noto Sans KR',sans-serif;
  letter-spacing:-.04em;color:#fff;text-shadow:0 2px 30px rgba(0,0,0,.25);}
.login-screen .ll-progress{display:flex;align-items:center;gap:18px;margin-top:34px;}
.login-screen .ll-count{font:500 12px/1 'Sora',sans-serif;letter-spacing:.14em;color:rgba(255,255,255,.55);}
.login-screen .ll-count b{color:#fff;font-weight:600;}
.login-screen .ll-bars{display:flex;gap:8px;}
.login-screen .ll-bars i{position:relative;width:48px;height:2px;background:rgba(255,255,255,.22);overflow:hidden;border-radius:2px;}
.login-screen .ll-bars em{position:absolute;inset:0;background:#fff;transform:scaleX(0);transform-origin:left;}
.login-screen .ll-bars i.done em{transform:scaleX(1);}
.login-screen .ll-bars i.active em{animation:llBar var(--ll-slide-ms,6500ms) linear forwards;}
@keyframes llBar{to{transform:scaleX(1);}}

/* ---- 로그인 카드: 절제된 라이트 글래스 ---- */
.login-screen .ll-card-wrap{align-self:center;min-width:0;animation:llRise 1s cubic-bezier(.2,.8,.2,1) .35s both;}
@keyframes llRise{from{opacity:0;transform:translateY(18px);}to{opacity:1;transform:none;}}
.login-screen .ll-card{padding:40px 34px 34px;border-radius:22px;text-align:left;color:#0e1116;
  background:rgba(255,255,255,.9);border:1px solid rgba(255,255,255,.6);
  box-shadow:0 40px 90px rgba(0,0,0,.45);
  backdrop-filter:blur(22px) saturate(1.3);-webkit-backdrop-filter:blur(22px) saturate(1.3);}
.login-screen .login-logo{height:34px;width:auto;margin:0 0 30px;display:block;}
.login-screen .ll-card-title{font-size:22px;font-weight:700;letter-spacing:-.02em;color:#0e1116;}
.login-screen .ll-card-sub{font-size:13.5px;color:#6b7180;margin-top:6px;}
.login-screen .ll-field{position:relative;margin-top:22px;}
.login-screen .ll-field:first-of-type{margin-top:30px;}
.login-screen .ll-field input{width:100%;height:52px;padding:20px 40px 6px 0;border:none;border-bottom:1.5px solid #d3d7df;
  border-radius:0;background:transparent;font-size:16px;color:#0e1116;outline:none;transition:border-color .25s;}
.login-screen .ll-field input:focus{border-bottom-color:#0e1116;}
.login-screen .ll-field::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1.5px;background:var(--ll-blue);
  transform:scaleX(0);transform-origin:left;transition:transform .35s cubic-bezier(.2,.8,.2,1);}
.login-screen .ll-field:focus-within::after{transform:scaleX(1);}
.login-screen .ll-field label{position:absolute;left:0;top:26px;transform:translateY(-50%);font-size:15px;color:#8a909c;pointer-events:none;
  transition:top .2s ease,font-size .2s ease,color .2s ease,letter-spacing .2s ease;}
.login-screen .ll-field input:focus + label,
.login-screen .ll-field input:not(:placeholder-shown) + label{top:8px;font-size:11px;letter-spacing:.06em;color:#5b6170;}
.login-screen .ll-pw-toggle{position:absolute;right:0;bottom:6px;width:36px;height:36px;border:none;background:transparent;
  color:#9aa0ab;display:flex;align-items:center;justify-content:center;cursor:pointer;border-radius:8px;}
.login-screen .ll-pw-toggle svg{width:18px;height:18px;}
.login-screen .ll-pw-toggle[aria-pressed="true"]{color:#0e1116;}
.login-screen .login-error{color:#C4432E;font-size:12.5px;font-weight:600;margin-top:14px;}
.login-screen .ll-login-btn{width:100%;height:54px;margin-top:30px;border:none;border-radius:12px;cursor:pointer;
  display:flex;align-items:center;justify-content:space-between;padding:0 20px;
  background:#0e1116;color:#fff;font-size:15px;font-weight:600;letter-spacing:.04em;
  transition:background .3s ease, transform .15s ease;}
.login-screen .ll-login-btn svg{width:18px;height:18px;transition:transform .3s ease;}
.login-screen .ll-login-btn:hover{background:var(--ll-blue);}
.login-screen .ll-login-btn:hover svg{transform:translateX(4px);}
.login-screen .ll-login-btn:active{transform:scale(.99);}
.login-screen .ll-login-btn:disabled{opacity:.7;cursor:progress;}
.login-screen .ll-copy{margin-top:18px;font:500 11px/1 'Sora',sans-serif;letter-spacing:.12em;color:rgba(255,255,255,.5);text-align:center;}

/* ---- 태블릿/모바일: 사진 밴드(위) → 타이틀 → 카드 ---- */
@media (max-width: 960px){
  .login-screen .ll-visual{position:relative;height:min(80vw,46svh);min-height:240px;}
  /* 2026-09-23(3): 위쪽은 상태바(까만 띠) 색에서 사진으로 자연스럽게 이어지도록 진한 블랙→투명 그라데이션.
     viewport-fit=cover가 먹는 기기에서는 사진이 상태바 뒤까지 올라가고(safe-area만큼 높이 추가), 안 먹는 기기에서도
     띠와 사진 사이 경계가 보이지 않는다. */
  .login-screen .ll-visual{height:calc(min(80vw,46svh) + env(safe-area-inset-top,0px));min-height:calc(240px + env(safe-area-inset-top,0px));}
  .login-screen .ll-shade{background:
    linear-gradient(0deg,var(--ll-bg) 0%,rgba(7,9,13,0) 38%),
    linear-gradient(180deg,var(--ll-bg) 0%,rgba(7,9,13,.55) calc(env(safe-area-inset-top,0px) + 4%),rgba(7,9,13,0) calc(env(safe-area-inset-top,0px) + 26%));}
  .login-screen .ll-layout{grid-template-columns:1fr;gap:22px;min-height:0;
    margin-top:-34px;padding:0 20px calc(22px + env(safe-area-inset-bottom));}
  .login-screen .ll-hero{align-self:start;padding:0;display:block;}
  .login-screen .ll-eyebrow{font-size:10px;letter-spacing:.26em;gap:10px;}
  .login-screen .ll-eyebrow::before{width:22px;}
  .login-screen .ll-title{margin-top:12px;font-size:clamp(34px,10vw,52px);}
  .login-screen .ll-title br{display:none;}
  .login-screen .ll-progress{margin-top:16px;}
  .login-screen .ll-bars i{width:34px;}
  .login-screen .ll-card-wrap{width:100%;max-width:440px;margin:0 auto;}
  .login-screen .ll-card{padding:30px 24px 26px;border-radius:20px;background:rgba(255,255,255,.97);}
  .login-screen .login-logo{height:30px;margin-bottom:22px;}
}
@media (prefers-reduced-motion: reduce){
  .login-screen *,.login-screen *::before,.login-screen *::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important;}
}

/* 2026-09-23: 스캔 모달 하단(상태 문구·촬영 버튼 ↔ 인식 결과) 높이 고정 — 결과가 뜰 때 모달이 위로 튀지 않게.
   값은 결과 영역(배지+입력칸+버튼 2개)의 실제 높이를 재서 맞춤. */
.scan-bottom{min-height:var(--scan-bottom-h,156px);display:flex;flex-direction:column;}
/* 남는 높이는 문구와 버튼 사이로 — "바로 인식" 버튼은 항상 아래 "닫기" 바로 위에 붙는다 */
.scan-bottom #scanCaptureBtn{margin-top:auto !important;}
.scan-bottom #scanStatus{margin-bottom:10px;}
/* 2026-09-23(2): 결과 화면 버튼 두 개를 한 줄로 — 촬영 중 화면과 높이를 맞춰 빈 공간 없이도 모달이 안 튀게 */
.scan-result-actions{display:flex;gap:8px;margin-top:12px;align-items:stretch;}
.scan-result-actions .btn-ghost{flex:0 0 34%;border-radius:12px;font-size:14px;}
.scan-result-actions .submit-btn{flex:1;margin:0;width:auto;}
.scan-barcode-debug{margin:6px 0 0;font-size:10.5px;line-height:1.35;color:var(--muted);word-break:break-all;opacity:.85;}
.scan-barcode-debug[hidden]{display:none;}

/* 2026-09-23(3): 사양표에 없는 품번 — 알약을 붉은 톤으로 */
#specInfoPill.spec-info-pill.unknown{background:rgba(180,72,58,.10);color:#B4483A;box-shadow:inset 0 0 0 1px rgba(180,72,58,.28);}
#specInfoPill.spec-info-pill.unknown .sip-warn{color:#B4483A;font-weight:700;}

/* ==========================================================================
   2026-09-23(3): 헤더 슬로건 "Quality in Motion." + 개발자 표기 위치 이동
   ========================================================================== */
.brand-tagline{
  font-family:'Unbounded','Sora','Noto Sans KR',sans-serif;font-weight:800;font-size:11.5px;letter-spacing:.02em;
  margin-top:3px;display:inline-block;overflow:visible;
  /* 1층: 좌→우로 흐르는 빛 띠 / 2층: DM 블루→스틸→DM 레드 팝아트 그라데이션 */
  background-image:
    linear-gradient(105deg, rgba(255,255,255,0) 38%, rgba(140,215,255,.95) 47%, #ffffff 50%, rgba(255,214,120,.95) 53%, rgba(255,255,255,0) 62%),
    linear-gradient(90deg, #1f5fbf 0%, #3d5a80 48%, #e2343f 100%);
  background-size:260% 100%, 100% 100%;
  background-position:120% 0, 0 0;
  background-repeat:no-repeat;
  -webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-fill-color:transparent;
  /* 팝아트 느낌의 살짝 어긋난 그림자(글자 모양 그대로 따라감) */
  filter:drop-shadow(1px 1px 0 rgba(226,52,63,.22)) drop-shadow(0 0 6px rgba(31,95,191,.10));
  animation:taglineShine 3.6s cubic-bezier(.45,0,.2,1) infinite;
}
@keyframes taglineShine{
  0%{background-position:120% 0, 0 0;}
  55%,100%{background-position:-20% 0, 0 0;}
}
@media (prefers-reduced-motion: reduce){ .brand-tagline{animation:none;} }

.dev-credit{margin:0;font-size:11px;font-weight:500;letter-spacing:.02em;color:#9aa1ad;}
/* 모바일: main 맨 아래 가운데(하단 탭바가 가리지 않도록 main의 아래 여백 안쪽에 위치) */
.dev-credit-mobile{text-align:center;padding:26px 0 4px;}
.dev-credit-desktop{display:none;}
body.is-desktop .dev-credit-mobile{display:none;}
/* 데스크톱: 사이드바 로그아웃 버튼 위, 구분선 바로 위 */
body.is-desktop .dev-credit-desktop{display:block;margin-top:auto;padding:0 14px 10px;font-size:11px;color:var(--dsk-muted,#9aa1ad);opacity:.8;}

/* 2026-09-23(4): 저장 대기열 상태 칩 — 헤더 바로 아래 가운데, 어느 탭에서나 보임 */
.save-queue-chip{position:fixed;left:50%;top:78px;transform:translateX(-50%);z-index:26;
  display:inline-flex;align-items:center;gap:8px;max-width:calc(100% - 32px);
  padding:8px 14px;border:none;border-radius:999px;
  background:rgba(22,26,34,.88);color:#fff;font-size:12.5px;font-weight:600;letter-spacing:.01em;white-space:nowrap;
  box-shadow:0 6px 20px rgba(10,14,22,.22);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  animation:sqcIn .28s cubic-bezier(.2,.8,.2,1);}
.save-queue-chip[hidden]{display:none;}
.save-queue-chip em{font-style:normal;font-weight:500;opacity:.7;overflow:hidden;text-overflow:ellipsis;}
.save-queue-chip b{font-weight:800;text-decoration:underline;text-underline-offset:2px;}
.save-queue-chip.failed{background:#B4483A;}
.save-queue-chip .sqc-spin{width:12px;height:12px;border-radius:50%;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;animation:sqcSpin .8s linear infinite;flex-shrink:0;}
.save-queue-chip .sqc-ico{width:16px;height:16px;border-radius:50%;background:#fff;color:#B4483A;font-weight:900;font-size:11px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;}
@keyframes sqcSpin{to{transform:rotate(360deg);}}
@keyframes sqcIn{from{opacity:0;transform:translateX(-50%) translateY(-6px);}to{opacity:1;transform:translateX(-50%) translateY(0);}}
body.is-desktop .save-queue-chip{top:86px;}

/* 2026-09-23(6): 초점 슬라이더 */
.scan-focus-adjust{display:block;margin-top:8px;}
.scan-focus-adjust.hidden{display:none;}
.scan-focus-adjust .sfa-row{display:flex;align-items:center;gap:8px;}
.scan-focus-adjust .sfa-label{font-size:12px;font-weight:700;color:var(--ink,#1f2937);}
.scan-focus-adjust .sfa-end{font-size:11px;color:var(--muted,#6b7280);white-space:nowrap;}
.scan-focus-adjust input[type=range]{flex:1;min-width:0;accent-color:var(--steel,#3d5a80);height:28px;}
.scan-focus-adjust .sfa-auto{flex-shrink:0;padding:6px 12px;border-radius:999px;border:1.5px solid #D7DCE5;background:#EEF1F6;color:var(--steel-dark,#1f2937);font-size:12px;font-weight:700;}
.scan-focus-adjust .sfa-auto.on{background:var(--steel,#3d5a80);border-color:var(--steel,#3d5a80);color:#fff;}
.scan-focus-adjust .sfa-hint{margin:4px 0 0;font-size:11px;line-height:1.4;color:var(--muted,#6b7280);}
.scan-focus-adjust .sfa-hint b{color:var(--steel,#3d5a80);}

/* ==========================================================================
   2026-09-23(14): 로그인 전환 모션 — 컷 편집식 키네틱 타이포 (js/auth.js createLoginMotion)
   참고 영상 첫 5초의 문법: 페이드 없는 빠른 컷, 어두운 화면 ↔ 밝은 그리드 교차, 외곽선 ↔ 채움, 선택 핸들 사각형,
   크롭된 대형 글자 + 가이드 선. 포인트 색은 DM 블루 하나(+ 마침표 DM 레드). data-s 값이 곧 현재 컷.
   ========================================================================== */
.login-motion{position:fixed;inset:0;z-index:9999;pointer-events:none;overflow:hidden;
  --lm-blue:#2f6fe4;--lm-red:#e2343f;--lm-dark:#111214;--lm-light:#f2f2ef;--lm-ink:#111214;--lm-white:#f7f7f5;
  --lm-fs:min(24vw, 19vh, 210px);--lm-ease:cubic-bezier(.16,1,.3,1);
  font-family:'Sora','Noto Sans KR',sans-serif;font-weight:800;}
.login-motion .lm-bg{position:absolute;inset:0;background:var(--lm-dark);}
.login-motion .lm-grid{position:absolute;inset:0;display:none;
  background-image:linear-gradient(rgba(17,18,20,.07) 1px, transparent 1px),linear-gradient(90deg, rgba(17,18,20,.07) 1px, transparent 1px);
  background-size:40px 40px;background-position:center center;}
.login-motion .lm-sc{position:absolute;inset:0;display:none;place-items:center;}
.login-motion[data-s="1"] .lm-s1,.login-motion[data-s="2"] .lm-s2,
.login-motion[data-s="3"] .lm-s3,.login-motion[data-s="4"] .lm-s3,
.login-motion[data-s="5"] .lm-s5,.login-motion[data-s="6"] .lm-s5,
.login-motion[data-s="7"] .lm-s7,.login-motion[data-s="8"] .lm-s8,.login-motion[data-s="9"] .lm-s8{display:grid;}
.login-motion[data-s="1"] .lm-bg{background:var(--lm-blue);}
.login-motion[data-s="5"] .lm-bg,.login-motion[data-s="6"] .lm-bg,.login-motion[data-s="7"] .lm-bg,
.login-motion[data-s="8"] .lm-bg,.login-motion[data-s="9"] .lm-bg{background:var(--lm-light);}
.login-motion[data-s="5"] .lm-grid,.login-motion[data-s="6"] .lm-grid,.login-motion[data-s="7"] .lm-grid,
.login-motion[data-s="8"] .lm-grid,.login-motion[data-s="9"] .lm-grid{display:block;}

/* 1: 블루 화면에 큰 Q가 오른쪽에서 밀려 들어옴 */
.login-motion .lm-q1{font-size:min(70vh, 110vw);line-height:.8;color:var(--lm-dark);letter-spacing:-.05em;}
.login-motion[data-s="1"] .lm-q1{animation:lmSlam .11s cubic-bezier(.2,.8,.2,1) both;}
@keyframes lmSlam{from{transform:translate3d(45%,0,0);}to{transform:none;}}
/* 2: 검정 화면에 흰 Q */
.login-motion .lm-q2{font-size:min(26vh, 40vw);line-height:1;color:var(--lm-white);letter-spacing:-.05em;}
/* 3/4: QUALITY 외곽선 → 채움, 선택 핸들 사각형 */
.login-motion .lm-caps{font-size:min(12.5vw, 13vh, 140px);letter-spacing:.14em;margin-right:-.14em;line-height:1;
  color:transparent;-webkit-text-stroke:1.4px var(--lm-white);}
.login-motion[data-s="4"] .lm-caps{color:var(--lm-white);-webkit-text-stroke:0;}
.login-motion .lm-sq{position:absolute;left:var(--x);top:var(--y);width:9px;height:9px;border:1.4px solid var(--lm-white);box-sizing:border-box;}
.login-motion[data-s="4"] .lm-sq{background:var(--lm-white);}
.login-motion[data-s="3"] .lm-caps{animation:lmNudge .11s linear both;}
@keyframes lmNudge{from{transform:translate3d(-2.5%,0,0);}to{transform:none;}}
/* 5/6: 밝은 그리드 + Quality 채움 → 외곽선 */
.login-motion .lm-w5{font-size:min(17vw, 15vh, 170px);letter-spacing:-.045em;line-height:1;color:var(--lm-ink);}
.login-motion[data-s="6"] .lm-w5{color:transparent;-webkit-text-stroke:1.2px var(--lm-ink);}
/* 7: 화면을 넘치게 크롭한 대형 글자 + 제도용 가이드 */
.login-motion .lm-s7{place-items:center start;}
.login-motion .lm-crop{font-size:min(58vh, 62vw);letter-spacing:-.05em;line-height:.9;color:var(--lm-ink);white-space:nowrap;
  margin-left:6vw;animation:none;}
.login-motion[data-s="7"] .lm-crop{animation:lmDrift .25s cubic-bezier(.2,.7,.2,1) both;}
@keyframes lmDrift{from{transform:translate3d(4vw,0,0);}to{transform:translate3d(-6vw,0,0);}}
.login-motion .lm-guide{position:absolute;background:rgba(17,18,20,.55);}
.login-motion .lm-gh1{left:0;right:0;top:22%;height:1px;}
.login-motion .lm-gh2{left:0;right:0;top:78%;height:1px;}
.login-motion .lm-gv{top:0;bottom:0;left:6vw;width:1px;}
.login-motion .lm-circle{position:absolute;width:min(90vh,120vw);aspect-ratio:1;border:1px solid rgba(17,18,20,.35);border-radius:50%;
  right:-30vw;top:50%;transform:translateY(-50%);}
.login-motion .lm-label{position:absolute;left:calc(6vw + 8px);top:calc(22% - 34px);font:600 10px/1.3 'JetBrains Mono',monospace;color:rgba(17,18,20,.6);}
.login-motion[data-s="7"] .lm-guide{animation:lmGuide .2s var(--lm-ease) both;}
.login-motion[data-s="7"] .lm-gh1,.login-motion[data-s="7"] .lm-gh2{transform-origin:left center;}
.login-motion[data-s="7"] .lm-gv{transform-origin:center top;animation-name:lmGuideV;}
@keyframes lmGuide{from{transform:scaleX(0);}to{transform:scaleX(1);}}
@keyframes lmGuideV{from{transform:scaleY(0);}to{transform:scaleY(1);}}
/* 8: 최종 문구 Quality / IN — / Motion. */
.login-motion .lm-stack{display:grid;justify-items:start;}
.login-motion .lm-line{overflow:hidden;padding:0 .02em;}
.login-motion .lm-word{display:block;font-size:var(--lm-fs);line-height:1;letter-spacing:-.045em;color:var(--lm-ink);white-space:nowrap;padding:.04em 0 .1em;}
.login-motion .lm-ch{display:inline-block;}
.login-motion .lm-accent{color:var(--lm-red);}
.login-motion .lm-l2{display:flex;align-items:center;gap:.6em;justify-self:stretch;font-size:calc(var(--lm-fs) * .22);margin:.3em 0 .4em;}
.login-motion .lm-in{font-weight:600;letter-spacing:.32em;text-transform:uppercase;color:rgba(17,18,20,.6);line-height:1.2;display:block;}
.login-motion .lm-rule{flex:1;height:2px;background:var(--lm-blue);transform-origin:left center;}
.login-motion[data-s="8"] .lm-ch{animation:lmCharIn .34s var(--lm-ease) calc(var(--i) * .022s) both;}
.login-motion[data-s="8"] .lm-l3 .lm-ch{animation-delay:calc(.07s + var(--i) * .022s);}
.login-motion[data-s="8"] .lm-in{animation:lmCharIn .3s var(--lm-ease) .12s both;}
.login-motion[data-s="8"] .lm-rule{animation:lmGuide .4s var(--lm-ease) .16s both;}
@keyframes lmCharIn{from{transform:translate3d(0,110%,0);}to{transform:none;}}
/* 9(OUT): 최종 문구가 외곽선으로 한 번 끊긴 뒤 화면 전체가 위로 걷힌다 */
.login-motion[data-s="9"] .lm-word{color:transparent;-webkit-text-stroke:1.2px var(--lm-ink);}
.login-motion[data-s="9"] .lm-accent{-webkit-text-stroke-color:var(--lm-red);}
.login-motion.lm-wipe-out{animation:lmWipeOut .4s cubic-bezier(.76,0,.24,1) forwards;}
@keyframes lmWipeOut{from{clip-path:inset(0 0 0 0);}to{clip-path:inset(0 0 100% 0);}}
