/* 기본 스타일 — 공용 유틸리티 클래스.
   토큰(tokens.css)·폰트(fonts.css) 위에서 동작한다.
   클래스가 사라지면 tests/test_design_tokens.py 가 깨진다. */

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-sans);
  color: var(--ink);
  /* 페이지 캔버스는 옅은 틴트(--bg-soft), 카드는 흰 배경(--bg) + 그림자로
     띄운다 — 평평한 흰 배경 위 1px 테두리만 있던 이전과 달리 층이
     생긴다. */
  background: var(--bg-soft);
  line-height: 1.7;
  -webkit-text-size-adjust: 100%;
  /* ★UI 리뷰 2026-08-12 실측(관리 지원자 목록·공고 목록 표, 1440px·375px
     둘 다) — 한글은 공백이 없어도 음절 사이마다 줄바꿈이 허용된다(UAX #14).
     이 규칙이 없으면 브라우저의 표 자동 레이아웃이 짧은 한글 칸(배지·
     "인쇄" 링크 등)의 최소 폭을 "글자 하나"로 계산해, 칸이 조금만 좁아져도
     "게시중"→"게시"/"중", "인쇄"→"인"/"쇄", "김테스트"→"김테스"/"트" 처럼
     단어 중간이 잘려 세로로 쌓인다 — 375px 관리 목록에서는 공고 제목 한
     줄("회계감사본부 경력 회계사 채용")이 글자 수만큼(약 14줄) 세로로
     쌓여 행 하나가 화면을 가득 채웠다. `word-break: keep-all` 은 한글도
     라틴 문자처럼 "공백에서만" 줄바꿈하게 강제한다 — 배지·표 칸처럼
     좁은 곳은 내용 폭만큼 넓어지거나(표 자동 레이아웃), 공백이 있는 긴
     문구는 정상적으로 여러 줄로 접힌다(글자 단위로 쪼개지지 않는다).
     정말 못 들어가는 긴 값은 .card 의 overflow-wrap: break-word 나 표의
     .table-scroll(overflow-x: auto)이 그대로 안전판 역할을 한다. */
  word-break: keep-all;
}

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 var(--sp-4); }

/* 제목 — 굵기뿐 아니라 크기 단계로도 위계를 준다. h1 은 이제 본문의 2배를
   넘고, letter-spacing 을 살짝 좁혀 큰 글자가 헐거워 보이지 않게 한다. */
/* ★UI 리뷰 2026-08-12 — 제목은 폰트가 가장 커서 body 의 word-break:
   keep-all(위 참고) 과 만나면 가장 먼저 사고가 난다: 공백 없는 극단값
   (지원자 이름 60자 상한 테스트 마커, 관리자가 공백 없이 입력한 공고
   제목 등)이 더는 글자 단위로 줄바꿈되지 않고 h1 폭을 그대로 뚫고
   나간다 — 인쇄본(.print-name, .card 밖이라 카드의 overflow-wrap 안전판을
   못 받음)에서 실제로 이 회귀가 나 PDF 추출 텍스트에서 이름이 통째로
   잘렸다(test_bulk_pdf_export_contains_all_field_markers). 제목 3종에는
   여기서 직접 안전판을 켠다 — keep-all 은 "가능하면 공백에서만 끊어라",
   이 break-word 는 "그래도 안 들어가면 그때만 끊어라"인 최후 수단이라
   평소 제목 길이에는 아무 영향이 없다. */
h1, h2, h3 { color: var(--brand-deep); font-weight: 700; line-height: var(--lh-tight); overflow-wrap: break-word; }
h1 { font-size: var(--fs-2xl); font-weight: 800; letter-spacing: -0.02em; margin: var(--sp-7) 0 var(--sp-4); }
h2 { font-size: var(--fs-xl); letter-spacing: -0.01em; margin: var(--sp-6) 0 var(--sp-3); }
h3 { font-size: var(--fs-md); margin: var(--sp-5) 0 var(--sp-2); }

/* 절 제목 — 원본의 좌측 강조선 패턴을 유지하되, 위 h1/h2/h3 크기 규칙 위에
   얹힌다. */
.section-title {
  border-left: 4px solid var(--brand);
  padding-left: var(--sp-3);
  margin: var(--sp-6) 0 var(--sp-4);
}

