/*! adriven-ui 1.7.0 — 에이드리븐 ERP 공용 UI */

/*
  이 파일 하나가 네 앱(포털·ERP / 계약관리 / 인사·근태 / 슬라이드)의 시각
  기반이다. 빌드 도구도 npm도 Sass도 쓰지 않는다.

  ## 왜 서브모듈(vendor/erp-design-tokens)을 대신하는가

  그 파일은 "공유 토큰"이었지만 실제로 공유되지 않았다 — 네 앱 중 1.5개만
  쓰고, 슬라이드 앱은 색상 코드를 손으로 베껴 자기 토큰을 따로 갖고 있고,
  거기서는 --radius-sm이 4px(여기는 6px)이다. 무엇보다 **버전이 없다**:
  커밋 2개, 태그 0개, 두 앱 모두 heads/master. 그래서 아무도 안전하게 고칠
  수 없었고, 실제로 다크 모드 --primary 누락을 발견했을 때 팀은 이 파일을
  고치지 않고 dashboard.css에서 우회했다.

  이제 **파일 이름에 버전이 있다.** 각 앱이 이 파일을 자기 저장소에 복사해
  커밋한다(GOV.UK 릴리스 zip, Salesforce의 파일 내 버전 배너와 같은 방식).
  갱신은 CI가 상류와 비교해 알려준다 — 서브모듈이 구조적으로 못 주는 신호다.

  ## 레이어 — 이행 중에 아무것도 깨지지 않게 하는 장치

  레이어에 들어 있지 **않은** CSS는 레이어 안의 모든 CSS를 이긴다.
  화면 CSS(app.css)는 레이어 밖이므로 손대기 전까지 계속 이긴다. 그리고 ad.deprecated가 맨 앞(= 가장 약함)이라 옛 토큰 이름 호환이
  새 규칙을 절대 못 이긴다. Salesforce Lightning이 같은 순서를 쓴다.
  브라우저 지원 96%(2022년 이후 전 브라우저).

  ## 다크 모드는 없다

  2026-09-09 결정. 예전 파일은 다크용 80줄을 갖고 있었는데 그중 40개 선언이
  완전 중복이었고, data-theme를 써 넣는 코드가 세 저장소 어디에도 없어서
  **아무도 켤 수 없었다.** OS 설정이 다크인 사람에게만 우연히 켜지고, 그
  상태에서 링크 명암비가 3.34(기준 4.5)로 미달이었다. 절반 고장난 기능을
  유지하는 대신 없앤다. 나중에 필요해지면 2층 토큰만 다시 정의하면 된다 —
  그래서 컴포넌트가 1층 색을 직접 쓰지 못하게 해 두었다.
*/

@layer ad.deprecated, ad.tokens, ad.base, ad.component;

/* ==========================================================================
   1층 — 원시. 팔레트와 눈금뿐. **컴포넌트에서 직접 쓰지 않는다.**
   ========================================================================== */

