/* safety-checklist — 5색 변수·48px 규격 (설계 §8.2, 플랜 Global Constraints, 태스크5 UI 규격) */

:root {
  /* 5색 체계 — 원천은 design-kit(control 프리셋, 사용자 결정 2026-08-10: 대시보드와 통일).
     이 파일은 색을 발명하지 않는다: 킷 토큰 참조 + color-mix 파생만(웹 대시보드와 같은 소비 계약).
     토큰 정의는 ./design-kit/tokens.css — index.html 이 styles.css 보다 먼저 링크한다. */
  --color-primary: var(--accent);
  --color-cta: var(--accent);
  --color-danger: var(--danger);
  --color-success: var(--ok);
  --color-neutral: var(--muted);
  --color-bg: var(--bg);
  --color-surface: var(--surface);
  --color-text: var(--text);

  /* tint 배경 위 텍스트 전용 파생 — 킷 전환으로 전 조합 재실측(2026-08-10, WCAG 상대휘도,
     실제 합성 배경 반영): ok on tint-success 4.54 · muted on tint-neutral 5.73 · 흰 텍스트 on
     muted/ok/danger 배지 6.82/5.04/6.20 · on-accent on accent 5.35 — AA 통과.
     primary(accent) 원색은 재시도 버튼 hover/active(삼중 합성)에서 4.29 미달 → 84:16 파생
     (--color-primary-text)으로 5.06/4.64. banner-info 는 원색 그대로 통과.
     success 원색은 banner-success(tint 8% over 페이지 bg)에서 4.17 미달 → 92:8 파생으로
     4.55/4.97/5.52(banner/surface쪽/흰배경).
     danger 원색만 이중 합성(queue-btn-delete:active — surface→tint-neutral 12% 위에
     tint-danger-strong 20%)에서 3.86 미달이라, 기존 감사와 같은 처방(어둡히는 방향)으로
     84:16 파생 — 이중합성 4.67 · banner-error 6.66 · surface 7.51 로 전 자리 개선. */
  --color-success-text: color-mix(in srgb, var(--ok) 92%, var(--text));
  --color-primary-text: color-mix(in srgb, var(--accent) 84%, var(--text));
  /* 보류(대기) 신호 — 킷 warn 계열. 재실측(2026-08-10): warn on queue-row 합성 4.80 ·
     흰배경 5.71 · muted on tint-warn(over bg) 5.46 — 전부 원색 AA 통과, 파생 불필요. */
  --color-warn: var(--warn);
  --color-warn-text: var(--warn);
  --tint-warn: color-mix(in srgb, var(--warn) 10%, transparent);
  --tint-warn-strong: color-mix(in srgb, var(--warn) 22%, transparent);
  --color-danger-text: color-mix(in srgb, var(--danger) 84%, var(--text));
  --color-neutral-text: var(--muted);

  /* 5색의 tint — 고정 rgba 대신 토큰 기반 color-mix(킷 소비 원칙: raw 색상값 금지) */
  --tint-primary: color-mix(in srgb, var(--accent) 8%, transparent);
  --tint-primary-strong: color-mix(in srgb, var(--accent) 16%, transparent);
  --tint-cta: color-mix(in srgb, var(--accent) 10%, transparent);
  --tint-danger: color-mix(in srgb, var(--danger) 8%, transparent);
  --tint-danger-strong: color-mix(in srgb, var(--danger) 20%, transparent);
  --tint-success: color-mix(in srgb, var(--ok) 8%, transparent);
  --tint-success-strong: color-mix(in srgb, var(--ok) 20%, transparent);
  --tint-neutral: color-mix(in srgb, var(--muted) 12%, transparent);
  --tint-neutral-strong: color-mix(in srgb, var(--muted) 35%, transparent);

  --control-h: 48px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --topbar-h: 56px;
  /* T4: 진행바 실측 높이로 app.js(buildStep2)가 매 렌더마다 덮어쓴다 — 이 값은 JS 실행 전
     초기 페인트용 대략치일 뿐이다(진행바는 write-step2 진입 전엔 hidden 이라 측정 불가). */
  --progress-bar-h: 64px;
  --transition-fast: 180ms ease;
  --transition: 220ms ease;
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans KR", "Malgun Gothic", Roboto, Helvetica, Arial, sans-serif;
}

/* [hidden] 전역 가드 — 반드시 저자 오리진에 있어야 한다.
   UA 의 `[hidden]{display:none}` 은 UA 오리진이라 저자의 `.action-bar{display:flex}` 에 항상 진다.
   이 한 줄이 없으면 hidden 이 무시되어 position:fixed 액션바 2개가 겹쳐 그려지고 조작이 막힌다. */
[hidden] { display: none !important; }

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--color-bg);
  color: var(--color-text);
  /* 킷 폰트 페어(대시보드와 통일, 2026-08-10) — CDN 미도달(오프라인 콜드)이면 토큰의
     폴백 스택 → 시스템 한글 폰트로 자연 강등된다(현장 저속망 배려, 렌더 차단 없음). */
  font-family: var(--font-body, var(--font-sans));
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
  /* P0-1(재평가 0920) — 한국어 어절이 좁은 폭에서 중간에 갈라졌다(실측: '한빛에스티'→
     '한빛에스/티', '「예정된' 분리). 전역 기본을 keep-all 로 — 표의 nowrap·개별 anywhere
     스코프(#email-send 등, 긴 URL·영문 고유명사 한정)는 그대로 각자 규칙이 이긴다. */
  word-break: keep-all;
}

body {
  min-height: 100vh;
}

h1, h2, h3, p, ul, ol, figure { margin: 0; }

button, input, select, textarea {
  font-family: inherit;
  font-size: 16px; /* iOS 자동 확대 방지 */
  color: var(--color-text);
}

a { color: var(--color-primary); }

/* 클릭 가능 요소 커서 (실제 클릭 핸들러가 있는 요소만) */
button, select, input[type="checkbox"], summary, label.ack-label { cursor: pointer; }
button:disabled { cursor: not-allowed; }

/* focus-visible: 절대 제거하지 않는다 */
:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
:focus:not(:focus-visible) { outline: none; }

/* 전환 150-300ms, reduced-motion 존중 */
button, .seg-btn, .banner, details > summary .chevron, .progress-fill {
  transition: background-color var(--transition-fast), color var(--transition-fast),
    border-color var(--transition-fast), transform var(--transition-fast), width var(--transition);
}
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}
/* 움직임을 줄여 달라는 사람에게는 막대를 **멈추되 지우지 않는다** — 지우면 「확인 중」이라는
   신호 자체가 사라져 이 작업이 고치려던 혼동으로 되돌아간다. */
@media (prefers-reduced-motion: reduce) {
  .sync-progress > span { animation: none; width: 100%; opacity: 0.55; }
}


.app-shell {
  max-width: 640px;
  margin: 0 auto;
  min-height: 100vh;
  background: var(--color-bg);
  display: flex;
  flex-direction: column;
  position: relative;
}