.card {
  background: var(--bg);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-sig);   /* 시그니처 */
  padding: var(--sp-5);
  box-shadow: var(--shadow-sm);
  /* ★UI 리뷰 2026-08 지적사항 2(치명) — 포트폴리오 URL 처럼 공백 없는
     긴 문자열 한 토큰은 브라우저가 알아서 안 쪼갠다. 이 리포 전체에
     overflow-wrap/word-break 규칙이 하나도 없었다(공개 지원폼의
     apply-form 카드도 이 규칙을 공유한다 — 자기소개서 URL·긴 링크
     첨부 등 지원자가 직접 입력하는 텍스트도 마찬가지로 넘칠 수 있다). */
  overflow-wrap: break-word;
}

.btn {
  display: inline-block;
  padding: 0.7rem 1.6rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--ink);
  font-family: inherit;
  font-size: 1rem;
  cursor: pointer;
  text-decoration: none;
  transition: border-color var(--motion-fast), background var(--motion-fast);
}
.btn:hover {
  border-color: var(--brand);
  background: var(--bg-soft);
}
/* ★실제 브라우저로 v2-5 증명사진 슬롯을 확인하다가 잡은 버그 — 위
   `display: inline-block` 이 author 스타일이라, `hidden` 속성이 기대는
   브라우저 기본 스타일(`[hidden] { display: none }`, user-agent 출처)을
   그대로 덮어써버린다. 그 결과 JS 가 `el.hidden = true` 로 꺼도 버튼이
   화면에 그대로 남는다(계산된 display 가 여전히 inline-block) — pytest 는
   마크업 존재만 보고 실제 CSS cascade 는 안 봐서 이 문제를 못 잡았다.
   `.btn` 에 `hidden` 을 쓰는 곳이 앞으로도 생길 수 있으므로 base.css 에서
   한 번에 막는다(apps/public/static/style.css 의 .photo-frame-empty[hidden]
   과 같은 이유·같은 처방). */
.btn[hidden] {
  display: none;
}
.btn-primary {
  background: var(--brand);
  border-color: var(--brand);
  /* 흰 글자는 --brand 배경에서 2.43:1 — WCAG AA(4.5:1) 미달.
     --brand-deep 글자는 5.84:1 로 통과한다. 지원하기 버튼이라 타협하지 않는다. */
  color: var(--brand-deep);
  border-radius: var(--radius-sig);   /* 주요 버튼만 시그니처 */
  font-weight: 700;
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--motion-base), transform var(--motion-base),
              background var(--motion-fast), border-color var(--motion-fast),
              color var(--motion-fast);
}
.btn-primary:hover {
  background: var(--brand-deep);
  border-color: var(--brand-deep);
  color: var(--on-brand);   /* --brand-deep 배경에서는 흰 글자가 14.15:1 로 통과 */
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}
/* ★UI 리뷰 2026-08-12(2차) — 눌렀을 때 살짝 가라앉는 반응이 없어 클릭이
   실제로 먹혔는지 hover 상태와 구분이 안 됐다. hover 의 "뜨는" 방향과
   반대로 눌러 원래 자리로 되돌리면 손끝의 클릭감과 화면이 맞아떨어진다. */
.btn:active {
  background: var(--line-soft);
}
.btn-primary:active {
  transform: translateY(0);
  box-shadow: var(--shadow-sm);
}
/* ★UI 리뷰 2026-08-12(2차) — admin.js 는 상태변경·메모저장·파기·AI
   재생성 같은 POST 제출 버튼을 누르는 즉시 disabled 로 바꾼다(이중 제출
   방지, 특히 AI 재생성은 응답까지 수 초~수십 초 걸린다) — 그런데 눌러도
   생김새가 그대로라 "정말 눌렸나" 다시 누르고 싶어지는 화면이었다.
   옅어진 채 커서까지 바뀌면 "지금 처리 중"이라는 것이 보인다. hover 도
   같이 죽여 비활성 버튼 위에서 색이 바뀌며 눌러도 되는 것처럼 보이는
   것을 막는다. */
.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}
.btn:disabled:hover {
  background: var(--bg);
  border-color: var(--line);
}
.btn-primary:disabled,
.btn-primary:disabled:hover {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--brand-deep);
}

