﻿/* ============================================================
   HorizonOps — "승인 도면(The Approved Drawing)"
   운영 화면은 검토와 승인이 찍히는 한 장의 기술 도면이다.
   문법: 흰 시트 위 잉크 선굵기 위계(heavy 2px / medium 1.5px / light 1px / hair 1px),
         주서(朱書) 액센트로만 활성·위험 표시, 사각 검인 스탬프, 부품표(BOM) 표, 표제란 헤더.
   외부 의존성 없음(폰트·CSS·JS 전부 로컬/시스템), 라이트 고정.
   접근성 규칙: 상태는 색 단독으로 전달하지 않고 항상 텍스트 라벨을 동반한다.
   ============================================================ */

/* Pretendard Variable — 저장소 동봉 셀프호스팅(런타임 외부 요청 없음).
   @font-face 두 벌(상용 한글 / 나머지 한글)은 생성물이므로 fonts/pretendard.css 에 따로 둔다.
   그 파일이 이 파일보다 먼저 실린다. SIL Open Font License 1.1, 전문: fonts/OFL-Pretendard.txt */

:root {
    /* --- 지면 --- */
    --paper: #ffffff; /* 시트·카드·표 표면 */
    --paper-2: #f5f7f9; /* 표제 칸·코드 블록 등 옅은 채움 */
    --desk: #e9edf1; /* 페이지 바탕 — 시트가 뚜렷이 떠 보이도록 */
    --row-hover: #f2f6fa;

    /* --- 잉크 --- */
    --ink: #1a1f26; /* 본문·굵은 선 */
    --ink-2: #465060; /* 보조 */
    --ink-3: #66717f; /* 흐림 — 흰 바탕 대비 4.9:1 (AA) */
    --ink-pressed: #0d1116; /* 일반 버튼 :active — 잉크보다 한 단 더 눌린 검정 */

    /* --- 선 위계 (이 디자인의 중심) --- */
    --line-heavy: #1a1f26; /* 2px  — 시트 프레임, 헤더 밴드 하단, 모달 프레임 */
    --line-medium: #3a434f; /* 1.5px — 표 외곽, 버튼, 입력, 카드 */
    --line-light: #c2c9d2; /* 1px   — 표 행 구분 */
    --line-hair: #dde2e8; /* 1px   — 표 세로 칸 구분, 시트 내부 이중 보더 */

    /* --- 주서(朱書): 활성·진행·위험 확정에만 쓴다 --- */
    --accent: #c33d1f;
    --accent-pressed: #9c3018; /* 위험 버튼 :active — 주서가 눌린 상태 */
    --accent-soft: #fbeeea;
    --link: #245ea8; /* 도면 파랑 */
    /* 주서 후광 단독으로는 흰 바탕 대비 1.55:1 — 실선 1px 코어(5.2:1)를 안쪽에 겹쳐 3:1 이상을 확보한다. */
    --focus-ring: 0 0 0 1px var(--accent), 0 0 0 4px color-mix(in srgb, var(--accent) 30%, transparent);
    /* 그림자 한 면 규칙: 막 위에 뜬 중앙 다이얼로그(작업 지시서·재연결 알림)만 이 두 값을 쓴다. */
    --veil: color-mix(in srgb, var(--ink) 50%, transparent);
    --shadow-dialog: 0 12px 40px color-mix(in srgb, var(--ink) 25%, transparent);

    /* --- 상태 스탬프: soft 배경 + 진한 잉크 (흰 표면 대비 확보) --- */
    --status-good-bg: #e4f4e4;
    --status-good-ink: #0b7a0b;
    --status-warning-bg: #fdf1d6;
    --status-warning-ink: #8a5f00;
    --status-serious-bg: #fdeae1;
    --status-serious-ink: #ad4a24;
    --status-critical-bg: #fae2e2;
    --status-critical-ink: #a32424;
    --status-info-bg: #e8f0fb;
    --status-info-ink: #1f5fbf;
    --status-neutral-bg: #edeff2;
    --status-neutral-ink: #57616e;

    /* --- 서체 --- */
    /* 두 목소리. 찍힌 글자(라벨·숫자·표 머리글·브랜드)는 Bahnschrift = Windows 내장 DIN,
       읽는 글자(본문)는 Pretendard. Bahnschrift에 한글이 없으므로 라벨의 한글은
       바로 다음 순위인 Pretendard가 받는다 — 라틴·숫자는 도면 레터링, 한글은 Pretendard. */
    --font-label: Bahnschrift, "Pretendard Variable", "Segoe UI", "Malgun Gothic", system-ui, sans-serif;
    --font-body: "Pretendard Variable", "Segoe UI", "Malgun Gothic", system-ui, -apple-system, sans-serif;
    --font-mono: "Cascadia Mono", Consolas, monospace;
}

* {
    box-sizing: border-box;
}

html {
    color-scheme: light;
}

body {
    margin: 0;
    background: var(--desk);
    color: var(--ink);
    font-family: var(--font-body);
    /* 0.9375rem = 브라우저 기본 16px 기준 15px. rem이라 사용자가 글자 크기를 키우면 함께 커진다. */
    font-size: 0.9375rem;
    line-height: 1.55;
    /* 도면 한 장이 화면을 채운다: 밴드(높이 가변) + 시트가 세로 flex로 쌓이고 시트가 남는 높이를 먹는다 */
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    /* 기입 커서도 주서다 — 어디에 쓰고 있는지가 이 시스템의 액센트 색으로 보인다 */
    caret-color: var(--accent);
    /* 한국어는 어절로 읽힌다 — 기본값은 '자동 갱신'을 '자' / '동 갱신'으로 끊는다.
       끊지 않되, 한 줄에 도저히 들어가지 않는 낱말(긴 설정 키·경로)은 그때만 쪼갠다. */
    word-break: keep-all;
    overflow-wrap: break-word;
}

/* 브라우저가 그리는 면도 이 도면의 일부다: 선택은 주서 위의 형광펜, 잉크는 그대로 남긴다 */
::selection {
    background: var(--accent-soft);
    color: var(--ink);
}

/* 스크롤바 = 제도판 위 자(尺): 데스크 색 트랙에 잉크 썸, 둥근 모서리 없음 */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--ink-3) var(--desk);
}

::-webkit-scrollbar {
    width: 12px;
    height: 12px;
}

::-webkit-scrollbar-track {
    background: var(--desk);
}

::-webkit-scrollbar-thumb {
    background: var(--ink-3);
    border: 3px solid var(--desk);
    border-radius: 0;
}

    ::-webkit-scrollbar-thumb:hover {
        background: var(--ink-2);
    }

::-webkit-scrollbar-corner {
    background: var(--desk);
}

h1 {
    font-family: var(--font-label);
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    margin: 0 0 0.5rem;
}

    /* Blazor가 내비게이션마다 h1으로 포커스를 옮긴다 — 마우스 사용자에겐 링을 숨기되
       키보드 사용자(focus-visible)에겐 현재 위치를 보여준다 (접근성). */
    h1:focus:not(:focus-visible) {
        outline: none;
    }

    /* 제목은 블록이라 링을 두르면 경고 상자처럼 읽힌다 — 후광 대신 또렷한 윤곽선,
       색은 잉크로 둔다(주서는 활성·위험의 뜻을 이미 지고 있다). */
    h1:focus-visible {
        outline: 2px solid var(--ink);
        outline-offset: 4px;
    }