/* ---------- Topbar ---------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-4);
  background: var(--color-primary);
  color: var(--color-surface);
}
/* 제목은 **바 기준 절대 중앙**에 고정한다(2026-09-20 사용자 실기기 지적 — 홈에서 제목이
   왼쪽으로 치우쳐 보였다). 앞서는 flex:1 + margin-right:48px 로 "뒤로가기 버튼 폭만큼
   오른쪽을 비워 균형을 맞추는" 방식이었는데, 그 48px 보정이 **버튼이 항상 있다고 가정**한다.
   홈에서는 #btn-back 이 hidden 이라 좌측 48px 이 사라지는데 우측 보정만 남아 제목이
   왼쪽으로 밀렸다 — 허브 실측: 홈 왼쪽 24px 치우침 / 버튼이 보이는 화면은 정상(0~4px).
   left/right 를 같은 값으로 잡아 흐름에서 빼면 버튼 유무와 무관하게 항상 중앙이다
   (실측 390·360·320px × 홈·관리 6케이스 전부 치우침 0px, 뒤로가기와 겹침 없음).
   56px = 버튼 48px + 좌우 여백 — 이보다 작으면 긴 제목이 버튼 위로 올라탄다.
   nowrap+ellipsis: 고정폭이 되었으므로 아주 긴 제목은 두 줄로 흐르는 대신 말줄임한다
   (바 높이 56px 고정이라 두 줄이 되면 글자가 잘려 나간다). */
.topbar h1 {
  font-size: 17px;
  font-weight: 700;
  position: absolute;
  left: 56px;
  right: 56px;
  margin: 0;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#btn-back {
  /* 아이콘 전용이지만 장갑 낀 현장 사용을 전제로 48px 터치 타깃 (Apple HIG 하한 44px 상회) */
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  color: var(--color-surface);
  border-radius: 999px;
  padding: 0;
}
#btn-back:hover { background: color-mix(in srgb, var(--on-accent) 15%, transparent); }
#btn-back[hidden] { display: none; }

/* ---------- Banner region (전역, 화면 무관 상시 위치) ---------- */
#banner-region { padding: 0 var(--space-4); }
#banner-region:empty { padding: 0; }
/* home-plans-banner(사전등록 계획 동기화 배너)도 같은 .banner 패턴이라 이 목록에 넣는다(C2 감사 —
   빠뜨리면 전역 [hidden]!important 에만 기대게 돼 이 파일의 동반 가드 관례를 벗어난다) */
#home-master-banner[hidden], #home-storage-banner[hidden], #home-plans-banner[hidden] { display: none; }

.banner {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding: var(--space-3) var(--space-3);
  border-radius: var(--radius-md);
  font-size: 14px;
  line-height: 1.5;
  border: 1px solid transparent;
}
.banner-text { flex: 1; word-break: keep-all; }
.banner-close {
  /* 아이콘 16px + 44px 터치 타깃(Apple HIG 하한). 배너가 과하게 두꺼워지지 않도록 48px 대신 44px */
  width: 44px;
  height: 44px;
  margin: calc(-1 * var(--space-2)) calc(-1 * var(--space-2)) calc(-1 * var(--space-2)) 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  padding: 0;
  color: inherit;
  line-height: 0;
  flex-shrink: 0;
}
.banner-close:hover { background: var(--row-hover); }
.banner-info { background: var(--tint-primary); border-color: var(--tint-primary-strong); color: var(--color-primary); }
/* color 는 --color-success/--color-danger 가 아니라 -text 파생 변수다(C1) — 자신의 옅은 tint
   배경 위에 얹히는 텍스트라 원본은 4.09~4.32:1 로 AA 미달이었다(계산 근거는 :root 주석). */
.banner-success { background: var(--tint-success); border-color: var(--tint-success-strong); color: var(--color-success-text); }
.banner-warn { background: var(--tint-neutral); border-color: var(--tint-neutral-strong); color: var(--color-text); }
.banner-error { background: var(--tint-danger); border-color: var(--tint-danger-strong); color: var(--color-danger-text); }

/* ---------- Layout ---------- */
main {
  flex: 1;
  padding: var(--space-4) var(--space-4) calc(var(--control-h) + var(--space-6) + env(safe-area-inset-bottom, 0px));
}
.screen[hidden] { display: none; }

section.screen > .screen-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.section-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--color-text);
  margin-bottom: var(--space-2);
}
.muted { color: var(--color-neutral); font-size: 14px; }

/* ---------- Buttons ---------- */
.btn {
  height: var(--control-h);
  min-height: var(--control-h);
  padding: 0 var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  font-weight: 600;
  font-size: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
}
.btn-block { width: 100%; }
.btn-primary { background: var(--color-cta); color: var(--color-surface); }
/* hover/active는 5색 밖 새 색상 대신, 팔레트에 이미 있는 더 짙은 Primary 파랑으로 전환 */
.btn-primary:hover:not(:disabled) { background: var(--accent-hover); }
.btn-primary:active:not(:disabled) { background: var(--accent-active); transform: scale(0.98); }
/* secondary — **새 점검 갈래** 전용 채움(사용자 지시 2026-08-19).
   왜 앰버(--accent2 #8F5A10)가 아닌가: 승인 팔레트의 --warn(#93590F)과 사실상 같은 색이고,
   이 앱에서 앰버는 이미 '보류·대기' 전용 어휘다(.continue-card · .text-warn · 큐 행 틴트).
   새 점검이 '주의'로 읽히면 안 된다. 그래서 **짙은 먹녹(--color-text)** 으로 가른다 —
   어떤 상태 어휘와도 겹치지 않고 초록 CTA 와 한눈에 갈린다.
   대비(실측 계산): 흰 글자 15.7:1 · hover 10.2:1 · active 8.4:1 — 전부 AA 여유.
   hover 가 **밝아지는** 방향인 것은 원색이 이미 거의 검정이라 어둡힐 여지가 없기 때문이다
   (primary 는 반대로 어두워진다 — 두 계열의 규칙이 다른 이유를 여기 적어 둔다). */
.btn-secondary { background: var(--color-text); color: var(--color-surface); }
.btn-secondary:hover:not(:disabled) { background: color-mix(in srgb, var(--color-text) 86%, var(--color-surface)); }
.btn-secondary:active:not(:disabled) { background: color-mix(in srgb, var(--color-text) 78%, var(--color-surface)); transform: scale(0.98); }
.btn-outline { background: var(--color-surface); color: var(--color-primary); border-color: var(--tint-primary-strong); }
.btn-outline:hover:not(:disabled) { background: var(--tint-primary); }
.btn-outline:active:not(:disabled) { background: var(--tint-primary-strong); }
.btn-ghost { background: transparent; color: var(--color-primary); border-color: transparent; }
.btn-ghost:hover:not(:disabled) { background: var(--tint-primary); }
.btn-ghost:active:not(:disabled) { background: var(--tint-primary-strong); }
.btn:disabled { opacity: 0.5; }

/* ---------- Fields ---------- */
.field { display: flex; flex-direction: column; gap: var(--space-2); }
.field-label { font-size: 14px; font-weight: 600; color: var(--color-text); }
.field-hint { font-size: 12px; color: var(--color-neutral); }