/* 입력 필드에는 시그니처 라운드를 쓰지 않는다. */
.field { margin-bottom: var(--sp-4); }
.field > label { display: block; font-weight: 700; margin-bottom: var(--sp-2); }
.field input, .field textarea, .field select {
  width: 100%;
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-family: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--bg);
  transition: border-color var(--motion-fast), box-shadow var(--motion-fast);
}
/* ★실측 — 체크박스·라디오는 브라우저 기본 파란색 그대로 남아 나머지
   화면의 teal/navy 팔레트와 어긋났다. accent-color 는 대부분의 현대
   브라우저(Chromium·Firefox·Safari)가 지원하는 표준 속성으로, 네이티브
   컨트롤의 접근성(키보드·스크린리더)은 그대로 유지한 채 색만 브랜드에
   맞춘다. --brand 대신 --brand-deep 을 쓰는 이유는 다른 곳(포커스
   링·버튼 글자)과 같다 — --brand 는 흰 배경에서 대비가 낮다. */
input[type="checkbox"],
input[type="radio"] {
  accent-color: var(--brand-deep);
}

/* ★실측(1440px, 지원서 "포트폴리오 파일") — input[type=file]은 위 규칙의
   테두리·라운드·배경은 받지만, 브라우저가 그리는 "파일 선택" 버튼
   부분만은 CSS로 손댈 수 없는 OS 기본 회색 버튼 그대로 남아 나머지
   폼과 눈에 띄게 어긋났다. 표준 ::file-selector-button 의사요소로 그
   버튼만 .btn 톤(테두리·라운드·배경)에 맞춘다 — 색·폭·라운드는 이미
   쓰는 토큰만 재사용한다. */
.field input[type="file"] {
  padding: 0.4rem;
}
.field input[type="file"]::file-selector-button {
  margin-right: var(--sp-3);
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-soft);
  color: var(--ink);
  font-family: inherit;
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: border-color var(--motion-fast), background var(--motion-fast);
}
.field input[type="file"]:hover::file-selector-button {
  border-color: var(--brand-mid);
  background: var(--bg);
}
.field input:hover, .field textarea:hover, .field select:hover {
  border-color: var(--brand-mid);
}
.field-error { color: var(--danger); font-size: var(--fs-xs); margin-top: var(--sp-1); }
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"] {
  border-color: var(--danger);
}

/* --brand 아웃라인은 흰 배경에서 2.43:1 — WCAG 2.4.11 의 3:1 미달.
   --brand-deep 은 명도가 낮아 충분한 대비를 낸다. */
:focus-visible { outline: 3px solid var(--brand-deep); outline-offset: 2px; }

.badge {
  display: inline-block;
  padding: 0.15rem 0.6rem;
  border-radius: var(--radius-pill);
  background: var(--brand-pale);
  color: var(--brand-deep);
  font-size: var(--fs-xs);
  font-weight: 700;
  vertical-align: middle;
}
.badge-alert { background: var(--danger-pale); color: var(--danger); }
/* 상태 배지 — 관리 목록에서 색·형태만으로 훑어볼 수 있게 하는 3종 추가.
   전부 기존 브랜드/중립 토큰만 조합한다(새 색상군을 들이지 않는다). */
.badge-neutral { background: var(--line-soft); color: var(--ink-2); }        /* 접수·초안 등 아직 진행 전 */
.badge-strong { background: var(--brand-deep); color: var(--on-brand); }     /* 면접 등 강조가 필요한 다음 단계 */
.badge-success { background: var(--brand); color: var(--brand-deep); }      /* 합격·게시 등 긍정적 결과 */

.table { width: 100%; border-collapse: collapse; }
.table th, .table td {
  padding: 0.85rem var(--sp-3);
  border-bottom: 1px solid var(--line-soft);
  text-align: left;
  vertical-align: top;
  /* 접수번호·제출일처럼 숫자가 섞인 값이 행마다 자리수가 바뀌어도
     글자폭이 흔들리지 않게 한다 — 좌우 정렬 여부와 무관하게 항상
     적용해서 세로로 훑을 때 숫자만 살짝 들쭉날쭉해 보이는 것을 막는다. */
  font-variant-numeric: tabular-nums;
}
.table th {
  background: var(--bg-soft);
  color: var(--brand-mid);
  font-weight: 700;
  white-space: nowrap;
}
/* ★UI 리뷰 2026-08-12(2차) — 헤더~본문 경계가 본문 행 사이 구분선과
   같은 두께·색이라 "표에 줄이 많다"로만 읽히고 헤더가 도드라지지
   않았다. 헤더 아래만 더 굵고 진한 선으로 분리해 "여기부터 데이터"를
   한 번에 알 수 있게 한다. */