h2 {
    font-family: var(--font-label);
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: var(--ink);
    /* 제목 위 여백 > 아래 여백 */
    margin: 2rem 0 0.7rem;
    padding-bottom: 0.3rem;
    border-bottom: 1px solid var(--line-light);
}

/* 표제줄: 제목 + 그 블록의 행동이 한 줄에 앉고 밑줄이 그어진다.
   h2와 같은 리듬(위 여백 > 아래 여백)을 쓰고, h2 자신의 여백·밑줄은 거둔다(선이 두 번 그어지지 않게).
   페이지마다 복제돼 값이 어긋나던 규칙이라 시스템으로 올렸다 — .pool-head는 풀 전용 변주다. */
.card-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    margin: 2rem 0 0.7rem;
    padding-bottom: 0.3rem;
    border-bottom: 1px solid var(--line-light);
}

    .card-head h2 {
        display: flex;
        align-items: center;
        margin: 0;
        padding: 0;
        border: 0;
    }

/* 카드의 첫 줄이 표제줄이면 위 여백은 카드 패딩이 이미 준다 */
.card > .card-head:first-child {
    margin-top: 0;
}

.card-head-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
}

a {
    color: var(--link);
    /* 색만으로 링크를 구분하지 않는다 (본문 잉크와 색 대비 3:1 미만) */
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
}

    a:hover {
        color: var(--ink);
    }

    a:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
        border-radius: 2px;
    }

/* 본문 건너뛰기 — 평소엔 지면 밖에 있다가 첫 Tab에만 왼쪽 위로 나와 앉는다(밴드 위) */
.skip-link {
    position: absolute;
    left: -999px;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

    .skip-link:focus-visible {
        position: fixed;
        left: 0;
        top: 0;
        width: auto;
        height: auto;
        z-index: 200;
        padding: 0.5rem 0.9rem;
        background: var(--ink);
        color: var(--paper);
        border-radius: 0;
        text-decoration: none;
        font-family: var(--font-label);
        font-size: 0.85rem;
        letter-spacing: 0.03em;
    }

/* ---------- 표제란 (상단 헤더 밴드) ---------- */

.topbar {
    background: var(--paper);
    border-bottom: 2px solid var(--line-heavy);
    /* 밴드는 접히되 눌리지는 않는다 — body의 세로 flex에서 자기 높이를 지킨다 */
    flex: 0 0 auto;
}

.topbar-inner {
    max-width: 1280px;
    margin: 0 auto;
    padding: 0 1.25rem;
    display: flex;
    align-items: stretch;
    flex-wrap: wrap;
    gap: 0 1rem;
    min-height: 54px;
}

.topbar .brand {
    display: flex;
    align-items: center;
    font-family: var(--font-label);
    font-weight: 700;
    font-size: 1.12rem;
    letter-spacing: 0.09em;
    color: var(--ink);
    text-decoration: none;
    white-space: nowrap;
}

/* 브랜드 마크: 제도된 H 한 글자. 라운드 0, 그림자 없음 — 배지도 원형 바탕도 이 세계에 없다.
   상단 바에서는 대문자 높이(1.12rem × 약 0.71 = 0.79rem)의 1.4배를 정사각 격자의 변으로 잡는다. */
.brand-mark {
    flex: none;
    width: 1.25rem;
    height: 1.25rem;
    margin-right: 0.5rem;
    border-radius: 0;
    box-shadow: none;
}

/* 로그인 표지의 심볼: 치수 보조선까지 보이는 크기라 기본 변형을 쓴다. */
.login-mark {
    display: block;
    width: 2.6rem;
    height: 2.6rem;
    margin: 0 0 0.6rem;
    border-radius: 0;
    box-shadow: none;
}

.topbar nav {
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    min-width: 0;
    /* 항목이 늘어나면 내비 자신이 여러 줄로 접힌다 — 브랜드와 우측 표제란 칸을 아래로 밀어내지 않는다.
       (flex-basis:auto면 내비의 최대 폭이 줄바꿈 계산에 쓰여 우측 칸이 통째로 다음 줄로 떨어졌고,
        그때 세로 구분선은 밴드를 가로지르지 못한 채 44px짜리 토막으로 남았다) */
    flex: 1 1 0;
}

    .topbar nav > a {
        display: flex;
        align-items: center;
        padding: 0.5rem 0.8rem;
        font-size: 0.88rem;
        font-weight: 500;
        color: var(--ink-2);
        text-decoration: none;
        white-space: nowrap;
        border-bottom: 3px solid transparent;
        margin-bottom: -2px; /* 주서 밑줄이 헤더 밴드의 2px 잉크선 위에 앉도록 */
        transition: color 140ms ease-out, background-color 140ms ease-out;
    }

        .topbar nav > a:hover {
            color: var(--ink);
            background: var(--row-hover);
        }

        .topbar nav > a.active {
            color: var(--ink);
            font-weight: 600;
            border-bottom-color: var(--accent);
        }

        .topbar nav > a:focus-visible {
            outline: none;
            box-shadow: var(--focus-ring);
        }

/* 내비 서랍(묶음 항목). 트리거는 이웃한 내비 링크와 같은 문법이고, 펼쳐지는 목록은
   행 작업 메뉴와 같은 어휘다 — 두 메뉴는 한 벌이어야 한다(.action-menu-list를 그대로 쓴다). */
.nav-group {
    position: relative;
    display: flex;
    align-items: stretch;
}

.nav-group-trigger {
    appearance: none;
    display: flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.5rem 0.8rem;
    border: 0;
    border-bottom: 3px solid transparent;
    border-radius: 0;
    margin-bottom: -2px; /* 주서 밑줄이 헤더 밴드의 2px 잉크선 위에 앉도록 */
    background: none;
    font-family: inherit;
    font-size: 0.88rem;
    font-weight: 500;
    color: var(--ink-2);
    white-space: nowrap;
    cursor: pointer;
    transition: color 140ms ease-out, background-color 140ms ease-out;
}

    .nav-group-trigger:hover {
        color: var(--ink);
        background: var(--row-hover);
    }

    /* 서랍 안 어느 장에 있든 트리거가 대신 밑줄을 켠다 — 접었다고 현재 위치가 사라지지 않는다. */
    .nav-group-trigger.active {
        color: var(--ink);
        font-weight: 600;
        border-bottom-color: var(--accent);
    }

    .nav-group-trigger:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
    }

.nav-group[data-open="true"] .action-menu-caret {
    transform: rotate(180deg);
}

/* 목록은 트리거 왼쪽 끝에 맞춰 열린다(라벨 아래여야 어느 서랍인지 읽힌다).
   스크립트가 붙으면 portal.js가 같은 자리를 화면 좌표로 다시 잡는다.
   공용 목록면(.action-menu-list)의 right:0을 덮어야 하므로 두 클래스를 함께 짚는다 —
   같은 특정도로 두면 파일 안 순서에 기대게 되고, 순서는 언젠가 바뀐다. */