.input, select.input, textarea.input {
  height: var(--control-h);
  padding: 0 var(--space-3);
  border: 1px solid var(--tint-neutral-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  width: 100%;
}
.input:hover { border-color: var(--color-neutral); }
.input:focus-visible { border-color: var(--color-primary); }
/* disabled 가 '값 표시' 수단으로도 쓰인다(계획 잠금, app.js renderWriteStep1) — --color-neutral 텍스트는
   흰 배경에 합성한 --tint-neutral 배경 위에서 4.09:1 로 WCAG AA 본문 4.5:1 미달이라 본문 색으로 올린다.
   비활성 구분은 배경 틴트와 not-allowed 커서로 충분하다(H6). */
.input:disabled { background: var(--tint-neutral); color: var(--color-text); cursor: not-allowed; }
/* readonly 입력(계획 잠금의 점검일, disabled 대신 사용 — 탭 순서·포커스 유지, H6)도 같은 시각 잠김 표시 */
.input:read-only:not([type="checkbox"]) { background: var(--tint-neutral); }
textarea.input {
  height: auto;
  min-height: 88px;
  padding: var(--space-3);
  resize: vertical;
  line-height: 1.5;
}
select.input {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='20' height='20'><path d='M6 9l6 6 6-6' fill='none' stroke='%2340615b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right var(--space-3) center;
  padding-right: var(--space-6);
}

/* ---------- Home ---------- */
.sync-line { font-size: 13px; color: var(--color-neutral); display: flex; align-items: center; gap: var(--space-2); }
.sync-line-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }
.sync-line-row .sync-line { flex: 1 1 auto; }
.btn-master-refresh { flex: 0 0 auto; padding: var(--space-1) var(--space-2); font-size: 12px; min-height: 0; }

/* 「N분 전 확인 · 최신이 아닐 수 있습니다」의 강조. **색만으로 말하지 않는다** — 문구가 이미
   낡음을 말하고 있고, 색은 거기에 무게만 더한다(WCAG 1.4.1). */
.sync-line-stale { color: var(--color-warn-text); font-weight: 600; }
.sync-line-loading { color: var(--color-neutral-text); }

/* 확인 중임을 **움직임**으로 말한다. 정지한 흐림(dim)은 「사용 불가」로 읽히지만
   움직이는 막대는 「진행 중」으로 읽힌다 — 목록을 로딩 중에도 눌러야 하는 이 화면에서는
   그 차이가 결정적이다(적대 검토 2026-08-25 #4). */
.sync-progress {
  height: 3px;
  border-radius: 999px;
  background: var(--tint-neutral);
  overflow: hidden;
  margin-bottom: var(--space-2);
}
.sync-progress > span {
  display: block;
  height: 100%;
  width: 40%;
  border-radius: 999px;
  background: var(--color-primary);
  animation: sync-slide 1.1s ease-in-out infinite;
}
@keyframes sync-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(250%); }
}


.template-list { display: flex; flex-direction: column; gap: var(--space-3); }

/* 새 점검 구역 — 카드 경계 + **왼쪽 굵은 선**으로 갈래를 표시한다. 색만 바꾸면 버튼 하나만
   달라 보이고, 카드로 묶어야 "다른 종류의 묶음" 으로 읽힌다(사용자 지시 2026-08-19). */
.newcheck-card {
  /* 배경은 다른 카드와 **같은 흰 카드**다. 옅은 먹 틴트(4%)로 해 봤더니 페이지 배경
     (--color-bg #F1F6F5)과 거의 같은 색이라 카드 경계가 죽었다 — 갈래 표시는 왼쪽 굵은 선과
     버튼 색이 진다. 덕분에 안의 글자도 다른 카드와 같은 불투명 합성이라 대비 계산이 하나로 준다. */
  background: var(--color-surface);
  border: 1px solid var(--tint-neutral-strong);
  border-left: 4px solid var(--color-text);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.newcheck-card .section-title { margin-bottom: 0; }
.newcheck-note { font-size: 13px; color: var(--color-neutral); margin: 0; line-height: 1.6; }
/* 예정된 점검에도 대칭으로 — 두 갈래가 **나란히** 서 있음을 왼쪽 선이 말한다.
   선이 한쪽에만 있으면 새 점검이 '예외' 로 보인다. */
#home-plans { border-left: 4px solid var(--color-primary); }

.continue-card {
  background: var(--tint-warn);   /* 보류(작성 중) 신호 — 관제 의미: 앰버 */
  border: 1px solid var(--tint-warn-strong);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.continue-card[hidden] { display: none; }
/* T2: .muted(색: --color-neutral) 는 대부분 흰/page-bg 위라 그대로 4.5:1 이상이지만, 이 카드
   배경(현재 --tint-warn, 킷 전환 전 tint-primary 시절 3.990:1 미달 실측)과 합쳐지면 위험한 자리다 — 여기서만 파생 변수로 덮는다(범용
   .muted 규칙은 다른 곳(홈 안내문 등)에서 이미 통과라 그대로 둔다). */
.continue-card .muted { color: var(--color-neutral-text); }

.queue-card {
  background: var(--color-surface);
  border: 1px solid var(--tint-neutral-strong);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.queue-header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
#btn-sync-now { padding: 0 var(--space-3); }
.queue-header-left { display: flex; align-items: center; gap: var(--space-2); }
.badge {
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--color-danger);
  color: var(--color-surface);
  font-size: 12px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.badge[hidden] { display: none; }

.queue-list { display: flex; flex-direction: column; gap: var(--space-2); }
.queue-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--tint-neutral);
  font-size: 13px;
}
.queue-title { font-weight: 600; }
/* T2: .queue-row 는 흰 .queue-card 위에 --tint-neutral(12%) 이 얹힌 배경이다(위 343행) — 원본
   --color-neutral 텍스트는 여기서 4.106:1 로 AA 미달이었다(회귀 테스트 §19 표 참고). */
.queue-sub { color: var(--color-neutral-text); }
/* R2: --color-danger-text 는 T2 에서 #A11A1A 로 재조정됐다(:root 주석 참고) — 이 자리
   (.queue-row 배경 위 텍스트)에서도 6.49:1 로 넉넉히 통과한다. */
.text-danger { color: var(--color-danger-text); font-weight: 600; }
.text-warn { color: var(--color-warn-text); font-weight: 600; }   /* 전송 대기 등 보류 상태 */
h1, h2, h3 { font-family: var(--font-heading, var(--font-sans)); }   /* 킷 헤딩 페어(D2Coding) */
.text-neutral { color: var(--color-neutral-text); }

/* 큐 행 조작(상세·다시 시도·삭제) — 갇힌 항목의 탈출구.
   375px 에서 버튼 3개가 들어가도록 wrap 허용. 높이는 .btn 의 48px 규격 그대로 둔다. */
.queue-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-1); }
.queue-actions .btn { flex: 1 1 auto; min-width: 80px; font-size: 14px; padding: 0 var(--space-2); }
/* 경계선은 .btn-outline 의 --tint-primary-strong 를 그대로 둔다(더 옅은 tint 로 덮으면 경계 대비가 떨어진다).
   T2: 이 버튼은 .queue-row(흰 카드 위 tint-neutral 12%) 안에 있어, hover/active 배경이 그 위에
   다시 겹쳐 합성된다(이중 합성) — 기본 상태(색: --color-cta, 흰 .btn-outline 배경)는 5.17:1 로
   이미 통과라 그대로 두고, hover/active 만 텍스트를 --color-primary 로 바꿔 통과시켰다
   (지시대로 --color-primary 재사용, 6.6/5.8:1). */
.queue-btn-retry { color: var(--color-cta); font-weight: 700; }
.queue-btn-retry:hover:not(:disabled) { background: var(--tint-cta); color: var(--color-primary-text); }
.queue-btn-retry:active:not(:disabled) { background: var(--tint-primary-strong); color: var(--color-primary-text); }
/* T2: 기본 상태도 포함해 전부 --color-danger-text 로 통일했다(기본 상태도 흰 배경 위에서 원본
   --color-danger 로 이미 충분했지만, hover/active 만 다른 변수를 쓰면 상태 전환에 색이 두 번
   바뀌는 것처럼 보인다 — 밝기만 다른 하나의 변수로 세 상태 모두 커버). */
