/* ==========================================================================
   GLINS ERP - 공통 스타일
   외부 CDN을 쓰지 않는다 (사내망/오프라인에서도 동일하게 보이도록)
   ========================================================================== */

/* 한글 본문용 글꼴. 파일을 함께 배포하므로 직원 PC 에 설치돼 있지 않아도,
   인터넷이 끊겨 있어도 모두 같은 화면을 본다.
   Variable 폰트 하나로 100~900 굵기를 전부 커버한다. (SIL OFL 1.1)  */
@font-face {
    font-family: "Pretendard";
    src: url("../fonts/PretendardVariable.woff2") format("woff2-variations");
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

:root {
    /* 브랜드 색. 기준은 --brand-600 (#3182F6) 이고 나머지는 같은 색조의 명암 단계다.
       사이드바·버튼·링크·강조가 전부 이 계열이라, 색을 바꾸려면 여기만 손대면 된다. */
    --brand-900: #101c33;   /* 사이드바 바탕, 큰 제목 글자 */
    --brand-800: #16294a;
    --brand-700: #1a5ecc;   /* 버튼 hover, 옅은 바탕 위 글자 */
    --brand-600: #3182f6;   /* ★ 기준색 */
    --brand-500: #5a9bff;
    --brand-100: #dbe9ff;   /* 옅은 테두리 */
    --brand-50:  #f0f6ff;   /* 옅은 바탕 */

    --slate-900: #0f172a;
    --slate-700: #334155;
    --slate-600: #475569;
    --slate-500: #64748b;
    --slate-400: #94a3b8;
    --slate-300: var(--nav-text);
    --slate-200: #e2e8f0;
    --slate-100: #f1f5f9;
    --slate-50: #f8fafc;

    --green-600: #16a34a;
    --green-50: #f0fdf4;
    --red-600: #dc2626;
    --red-50: #fef2f2;
    --amber-600: #d97706;
    --amber-50: #fffbeb;

    /* 카드·팝업·입력칸의 바탕. 밝은 테마에서는 흰색이다.
       색을 칠한 바탕(파란 버튼, 사이드바) 위에 얹는 글자는 --on-brand 다.
       두 흰색을 한 이름으로 두면 다크에서 카드만 어둡게 하지 못한다. */
    --surface: #fff;
    --on-brand: #fff;

    /* 파란 버튼을 눌렀을 때의 진한 바탕. --brand-700 은 글자색으로도 쓰여
       (링크 hover 등) 다크에서 밝아져야 하는데, 바탕은 반대로 어두워야 한다.
       한 이름으로 두면 둘 중 하나가 반드시 안 읽힌다. */
    --brand-strong: #1a5ecc;

    /* 원래부터 어두운 자리. 사이드바와 로그인 화면 왼쪽은 두 테마가 같은
       색을 쓴다 — 밝은 테마에서도 이미 어둡고, 흰 글자가 얹혀 있다. */
    --sidebar-bg: #101c33;
    --nav-text: #cbd5e1;
    --hero-1: #101c33;
    --hero-2: #17335c;
    --hero-3: #1e4f9e;
    --logo-1: #5a9bff;
    --logo-2: #16294a;
    --mark-2: #6ea8ff;

    /* 알림·달력·결재 순서도의 강조색. 200 은 칩 바탕, 700·800 은 그 위 글자다. */
    --green-200: #bbf7d0;
    --green-700: #15803d;
    --red-200: #fecaca;
    --red-300: #fca5a5;
    --red-800: #991b1b;
    --red-hover: #fde8e8;
    --amber-200: #fde68a;
    --amber-800: #92400e;
    --violet-50: #f5f0ff;
    --violet-200: #ddd6fe;
    --violet-600: #7c3aed;
    --highlight: #fef9c3;      /* 방금 바뀐 줄을 잠깐 밝히는 색 */

    /* 글꼴은 여기 두 줄이 전부다. 화면마다 따로 적어 두면 한 곳만 바뀌어
       같은 표 안에서 글자 모양이 달라진다.

       Pretendard 는 파일을 함께 배포하므로 어느 PC 에서나 같게 보인다.
       뒤에 세운 것들은 그 파일을 못 읽었을 때를 위한 대비다.

       **화면에 쓰는 글꼴은 이것 하나다.** 고정폭 글꼴을 따로 두었더니 같은
       화면 안에서 글씨 크기가 달라 보였다. 숫자를 세로로 맞추는 일은 글꼴을
       바꾸지 않고 font-variant-numeric 으로 한다(.mono 참고). */
    --font-sans: "Pretendard", -apple-system, BlinkMacSystemFont, "Segoe UI",
                 "Malgun Gothic", "맑은 고딕", sans-serif;

    --sidebar-w: 236px;
    --radius: 8px;
    --shadow-sm: 0 1px 2px rgba(15, 23, 42, .06);
    --shadow: 0 1px 3px rgba(15, 23, 42, .1), 0 1px 2px rgba(15, 23, 42, .06);
    --shadow-lg: 0 10px 25px rgba(15, 23, 42, .12);
}

/* ============================================================ 다크 테마

   사람마다 골라 쓴다(users.theme). 고른 값은 화면을 그릴 때 서버가
   <html data-theme="dark"> 로 찍어 주므로, 켜는 순간 흰 화면이 번쩍이지 않는다.

   **규칙은 그대로 두고 색만 갈아 끼운다.** 화면마다 다크용 규칙을 따로 쓰면
   앞으로 화면을 고칠 때마다 두 벌을 손대야 하고, 한쪽만 고쳐진 자리가 반드시
   생긴다. 색이 이미 변수로 모여 있어 여기만 덮어쓰면 된다.

   회색 사다리(--slate-*)의 숫자는 '밝기' 가 아니라 '역할' 이다. 밝은 테마에서
   낮은 번호는 바탕·테두리로, 높은 번호는 글자로 써 왔다(실제 쓰임을 세어
   확인했다). 그래서 다크에서는 사다리를 뒤집는다 — --slate-50 이 가장 어두운
   바탕이 되고 --slate-900 이 가장 밝은 글자가 된다. 이름과 실제 색이 어긋나
   보이지만, 덕분에 색을 끌어다 쓰는 300 군데를 한 곳도 손대지 않는다.

   사이드바·로그인 왼쪽은 위에서 따로 뽑아 두었으므로 여기서 건드리지 않는다.
   두 테마가 같은 모습이다. */

[data-theme="dark"] {
    /* 브라우저가 만드는 것들(스크롤막대, 날짜 고르개, select 목록)도 함께
       어두워진다. 이것을 빼면 날짜칸만 흰 상자로 남는다. */
    color-scheme: dark;

    /* 파랑: 기준색은 살짝 밝혀 어두운 바탕에서도 또렷하게, 글자로 쓰는
       진한 쪽(700·800·900)은 반대로 밝은 쪽으로 뒤집는다. */
    --brand-900: #cfe0ff;
    --brand-800: #a9ccff;
    --brand-700: #8fbcff;
    --brand-600: #4d93ff;
    --brand-500: #5a9bff;
    --brand-100: #24384f;
    --brand-50:  #17253d;
    --brand-strong: #2f6fd0;

    /* 회색 사다리를 뒤집는다 (위 설명 참고) */
    --slate-900: #eef3f9;      /* 본문 글자 */
    --slate-700: #dee5ef;
    --slate-600: #c6d0de;
    --slate-500: #aab6c8;      /* 흐린 글자 */
    --slate-400: #8d9aae;
    --slate-300: #5d6a7d;      /* 입력칸 테두리 */
    --slate-200: #2b3646;      /* 표 경계선 */
    --slate-100: #0f151e;      /* 페이지 바탕 (카드보다 어둡다) */
    --slate-50:  #212c3b;      /* 카드 위의 옅은 칸 */

    --surface: #1a2331;        /* 카드·팝업·입력칸 */

    /* 강조색: 밝은 테마에서 '옅은 바탕 + 진한 글자' 이던 짝을
       '진한 바탕 + 옅은 글자' 로 뒤집는다. */
    --green-600: #4ade80;
    --green-700: #86efac;
    --green-200: #1f5136;
    --green-50:  #10281a;
    --red-600:   #f87171;
    --red-800:   #fca5a5;
    --red-300:   #7f2d33;
    --red-200:   #5c2126;
    --red-hover: #3a191c;
    --red-50:    #2b1416;
    --amber-600: #fbbf24;
    --amber-800: #fcd34d;
    --amber-200: #5c4318;
    --amber-50:  #2a1f0c;
    --violet-600: #c4b5fd;
    --violet-200: #3f2f66;
    --violet-50:  #241a3d;
    --highlight:  #4a3f14;

    /* 어두운 바탕에서는 옅은 회색 그림자가 보이지 않는다. 검게, 진하게. */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .5);
    --shadow: 0 1px 3px rgba(0, 0, 0, .6), 0 1px 2px rgba(0, 0, 0, .4);
    --shadow-lg: 0 10px 25px rgba(0, 0, 0, .6);
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
}

body {
    font-family: var(--font-sans);
    /* 한글은 받침이 있어 영문과 같은 값을 쓰면 빡빡해 보인다.
       크기와 줄간격은 올리고, 글자폭이 일정한 한글 특성상 자간은 살짝 좁힌다. */
    font-size: 15px;
    line-height: 1.7;
    letter-spacing: -.012em;
    color: var(--slate-900);
    background: var(--slate-100);
    -webkit-font-smoothing: antialiased;
}

/* 금액·수량·사업자번호가 표에서 자릿수대로 맞아떨어지게 한다.
   (.mono 도 같은 것을 켜지만 제 정의에서 함께 둔다) */
table.grid tbody td,
.stat .value {
    font-variant-numeric: tabular-nums;
}

a { color: var(--brand-600); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ============================================================ 로그인 화면 */

.login-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    /* 중간·끝 색은 배경용이라 --brand-700(버튼용 원색)보다 한 톤 가라앉혀 쓴다 */
    background: linear-gradient(135deg, var(--hero-1) 0%, var(--hero-2) 55%, var(--hero-3) 100%);
    position: relative;
    overflow: hidden;
}

.login-page::before,
.login-page::after {
    content: "";
    position: absolute;
    border-radius: 50%;
    background: rgba(255, 255, 255, .04);
}
.login-page::before { width: 520px; height: 520px; top: -180px; right: -140px; }
.login-page::after  { width: 380px; height: 380px; bottom: -160px; left: -110px; }

.login-card {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: 420px;
    background: var(--surface);
    border-radius: 14px;
    box-shadow: var(--shadow-lg);
    padding: 40px 36px 32px;
}

.login-brand { text-align: center; margin-bottom: 28px; }

.login-logo {
    width: 56px;
    height: 56px;
    margin: 0 auto 14px;
    border-radius: 14px;
    background: linear-gradient(135deg, var(--logo-1), var(--logo-2));
    color: var(--on-brand);
    font-size: 20px;
    font-weight: 800;
    letter-spacing: -.5px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.login-brand .brand-logo {
    display: block;
    margin: 0 auto 16px;
    max-height: 64px;
    max-width: 240px;
    object-fit: contain;
}

.login-brand h1 {
    margin: 0;
    font-size: 21px;
    font-weight: 700;
    letter-spacing: -.4px;
    color: var(--brand-900);
}

.login-brand p {
    margin: 6px 0 0;
    font-size: 14px;
    color: var(--slate-500);
}

/* 계정 신청 화면은 입력칸이 많아 로그인 카드보다 넓게 쓴다 */
.login-card.wide { max-width: 620px; }

.login-alt {
    margin-top: 20px;
    padding-top: 18px;
    border-top: 1px solid var(--slate-200);
    text-align: center;
    font-size: 14px;
    color: var(--slate-500);
}
.login-alt a { font-weight: 600; margin-left: 4px; }

.login-footer {
    margin-top: 26px;
    padding-top: 18px;
    border-top: 1px solid var(--slate-200);
    text-align: center;
    font-size: 13px;
    color: var(--slate-400);
    line-height: 1.8;
}

/* ============================================================ 레이아웃 */

.layout { display: flex; min-height: 100vh; }

.sidebar {
    width: var(--sidebar-w);
    flex-shrink: 0;
    background: var(--sidebar-bg);
    color: var(--on-brand);
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0; bottom: 0; left: 0;
    z-index: 30;
}

.sidebar-brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 18px 18px;
    border-bottom: 1px solid rgba(255, 255, 255, .08);
}

.sidebar-brand .mark {
    width: 32px; height: 32px;
    border-radius: 8px;
    background: linear-gradient(135deg, var(--brand-600), var(--mark-2));
    display: flex; align-items: center; justify-content: center;
    font-weight: 800; font-size: 14px;
}

/* 회사 로고를 등록하면 기본 마크(GL) 대신 그것이 나온다.
   로고는 가로로 긴 것이 많아 네모 칸에 욱여넣지 않고 높이만 맞춘다. */
.sidebar-brand .brand-logo {
    max-height: 30px;
    max-width: 116px;
    object-fit: contain;
}

.sidebar-brand .title { font-weight: 700; font-size: 15px; letter-spacing: -.3px; }
.sidebar-brand .sub { font-size: 12px; color: var(--slate-400); }

.nav { flex: 1; overflow-y: auto; padding: 14px 10px 20px; }

.nav-section {
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .06em;
    color: var(--slate-400);
    padding: 14px 10px 6px;
    text-transform: uppercase;
}

/* 맨 아래 두 개(개선요청·휴대폰 앱). 업무 메뉴가 아니라 'ERP 자체' 에
   관한 것이라, 가는 선 하나로 위와 갈라 둔다. */
