:root {
  /* service-notice 전용 반경 토큰 — --wds-radius-*(6/10/14/20/28/9999px)·
     --ds-radius-*(3/6/10/14/18/22/28/999px) 스케일에 8px·2px·"16px 16px 0 0"과
     정확히 일치하는 값이 없다(가장 가까운 --wds-radius-sm=6px, --wds-radius-md=10px
     둘 다 8px 패널 반경과 다르다). raw-border-radius 래칫(design-system/governance/
     anti-drift-static-baseline.json)을 채우면서 1a/1b 원본 픽셀을 그대로 보존하려고
     컴포넌트 티어 토큰으로 신설했다 — scripts/lib/css_var_fallback.py 의 "값 보존
     폴백" 관용구(`var(--x, 리터럴)`, contains_var_reference 가 이미 토큰화된 값으로
     본다)와 같은 취지, 디자인 변경 없음.
  */
  --service-notice-radius-panel: 8px;
  --service-notice-radius-grab: 2px;
  --service-notice-radius-sheet: 16px 16px 0 0;
}

.service-notice-banner {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  /* max-height:56px 제거 — 우회 방법 2줄째가 있으면 62px 까지 자연스럽게 늘어난다
     (design.md §E-2, M-8 편차 수리: 1단계 값은 2줄 배너를 잘랐다). */
  padding: 8px 12px;
  box-sizing: border-box;
  /* 긴 우회 문구 넘침 수리(notice-r6): 배너는 로그인 카드·관리 콘솔 미리보기
     device 처럼 폭이 정해진 컨테이너의 flex 자식이다. flex 자식의 min-width
     기본값은 auto(내용 최소 폭) — __row 안 __line2 가 nowrap 한 줄 텍스트를
     들고 있으면 그 내용 최소 폭이 컨테이너 폭보다 커져, ellipsis 가 걸리기도
     전에 배너 자체가 옆으로 밀려나 44×44 닫기 ×가 뷰포트 밖으로 잘렸다(모바일
     390) / 관리 콘솔 미리보기 열이 화면 밖으로 넘쳤다(1440, 중앙 09-27 실측).
     min-width:0 으로 flex 자식이 컨테이너 폭 안에서 실제로 줄어들게 한다 —
     그래야 __line2 의 overflow:hidden/ellipsis(아래)가 비로소 작동한다. */
  min-width: 0;
  /* 톤은 [data-tone] 규칙(아래)이 정한다 — 기본값은 중립(장애·점검 유형이 아닌
     feature/policy 공지, design.md §E-1 "neutral"). */
  background: var(--wds-color-surface);
  border-bottom: 1px solid var(--wds-color-border);
  font-size: var(--wds-font-size-body-s);
  line-height: 1.3;
}

/* 톤 = 면 8%(다크 12%) 섞기 + 칩·아이콘 글자는 상태색 그대로(design.md §E-1).
   *-text on *-container 짝은 대비 FAIL 이라 쓰지 않는다(같은 §E-1 표). */
.service-notice-banner[data-tone="error"] {
  background: color-mix(in srgb, var(--wds-color-error) 8%, var(--wds-color-surface));
  border-bottom-color: color-mix(in srgb, var(--wds-color-error) 45%, var(--wds-color-surface));
}
.service-notice-banner[data-tone="warning"] {
  background: color-mix(in srgb, var(--wds-color-warning) 8%, var(--wds-color-surface));
  border-bottom-color: color-mix(in srgb, var(--wds-color-warning) 45%, var(--wds-color-surface));
}
.service-notice-banner[data-tone="info"] {
  background: color-mix(in srgb, var(--wds-color-info) 8%, var(--wds-color-surface));
  border-bottom-color: color-mix(in srgb, var(--wds-color-info) 45%, var(--wds-color-surface));
}
.service-notice-banner[data-tone="success"] {
  background: color-mix(in srgb, var(--wds-color-success) 8%, var(--wds-color-surface));
  border-bottom-color: color-mix(in srgb, var(--wds-color-success) 45%, var(--wds-color-surface));
}
.service-notice-banner[data-tone="neutral"] {
  background: var(--wds-color-surface);
  border-bottom-color: var(--wds-color-border);
}