.table thead th {
  border-bottom: 2px solid var(--line);
}
/* ★UI 리뷰 2026-08-12(2차) — 얼룩말 줄무늬(짝수 행 배경)를 걷어냈다.
   이 표들(지원자 목록·공고 관리)은 행 사이에 이미 구분선이 있고, 줄무늬는
   그 구분선과 같은 목적(행 추적)을 다른 방식으로 한 번 더 반복해 오히려
   화면을 시끄럽게 했다 — 감사 실무 화면은 색이 아니라 선의 위계로
   조용히 정돈되는 편이 신뢰감을 준다. 대신 호버는 그대로 남긴다: 지금
   보고 있는 행이 어디인지는 실제로 필요한 신호다. */
.table tbody tr:hover { background: var(--brand-pale); }
/* 순수 수량(건수·점수)에만 쓴다 — 접수번호·날짜처럼 글자와 숫자가
   섞인 값은 우측정렬하면 자리수가 뒤죽박죽으로 보여 오히려 안 좋다. */
.table .num {
  text-align: right;
}
/* ★UI 리뷰 2026-08-12(2차) 후속 — 접수번호·날짜(YYYY-MM-DD)처럼 하이픈이
   낀 값은 keep-all 이 막는 음절 단위 줄바꿈과 별개로, 브라우저가 하이픈
   자리를 줄바꿈 기회로 보고 "2026-08-" / "12" 처럼 반으로 쪼갠다(실측,
   관리 지원자 목록). 값 자체가 하나의 단위라 절대 쪼개지면 안 되는
   칸에 쓴다 — 동시에 이 칸들이 내용 폭만큼만 차지하게 만들어, 정작
   넓어야 하는 공고 제목 칸이 밀려서 2줄로 접히는 것도 함께 막는다
   (표 자동 레이아웃은 줄바꿈이 막힌 칸에는 꼭 필요한 폭만 주고 남는
   폭을 줄바꿈 가능한 칸에 몰아준다). */
.table .nowrap {
  white-space: nowrap;
}

/* --ink-3 은 흰 배경 텍스트로 3.63:1 — WCAG AA(4.5:1) 미달이라 실제 글자에는 --ink-2 를 쓴다.
   --ink-3 은 토큰에 남겨 비텍스트·장식용으로만 쓴다.
   .empty 는 인쇄본(application_print.html)·AI 캡션(생성 시각 한 줄)처럼
   "박스로 강조하면 안 되는" 자리에도 두루 쓰이므로 여기서는 그대로
   둔다 — 화면 전체가 비어 보이는 목록 단위 빈 상태는 아래 .empty-state
   로 따로 분리한다. */
.empty { color: var(--ink-2); padding: var(--sp-5) 0; text-align: center; }

/* ★UI 리뷰 2026-08-12(2차) — "지원서가 없습니다" 같은 목록 전체가 빈
   화면은 .empty 의 맨 글자 한 줄만으로는 페이지가 아직 덜 그려진
   것처럼 보였다(지원 폼의 빈 증명사진 슬롯 .photo-frame 이 이미 쓰는
   점선+옅은 배경 언어를 그대로 가져와 "여기는 원래 비어 있을 수 있는
   자리"임을 스스로 드러낸다). 인쇄본·자격증/학력/경력 같은 절 안의
   짧은 안내문은 지금처럼 .empty 만 쓰고, 화면 전체의 결과가 없다는
   뜻일 때만 이 클래스를 같이 붙인다. */
.empty-state {
  padding: var(--sp-6) var(--sp-4);
  border: 1.5px dashed var(--line);
  border-radius: var(--radius);
  background: var(--bg-soft);
}