.queue-btn-delete { color: var(--color-danger-text); border-color: var(--tint-danger-strong); }
.queue-btn-delete:hover:not(:disabled) { background: var(--tint-danger); }
.queue-btn-delete:active:not(:disabled) { background: var(--tint-danger-strong); }
.queue-payload {
  margin: var(--space-2) 0 0;
  padding: var(--space-2);
  max-height: 240px;
  overflow: auto;
  background: var(--color-surface);
  border: 1px solid var(--tint-neutral-strong);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-all;
}

/* 이어쓰기 카드의 버튼 2개(이어쓰기·작성 취소) — 375px 에서 나란히, 좁으면 줄바꿈 */
.continue-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.continue-actions .btn { flex: 1 1 120px; }

/* '지난 계획의 작성 중' 행 여러 개를 가르는 구분선 — 새 색·토큰 없이 카드 테두리색을 그대로 쓴다 */
.orphan-draft-list { display: flex; flex-direction: column; gap: var(--space-3); }
.orphan-draft-row { display: flex; flex-direction: column; gap: var(--space-2); padding-top: var(--space-3); border-top: 1px solid var(--tint-warn-strong); }
.orphan-draft-row:first-child { padding-top: 0; border-top: none; }

/* 오늘 보낸 점검 — 예정 점검 행과 같은 뼈대(날짜·공사·회사 세 줄)로 맞춘다 */
.sent-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  border: 1px solid var(--tint-neutral-strong);
  font-size: 13px;
}
.sent-when { font-weight: 700; }
.sent-project { font-weight: 600; }
.sent-company { color: var(--color-neutral); }
/* 카드 제목 — .section-title(15px)은 옆의 48px 버튼에 눌려 제목으로 안 읽힌다(사용자 제보).
   17px/700 로 올리고 건수 배지를 붙여 시선의 닻을 만든다. */
.card-title { font-size: 17px; font-weight: 700; color: var(--color-text); }

/* 팀 거르기 한 줄 — 이름표는 옆에 붙여 세로 공간을 아낀다(칩 두 줄을 대체한 이유).
   select 높이는 앱의 다른 입력과 같은 48px(.input 규격)을 그대로 쓴다. */
.filter-row { display: flex; align-items: center; gap: var(--space-2); }
.filter-label { flex: 0 0 auto; font-size: 14px; font-weight: 600; color: var(--color-neutral-text); }
.filter-row .input { flex: 1 1 auto; min-width: 0; }

/* 앱 상태 목록 — 이름/값 두 칸. 값이 길어도(UA) 줄바꿈해서 잘리지 않게 한다. */
.diag-list { margin: var(--space-3) 0 0; font-size: 14px; }
.diag-row { display: flex; gap: var(--space-3); padding: var(--space-2) 0; border-top: 1px solid var(--tint-neutral); }
.diag-row:first-child { border-top: 0; }
.diag-row dt { flex: 0 0 96px; color: var(--color-neutral); }
.diag-row dd { flex: 1 1 auto; margin: 0; word-break: break-all; }
.diag-row dd.bad { color: var(--color-danger-text); font-weight: 600; }
.diag-row dd.ok { color: var(--color-text); }
#btn-install { margin-top: var(--space-3); width: 100%; }
#diag-install-hint { margin-top: var(--space-2); }

.sent-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); }
.sent-actions .btn { flex: 1 1 110px; }

/* ---------- 홈 요약줄(T2) — 예정·작성 중·미전송·오늘 보냄, 입구일 뿐이다 ---------- */
/* 63px 이하(판정 목표) — 값 18px + 라벨 11px + gap 2 + 상하 패딩(--space-1)*2 + 테두리 2. */
.home-summary { display: flex; gap: var(--space-2); }
.home-summary-cell {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: var(--space-1) 2px;
  background: var(--color-surface);
  border: 1px solid var(--tint-neutral-strong);
  border-radius: var(--radius-sm);
  font-family: inherit;
  cursor: pointer;
}
.home-summary-value { font-size: 18px; font-weight: 700; color: var(--color-text); line-height: 1.15; }
.home-summary-label { font-size: 11px; color: var(--color-neutral-text); white-space: nowrap; }
/* 「작성 중」은 「예정」의 부분집합이다(합계 아님) — 점선 테두리로 포함 관계를 암시하고,
   title(마크업)로 명시한다. */
#home-summary-draft { border-style: dashed; }

/* ---------- 예정된 점검(사전등록 계획) ---------- */
/* 홈의 목록과 관리 화면의 목록은 같은 행 컴포넌트다 — 선택자를 둘 다에 건다.
   한쪽만 걸면 관리 화면 행이 스타일 없이 떨어져 같은 것이 달라 보인다. */
#home-plans .plan-list, #screen-manage .plan-list { display: flex; flex-direction: column; gap: var(--space-2); }
/* 흰 배경(--color-surface) 위에 지난 계획을 --color-danger 텍스트로 표시한다 —
   대비비 4.83:1(WCAG AA 본문 4.5:1 하한 통과, 계산: task-4-report.md 참고).
   .queue-row 처럼 회색 틴트(--tint-neutral) 배경을 쓰면 4.15:1 로 AA 미달이라 여기서는 쓰지 않는다. */
#home-plans .plan-row, #screen-manage .plan-row {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  border: 1px solid var(--tint-neutral-strong);
}
#home-plans .plan-row-info, #screen-manage .plan-row-info { display: flex; flex-direction: column; gap: 2px; font-size: 13px; }
#home-plans .plan-line1, #screen-manage .plan-line1 {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-2);
}
#home-plans .plan-date, #screen-manage .plan-date { font-weight: 700; }
/* 팀 칩 — **글자와 테두리로** 말한다. 색으로 팀을 가르지 않는 이유는 app.js 주석 참고
   (팔레트 5색 · 팀 수 가변 · WCAG 1.4.1). 줄바꿈 금지: 오른쪽 끝 정렬이 스캔의 핵심이다. */
/* 「재등록」 — 지난 예정일인데 목록에 있는 이유. 팀 칩과 같은 문법(글자+테두리)이되
   색으로 갈라 준다: 이건 '분류' 가 아니라 '상태' 라 눈에 먼저 들어와야 한다. */
#home-plans .plan-reopened, #screen-manage .plan-reopened {
  flex: none;
  font-size: 12px;
  font-weight: 700;
  color: var(--color-primary-text);
  border: 1px solid var(--tint-primary-strong);
  border-radius: 999px;
  padding: 1px 8px;
  white-space: nowrap;
  margin-left: auto;
}
#home-plans .plan-reopened + .plan-team, #screen-manage .plan-reopened + .plan-team {
  margin-left: var(--space-2);
}
#home-plans .plan-team, #screen-manage .plan-team {
  flex: none;
  font-size: 12px;
  font-weight: 700;
  color: var(--color-neutral-text);
  border: 1px solid var(--tint-neutral-strong);
  border-radius: 999px;
  padding: 1px 8px;
  white-space: nowrap;
}
#home-plans .plan-overdue, #screen-manage .plan-overdue { color: var(--color-danger); }
#home-plans .plan-project, #screen-manage .plan-project { font-weight: 600; }
#home-plans .plan-company, #screen-manage .plan-company { color: var(--color-neutral); }
/* 큐 대기 중 안내(H1) — display 를 선언하지 않는다: 전역 [hidden]{display:none!important}(44행) 가드가
   그대로 이기게 두는 것이 이 파일의 관례다(같은 지뢰를 새로 심지 않는다). */
