/* nb-readability.css — NB/YN 공용 가독성 오버레이 (2026-08-11)
 *
 * 왜 오버레이인가: NB 25사이트·YN 11사이트의 CSS 가 전부 다르다(고유 톤).
 *   기존 파일을 고치거나 복사하면 사이트별 디자인이 깨진다. 그래서 **덮어쓰지 않고
 *   맨 뒤에 얹는 얇은 레이어**로 "12px 미만 글자"만 해소한다.
 *
 * 근거(라이브 실측):
 *   전수감사에서 사이트당 12px 미만 글자 151~266개 → 사장님 "글씨가 번지고 안 보인다"의 실체.
 *   · nb.mhna98.com(모바일 375): 201개 → **0개**
 *   · yn6.mhna98.com(모바일 375): 266개 → **0개**
 *   두 경우 모두 가로스크롤 미발생(scrollWidth 375 유지), NB패밀리 카드 높이 70px 정상.
 *
 * ⚠️ 선택자 주의(실측으로 배운 것):
 *   ① .nbf-logo / .nbf-txt 는 **자식(i, span)이 자체 font-size** 를 가진다 →
 *      부모만 지정하면 96개가 남는다. 그래서 자손까지 함께 지정한다.
 *   ② 사이트마다 라벨 클래스명이 다르다(deal-cat-tag, sc-badge, fs-free, latest-badge,
 *      rank-change, ad-tag, src-tag, aff-desc, aff-disclosure …). 개별 열거로는 못 끝난다 →
 *      **배지/태그/라벨 계열 부분일치([class*="-badge"] 등)** 로 안전망을 둔다.
 *      본문·제목 클래스는 건드리지 않으므로 레이아웃 위험이 없다(실측 확인).
 *
 * 접근성 기준: 본문 가독 최소 13px, 모바일 14px, 보조 라벨 12.5px(모바일 13px).
 */

/* ── 브랜드/로고 ── */
.brand-text span,
.brand-text small { font-size: 13px !important; line-height: 1.45 !important; }

/* ── NB 패밀리 추천 카드(전 사이트 공통 컴포넌트) ── */
.nbf-logo, .nbf-logo i, .nbf-logo * { font-size: 12.5px !important; }
.nbf-txt, .nbf-txt span, .nbf-txt * { font-size: 13px !important; line-height: 1.4 !important; }
.nbf-go { font-size: 13px !important; }

/* ── 섹션 키커·통계 보조문 ── */
.blog-kicker,
.active-tool-kicker,
.hero-stat-card small { font-size: 13px !important; }

/* ── 배지·태그·라벨·고지문 계열(사이트별 클래스명 차이를 부분일치로 흡수) ── */
[class*="-badge"],
[class*="-tag"],
[class*="-flag"],
[class*="-kicker"],
[class*="-eyebrow"],
[class*="-disclosure"],
[class*="-desc"],
[class*="-cat"],
[class*="-kw"],
[class*="-change"],
.src-badges, .src-badges *,
.fs-free,
.deal-tag,
.sc-badge,
/* 2026-08-11 추가(yn11 실측 잔여 11건): 고유 라벨 + 공통 소형 태그 */
.lang-caret,
.ad-label,
.card-soon,
.paypal-or,
[class*="-popular"],
sup, sub,
small { font-size: 12.5px !important; line-height: 1.35 !important; }