.nav-tail {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid rgba(255, 255, 255, .08);
}

/* ---- 사이드바 대분류 (접었다 편다)
   메뉴가 스무 개를 넘으며 한 화면에 들어오지 않게 되어 묶었다.
   <details> 라 자바스크립트가 꺼져 있어도 접히고 펴진다. */

.nav-group > summary.nav-section {
    display: flex;
    align-items: center;
    gap: 8px;
    list-style: none;          /* 기본 삼각형을 지우고 아래 화살표를 쓴다 */
    cursor: pointer;
    user-select: none;
    border-radius: 6px;
}

.nav-group > summary::-webkit-details-marker { display: none; }
.nav-group > summary:hover { color: var(--slate-300); }

/* 접힘 표시. 펴지면 아래를 가리킨다. */
.nav-group > summary::after {
    content: "▸";
    margin-left: auto;
    font-size: 10px;
    opacity: .6;
    transition: transform .15s;
}

.nav-group[open] > summary::after { transform: rotate(90deg); }

/* 접혀 있을 때만 머리에 건수를 보여준다. 펴면 항목마다 붙으므로 겹친다. */
.nav-group > summary .count {
    margin-left: 0;
    min-width: 19px;
    padding: 0 6px;
    border-radius: 10px;
    background: var(--amber-600);
    color: var(--on-brand);
    font-size: 12px;
    font-weight: 700;
    line-height: 19px;
    text-align: center;
}

.nav-group[open] > summary .count { display: none; }

.nav-group > summary .soon {
    font-size: 12px;
    font-weight: 500;
    padding: 1px 6px;
    border-radius: 10px;
    background: rgba(255, 255, 255, .08);
    color: var(--slate-500);
}

.nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 11px;
    margin-bottom: 2px;
    border-radius: 6px;
    color: var(--nav-text);
    font-size: 14px;
    transition: background .12s, color .12s;
}

.nav-item:hover { background: rgba(255, 255, 255, .07); color: var(--on-brand); text-decoration: none; }
.nav-item.active { background: var(--brand-600); color: var(--on-brand); font-weight: 600; }
.nav-item .icon { width: 18px; text-align: center; flex-shrink: 0; opacity: .9; }

.nav-item.disabled {
    color: var(--slate-500);
    cursor: not-allowed;
    pointer-events: none;
}
.nav-item.disabled .soon {
    margin-left: auto;
    font-size: 12px;
    padding: 1px 6px;
    border-radius: 10px;
    background: rgba(255, 255, 255, .08);
    color: var(--slate-400);
}

/* 처리 대기 건수 배지. 어두운 사이드바에서 눈에 띄어야 하므로 경고색을 쓴다 */
.nav-item .count {
    margin-left: auto;
    min-width: 19px;
    padding: 0 6px;
    border-radius: 10px;
    background: var(--amber-600);
    color: var(--on-brand);
    font-size: 12px;
    font-weight: 700;
    line-height: 19px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.sidebar-foot {
    padding: 12px 16px 14px;
    border-top: 1px solid rgba(255, 255, 255, .08);
    font-size: 12px;
    color: var(--slate-500);
}

.main {
    flex: 1;
    margin-left: var(--sidebar-w);
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.topbar {
    height: 58px;
    background: var(--surface);
    border-bottom: 1px solid var(--slate-200);
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 24px;
    position: sticky;
    top: 0;
    z-index: 20;
}

.topbar h2 { margin: 0; font-size: 16px; font-weight: 700; letter-spacing: -.3px; }

.topbar-user { display: flex; align-items: center; gap: 14px; }

.avatar {
    width: 32px; height: 32px;
    border-radius: 50%;
    background: var(--brand-100);
    color: var(--brand-700);
    font-weight: 700;
    font-size: 14px;
    display: flex; align-items: center; justify-content: center;
}

.user-meta { line-height: 1.3; text-align: right; }
.user-meta .name { font-weight: 600; font-size: 14px; }
.user-meta .role { font-size: 12px; color: var(--slate-500); }

.content { padding: 24px; flex: 1; }

.page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 18px;
    flex-wrap: wrap;
}

.page-head h3 { margin: 0 0 4px; font-size: 20px; font-weight: 700; letter-spacing: -.4px; }
.page-head .desc { margin: 0; color: var(--slate-500); font-size: 14px; }
.page-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* ============================================================ 카드 */

.card {
    background: var(--surface);
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    margin-bottom: 18px;
}

.card-head {
    padding: 14px 18px;
    border-bottom: 1px solid var(--slate-200);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.card-head h4 { margin: 0; font-size: 15px; font-weight: 700; }
.card-body { padding: 18px; }
.card-body.tight { padding: 0; }

/* ============================================================ 통계 카드 */

.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 14px;
    margin-bottom: 18px;
}

.stat {
    background: var(--surface);
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    padding: 16px 18px;
    box-shadow: var(--shadow-sm);
    display: flex;
    align-items: center;
    gap: 14px;
}

.stat .ico {
    width: 42px; height: 42px;
    border-radius: 10px;
    display: flex; align-items: center; justify-content: center;
    font-size: 19px;
    flex-shrink: 0;
}
.stat .ico.brand { background: var(--brand-50); }
.stat .ico.green { background: var(--green-50); }
.stat .ico.amber { background: var(--amber-50); }
.stat .ico.red   { background: var(--red-50); }

.stat .label { font-size: 13px; color: var(--slate-500); }
.stat .value { font-size: 22px; font-weight: 700; letter-spacing: -.5px; line-height: 1.25; }
.stat .value small { font-size: 13px; font-weight: 500; color: var(--slate-400); }

/* ============================================================ 폼 */

.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 16px 20px;
}

.field { display: flex; flex-direction: column; gap: 6px; }
.field.full { grid-column: 1 / -1; }

/* 함께 읽어야 뜻이 통하는 칸들을 한 줄에 나란히 둔다.
   (입금은행·계좌번호·예금주 / 과세구분·공급가액·부가세·합계)
   바깥 격자는 폭에 따라 열 수가 달라져 '한 줄' 을 보장할 수 없어서,
   줄마다 열 수를 --cols 로 못박은 작은 격자를 하나 더 둔다.
   좁아지면 둘씩, 더 좁아지면 하나씩 접는다. */
.field-row {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr));
    gap: 16px 20px;
}

@media (max-width: 900px) {
    .field-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
    .field-row { grid-template-columns: minmax(0, 1fr); }
}

.field label {
    font-size: 13px;
    font-weight: 600;
    color: var(--slate-700);
}

.field label .req { color: var(--red-600); margin-left: 2px; }
.field .hint { font-size: 12px; color: var(--slate-400); }

/* hidden 을 붙였는데도 보이는 일이 없도록.
   .input 이 width/padding 을 잡고 있어 브라우저 기본 display:none 이
   덮이는 경우가 있다. */
[hidden] { display: none !important; }

.input, .select, .textarea {
    width: 100%;
    padding: 9px 11px;
    border: 1px solid var(--slate-300);
    border-radius: 6px;
    font-family: inherit;
    font-size: 14px;
    color: var(--slate-900);
    background: var(--surface);
    transition: border-color .12s, box-shadow .12s;
}

.input:focus, .select:focus, .textarea:focus {
    outline: none;
    border-color: var(--brand-600);
    box-shadow: 0 0 0 3px rgba(49, 130, 246, .18);
}

.input:disabled, .input[readonly] { background: var(--slate-100); color: var(--slate-500); }
.textarea { resize: vertical; min-height: 82px; }

.input-lg { padding: 11px 13px; font-size: 15px; }

/* 입력칸 + 버튼 조합 (예: 우편번호 + 주소 검색) */
.input-group { display: flex; gap: 6px; }
.input-group .input { flex: 1; min-width: 0; }
.input-group .btn { flex-shrink: 0; }

.checkbox { display: flex; align-items: center; gap: 8px; font-size: 14px; cursor: pointer; }
.checkbox input { width: 16px; height: 16px; accent-color: var(--brand-600); cursor: pointer; }

.form-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    padding-top: 18px;
    margin-top: 18px;
    border-top: 1px solid var(--slate-200);
}

fieldset {
    border: none;
    padding: 0;
    margin: 0 0 22px;
}
fieldset legend {
    font-size: 14px;
    font-weight: 700;
    color: var(--brand-800);
    padding: 0 0 10px;
    margin-bottom: 4px;
    width: 100%;
    border-bottom: 1px solid var(--slate-200);
}

/* ============================================================ 품목 찾기 */

/* 견적·수주 명세 팝업에서 등록된 품목을 골라 채우는 칸.
   결과 목록은 칸 아래로 겹쳐 펼쳐진다. 팝업 자체를 늘리면 아래에 있는
   수량·단가가 화면 밖으로 밀려나 무엇을 채웠는지 보이지 않는다. */
.item-picker {
    position: relative;
    padding: 12px 14px;
    margin-bottom: 16px;
    border: 1px solid var(--brand-100);
    border-radius: var(--radius);
    background: var(--brand-50);
}

.item-picker .hint { color: var(--slate-500); }
.item-picker .hint .mono { color: var(--brand-700); }

.picker-results {
    position: absolute;
    z-index: 5;
    left: 14px;
    right: 14px;
    top: 66px;
    max-height: 240px;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--slate-300);
    border-radius: 6px;
    box-shadow: 0 10px 24px rgba(15, 23, 42, .12);
}

.picker-row {
    display: flex;
    flex-direction: column;
    gap: 2px;
    width: 100%;
    padding: 9px 12px;
    border: none;
    border-bottom: 1px solid var(--slate-100);
    background: none;
    text-align: left;
    font-family: inherit;
    cursor: pointer;
}

.picker-row:last-child { border-bottom: none; }
.picker-row:hover { background: var(--brand-50); }
.picker-name { font-size: 14px; font-weight: 600; color: var(--slate-900); }
.picker-meta {
    font-size: 12px;
    color: var(--slate-500);
    font-variant-numeric: tabular-nums;
}

.picker-none { padding: 12px; font-size: 13px; color: var(--slate-500); }

/* 문장 안에 끼워 넣는 작은 조작 버튼. 버튼 모양을 내면 문장이 끊긴다. */
.link-button {
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    color: var(--brand-700);
    text-decoration: underline;
    cursor: pointer;
}
.link-button:hover { color: var(--brand-800); }

/* ============================================================ 담당자 목록 */

/* 담당자는 표로 한 줄씩만 보여준다. 추가·수정은 팝업에서 하므로
   담당자가 몇 명이 되든 화면이 길어지지 않는다. */
.contact-box {
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    overflow: hidden;
    margin-bottom: 12px;
}

.contact-grid thead th { background: var(--slate-50); }
.contact-grid tbody td { padding: 9px 12px; }

/* 대표 담당자 줄을 눈에 띄게 */
.contact-grid tbody tr:has(input[name="contact_primary"]:checked) {
    background: var(--brand-50);
}
.contact-grid tbody tr:has(input[name="contact_primary"]:checked) b {
    color: var(--brand-700);
}

.contact-grid input[type="radio"] {
    width: 16px; height: 16px;
    accent-color: var(--brand-600);
    cursor: pointer;
}

.contact-none {
    padding: 22px;
    margin-bottom: 12px;
    border: 1px dashed var(--slate-300);
    border-radius: var(--radius);
    background: var(--slate-50);
    text-align: center;
    color: var(--slate-500);
    font-size: 14px;
}

/* ============================================================ 서류 올리기 확인 */

/* 파일 한 개당 카드 하나. 손봐야 하는 줄은 눈에 띄게 둔다. */
.upload-row { margin-bottom: 14px; }
.upload-row .card-head { flex-wrap: wrap; gap: 8px; }

.upload-row-check {
    border-color: var(--amber-600);
    box-shadow: 0 0 0 3px rgba(217, 119, 6, .1);
}
.upload-row-check .card-head { background: var(--amber-50); }

/* ============================================================ 메뉴 권한 */

.menu-perms {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 8px 16px;
    margin-bottom: 10px;
}

.menu-perm {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 12px;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    background: var(--slate-50);
    font-size: 14px;
    cursor: pointer;
}
.menu-perm:hover { border-color: var(--brand-500); }
.menu-perm:has(input:checked) {
    border-color: var(--brand-600);
    background: var(--brand-50);
    font-weight: 600;
}

/* ---- 대분류로 묶은 메뉴 체크상자
   사용자 폼 · 계정 승인 · 권한 묶음 · 일괄 적용이 같은 조각을 쓴다.
   묶음은 사이드바와 같다 (app/auth.py 의 MENU_GROUPS). */

.menu-groups { display: flex; flex-direction: column; gap: 12px; }

.menu-group {
    padding: 10px 12px 4px;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
}

.menu-group-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    font-size: 13px;
    cursor: pointer;
}

.menu-group-head .muted { font-size: 12px; }
.menu-group .menu-perms { margin-bottom: 6px; }

/* ---- 일괄 적용의 묶음 고르기 줄 */
.bulk-preset {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 10px;
    margin-bottom: 12px;
}

.bulk-preset .select { flex: 1; min-width: 260px; }
.bulk-preset .flabel { font-size: 13px; font-weight: 600; color: var(--slate-700); }
.bulk-preset .hint { flex-basis: 100%; font-size: 12px; color: var(--slate-500); }

/* ---- 메뉴 일괄 적용 (사용자·권한 관리 목록 아래)
   메뉴가 하나 늘 때마다 계정을 한 명씩 여는 것이 번거로워 둔 자리다. */