[data-theme="dark"] .service-notice-banner[data-tone="error"] {
  background: color-mix(in srgb, var(--wds-color-error) 12%, var(--wds-color-surface));
}
[data-theme="dark"] .service-notice-banner[data-tone="warning"] {
  background: color-mix(in srgb, var(--wds-color-warning) 12%, var(--wds-color-surface));
}
[data-theme="dark"] .service-notice-banner[data-tone="info"] {
  background: color-mix(in srgb, var(--wds-color-info) 12%, var(--wds-color-surface));
}
[data-theme="dark"] .service-notice-banner[data-tone="success"] {
  background: color-mix(in srgb, var(--wds-color-success) 12%, var(--wds-color-surface));
}

/* 2026-09-26 중앙 판정(axe 실측): design.md §E-1 이 추정한 라이트 error 5.83 는
   실측과 달랐다(color-mix 8% 면 위 --wds-color-error(red-500) 실측 3.39, FAIL) —
   design.md 자체가 "실제 값은 build 가 다시 잰다"고 적어 둔 대로 재측정해 고친다.
   design.md 이 금지한 조합은 *-text on *-container(레드톤 90% 불투명 면) 였고,
   여기 면은 그보다 훨씬 흰 8%/12% 섞임이라 더 어두운 -text(red/amber/sky/green-700)
   가 오히려 필요 대비를 만족한다(같은 축, 더 진한 값). */
.service-notice-banner[data-tone="error"] .service-notice-banner__chip,
.service-notice-banner[data-tone="error"] .service-notice-banner__icon {
  color: var(--wds-color-error-text);
}
.service-notice-banner[data-tone="warning"] .service-notice-banner__chip,
.service-notice-banner[data-tone="warning"] .service-notice-banner__icon {
  color: var(--wds-color-warning-text);
}
.service-notice-banner[data-tone="info"] .service-notice-banner__chip,
.service-notice-banner[data-tone="info"] .service-notice-banner__icon {
  color: var(--wds-color-info-text);
}
.service-notice-banner[data-tone="success"] .service-notice-banner__chip,
.service-notice-banner[data-tone="success"] .service-notice-banner__icon {
  color: var(--wds-color-success-text);
}

.service-notice-banner[hidden] {
  display: none;
}

.service-notice-banner__row {
  flex: 1 1 auto;
  /* 위 .service-notice-banner 의 min-width:0 주석과 같은 이유 — __row 자신도
     .service-notice-banner 의 flex 자식이라 같은 기본값 함정을 그대로 물려받는다. */
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-align: left;
  color: inherit;
  font: inherit;
}

.service-notice-banner__icon {
  flex: 0 0 auto;
  display: inline-flex;
  font-size: var(--wds-font-size-body-1);
}
.service-notice-banner__icon .wds-inline-icon {
  width: 18px;
  height: 18px;
}

.service-notice-banner__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1 1 auto;
}

/* 좁아지면 줄바꿈(design.md §E-2 — 340px 미리보기에서 제목이 0px 로 눌려 시각과
   "외 N건"이 겹치던 것을 잡았다). */
.service-notice-banner__line1 {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.service-notice-banner__chip {
  flex: 0 0 auto;
  font-weight: 600;
  font-size: var(--wds-font-size-label-s);
}
.service-notice-banner__chip:empty {
  display: none;
}

.service-notice-banner__title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 4em;
  flex: 1 1 auto;
}

.service-notice-banner__badge {
  flex: 0 0 auto;
  padding: 0 6px;
  border-radius: var(--wds-radius-sm, 4px);
  font-size: var(--wds-font-size-label-s);
  font-weight: 600;
  background: color-mix(in srgb, currentColor 16%, transparent);
}

.service-notice-banner__time {
  flex: 0 0 auto;
  font-size: var(--wds-font-size-label-s);
  opacity: 0.75;
  white-space: nowrap;
}