.action-menu-list.nav-menu {
    left: 0;
    right: auto;
}

    /* 목록은 밴드와 함께 정적으로 그려지고 접힌 채로 기다린다 (display:flex가 [hidden]을 이긴다). */
    .nav-menu[hidden] {
        display: none;
    }

    .nav-menu .menu-item {
        padding: 0.4rem 0.8rem;
    }

    /* 현재 장은 밴드의 3px 주서 밑줄과 같은 굵기로 표시한다 — 선이 눕는 자리만 왼쪽으로 바뀐다. */
    .nav-menu .menu-item.active {
        font-weight: 700;
        box-shadow: inset 3px 0 0 var(--accent);
    }

/* 표제란 우측 칸: 위에 작은 항목명, 아래 값 */
.topbar-user {
    margin-left: auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 0.3rem 0 0.3rem 1rem;
    border-left: 1px solid var(--line-light);
    min-width: 8rem;
}

    .topbar-user .tb-label {
        font-family: var(--font-label);
        font-size: 0.68rem;
        font-weight: 600;
        letter-spacing: 0.12em;
        color: var(--ink-3);
        line-height: 1.3;
    }

    /* 이름과 '내 데스크톱'은 한 기입선에 나란히 앉는다 — 칸이 한 줄 더 자라지 않게. */
    .topbar-user .tb-line {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        gap: 0 0.5rem;
        min-width: 0;
    }

    .topbar-user .tb-value {
        font-family: var(--font-label);
        font-size: 0.9rem;
        font-weight: 600;
        color: var(--ink);
        line-height: 1.3;
        overflow-wrap: anywhere;
    }

    /* '내 데스크톱'은 내비가 아니라 내 칸에 속한 조용한 길이다 — 밑줄은 짚을 때만 나온다. */
    .topbar-user .tb-link {
        font-family: var(--font-label);
        font-size: 0.76rem;
        font-weight: 600;
        line-height: 1.25;
        color: var(--ink-2);
        text-decoration: none;
        white-space: nowrap;
        transition: color 140ms ease-out;
    }

        .topbar-user .tb-link:hover,
        .topbar-user .tb-link:focus-visible {
            color: var(--ink);
            text-decoration: underline;
            text-decoration-thickness: 1px;
            text-underline-offset: 2px;
        }

        .topbar-user .tb-link:focus-visible {
            outline: none;
            box-shadow: var(--focus-ring);
        }

        .topbar-user .tb-link.active {
            color: var(--ink);
            text-decoration: underline;
            text-decoration-color: var(--accent);
            text-decoration-thickness: 2px;
            text-underline-offset: 2px;
        }

    /* 로그아웃은 폼 POST다(링크로 두면 프리페치·미리보기가 세션을 끊는다).
       버튼이지만 '내 데스크톱'과 같은 기입선에 같은 글자로 앉는다 — 문법은 링크, 동작은 제출. */
    .topbar-user .tb-logout {
        display: inline;
        margin: 0;
    }

    .topbar-user .tb-logout-btn {
        padding: 0;
        border: 0;
        background: none;
        cursor: pointer;
    }

/* 좁은 창에서는 표제란이 여러 줄로 접힌다 — 세로 구분선은 그때 밴드를 가로지르는 구분선이 된다.
   (제 폭만큼만 그어진 선은 접힌 줄을 나누지 못하고 밑줄처럼 떠 보였다)
   내비가 세 링크 + 세 서랍으로 줄어든 뒤로 1024px까지는 한 줄로 서므로 접히는 폭을 940px로 내렸다. */
@media (max-width: 940px) {
    .topbar-user {
        flex: 1 0 100%;
        flex-direction: row;
        align-items: baseline;
        /* 세로 배치일 때의 세로 가운데 정렬(justify-content:center)이 가로 배치에서는
           글을 밴드 한가운데로 밀어버린다 — 표제란 칸은 왼쪽 기입선에 맞춘다 */
        justify-content: flex-start;
        gap: 0 0.5rem;
        margin-left: 0;
        border-left: 0;
        border-top: 1px solid var(--line-light);
        padding: 0.3rem 0;
        min-width: 0;
    }

}

/* ---------- 페이지와 도면 시트 ---------- */

.page {
    /* body가 세로 flex라 margin:0 auto가 align-self:stretch를 무효화한다 —
       width를 못박지 않으면 시트가 내용 폭(빈 화면에서 420px)까지 쪼그라든다. */
    width: 100%;
    max-width: 1280px;
    margin: 0 auto;
    padding: 1.5rem 1.25rem 3rem;
    /* 헤더 밴드가 몇 줄로 접히든(내비 13개는 1280px에서 두 줄이 된다) 시트가 남는 높이를 정확히 먹는다 */
    flex: 1 0 auto;
    display: flex;
    flex-direction: column;
}

/* 미인증 화면(로그인)은 표가 아니라 기입란 두 칸짜리 도면이다 — 시트를 좁혀 세로 가운데 놓는다. */
.page-narrow {
    max-width: 34rem;
    justify-content: center;
    padding-top: 3rem;
}

/* 시트: 2px 잉크 프레임 + 안쪽 1px hairline 이중 보더.
   세로 흐름이라 flex column — 표제란(.sheet-footer)이 내용 길이와 무관하게 프레임 하단을 마감한다. */
.sheet {
    position: relative;
    display: flex;
    flex-direction: column;
    background: var(--paper);
    border: 2px solid var(--line-heavy);
    padding: 1.4rem 1.6rem 1.6rem;
    /* 내용이 짧아도 한 장의 도면으로 서 있게 한다 — 밴드 높이를 상수로 빼지 않고(밴드는 접힌다)
       body → .page → .sheet 세로 flex 사슬에서 남는 높이를 먹는다. 유령 스크롤바가 생기지 않는다. */
    flex: 1 0 auto;
    min-height: 0;
}

    .sheet::before {
        content: "";
        position: absolute;
        inset: 5px;
        border: 1px solid var(--line-hair);
        pointer-events: none;
    }

    /* 시트 상단 타이틀 스트립 */
    .sheet > h1 {
        margin: 0 0 0.6rem;
        padding-bottom: 0.5rem;
        border-bottom: 1.5px solid var(--line-medium);
    }

.page-subtitle {
    color: var(--ink-2);
    margin: 0 0 1.2rem;
    font-size: 0.9rem;
}

/* ---------- 시트 하단 표제란 (title block) ---------- */

/* 도면은 프레임 안에서 끝난다 — 내용이 짧아도 표제란은 늘 맨 아래 줄에 앉는다 */
.sheet-footer {
    margin-top: auto;
    padding-top: 2.2rem;
}

.titleblock {
    display: flex;
    flex-wrap: wrap;
    margin: 0;
    background: var(--paper-2);
    border: 1.5px solid var(--line-medium);
}

    .titleblock > div {
        flex: 1 1 12rem;
        min-width: 0;
        padding: 0.35rem 0.8rem;
        border-left: 1px solid var(--line-hair);
    }

        .titleblock > div:first-child {
            border-left: 0;
        }

    .titleblock dt {
        font-family: var(--font-label);
        font-size: 0.66rem;
        font-weight: 600;
        letter-spacing: 0.12em;
        color: var(--ink-3);
        line-height: 1.3;
    }

    .titleblock dd {
        margin: 0;
        font-family: var(--font-label);
        font-size: 0.86rem;
        font-weight: 600;
        font-variant-numeric: tabular-nums;
        color: var(--ink);
        line-height: 1.35;
        overflow-wrap: anywhere;
    }