#home-plans .plan-note, #screen-manage .plan-note { color: var(--color-danger); font-size: 12px; }
/* 375px 폭에서 버튼 2개(예정일 변경 · 취소)가 겹치지 않도록 wrap 허용, 48px 규격은 .btn 그대로 */
#home-plans .plan-actions, #screen-manage .plan-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
#home-plans .plan-actions .btn, #screen-manage .plan-actions .btn { flex: 1 1 120px; }

/* T1: 홈 행만 — 버튼이 협력사 줄 오른쪽 끝에 붙는다(#screen-manage 는 그대로 아래 전폭).
   공사명(.plan-project)은 이 줄 밖에 있어 폭을 그대로 유지한다. */
#home-plans .plan-meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
/* 희생 순서 ③ — 협력사명이 가장 먼저 줄어든다(공사명·버튼은 줄이지 않는다, 실측 근거). */
#home-plans .plan-meta-row .plan-company {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* 버튼은 더 이상 전폭이 아니다 — 글자 폭대로, 높이(48px)는 .btn 규격 그대로 유지한다
   (장갑 착용 이유로 축소 보류 — 사용자 지시). */
#home-plans .plan-meta-row .plan-actions {
  flex: none;
  display: flex;
  gap: var(--space-2);
}
#home-plans .plan-meta-row .plan-actions .btn {
  flex: none;
  width: auto;
  padding: 0 var(--space-3);
  white-space: nowrap;
}
/* T1: 날짜가 그룹 헤더로 옮겨간 행은 이 줄의 날짜를 감춘다(renderPlanList) — 남은 것(재등록·팀
   칩)을 오른쪽 끝에 붙인다. 완전히 비면(재등록도 팀 칩도 없음) renderPlanList 가 줄 자체를 감춘다. */
#home-plans .plan-line1.no-date { justify-content: flex-end; }

/* T1: 날짜 그룹 헤더 — 같은 날짜 행이 연속될 때 한 번만 뜬다(renderPlanList 가 만든다).
   행이 아니라서 별도 padding·연한 배경으로 "행이 아니라 이정표"임을 표시한다. */
.plan-date-group {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  padding: 2px var(--space-1);
  font-size: 12px;
  font-weight: 700;
  color: var(--color-neutral-text);
}
.plan-date-group-count { font-weight: 400; }

#screen-manage .plan-manage-panel, #home-sent-panel-scope .plan-manage-panel, #void-panel, #email-panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--tint-primary-strong);
  border-radius: var(--radius-md);
}
/* 동반 가드(C2) — 이 파일의 다른 display 선언 규칙(.continue-card[hidden] 등)은 전부 짝을 둔다.
   전역 [hidden]{display:none!important}(44행)가 !important 라 지금은 안 깨지지만(그래서 Minor),
   과거 .action-bar{display:flex}가 [hidden]을 덮어써 앱 전체가 막힌 사고가 이 클래스의 결함이었다 —
   나중에 전역 가드에서 !important 를 떼면 이 규칙만 그날 터진다. 명시적으로 짝을 둔다. */
#screen-manage .plan-manage-panel[hidden], #void-panel[hidden], #email-panel[hidden] { display: none; }
#screen-manage .plan-manage-actions, #void-panel .plan-manage-actions, #email-panel .plan-manage-actions { display: flex; gap: var(--space-3); }
#screen-manage .plan-manage-actions .btn, #void-panel .plan-manage-actions .btn, #email-panel .plan-manage-actions .btn { flex: 1; }
/* 헤더 버튼 2개(관리·사전등록) — 375px 에서 제목과 겹치지 않게 줄바꿈을 허용한다 */
.queue-header-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* ---------- 작성: step1 ---------- */
#write-step1[hidden], #write-step2[hidden] { display: none; }
/* 계획 잠금 컨텍스트(H3·H6) — 잠긴 점검일·협력회사·공사 값을 유일하게 노출하는 텍스트라
   .field-hint 의 옅은 --color-neutral 대신 본문색을 쓴다(disabled select 는 값을 다른 곳에 안 보여준다). */
#f-plan-context { color: var(--color-text); font-weight: 600; }
.tmp-project-wrap { display: flex; flex-direction: column; gap: var(--space-2); }
.tmp-project-wrap[hidden] { display: none; }

/* T5: 점검일·협력회사·공사(locked 전용)와 나머지 필드 사이 간격을 .screen-body 와 동일하게
   유지한다 — 이 래퍼가 .screen-body 의 직계 자식이 되면서 한 단 더 감싸졌기 때문이다. */
.field-stack { display: flex; flex-direction: column; gap: var(--space-5); }

/* T5 — 계획 요약 블록. 잠긴 값 3개(점검일·협력회사·공사)를 필드 3개 대신 한 블록으로 보여준다.
   공사명은 목록(2줄 클립)과 달리 여기서 전문을 보여주는 게 목적이라 줄바꿈을 허용한다. */
.plan-lock-summary {
  background: var(--color-surface);
  border: 1px solid var(--tint-neutral-strong);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
}
.plan-lock-summary-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.plan-lock-summary-title { font-size: 13px; font-weight: 700; color: var(--color-neutral-text); }
.plan-lock-summary-body { display: flex; flex-direction: column; gap: var(--space-1); margin: 0; font-size: 14px; }
.plan-lock-summary-row { display: flex; gap: var(--space-2); }
.plan-lock-summary-row dt { flex: 0 0 56px; margin: 0; color: var(--color-neutral-text); font-weight: 600; }
.plan-lock-summary-row dd { flex: 1 1 auto; min-width: 0; margin: 0; font-weight: 600; color: var(--color-text); white-space: normal; overflow-wrap: break-word; }

/* 「변경」류 보조 버튼 — 주 액션(.btn, 48px)과 달리 빈도가 낮은 되돌리기 동작이라
   시각 높이는 줄이되, **탭 영역은 44px 하한을 지킨다**(장갑 착용 전제).
   실측(2026-09-16): padding 만으로는 33px 이라 미달이었다 — ::after 로 히트 영역만
   넓힌다(행 높이를 키우지 않고 하한을 맞추는 방법, .go 버튼과 같은 처방). */
.plan-lock-edit-btn { position: relative; }
.plan-lock-edit-btn::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 44px;
  transform: translateY(-50%);
}
.plan-lock-edit-btn {
  flex: 0 0 auto;
  background: none;
  border: none;
  padding: var(--space-2) var(--space-2);
  margin: calc(-1 * var(--space-2)) calc(-1 * var(--space-2)) calc(-1 * var(--space-2)) 0;
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--color-primary);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.plan-lock-edit-btn:hover { background: var(--tint-primary); }
.plan-lock-edit-btn:active { background: var(--tint-primary-strong); }

/* T5 — 점검자 소속팀·표시명 힌트 줄(locked 전용). .field-hint 의 옅은 --color-neutral 대신
   본문색을 쓴다(#f-plan-context 와 같은 이유, 656행 참고 — 유일한 판독 수단). */