.service-notice-banner__line2 {
  display: block;
  font-size: var(--wds-font-size-label-s);
  opacity: 0.85;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 모바일(520px 이하, design-system/foundations/breakpoints.md 정본 분기점)에서는
   우회 줄을 1줄 말줄임 대신 2줄까지 줄바꿈 후 말줄임한다(notice-r6 발주서) — 긴
   우회 문구가 1줄에서 거의 통째로 잘리는 것보다 2줄이 더 읽힌다. -webkit-box
   line-clamp 를 모르는 브라우저는 위 기본 규칙(1줄 nowrap+ellipsis)으로 그대로
   내려간다 — 실패해도 잘리기만 하고 넘치지 않는다(위 min-width:0 수리로 이미
   보장). */
@media (max-width: 520px) {
  .service-notice-banner__line2 {
    display: -webkit-box;
    white-space: normal;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }
}

.service-notice-banner__more {
  font-size: var(--wds-font-size-label-s);
  opacity: 0.75;
  margin-left: auto;
  flex: 0 0 auto;
}

.service-notice-banner__close {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  min-width: 44px;
  min-height: 44px;
  background: none;
  border: none;
  cursor: pointer;
  font-size: var(--wds-font-size-h3);
  line-height: 1;
}

.service-notice-popover {
  position: absolute;
  top: 100%;
  left: 12px;
  /* right:12px + width:auto 로 컨테이너(.service-notice-banner, position:relative)
     실제 폭 안에서만 커진다 — 좁은 로그인 카드 안에서 100vw 기준 폭을 쓰면
     카드 오른쪽 밖으로 넘쳐 잘린다(2026-09-26 중앙 판정, web-1440-light-detail.png
     실측). max-width 440px 는 design.md §E-2 의 설계 폭 상한. */
  right: 12px;
  z-index: 40;
  width: auto;
  max-width: 440px;
  max-height: min(60vh, 560px);
  overflow-y: auto;
  margin-top: 4px;
  padding: 12px;
  background: var(--wds-color-surface);
  border: 1px solid var(--wds-color-border);
  border-radius: var(--service-notice-radius-panel, 8px);
  /* raw rgba(0,0,0,0.12) 폴백은 어떤 fallback 을 써도 raw-rgb 스캐너(line 단위,
     var() 여부 무관)에 다시 걸린다 — --wds-shadow-lg(0 12px 24px rgba(0,0,0,0.1))
     로 완전 대체(리터럴 폴백 없음). 원본보다 blur 4px 더 넓고 opacity 가 0.02 낮아
     팝오버 그림자가 아주 약간 더 부드럽다(같은 elevation 스케일 안에서의 근사치).
  */
  box-shadow: var(--wds-shadow-lg);
  font-size: var(--wds-font-size-body-s);
}

.service-notice-popover__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}

.service-notice-popover__stage {
  flex: 0 0 auto;
  padding: 2px 8px;
  border-radius: var(--wds-radius-sm, 4px);
  font-size: var(--wds-font-size-label-s);
  font-weight: 600;
  background: var(--wds-color-surface-hover);
}