/* ---------- 주기(NOTES): 시트 하단 참조 영역 ---------- */

.sheet-notes {
    margin-top: 2rem;
    padding-top: 0.55rem;
    border-top: 1.5px solid var(--line-medium);
}

    .sheet-notes .notes-title {
        margin: 0 0 0.35rem;
        padding: 0;
        border: 0;
        font-family: var(--font-label);
        font-size: 0.76rem;
        font-weight: 700;
        letter-spacing: 0.14em;
        color: var(--ink-2);
    }

.notes-list {
    margin: 0;
    padding-left: 1.7rem;
    font-size: 0.88rem;
}

    .notes-list li {
        margin: 0.22rem 0;
    }

        .notes-list li::marker {
            font-family: var(--font-label);
            font-weight: 600;
            color: var(--ink-3);
        }

/* ---------- 버튼 ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.9rem;
    border: 1.5px solid var(--line-medium);
    border-radius: 2px;
    background: var(--paper);
    color: var(--ink);
    font-family: var(--font-label);
    font-size: 0.88rem;
    font-weight: 600;
    line-height: 1.3;
    cursor: pointer;
    transition: background-color 140ms ease-out, border-color 140ms ease-out, color 140ms ease-out;
}

    /* 링크로 쓰이는 버튼 — 밑줄 대신 버튼 프레임이 어포던스다 */
    a.btn,
    a.btn:hover {
        text-decoration: none;
    }

    /* 호버는 도장이 찍히듯 반전된다 */
    .btn:hover:not(:disabled) {
        background: var(--ink);
        border-color: var(--ink);
        color: var(--paper);
    }

    .btn:active:not(:disabled) {
        background: var(--ink-pressed);
        border-color: var(--ink-pressed);
        color: var(--paper);
    }

    .btn:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
        border-color: var(--accent);
    }

    .btn:disabled {
        cursor: not-allowed;
        background: var(--paper);
        border-style: dashed;
        border-color: var(--line-light);
        color: var(--ink-3);
    }

.btn-sm {
    padding: 0.24rem 0.6rem;
    font-size: 0.8rem;
}

/* 위험 확정: 주서 */
.btn-danger {
    border-color: var(--accent);
    color: var(--accent);
}

    .btn-danger:hover:not(:disabled) {
        background: var(--accent);
        border-color: var(--accent);
        color: var(--paper);
    }

    .btn-danger:active:not(:disabled) {
        background: var(--accent-pressed);
        border-color: var(--accent-pressed);
    }

/* ---------- 폼 컨트롤 ---------- */

/* :where()로 특정도를 0으로 낮춰 .cell-mono 같은 유틸리티가 덮어쓸 수 있게 한다 */
input:where(:not([type=checkbox]):not([type=radio])),
select,
textarea {
    font-family: var(--font-body);
    font-size: 0.9rem;
    color: var(--ink);
    background: var(--paper);
    border: 1.5px solid var(--line-medium);
    border-radius: 2px;
    padding: 0.35rem 0.55rem;
}

    input:where(:not([type=checkbox]):not([type=radio])):focus-visible,
    select:focus-visible,
    textarea:focus-visible {
        outline: none;
        border-color: var(--accent);
        box-shadow: var(--focus-ring);
    }

    input:where(:not([type=checkbox]):not([type=radio])):disabled,
    select:disabled,
    textarea:disabled {
        background: var(--paper-2);
        border-color: var(--line-light);
        color: var(--ink-3);
        cursor: not-allowed;
    }

::placeholder {
    color: var(--ink-3);
    opacity: 1;
}

label {
    color: var(--ink-2);
    font-size: 0.9rem;
}

/* 도면 기입란: 라벨이 입력 위에 얹힌 칸 */
.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 0.6rem 0.9rem;
    margin: 0.7rem 0 0.9rem;
}

    .form-grid label {
        display: flex;
        flex-direction: column;
        gap: 0.2rem;
        font-family: var(--font-label);
        font-size: 0.8rem;
        font-weight: 600;
        letter-spacing: 0.02em;
        color: var(--ink-2);
    }

/* 숫자 기입란이 문자열 칸만큼 넓을 이유는 없다 */
.form-grid input[type="number"] {
    max-width: 10rem;
}

/* 칸 아래 부기 — 값이 비었을 때 무엇이 대신 쓰이는지 말하는 자리 */
.form-note {
    margin: 0.1rem 0 0.6rem;
    font-size: 0.82rem;
}

/* 사유처럼 한 줄이 필요한 칸은 격자 한 줄을 다 쓴다 */
.field-wide {
    grid-column: 1 / -1;
}

.inline-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin: 0.6rem 0 0.9rem;
}

/* ---------- 카드 / 패널 / 알림 ---------- */

.card,
.panel,
.alert {
    background: var(--paper);
    border: 1.5px solid var(--line-medium);
    border-radius: 0;
    padding: 1rem 1.2rem;
}

.panel,
.alert {
    margin: 0.9rem 0;
}

/* 알림: 상태 soft 배경 + 상태 잉크 1.5px 보더 (색 옆에는 항상 글이 있다) */
.card.alert-good,
.alert.alert-ok {
    background: var(--status-good-bg);
    border-color: var(--status-good-ink);
}

.card.alert-warning,
.alert.alert-warning {
    background: var(--status-warning-bg);
    border-color: var(--status-warning-ink);
}

.card.alert-critical,
.alert.alert-error {
    background: var(--status-critical-bg);
    border-color: var(--status-critical-ink);
}

.card.alert-info,
.alert.alert-info {
    background: var(--status-info-bg);
    border-color: var(--status-info-ink);
}

/* 알림 자리(공지). 비어 있어도 접근성 트리에 남아 있어야 나중에 채워지는 글이 읽힌다 —
   자리 자체는 아무 상자도 갖지 않으므로 비어 있는 동안 높이 0으로 접힌다. */
.notice-slot {
    margin: 0;
    padding: 0;
    border: 0;
}

/* 진행 중인 작업 폼: 주서 프레임 하나로만 강조한다 (폼마다 임의 색 금지) */
.card.card-emphasis {
    border-color: var(--accent);
    box-shadow: none;
}

details.panel > summary {
    font-family: var(--font-label);
    font-weight: 600;
    letter-spacing: 0.02em;
    cursor: pointer;
}

    details.panel > summary:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
    }

/* ---------- 부품표(BOM) 표 ---------- */

/* 넓은 표는 페이지가 아니라 표가 스크롤한다 (좁은 창·200% 확대 대응) */
/* 행 메뉴는 래퍼의 overflow를 잠시 풀어 빠져나오게 하지 않는다 — overflow를 바꾸는 순간
   브라우저가 가로 스크롤 위치를 0으로 되감아, 오른쪽 열을 보던 시선이 튕겨 돌아왔다.
   대신 메뉴만 화면 좌표(position:fixed)로 띄운다 (portal.js openMenu). */
.table-wrap {
    overflow-x: auto;
}