.bulk-menus {
    padding: 14px 18px;
    border-top: 1px solid var(--slate-200);
    background: var(--slate-50);
}

.bulk-head { margin-bottom: 10px; font-size: 13px; }
.bulk-head .muted { font-weight: 500; font-size: 12px; }

.bulk-acts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
}

.bulk-acts .hint { font-size: 12px; color: var(--slate-500); }

.soon-tag {
    margin-left: auto;
    font-size: 12px;
    font-weight: 500;
    padding: 1px 6px;
    border-radius: 10px;
    background: var(--slate-200);
    color: var(--slate-500);
}

/* ============================================================ 수주 · 매출 */

/* 오른쪽 정렬. 숫자 칸의 머리글(th)에도 필요해서 따로 둔다 —
   .num 은 본문 칸에만 붙이는 것이 이 저장소의 약속이라 머리글에는 안 붙는다. */
.right { text-align: right; }
th.right, td.right { text-align: right; }
input.right { text-align: right; }

/* 표 안에서는 위의 th.right 만으로는 이기지 못한다. 머리글을 왼쪽으로
   못박는 규칙(table.grid thead th)이 선택자가 더 길어 더 세기 때문이다.
   그래서 숫자 칸 머리글만 홀로 왼쪽에 남아, '1월' 과 그 아래 금액이 서로
   다른 줄처럼 보였다. 같은 세기로 다시 적어 준다.
   (.center 는 table.grid .center 로 적혀 있어 원래부터 이겼다) */
table.grid .right { text-align: right; }

/* 남은 수량보다 많이 적었을 때. 저장은 서버가 다시 막는다. */
.input-warn, .input-warn:focus {
    border-color: var(--red-600);
    box-shadow: 0 0 0 3px rgba(220, 38, 38, .15);
}

/* 합계 줄 */
table.grid tfoot td {
    padding: 8px 14px;
    border-top: 1px solid var(--slate-200);
    background: var(--slate-50);
    font-size: 14px;
}
table.grid tfoot tr.sum-total td {
    background: var(--brand-50);
    font-size: 15px;
    border-top: 2px solid var(--brand-600);
}
table.grid tfoot .num { font-variant-numeric: tabular-nums; }

.remain { color: var(--brand-700); }

/* 수주 대비 매출 진행률 */
.progress {
    width: 68px;
    height: 7px;
    border-radius: 4px;
    background: var(--slate-200);
    overflow: hidden;
}
.progress span {
    display: block;
    height: 100%;
    background: var(--brand-600);
    border-radius: 4px;
}

/* 머리글·값이 짝을 이루는 상세 정보 */
.detail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 12px 24px;
}
.detail-grid > div {
    display: flex;
    gap: 10px;
    align-items: baseline;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--slate-100);
}
.detail-grid .full { grid-column: 1 / -1; }
.detail-grid .k {
    flex-shrink: 0;
    width: 108px;
    font-size: 13px;
    font-weight: 600;
    color: var(--slate-500);
}
.detail-grid .v { min-width: 0; word-break: break-word; }

/* ============================================================ 불러오기 미리보기 */

table.grid tbody tr.row-error { background: var(--red-50); }
table.grid tbody tr.row-error:hover { background: var(--red-hover); }

.import-error {
    font-size: 13px;
    color: var(--red-800);
    line-height: 1.5;
}
.import-error + .import-error { margin-top: 3px; }

/* 담당자 팝업 안의 입력칸 */
.contact-fields { gap: 12px 14px; }

@media (min-width: 560px) {
    .contact-fields { grid-template-columns: repeat(2, 1fr); }
}

/* ============================================================ 버튼 */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 15px;
    border: 1px solid transparent;
    border-radius: 6px;
    font-family: inherit;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s;
    white-space: nowrap;
    /* 줄높이를 못 박아 둔다. 안 그러면 같은 btn 이라도 <button> 은 브라우저
       기본값(normal)을, <a> 는 body 의 1.7 을 쓰게 되어 나란히 놓았을 때
       높이가 어긋난다. (예: '입금 수정' 버튼과 '매출 수정' 링크) */
    line-height: 1.25;
    vertical-align: middle;
}
.btn:hover { text-decoration: none; }

.btn-primary { background: var(--brand-600); color: var(--on-brand); }
.btn-primary:hover { background: var(--brand-strong); }

.btn-default { background: var(--surface); color: var(--slate-700); border-color: var(--slate-300); }
.btn-default:hover { background: var(--slate-50); border-color: var(--slate-400); }

.btn-danger { background: var(--surface); color: var(--red-600); border-color: var(--red-300); }
.btn-danger:hover { background: var(--red-50); }

.btn-ghost { background: transparent; color: var(--slate-600); }
.btn-ghost:hover { background: var(--slate-100); }

.btn-block { width: 100%; padding: 11px 15px; font-size: 15px; }
.btn-sm { padding: 5px 10px; font-size: 13px; }

/* ============================================================ 테이블 */

.table-wrap { overflow-x: auto; }

table.grid {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}

table.grid thead th {
    background: var(--slate-50);
    border-bottom: 1px solid var(--slate-200);
    padding: 10px 14px;
    text-align: left;
    font-size: 13px;
    font-weight: 700;
    color: var(--slate-600);
    white-space: nowrap;
}

table.grid thead th a { color: var(--slate-600); }
table.grid thead th a:hover { color: var(--brand-600); text-decoration: none; }

table.grid tbody td {
    padding: 11px 14px;
    border-bottom: 1px solid var(--slate-100);
    vertical-align: middle;
}

/* 칸과 칸 사이 세로선.
   가로줄만 있으면 칸이 좁을 때 눈이 옆으로 미끄러진다 — 열두 달 표에서
   1월 옆이 2월인지 짚어 가며 세게 되는 것이 그 때문이다.

   색은 가로줄과 같은 것을 쓴다. 진하게 두면 표가 격자로 갑갑해지고,
   목록처럼 글자 칸이 넓은 표에서는 엑셀처럼 보인다. 있는 듯 없는 듯한
   선이 칸을 갈라 주기만 하면 된다.

   머리글(th)에도 넣어야 위아래가 한 줄로 이어져 보인다.
   첫 칸에는 붙지 않는다(+ 선택자라 두 번째 칸부터 걸린다). 묶음 머리처럼
   칸 하나가 줄 전체를 차지하는 곳(colspan)도 저절로 비켜 간다. */
table.grid th + th,
table.grid td + td { border-left: 1px solid var(--slate-100); }

table.grid tbody tr:hover { background: var(--brand-50); }
table.grid tbody tr:last-child td { border-bottom: none; }

table.grid .num { text-align: right; font-variant-numeric: tabular-nums; }
table.grid .center { text-align: center; }
table.grid .nowrap { white-space: nowrap; }
table.grid .muted { color: var(--slate-400); }

/* 숫자에 뜻을 실어야 할 때. 재고가 늘었나 줄었나, 모자라나.
   배지를 쓰기에는 숫자 옆이 좁고, 색만으로 충분한 자리다.
   (색이 안 보이는 사람을 위해 부호나 글자를 늘 함께 적는다) */
.txt-red   { color: var(--red-600); font-weight: 600; }
.txt-green { color: var(--green-600); font-weight: 600; }
.txt-amber { color: var(--amber-600); font-weight: 600; }

.empty {
    padding: 54px 20px;
    text-align: center;
    color: var(--slate-400);
}
.empty .big { font-size: 34px; margin-bottom: 10px; opacity: .5; }
.empty p { margin: 0 0 4px; font-size: 15px; color: var(--slate-500); }
.empty .sub { font-size: 13px; }

/* 상세보기 정의형 테이블 */
table.detail { width: 100%; border-collapse: collapse; font-size: 14px; }
table.detail th, table.detail td {
    padding: 11px 14px;
    border-bottom: 1px solid var(--slate-100);
    text-align: left;
    vertical-align: top;
}
table.detail th {
    width: 130px;
    background: var(--slate-50);
    font-weight: 600;
    color: var(--slate-600);
    font-size: 13px;
    white-space: nowrap;
}

/* ============================================================ 배지 */

.badge {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 20px;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.7;
    white-space: nowrap;
}

.badge-brand  { background: var(--brand-50); color: var(--brand-700); }
.badge-green  { background: var(--green-50); color: var(--green-600); }
.badge-amber  { background: var(--amber-50); color: var(--amber-600); }
.badge-red    { background: var(--red-50); color: var(--red-600); }
.badge-gray   { background: var(--slate-100); color: var(--slate-500); }

/* ============================================================ 검색바 */

.searchbar {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    align-items: center;
    padding: 14px 18px;
    border-bottom: 1px solid var(--slate-200);
    background: var(--slate-50);
    border-radius: var(--radius) var(--radius) 0 0;
}

.searchbar .input, .searchbar .select { width: auto; }
.searchbar .grow { flex: 1; min-width: 200px; }
.searchbar .spacer { flex: 1; }

/* ============================================================ 페이지네이션 */

.pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 13px 18px;
    border-top: 1px solid var(--slate-200);
    flex-wrap: wrap;
}

.pagination .info { font-size: 13px; color: var(--slate-500); }
.pagination .pages { display: flex; gap: 4px; }

.pagination .pages a, .pagination .pages span {
    min-width: 32px;
    height: 32px;
    padding: 0 8px;
    border-radius: 6px;
    border: 1px solid var(--slate-200);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    color: var(--slate-600);
    background: var(--surface);
}
.pagination .pages a:hover { background: var(--slate-50); text-decoration: none; }
.pagination .pages .current {
    background: var(--brand-600);
    border-color: var(--brand-600);
    color: var(--on-brand);
    font-weight: 600;
}
.pagination .pages .disabled { color: var(--slate-300); background: var(--slate-50); }

/* ============================================================ 알림 메시지 */

.flashes { margin-bottom: 16px; display: flex; flex-direction: column; gap: 8px; }

.flash {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    padding: 11px 14px;
    border-radius: 6px;
    font-size: 14px;
    border: 1px solid;
}

.flash-error   { background: var(--red-50);   border-color: var(--red-200); color: var(--red-800); }
.flash-success { background: var(--green-50); border-color: var(--green-200); color: var(--green-700); }
.flash-warning { background: var(--amber-50); border-color: var(--amber-200); color: var(--amber-800); }
.flash-info    { background: var(--brand-50);  border-color: var(--brand-100); color: var(--brand-700); }

.flash .ico { flex-shrink: 0; }

/* ============================================================ 안내 박스 */

.notice {
    padding: 12px 15px;
    border-radius: 6px;
    font-size: 14px;
    background: var(--brand-50);
    border: 1px solid var(--brand-100);
    color: var(--brand-700);
    line-height: 1.7;
}
.notice code {
    background: var(--surface);
    border: 1px solid var(--brand-100);
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 13px;
}

/* 문서번호·관리번호·날짜·파일이름처럼 **글자를 세로로 맞춰 읽는 값**에 붙인다.
   자릿수만 맞추고 글꼴은 본문 그대로 둔다.

   예전에는 여기서 고정폭 글꼴(Consolas 등)로 바꿨다. 그런데 고정폭은 글자
   높이가 낮아 같은 크기라도 본문보다 작아 보인다. 한 화면에 두 글꼴이 섞이니
   "저기만 글씨가 작고 이상하다" 는 말이 계속 나왔고, 실제로 그랬다.

   화면의 글꼴은 하나다(Pretendard). 자릿수 맞춤은 글꼴을 바꾸지 않고
   font-variant-numeric 으로 얻는다 — Pretendard 가 이 기능을 갖고 있다.
   크기도 못박지 않는다. 표 글씨를 키우면 이 칸도 함께 커져야 한다. */
.mono {
    font-variant-numeric: tabular-nums;
}

/* ============================================================ 모달 */

.modal-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 100;
    background: rgba(15, 23, 42, .5);
    padding: 24px;
    overflow-y: auto;
}

.modal-backdrop.open {
    display: flex;
    align-items: flex-start;
    justify-content: center;
}

.modal {
    background: var(--surface);
    border-radius: 10px;
    box-shadow: var(--shadow-lg);
    width: 100%;
    max-width: 620px;
    margin: auto;
    overflow: hidden;
    animation: modal-in .16s ease-out;
}

.modal--narrow { max-width: 460px; }
.modal--wide   { max-width: 820px; }

@keyframes modal-in {
    from { opacity: 0; transform: translateY(-10px); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .modal { animation: none; }
}

.modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 18px;
    border-bottom: 1px solid var(--slate-200);
}

.modal-head h4 { margin: 0; font-size: 15px; font-weight: 700; }

.modal-close {
    border: none;
    background: transparent;
    font-size: 24px;
    line-height: 1;
    color: var(--slate-400);
    cursor: pointer;
    padding: 0 4px;
}
.modal-close:hover { color: var(--slate-700); }

.modal-body {
    padding: 18px 20px 20px;
    max-height: calc(100vh - 160px);
    overflow-y: auto;
}

/* 주소 검색처럼 여백 없이 꽉 채우는 경우 */
.modal-body.tight { padding: 0; overflow: hidden; }

/* 팝업 안에서는 마지막 구역의 아래 여백을 줄인다 */
.modal-body fieldset:last-of-type { margin-bottom: 0; }

/* ============================================================ 검수 증빙사진

   붙이기 전 미리보기(.photo-stage-item)와 이미 붙여둔 사진(.photo-item)이
   같은 크기로 보여야, 무엇이 올라갈 것이고 무엇이 이미 올라갔는지 한눈에
   구분되지 않는 일이 없다. 그래서 두 칸의 그림 높이를 같게 둔다. */