@layer ad.tokens {
  :root {
    /* --- 브랜드 (2026-09-09: 에이드리븐 브랜드 색 #1b67b2로 확정) ---------
       같은 색조(210도)에서 명도만 옮겨 만든 단계다. 괄호 안은 흰 배경 대비.
       예전 청록(#0e7c86, 4.95)보다 브랜드 색이 오히려 대비가 좋다(5.79). */
    --ad-blue-50:  #f2f6fa;   /*  1.09 — 선택된 메뉴 배경 */
    --ad-blue-100: #dbe6f0;   /*  1.27 — 배지 배경 */
    --ad-blue-200: #a6ccf2;   /*  1.67 */
    --ad-blue-300: #68a9e8;   /*  2.49 */
    --ad-blue-400: #2a85df;   /*  3.81 — 큰 글자·테두리만 */
    --ad-blue-500: #1e71c3;   /*  4.99 */
    --ad-blue-600: #1b67b2;   /*  5.79 — 브랜드. 버튼 배경(흰 글자 5.79) */
    --ad-blue-700: #15528e;   /*  7.99 — 링크·강조 글자, 버튼 hover */
    --ad-blue-800: #11406f;   /* 10.57 — 누른 상태 */
    --ad-blue-900: #0c2e50;   /* 13.80 */

    /* --- 중성 --------------------------------------------------------------
       파란기가 들어 있는 회색이다(색조 약 215도). 순수 무채색 회색은 화면에서
       탁하고 값싸 보이며, Vercel·Linear·GitHub 모두 색조를 넣는다. 이건 예전
       파일에서 **잘 되어 있던 부분**이라 값을 유지한다 — 명암비가 기준에
       미달했던 두 단계만 조정했다. */
    --ad-gray-00: #ffffff;
    --ad-gray-05: #f8f9fb;
    --ad-gray-10: #f2f4f7;
    --ad-gray-15: #eef1f5;
    --ad-gray-20: #e7ebf0;   /* 신규 — 표 행 구분선이 거의 안 보였다 */
    --ad-gray-30: #d4dae2;   /* 1.41 (예전 #dde2e8은 1.30) — GitHub 수준으로 */
    --ad-gray-50: #6b7280;   /* 4.83 (예전 #8991a0은 3.17로 기준 미달) */
    --ad-gray-60: #5b6472;   /* 6.19 */
    --ad-gray-90: #1c222b;   /* 14.9 */

    /* --- 상태 --------------------------------------------------------------
       값은 예전 것을 유지한다(전부 대비 양호). 바꾸는 것은 **쓰는 규칙**이다:
       기본은 회색, 색은 "사람이 조치해야 하는 것"에만. 지금 알약이 102번
       쓰이는데 정상 건까지 초록이라 표가 길어지면 색이 정보를 잃는다. */
    --ad-red-50:   #fce8e8;
    --ad-red-600:  #c02626;
    --ad-amber-50: #fdecd6;
    --ad-amber-600:#9a5208;   /* 예전 #b5620a는 알약 배경 위 3.85로 미달 */
    --ad-green-50: #e2f6ea;
    --ad-green-600:#1a7a41;

    /* --- 모듈 색 ------------------------------------------------------------
       **상태색이 아니다.** 상태색(빨강·주황·초록)은 "사람이 조치해야 하는
       것"을 가리키고, 이 색들은 **어느 모듈인가**를 가리킨다 — 길찾기다.
       Notion 사이드바 아이콘, Linear 프로젝트 색, Google Workspace 앱 색이
       같은 용도로 쓰는 그것이다.

       그래서 쓰는 자리도 하나로 묶어 둔다: **아이콘 칩 안에서만** 쓴다.
       카드 배경이나 글자에 쓰면 화면이 알록달록해지고, 그때부터는 색이
       상태를 뜻하는지 모듈을 뜻하는지 아무도 모른다.

       색조를 브랜드(210°)에서 충분히 벌리고, 상태색과 헷갈리지 않게
       골랐다(초록·빨강 계열을 피했다). 괄호 안은 **자기 칩 배경 위 대비**. */
    --ad-teal-50:    #d3ebe6;
    --ad-teal-700:   #0f6b5e;   /* 5.11 */
    --ad-violet-50:  #e4dff5;
    --ad-violet-700: #5a3cb8;   /* 5.83 */
    --ad-magenta-50: #f6dfea;
    --ad-magenta-700:#a32d6b;   /* 5.30 */
    --ad-orange-50:  #f7e3d4;
    --ad-orange-700: #9a5208;   /* 4.71 — amber-600과 같은 값(경고색과 색조를
                                   공유하지만 칩 안에서만 쓰므로 섞이지 않는다) */
    --ad-lime-50:    #e7f0d5;
    --ad-lime-700:   #4d6b16;   /* 5.20 — 영업관리(1.6.0). 색환에서 가장 넓게
                                   비어 있던 자리가 여기였다(주황 30° 다음이
                                   청록 172°). 상태 초록(#1a7a41, 144°)과는
                                   63° 떨어져 있고, 무엇보다 이 색은 아이콘
                                   칩 안에만 나타나서 상태 알약과 같은
                                   자리에 서는 일이 없다 — 주황이 경고색과
                                   색조를 공유해도 되는 것과 같은 이유다. */

    /* --- 눈금 --------------------------------------------------------------
       48·64px을 추가한다. 예전 최대가 32px이라 "구역이 나뉘었다"는 느낌을
       만들 수가 없었다. */
    --ad-size-1: 4px;
    --ad-size-2: 8px;
    --ad-size-3: 12px;
    --ad-size-4: 16px;
    --ad-size-5: 20px;
    --ad-size-6: 24px;
    --ad-size-8: 32px;
    --ad-size-12: 48px;
    --ad-size-16: 64px;

    /* 모서리는 3단계로 줄인다(예전 5단계 중 실제로 쓰인 것은 3개다). */
    --ad-radius-1: 6px;      /* 작은 요소 */
    --ad-radius-2: 10px;     /* 카드·패널 */
    --ad-radius-full: 9999px;

    /* --------------------------------------------------------------------
       2층 — 의미. 용도가 이름에 있다. **컴포넌트는 이것만 쓴다.**
       전경/배경은 반드시 짝으로 둔다 — 짝이 없어서 명암비 미달 4건이
       생겼다. 모든 짝은 4.5:1 이상이다.
       -------------------------------------------------------------------- */
    --ad-bg-page:    var(--ad-gray-10);
    --ad-bg-surface: var(--ad-gray-00);
    --ad-bg-sunken:  var(--ad-gray-05);
    --ad-bg-hover:   var(--ad-gray-05);

    --ad-fg-default: var(--ad-gray-90);   /* 14.9 on surface */
    --ad-fg-muted:   var(--ad-gray-60);   /*  6.19 */
    --ad-fg-subtle:  var(--ad-gray-50);   /*  4.83 — 표 머리글·캡션 */
    --ad-fg-inverse: var(--ad-gray-00);

    --ad-border:        var(--ad-gray-30);
    --ad-border-soft:   var(--ad-gray-20);

    --ad-brand-bg:   var(--ad-blue-600);  /* 버튼 배경 + 흰 글자 5.79 */
    --ad-brand-fg:   var(--ad-blue-700);  /* 링크·강조 글자 7.99 */
    --ad-brand-wash: var(--ad-blue-50);   /* 선택된 메뉴 배경 */
    --ad-brand-hover: var(--ad-blue-700);
    --ad-brand-active: var(--ad-blue-800);

    --ad-danger-fg: var(--ad-red-600);    --ad-danger-bg: var(--ad-red-50);
    --ad-warn-fg:   var(--ad-amber-600);  --ad-warn-bg:   var(--ad-amber-50);
    --ad-ok-fg:     var(--ad-green-600);  --ad-ok-bg:     var(--ad-green-50);

    /* 모듈 색도 **짝으로** 정의한다 — 전경만 바꾸다 대비가 깨지는 일을
       막는 것이 이 규칙의 목적이고, 여기도 예외가 아니다. */
    --ad-mod-crm-fg:        var(--ad-lime-700);    --ad-mod-crm-bg:        var(--ad-lime-50);
    --ad-mod-sales-fg:      var(--ad-blue-700);    --ad-mod-sales-bg:      var(--ad-blue-100);
    --ad-mod-accounting-fg: var(--ad-teal-700);    --ad-mod-accounting-bg: var(--ad-teal-50);
    --ad-mod-contract-fg:   var(--ad-violet-700);  --ad-mod-contract-bg:   var(--ad-violet-50);
    --ad-mod-people-fg:     var(--ad-magenta-700); --ad-mod-people-bg:     var(--ad-magenta-50);
    --ad-mod-slides-fg:     var(--ad-orange-700);  --ad-mod-slides-bg:     var(--ad-orange-50);

    /* 그림자는 5단계에서 2개로. 규칙: 가만히 있는 것 = 테두리, 반응하는 것 =
       그림자(Stripe 규율). 예전에는 5개를 정의하고 2개만 썼다. */
    --ad-shadow-card:   0 1px 3px rgba(20, 24, 30, 0.06);
    --ad-shadow-raised: 0 4px 12px rgba(20, 24, 30, 0.10);

    /* 상단 바 높이. 화면 CSS가 `calc(100vh - 61px)`로 손계산한 값을
       박아 두었는데, 글자 크기나 여백을 바꾸는 순간 어긋난다. */
    --ad-topbar-h: 56px;

    /* 모션 — `all`을 쓰지 않는다. 크기·위치까지 애니메이션 대상이 되어
       화면이 미세하게 떨린다. */
    --ad-motion-fast: 120ms cubic-bezier(0.2, 0, 0, 1);
    --ad-motion-base: 160ms cubic-bezier(0.2, 0, 0, 1);

    /* 서체 — 1.1.0에서 실물이 들어왔다(pretendard.css). 그 파일을 이것보다
       **먼저** 링크해야 한다. 시스템 글꼴을 뒤에 남겨 두는 이유: 폰트 조각이
       도착하기 전(font-display: swap)과, 조각에 없는 글자(직원이 입력한
       희귀 한자 등)에 쓰인다. */
    --ad-font-sans: "Pretendard Variable", -apple-system, BlinkMacSystemFont,
      system-ui, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
    --ad-font-size: 0.9375rem;   /* 15px */
  }
}