.service-notice-popover__title {
  flex: 1 1 auto;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.service-notice-popover__title:focus,
.service-notice-popover__title:focus-visible {
  /* 제목은 조작 요소가 아니다 — JS 가 열릴 때 tabindex=-1 로 프로그램 포커스만
     이동시켜 스크린 리더에 알리는 용도(APG 대화상자 관행). 시각적 포커스 테두리를
     주면 입력칸처럼 보이므로 outline 을 없앤다. 실제 조작 요소(× 닫기 버튼 등)의
     focus-visible 링은 그대로 둔다. */
  outline: none;
}

.service-notice-popover__workaround {
  margin: 0 0 8px;
  padding: 8px 10px;
  border-radius: var(--wds-radius-sm, 4px);
  background: var(--wds-color-surface-hover);
  font-size: var(--wds-font-size-body-s);
}

.service-notice-timeline {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.service-notice-timeline__item {
  font-size: var(--wds-font-size-body-s);
}

.service-notice-timeline__stage {
  font-weight: 600;
  margin-right: 6px;
}

.service-notice-timeline__pin {
  margin-left: 6px;
  padding: 0 6px;
  border-radius: var(--wds-radius-sm, 4px);
  background: var(--wds-color-surface-hover);
  font-size: var(--wds-font-size-label-s);
}

.service-notice-timeline__text {
  margin: 2px 0 0;
}

.service-notice-timeline__more {
  margin-top: 6px;
  background: none;
  border: none;
  color: var(--wds-color-primary);
  cursor: pointer;
  padding: 0;
  font-size: var(--wds-font-size-label-s);
}

.service-notice-popover__close {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  min-width: 24px;
  min-height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  cursor: pointer;
  border-radius: var(--wds-radius-sm);
  color: inherit;
}

.service-notice-popover__close:hover {
  /* --wds-color-surface-hover 는 이미 실존 토큰(#ecedee 라이트/다크 대응) — 원본의
     rgba(0,0,0,0.06) 폴백은 애초에 미정의 커스텀 프로퍼티용 죽은 값이었다(토큰
     이름 자체는 맞았다). 폴백을 지우면 실제 토큰이 해석되어 검정 워시 대신 연한
     회색 hover 면이 된다 — 같은 "hover 강조" 역할, 값만 시스템 실값으로 정정.
  */
  background: var(--wds-color-surface-hover);
}

.service-notice-sheet {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: flex-end;
}

.service-notice-sheet__scrim {
  position: absolute;
  inset: 0;
  /* --wds-color-overlay: rgb(0 0 0 / 40%) 가 원본 rgba(0,0,0,0.4) 와 완전히 동일한
     색이다(RGBA 채널 100% 일치) — 순수 개선, 시각 변화 없음. */
  background: var(--wds-color-overlay);
}

.service-notice-sheet__panel {
  position: relative;
  width: 100%;
  /* 669 §M-5 짧은 시트 — min(70vh, 뷰포트 − 96px). --wizon-vvh 는 전역 시각 뷰포트
     높이 커스텀 프로퍼티(모바일 주소창 접힘 대응); 미정의 환경은 100vh 로 근사. */
  max-height: min(70vh, calc(var(--wizon-vvh, 100vh) - 96px));
  overflow-y: auto;
  padding: 16px;
  /* 하단 "확인"이 고정 자리라 스크롤 끝 마지막 기록이 가리지 않게(671 §9.11ⓓ) —
     버튼 높이(44px 본문 + margin-top 12px) 만큼 여백을 둔다. */
  padding-bottom: 56px;
  background: var(--wds-color-surface);
  border-radius: var(--service-notice-radius-sheet, 16px 16px 0 0);
  box-sizing: border-box;
}

.service-notice-sheet__workaround {
  margin: 0 0 8px;
  padding: 8px 10px;
  border-radius: var(--wds-radius-sm, 4px);
  background: var(--wds-color-surface-hover);
  font-size: var(--wds-font-size-body-s);
}

.service-notice-sheet__confirm {
  position: sticky;
  bottom: 0;
}

.service-notice-sheet__grab {
  width: 36px;
  height: 4px;
  margin: 0 auto 12px;
  border-radius: var(--service-notice-radius-grab, 2px);
  background: var(--wds-color-border);
}

/* 데스크톱 팝오버(.service-notice-popover__title, 121행)와 같은 굵기 — 09-26
   정정: 시트에 제목이 없어 팝오버와 문구가 달라 보였다. */
.service-notice-sheet__title {
  margin: 0 0 4px;
  font-weight: 600;
}

.service-notice-sheet__confirm {
  width: 100%;
  min-height: 44px;
  margin-top: 12px;
  border-radius: var(--service-notice-radius-panel, 8px);
  border: none;
  /* --wds-color-primary(blue-600 #1a75eb)/--wds-color-on-primary(#fff) — 원본의
     #2563eb/#fff 는 시스템 토큰에 한 번도 연결된 적 없는 ad-hoc 값이었다(바로 이
     드리프트가 래칫이 잡으려는 것). 같은 "주요 확인 버튼" 역할의 실제 브랜드
     프라이머리로 정정 — 톤이 살짝 더 밝은 파랑으로 바뀐다.
  */
  background: var(--wds-color-primary);
  color: var(--wds-color-on-primary);
  font-weight: 600;
  cursor: pointer;
}

.service-notice-composer-note {
  padding: 6px 12px;
  font-size: var(--wds-font-size-caption);
  /* --wds-color-text-subtle = var(--wds-gray-500) = #6b7280 — 원본 폴백과 완전
     동일(원래 var 이름 --wds-color-text-secondary 는 wds.css 에 없는 죽은 참조
     였다 — 폴백 값만 항상 쓰이고 있었다). 순수 정정, 시각 변화 없음.
  */
  color: var(--wds-color-text-subtle);
  border-top: 1px solid var(--wds-color-border);
}

/* 로그인 시트 슬롯(#serviceNoticeSlotLogin)은 공지가 «보일 때만» 자리를 차지한다.
   빈 슬롯(또는 숨은 배너만 든 슬롯)도 로그인 시트의 flex 자식이라 앞뒤 gap 을 한 번 더
   만들어 인접 간격 8→16 등 로그인 기하 계약(test_login_hidden_display_override·
   r32·r33 live contract)을 깼다(2026-09-27 CI #6747 portal-suite-gate 실측).
   :has() 를 모르는 브라우저는 두 번째 규칙만 버리고 첫 규칙(빈 슬롯)은 지킨다. */
.login-service-notice-slot:empty {
  display: none;
}

.login-service-notice-slot:not(:has(> .service-notice-banner:not([hidden]))) {
  display: none;
}