.photo-manage,
#photoStage {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 14px;
    margin-top: 14px;
}

.photo-item,
.photo-stage-item {
    border: 1px solid var(--slate-200);
    border-radius: 8px;
    padding: 10px;
    background: var(--surface);
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.photo-stage-item { border-style: dashed; background: var(--slate-50); }

.photo-item img,
.photo-stage-item img {
    width: 100%;
    height: 130px;
    object-fit: contain;
    background: var(--slate-100);
    border-radius: 6px;
}

.photo-item form { margin: 0; }

.photo-caption-form {
    display: flex;
    gap: 6px;
    align-items: center;
}
.photo-caption-form .input { flex: 1; min-width: 0; }
.modal-body .form-actions { margin-bottom: 0; }
.modal-body [data-modal-errors]:not(:empty) { margin-bottom: 14px; }

.modal-loading {
    padding: 48px 20px;
    text-align: center;
    color: var(--slate-400);
    font-size: 14px;
}

.postcode-slot {
    width: 100%;
    height: 460px;
    overflow: hidden;
}

/* 팝업으로 방금 추가·수정한 줄을 잠깐 강조 */
@keyframes row-added {
    0%   { background: var(--highlight); }
    100% { background: transparent; }
}

table.grid tbody tr.row-added {
    animation: row-added 2.4s ease-out;
}

/* ============================================================ 오류 페이지 */

.error-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    text-align: center;
}
.error-page .code {
    font-size: 64px;
    font-weight: 800;
    color: var(--slate-300);
    letter-spacing: -2px;
    line-height: 1;
}
.error-page .msg { margin: 14px 0 24px; font-size: 15px; color: var(--slate-600); }

/* ============================================================ 반응형 */

@media (max-width: 900px) {
    .sidebar { transform: translateX(-100%); transition: transform .2s; }
    .sidebar.open { transform: translateX(0); }
    .main { margin-left: 0; }
    .menu-toggle { display: inline-flex !important; }
    .content { padding: 16px; }
    .topbar { padding: 0 14px; }
    .scrim {
        position: fixed; inset: 0; background: rgba(15, 23, 42, .45); z-index: 25;
    }
}

.menu-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 34px; height: 34px;
    margin-right: 10px;
    border: 1px solid var(--slate-300);
    border-radius: 6px;
    background: var(--surface);
    cursor: pointer;
    font-size: 15px;
}

@media print {
    .sidebar, .topbar, .page-actions, .form-actions, .searchbar, .pagination { display: none !important; }
    .main { margin-left: 0; }
    body { background: #fff; }
    .card { border: none; box-shadow: none; }
}


/* ============================================================ 입금 관리 */

/* 매출 줄 안에 붙는 입금 한 건. 아래로 줄을 늘리지 않고 옆으로 붙인다.
   (표가 두 줄, 세 줄이 되면 훑기 어렵다) */
.pay-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-left: 6px;
    padding: 2px 4px 2px 8px;
    border: 1px solid var(--slate-200);
    border-radius: 999px;
    background: var(--surface);
    font-size: 12px;
    vertical-align: middle;
}
.pay-chip .mono { font-size: 12px; }

/* 입금 하나를 고치는 줄. 수정 폼과 삭제 버튼이 나란히 선다 */
.pay-panel { display: flex; flex-direction: column; gap: 10px; }
.pay-edit {
    display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap;
    padding-bottom: 10px;
    border-bottom: 1px dashed var(--slate-300);
}
.pay-edit .pay-inline { flex: 1; }

/* 매출 아래에 붙는 입금 내역 줄 */
.pay-detail td { background: var(--slate-50); padding-top: 6px; padding-bottom: 6px; }
.pay-lines { display: flex; flex-wrap: wrap; gap: 6px 18px; font-size: 13px; }
.pay-line { display: inline-flex; align-items: center; gap: 6px; }

/* 표 안에 접어둔 입금 입력줄 */
.pay-form td { background: var(--brand-50); }
.pay-inline {
    display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px;
}
.pay-inline label {
    display: flex; flex-direction: column; gap: 4px;
    font-size: 13px; color: var(--slate-600); font-weight: 600;
}
.pay-inline label.grow { flex: 1; min-width: 160px; }
.pay-inline .input, .pay-inline .select { min-width: 130px; }


/* 같은 자료를 보는 방식이 두 가지일 때 쓰는 탭 (매출별 / 거래처별) */
.tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 16px;
    border-bottom: 1px solid var(--slate-200);
}
.tabs .tab {
    padding: 9px 16px;
    font-size: 14px;
    font-weight: 600;
    color: var(--slate-500);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}
.tabs .tab:hover { color: var(--slate-700); }
/* 탭 옆에 붙는 한 줄 안내. 이 화면이 무엇을 보여주는지 짚어준다 */
.tabs .tab-note {
    margin-left: auto;
    align-self: center;
    padding-bottom: 6px;
    font-size: 13px;
    color: var(--slate-500);
}

.tabs .tab.active {
    color: var(--brand-700);
    border-bottom-color: var(--brand-600);
}

/* 손볼 것이 몇 건 있는지. 사이드바 배지와 같은 모양으로 둔다. */
.tabs .tab .count {
    display: inline-block;
    min-width: 18px;
    padding: 1px 6px;
    margin-left: 4px;
    border-radius: 9px;
    background: var(--amber-600);
    color: var(--on-brand);
    font-size: 12px;
    font-weight: 700;
    text-align: center;
    vertical-align: 1px;
}

/* ============================================================ 공용 캘린더

   한 주가 격자(grid) 하나다. 열은 요일 7칸으로 고정하고, 행은
       1행        날짜 숫자
       2행~       일정 막대가 쌓이는 층(lane). 주마다 --lanes 로 개수를 준다
       마지막 행  남는 높이를 먹는 칸 (칸 높이를 고르게 하려고 둔다)
   바탕 칸은 1행부터 끝까지 걸쳐 두고 그 위에 막대를 얹는다. 격자에서는
   같은 칸에 여러 개를 겹쳐 놓을 수 있어서, 자리 계산을 손으로 하지 않아도
   여러 날짜리 막대가 요일 칸에 정확히 맞아떨어진다.

   날짜 숫자는 바탕 칸 안에 넣지 않고 1행에 따로 놓는다. 여러 행에 걸친
   항목의 내용은 auto 행 높이를 늘려 주지 않기 때문에(마지막 행이 1fr 이라
   더욱 그렇다), 칸 안에 두면 1행이 0 이 되어 숫자가 흘러넘치고 첫 막대가
   그 위에 겹쳐 날짜가 가려진다.                                            */

.cal {
    border-top: 1px solid var(--slate-200);
}

.cal-head,
.cal-week {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
}

.cal-head-cell {
    padding: 8px 0;
    border-bottom: 1px solid var(--slate-200);
    background: var(--slate-50);
    color: var(--slate-500);
    font-size: 13px;
    font-weight: 600;
    text-align: center;
}

/* 주말은 글자색만 달리한다. 바탕까지 칠하면 일정 막대가 묻힌다.
   data-wd 는 칸 순서가 아니라 요일 번호다(월 0 … 토 5, 일 6). 주 시작을
   일요일로 바꿔도 색이 따라 움직이지 않아야 해서 그렇게 두었다. */
.cal-head-cell[data-wd="5"] { color: var(--brand-700); }
.cal-head-cell[data-wd="6"] { color: var(--red-600); }

/* ---- 검색줄에 폼이 둘이다. 왼쪽은 달·분류 고르기(GET), 오른쪽 끝은
        주 시작 요일 고르기(POST, 계정에 저장). */

.cal-filter { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

.cal-weekstart {
    display: flex;
    gap: 4px;
    align-items: center;
    margin-left: auto;
}

.cal-weekstart .lbl {
    margin-right: 2px;
    color: var(--slate-500);
    font-size: 13px;
    white-space: nowrap;
}

/* 글자 한 자짜리 단추라 기본 좌우 여백이 너무 넓다 */
.cal-weekstart .btn { min-width: 32px; padding-left: 9px; padding-right: 9px; }

/* 한 주의 높이는 그 주에 필요한 층수(--lanes)가 정한다. 일정이 많은 주는
   그만큼 길어진다 —— 접지 않고 다 보여 주기로 했기 때문이다
   (app/views/calendar.py 의 MAX_LANES 주석).

   min-height 는 일정이 없는 주가 납작해지지 않게 잡아 주는 값이고, 마지막
   행(minmax)은 막대 아래에 숨 쉴 자리를 둔다. */
.cal-week {
    grid-template-rows: auto repeat(var(--lanes, 1), 22px) minmax(10px, 1fr);
    min-height: 104px;
    border-bottom: 1px solid var(--slate-200);
}

.cal-cell {
    grid-row: 1 / -1;
    border-left: 1px solid var(--slate-200);
    color: inherit;
    text-decoration: none;
}

.cal-cell:first-child { border-left: 0; }
.cal-cell:hover { background: var(--brand-50); text-decoration: none; }

/* ---- 칸에 마우스를 올렸을 때만 나오는 ＋ (일정 등록)

   예전에는 칸 아무 데나 누르면 등록 화면이 떴다. 달력을 훑다가 스친 것만으로
   창이 열려서, 누를 자리를 따로 두었다.

   자리를 absolute 로 잡는 이유: 이 칸은 1행부터 끝까지 걸쳐 있어, 안에 그냥
   넣으면 1행 높이를 밀어 올려 날짜 숫자와 막대가 어긋난다.
   날짜 숫자(왼쪽 6px + 최소 22px) 옆에 앉히려고 30px 을 띄운다. */
.cal-add {
    position: absolute;
    top: 5px;
    left: 30px;
    z-index: 2;
    display: none;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border-radius: 5px;
    background: var(--brand-600);
    color: var(--on-brand);
    font-size: 13px;
    line-height: 1;
    text-decoration: none;
}

.cal-cell { position: relative; }
.cal-cell:hover .cal-add { display: flex; }
.cal-add:hover { background: var(--brand-strong); text-decoration: none; }

/* 손가락에는 hover 가 없다. 휴대폰에서는 늘 보이되 옅게 둔다 —— 아예 안
   보이면 그 화면에서는 일정을 새로 적을 길이 사라진다. */
@media (hover: none) {
    .cal-add { display: flex; opacity: .45; }
}

/* 이번 달이 아닌 날. 지우지 않고 흐리게만 둔다.
   달 경계에 걸친 일정이 어디서 시작해 어디서 끝나는지 보여야 하기 때문이다. */
.cal-cell.out { background: var(--slate-50); }

/* 날짜 숫자는 1행에 놓인 별개의 칸이다(위 머리말 참고).
   눌렀을 때는 뒤에 깔린 바탕 칸이 받아야 하므로 pointer-events 를 끈다. */
.cal-daynum {
    z-index: 2;
    align-self: start;
    justify-self: start;
    pointer-events: none;
    min-width: 22px;
    margin: 6px 0 2px 6px;
    padding: 1px 0;
    color: var(--slate-600);
    font-size: 13px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.cal-daynum.out { color: var(--slate-300); }

.cal-daynum[data-wd="5"] { color: var(--brand-700); }
.cal-daynum[data-wd="6"] { color: var(--red-600); }

.cal-daynum.today {
    border-radius: 999px;
    background: var(--brand-600);
    color: var(--on-brand);
}

/* ---- 일정 막대 */

.cal-bar {
    z-index: 1;                 /* 바탕 칸 위로 */
    overflow: hidden;
    align-self: center;
    display: flex;
    align-items: center;
    gap: 5px;
    height: 20px;
    margin: 0 4px;
    padding: 0 7px;
    border-radius: 4px;
    font-size: 12px;
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
}

.cal-bar:hover { text-decoration: none; filter: brightness(.94); }
.cal-bar .txt { overflow: hidden; text-overflow: ellipsis; }
.cal-bar b { opacity: .75; font-weight: 600; }

/* 반복 일정 표시. 막대 색은 분류가 쓰고 있어서, 반복은 글자 앞의 작은
   기호로만 알린다. flex-shrink:0 이 없으면 이름이 길 때 이것부터 눌린다. */
.cal-rep { flex-shrink: 0; opacity: .6; font-style: normal; font-size: 11px; }

/* ---- 끌어 옮기기 (static/js/cal_drag.js)

   잡을 수 있는 막대만 손 모양이 된다. 반복 일정은 draggable 이 없어 그대로
   화살표라, 잡히지 않는다는 것이 손끝으로 먼저 전해진다. */
.cal-bar[draggable="true"] { cursor: grab; }
.cal-bar[draggable="true"]:active { cursor: grabbing; }

.cal-bar.cal-dragging { opacity: .4; }
.cal-bar.cal-moving { opacity: .5; pointer-events: none; }

/* 끄는 동안 막대의 pointer-events 를 끄지 않는다. 크롬은 끌던 요소의
   pointer-events 가 바뀌면 끌기를 취소해 버린다 —— 그래서 처음에 아예
   옮겨지지 않았다. 놓은 자리는 좌표로 센다(cal_drag.js). */

/* 놓을 자리 표시. 테두리가 아니라 바탕을 칠한다 —— 칸이 좁아 테두리를
   두르면 옆 칸과 붙어 어디가 어디인지 되레 흐려진다. */
.cal-cell.cal-drop { background: var(--brand-50); box-shadow: inset 0 0 0 2px var(--brand-600); }

.cal-undo { margin-left: 10px; }

/* 주 경계에서 잘린 쪽. 모서리를 각지게 두어 다음 주로 이어짐을 보인다. */
.cal-bar.clip-l { margin-left: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; }
.cal-bar.clip-r { margin-right: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; }

/* 분류별 색.
   **분류 열쇠가 아니라 분류에 적어 둔 색 이름표로 칠한다**
   (app/views/calendar.py 의 CATEGORY_COLORS). 분류는 사람이 늘릴 수 있으므로
   열쇠로 칠하면 분류가 늘 때마다 이 파일을 고쳐야 하고, 고치지 않은 분류는
   색 없이 그려진다.

   'strong' 만 옅은 바탕이 아니라 진하게 칠한다. '중요' 가 쓰는 색이다 —
   제목에 '※ 중요※' 라고 적어 두던 것을 대신하는 분류라, 다른 막대와 섞여
   보이면 뜻이 없다. 'red'(휴무)도 붉은 계열이지만 옅어서 한눈에 갈린다. */
.cal-bar[data-color="strong"] { background: var(--red-600); color: var(--on-brand); }
.cal-bar[data-color="strong"] b,
.cal-bar[data-color="strong"] .cal-rep { opacity: .85; }

.cal-bar[data-color="blue"]   { background: var(--brand-50);  color: var(--brand-700); }
.cal-bar[data-color="green"]  { background: var(--green-50);  color: var(--green-600); }
.cal-bar[data-color="amber"]  { background: var(--amber-50);  color: var(--amber-600); }
.cal-bar[data-color="violet"] { background: var(--violet-50); color: var(--violet-600); }
.cal-bar[data-color="red"]    { background: var(--red-50);    color: var(--red-600); }
.cal-bar[data-color="gray"]   { background: var(--slate-100); color: var(--slate-600); }

/* 접힌 건수. 눌러서 그 날 하루치 목록(_day.html)을 연다.
   바탕 칸(그 날짜로 등록하는 링크) 위에 얹혀야 눌리므로 z-index 는 막대와
   같이 준다. justify-self 를 주지 않으면 칸 너비만큼 늘어나, 글자가 없는
   자리까지 눌러도 목록이 열린다. */
.cal-more {
    z-index: 1;
    align-self: center;
    justify-self: start;
    margin: 0 6px;
    padding: 1px 5px;
    border-radius: 4px;
    color: var(--slate-500);
    font-size: 12px;
    font-weight: 600;
    text-decoration: none;
}

.cal-more:hover {
    background: var(--slate-100);
    color: var(--slate-700);
    text-decoration: none;
}

/* ---- 하루치 목록
   달력의 '＋n' 을 눌러 뜨는 팝업과, 자바스크립트가 막혔을 때의 전체 화면이
   같은 조각을 쓴다. */

.cal-day-note {
    margin: 0 0 12px;
    color: var(--slate-500);
    font-size: 13px;
}

.cal-daylist { list-style: none; margin: 0; padding: 0; }
.cal-daylist li + li { border-top: 1px solid var(--slate-100); }

.cal-dayitem {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 8px;
    border-radius: 6px;
    color: inherit;
    text-decoration: none;
}

.cal-dayitem:hover { background: var(--slate-50); text-decoration: none; }

.cal-dot { flex-shrink: 0; margin-top: 4px; }

/* 시각 칸을 고정 너비로 두면 '종일' 과 시각이 섞여도 이름이 한 줄로 선다 */
.cal-dayitem .when {
    flex-shrink: 0;
    width: 42px;
    color: var(--slate-500);
    font-size: 13px;
    line-height: 20px;
}

.cal-dayitem .body { min-width: 0; }
.cal-dayitem .ttl { font-size: 14px; font-weight: 600; }

.cal-dayitem .meta {
    display: block;
    margin-top: 2px;
    color: var(--slate-500);
    font-size: 12px;
}

.cal-day-foot {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--slate-200);
    text-align: right;
}

/* ---- 일정 조회 (읽기만 하는 화면)

   달력·목록에서 일정을 누르면 이것이 먼저 뜬다. 고치려면 여기서 '수정' 을
   한 번 더 눌러야 한다. */

.cal-view .ttl {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 14px;
    font-size: 17px;
    font-weight: 700;
    line-height: 1.4;
}

.cal-view-rows {
    display: grid;
    grid-template-columns: 76px minmax(0, 1fr);
    gap: 8px 12px;
    margin: 0;
    font-size: 14px;
}

.cal-view-rows dt { color: var(--slate-500); font-weight: 600; }
.cal-view-rows dd { margin: 0; min-width: 0; word-break: break-word; }
.cal-view-rows dd.pre { white-space: pre-wrap; }
.cal-view-rows .hint { display: block; margin-top: 2px; }

.cal-view-acts {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--slate-200);
}