/* ==========================================================================
   ad.base — 브라우저 기본값 정규화

   `line-height`가 예전 CSS 501줄에 **0건**이었다. 그래서 브라우저가 글꼴
   기본값을 쓰는데 맑은 고딕은 1.33배이고 한글 권장은 1.5배 이상이다. 카드
   안의 제목과 설명이 붙어 보이던 이유다.
   ========================================================================== */

@layer ad.base {
  :root {
    color-scheme: light;
  }
  body {
    background: var(--ad-bg-page, #f2f4f7);
    color: var(--ad-fg-default, #1c222b);
    font-family: var(--ad-font-sans);
    font-size: var(--ad-font-size);
    line-height: 1.7;
  }
  /* 표 안은 촘촘하게, 표 밖은 널찍하게 — 2026-09-09 밀도 규칙.
     AWS Cloudscape의 판정을 따른다: 조밀은 목록·표에만, 폼·오류·빈 화면은
     널찍하게. 두 디자이너가 "더 조밀하게" vs "더 널찍하게"로 갈렸는데 서로
     다른 표면을 말하고 있었다. */
  table {
    line-height: 1.5;
    font-size: 0.875rem;   /* 14px — 표 안 */
  }

  /* --- 크기 눈금 ---------------------------------------------------------
     예전에는 대시보드에서 **가장 큰 글자가 16px**이었고, 섹션 제목과 카드
     이름의 차이가 1px이었다. 눈이 어디부터 볼지 판단할 근거가 없었다.

     세 가지 규칙이 들어 있다:

     1. **큰 글자에는 음수 자간.** 글꼴은 본문 크기에서 자연스럽게 보이도록
        자간이 설계돼 있어서, 키우면 글자 사이가 상대적으로 벙벙해진다.
     2. **작은 한글에는 양수 자간과 대문자 변환을 쓰지 않는다.** 한글에는
        대소문자가 없어 `text-transform: uppercase`는 무의미하고(섞인 영문만
        튄다), 자간을 벌리면 낱글자가 흩어진다. 정부 디자인시스템 KRDS도
        24px 이하는 자간 0을 규정한다.
     3. **줄 높이를 반드시 지정한다.** 예전에는 CSS 501줄에 line-height가
        0건이라 글꼴 기본값(맑은 고딕 1.33)이 쓰였다. 그리고 함정이 있다 —
        줄 높이 없이 Pretendard로 바꾸면 기본값이 1.19라 **더 답답해진다.**
        그래서 폰트 교체와 줄 높이 지정은 반드시 같이 간다. */
  h1 { font-size: 1.375rem; font-weight: 700; line-height: 1.4; letter-spacing: -0.02em; }
  h2 { font-size: 1.125rem; font-weight: 700; line-height: 1.4; letter-spacing: -0.015em; }
  h3 { font-size: 0.9375rem; font-weight: 600; line-height: 1.5; letter-spacing: -0.01em; }
  h4 { font-size: 0.875rem; font-weight: 600; line-height: 1.5; }

  /* **아이콘 스프라이트는 자리를 차지하면 안 된다.**
     `_icons.html`의 뿌리 `<svg>`에 `hidden`이 붙어 있는데, SVG에서는 그게
     듣지 않는다 — 브라우저 기본 스타일의 `svg:not(:root)`(명시도 0,1,1)가
     `[hidden]`(0,1,0)을 이기기 때문이고 Chrome·Firefox 공통이다. 그래서
     스프라이트가 **300×150 상자로 그려져 모든 화면 맨 위에 150px짜리 빈
     띠**를 만들고 있었다(2026-09-10 발견). 작성자 스타일은 브라우저 기본을
     이기므로 한 줄이면 된다. */
  svg[hidden] { display: none; }

  /* 금액·수량은 폭이 같은 숫자로. 없으면 오른쪽 정렬한 금액이 미세하게
     흔들려 보인다. `.num`에는 이미 있었지만 KPI·합계 등에서 빠져 있었다. */
  .num, td, th, input[type="number"] {
    font-variant-numeric: tabular-nums;
  }

  /* 키보드로 옮겨 다닐 때 지금 어디인지 보여야 한다. 예전에는 포커스 표시가
     저장소 전체에서 한 곳뿐이었고, 그 색조차 명암비 1.72로 사실상 안 보였다.
     안쪽 링을 배경색으로 깔아 어떤 배경에서도 바깥 링이 읽힌다(GOV.UK 원리). */
  :focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--ad-bg-surface, #fff),
                0 0 0 4px var(--ad-brand-bg, #1b67b2);
    border-radius: 2px;
  }

  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      transition-duration: 0.01ms !important;
      animation-duration: 0.01ms !important;
    }
  }
}