/* 긴 표(감사 로그·IP 할당·작업 이력·머신 목록)만 세로로도 표가 스크롤한다 —
   그래야 thead의 sticky가 실제로 붙는다. 짧은 표에 붙이면 쓸데없는 안쪽 스크롤바만 생긴다.
   행 메뉴는 화면 좌표(position:fixed)로 뜨고, portal.js가 캡처 단계 scroll을 듣고 있어
   이 래퍼가 스크롤되면 메뉴는 닫힌다. */
.table-wrap.table-wrap-tall {
    max-height: min(70vh, 48rem);
    overflow: auto;
}

/* 넓은 표에서 가로로 밀면 '이게 어느 행이었나'가 먼저 사라진다 — 행을 지목하는 첫 칸만 남긴다.
   붙이는 곳은 첫 칸이 실제로 그 행의 이름인 표뿐이다(머신·IP·시각·작업). */
.table-wrap-pin :is(th, td):first-child {
    position: sticky;
    left: 0;
    background: var(--paper);
    z-index: 3;
    /* 안쪽 그림자지만 뜬 면이 아니라 세로 칸 구분선과 같은 굵기·같은 색의 hairline이다 (칸 밖으로 번지지 않는다) */
    box-shadow: inset -1px 0 0 var(--line-hair);
}

/* 머리글의 첫 칸은 가로·세로 양쪽으로 고정되므로 나머지 머리글(z 2)보다 한 단 위에 있어야 한다 */
.table-wrap-pin thead th:first-child {
    z-index: 4;
}

/* 고정 칸은 제 배경을 직접 칠하므로 행 상태(호버·선택)도 직접 따라간다 */
.table-wrap-pin tbody tr:hover td:first-child {
    background: var(--row-hover);
}

.table-wrap-pin tbody tr.row-selected td:first-child {
    background: var(--accent-soft);
}

:is(.table, table.grid) {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background: var(--paper);
    border: 1.5px solid var(--line-medium);
    border-radius: 0;
    font-size: 0.9rem;
}

    :is(.table, table.grid) thead th {
        /* 세로로 스크롤되는 컨테이너(.table-wrap-tall) 안에서 머리글이 남는다 (그 밖에서는 무해).
           border-collapse: separate라 아래 1.5px 선은 칸 자신이 그리는 선이고, 따라서 붙어서 함께 움직인다. */
        position: sticky;
        top: 0;
        z-index: 2;
        background: var(--paper);
        text-align: left;
        font-family: var(--font-label);
        font-size: 0.78rem;
        font-weight: 600;
        letter-spacing: 0.03em;
        color: var(--ink-2);
        border-bottom: 1.5px solid var(--line-medium);
        padding: 0.5rem 0.85rem;
        white-space: nowrap;
    }

    :is(.table, table.grid) tbody td {
        padding: 0.55rem 0.85rem;
        border-bottom: 1px solid var(--line-light);
        vertical-align: middle;
        /* 부품표의 수치는 자릿수가 세로로 맞아야 읽힌다 (한글·라틴 글자에는 영향 없음) */
        font-variant-numeric: tabular-nums;
    }

    /* 세로 칸 구분은 가장 가는 선으로 */
    :is(.table, table.grid) thead th + th,
    :is(.table, table.grid) tbody td + td,
    :is(.table, table.grid) tfoot th + td,
    :is(.table, table.grid) tfoot td + td {
        border-left: 1px solid var(--line-hair);
    }

    :is(.table, table.grid) tbody tr:last-child td {
        border-bottom: none;
    }

    /* 합계 줄: 부품표의 마지막 칸. 본문보다 굵은 선으로 끊고 옅은 채움으로 구분한다 */
    :is(.table, table.grid) tfoot th,
    :is(.table, table.grid) tfoot td {
        padding: 0.5rem 0.85rem;
        background: var(--paper-2);
        border-top: 1.5px solid var(--line-medium);
        text-align: left;
        font-family: var(--font-label);
        font-size: 0.84rem;
        font-weight: 700;
        font-variant-numeric: tabular-nums;
        color: var(--ink);
    }

    :is(.table, table.grid) tbody tr:hover td {
        background: var(--row-hover);
    }

    :is(.table, table.grid) tbody tr.row-selected td {
        background: var(--accent-soft);
    }

.cell-muted {
    color: var(--ink-3);
}

/* 표 칸의 둘째 줄 — 이름 아래 부서·직함처럼 '가르는 데 쓰이는' 보조 사실 */
.cell-sub {
    display: block;
    font-size: 0.8rem;
}

.cell-mono {
    font-family: var(--font-mono);
    font-size: 0.85rem;
}

/* 행마다 작업 메뉴 하나 — 우측 정렬로 세워 줄을 흐트러뜨리지 않는다 */
.cell-actions {
    text-align: right;
    white-space: nowrap;
}

/* 표에 붙는 부기 한 줄 — 표가 무엇을 세는지, 무엇을 세지 않는지 */
.table-note {
    color: var(--ink-2);
    font-size: 0.85rem;
    margin: 0.6rem 0 1.2rem;
}