.cal-view-acts .btn-ghost { margin-left: auto; }

/* ---- 다가오는 일정 목록 (「목록」 탭)
   날짜 머리 + 그 날의 줄들. 줄은 하루치 팝업과 같은 것을 쓴다. */

.cal-agenda-day { border-bottom: 1px solid var(--slate-200); }
.cal-agenda-day:last-child { border-bottom: 0; }

/* 날짜 머리 자체가 그 날 하루치 화면으로 가는 링크다 */
.cal-agenda-day .head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 18px;
    background: var(--slate-50);
    color: var(--slate-600);
    font-size: 13px;
    text-decoration: none;
}

.cal-agenda-day .head:hover { background: var(--brand-50); text-decoration: none; }
.cal-agenda-day .head .d { font-size: 15px; font-weight: 700; color: var(--slate-700); }
.cal-agenda-day .head .n { margin-left: auto; color: var(--slate-400); }

/* 주말 색은 달력과 같은 규칙이다 — 요일 번호(월 0 … 토 5, 일 6) */
.cal-agenda-day .head .wd[data-wd="5"] { color: var(--brand-700); }
.cal-agenda-day .head .wd[data-wd="6"] { color: var(--red-600); }

.cal-agenda-day.today .head { background: var(--brand-50); }
.cal-agenda-day .cal-daylist { padding: 4px 10px; }

/* ---- 분류 안내 */

.cal-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    padding: 12px 18px;
    color: var(--slate-500);
    font-size: 13px;
}

.cal-legend-item { display: flex; align-items: center; gap: 6px; }

/* 분류 색 조각. 이름표(.cal-legend-item i)와 하루치 목록의 점(.cal-dot)이
   같은 색을 쓴다. 색은 한 곳에만 적어 둔다. */
.cal-legend-item i,
.cal-dot {
    width: 12px;
    height: 12px;
    border-radius: 3px;
}

.cal-legend-item i[data-color="strong"], .cal-dot[data-color="strong"] { background: var(--red-600); }
.cal-legend-item i[data-color="blue"],   .cal-dot[data-color="blue"]   { background: var(--brand-100); }
.cal-legend-item i[data-color="green"],  .cal-dot[data-color="green"]  { background: var(--green-200); }
.cal-legend-item i[data-color="amber"],  .cal-dot[data-color="amber"]  { background: var(--amber-200); }
.cal-legend-item i[data-color="violet"], .cal-dot[data-color="violet"] { background: var(--violet-200); }
.cal-legend-item i[data-color="red"],    .cal-dot[data-color="red"]    { background: var(--red-200); }
.cal-legend-item i[data-color="gray"],   .cal-dot[data-color="gray"]   { background: var(--slate-200); }

/* 새 분류 칸. 드롭다운에서 '＋ 새 분류' 를 골랐을 때만 열린다.
   자바스크립트가 막혀 있으면 늘 보이는데, 그래도 고른 대로 저장된다. */
.cal-newcat { display: flex; gap: 8px; margin-top: 6px; }
.cal-newcat .input { flex: 2; min-width: 0; }
.cal-newcat .select { flex: 1; min-width: 90px; }

/* ---- 회의록의 할 일
   끝난 줄은 지우지 않고 흐리게만 둔다. 무엇을 하기로 했었는지가 회의록의
   기록이라, 끝났다고 목록에서 빼면 그 회의가 무엇을 남겼는지 알 수 없다. */
.todo-done td { opacity: .55; }
.todo-done td:nth-child(2) { text-decoration: line-through; }

/* ---- 회의록의 사진 첨부
   이름만 세우면 무엇을 찍은 것인지 하나씩 열어 봐야 한다. 회의록의 사진은
   대개 화이트보드나 현장이라 눈으로 훑을 수 있어야 쓸모가 있다. */
.note-shots {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
}

.note-shot {
    display: block;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--slate-50);
    color: inherit;
    text-decoration: none;
}

.note-shot:hover { border-color: var(--brand-500); text-decoration: none; }

/* 가로세로가 제각각인 사진을 같은 칸에 담는다. 비율을 억지로 늘리지 않고
   넘치는 쪽을 잘라내야 줄이 들쭉날쭉해지지 않는다. */
.note-shot img {
    display: block;
    width: 100%;
    height: 118px;
    object-fit: cover;
}

.note-shot .nm {
    display: block;
    padding: 6px 8px;
    font-size: 12px;
    color: var(--slate-600);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---- 달 넘기기 */

.cal-nav { display: flex; gap: 6px; margin-right: auto; }

/* ---- 일정 폼의 시각 칸
   '종일' 이 켜져 있으면 시각 칸을 감춘다. 자바스크립트 없이 처리하려고
   :has 를 쓴다. 모르는 브라우저에서는 칸이 그냥 보이기만 하고, 종일로
   저장하면 서버가 시각을 비우므로 값이 어긋나지는 않는다. */

.cal-times { display: flex; align-items: center; gap: 8px; margin-top: 8px; }
.cal-times .input { width: auto; }
.cal-times .tilde { color: var(--slate-400); }
.cal-when:has(input[name="all_day"]:checked) .cal-times { display: none; }

/* ---- 일정 폼의 반복 칸
   '반복 안 함' 이면 간격·종료일을 감춘다. 위 시각 칸과 같은 방식이고,
   :has 를 모르는 브라우저에서 그냥 보이기만 하는 것도 마찬가지다. */

.cal-repeat:has(select[name="repeat_kind"] option[value=""]:checked)
.cal-repeat-opt { display: none; }

/* 반복 일정을 열었을 때 맨 위에 붙는 안내 */
.cal-series {
    margin-bottom: 16px;
    padding: 10px 14px;
    border: 1px solid var(--brand-100);
    border-radius: 6px;
    background: var(--brand-50);
    color: var(--brand-700);
    font-size: 13px;
    line-height: 1.6;
}

/* '이 회차만' 버튼과 되돌리기 버튼. 각각이 따로 제출되는 폼이라
   버튼 하나씩 폼에 담겨 있고, 그것들을 한 줄로 늘어놓는다. */
.cal-series-acts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 10px;
}

.cal-series-note { margin: 0 0 8px; font-size: 12px; color: var(--slate-500); }
.cal-series-acts .cal-series-note { margin: 0; }

/* ---- 참여율 계상률표
   열두 달 + 사람 + 과제라 가로가 길다. 표 자체는 .table-wrap 이 가로로
   밀어 주므로, 여기서는 칸을 좁히고 숫자를 읽기 좋게만 만든다. */

.pr-grid { font-size: 13px; }
.pr-grid th, .pr-grid td { padding: 6px 7px; }
/* 칸 안의 금액. 늘 보이는 값이라 읽을 수 있을 만큼은 진하게 두되,
   참여율보다는 물러나 있어야 한다 — 표에서 먼저 봐야 하는 것은 %다. */
.pr-grid .pr-amt {
    color: var(--slate-500);
    font-size: 12px;
    line-height: 1.35;
    margin-top: 1px;
}

/* 입사 전·퇴사 후. 참여율이 적혀 있어도 금액은 0 이라, 왜 0 인지
   표만 보고 알 수 있어야 한다. */
.pr-grid .pr-off { background: var(--slate-50); color: var(--slate-300); }
.pr-grid .pr-off .pr-amt { color: var(--slate-300); }

/* 금액을 못박아 둔 달 */
.pr-grid .pr-fixed .pr-amt { color: var(--brand-700); font-weight: 600; }

.pr-grid .pr-lock { font-size: 11px; opacity: .8; }

/* ---- 사람과 사람 사이 구분
   한 사람이 여러 사업에 걸쳐 줄이 여럿이라, 선이 없으면 어디까지가 같은
   사람인지 눈으로 좇기 어렵다. 사람이 바뀌는 줄에만 굵게 긋는다. */

.pr-grid tbody tr.pr-person > td {
    border-top: 2px solid var(--slate-400);
}

/* 첫 사람 위에는 머리글 선이 이미 있으므로 겹쳐 긋지 않는다 */
.pr-grid tbody tr.pr-person:first-child > td { border-top: 0; }

/* 이름 칸은 여러 줄에 걸쳐 있다. 옅은 바탕을 깔아 한 덩어리로 읽히게 한다. */
.pr-grid td.pr-name {
    background: var(--slate-50);
    border-right: 1px solid var(--slate-200);
    vertical-align: top;
    padding-top: 9px;
    line-height: 1.5;
}

/* 사람마다의 월 합계 줄. 표에서 가장 먼저 봐야 하는 줄이다. */
.pr-grid .pr-sum td { background: var(--slate-50); font-weight: 600; }
.pr-grid tfoot .pr-foot td { background: var(--brand-50); font-weight: 600; }

/* ---- 사업별 보기의 사업 머리줄
   예산 대비 집행을 여기 얹는다. 사업별로 보는 이유가 '예산을 넘었는가' 라서,
   그 답이 블록 안에 있어야 표를 위아래로 왔다 갔다 하지 않는다. */