/* ★2026-08-10 접근성 라운드 — "본문 바로가기" 스킵 링크. 지원 폼(공개
   앱)은 절이 10개라 진행 표시 nav 하나에만 링크가 10개다(apply.html) —
   화면리더는 랜드마크 이동으로 건너뛸 수 있지만, 스크린리더 없이 키보드만
   쓰는(예: 마우스를 못 쓰는) 방문자는 Tab 을 10번 넘게 눌러야 첫 입력칸에
   닿는다(WCAG 2.4.1 Bypass Blocks). 평소에는 화면 밖(visually-hidden 과
   같은 클립 기법)에 있다가 포커스를 받는 순간에만 보이게 한다 — 마우스
   사용자에게는 아무것도 달라지지 않는다. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--brand-deep);
  color: var(--on-brand);
  padding: var(--sp-3) var(--sp-4);
  border-radius: 0 0 8px 0;
  font-weight: 600;
}
.skip-link:focus {
  left: 0;
}

/* v2-11: WAT 의 헤더 리듬(64px, 헤어라인 하단선)을 참고해 기존 84px 에서
   72px 로 다듬었다 — 로고·로그아웃 버튼만 있는 한 줄 헤더라 84px 는
   여백이 과했다. 완전히 64px 로 맞추지 않은 이유는 삼덕 사이트명이
   길어서(예: "삼덕회계법인 채용") WAT 보다 한 줄 텍스트가 커 보일 여지를
   남겨야 하기 때문이다. */
.site-header {
  border-bottom: 1px solid var(--line-soft);
  background: var(--bg);
}
.site-header .wrap { display: flex; align-items: center; min-height: 72px; }
.site-title {
  color: var(--brand-deep);
  font-weight: 700;
  font-size: 1.25rem;
  text-decoration: none;
}
/* ★가로 스크롤 컨테이너는 반드시 포함 블록이어야 한다 (390px 실측으로 잡은 결함).
   `overflow-x: auto` 만으로는 **절대위치 자손을 가두지 못한다.** 포함 블록은
   가장 가까운 '위치가 지정된' 조상이므로, 스크롤러가 static 이면 절대위치
   자손은 스크롤러를 그대로 통과해 페이지를 밀어낸다.

   실제 사례: 자격증 표의 삭제 열 헤더에 있는 스크린리더 전용
   `<span class="visually-hidden">삭제</span>`(1px, position:absolute)가
   표 안쪽 x=464 에 놓였는데, .table-scroll 이 static 이라 갇히지 않았다.
   그 결과 390px 화면에서 문서 전체가 90px 가로로 밀렸다 — 표는 멀쩡히
   자기 안에서 스크롤되고 있었고, 넘치는 요소는 1px 짜리 보이지 않는
   접근성 보조 요소였다. 눈으로는 원인을 찾을 수 없는 종류의 결함이다.

   미디어쿼리 안이 아니라 항상 적용한다 — 스크롤이 걸리는 폭에서만
   필요한 게 아니라, 이 요소들이 스크롤러로 쓰이는 한 늘 필요하다. */
.table-scroll,
.apply-progress ol {
  position: relative;
}
/* ★UI 리뷰 2026-08 지적사항 5(보통) — overflow-x: auto 자체는 원래
   ``@media (max-width: 768px)`` 안에만 있었다(아래). 바로 위 주석이 이미
   "미디어쿼리 안이 아니라 항상 적용한다"는 원칙을 말하는데, position 만
   그 원칙을 따르고 overflow-x 는 안 따르고 있었다 — 관리 목록 표가
   8열로 늘어난 지금은 768px 보다 넓은 800~1000px 노트북 창에서도
   넘칠 수 있다. 항상 스크롤 가능하게 두는 편이 안전하다(스크롤이
   필요 없는 폭에서는 auto 가 아무 것도 하지 않으니 부작용도 없다). */
.table-scroll {
  overflow-x: auto;
}

.site-footer {
  margin-top: var(--sp-7);
  border-top: 1px solid var(--line-soft);
  background: var(--bg-soft);
  color: var(--ink-2);
  font-size: var(--fs-sm);
}
.site-footer .wrap { padding-top: var(--sp-4); padding-bottom: var(--sp-4); }

@media (max-width: 768px) {
  h1 { font-size: var(--fs-xl); margin: var(--sp-5) 0 var(--sp-3); }
  h2 { font-size: var(--fs-lg); }
  .wrap { padding: 0 var(--sp-3); }
  .site-header .wrap { min-height: 60px; }
  /* ★overflow-x: auto 는 이제 미디어쿼리 밖(항상 적용)으로 옮겼다 — 위
     .table-scroll 규칙 참고. 여기 다시 적으면 "미디어쿼리 안에서만
     스크롤 가능"으로 오해하기 쉬워 아예 지웠다(중복 선언 자체는
     해롭지 않지만, 다음에 이 규칙만 보고 "768px 안에서만 필요하구나"로
     잘못 판단할 여지를 없앤다). */
  .card { padding: var(--sp-4); }
}