/* 긴 텍스트 셀 말줄임 — 전문은 title/상세 링크로 제공하는 곳에서만 쓴다 */
.cell-truncate {
    max-width: 22rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 스크린리더 전용 텍스트 (표 caption 등) — 시각적으로 숨기되 접근성 트리에는 남긴다 */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* ---------- 검인 스탬프 (항상 텍스트 라벨 동반) ---------- */

.badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.08rem 0.5rem;
    border: 1.5px solid currentColor;
    /* 검인은 사각이다 — 둥근 모서리는 이 세계의 문법이 아니다 */
    border-radius: 0;
    font-family: var(--font-label);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

    /* 링크로 쓰이는 스탬프(묶음 ×N 등) */
    a.badge {
        text-decoration: none;
    }

        a.badge:hover {
            color: inherit;
            outline: 1.5px solid currentColor;
            outline-offset: 1px;
        }

        a.badge:focus-visible {
            outline: none;
            box-shadow: var(--focus-ring);
        }

.badge-good {
    background: var(--status-good-bg);
    color: var(--status-good-ink);
}

.badge-warning {
    background: var(--status-warning-bg);
    color: var(--status-warning-ink);
}

.badge-serious {
    background: var(--status-serious-bg);
    color: var(--status-serious-ink);
}

.badge-critical,
.badge-danger {
    background: var(--status-critical-bg);
    color: var(--status-critical-ink);
}

.badge-info {
    background: var(--status-info-bg);
    color: var(--status-info-ink);
}

.badge-neutral {
    background: var(--status-neutral-bg);
    color: var(--status-neutral-ink);
}

/* ---------- 계기 띠 (라벨 + 수치가 한 줄에 늘어선 눈금판) ---------- */

/* 타일 격자가 아니라 계기판 한 줄 — 항목 사이는 hairline으로만 끊는다 */
.gauge-strip {
    display: flex;
    flex-wrap: wrap;
    margin: 0.75rem 0 0.45rem;
    background: var(--paper);
    border: 1.5px solid var(--line-medium);
}

    .gauge-strip > div {
        flex: 1 1 9rem;
        min-width: 0;
        display: flex;
        align-items: baseline;
        gap: 0.5rem;
        padding: 0.4rem 0.85rem;
        border-left: 1px solid var(--line-hair);
    }

        .gauge-strip > div:first-child {
            border-left: 0;
        }

    .gauge-strip dt {
        font-family: var(--font-label);
        font-size: 0.76rem;
        font-weight: 600;
        letter-spacing: 0.04em;
        color: var(--ink-2);
        white-space: nowrap;
    }

    .gauge-strip dd {
        margin: 0 0 0 auto;
        font-family: var(--font-label);
        font-size: 1.1rem;
        font-weight: 700;
        font-variant-numeric: tabular-nums;
        line-height: 1.2;
        color: var(--ink);
    }

/* 수치의 의미색 — 라벨(열 머리글·항목명)이 항상 곁에 있으므로 색은 보조 신호로만 얹는다 */
.num-good {
    color: var(--status-good-ink);
}

.num-warning {
    color: var(--status-warning-ink);
}

.num-serious {
    color: var(--status-serious-ink);
}

.num-critical {
    color: var(--status-critical-ink);
}

.num-info {
    color: var(--status-info-ink);
}

:is(.num-good, .num-warning, .num-serious, .num-critical, .num-info) {
    font-weight: 600;
}

/* ---------- 인라인 아이콘 (본문 글줄에 앉는 stroke 1.5 SVG) ---------- */

.icon-inline {
    flex: none;
    vertical-align: -0.13em;
    margin-right: 0.1rem;
}

/* ---------- 제원표 (상세 정의 리스트) ---------- */

.detail-list {
    display: grid;
    /* 10.625rem = 기본 16px 기준 170px — 값은 그대로 두고 단위만 rem으로 (확대 시 라벨 칸도 함께 큰다) */
    grid-template-columns: 10.625rem 1fr;
    gap: 0;
    margin: 0;
    background: var(--paper);
    border: 1.5px solid var(--line-medium);
    border-radius: 0;
    padding: 0;
    font-size: 0.9rem;
}

    .detail-list dt {
        font-family: var(--font-label);
        font-size: 0.8rem;
        font-weight: 600;
        letter-spacing: 0.02em;
        color: var(--ink-2);
        background: var(--paper-2);
        padding: 0.45rem 0.9rem;
        border-bottom: 1px solid var(--line-hair);
    }

    .detail-list dd {
        margin: 0;
        padding: 0.45rem 0.9rem;
        border-bottom: 1px solid var(--line-hair);
        border-left: 1px solid var(--line-hair);
        overflow-wrap: anywhere;
    }

    .detail-list dt:last-of-type,
    .detail-list dd:last-of-type {
        border-bottom: none;
    }

/* ---------- 링크 목록 (홈) ---------- */

.link-list {
    margin: 0.4rem 0 0;
    padding-left: 1.2rem;
}

    .link-list li {
        margin: 0.25rem 0;
    }

        /* 목록 기호도 브라우저 기본색으로 두지 않는다 — 잉크로 찍는다 */
        .link-list li::marker {
            color: var(--ink);
        }

/* ---------- 주기(註記) 탭 ---------- */

.tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.1rem;
    border-bottom: 1px solid var(--line-light);
    margin: 1.2rem 0 1rem;
}

.tab {
    appearance: none;
    border: 0;
    border-bottom: 3px solid transparent;
    border-radius: 0;
    background: none;
    color: var(--ink-2);
    font-family: var(--font-label);
    font-size: 0.88rem;
    font-weight: 600;
    line-height: 1.3;
    padding: 0.45rem 0.8rem;
    margin-bottom: -1px;
    cursor: pointer;
    transition: color 140ms ease-out;
}

    .tab:hover {
        color: var(--ink);
    }

    .tab:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
    }

    .tab[aria-pressed="true"] {
        color: var(--ink);
        border-bottom-color: var(--accent);
    }

    .tab .tab-count {
        color: var(--ink-3);
        font-weight: 400;
    }

    .tab[aria-pressed="true"] .tab-count {
        color: var(--ink-2);
    }

/* ---------- 작업 지시서 모달 ---------- */

.modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background: var(--veil);
    animation: modal-veil 140ms ease-out;
}

.modal-sheet {
    position: relative;
    display: flex;
    flex-direction: column;
    width: min(680px, calc(100vw - 2rem));
    max-height: 85vh;
    background: var(--paper);
    border: 2px solid var(--line-heavy);
    /* 이 시스템에서 그림자가 허용되는 유일한 면 */
    box-shadow: var(--shadow-dialog);
    animation: modal-rise 180ms cubic-bezier(0.16, 1, 0.3, 1);
}

    .modal-sheet:focus {
        outline: none;
    }

.modal-head {
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
    padding: 0.8rem 1rem;
    border-bottom: 2px solid var(--line-heavy);
}

.modal-mark {
    flex: none;
    margin-top: 0.15rem;
    padding: 0.1rem 0.4rem;
    border: 1.5px solid var(--accent);
    border-radius: 0;
    font-family: var(--font-label);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    color: var(--accent);
    white-space: nowrap;
}

.modal-heading {
    min-width: 0;
}

.modal-title {
    font-family: var(--font-label);
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--ink);
    margin: 0;
    padding: 0;
    border: 0;
}

.modal-subtitle {
    margin: 0.15rem 0 0;
    font-size: 0.85rem;
    color: var(--ink-2);
}

.modal-close {
    flex: none;
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.8rem;
    height: 1.8rem;
    padding: 0;
    border: 1.5px solid var(--line-medium);
    border-radius: 2px;
    background: var(--paper);
    color: var(--ink);
    cursor: pointer;
    transition: background-color 140ms ease-out, color 140ms ease-out, border-color 140ms ease-out;
}

    .modal-close:hover {
        background: var(--ink);
        border-color: var(--ink);
        color: var(--paper);
    }

    .modal-close:focus-visible {
        outline: none;
        border-color: var(--accent);
        box-shadow: var(--focus-ring);
    }

/* 본문만 스크롤한다 — 지시서가 길어져도 시트 자체는 85vh 프레임을 지킨다 */
.modal-body {
    flex: 1 1 auto;
    min-height: 0;
    padding: 1rem 1.15rem 1.25rem;
    overflow-y: auto;
}

    .modal-body > :first-child {
        margin-top: 0;
    }

    /* 확정 바가 있는 지시서에서는 본문 하단 여백을 바가 대신 진다 —
       그래야 고정된 바가 시트 바닥에 붙어 마감된다 (흰 띠가 남지 않는다) */
    .modal-body:has(> .modal-actions) {
        padding-bottom: 0;
    }

/* 확정 줄: 본문 안 하단에 고정된다. 긴 지시서에서 '실행/취소'를 찾아 스크롤하는 일이 없도록.
   좌우·하단 패딩을 상쇄해 바가 지시서 폭을 가로질러 마감한다. */
.modal-actions {
    position: sticky;
    bottom: 0;
    z-index: 1;
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    align-items: center;
    gap: 0.5rem;
    margin: 1.2rem -1.15rem 0;
    padding: 0.7rem 1.15rem 0.8rem;
    background: var(--paper);
    border-top: 1.5px solid var(--line-medium);
}

/* 제출 실패는 확정 바와 함께 떠 있어야 한다 — 위로 스크롤해야 보이는 오류는 없는 오류다 */
.modal-alert {
    margin: 0;
}

.modal-actions .modal-alert {
    order: -1;
    flex: 1 1 100%;
    margin-bottom: 0.15rem;
}