.pr-grid .pr-block td {
    padding: 0;
    background: var(--brand-50);
    border-bottom: 1px solid var(--brand-100);
}

.pr-block-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 12px;
    padding: 9px 12px;
    font-size: 13px;
    text-align: left;
    white-space: normal;
}

.pr-block-head > b { font-size: 14px; }
.pr-block-head .pr-budget { font-size: 12px; color: var(--slate-600); }
.pr-block-head .pr-budget b { font-variant-numeric: tabular-nums; }
.pr-block-head .btn { margin-left: auto; }

/* 보기 전환(사람별·사업별). 카드 안에 들어가므로 여백을 카드에 맞춘다. */
.pr-views { margin: 0; padding: 12px 18px 0; }

/* ---- 사업비 집행률 막대
   숫자만으로는 '얼마나 썼나' 가 한눈에 안 들어온다. 넘긴 것은 빨갛게. */

.bg-bar {
    width: 90px;
    height: 7px;
    border-radius: 4px;
    background: var(--slate-200);
    overflow: hidden;
}

.bg-bar i {
    display: block;
    height: 100%;
    border-radius: 4px;
    background: var(--brand-600);
}

.bg-bar i.over { background: var(--red-600); }

/* ---- 과제 수행기간 막대

   날짜 두 개(2026-01-01 ~ 2026-12-31)만 적혀 있으면 '지금 어디쯤인가' 는
   머리로 세어야 한다. 남은 날이 한 달인지 반년인지에 따라 할 일이 다르므로
   지난 만큼을 칠해 보인다. 사업비 집행률과 같은 막대를 써서, 두 화면의
   '얼마나 찼나' 가 같은 모양으로 읽히게 한다. */

.term { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
.term .bg-bar { width: 76px; flex-shrink: 0; }
.term-left { font-size: 12px; color: var(--slate-500); }

/* 한 달 안쪽. 정산·연장 준비를 시작해야 하는 때라 눈에 띄어야 한다. */
.term-left.soon { color: var(--amber-600); font-weight: 600; }
.term-left.done { color: var(--slate-400); }

/* 끝난 과제의 막대는 회색으로 둔다. 파랗게 꽉 찬 막대는 '잘 됐다' 로
   읽히는데, 여기서 100% 는 그냥 기간이 지났다는 뜻이다. */
.bg-bar i.done { background: var(--slate-300); }

/* 100% 초과 · 예산 초과. 정산에서 그대로 걸리는 자리라 눈에 띄어야 한다. */
.pr-over { background: var(--red-50) !important; color: var(--red-600) !important; }

.cal-legend-item i.pr-key { width: 12px; height: 12px; border-radius: 3px; }
.cal-legend-item i.pr-key.green { background: var(--green-200); }
.cal-legend-item i.pr-key.amber { background: var(--amber-200); }
.cal-legend-item i.pr-key.red   { background: var(--red-200); }
.cal-legend-item i.pr-key.gray  { background: var(--slate-200); }

/* ---- 표 안의 묶음 여닫기

   줄이 너무 많아 눈으로 따라가기 어려울 때, 묶음 머리를 눌러 그 묶음만
   접어 둔다. 사업비 사용내역의 '달' 과 과제 사업비 목록의 '사업' 이 쓴다.

   표 안에서는 <details> 를 쓸 수 없어(줄을 감쌀 수 없다) 묶음마다 tbody 를
   따로 두고 class 를 붙였다 뗐다 한다. */

.fold-toggle {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    margin: -4px 0;
    padding: 4px 6px 4px 0;
    border: 0;
    border-radius: 6px;
    background: none;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.fold-toggle:hover { color: var(--brand-600); }
.fold-toggle:hover .fold-caret { color: var(--brand-600); }

.fold-caret {
    display: inline-block;
    width: 12px;
    font-size: 12px;
    color: var(--slate-400);
    /* 회전축을 글자 한가운데로 두어야 접을 때 삼각형이 제자리에서 돈다 */
    transform-origin: 50% 50%;
    transition: transform .15s ease;
}

.fold-group.is-closed .fold-caret { transform: rotate(-90deg); }

/* 머리줄만 남기고 그 묶음의 줄들을 감춘다 */
.fold-group.is-closed tr:not(.fold-head) { display: none; }

/* 묶음마다 tbody 를 나누면서 'table.grid tbody tr:last-child' 의 경계선
   지우기가 묶음마다 걸리게 됐다. 그대로 두면 앞 묶음의 마지막 줄과 다음
   묶음의 머리가 선 없이 붙는다. 표의 진짜 마지막 묶음에서만 지운다. */
.fold-group:not(:last-of-type) tr:last-child td {
    border-bottom: 1px solid var(--slate-100);
}

/* 묶음 머리의 잔액이 마이너스일 때. 칸 전체를 칠하는 .pr-over 와 달리
   숫자만 붉게 한다 — 머리줄은 다른 값도 함께 서 있는 자리다. */
.pr-left-over { color: var(--red-600); }

/* 세부항목. 비목 옆에 한 줄로 붙는다 — 아래로 내려 쓰면 세부항목이 있는
   줄만 두 줄 높이가 되어 표가 들쭉날쭉해진다. */
.ex-sub { font-size: 12px; color: var(--slate-400); }

/* 배정 폼의 열두 달 입력칸 */
.pr-input td { padding: 4px; }
.pr-input .input { width: 100%; min-width: 62px; padding: 6px 4px; font-size: 12px; }

/* ---- 기자재 폼의 수량·단위
   함께 읽어야 뜻이 통하는 두 칸이라 한 줄에 붙여 둔다. 단위는 'EA' 정도라
   좁아도 되고, 수량이 넓어야 눈에 든다. */

.eq-qty { display: flex; gap: 8px; }
.eq-qty .num { flex: 2; }
.eq-qty .input:last-child { flex: 1; min-width: 60px; }

/* 삭제 줄은 폼 바깥이라 위쪽에 선을 하나 그어 구분한다. */
.danger-row {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--slate-200);
}

/* 좁은 화면에서는 요일 폭이 모자라 막대 글씨가 잘린다.
   달력 자체를 가로로 밀어 보게 하고, 최소 폭을 정해 둔다. */
@media (max-width: 720px) {
    .cal { overflow-x: auto; }
    .cal-head, .cal-week { min-width: 640px; }
    .cal-nav { margin-right: 0; }
}

/* ============================================================ 전자결재

   결재선을 순서도로 그린다. 마디(.ap-node)를 화살표로 잇는다.
   카드를 나란히 놓기만 했을 때는 순서가 아니라 목록으로 읽혔다 —
   앞사람이 승인해야 다음으로 넘어간다는 것이 그림에 없었다.

   기본은 가로다. 종이 결재란과 같은 순서라, 화면에서 본 것과 인쇄물이
   서로 다르게 읽히지 않는다. 좁은 칸(작성 화면 옆)에서는 .vertical 로
   방향만 세운다. 마디 모양은 같은 것을 쓴다.

   마디를 그리는 곳은 templates/approval/_flow.html 한 군데다.            */

.ap-flow {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 16px 18px;
}

/* 지난 회차(반려되고 다시 올린 것)는 한 톤 죽여 지금 도는 줄과 구분한다 */
.ap-past { opacity: .62; }

.ap-node {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    min-width: 168px;
    max-width: 280px;
    padding: 10px 12px;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    background: var(--slate-50);
}

/* 이름 첫 글자를 딴 동그라미. 사진 대신이다. */
.ap-ava {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 999px;
    background: var(--slate-200);
    color: var(--slate-600);
    font-size: 14px;
    font-weight: 700;
}

.ap-node-body { min-width: 0; }
.ap-node-name { font-size: 14px; line-height: 1.35; }
.ap-node-name b { font-weight: 700; }
.ap-node-name .muted { margin-left: 3px; font-size: 13px; }
.ap-node-sub { margin-top: 1px; font-size: 12px; }
.ap-node-when { margin-top: 3px; font-size: 12px; }

.ap-node-tag {
    margin-top: 4px;
    color: var(--slate-500);
    font-size: 12px;
    font-weight: 600;
}

.ap-node-state {
    margin-left: 5px;
    padding: 1px 6px;
    border-radius: 999px;
    background: rgba(15, 23, 42, .07);
}

.ap-node-note { margin-top: 3px; color: var(--slate-500); font-size: 12px; }

.ap-node-opinion {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid rgba(15, 23, 42, .08);
    color: var(--slate-600);
    font-size: 13px;
    line-height: 1.6;
    white-space: pre-wrap;
    word-break: break-word;
}

/* 작업 칸은 결재가 아니다. 클립을 달아 도장 자리와 눈으로 갈라 둔다.
   색만으로 가르면 '승인 안 한 결재 칸' 으로 읽힌다. */
.ap-node[data-kind="action"] .ap-node-order::before { content: "📎 "; }

/* ---- 마디 상태별 색. 글자(상태 딱지)와 색을 함께 두어, 색을 못 가리는
        사람에게도 무엇이 끝나고 무엇이 남았는지 보이게 한다. */

.ap-node[data-state="draft"] { background: var(--surface); }

/* 아직 올리지 않은 예정 결재선은 테두리를 점선으로 둔다 */
.ap-node[data-state="plan"],
.ap-node[data-state="blank"] { border-style: dashed; background: var(--surface); }

/* 경로는 정해졌는데 사람을 아직 안 고른 칸. 채워야 할 자리로 보여야 한다. */
.ap-node[data-state="blank"] { border-color: var(--amber-600); }
.ap-node[data-state="blank"] .ap-ava { background: var(--amber-50); color: var(--amber-600); }
.ap-node[data-state="blank"] .ap-node-name b { color: var(--slate-400); }

.ap-node[data-state="current"] {
    border-color: var(--brand-500);
    background: var(--brand-50);
    box-shadow: 0 0 0 3px rgba(49, 130, 246, .1);
}

.ap-node[data-state="current"] .ap-ava { background: var(--brand-600); color: var(--on-brand); }

.ap-node[data-state="approved"],
.ap-node[data-state="done"],
.ap-node[data-state="end"] { border-color: var(--green-200); background: var(--green-50); }

.ap-node[data-state="approved"] .ap-ava,
.ap-node[data-state="done"] .ap-ava,
.ap-node[data-state="end"] .ap-ava { background: var(--green-200); color: var(--green-600); }

.ap-node[data-state="rejected"] { border-color: var(--red-200); background: var(--red-50); }
.ap-node[data-state="rejected"] .ap-ava { background: var(--red-200); color: var(--red-600); }

/* 중단은 반려와 다르다. 붉게 칠하면 '누가 물렸다' 로 읽히는데, 기안자가
   스스로 접은 것이다. 색을 빼고 글자를 그어 끝난 것만 보인다. */
.ap-node[data-state="canceled"] { border-style: dashed; background: var(--slate-100); }
.ap-node[data-state="canceled"] .ap-node-name b { text-decoration: line-through; }

/* ---- 마디를 잇는 화살표.
   글자를 CSS 에 두는 이유: 화살표는 읽어 줄 내용이 아니라 방향 표시라,
   본문에 글자로 남으면 화면 낭독기가 '오른쪽 화살표' 를 매번 읽는다. */

.ap-arrow {
    flex: 0 0 auto;
    color: var(--slate-300);
    font-size: 15px;
    line-height: 1;
}

.ap-arrow::before { content: "→"; }

/* ---- 세로로 세운 순서도 (작성 화면 옆칸) */

.ap-flow.vertical {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    padding: 0;
}

.ap-flow.vertical .ap-node { max-width: none; }
.ap-flow.vertical .ap-arrow { margin-left: 25px; }   /* 동그라미 가운데에 맞춘다 */
.ap-flow.vertical .ap-arrow::before { content: "↓"; }

/* ---- 불러오는 항목 (거래처 · 담당자 · 과제)
   위에서 고르고 아래 글자 칸에 들어간다. 글자 칸을 감추지 않는 이유는,
   목록에 없는 업체를 직접 적을 수 있어야 하고 무엇이 저장되는지 눈에
   보여야 하기 때문이다. */

.ap-lookup { display: grid; gap: 4px; }

/* 묻지 않는 칸(보존 연한). 입력칸처럼 보이면 고칠 수 있는 줄 알게 된다. */
.ap-fixed {
    padding: 9px 0;
    color: var(--slate-600);
    font-size: 14px;
    font-weight: 600;
}

/* 계산되는 칸(부가세 · 합계). 눌러도 고칠 수 없다는 것이 보여야 한다. */
input[data-computed] {
    background: var(--slate-50);
    color: var(--slate-700);
    font-weight: 600;
    text-align: right;
    cursor: default;
}

/* ---- 요약 값(품의서의 과제명).
   목록에서는 건명 밑에 한 줄로, 상세에서는 제목 밑에 붙는다.
   서류를 열지 않아도 어느 과제의 건인지 보이게 하려고 끌어올린 값이다. */

.ap-summary {
    display: block;
    margin-top: 2px;
    color: var(--slate-500);
    font-size: 12px;
}

.ap-summary b { color: var(--slate-600); font-weight: 600; }

/* ---- 작성 화면의 결재선 칸.
   왼쪽에서 고르고 오른쪽에서 확인한다. 좁아지면 순서도가 아래로 내려간다. */

.ap-line-editor {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 260px);
    gap: 20px;
    align-items: start;
}

.ap-line-picks { display: grid; gap: 10px; }
.ap-line-picks .field { margin: 0; }

.ap-line-view {
    padding: 12px 14px;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    background: var(--slate-50);
}