/* ==========================================================================
   ad.deprecated — 옛 토큰 이름 호환

   **맨 앞 레이어 = 가장 약함.** 그래서 이 블록이 새 규칙을 절대 못 이긴다.
   dashboard.css와 accounting.css가 쓰는 이름 43개를 새 토큰으로 잇는다
   (정의된 184개 중 실제로 쓰이는 것은 43개뿐이었다).

   여기 있는 이름은 **다음 메이저에서 삭제한다.** 컴포넌트 층을 만들면서
   호출부를 새 이름으로 옮기고, 다 옮기면 이 블록이 비어 사라진다.

   `--surface-2`와 `--text`도 넣어 둔다 — 정의된 적이 없는데 청구서 상세가
   쓰고 있어서, CSS 규칙상 그 선언이 무효가 되어 「초안」·「승인 대기」 안내
   상자가 배경 없이 떠 있었다. 이 PR에서 그 두 줄은 지우지만, 다른 곳에
   같은 이름이 또 있을 경우를 대비해 이어 둔다.
   ========================================================================== */

@layer ad.deprecated {
  :where(:root) {
    --primary:          var(--ad-brand-bg);
    --primary-hover:    var(--ad-brand-hover);
    --primary-light:    var(--ad-blue-400);
    --success:          var(--ad-ok-fg);
    --success-bg:       var(--ad-ok-bg);
    --warning:          var(--ad-warn-fg);
    --warning-bg:       var(--ad-warn-bg);
    --danger:           var(--ad-danger-fg);
    --danger-bg:        var(--ad-danger-bg);

    --bg-primary:       var(--ad-bg-page);
    --bg-card:          var(--ad-bg-surface);
    --bg-light:         var(--ad-bg-sunken);
    --bg-hover:         var(--ad-bg-hover);
    --surface-2:        var(--ad-bg-sunken);

    --text-primary:     var(--ad-fg-default);
    --text:             var(--ad-fg-default);
    --text-secondary:   var(--ad-fg-muted);
    --text-tertiary:    var(--ad-fg-subtle);
    --text-inverse:     var(--ad-fg-inverse);

    --border-color:     var(--ad-border);
    --border-light:     var(--ad-border-soft);

    --sidebar-bg:          var(--ad-bg-surface);
    --sidebar-text:        var(--ad-fg-muted);
    --sidebar-text-hover:  var(--ad-fg-default);
    --sidebar-border:      var(--ad-border);
    --sidebar-active-bg:   var(--ad-brand-wash);
    --sidebar-active-text: var(--ad-brand-fg);

    --header-bg:        var(--ad-bg-surface);
    --header-text:      var(--ad-fg-default);
    --header-border:    var(--ad-border);

    --shadow-sm:        var(--ad-shadow-card);
    --shadow-md:        var(--ad-shadow-raised);

    --radius-sm:        var(--ad-radius-1);
    --radius-md:        var(--ad-radius-1);
    --radius-lg:        var(--ad-radius-2);
    --radius-full:      var(--ad-radius-full);

    --space-1:          var(--ad-size-1);
    --space-2:          var(--ad-size-2);
    --space-3:          var(--ad-size-3);
    --space-4:          var(--ad-size-4);
    --space-5:          var(--ad-size-5);
    --space-6:          var(--ad-size-6);
    --space-8:          var(--ad-size-8);

    --transition-fast:  var(--ad-motion-fast);
    --font-family:      var(--ad-font-sans);
    --font-size-base:   var(--ad-font-size);
  }
}


/* ==========================================================================
   ad.component — 컴포넌트

   지금은 알림 하나뿐이다. 나머지 7개(패널 본문·표 스크롤·빈 화면·폼 행·
   입력칸 폭·버튼 묶음·세로 간격)는 PR 3~5에서 들어온다.

   알림을 먼저 만드는 이유: 지금 같은 「알림」이 **세 가지로 구현**돼 있고,
   그중 하나가 실제로 깨져 있었다.

   1. `.error-banner` — 22회. 그런데 이 클래스는 dashboard.css의 로그인
      섹션에 정의돼 있고 **빨강**이다. 청구서 상세의 「초안」·「승인 대기」는
      오류가 아니라 안내인데 이걸 쓰고 있었다.
   2. `.panel` + 인라인 `border-left: 3px solid #c0392b` — 4회. `#c0392b`는
      토큰이 아니다(`--danger`는 `#c02626`이니 **비슷하지만 다른 빨강**).
   3. `.error-banner` + 정의되지 않은 토큰으로 색을 지우기 — 2회. 정의 없는
      변수를 쓴 선언은 무효가 되어 **배경이 투명으로 떨어졌다.**

   모든 `var()`에 비상값을 적는다 — 토큰 이름이 틀려도 화면이 깨지지 않게
   (GOV.UK v6·IBM Carbon이 컴파일 CSS에서 하는 방식). 위 3번 사고의 직접
   처방이다.
   ========================================================================== */