@keyframes modal-veil {
    from {
        opacity: 0;
    }
}

@keyframes modal-rise {
    from {
        opacity: 0;
        transform: translateY(-8px);
    }
}

/* ---------- 행 작업 메뉴 ---------- */

.action-menu {
    position: relative;
    display: inline-block;
}

.action-menu-caret {
    flex: none;
    transition: transform 140ms ease-out;
}

.action-menu[data-open="true"] .action-menu-caret {
    transform: rotate(180deg);
}

/* 메뉴 밖을 누르면 닫히도록 깔아 두는 투명 면 (키보드는 Esc로 닫는다) */
.action-menu-veil {
    position: fixed;
    inset: 0;
    z-index: 20;
}

/* 기본 배치는 트리거 기준 absolute — 스크립트가 없어도 제자리에 열린다.
   portal.js가 열리는 순간 화면 좌표(fixed)로 바꿔 표 래퍼의 잘림에서 꺼낸다. */
.action-menu-list {
    position: absolute;
    top: calc(100% + 3px);
    right: 0;
    z-index: 30;
    min-width: 12rem;
    display: flex;
    flex-direction: column;
    padding: 0.2rem;
    background: var(--paper);
    border: 1.5px solid var(--line-medium);
}

.menu-item {
    appearance: none;
    display: block;
    width: 100%;
    text-align: left;
    /* 링크로 채워질 수도 있다(내비 서랍) — 메뉴 항목은 밑줄이 아니라 반전으로 말한다. */
    text-decoration: none;
    border: 0;
    border-radius: 0;
    background: none;
    color: var(--ink);
    font-family: var(--font-label);
    font-size: 0.86rem;
    font-weight: 600;
    line-height: 1.35;
    padding: 0.4rem 0.6rem;
    cursor: pointer;
    transition: background-color 140ms ease-out, color 140ms ease-out;
}

    .menu-item:hover:not(:disabled) {
        background: var(--ink);
        color: var(--paper);
    }

    .menu-item:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
    }

    .menu-item:disabled {
        color: var(--ink-3);
        cursor: not-allowed;
    }

    .menu-item.menu-item-danger {
        color: var(--accent);
    }

        .menu-item.menu-item-danger:hover:not(:disabled) {
            background: var(--accent);
            color: var(--paper);
        }

/* ---------- 계정 선택기 (Account Picker) ---------- */

/* 기입란 문법 그대로다 — 1.5px 테두리·2px radius·주서 포커스. 다른 점은 칸 아래로
   후보 목록(행 작업 메뉴와 같은 면)이 열리고, 고른 뒤에는 칸이 칩으로 바뀐다는 것뿐이다. */
.ad-picker {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    position: relative;
}

.ad-picker-label {
    font-family: var(--font-label);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--ink-2);
}

.ad-picker-field {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

    .ad-picker-field input {
        flex: 1 1 auto;
        min-width: 0;
    }

.ad-picker-status {
    flex: none;
    font-family: var(--font-label);
    font-size: 0.76rem;
    color: var(--ink-3);
}

/* 확정 칩: '타이핑한 문자열'이 아니라 '확인된 계정'이라는 표시 */
.ad-picker-chip {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    padding: 0.3rem 0.5rem;
    background: var(--paper-2);
    border: 1.5px solid var(--line-medium);
    border-radius: 2px;
}

.ad-picker-chip-name {
    font-weight: 600;
}

.ad-picker-chip-login {
    color: var(--ink-2);
}

.ad-picker-chip-clear {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.3rem;
    height: 1.3rem;
    padding: 0;
    background: var(--paper);
    color: var(--ink);
    border: 1.5px solid var(--line-medium);
    border-radius: 2px;
    cursor: pointer;
}

    .ad-picker-chip-clear:hover:not(:disabled) {
        background: var(--ink);
        color: var(--paper);
    }

    .ad-picker-chip-clear:focus-visible {
        outline: none;
        border-color: var(--accent);
        box-shadow: var(--focus-ring);
    }

    .ad-picker-chip-clear:disabled {
        border-style: dashed;
        color: var(--ink-3);
        cursor: not-allowed;
    }

/* 후보 목록 — 행 작업 메뉴와 같은 면(흰 바탕 1.5px, radius 0, 그림자 없음) */
.ad-picker-list {
    list-style: none;
    margin: 0.2rem 0 0;
    padding: 0.2rem;
    max-height: 16rem;
    overflow-y: auto;
    background: var(--paper);
    border: 1.5px solid var(--line-medium);
}

.ad-picker-option {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    padding: 0.3rem 0.5rem;
    cursor: pointer;
}

    .ad-picker-option + .ad-picker-option {
        border-top: 1px solid var(--line-hair);
    }

    .ad-picker-option:hover,
    .ad-picker-option.is-highlighted {
        background: var(--row-hover);
    }

    /* 짚고 있는 후보는 왼쪽 3px 주서 막대 — 내비 서랍의 현재 장과 같은 표시다 */
    .ad-picker-option.is-highlighted {
        box-shadow: inset 3px 0 0 0 var(--accent);
    }

.ad-picker-option-name {
    font-weight: 600;
}

.ad-picker-option-login {
    color: var(--ink-2);
}

.ad-picker-option-marks {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    margin-left: auto;
}

/* 부서·직함 — 이름 아래 한 줄로 내려 앉는다. 같은 이름의 두 사람을 가르는 것은 대개 이 줄이다 */
.ad-picker-option-meta {
    flex-basis: 100%;
    font-size: 0.8rem;
    color: var(--ink-3);
}

.ad-picker-recent {
    margin-top: 0.2rem;
}

.ad-picker-recent-head {
    margin: 0;
    font-family: var(--font-label);
    font-size: 0.76rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--ink-3);
}

.ad-picker-recent-item {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: 100%;
    padding: 0;
    background: none;
    border: 0;
    text-align: left;
    color: inherit;
    font: inherit;
    cursor: pointer;
}

    .ad-picker-recent-item:focus-visible {
        outline: none;
        box-shadow: var(--focus-ring);
    }

.ad-picker-note {
    margin: 0.2rem 0 0;
    font-size: 0.8rem;
    color: var(--ink-3);
}

/* 이미 데스크톱을 가진 사람을 고른 경우 — 막지 않고 사실만 적는다 */
.ad-picker-warning {
    margin: 0.2rem 0 0;
    font-size: 0.8rem;
    color: var(--status-warning-ink);
}

/* ---------- 런북 (마크다운 렌더) ---------- */

/* 목차 — 문서 제목에서 자동 생성. 표제 채움 위에 두 단으로 눕힌 참조 목록. 링크는 도면 파랑, 밑줄은 호버에서만. */
.toc {
    margin: 0 0 2rem;
    padding: 0.8rem 1rem 0.9rem;
    background: var(--paper-2);
    border: 1.5px solid var(--line-medium);
}
.toc-title {
    margin: 0 0 0.5rem;
    padding: 0;
    border: 0;
    font-family: var(--font-label);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--ink-2);
}
.toc-list {
    margin: 0;
    padding-left: 1.4rem;
    columns: 2;
    column-gap: 2rem;
    font-size: 0.92rem;
    line-height: 1.7;
}
    .toc-list > li { break-inside: avoid; }
    .toc-list ol { margin: 0; padding-left: 1.2rem; font-size: 0.86rem; color: var(--ink-2); }
    .toc a { text-decoration: none; }
    .toc a:hover, .toc a:focus-visible { text-decoration: underline; }