/* ---------- 작성: 진행률 바(상단 고정) ---------- */
.progress-bar {
  position: sticky;
  top: var(--topbar-h);
  z-index: 20;
  background: var(--color-surface);
  border-bottom: 1px solid var(--tint-neutral-strong);
  padding: var(--space-2) var(--space-4);
  margin: 0 calc(-1 * var(--space-4)) var(--space-4);
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.progress-track {
  flex: 1;
  height: 8px;
  border-radius: 999px;
  background: var(--tint-neutral);
  overflow: hidden;
}
.progress-fill { height: 100%; background: var(--color-cta); width: 0%; border-radius: 999px; }
#progress-text { font-size: 13px; font-weight: 700; white-space: nowrap; }
/* 아이콘 + **보이는 라벨**(사용자 지시 2026-08-19 UX 개선) — 라벨을 넣느라 터치 타깃을
   깎지 않는다. 높이 48px 유지, 폭만 글자만큼 늘린다(장갑 착용 조작 전제). */
.jump-label { font-size: 13px; font-weight: 700; }
#btn-jump-unanswered {
  min-width: 48px;
  height: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex-shrink: 0;
  padding: 0 12px;
  border-radius: 999px;
  background: var(--tint-primary);
  color: var(--color-primary);
  border: none;
}
#btn-jump-unanswered:disabled { opacity: 0.35; }

/* ---------- 아코디언(분류) ---------- */
.category {
  background: var(--color-surface);
  border: 1px solid var(--tint-neutral-strong);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-3);
  /* T4 수정(2026-09-16 실측): `overflow:hidden` 은 **스크롤 컨테이너를 만들어** 자식의
     position:sticky 를 무력화한다 — 머리글이 고정되지 않고 그대로 화면 밖으로 밀려났다
     (scrollY 0→900 에서 머리글 top 162→-738, 즉 sticky 가 전혀 안 걸렸다).
     `clip` 은 같은 모서리 클리핑을 하면서 스크롤 컨테이너를 만들지 않는다(검증: top 93 고정).
     분류가 바뀔 때 머리글이 교체되는 것은 overflow 가 아니라 **컨테이닝 블록(.category)**
     제약이 이미 해 준다. */
  overflow: clip;
}
.category-summary {
  list-style: none;
  min-height: var(--control-h);
  padding: var(--space-2) var(--space-4);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-weight: 700;
  background: var(--tint-primary);
  /* T4: 지금 스크롤 중인 분류를 항상 보여준다 — 진행바(z-index 20) 바로 아래 고정.
     조상 .category 의 overflow:hidden(모서리 클리핑용)이 이 sticky 의 컨테이닝 범위가
     되므로, 그 분류의 항목을 지나 다음 분류로 넘어가면 자연히 다음 머리글로 교체된다. */
  position: sticky;
  top: calc(var(--topbar-h) + var(--progress-bar-h));
  z-index: 15;
}
.category-summary::-webkit-details-marker { display: none; }
.category-title { flex: 1; }
.cat-chip {
  font-size: 12px;
  font-weight: 700;
  color: var(--color-primary);
  background: var(--color-surface);
  border-radius: 999px;
  padding: 2px 10px;
}
.chevron { display: inline-flex; color: var(--color-primary); transform: rotate(-90deg); }
details[open] > .category-summary .chevron { transform: rotate(0deg); }
/* T3: .item-card 는 이제 자체 바깥 여백이 없다(아래 구분선 1px만) — 연속된 항목 카드끼리는
   gap 을 0으로 둬 표처럼 붙이고, 카드가 아닌 형제(안내 상자·세부 접힘 상자)에는 그 gap 을
   margin-top 으로 되살린다. */
.category-body { padding: var(--space-3) var(--space-4); display: flex; flex-direction: column; gap: 0; }
.category-body > * + * { margin-top: var(--space-3); }
.category-body > .item-card + .item-card { margin-top: 0; }

/* ---------- 항목 카드 ---------- */
/* T3: 122항목 전부 스크롤(390px 실측 22,000px)에 대응 — 카드 껍데기(테두리·라운드·바깥 여백)를
   버리고 아래 구분선 1px만 남긴 행(row) 형태로 바꾼다. 본문·판정 3버튼·부적합 입력칸의
   구조와 판정 로직은 그대로 둔다 — 줄이는 대상은 껍데기뿐이다. */
.item-card {
  padding: 11px 14px;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  border-bottom: 1px solid var(--tint-neutral-strong);
}
/* 답한 항목 표시를 테두리 색 대신 배경 톤 다운 + 본문 흐리기로 옮긴다(위 테두리 제거에 맞춰).
   opacity 만 쓰는 이유: color-neutral/danger/success 계열 변수를 새로 선언하면 19d 대비표
   포괄 검사 대상이 된다 — 원본 --color-text 는 흰 배경에서 대비가 매우 높아(약 14:1) 낮춘
   불투명도로도 AA 4.5:1 을 넉넉히 넘긴다. */
.item-card.is-answered { background: var(--tint-neutral); }
.item-card.is-answered .item-text { opacity: 0.72; }
.item-card.is-invalid { background: var(--tint-danger); }
/* T2: is-invalid 카드(부적합 응답인데 사유 미입력) 배경이 --tint-danger 로 바뀌면, 흰 배경에서는
   4.5:1 이상이던 --color-neutral 텍스트(.criteria-body·아래 .note-counter)가 4.21:1 로 미달된다
   — 정상(흰 배경) 카드의 같은 규칙은 이미 통과라 기본 규칙은 그대로 두고 이 조합만 덮는다. */
.item-card.is-invalid .criteria-body, .item-card.is-invalid .note-counter { color: var(--color-neutral-text); }
/* T3: 부적합을 구두로 지목하기 위한 일련번호("11번이 문제입니다") — type=item 에만 매긴다. */
.item-head { display: flex; align-items: baseline; gap: var(--space-1); }
.item-idx { font-weight: 700; color: var(--color-primary); flex-shrink: 0; }
.item-idx:empty { display: none; }
.item-text { font-size: 15px; font-weight: 600; line-height: 1.5; }
.item-criteria { font-size: 13px; }
/* 접이식 '점검기준' — 텍스트 높이(약 26px)로는 터치 타깃이 부족해 44px 하한을 강제 */
/* 펼침 표시를 **되살린다**(사용자 지시 2026-08-19 UX 개선). 기본 삼각형을 지워 놓아
   접힌 상태인지 알 방법이 없었다 — NN/g 아코디언 지침은 "펼칠 수 있음을 시각적으로 분명히
   드러내라(캐럿·플러스)"고 못 박는다. 기본 마커 대신 우리 캐럿을 그린다(회전으로 상태 표시). */