.ap-line-view-head {
    margin-bottom: 10px;
    color: var(--slate-500);
    font-size: 12px;
    font-weight: 700;
}

.ap-line-view .ap-node { background: var(--surface); }
.ap-line-view .hint { display: block; margin-top: 10px; }

@media (max-width: 860px) {
    .ap-line-editor { grid-template-columns: minmax(0, 1fr); }
}

/* 양식이 정한 항목의 값. 이름 칸을 왼쪽에 고정해 나란히 읽히게 한다. */
.ap-values {
    margin-bottom: 16px;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    overflow: hidden;
}

.ap-values .row { display: flex; border-bottom: 1px solid var(--slate-100); }
.ap-values .row:last-child { border-bottom: 0; }

.ap-values .k {
    flex: 0 0 150px;
    padding: 9px 12px;
    background: var(--slate-50);
    color: var(--slate-600);
    font-size: 14px;
    font-weight: 600;
}

.ap-values .v { flex: 1; min-width: 0; padding: 9px 12px; font-size: 14px; }
.ap-values .v.pre { white-space: pre-wrap; word-break: break-word; }

/* ---- 서류 고르기 */

.ap-pick {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 12px;
}

.ap-pick-card {
    display: block;
    padding: 16px 18px;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-sm);
    color: inherit;
    text-decoration: none;
}

.ap-pick-card:hover {
    border-color: var(--brand-500);
    box-shadow: var(--shadow);
    text-decoration: none;
}

.ap-pick-card .nm { font-size: 16px; font-weight: 700; }
.ap-pick-card .pfx { margin-top: 2px; font-size: 12px; }
.ap-pick-card .desc { margin-top: 8px; color: var(--slate-500); font-size: 13px; line-height: 1.6; }

/* ---- 양식 편집의 항목 표
   입력칸이 들어가는 표라 칸 사이를 좁히고 세로 가운데를 맞춘다. */

.ap-field-table td { padding: 6px; vertical-align: middle; }
.ap-field-table .input, .ap-field-table .select { width: 100%; }
.ap-field-table textarea.input { min-height: 0; resize: vertical; }
.ap-field-table .grip { color: var(--slate-300); text-align: center; cursor: default; }

/* 첨부 목록. 작성 화면과 상세 화면이 같은 모양을 쓴다. */
.ap-files {
    margin: 0 0 12px;
    padding: 0;
    list-style: none;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    overflow: hidden;
}

.ap-files li {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--slate-100);
    background: var(--slate-50);
    font-size: 14px;
}

.ap-files li:last-child { border-bottom: 0; }
.ap-files .nm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ap-files .sz { flex: 0 0 auto; font-size: 12px; font-variant-numeric: tabular-nums; }

/* 품의 본문. 기안자가 친 줄바꿈을 그대로 살린다. */
.ap-content {
    padding: 16px 18px;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius);
    background: var(--slate-50);
    font-size: 15px;
    line-height: 1.9;
    white-space: pre-wrap;
    word-break: break-word;
}

/* ============================================================ 공지사항

   대시보드 알림창과 공지사항 화면이 같은 목록을 쓴다
   (templates/notices/_list.html).

   표(table.grid)로 하지 않았다. 공지는 칸으로 나뉜 값이 아니라 한 줄로
   읽는 글이라, 표에 넣으면 제목 길이에 따라 줄 높이가 들쭉날쭉해진다.   */

.nt-list { margin: 0; padding: 0; list-style: none; }

.nt-item {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 11px 18px;
    border-bottom: 1px solid var(--slate-100);
    font-size: 14px;
}

.nt-item:last-child { border-bottom: 0; }

/* 중요 공지는 맨 위에 있지만 그것만으로는 눈에 띄지 않는다 —
   목록의 첫 줄은 그냥 첫 줄로 읽힌다. 딱지와 함께 바탕도 물들인다. */
.nt-item.pinned { background: var(--red-50); }

/* 팝업으로 방금 올린 공지를 잠깐 밝힌다. 강조 규칙(row-added)이 표에만 걸려
   있어서 목록 줄에는 따로 붙여 준다. 애니메이션이 끝나면 중요 공지의 바탕색이
   그대로 돌아온다. */
.nt-item.row-added { animation: row-added 2.4s ease-out; }

/* 제목은 링크지만 파랗게 두지 않는다. 목록 전체가 링크라 파란 줄만
   늘어서면 무엇을 눌러야 할지가 오히려 안 보인다. */
.nt-title {
    flex: 1;
    min-width: 0;
    color: var(--slate-900);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.nt-title:hover { color: var(--brand-700); }

/* 아직 안 읽은 공지. 사이드바 배지와 같은 색을 써서 '저 숫자가 이것들' 인
   것이 이어져 보이게 한다. 색만으로 가르지 않도록 글자를 함께 둔다. */
.nt-new {
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 10px;
    background: var(--amber-600);
    color: var(--on-brand);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0;
}

.nt-meta {
    flex: 0 0 auto;
    color: var(--slate-500);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
}

/* 카드 머리에 단추가 둘 이상일 때 벌려 놓는다 */
.head-acts { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---- 공지 한 건. 팝업과 전체 화면이 같은 조각을 쓴다. */

.nt-detail-title {
    margin: 0 0 4px;
    font-size: 18px;
    font-weight: 700;
    letter-spacing: -.3px;
}

.nt-detail-meta {
    margin-bottom: 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--slate-200);
    color: var(--slate-500);
    font-size: 13px;
}

/* 본문은 적은 그대로 보여준다. 품의 본문(.ap-content)과 같은 크기·줄간격이라
   두 화면의 '사람이 적은 글' 이 같게 읽힌다. 여기는 카드 안이라 테두리는 뺀다. */
.nt-body {
    font-size: 15px;
    line-height: 1.9;
    white-space: pre-wrap;
    word-break: break-word;
}

/* 좁은 화면에서는 제목과 게시일이 한 줄에 들어가지 않는다. 두 줄로 세운다. */
@media (max-width: 560px) {
    .nt-item { flex-direction: column; align-items: flex-start; gap: 2px; }
    .nt-title { white-space: normal; }
}


/* ============================================================ 주간업무회의

   회의실에 띄워 놓고 위에서부터 내려가며 발표하는 화면이다. 그래서 접거나
   펴는 장치를 두지 않았고, 사람 사이의 경계(.wk-who)를 카드보다 진하게
   그었다 — 멀리서 봐도 '다음 사람' 이 어디서 시작하는지 보여야 한다.     */

/* 주차 넘기기. 가운데에 날짜를 둔다 — '몇 주차' 만으로는 언제인지
   안 떠오른다. */
.wk-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 14px;
}
.wk-when { display: flex; align-items: baseline; gap: 10px; font-size: 15px; }
.wk-now { font-size: 13px; }

/* 회의 정보. 사람 칸보다 한 단 낮게 보이도록 여백을 줄인다 */
.wk-meet .card-body { padding: 12px 16px; }
.wk-meet-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}
.wk-meet-facts { display: flex; gap: 20px; flex-wrap: wrap; font-size: 14px; }
.wk-meet-facts .muted { margin-right: 6px; font-size: 13px; }

.wk-agenda { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--slate-200); }
.wk-agenda .muted { font-size: 13px; }
.wk-agenda .pre,
.wk-note .pre {
    margin-top: 4px;
    font-size: 14px;
    line-height: 1.8;
    white-space: pre-wrap;
    word-break: break-word;
}

/* 사람 한 칸 */
.wk-report { margin-bottom: 14px; }
.wk-who {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--slate-200);
    background: var(--slate-50);
    border-radius: 10px 10px 0 0;
    font-size: 15px;
}

/* 적은 글 한 칸. 자유 양식이라 적은 그대로(줄바꿈까지) 보인다.
   제목을 글보다 작고 옅게 두어, 멀리서 볼 때 제목이 아니라 내용이
   먼저 읽히게 한다. */
.wk-box + .wk-box {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px dashed var(--slate-200);
}
.wk-box-label {
    margin-bottom: 4px;
    color: var(--slate-500);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: -.2px;
}
.wk-box-text {
    font-size: 15px;
    line-height: 1.85;
    white-space: pre-wrap;
    word-break: break-word;
}

/* 적는 화면의 글칸. 여러 줄을 이어 적는 자리라 줄 간격을 벌린다 */
.wk-area { line-height: 1.8; resize: vertical; }

/* 지난 주 계획을 옮겨다 놓았다는 안내. 옮겨 온 화면에서만 뜬다 */
.wk-carried {
    margin-bottom: 14px;
    padding: 9px 12px;
    border-left: 3px solid var(--brand-600);
    background: var(--slate-50);
    border-radius: 0 6px 6px 0;
}

/* 적는 화면의 발표자 줄 */
.wk-writer {
    display: flex;
    gap: 20px;
    flex-wrap: wrap;
    margin-bottom: 16px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--slate-200);
    font-size: 14px;
}
.wk-writer .muted { margin-right: 6px; font-size: 13px; }

/* 아직 안 쓴 사람 */
.wk-missing { margin-top: 4px; }
.wk-missing b { font-size: 14px; }
.wk-names { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.wk-name {
    padding: 3px 10px;
    border: 1px solid var(--slate-200);
    border-radius: 999px;
    background: var(--surface);
    font-size: 13px;
}

/* ---- 분리수거 당번 (돌림판)

   회의실에서 다 같이 보는 자리라 이름을 크게 둔다. 멀리서 읽혀야 한다. */

.wk-duty .card-body,
.wk-duty-now .card-body { padding: 12px 16px; }
.wk-duty { margin-bottom: 14px; }
.wk-duty-now { margin-bottom: 16px; }

.wk-duty-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
}
.wk-duty-row .muted { font-size: 13px; }
.wk-duty-name {
    margin: 2px 0;
    font-size: 24px;
    font-weight: 800;
    letter-spacing: -.5px;
}
.wk-duty-none { margin: 2px 0; color: var(--slate-500); font-size: 16px; }

/* 판과 고르는 칸을 나란히. 좁아지면 판이 위로 간다 */
.wk-wheel-wrap {
    display: grid;
    grid-template-columns: minmax(320px, 1.1fr) minmax(260px, .9fr);
    gap: 16px;
    align-items: start;
    margin-bottom: 16px;
}
.wk-wheel-card .card-body { text-align: center; }

/* 판은 칸 너비를 따라간다. 캔버스는 자바스크립트가 배율까지 맞춰 다시 그린다.
   판 자체를 눌러도 돌아가므로 손 모양 커서를 준다 — 화면에 판이 크게 있으면
   사람은 단추보다 판을 먼저 누른다. */
.wk-wheel-stage { max-width: 420px; margin: 0 auto; }
#wheel { width: 100%; height: auto; display: block; cursor: pointer; }

/* 회의실에서 누르는 단추라 크게 둔다 */
.wk-wheel-acts { margin-top: 14px; }
.wk-spin { padding: 11px 30px; font-size: 16px; min-width: 160px; }

/* 멈춘 뒤에 뜨는 결과. 확정을 누르기 전에는 저장되지 않는다 */
.wk-winner {
    margin-top: 16px;
    padding: 14px;
    border: 1px solid var(--slate-200);
    border-radius: 10px;
    background: var(--slate-50);
}
.wk-winner .muted { font-size: 12px; }
.wk-winner-name {
    margin: 4px 0 12px;
    font-size: 30px;
    font-weight: 800;
    letter-spacing: -.6px;
}

/* 뽑힌 사람 목록. 두 명을 뽑으므로 차례가 보여야 한다 */
.wk-winner-list {
    margin: 8px 0 14px;
    padding: 0;
    list-style: none;
    counter-reset: wk-win;
}
.wk-winner-list li {
    counter-increment: wk-win;
    font-size: 26px;
    font-weight: 800;
    letter-spacing: -.5px;
    line-height: 1.35;
}
.wk-winner-list li::before {
    content: counter(wk-win) ". ";
    color: var(--slate-500);
    font-size: 15px;
    font-weight: 600;
}
.wk-winner .btn + .btn { margin-left: 8px; }

/* 판이 멈추는 순간 결과가 한 번 튀어 나온다. 그냥 나타나면 멈춘 줄 모르고
   넘어가는 사람이 있다. */