@media (max-width: 940px) { .toc-list { columns: 1; } }

.runbook h1,
.runbook h2 {
    font-family: var(--font-label);
    font-size: 1rem;
    font-weight: 700;
    margin: 1.6rem 0 0.5rem;
    padding-bottom: 0.3rem;
    border-bottom: 1px solid var(--line-light);
}

    .runbook h1:first-child,
    .runbook h2:first-child {
        margin-top: 0;
    }

.runbook h3 {
    font-family: var(--font-label);
    font-size: 0.92rem;
    font-weight: 700;
    margin: 1.2rem 0 0.35rem;
}

.runbook code {
    font-family: var(--font-mono);
    font-size: 0.85rem;
    background: var(--paper-2);
    border: 1px solid var(--line-hair);
    border-radius: 2px;
    padding: 0.05rem 0.3rem;
}

.runbook pre {
    background: var(--paper-2);
    border: 1px solid var(--line-light);
    border-radius: 0;
    padding: 0.75rem 0.9rem;
    overflow-x: auto;
}

    .runbook pre code {
        background: none;
        border: none;
        padding: 0;
    }

.runbook table {
    border-collapse: separate;
    border-spacing: 0;
    border: 1.5px solid var(--line-medium);
    font-size: 0.9rem;
}

    .runbook table th {
        font-family: var(--font-label);
        font-size: 0.78rem;
        letter-spacing: 0.03em;
        color: var(--ink-2);
        background: var(--paper);
        border-bottom: 1.5px solid var(--line-medium);
    }

    .runbook table th,
    .runbook table td {
        padding: 0.4rem 0.7rem;
        text-align: left;
    }

    .runbook table td {
        border-bottom: 1px solid var(--line-light);
    }

    .runbook table th + th,
    .runbook table td + td {
        border-left: 1px solid var(--line-hair);
    }

    .runbook table tr:last-child td {
        border-bottom: none;
    }

.runbook ul,
.runbook ol {
    padding-left: 1.4rem;
}

.runbook li {
    margin: 0.2rem 0;
}

/* ---------- 폼 검증 (상태 스탬프 팔레트와 정합) ---------- */

.valid.modified:not([type=checkbox]) {
    border-color: var(--status-good-ink);
}

.invalid {
    border-color: var(--status-critical-ink);
}

.validation-message,
.text-danger {
    color: var(--status-critical-ink);
}

.validation-message {
    font-size: 0.85rem;
}

/* ---------- Blazor 오류 표시 ---------- */

.blazor-error-boundary {
    background: var(--status-critical-bg);
    border: 1.5px solid var(--status-critical-ink);
    border-radius: 0;
    padding: 1rem 1.2rem;
    color: var(--status-critical-ink);
}

    .blazor-error-boundary::after {
        content: "오류가 발생했습니다.";
    }

/* ---------- 고대비 모드(강제 색상) 존중 ---------- */

/* 이 세계의 포커스 링은 box-shadow로 그린다 — 고대비 모드는 그림자를 통째로 지우므로
   outline: none 을 선언해 둔 자리에서 포커스가 사라진다. 시스템 색 윤곽선으로 되돌린다.
   (지워야 할 선언이 outline: none 이라 이 모드에서만 !important를 쓴다.) */
@media (forced-colors: active) {
    :focus-visible {
        outline: 2px solid Highlight !important;
        outline-offset: 2px;
    }

    /* 서랍 안 현재 장 표시는 3px 주서 inset 그림자 하나에 걸려 있다 — 그림자가 지워지면
       굵기만 남아 어느 항목인지 읽히지 않으므로 밑줄로 한 번 더 말한다.
       밴드·탭의 3px 밑줄은 보더라 강제 색상에서도 살아남는다(꺼진 쪽은 transparent 그대로). */
    .nav-menu .menu-item.active {
        text-decoration: underline;
        text-decoration-thickness: 2px;
        text-underline-offset: 3px;
    }
}

/* ---------- 모션 축소 요청 존중 ---------- */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}

/* ── 계정 다중 선택기 · 구성원 고르기 (ADR-0011) ───────────────────────────
   칩 하나는 기존 .ad-picker-chip 그대로 쓰고, 여기서는 그 칩을 세로로 쌓는 그릇만 정한다. */
.ad-multipicker {
    display: grid;
    gap: 0.5rem;
}

.ad-multipicker-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.35rem;
}

/* 제거할 구성원을 고르는 목록 — 한 줄에 한 사람, 체크박스가 줄의 시작점이다. */
.member-choice {
    list-style: none;
    margin: 0.5rem 0;
    padding: 0;
    display: grid;
    gap: 0.25rem;
    max-height: 18rem;
    overflow-y: auto;
    border: 1.5px solid var(--line-medium);
    padding: 0.4rem;
}

    .member-choice label {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        padding: 0.15rem 0.2rem;
        cursor: pointer;
    }

    .member-choice .cell-mono {
        color: var(--ink-2);
    }

/* ---------- 추이 막대 (로그온 소요시간) ----------
   차트는 표의 대체가 아니라 표 옆의 요약이다. 같은 숫자를 아래 표가 그대로 싣고,
   막대에는 높이와 라벨이 함께 있어 색만으로 값을 읽지 않는다. */
.trend-chart {
    margin: 0.75rem 0 0.25rem;
    background: var(--paper);
    border: 1.5px solid var(--line-medium);
    padding: 0.75rem 0.85rem 0.5rem;
    overflow-x: auto;
}

    .trend-chart svg {
        display: block;
        max-width: 100%;
        height: auto;
    }

    /* 중앙값은 잉크로 채운 막대, p90은 같은 자리에 겹치는 주서 윤곽선. */
    .trend-chart .bar-median {
        fill: var(--ink-2);
    }

    .trend-chart .bar-p90 {
        fill: none;
        stroke: var(--accent);
        stroke-width: 1.5;
    }

    .trend-chart .axis-line {
        stroke: var(--line-medium);
        stroke-width: 1;
    }

    .trend-chart .grid-line {
        stroke: var(--line-hair);
        stroke-width: 1;
    }

    /* 표제란 항목명과 같은 단계 - 도면 안의 가장 작은 '찍힌 글자'다. */
    .trend-chart .tick-label,
    .trend-chart .bar-label {
        font-family: var(--font-label);
        font-size: 0.68rem;
        fill: var(--ink-3);
    }

/* 범례 — 색과 형태를 글자로 한 번 더 말한다. */
.trend-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    margin: 0.35rem 0 0;
    padding: 0;
    list-style: none;
    font-size: 0.8rem;
    color: var(--ink-2);
}

    .trend-legend li {
        display: flex;
        align-items: center;
        gap: 0.35rem;
    }

    .trend-legend i {
        display: inline-block;
        width: 0.8rem;
        height: 0.8rem;
    }

    .trend-legend .swatch-median {
        background: var(--ink-2);
    }

    .trend-legend .swatch-p90 {
        background: transparent;
        border: 1.5px solid var(--accent);
    }