.item-criteria summary {
  list-style: none;
  color: var(--color-primary);
  font-weight: 600;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1) 0;
  cursor: pointer;
}
.item-criteria summary::-webkit-details-marker { display: none; }
.item-criteria summary::after {
  content: '';
  width: 8px; height: 8px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.15s ease;
}
.item-criteria[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
@media (prefers-reduced-motion: reduce) {
  .item-criteria summary::after { transition: none; }
}
/* T3: 테두리 박스 대신 왼쪽 3px 막대로 — 카드 자체 테두리를 없앤 뒤에도 "판정 근거" 블록임을
   구분해야 한다. color 는 그대로 --color-neutral(19d 안전 목록 등재분, 배경은 불투명 흰색 유지). */
.criteria-body {
  color: var(--color-neutral);
  padding: var(--space-1) 0 var(--space-1) var(--space-2);
  margin-top: var(--space-1);
  border-left: 3px solid var(--tint-neutral-strong);
  line-height: 1.5;
}

.seg { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: var(--space-2); }
.seg-btn {
  height: var(--control-h);
  border-radius: var(--radius-sm);
  border: 1px solid var(--tint-neutral-strong);
  background: var(--color-surface);
  font-weight: 700;
  color: var(--color-text);
}
.seg-btn:hover { background: var(--tint-neutral); }
.seg-btn:active { transform: scale(0.97); }
.seg-btn[aria-pressed="true"].seg-y { background: var(--color-success); border-color: var(--color-success); color: var(--color-surface); }
.seg-btn[aria-pressed="true"].seg-n { background: var(--color-danger); border-color: var(--color-danger); color: var(--color-surface); }
.seg-btn[aria-pressed="true"].seg-na { background: var(--color-neutral); border-color: var(--color-neutral); color: var(--color-surface); }

.note-wrap { display: flex; flex-direction: column; gap: var(--space-1); }
.note-wrap[hidden] { display: none; }
.note-counter { align-self: flex-end; font-size: 12px; color: var(--color-neutral); }

/* 세부 항목(일반 안전수칙) 접는 상자 — 기본안전수칙이 있는 분류에만 생긴다.
   분류 아코디언 안에 한 겹 더 들어가므로 배경을 쓰지 않고 테두리로만 구분한다(중첩 강조 회피). */
.sub-items { border: 1px solid var(--tint-neutral-strong); border-radius: var(--radius-sm); }
.sub-items-summary {
  list-style: none;
  min-height: var(--control-h);           /* 48px — 터치 타깃 하한 */
  padding: var(--space-2) var(--space-3);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  font-weight: 600;
  color: var(--color-primary);
}
.sub-items-summary::-webkit-details-marker { display: none; }
.sub-items-summary > span { flex: 1; }
.sub-items-summary:hover { background: var(--tint-primary); }
.sub-items[open] > .sub-items-summary .chevron { transform: rotate(0deg); }
.sub-items-body {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 0 var(--space-3) var(--space-3);
}
.sub-items-body > * + * { margin-top: var(--space-3); }
.sub-items-body > .item-card + .item-card { margin-top: 0; }

/* 기본안전수칙을 해당없음으로 골라 하위를 함께 처리했을 때만 보이는 안내.
   display 를 선언하지 않는다 — [hidden] 전역 가드가 그대로 이긴다(.action-bar 사고 재발 방지).
   배경은 항상 불투명한 카드 위다: 해당없음일 때만 뜨므로 .is-invalid(부적합+사유미입력) 틴트와
   동시에 존재할 수 없다 → 대비 계산은 흰 배경 기준 하나로 충분하다. */
.cascade-note { color: var(--color-neutral); font-size: 13px; line-height: 1.5; }

/* ---------- note 유형: 안내 박스 ---------- */
.note-box {
  background: var(--tint-neutral);
  border: 1px dashed var(--tint-neutral-strong);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  font-size: 13px;
  color: var(--color-text);
  line-height: 1.5;
}
/* T2: .note-box 배경(--tint-neutral, 위 561행)과 조합하면 --color-neutral 라벨 텍스트가
   AA 미달이다(자신의 tint 위 텍스트 — .banner-success 와 같은 결함 클래스). */
.note-box .note-box-label { font-weight: 700; color: var(--color-neutral-text); display: block; margin-bottom: 4px; font-size: 12px; }

/* ---------- 검토 ---------- */
.summary-card {
  background: var(--color-surface);
  border: 1px solid var(--tint-neutral-strong);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-2) var(--space-3);
  font-size: 14px;
}
.summary-card dt { color: var(--color-neutral); }
.summary-card dd { margin: 0; font-weight: 600; }

/* color 는 -text 파생 변수(C1 감사 중 발견 — .banner-success 와 정확히 같은 패턴:
   자신의 옅은 tint-success 배경 위에 얹히는 텍스트라 원본 --color-success 는 4.32:1 로 미달이었다). */
.findings-empty {
  background: var(--tint-success);
  border: 1px solid var(--tint-success-strong);
  color: var(--color-success-text);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  font-weight: 600;
  text-align: center;
}
.finding-card {
  background: var(--tint-danger);
  border: 1px solid var(--tint-danger-strong);
  border-left: 4px solid var(--color-danger);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
/* color 는 -text 파생 변수(C1 감사 중 발견 — .finding-card 배경이 tint-danger 라 .banner-error 와
   같은 패턴, 원본 --color-danger 는 4.09:1 로 미달이었다). border-left 는 장식용 보더라 그대로 둔다. */
.finding-category { font-size: 12px; font-weight: 700; color: var(--color-danger-text); }
.finding-text { font-weight: 600; }
.finding-note { font-size: 14px; color: var(--color-text); white-space: pre-wrap; }

.ack-label {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  min-height: var(--control-h);
  padding: var(--space-2) var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--tint-neutral-strong);
  border-radius: var(--radius-md);
  font-size: 14px;
  line-height: 1.5;
}
.ack-label input[type="checkbox"] {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  accent-color: var(--color-primary);
  margin-top: 2px;
}

/* ---------- 하단 고정 액션 바 ---------- */
.action-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 25;
  max-width: 640px;
  margin: 0 auto;
  background: var(--color-surface);
  border-top: 1px solid var(--tint-neutral-strong);
  padding: var(--space-3) var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
  display: flex;
  gap: var(--space-3);
}
.action-bar .btn { flex: 1; }

/* ---------- 반응형 ---------- */
@media (min-width: 768px) {
  .app-shell { border-left: 1px solid var(--tint-neutral-strong); border-right: 1px solid var(--tint-neutral-strong); }
  main { padding-left: var(--space-6); padding-right: var(--space-6); }
}
@media (min-width: 1024px) {
  /* 새 색상 대신 승인된 neutral의 저채도 tint로 데스크톱 레터박스 배경 처리 */
  body { background: var(--tint-neutral); }
}

/* ================= 인쇄 (설계 2026-08-05-print-sheet §2) =================
   화면에서는 #print-sheet 가 [hidden] 이라 안 보인다. 인쇄 순간에만 열고 그것만 남긴다.
   .app-shell 을 통째로 숨기는 이유: 상단바·액션바는 position:sticky/fixed 라 인쇄에서
   페이지마다 겹쳐 찍힌다. 요소를 하나씩 지우는 것보다 "인쇄할 것만 남긴다"가 안전하다.

   색은 **새로 만들지 않는다** — 5색 체계 안의 --color-text(거의 검정)와 --tint-neutral 을
   그대로 쓴다. 종이용 회색을 따로 만들면 팔레트가 두 벌이 되고, 가드(검증 7)가 그것을
   잡아낸 것이 옳았다. */
#print-sheet { display: none; }