@keyframes wk-pop {
    0%   { transform: scale(.9); opacity: 0; }
    60%  { transform: scale(1.03); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
}
.wk-winner.is-in { animation: wk-pop .32s ease-out; }
@media (prefers-reduced-motion: reduce) {
    .wk-winner.is-in { animation: none; }
}

.wk-fresh { display: block; margin-bottom: 4px; }
.wk-people { margin-top: 12px; display: flex; flex-direction: column; gap: 2px; }
.wk-people.is-locked { opacity: .5; pointer-events: none; }

.wk-person {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
}
.wk-person:hover { background: var(--slate-50); }
.wk-person .nm { font-weight: 600; }
.wk-person .muted { font-size: 12px; }
/* 걸린 횟수는 오른쪽 끝에 붙여 세로로 줄이 맞게 한다 */
.wk-person .badge { margin-left: auto; }

/* 인쇄. 발표 자료로 그대로 뽑는 일이 있다 — 사람 칸이 페이지 사이에서
   갈라지지 않게 붙잡고, 넘기기 단추는 종이에 남길 이유가 없다. */
@media print {
    .wk-nav, .wk-missing { display: none !important; }
    .wk-report { break-inside: avoid; page-break-inside: avoid; }
    .wk-who { background: none; border-bottom: 1px solid #999; }
    .wk-duty .btn { display: none !important; }
}

@media (max-width: 900px) {
    .wk-wheel-wrap { grid-template-columns: 1fr; }
}

@media (max-width: 720px) {
    .wk-nav { flex-wrap: wrap; }
    .wk-when { order: -1; width: 100%; justify-content: center; }
}

/* ============================================================ 개선요청

   처리 단추 둘(반영완료·반려)을 나란히 두되, 반려가 실수로 눌리지 않게
   조금 떼어 놓는다. 되돌리기는 결과 칸 아래에 조용히 붙인다. */

.imp-decide { display: flex; gap: 10px; }
.imp-decide .btn-danger { margin-left: 6px; }
.imp-reopen { margin-top: 12px; text-align: right; }

/* ============================================================ 휴대폰 앱 안내

   사이드바 「📱 휴대폰 앱」 화면(templates/app_guide.html). PC 에서 보는
   화면이라 두 칸으로 벌려 놓고, 좁아지면 한 줄로 세운다. */

.ag-share { display: flex; gap: 24px; align-items: flex-start; }
.ag-share-body { flex: 1; min-width: 0; }
.ag-share p { margin: 0 0 10px; }

.ag-qr { flex: 0 0 auto; text-align: center; }

.ag-qr img {
    display: block;
    width: 180px; height: 180px;
    padding: 8px;
    border: 1px solid var(--slate-200);
    border-radius: 10px;
    /* 다크 테마에서도 흰 바탕이어야 카메라가 읽는다 */
    background: #fff;
}

.ag-qr .hint { margin-top: 8px; font-size: 12px; }

.ag-url {
    padding: 9px 12px;
    border: 1px solid var(--slate-200);
    border-radius: 6px;
    background: var(--slate-50);
    font-size: 14px;
    word-break: break-all;
}

.ag-notice {
    width: 100%;
    margin-top: 10px;
    font-family: inherit;
    font-size: 13px;
    line-height: 1.6;
    resize: vertical;
}

.ag-acts { display: flex; align-items: center; gap: 12px; margin-top: 10px; }

/* 배포 주소 못박기 (최고관리자만) */
.ag-urlset { margin: 0 0 12px; font-size: 13px; }
.ag-urlset summary { color: var(--brand-700); cursor: pointer; font-weight: 600; }
.ag-urlset .hint { margin: 8px 0 0; }
.ag-urlform { display: flex; gap: 8px; margin-top: 8px; }
.ag-urlform .input { flex: 1; min-width: 0; }

/* 기종별 안내 두 칸 */
.ag-two {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 24px;
}

.ag-two h5 { margin: 0 0 8px; font-size: 15px; font-weight: 700; }
.ag-two ol { margin: 0; padding-left: 20px; }
.ag-two li { margin-bottom: 8px; }

/* 잘못 깔면 알림이 없는 앱이 생긴다. 그 경고는 눈에 띄어야 한다. */
.ag-warn {
    margin: 0 0 10px;
    padding: 9px 12px;
    border-radius: 6px;
    background: var(--amber-50);
    color: var(--amber-600);
    font-size: 13px;
    line-height: 1.6;
}

.ag-list { margin: 0; padding-left: 20px; }
.ag-list li { margin-bottom: 8px; }

.ag-mine {
    margin: 14px 0 0;
    padding: 11px 14px;
    border-radius: 8px;
    background: var(--slate-50);
    font-size: 14px;
}

.ag-note { padding: 14px 18px 0; }

@media (max-width: 860px) {
    .ag-share { flex-direction: column; }
    .ag-qr { align-self: center; }
    .ag-two { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================ 휴대폰 화면

   ERP 를 휴대폰으로 여는 경우(홈 화면 아이콘 포함)를 위한 손질이다.
   먼저 쓰겠다고 한 두 갈래 —— 캘린더 확인과 결재 승인 —— 을 손봤다.

   화면 폭 640px 을 경계로 잡는다. 900px(사이드바가 서랍이 되는 지점)은
   태블릿 가로도 걸리는 폭이라 단추까지 키우면 데스크톱에서 어색해진다.

   달력 격자 자체는 여기서 손대지 않는다. 칸을 아무리 줄여도 휴대폰에서
   일곱 칸에 일정 이름이 들어가지 않는다. 대신 「목록」 탭을 만들어 두었다
   (`/calendar/list`). */

/* 좁은 화면에서만 나오는 것 / 좁은 화면에서만 감추는 것 */
.only-phone { display: none; }

@media (max-width: 640px) {
    .only-phone { display: flex; }

    /* 탭이 화면보다 넓으면 잘려서 뒤쪽 탭은 아예 누를 수 없다
       (전자결재는 탭이 넷이다). 가로로 밀어 볼 수 있게 둔다. */
    .tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .tabs::-webkit-scrollbar { display: none; }
    .tabs .tab { flex: 0 0 auto; white-space: nowrap; }
    .tabs .tab-note { display: none; }          /* 옆에 설 자리가 없다 */

    /* 손가락으로 누를 크기로. 기본값은 마우스 기준이라 작다. */
    .btn { padding: 11px 15px; }
    .btn-sm { padding: 8px 12px; }

    /* 머리말 단추가 제목 아래로 내려온다. 한 줄에 다 못 서면 가로를 나눠
       채워, 좁은 단추를 겨누다 옆것을 누르는 일을 줄인다. */
    .page-actions { width: 100%; }
    .page-actions .btn { flex: 1 1 auto; }

    /* 검색줄도 한 줄에 못 선다. 칸이 화면 폭을 쓰게 둔다. */
    .searchbar .input,
    .searchbar .select { width: 100%; }
    .searchbar .grow { min-width: 0; }

    /* 표에서 접어 두는 칸. 무엇을 접을지는 화면마다 다르므로 이름표만
       여기 두고, 어느 칸에 붙일지는 그 화면의 템플릿이 정한다. */
    .col-sm-hide { display: none; }

    /* 결재 항목 값: 이름 칸 150px 고정을 풀고 위아래로 세운다 */
    .ap-values .row { flex-direction: column; }
    .ap-values .k { flex: none; padding-bottom: 2px; }
    .ap-values .v { padding-top: 2px; }
}

/* 서류를 다 읽은 자리에 다시 두는 승인·반려 단추(전자결재 상세).
   휴대폰에서는 머리말 단추가 화면 위로 사라져, 결재하려면 다시 올려야 한다. */
.ap-foot-actions { gap: 8px; margin-top: 16px; }
.ap-foot-actions .btn { flex: 1; padding: 13px 15px; font-size: 15px; }

/* ==========================================================================
   근태 (GPS 출퇴근)

   오늘 카드와 출퇴근 단추는 PC 화면과 휴대폰 화면이 같은 조각을 쓴다
   (attendance/_punch.html). 그래서 생김새도 여기 한 벌만 둔다 —— 폭으로
   갈라 두지 않고, 좁으면 저절로 한 줄씩 내려가게 짠다.
   ========================================================================== */

.att-punch {
    margin-bottom: 16px;
    padding: 16px;
    border: 1px solid var(--slate-200);
    border-radius: 12px;
    background: var(--surface);
}

/* ---- 오늘 날짜 줄 */

.att-day {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 14px;
}

.att-day .d { font-size: 17px; font-weight: 700; letter-spacing: -.3px; }
.att-day .wd { color: var(--slate-500); font-size: 14px; }
.att-day .muted { font-size: 13px; }

/* 주말 색은 달력과 같은 규칙 (요일 번호: 월 0 … 토 5, 일 6) */
.att-day .wd[data-wd="5"] { color: var(--brand-700); }
.att-day .wd[data-wd="6"] { color: var(--red-600); }

/* ---- 출근 · 퇴근 · 근무시간 세 칸 */

.att-times {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.att-times > div {
    flex: 1 1 140px;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    padding: 10px 12px;
    border-radius: 10px;
    background: var(--slate-50);
}

.att-times .k {
    flex: 0 0 auto;
    color: var(--slate-500);
    font-size: 12px;
    font-weight: 600;
}
.att-times .v { font-size: 18px; font-weight: 700; letter-spacing: -.5px; }

/* ---- 알려 주는 말 (어제 열린 줄 · 근무지 미등록 · 오늘의 갈래) */

.att-note {
    margin: 12px 0 0;
    padding: 10px 12px;
    border-radius: 10px;
    background: var(--slate-50);
    color: var(--slate-600);
    font-size: 13px;
    line-height: 1.6;
}

.att-note.warn {
    background: var(--amber-50);
    color: var(--amber-600);
}
.att-note.warn a { color: inherit; font-weight: 700; }

/* ---- 단추 두 개. 손가락이 닿는 크기로 크게 잡는다. */

.att-acts {
    display: flex;
    gap: 8px;
    margin-top: 14px;
}

.att-acts .btn {
    flex: 1;
    padding: 15px 12px;
    font-size: 16px;
    font-weight: 700;
}

/* ---- 찍은 결과 · 왜 안 되는지 */

.att-msg {
    margin: 12px 0 0;
    padding: 11px 13px;
    border-radius: 10px;
    background: var(--slate-50);
    color: var(--slate-600);
    font-size: 14px;
    line-height: 1.6;
}

.att-msg.ok   { background: var(--green-50); color: var(--green-600); }
.att-msg.warn { background: var(--amber-50); color: var(--amber-600); }
.att-msg.err  { background: var(--red-50);   color: var(--red-600); }

/* ---- 사유 칸. 반경 밖일 때만 열린다(attendance.js 가 hidden 을 푼다). */

.att-reason {
    margin-top: 12px;
    padding: 13px;
    border: 1px solid var(--amber-200);
    border-radius: 10px;
    background: var(--amber-50);
}

.att-reason label {
    display: block;
    margin-bottom: 7px;
    font-size: 13px;
    font-weight: 700;
    color: var(--slate-700);
}

.att-reason-acts { display: flex; gap: 8px; margin-top: 10px; }
.att-reason-acts .btn { flex: 1; }

/* ==================================================== 근무지 · 근무 규칙 */

/* 위도·경도·현재 위치로 채우기. 좁으면 단추가 아래로 내려간다. */
.att-coords {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.att-coords .input { flex: 1 1 160px; min-width: 0; }
.att-coords .btn { flex: 0 0 auto; }

/* 근무 요일 일곱 개 */
.att-days {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
    padding: 4px 0;
}

/* ==================================================== 목록 · 집계 화면 */

.att-month { padding: 0 6px; font-size: 15px; font-weight: 700; }

.att-daytitle {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 14px;
    font-size: 15px;
}

/* 목록 표 안의 요일. 달력과 같은 색 규칙이다. */
.grid .muted[data-wd="5"] { color: var(--brand-700); }
.grid .muted[data-wd="6"] { color: var(--red-600); }

/* ---- 고치기 폼 위에 붙는, 지금 찍혀 있는 값 */

.att-edit-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
    font-size: 16px;
}

.att-edit-was {
    margin-bottom: 16px;
    padding: 12px 14px;
    border-radius: 10px;
    background: var(--slate-50);
    font-size: 13px;
    line-height: 1.9;
}

.att-edit-was .k {
    display: inline-block;
    min-width: 62px;
    color: var(--slate-500);
    font-weight: 600;
}

/* ---- 휴대폰의 최근 기록 줄 */

.att-mlist li { padding: 12px 14px; }

.att-mlist .row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 7px;
}

.att-mlist .d { font-size: 15px; font-weight: 700; }
.att-mlist .wd { color: var(--slate-500); font-size: 13px; }
.att-mlist .wd[data-wd="5"] { color: var(--brand-700); }
.att-mlist .wd[data-wd="6"] { color: var(--red-600); }
.att-mlist .meta { margin-top: 5px; color: var(--slate-500); font-size: 13px; }

/* 주소 검색이나 '현재 위치로 채우기' 가 방금 채운 칸을 잠깐 밝힌다.
   값이 조용히 바뀌면 바뀐 줄 모른다.

   표의 row-added 를 그대로 못 쓴다. 그 규칙은 `table.grid tbody tr` 에만
   걸려 있고, 끝 색도 transparent 라 입력칸에 쓰면 칸 바탕이 사라진다. */
@keyframes att-filled {
    0%   { background: var(--highlight); }
    100% { background: var(--surface); }
}

.att-coords .input.att-filled { animation: att-filled 2.4s ease-out; }

/* ---- 근무 규칙: 고정 / 탄력 고르기 */

.att-types {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 24px;
    margin-bottom: 10px;
}

/* 지금 고르지 않은 유형의 칸. **감추지 않고 흐리게만** 둔다 —— 유형을 바꿀 때
   반대쪽에 무엇이 적혀 있었는지 보여야 하고, 자바스크립트가 없어도 두 칸을
   모두 쓸 수 있어야 한다. 그래서 pointer-events 도 살려 둔다. */
.att-block.off {
    opacity: .5;
}

.att-block.off .card-head h4::after {
    content: " (지금 쓰지 않음)";
    color: var(--slate-400);
    font-weight: 500;
    font-size: 13px;
}

/* 탄력근무 구간표. 폼 한가운데 들어가는 표라 위아래로 조금 띄운다. */
.att-bands { margin: 16px 0 8px; }
.att-bands table { font-size: 13px; }

/* ---- 오늘 카드에 뜨는 '오늘은 몇 시까지' */

.att-until {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 10px;
    padding: 10px 12px;
    border-radius: 10px;
    background: var(--brand-50);
    color: var(--brand-700);
    font-size: 13px;
}

.att-until b { font-size: 16px; letter-spacing: -.3px; }