/* ── 렌더링 품질(글자 번짐 완화) ── */
html {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* ── 모바일: 한 단계 크게 + 터치타깃 44px(iOS HIG) ── */
@media (max-width: 768px) {
  .brand-text span,
  .brand-text small,
  .nbf-go,
  .blog-kicker,
  .active-tool-kicker,
  .hero-stat-card small { font-size: 14px !important; }
  .nbf-txt, .nbf-txt span, .nbf-txt * { font-size: 13.5px !important; }
  .nbf-logo, .nbf-logo i, .nbf-logo * { font-size: 12.5px !important; }

  [class*="-badge"],
  [class*="-tag"],
  [class*="-flag"],
  [class*="-kicker"],
  [class*="-eyebrow"],
  [class*="-disclosure"],
  [class*="-desc"],
  [class*="-cat"],
  [class*="-kw"],
  [class*="-change"],
  .src-badges, .src-badges *,
  .fs-free,
  .deal-tag,
  .sc-badge,
  .lang-caret,
  .ad-label,
  .card-soon,
  .paypal-or,
  [class*="-popular"],
  sup, sub,
  small { font-size: 13px !important; }

  /* 크기만 키운다 — 배치·색은 건드리지 않는다 */
  .theme-toggle,
  .nba-btn,
  .lang-select,
  header select,
  header button { min-height: 44px !important; }
}


/* ═══════════════════════════════════════════════════════════════════
   yn4 (YN PDF) 전용 가독성 보정 — **다크 테마용** (2026-08-12, 라이브 실측)
   ⚠️ 글자를 **밝게** 만드는 규칙이다. 밝은 배경 사이트에 복사하면 정반대 효과.
   실측 4건: .deal-count/.lp-d #6f6a7c 3.38~3.55 · .sc-btn 흰글자 4.00 · .deal-tag 4.46
   ═══════════════════════════════════════════════════════════════════ */
/* ① 너무 어두운 보조문 → 밝은 회색(어두운 배경에서 약 7.7:1) */
.deal-count,
.lp-d { color: #9aa0b8 !important; opacity: 1 !important; }
/* ② 어두운 브랜드색 글자 → 색조 유지하며 밝게(색값을 CSS 로 읽을 수 없어 filter 사용) */
.deal-tag { filter: brightness(1.45) saturate(0.95); }
/* ③ 밝은 브랜드색 배경 위 흰 글자 → 배경만 어둡게(글자는 흐려지지 않는다) */
.sc-btn { box-shadow: inset 0 0 0 100vmax rgba(0, 0, 0, 0.3) !important; filter: none !important; }

/* ═══ CLS: 상단 바 + 광고 슬롯 높이 예약 (2026-08-16) ═══════════════════════════
 * 실측(1280×800, CPU 4x 스로틀, 3회): CLS 0.8017 / 0.6822 / 0.2809 → 중간값 0.682
 *   = 전 사이트 최악(기준 0.1 이하). nb(0.255)보다 2.7배 나쁘다.
 * 이동은 두 종류로 갈린다:
 *   ① 결정적 — SECTION.hero 75→317 (+242px) @1485ms
 *      `#promoBanner`·`#recruitBanner` 가 빈 채로 HTML 에 있고 js/promo.js·js/recruit.js 가
 *      1.5초쯤 innerHTML 을 채운다 → 두 바(133+93=226px)가 갑자기 생겨 히어로 이하를 밀어낸다.
 *   ② 변동 — MAIN.container·SECTION.tools-section 이동 @938ms 등
 *      `.ad-slot` 에 높이 예약이 **없어서** 광고가 0 → 271~613px(모바일 최대 1948px)로
 *      커지며 아래 콘텐츠를 밀어낸다. 실행마다 광고 크기가 달라 CLS 편차(0.28~0.80)의 원인이다.
 *
 * ⚠️⚠️⚠️ 2026-08-16 3차 수정 — **진짜 원인은 `display: none` 이었다.**
 *    `#promoBanner` 만 예약이 안 걸리고(h0) `#recruitBanner` 는 잘 걸렸다. 계산된 스타일을 재 보니:
 *      134ms   promo[h0   disp:none  minh:133px kids:0]   ← min-height 는 적용돼 있는데 h0
 *      3299ms  promo[h133 disp:block minh:133px kids:4]
 *    범인은 이 파일이 아니라 **`css/style.css:438` 의 `.promo:empty { display: none; }`** 이다.
 *    `display:none` 이면 min-height 가 **자리를 차지하지 않는다**(박스가 생성되지 않으므로).
 *    → 비어 있는 동안만 `display:block` 으로 되살려 예약이 실제로 먹게 한다.
 *    `#promoBanner`(1,1,0) 가 `.promo:empty`(0,2,0) 를 이기므로 !important 불필요.
 *    ⚠️ 시각 안전 확인: 이 컨테이너는 배경·테두리·패딩이 전부 없다(라이브 computed 실측:
 *       background rgba(0,0,0,0) / border 0px none / padding 0px). 즉 비어 있는 133px 는
 *       **화면에 아무것도 보이지 않는 순수 여백**이다. 빈 상자가 보일 걱정은 없다.
 *
 * ⚠️ (2차 실패 기록) `:empty` 를 떼고 무조건 예약으로 바꿔 봤는데 **CLS 가 0.152 → 0.679 로 악화**했다.
 *    원인 진단이 틀렸기 때문이다 — "promo.js 가 껍데기를 일찍 넣어 :empty 가 풀린다"고 봤지만,
 *    실측하면 3.3초까지 `kids:0` 으로 :empty 가 계속 매칭 중이었다. :empty 는 무죄였다.
 *    (교훈: 예약이 안 걸리면 선택자부터 의심하지 말고 **computed display 를 먼저 볼 것**)
 *
 * ⚠️ min-height 는 무조건 걸어 둔다 — 껍데기가 먼저 들어오는 사이트(nb5~nb24)와 동일한 안전판.
 *    값이 최종 높이와 같아 영구적 빈 여백은 생기지 않는다.
 * ⚠️ 값은 이 사이트에서 채워진 뒤 실측한 높이다. 9개 뷰포트를 재서 경계를 잡았다:
 *    promo 133(≥900) / 138(700~860) / 184(480~640) / 201(375)
 *    recruit 93(≥700) / 213(≤640)  → 경계는 640px 과 860px, 420px
 *    **다른 사이트에 복사 금지** (nb 는 166/163 으로 전혀 다르다).
 * ⚠️ 광고를 줄이거나 늦추지 않는다 — 자리만 미리 잡고, 구글이 미충전으로 표시하면 접는다.
 *    (NB 오버레이에 이미 있는 검증된 규칙을 옮겨온 것)
 */
#promoBanner { min-height: 133px; }
/* ⚠️ 이 한 줄이 예약을 실제로 작동시킨다 — 지우면 style.css:438 의 display:none 때문에
      min-height 가 전부 무효가 되고 CLS 가 즉시 재발한다. */
#promoBanner:empty { display: block; }
#recruitBanner { min-height: 93px; }

@media (max-width: 860px) {
  #promoBanner { min-height: 138px; }
}

@media (max-width: 640px) {
  #promoBanner { min-height: 184px; }
  #recruitBanner { min-height: 213px; }
}

@media (max-width: 420px) {
  #promoBanner { min-height: 201px; }
}

/* 광고 슬롯 자리 예약 — 미충전이면 접어서 빈 공간이 남지 않게 한다.
   :has() 미지원 브라우저에서는 기본 100px 만 적용된다(깨지지 않는다). */
.ad-slot { min-height: 100px; }
.ad-slot:has(ins[data-ad-format="auto"]) { min-height: 300px; }
.ad-slot:has(ins[data-ad-status="unfilled"]),
.ad-slot:has(ins[data-ad-status="unfill-optimized"]) { min-height: 0 !important; }
/* ins 자체가 아직 없는 슬롯(스크립트가 만들기 전)은 접어 둔다 — 실측에서 이 상태가 0px 였다 */
.ad-slot:not(:has(ins)) { min-height: 0 !important; }