@layer ad.component {
  .ad-notice {
    --ad-notice-fg: var(--ad-fg-default, #1c222b);
    --ad-notice-bg: var(--ad-bg-sunken, #f8f9fb);
    --ad-notice-accent: var(--ad-border, #d4dae2);

    color: var(--ad-notice-fg);
    background: var(--ad-notice-bg);
    border: 1px solid var(--ad-border-soft, #e7ebf0);
    border-left: 3px solid var(--ad-notice-accent);
    border-radius: var(--ad-radius-1, 6px);
    padding: var(--ad-size-4, 16px) var(--ad-size-5, 20px);
    line-height: 1.7;
  }

  /* 변종은 **변수만 재지정**한다. 속성을 다시 쓰지 않는다(Bootstrap 5.3
     방식) — 그래서 클래스가 겹칠 때 무엇이 이기는지 읽을 필요가 없다. */
  .ad-notice--info   { --ad-notice-accent: var(--ad-brand-bg, #1b67b2); }
  .ad-notice--warn   { --ad-notice-accent: var(--ad-warn-fg, #9a5208);
                       --ad-notice-bg: var(--ad-warn-bg, #fdecd6); }
  .ad-notice--danger { --ad-notice-accent: var(--ad-danger-fg, #c02626);
                       --ad-notice-bg: var(--ad-danger-bg, #fce8e8); }
  .ad-notice--ok     { --ad-notice-accent: var(--ad-ok-fg, #1a7a41);
                       --ad-notice-bg: var(--ad-ok-bg, #e2f6ea); }
}

/* ==========================================================================
   아이콘과 로고 (1.1.0)
   ========================================================================== */

@layer ad.component {
  /* Lucide 인라인 스프라이트를 `<use href="#i-target">`으로 꺼내 쓴다.
     `stroke: currentColor`라 글자색을 그대로 따라가므로, 선택된 메뉴에서
     글자만 색이 바뀌고 아이콘은 그대로였던 문제가 사라진다.

     Lucide는 24px 기준 선 두께 2로 그려져 있어서, 18px로 줄이면 선이
     상대적으로 두꺼워 보인다. 그래서 두께를 낮춘다. */
  .ad-icon {
    inline-size: 1.125rem;      /* 18px — 사이드바 */
    block-size: 1.125rem;
    stroke-width: 1.75;
    flex: none;
    /* 글자와 같은 줄에서 시각적 중심을 맞춘다. baseline 정렬은 아이콘이
       글자보다 위로 떠 보인다. */
    vertical-align: -0.19em;
  }
  .ad-icon--sm { inline-size: 1rem; block-size: 1rem; stroke-width: 2; }
  .ad-icon--lg { inline-size: 1.25rem; block-size: 1.25rem; stroke-width: 1.6; }

  /* --- 로고 ---------------------------------------------------------------
     로고를 새로 디자인하는 게 아니다. **텍스트를 텍스트답게 처리**하는
     것만으로 달라진다. 예전에는 회사 이름이 카드 이름과 똑같은 15px/600
     텍스트 한 줄이었고, 파비콘도 없어서 탭에 회색 지구본이 떴다. */
  .ad-logo {
    display: inline-flex;
    align-items: center;
    gap: var(--ad-size-2, 8px);
    text-decoration: none;
    color: inherit;
  }
  .ad-logo__mark {
    inline-size: 1.75rem;
    block-size: 1.75rem;
    border-radius: var(--ad-radius-1, 6px);
    background: var(--ad-brand-bg, #1b67b2);
    color: var(--ad-fg-inverse, #fff);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.9375rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    flex: none;
  }
  .ad-logo__name { font-size: 1rem; font-weight: 700; letter-spacing: -0.015em; }
  .ad-logo__sub {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--ad-fg-subtle, #6b7280);
  }

  /* 사용자 이니셜. "누구로 로그인했는지"가 즉시 읽히고, 회사 색이 화면에
     한 번 더 등장한다. */
  .ad-avatar {
    inline-size: 1.75rem;
    block-size: 1.75rem;
    border-radius: var(--ad-radius-full, 9999px);
    background: var(--ad-brand-wash, #f2f6fa);
    color: var(--ad-brand-fg, #15528e);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    font-weight: 700;
    flex: none;
  }
}


/* ==========================================================================
   부품 (1.2.0)

   인라인 스타일 293개의 값을 전부 뽑아 세어 보니 취향이 흩어진 게 아니라
   **몇 개 모양의 반복**이었다. 그 말은 컴포넌트로 만들어야 할 것이 안
   만들어져 있고, 화면마다 손으로 다시 그려지고 있었다는 뜻이다.

     overflow-x:auto                  36회 (36곳 전부 동일)
     padding: var(--space-5) 계열     35회
     margin-bottom: var(--space-6)    33회
     colspan + class="muted"          빈 화면
     .error-banner                    21회
     border-left: 3px solid #c0392b    4회 (토큰이 아닌 생 색상값)
   ========================================================================== */

@layer ad.component {

  /* --- 표 스크롤 상자 ---------------------------------------------------
     36곳의 `<div style="overflow-x:auto">`를 대신한다. 그런데 그냥 클래스로
     바꾸는 것보다 두 가지를 더 한다.

     **① 키보드로 접근 가능하게 만든다.** 스크롤되는 상자는 키보드로도 스크롤
     할 수 있어야 하고 이건 WCAG 요구사항이다(2.1.1 키보드, 1.4.10 리플로).
     `role="region"` + `aria-labelledby` + `tabindex="0"`이면 스크린리더가
     "표를 위한 스크롤 영역"으로 읽어 주고 Tab으로 들어갈 수 있다. 매크로가
     그 속성을 붙인다(_ui.html의 table_scroll).

     **② 가장자리에 그림자를 깐다.** 요즘 브라우저는 조작하기 전까지 스크롤
     바를 숨기므로, 옆으로 더 있다는 표시가 없으면 사용자는 표가 잘린 줄
     모른다. `background-attachment: local`을 쓰면 내용과 함께 움직이는 두
     겹이 끝에 닿을 때 그림자를 가려 준다 — JS 없이 동작한다. */
  .ad-table-scroll {
    overflow-x: auto;
    background:
      /* 고정: 좌우 끝의 그림자 */
      linear-gradient(to right, rgba(20,24,30,.10), rgba(20,24,30,0)) 0 0 / 14px 100% no-repeat,
      linear-gradient(to left,  rgba(20,24,30,.10), rgba(20,24,30,0)) 100% 0 / 14px 100% no-repeat,
      /* 함께 움직임: 끝에 닿으면 위 그림자를 덮는다 */
      linear-gradient(to right, var(--ad-bg-surface, #fff), var(--ad-bg-surface, #fff)) 0 0 / 24px 100% no-repeat,
      linear-gradient(to left,  var(--ad-bg-surface, #fff), var(--ad-bg-surface, #fff)) 100% 0 / 24px 100% no-repeat;
    background-attachment: scroll, scroll, local, local;
  }
  /* 초점이 들어왔을 때 어디인지 보여야 한다. 바깥 그림자 대신 안쪽 테두리를
     쓰는 이유: 이 상자는 패널 안에 꽉 차 있어서 바깥 링이 잘린다. */
  .ad-table-scroll:focus-visible {
    outline: none;
    box-shadow: inset 0 0 0 2px var(--ad-brand-bg, #1b67b2);
  }

  /* --- 격자 표: 첫 열과 머리글을 붙여 둔다 (1.4.0) -----------------------
     예산은 계정 × 12달이라 열이 13개다. 옆으로 밀면 **계정과목이 화면에서
     사라져서** 무슨 숫자를 보고 있는지 알 수 없었다. 머리글도 같은 문제다 —
     계정이 스무 개면 아래쪽 줄에서는 그 열이 몇 월인지 보이지 않는다.

     `position: sticky`가 그것을 푸는 표준 방법인데, 표에서는 걸림돌이 하나
     있다: **`border-collapse: collapse`면 붙어 있는 칸의 테두리가 그려지지
     않는다.** 테두리 소유자가 칸이 아니라 표라서 칸과 함께 움직이지 않기
     때문이고, Chrome·Safari 공통이다. 그래서 이 변종만 `separate`로 두고
     칸이 자기 테두리를 갖게 한다(우리 표는 아래쪽 테두리만 쓰므로 겹쳐서
     두꺼워지는 문제가 없다).

     높이를 70vh로 제한하는 이유: 머리글이 「붙는」 대상은 페이지가 아니라
     **스크롤되는 상자**다. 상자에 높이 제한이 없으면 세로로 스크롤될 일이
     없어서 머리글이 붙을 일도 없다. 짧은 격자는 제한에 닿지 않으니 지금과
     똑같이 보이고, 긴 격자만 상자 안에서 스크롤된다. */
  .ad-table-scroll--grid { max-block-size: 70vh; }
  .ad-table-scroll--grid table {
    border-collapse: separate;
    border-spacing: 0;
  }
  .ad-table-scroll--grid thead th {
    position: sticky;
    inset-block-start: 0;
    z-index: 2;
    /* 아래 내용이 비쳐 보이면 안 된다 — 붙어 있는 칸은 그 위를 지나간다. */
    background: var(--ad-bg-surface, #fff);
  }
  .ad-table-scroll--grid :is(thead, tbody, tfoot) tr > :first-child {
    position: sticky;
    inset-inline-start: 0;
    z-index: 1;
    background: var(--ad-bg-surface, #fff);
    /* 테두리 대신 그림자를 쓴다 — 지나가는 내용과의 경계가 필요하고,
       `separate`에서도 오른쪽 한 줄만 확실히 그려진다. */
    box-shadow: 1px 0 0 var(--ad-border-soft, #e7ebf0);
  }
  /* 두 축이 만나는 왼쪽 위 칸은 둘보다 위에 있어야 한다. */
  .ad-table-scroll--grid thead tr > :first-child { z-index: 3; }

  /* --- 모듈 아이콘 칩 (1.5.0) --------------------------------------------
     대시보드 카드가 **글자만 넷** 있어서 어느 것이 무엇인지 한눈에 안
     들어왔다(2026-09-18 Jay). 카드마다 모듈 색 칩 + 아이콘을 왼쪽에 둔다.

     색은 칩 **안에서만** 쓴다 — 카드 배경·글자는 그대로다. 그래야 "색 =
     조치가 필요한 것"이라는 나머지 화면의 규칙과 부딪히지 않는다. */
  .ad-tile-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 36px;
    block-size: 36px;
    border-radius: var(--ad-radius-1, 6px);
    flex: none;
    /* 기본값은 브랜드 — 변종이 변수만 바꿔 끼운다(알림 부품과 같은 방식). */
    background: var(--ad-tile-icon-bg, var(--ad-brand-wash, #f2f6fa));
    color: var(--ad-tile-icon-fg, var(--ad-brand-fg, #15528e));
  }
  .ad-tile-icon--crm        { --ad-tile-icon-bg: var(--ad-mod-crm-bg);        --ad-tile-icon-fg: var(--ad-mod-crm-fg); }
  .ad-tile-icon--sales      { --ad-tile-icon-bg: var(--ad-mod-sales-bg);      --ad-tile-icon-fg: var(--ad-mod-sales-fg); }
  .ad-tile-icon--accounting { --ad-tile-icon-bg: var(--ad-mod-accounting-bg); --ad-tile-icon-fg: var(--ad-mod-accounting-fg); }
  .ad-tile-icon--contract   { --ad-tile-icon-bg: var(--ad-mod-contract-bg);   --ad-tile-icon-fg: var(--ad-mod-contract-fg); }
  .ad-tile-icon--people     { --ad-tile-icon-bg: var(--ad-mod-people-bg);     --ad-tile-icon-fg: var(--ad-mod-people-fg); }
  .ad-tile-icon--slides     { --ad-tile-icon-bg: var(--ad-mod-slides-bg);     --ad-tile-icon-fg: var(--ad-mod-slides-fg); }

  /* --- 눈금 전환 (1.4.0) ------------------------------------------------
     같은 표를 달별·분기별·연간으로 바꿔 보는 링크 묶음. **링크다** — 주소에
     상태가 남아야 그 화면을 그대로 공유하고 북마크할 수 있고, 자바스크립트
     없이 동작한다. 지금 보고 있는 것은 `aria-current`로 알린다(색만으로
     표시하면 스크린리더에는 아무 차이가 없다). */
  .ad-segmented {
    display: inline-flex;
    border: 1px solid var(--ad-border-soft, #e7ebf0);
    border-radius: var(--ad-radius-1, 6px);
    overflow: hidden;
  }
  .ad-segmented > a {
    padding: 3px var(--ad-size-3, 12px);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--ad-fg-muted, #5b6472);
    background: var(--ad-bg-surface, #fff);
    text-decoration: none;
  }
  .ad-segmented > a + a { border-inline-start: 1px solid var(--ad-border-soft, #e7ebf0); }
  .ad-segmented > a:hover { background: var(--ad-brand-wash, #f2f6fa); }
  .ad-segmented > a[aria-current="true"] {
    background: var(--ad-brand-bg, #1b67b2);
    color: var(--ad-gray-00, #fff);
  }

  /* --- 목록: 검색 · 정렬 · 페이지 (1.4.0) -------------------------------
     거래처가 이미 152개인데 목록에 검색이 없었다. 조건은 전부 주소에 담고
     (`?q=&sort=&page=`) 여기서는 모양만 준다. */
  .ad-search {
    display: flex;
    gap: var(--ad-size-2, 8px);
    align-items: center;
    padding: var(--ad-size-4, 16px) var(--ad-size-5, 20px);
    border-block-end: 1px solid var(--ad-border-soft, #e7ebf0);
  }
  .ad-search input[type="search"] { min-inline-size: 260px; }

  /* 머리글의 정렬 링크. 글자색을 그대로 쓰고 밑줄을 넣지 않는다 — 표 안의
     모든 머리글이 링크라서 밑줄이 있으면 표가 파랗게 얼룩진다. */
  .ad-sort {
    display: inline-flex;
    align-items: center;
    gap: var(--ad-size-1, 4px);
    color: inherit;
    text-decoration: none;
  }
  .ad-sort:hover { color: var(--ad-brand-fg, #15528e); }
  .ad-sort__mark { font-size: 0.6875rem; }
  /* 정렬되지 않은 열의 표시는 **있지만 조용해야** 한다 — 누를 수 있다는
     것은 알려야 하고, 그렇다고 열 일곱 개가 다 화살표로 소리치면 안 된다. */
  .ad-sort__mark--idle { opacity: 0.35; }

  .ad-pagination {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ad-size-3, 12px);
    align-items: center;
    justify-content: space-between;
    padding: var(--ad-size-3, 12px) var(--ad-size-5, 20px);
    border-block-start: 1px solid var(--ad-border-soft, #e7ebf0);
  }
  .ad-pagination__count {
    margin: 0;
    font-size: 0.8125rem;
    color: var(--ad-fg-muted, #5b6472);
    font-variant-numeric: tabular-nums;
  }
  .ad-pagination__pages {
    display: flex;
    gap: var(--ad-size-1, 4px);
    align-items: center;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .ad-pagination__pages a,
  .ad-pagination__off {
    display: block;
    min-inline-size: 32px;
    padding: 4px var(--ad-size-2, 8px);
    border-radius: var(--ad-radius-1, 6px);
    font-size: 0.8125rem;
    text-align: center;
    text-decoration: none;
    font-variant-numeric: tabular-nums;
  }
  .ad-pagination__pages a { color: var(--ad-brand-fg, #15528e); font-weight: 600; }
  .ad-pagination__pages a:hover { background: var(--ad-brand-wash, #f2f6fa); }
  .ad-pagination__pages a[aria-current="page"] {
    background: var(--ad-brand-bg, #1b67b2);
    color: var(--ad-gray-00, #fff);
  }
  /* 갈 수 없는 곳은 링크가 아니다 — 눌러 봤자 같은 화면이면 링크로 두면
     안 된다(GOV.UK도 이 자리를 링크에서 뺀다). */
  .ad-pagination__off { color: var(--ad-fg-muted, #5b6472); opacity: 0.5; }

  /* --- 패널 -------------------------------------------------------------
     `.panel`과 `.panel-head`는 이미 있었지만 **본문 클래스가 없어서** 안쪽
     여백을 35곳에서 손으로 넣고 있었다. */
  .ad-panel__body { padding: var(--ad-size-5, 20px); }
  .ad-panel__body--tight { padding: var(--ad-size-4, 16px) var(--ad-size-5, 20px); }

  /* 패널 맨 아래의 설명 문단. 값 분포에서 가장 많이 반복된 조합이다
     (`padding: 0 var(--space-5) var(--space-4); margin:0`). 머리 여백이 0인
     이유: 위의 표나 본문이 이미 여백을 갖고 있다. */
  .ad-panel__note {
    padding: 0 var(--ad-size-5, 20px) var(--ad-size-4, 16px);
    margin: 0;
    color: var(--ad-fg-muted, #5b6472);
    font-size: 0.875rem;
    line-height: 1.7;
  }
  .ad-panel__note + .ad-panel__note { padding-top: var(--ad-size-3, 12px); }
  /* 표 바로 아래에 붙는 설명은 위 여백이 필요하다. */
  .ad-table-scroll + .ad-panel__note { padding-top: var(--ad-size-4, 16px); }

  /* --- 빈 화면 -----------------------------------------------------------
     **세 종류를 구분한다.** 지금은 전부 `<td colspan=N class="muted">…없습니다
     </td>` 한 줄이라, 「아직 만든 게 없다」와 「필터에 안 걸렸다」가 같은
     모양이었다. Stripe·Cloudscape가 이 셋을 다른 상태로 다룬다:

       first_run  아직 만든 게 없음  → 가르친다. 동작 하나를 준다.
       no_results 필터에 안 걸림     → 풀어준다. **만들기 버튼을 주지 않는다.**
       all_clear  다 처리됨          → 안심시킨다. **동작 버튼을 주지 않는다.**

     마지막 것이 중요하다 — 결산 점검의 「정리할 항목이 없습니다」는 축하
     상태이고, 거기에 버튼을 두면 뭔가 잘못된 것처럼 읽힌다. */
  .ad-empty {
    padding: var(--ad-size-8, 32px) var(--ad-size-5, 20px);
    text-align: center;
    color: var(--ad-fg-muted, #5b6472);
  }
  .ad-empty__title {
    color: var(--ad-fg-default, #1c222b);
    font-weight: 600;
    margin: 0;
  }
  .ad-empty__hint {
    margin: var(--ad-size-2, 8px) auto 0;
    max-width: 46ch;
    font-size: 0.875rem;
    line-height: 1.7;
  }
  .ad-empty__action { margin-top: var(--ad-size-4, 16px); }
  .ad-empty--clear .ad-empty__title { color: var(--ad-ok-fg, #1a7a41); }

  /* 표 안의 빈 줄. 가운데 정렬하지 않는다 — 표의 첫 칸 위치에서 시작해야
     "이 표가 비었다"로 읽힌다. */
  .ad-empty-row {
    padding: var(--ad-size-6, 24px) var(--ad-size-5, 20px);
    color: var(--ad-fg-muted, #5b6472);
  }
  .ad-empty-row strong { color: var(--ad-fg-default, #1c222b); font-weight: 600; }

  /* --- 증빙 미리보기 ---------------------------------------------------
     경비 폼이 고른 파일의 미리보기를 만드는데, 그 스타일이 **자바스크립트
     문자열 안에** 있었다(`card.style.cssText = 'border:1px solid ' + ...`).
     CSS 파일도, 인라인 속성도 아닌 **세 번째 스타일 경로**였고, 거기에
     토큰이 아닌 `#c0392b`이 또 박혀 있었다.

     JS는 클래스만 붙이고 모양은 여기가 정한다 — 20MB 초과 표시도
     `.ad-thumb--over` 클래스 하나로. */
  .ad-thumb-caption {
    color: var(--ad-fg-muted, #5b6472);
    font-size: 0.875rem;
    margin-block-end: var(--ad-size-2, 8px);
  }
  .ad-thumb-strip {
    display: flex;
    gap: var(--ad-size-3, 12px);
    flex-wrap: wrap;
  }
  .ad-thumb {
    inline-size: 150px;
    border: 1px solid var(--ad-border, #d4dae2);
    border-radius: var(--ad-radius-1, 6px);
    padding: var(--ad-size-2, 8px);
  }
  .ad-thumb--over {
    border-color: var(--ad-danger-fg, #c02626);
    background: var(--ad-danger-bg, #fce8e8);
  }
  .ad-thumb__img {
    inline-size: 100%;
    block-size: 96px;
    object-fit: cover;
    border-radius: var(--ad-radius-1, 6px);
    display: block;
  }
  .ad-thumb__ext {
    block-size: 96px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--ad-bg-sunken, #f8f9fb);
    border-radius: var(--ad-radius-1, 6px);
    font-size: 0.75rem;
    color: var(--ad-fg-muted, #5b6472);
  }
  .ad-thumb__name {
    font-size: 0.75rem;
    margin-block-start: var(--ad-size-1, 4px);
    word-break: break-all;
    line-height: 1.35;
    color: var(--ad-fg-muted, #5b6472);
  }
  .ad-thumb--over .ad-thumb__name { color: var(--ad-danger-fg, #c02626); }

  /* --- 폼 오류 (1.3.0) -------------------------------------------------
     GOV.UK 오류 사양. 색에만 의존하지 않는다 — 요약은 제목 글자를 갖고,
     개별 메시지는 눈에 안 보이는 「오류:」 접두를 갖고, 잘못된 칸은 왼쪽
     굵은 테두리로 **묶음**을 표시한다(테두리가 색과 별개의 채널이다). */
  .ad-error-summary {
    border: 2px solid var(--ad-danger-fg, #c02626);
    border-radius: var(--ad-radius-1, 6px);
    padding: var(--ad-size-4, 16px) var(--ad-size-5, 20px);
    margin-block-end: var(--ad-size-5, 20px);
    background: var(--ad-bg-surface, #fff);
  }
  .ad-error-summary:focus { outline: none; }
  .ad-error-summary__title {
    margin: 0 0 var(--ad-size-2, 8px);
    font-weight: 700;
    color: var(--ad-danger-fg, #c02626);
  }
  .ad-error-summary__list {
    margin: 0;
    padding-inline-start: var(--ad-size-5, 20px);
    line-height: 1.8;
  }
  .ad-error-summary__list a {
    color: var(--ad-danger-fg, #c02626);
    font-weight: 600;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
  }

  .ad-field-error {
    display: block;
    color: var(--ad-danger-fg, #c02626);
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.5;
    margin-block: var(--ad-size-1, 4px);
  }
  /* 잘못된 칸을 묶음째 표시한다. 화면 확대기를 쓰는 사람은 한 번에 좁은
     영역만 보므로, 칸 하나만 빨갛게 하면 그게 오류인지 알 수 없다. */
  .ad-field-group--error {
    border-inline-start: 4px solid var(--ad-danger-fg, #c02626);
    padding-inline-start: var(--ad-size-3, 12px);
  }
  .ad-input--error {
    border-color: var(--ad-danger-fg, #c02626) !important;
  }

  /* 눈에는 안 보이지만 스크린리더는 읽는다. `display:none`이면 스크린리더도
     안 읽으므로 이 방식이어야 한다. */
  .ad-sr-only {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}