@media print {
  /* A4 한 장에 70줄을 넣는다(사용자 요청). 본문 폭 198mm 중 내용 열 71% = 140mm →
     6pt 에서 한 줄 66자. 6pt 는 작지만 원본 수기 양식도 이 정도였다 — 더 줄이면 현장에서 못 읽는다.

     **한 장은 조건부다** — 크로미움 실측(T3 70항목, 부적합 사유 24자):
       부적합 0건 → 1쪽 · 12건 → 2쪽 · 23건 → 2쪽
     사유가 두 줄로 접히는 행이 늘면 넘어간다. 부적합이 많은 날 2쪽이 되는 것은
     결함이 아니라 종이의 한계다(이 수치는 아래 폭 규칙을 고치기 **전과 후가 같다** — 확인함).
     다시 재려면: python tools/print-probe/probe.py [부적합주기] */
  @page { size: A4 portrait; margin: 6mm 6mm; }

  .app-shell, #banner-region { display: none !important; }
  #print-sheet { display: block !important; }

  html, body { background: var(--color-surface); color: var(--color-text); }

  #print-title {
    /* A1-2(6.4.2) 로 <h1>→<p> 강등 — 문서 h1 은 topbar-title 하나만 남긴다.
       h1,h2,h3 태그 선택자(:449)가 더 이상 안 걸리므로 헤딩 폰트를 여기서 명시해
       출력 모양을 그대로 유지한다. */
    font-family: var(--font-heading, var(--font-sans));
    font-size: 11pt;
    font-weight: 700;
    text-align: center;
    margin: 0 0 2mm;
    letter-spacing: 0.5px;
  }

  .print-head, .print-items {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
  }
  .print-head { margin-bottom: 1.5mm; }
  .print-head th, .print-head td {
    border: 0.4pt solid var(--color-text);
    font-size: 7pt;
    padding: 0.6mm 1.2mm;
    text-align: left;
    vertical-align: middle;
  }
  .print-head th { width: 15mm; font-weight: 700; }

  .print-items th, .print-items td {
    border: 0.4pt solid var(--color-text);
    font-size: 6pt;
    line-height: 1.15;
    padding: 0.35mm 0.8mm;
    vertical-align: top;
    word-break: break-all;   /* 한글 긴 문장이 칸을 넘지 않게 */
  }
  .print-items thead th { text-align: center; font-weight: 700; }
  /* 한 장에 들어가는 것이 목표지만, 항목이 늘어 넘칠 때를 대비해 남겨 둔다 —
     그때 2쪽부터 무슨 칸인지 모르게 되는 것을 막는다. */
  .print-items thead { display: table-header-group; }
  .print-items tr { break-inside: avoid; page-break-inside: avoid; }

  /* 점검기준 열은 인쇄하지 않는다(사용자 요청) — 그 폭을 내용에 돌렸다.
     폭은 **colgroup 에서만** 정한다. th 에 걸면 table-layout:fixed 가 병합 칸(colspan=3)의
     폭을 세 칸으로 쪼개 판정 칸이 2.9mm 가 되고 `N/A` 가 두 줄로 잘린다(실측).
     합이 정확히 100% 여야 브라우저가 비례 확대를 하지 않아 계산대로 나온다.
     본문 폭 198mm 기준 — 내용 71%(140mm) / Y·N 각 2.5%(5.0mm) / N/A 4%(7.9mm) /
     부적합 20%. `N/A` 는 6pt 굵게 약 3.5mm + 좌우 여백 1.6mm + 테두리 0.3mm ≈ 5.4mm 라
     7.9mm 면 기기 폰트가 조금 넓어도 견딘다. */
  .print-items .col-text { width: 71%; }
  .print-items .col-yn   { width: 2.5%; }
  .print-items .col-na   { width: 4%; }
  .print-items .col-note { width: 20%; }
  /* 판정 칸은 절대 줄바꿈하지 않는다 — 위 폭 계산이 어긋나도 `N/A` 가 쪼개지지 않게.
     (기본값 word-break: break-all 이 `N/` + `A` 로 끊는 것을 여기서 되돌린다.) */
  .print-items .c-res {
    text-align: center;
    font-weight: 700;
    white-space: nowrap;
    word-break: keep-all;
  }

  .print-head th,
  .print-items thead th,
  .print-items tr.g .c-text,
  .print-items .c-note-row {
    background: var(--tint-neutral);
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .print-items tr.g .c-text, .print-items .c-note-row { font-weight: 700; }
}

/* ---------- 발송 패널(#email-panel) — 제출 취소 패널과 같은 자리·같은 모양이다.
   패널 틀(배경·테두리·패딩·hidden 가드)은 위 458/471/472행의 #void-panel 과 공유 선택자로
   물려받는다. 여기서는 이 패널에만 있는 것 — 최근 주소 칩 · 상주 경고 · 주소를 담은 버튼 —
   만 더한다. 새 색은 만들지 않는다(전부 기존 토큰). */

/* 대상 요약 — #f-plan-context 와 같은 이유로, 긴 공사/회사명이 넘치지 않게 한다. */
#email-target { word-break: break-word; }

/* 최근 주소 — 오타를 가장 많이 막는 장치다. 눌러서 채운다(버튼은 app.js 가 만든다). */
.email-recent { display: flex; flex-wrap: wrap; gap: var(--space-2); }
#email-recent[hidden] { display: none; }
/* 터치 타깃 44px 하한(Apple HIG) — 칩이 실제 클릭 대상이다. 전환은 공용 button 규칙(107행)이
   이미 150~300ms 로 준다. 상태 구분(hover/active)은 여기서 명시한다. */
.email-recent-btn {
  cursor: pointer;
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--tint-primary-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-primary);
  font-size: 14px;
  font-weight: 600;
  word-break: break-all;
}
.email-recent-btn:hover { background: var(--tint-primary); }
.email-recent-btn:active { background: var(--tint-primary-strong); }

/* 민감도 경고 — **상주한다**(hover 도, 오류 뒤도 아니다: 패널을 열면 바로 보인다).
   확인 단계를 없앤 대신 이것이 유일한 상시 정보노출 안내다. 눈에 띄어야 한다.
   팔레트 밖 새 경고색(주황 계열)을 쓰지 않고 팔레트 안 danger 계열로 간다 —
   .finding-card 와 같은 조합(배경 tint-danger + 텍스트 color-danger-text)이고, 이 패널은
   흰 --color-surface 카드 위라 대비는 19a 표에서 계산해 확인했다(색상 리터럴은 검증 7이
   원문 그대로 스캔하므로 주석에도 승인 팔레트 밖 hex 를 적지 않는다). */
#email-warn {
  margin: 0;
  padding: var(--space-4);
  border: 1px solid var(--tint-danger-strong);
  border-left: 4px solid var(--color-danger);
  border-radius: var(--radius-md);
  background: var(--tint-danger);
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-danger-text);
}

/* 버튼 줄 — 보내기 글자에 **주소가 들어간다**(app.js sendButtonLabel). 375px 에서 두 버튼이
   한 줄에 안 들어가면 줄바꿈하고, 그래도 긴 주소는 버튼 **안에서** 접는다. .btn 은 높이가
   48px 고정이라 두 줄이 되면 글자가 넘치므로 이 버튼만 height:auto + min-height 로 푼다 —
   잘려 보이면 사용자가 어디로 가는지 확인할 수 없고, 그 순간 확인 단계를 없앤 근거가 사라진다.
   (닫기는 글자가 고정이라 늘어날 필요가 없다 → 남는 폭을 보내기가 가져간다.) */
#email-panel .plan-manage-actions { flex-wrap: wrap; }
#btn-email-close { flex: 0 1 auto; min-width: 96px; }
#btn-email-send {
  flex: 1 1 200px;
  height: auto;
  min-height: var(--control-h);
  padding-top: var(--space-2);
  padding-bottom: var(--space-2);
  line-height: 1.35;
  /* overflow-wrap:anywhere — **필요할 때만** 끊는 표준 속성이다. 칩(.email-recent-btn)이
     break-all 인 것과 다른 이유: 칩 글자는 주소 하나뿐이라 아무 데서나 끊어도 되지만, 이
     버튼은 "주소 + 으로 보내기" 라 낱말 중간을 함부로 끊으면 읽기가 나빠진다.
     레거시 word-break:break-word 는 비표준이라 쓰지 않는다.
     앞줄의 break-word 는 폴백이다 — anywhere 는 Safari 15.4+/Chrome 80+ 이고, 현장 폰 중에
     그보다 낮은 것이 있으면 선언이 통째로 무시돼 긴 주소가 버튼 밖으로 넘친다. 구형은
     break-word 로 접고, 신형은 뒤 선언이 이긴다. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
}
