/* 블로그 서브도메인 테마 — Slate & Navy.
 *
 * 포폴(main.css)과 **의도적으로 갈라지는** 테마다. v45까지는 main.css 토큰을 그대로
 * 상속했지만(= 두 사이트가 같은 색), 블로그를 별개 사이트처럼 보이게 하는 것이 목적이므로
 * 아래 body.blog 블록에서 색 토큰을 전부 재정의한다.
 *
 * 규칙 세 가지 — 어기면 다크 모드에서 조용히 깨진다:
 *   1. 컴포넌트 규칙 안에 hex를 직접 쓰지 않는다. 전부 var(--…).
 *   2. main.css는 한 줄도 고치지 않는다. 블로그 쪽에서만 덮어쓴다.
 *   3. 포폴 남색(#00215D)만 계승하고 오렌지(#FF6A1A)는 UI에 쓰지 않는다.
 *      (로고 SVG 안의 오렌지는 브랜드 마크라 예외)
 *
 * 클래스 접두어 b- 는 main.css의 포폴 규칙과 충돌하지 않게 하려는 것.
 * blog.css는 main.css보다 뒤에 로드되므로, 같은 특이도면 이 파일이 이긴다.
 * 모바일은 포폴과 같은 방식: 단일 URL·단일 템플릿 + 미디어쿼리로 전용 컴포넌트 전환.
 */

/* ══ 토큰 (라이트 = 기본) ══════════════════════════════════ */
body.blog {
  /* 면 */
  --bg: #F5F6FA;
  --bg-alt: #E9ECF4;
  --bg-elev: #FFFFFF;

  /* 글자 */
  --text: #1A1F2B;
  --text-muted: #5B6478;
  --heading: #0D1220;

  /* 선 */
  --line: rgba(26, 31, 43, .12);
  --line-strong: rgba(26, 31, 43, .26);

  /* 강조 — 포폴 남색 계승 */
  --accent: #00215D;
  --accent-hover: #002F84;
  --accent-soft: rgba(0, 33, 93, .09);
  --accent-on: #F3F6FC;

  /* 커버 그라디언트 위 글자색. v48까지는 드로어·액션바·관리자 사이드바도 '항상 어두운
     크롬 면'으로 뒀지만, 프로토타입은 **모든 면이 테마를 따른다** — 그 면들을 라이트로
     되돌리면서 --surface-dark / --on-dark-line은 쓰임이 없어져 지웠다. */
  --on-dark: #F3F6FC;
  --on-dark-muted: #8A94A8;

  /* 커버 — 라이트/다크 양쪽에서 항상 어둡다. 그 위 글자색도 테마와 무관하게 고정 */
  --cover-grad: linear-gradient(160deg, #0D1220, #00215D);
  --cover-shade: linear-gradient(to top, rgba(6, 10, 20, .7), transparent 65%);
  --on-cover: #FBFCFF;
  --on-cover-muted: #A8C0EE;
  --on-cover-dim: rgba(243, 246, 252, .78);
  --on-cover-line: rgba(243, 246, 252, .28);
  --on-cover-wash: rgba(243, 246, 252, .14);

  /* 특수 */
  --code-bg: #11162A;

  /* 상태 3색 — 시안 부록 A-2. 이 테마에서 **새로 만든 유일한 색**이다.
     상태를 accent(남색)로 표시하지 않는다. accent는 '선택된 것'과 '주요 액션' 전용이라,
     발행 뱃지까지 남색으로 칠하면 무엇이 눌리는 것인지 구분이 사라진다.
     밝은 초록(#2FBF71 류)을 쓰지 않는 이유는 대비다 — 흰 카드 위에서 2.2:1로 AA 미달. */
  --ok: #1F6F4A;
  --ok-soft: rgba(31, 111, 74, .1);
  --warn: #8A5A00;
  --warn-soft: rgba(138, 90, 0, .1);
  --danger: #B0342A;
  --danger-soft: rgba(176, 52, 42, .09);

  /* 형태 */
  --radius: 3px;
  --radius-lg: 10px;
  --wrap: 1180px;
  --read: 780px;
  --rail: 268px;
  --header-h: 64px;

  /* 모션 */
  --dur-1: 120ms;
  --dur-2: 180ms;
  --dur-3: 240ms;
  --dur-4: 320ms;
  --ease: cubic-bezier(.2, .7, .3, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);

  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
}

/* ══ 토큰 (다크) ═══════════════════════════════════════════
 * 라이트가 기본이고 다크는 토글로 들어가는 선택지다. 컴포넌트 규칙은 그대로 두고
 * 값만 바꾼다 — 위에서 hex를 전부 없앤 이유가 이것이다.
 *
 * accent를 원본 남색에서 밝은 파랑으로 **교체**한다. #00215D는 다크 배경 대비 1.6:1이라
 * 링크·칩·활성 목차가 배경에 먹혀 사라진다. 커버 그라디언트에만 원본 남색 계열을
 * 남겨 브랜드감을 유지한다.
 * 형태(--radius/--wrap/--read/--rail)와 모션 토큰은 테마와 무관하므로 다시 선언하지 않는다. */
html[data-theme="dark"] body.blog {
  --bg: #0C1018;
  --bg-alt: #121826;
  --bg-elev: #151C2C;   /* --bg와 명도차 약 3.5% — 더 줄이면 카드 경계가 사라진다 */

  --text: #D7DEEC;      /* 순백 금지 — 다크에서 #FFF 본문은 잔상이 남는다 */
  --text-muted: #8A94A8;
  --heading: #F3F6FC;

  --line: rgba(215, 222, 236, .12);
  --line-strong: rgba(215, 222, 236, .26);

  --accent: #6E9BE8;
  --accent-hover: #8FB4EF;
  --accent-soft: rgba(110, 155, 232, .14);
  --accent-on: #0C1018;   /* accent 위 글자색이 어두워진다 — 라이트와 반대 */

  --cover-grad: linear-gradient(160deg, #070A11, #0D2A63);
  --code-bg: #0A0F1A;        /* 배경보다 더 어둡게 */

  /* 상태 3색도 함께 밝힌다. 라이트 값(#1F6F4A 등)은 다크 배경 대비 3:1 미만이라
     그대로 두면 뱃지 글자가 배경에 먹힌다. */
  --ok: #4FBE8B;
  --ok-soft: rgba(79, 190, 139, .13);
  --warn: #E0A94A;
  --warn-soft: rgba(224, 169, 74, .13);
  --danger: #E8705F;         /* 라이트의 #B0342A는 다크 배경에서 대비 미달 */
  --danger-soft: rgba(232, 112, 95, .13);
}

/* 테마를 뒤집는 순간 컴포넌트의 색 트랜지션이 한꺼번에 재생돼 화면이 흐물거린다.
   전환 프레임 동안만 트랜지션을 끈다(base.html의 flipTheme이 속성을 붙였다 뗀다). */
html[data-theme-anim="off"] body.blog *,
html[data-theme-anim="off"] body.blog *::before,
html[data-theme-anim="off"] body.blog *::after { transition: none !important; }

/* 브라우저가 CSS 적용 전에 칠하는 캔버스 색을 실제 테마에 맞춘다.
   'light dark'로 선언해 두면 OS가 다크일 때 페이지 이동마다 **어두운 화면이 한 프레임
   번쩍인다**(라이트 모드인데도). 카테고리 링크를 누를 때 실제로 발생했다. */
html[data-theme="light"] { color-scheme: light; }
html[data-theme="dark"] { color-scheme: dark; }

body.blog main { min-height: 60vh; }
.b-wrap { max-width: var(--wrap); margin-inline: auto; padding: 0 44px 72px; }
.b-mono { font-family: var(--font-mono); }

/* 포커스 링은 지우지 않는다 — 키보드 사용자가 위치를 잃는다 */
body.blog :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ══ 관리자 바 ═════════════════════════════════════════════ */
.b-adminbar { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 28px; background: var(--accent-soft); border-bottom: 1px solid var(--line); }
.b-adminbar-tag { display: flex; align-items: center; gap: 9px; font-family: var(--font-mono);
  font-size: 11.5px; letter-spacing: .08em; color: var(--accent); }
.b-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.b-adminbar-actions { display: flex; gap: 8px; }

/* ══ 헤더 ══════════════════════════════════════════════════
 * 시안은 밝은 헤더다. 로고는 전부 남색인 logo-blog.svg를 쓰고, 다크 테마에서만
 * 전부 밝은색인 logo-blog-dark.svg로 스왑한다(두 img를 두고 여기서 토글).
 * 둘 다 오렌지를 쓰지 않는다 — 포폴 logo.svg와 달라지는 지점이다. */
.b-header { display: flex; align-items: center; gap: 22px; padding: 0 44px; height: var(--header-h);
  background: var(--bg);   /* color-mix 미지원 폴백 — 반드시 앞줄에 */
  background: color-mix(in srgb, var(--bg) 92%, transparent); backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line); color: var(--text);
  position: sticky; top: 0; z-index: 50; }
.b-brand { display: flex; align-items: center; gap: 7px; }
.b-logo { height: 18px; width: auto; display: block; }
.b-logo-sm { height: 16px; opacity: .8; }
/* 로고 스왑 — 라이트는 남색본, 다크는 흰본 */
.b-logo-dark { display: none; }
html[data-theme="dark"] .b-logo-light { display: none; }
html[data-theme="dark"] .b-logo-dark { display: block; }
.b-suffix { font-family: var(--font-mono); font-size: 14px; font-weight: 700; color: var(--accent); }
.b-nav { display: flex; align-items: center; gap: 22px; margin-left: 12px; }
.b-nav-item { display: flex; align-items: baseline; gap: 6px; font-size: 13.5px;
  color: var(--text-muted); padding-bottom: 3px; border-bottom: 2px solid transparent;
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.b-nav-item:hover { color: var(--heading); }
.b-nav-item.is-active { color: var(--heading); font-weight: 600; border-bottom-color: var(--accent); }
.b-nav-en { font-family: var(--font-mono); font-size: 11px; opacity: .6; }
.b-actions { display: flex; align-items: center; gap: 12px; margin-left: auto; }
.b-search { display: flex; align-items: center; gap: 8px; width: 230px; height: 36px; padding: 0 12px;
  border: 1px solid var(--line-strong); border-radius: var(--radius); color: var(--text-muted);
  background: var(--bg-elev); transition: border-color var(--dur-1) var(--ease); }
.b-search:focus-within { border-color: var(--accent); }
.b-search input { border: 0; background: none; color: var(--text); font: inherit; font-size: 13px; width: 100%; outline: none; }
.b-search input::placeholder { color: var(--text-muted); }
.b-icon-btn { width: 36px; height: 36px; flex: none; border-radius: var(--radius); border: 1px solid var(--line-strong);
  background: none; color: var(--text-muted); display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease); }
.b-icon-btn:hover { border-color: var(--accent); color: var(--accent); }
/* 검색 토글은 모바일 전용 — .b-icon-btn(display:flex) 뒤에 와야 이긴다 */
.b-search-toggle { display: none; }
.b-logout { margin: 0; display: flex; }
.b-burger { display: none; border: 0; background: none; color: var(--heading); cursor: pointer; padding: 6px; }

/* ══ 버튼 ══════════════════════════════════════════════════ */
/* line-height를 반드시 못 박을 것. <button>은 body의 line-height를 **상속하지 않는다**
 * (UA가 normal로 덮는다). 같은 .b-btn을 <a>와 <button>에 걸어도 <a>는 1.6, <button>은
 * ~1.15가 적용돼 높이가 6.5px 어긋난다 — 글 관리의 '수정'(a)과 '숨김'(button)이
 * 나란히 있어 그 차이가 그대로 보였다. font-family도 같은 이유로 명시한다. */
.b-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 8px 16px; border-radius: var(--radius);
  font-family: inherit; font-size: 13px; font-weight: 700; line-height: 1.25;
  cursor: pointer; border: 1px solid transparent;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.b-btn-accent { background: var(--accent); color: var(--accent-on); }
.b-btn-accent:hover { background: var(--accent-hover); color: var(--accent-on); }
.b-btn-line { border-color: var(--line-strong); color: var(--text); background: none; }
.b-btn-line:hover { border-color: var(--accent); color: var(--accent); }
.b-btn-danger { border-color: var(--danger); color: var(--danger); background: none; }
.b-btn-danger:hover { background: var(--danger-soft); }
.b-btn-lg { padding: 12px 22px; font-size: 14px; width: fit-content; }
.b-btn[disabled] { opacity: .5; cursor: not-allowed; }

/* ══ 히어로 (시안 01: 좌 텍스트 · 우 커버 2단 카드) ══════════
 * v45까지는 풀블리드 다크 오버레이였다. 시안이 밝은 2단 카드로 바뀌었으므로
 * 마크업(절대배치 전제)은 그대로 두고 여기서 그리드로 재배치한다. */
.b-hero { position: relative; display: grid; grid-template-columns: 1fr 1fr; align-items: stretch;
  height: 340px; margin: 34px 0 0; border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; background: var(--bg-elev); color: inherit;
  transition: border-color var(--dur-2) var(--ease); }
.b-hero:hover { border-color: var(--accent); }
/* 커버 칸 — 썸네일이 없어도 남색 판이 보이게 그라디언트를 깐다(백지 방지) */
.b-hero-img { grid-column: 2; grid-row: 1; display: grid; place-items: center;
  background: var(--cover-grad); overflow: hidden; }
.b-hero-img img { width: 100%; height: 100%; object-fit: cover; }
/* 밝은 카드라 대비용 그늘이 필요 없다 */
.b-hero-shade { display: none; }
.b-hero-inner { position: static; grid-column: 1; grid-row: 1; display: flex; flex-direction: column;
  justify-content: center; padding: 48px 44px; min-width: 0; }
.b-hero-tags { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.b-pick { font-family: var(--font-mono); font-size: 11px; font-weight: 700; letter-spacing: .09em;
  color: var(--accent-on); background: var(--accent); padding: 4px 9px; border-radius: 2px; }
.b-hero-meta { font-size: 12px; color: var(--text-muted); }
.b-cat { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-mono);
  font-size: 11.5px; color: var(--text-muted); }
.b-cat i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
/* 제목·요약은 **줄 수로 잘라 넣는다.** .b-hero는 height:340px 고정 + overflow:hidden이라
 * 길면 카드 바닥에서 그냥 잘린다 — 배포본에서 61자 제목이 4줄을 먹고 요약이 문장 중간에
 * 끊겼다. 넘치는 것을 방치하면 '어중간하게 잘린 문장'이 남지만, 말줄임은 잘렸다는 것을
 * 독자가 알 수 있다.
 *
 * 340px 안의 실제 여유는 242px이고(패딩 48*2 + 테두리 2를 뺀 값), 배지줄 37 + '읽기 →' 44를
 * 빼면 제목·요약 몫이 160px이다. 제목 2줄(36px 기준 99) + 요약 2줄(51) = 150 으로 맞췄다.
 * **위 세 값 중 하나라도 바꾸면 이 계산을 다시 해야 한다.**
 * 상한을 42 → 36px로 내린 것도 같은 이유다. 42px 2줄은 113px이라 요약이 한 줄밖에 못 남는다. */
/* 한글 제목 줄바꿈 — 음절 사이가 아니라 **띄어쓰기에서** 끊는다.
   기본값(word-break: normal)은 한글을 어디서든 끊을 수 있다고 보므로
   `카카오 로컬 API로 입지 데이터…`가 `…입 / 지…`처럼 낱말 가운데서 잘렸다.
   keep-all은 공백을 낱말 경계로 삼아 그걸 막는다(main.css의 .ov-name·.chat-bubble이
   이미 쓰는 방식이다).

   overflow-wrap을 함께 주는 이유: keep-all만 두면 띄어쓰기 없는 긴 문자열(URL·영문
   합성어)이 끊기지 못해 **상자 밖으로 삐져나간다.** 그때만 강제로 끊는 안전판이다. */
.b-hero-title,
.b-cover-inner h1,
.b-card-body h2,
.b-page-head h1,
.b-postnav-t,
.b-series-name,
body.blog .article-body h2,
body.blog .article-body h3 { word-break: keep-all; overflow-wrap: break-word; }

.b-hero-title { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-family: var(--font-display); font-size: clamp(26px, 2.6vw, 36px);
  font-weight: 700; line-height: 1.18; letter-spacing: -.024em; color: var(--heading);
  margin-bottom: 14px; text-wrap: balance; }
.b-hero-ex { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: 15px; line-height: 1.7; color: var(--text-muted); text-wrap: pretty; }
/* 링크 어포던스 — 시안의 '읽기 →'. 마크업에 없어 장식으로 붙인다 */
.b-hero-inner::after { content: "읽기 →"; margin-top: 26px; font-size: 13.5px; font-weight: 600;
  color: var(--accent); }

/* 히어로 캐러셀 — 데스크톱은 첫 장만 보이고, 모바일에서 트랙이 가로 스크롤이 된다 */
.b-hero-wrap { position: relative; }
.b-hero-track > .b-hero:not(:first-child) { display: none; }
.b-hero-dots { display: none; }

/* 커버 없는 카드/히어로의 이니셜 판 — 컬러 그라디언트(main.css .pg-*)를 덮는다.
   같은 특이도라도 blog.css가 뒤에 로드돼 이긴다. */
.b-hero, .b-card-cover, .b-cover { background-image: none; }
.b-card-cover > img, .b-cover > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.b-initial { font-family: var(--font-mono); font-size: 40px; font-weight: 700;
  color: var(--text-muted);
  color: color-mix(in srgb, var(--accent) 26%, transparent); }

/* ══ 필터 · 칩 ═════════════════════════════════════════════ */
.b-filters { margin: 30px 0 0; }
.b-chips { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
/* 종류(kind)는 테두리 칩, 카테고리는 테두리 없는 납작한 칩 — 시안이 두 축을 이렇게 구분한다 */
.b-chip { padding: 7px 15px; border-radius: var(--radius); border: 1px solid var(--line-strong);
  font-size: 12.5px; font-weight: 600; color: var(--text); white-space: nowrap;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease); }
.b-chip:hover:not(.is-on) { background: var(--accent-soft); border-color: var(--accent); }
.b-chip.is-on { background: var(--heading); border-color: var(--heading); color: var(--bg); }
.b-chip-cat { padding: 6px 11px; border: 0; font-weight: 600; color: var(--text-muted); background: transparent; }
.b-chip-cat:hover:not(.is-on) { background: transparent; color: var(--accent); }
.b-chip-cat.is-on { background: transparent; color: var(--heading); border: 0; }
.b-chip-div { width: 1px; height: 22px; background: var(--line); margin: 0 6px; }
.b-chip-gap { flex: 1; }
.b-count { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-muted); }
/* 시리즈 칩은 모바일 전용 — 데스크톱 내비에 이미 시리즈가 있다.
   미디어쿼리보다 반드시 위에 둘 것(같은 특이도라 나중 규칙이 이긴다). */
.b-chip-series { display: none; }

/* ══ 카드 그리드 ═══════════════════════════════════════════ */
.b-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 26px; margin-top: 26px; }
/* position:relative — 수정 칩(.b-edit-chip)의 기준. 칩은 커버 <a> 밖에 있어야
   실제로 눌리므로(링크 안의 링크는 만들 수 없다) 카드를 기준으로 겹쳐 올린다. */
.b-card { position: relative; display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; background: var(--bg-elev);
  transition: transform var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease); }
.b-card:hover { border-color: var(--accent); transform: translateY(-2px); }
/* 고정 height 금지 — 썸네일이 늦게 오면 레이아웃이 밀린다(CLS) */
.b-card-cover { position: relative; aspect-ratio: 16 / 9; display: flex; align-items: center;
  justify-content: center; background: var(--bg-alt); overflow: hidden; }
.b-card-cover > img { transition: transform var(--dur-3) var(--ease); }
.b-card:hover .b-card-cover > img { transform: scale(1.03); }
.b-kind { position: absolute; top: 11px; left: 11px; padding: 4px 8px; border-radius: 2px;
  background: var(--bg-elev);
  background: color-mix(in srgb, var(--bg-elev) 92%, transparent); color: var(--heading);
  font-size: 11px; font-weight: 700; }
.b-kind.work { background: var(--accent); color: var(--accent-on); }
/* z-index — 커버 링크 위에 떠야 클릭이 칩에 닿는다. 아래 있으면 눌러도 글 상세로 간다.
   기준은 .b-card다(커버가 카드의 첫 요소라 카드 우상단 = 커버 우상단). */
.b-edit-chip { position: absolute; z-index: 2; top: 11px; right: 11px;
  padding: 4px 8px; border-radius: 2px;
  background: var(--bg-elev);
  background: color-mix(in srgb, var(--bg-elev) 92%, transparent); border: 1px solid var(--accent);
  color: var(--accent); font-family: var(--font-mono); font-size: 10.5px;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease); }
/* 눌리는 것임을 보이게 — <span>이던 시절에는 hover 반응이 없어 장식으로 읽혔다 */
.b-edit-chip:hover { background: var(--accent); color: var(--accent-on); }
/* flex:1 — 카드가 행 높이에 맞춰 늘어날 때 **본문이 그 높이를 받아야** 한다.
   없으면 내용이 위에 뭉치고 남는 공간이 전부 지표 줄 아래로 떨어져, 요약 길이에 따라
   지표 줄 위치가 카드마다 달라진다(실측 바닥여백 21/46/68px). */
.b-card-body { padding: 18px 20px 20px; display: flex; flex-direction: column; color: inherit; flex: 1; }
.b-card-kicker { display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); margin-bottom: 9px; }
.b-card-cat { color: var(--accent); font-weight: 700; }
/* 제목 min-height — 한 줄짜리 제목이 섞여도 카드 아래 지표 줄의 높이가 어긋나지 않는다 */
.b-card-body h2 { margin: 0 0 8px; font-family: var(--font-display); font-size: 1.19rem; font-weight: 600;
  line-height: 1.32; letter-spacing: -.01em; color: var(--heading); min-height: 50px; text-wrap: pretty; }
.b-card-body p { margin: 0 0 14px; font-size: .84rem; line-height: 1.6; color: var(--text-muted); text-wrap: pretty; }
/* margin-top:auto — 남는 공간을 지표 줄 **위로** 몰아 항상 카드 바닥에 붙인다.
   요약이 없거나 짧은 카드에서도 같은 자리에 선다. */
.b-card-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: auto; padding-top: 12px; border-top: 1px solid var(--line);
  font-size: .69rem; color: var(--text-muted); }
.b-empty { grid-column: 1 / -1; padding: 70px 0; text-align: center; color: var(--text-muted); font-size: 14px; }

/* ══ 구독 밴드 ═════════════════════════════════════════════ */
.b-subscribe { display: flex; align-items: center; justify-content: space-between; gap: 28px; flex-wrap: wrap;
  margin-top: 44px; padding: 30px 34px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--bg-alt); }
.b-sub-title { font-family: var(--font-display); font-size: 20px; font-weight: 700; color: var(--heading); }
.b-sub-desc { margin-top: 6px; font-size: 13.5px; color: var(--text-muted); }
.b-soon { font-family: var(--font-mono); font-size: 11.5px; color: var(--accent); }
.b-sub-form { display: flex; gap: 8px; }
.b-sub-form input { padding: 12px 16px; min-width: 240px; border-radius: var(--radius);
  border: 1px solid var(--line-strong); background: var(--bg-elev); color: var(--text);
  font: inherit; font-size: 13.5px; outline: none; }
.b-sub-form input:focus { border-color: var(--accent); }

/* ══ 글 상세 — 커버 ════════════════════════════════════════
 * 커버 이미지가 없는 글이 다수다. 그라디언트 + 키커 + 제목만으로 성립해야 하고,
 * 이미지는 그 위에 opacity로 얹는다. */
/* 비공개 글 미리보기 배너 — 공개 글로 착각하지 않게 상단에 고정 폭으로 깐다 */
.b-preview-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 44px; background: var(--accent-soft);
  border-bottom: 1px solid var(--line); font-size: .84rem; color: var(--text); }
.b-preview-bar .b-mono { font-size: 11px; letter-spacing: .1em; color: var(--accent); font-weight: 700; }
.b-preview-bar a { margin-left: auto; font-weight: 600; color: var(--accent); }
@media (max-width: 720px) { .b-preview-bar { padding: 10px 18px; } }

.b-article { padding-bottom: 72px; }
.b-cover { position: relative; min-height: 376px; display: flex; align-items: flex-end;
  background: var(--cover-grad); }
.b-cover > img { opacity: .55; }
.b-cover::after { content: ""; position: absolute; inset: 0; background: var(--cover-shade); }
.b-cover-inner { position: relative; z-index: 1; width: 100%; max-width: var(--wrap); margin: 0 auto;
  padding: 0 44px 38px; display: flex; flex-direction: column; gap: 13px; }
.b-cover-inner h1 { margin: 0; font-family: var(--font-display); font-size: clamp(25px, 4.2vw, 44px);
  font-weight: 700; line-height: 1.16; letter-spacing: -.024em; color: var(--on-cover); max-width: 840px;
  text-wrap: pretty; }
.b-cover .b-cat, .b-cover .b-mono { color: var(--on-cover-dim); }
.b-cover-back { align-self: flex-start; padding: 7px 13px; border-radius: var(--radius);
  border: 1px solid var(--on-cover-line); background: none; font-size: 12.5px;
  color: var(--on-cover-dim); transition: background var(--dur-2) var(--ease); }
.b-cover-back:hover { background: var(--on-cover-wash); color: var(--on-cover); }
.b-cover-kicker { font-size: 12px; letter-spacing: .1em; color: var(--on-cover-muted); }
.b-byline { display: flex; align-items: center; gap: 12px; }
.b-byline img { width: 32px; height: 32px; flex: none; border-radius: var(--radius); display: block; object-fit: cover; }

/* ══ 글 상세 — 본문 그리드 · 조판 ══════════════════════════ */
.b-article-grid { max-width: var(--wrap); margin: 0 auto; padding: 44px 40px 64px;
  display: grid; grid-template-columns: minmax(0, var(--read)) var(--rail); gap: 44px; justify-content: center; }
.b-article-main { min-width: 0; }

/* main.css의 .article-body 위에 블로그 조판을 덮는다. 본문 폭 780 / 18px / 1.85 —
   한글 한 줄 42~46자. 이 폭을 넘기면 줄을 놓친다. */
body.blog .article-body { font-size: 1.125rem; line-height: 1.85; color: var(--text); }
body.blog .article-body > * + * { margin-top: 1.2em; }
body.blog .article-body h2 { margin-top: 2em; font-size: 1.62rem; font-weight: 600; letter-spacing: -.015em;
  color: var(--heading); padding-left: 14px; border-left: 3px solid var(--accent);
  scroll-margin-top: 88px; }   /* 목차 점프 시 고정 헤더에 가리지 않게 — IO rootMargin과 같은 값 */
body.blog .article-body h3 { margin-top: 1.6em; font-size: 1.25rem; font-weight: 600;
  color: var(--heading); scroll-margin-top: 88px; }
body.blog .article-body a { color: var(--accent); text-decoration: underline;
  text-underline-offset: 3px; text-decoration-thickness: 1px; }
/* 리스트 — 마커(•, 1.)를 **본문과 같은 왼쪽선**에 세운다.
   기본값 list-style-position:outside는 마커를 콘텐츠 상자 **밖**에 그린다. main.css의
   전역 리셋(* { padding: 0 })이 브라우저 기본 padding-left까지 지워, 마커가 갈 자리가
   아예 없었다 — 발행 화면에서는 본문 왼쪽으로 삐져나가고 미리보기(overflow:auto)에서는
   잘려서 보이지 않았다.
   여백을 주는 대신 마커를 상자 **안**으로 들인다. 목록만 들여쓰기되어 문단과 어긋나
   보이는 것을 사용자가 원치 않았다(들여쓰기 없이 문단 왼쪽선에 맞춘다).
   대가: 항목이 길어 줄이 넘어가면 둘째 줄이 마커 아래에서 시작한다(매달린 들여쓰기
   없음). outside여야 얻는 정렬이라 둘 중 하나는 포기해야 한다. */
body.blog .article-body ul,
body.blog .article-body ol { padding-left: 0; list-style-position: inside; }
/* 중첩 목록만 들여쓴다 — 안 그러면 상위·하위가 같은 선에 서서 구분이 사라진다 */
body.blog .article-body li > ul,
body.blog .article-body li > ol { padding-left: 1.2em; margin-top: .4em; }
/* 항목 간격 — `> * + *`(1.2em)는 직계 자식만 잡아 li에는 닿지 않는다.
   문단만큼 벌리면 목록이 흩어져 보이므로 그보다 좁게 준다. */
body.blog .article-body li + li { margin-top: .4em; }
body.blog .article-body blockquote { padding: 18px 20px; background: var(--bg-alt);
  border-left: 3px solid var(--accent); border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 1rem; line-height: 1.75; color: var(--text); }
/* 코드블록은 두 테마 모두 어둡다(하이라이트 테마를 뒤집지 않는다). highlight.js의
   github-dark-dimmed가 자체 background를 선언하므로 여기서 덮어써야 한다 —
   이 파일에서 !important를 쓰는 유일한 지점이며, 외부 CSS 우선순위 때문이다. */
body.blog .article-body pre,
body.blog .article-body pre code.hljs { background: var(--code-bg) !important; }
body.blog .article-body pre { border: 1px solid var(--line);
  border-radius: var(--radius); padding: 16px 18px; font-size: .81rem; line-height: 1.75;
  overflow-x: auto; }   /* 코드 한 줄이 길면 모바일 레이아웃 전체가 밀린다 */
body.blog .article-body img { width: 100%; height: auto; border-radius: var(--radius); }
body.blog .article-body table { width: 100%; border-collapse: collapse; font-size: .94rem; }
body.blog .article-body th { text-align: left; padding: 10px 12px; border-bottom: 1.5px solid var(--heading); }
body.blog .article-body td { padding: 10px 12px; border-bottom: 1px solid var(--line); }

.b-engage { margin-top: 36px; }
.b-admin-actions { display: flex; gap: 12px; align-items: center; margin-top: 28px;
  padding-top: 22px; border-top: 1px solid var(--line); }
.b-admin-actions form { margin: 0; }
/* 글 위쪽 변형. 긴 글을 고칠 때 본문 끝까지 내려가지 않게 같은 조작을 위에도 둔다.
   본문 열(.b-article-main) 안에 있으므로 **아래 블록과 같은 좌측선**에 선다 —
   정렬을 따로 주지 않는 이유다(오른쪽으로 밀면 본문과 어긋나 보인다).
   위에서는 구분선을 긋지 않는다: 커버가 이미 경계라 줄이 하나 더 생기면 본문이
   시작하기도 전에 화면이 끊겨 보인다. */
.b-admin-actions.is-top { margin-top: 0; margin-bottom: 22px;
  padding-top: 0; border-top: 0; }
.b-postnav { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 32px; }
.b-postnav a { display: flex; flex-direction: column; gap: 6px; padding: 18px;
  border: 1px solid var(--line); border-radius: var(--radius); color: inherit;
  transition: border-color var(--dur-2) var(--ease); }
.b-postnav a:hover { border-color: var(--accent); }
.b-postnav a.is-next { text-align: right; }
.b-postnav-t { font-size: 15px; font-weight: 700; color: var(--heading); }
/* 모바일 전용 '목록으로' — 기본은 숨김이고 ~720 블록에서만 켠다.
   기본값 규칙이 미디어쿼리보다 **앞**에 있어야 한다(같은 특이도면 나중 규칙이 이긴다). */
.b-backlist { display: none; }

/* ══ 우측 레일 · 목차 · 진행률 ══════════════════════════════
 * sticky는 조상에 overflow:hidden이 있으면 조용히 죽는다. .b-article-grid와 그
 * 조상에 overflow를 걸지 말 것. */
.b-rail { position: sticky; top: 88px; align-self: start; display: flex; flex-direction: column; gap: 14px; }
.b-rail-card { padding: 18px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg-elev); }
.b-rail-label { display: block; font-size: 10.5px; letter-spacing: .14em; color: var(--text-muted); margin-bottom: 10px; }
.b-rail-line { margin: 0 0 6px; font-size: 13px; color: var(--text-muted); }
.b-rail-back { font-size: 12px; color: var(--text-muted); }
.b-rail-back:hover { color: var(--accent); }

.b-readbar { position: fixed; top: 0; left: 0; right: 0; height: 3px; background: var(--line); z-index: 60; }
.b-readbar span { display: block; height: 100%; width: 0; background: var(--accent);
  transition: width var(--dur-1) linear; }
.b-toc ul { list-style: none; margin: 6px 0 0; padding: 0; }
.b-toc li { margin: 0; }
.b-toc a { display: block; padding: 4px 0 4px 9px; border-left: 2px solid transparent;
  font-size: .84rem; line-height: 1.5; color: var(--text-muted);
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.b-toc a:hover { color: var(--text); }
.b-toc a.is-current, .b-toc a.is-active { color: var(--accent); font-weight: 600; border-left-color: var(--accent); }
.b-toc ul ul a { padding-left: 22px; font-size: .8rem; }
.b-progress { height: 4px; border-radius: 99px; background: var(--bg-alt); margin: 12px 0 6px; }
.b-progress span { display: block; height: 100%; width: 0; border-radius: 99px; background: var(--accent);
  transition: width var(--dur-1) linear; }
.b-rail-eps { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.b-rail-eps a { font-size: 13.5px; line-height: 1.5; color: var(--text-muted); }
.b-rail-eps a:hover { color: var(--accent); }
.b-rail-eps li.is-current a { color: var(--accent); font-weight: 700; }

/* 태블릿에서 레일 대신 본문 위에 뜨는 접이식 목차 (기본 숨김) */
.b-toc-inline { display: none; margin-bottom: 22px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--bg-elev); }
.b-toc-inline > summary { min-height: 44px; padding: 0 16px; cursor: pointer; font-size: 13px;
  color: var(--heading); list-style: none; display: flex; align-items: center;
  justify-content: space-between; gap: 12px; }
.b-toc-inline > summary::-webkit-details-marker { display: none; }
.b-toc-inline > summary .b-mono { font-size: 11.5px; letter-spacing: .12em; color: var(--text-muted); }
.b-toc-more { display: inline-flex; align-items: center; gap: 4px; font-size: 12.5px;
  font-weight: 600; color: var(--accent); }
.b-toc-more::after { content: "▾"; }
.b-toc-inline[open] .b-toc-more::after { content: "▴"; }
/* 열리면 '펼치기'가 아니라 '접기'다 — 라벨이 상태를 따라가지 않으면 오히려 헷갈린다 */
.b-toc-inline[open] .b-toc-more { font-size: 0; }
.b-toc-inline[open] .b-toc-more::before { content: "접기"; font-size: 12.5px; }
.b-toc-inline .b-toc { padding: 0 16px 14px; }

/* ══ 연락처 ════════════════════════════════════════════════
 * 포폴 /contact/ 와 **구성이 같다**(이메일·링크·위치·메시지 보내기). 다른 건 톤뿐이라
 * 새 토큰 없이 기존 토큰만 쓴다. 클래스는 b- 접두어로 새로 두었다 — main.css의
 * .contact-* 를 재사용하면 포폴 쪽 radius(8·14px)·색이 그대로 딸려 와, 3px 각진
 * Slate & Navy 사이에서 그 두 덩어리만 둥글게 남는다.
 */
.b-contact { display: grid; grid-template-columns: 1fr 1fr; gap: 56px;
  align-items: start; padding-bottom: 72px; }
.b-contact-links { display: flex; flex-direction: column; gap: 8px; }
.b-cl { display: flex; align-items: center; gap: 14px; padding: 15px 18px;
  border: 1px solid var(--line); border-radius: var(--radius); color: inherit;
  transition: border-color var(--dur-2) var(--ease), background var(--dur-2) var(--ease); }
.b-cl:hover { border-color: var(--accent); background: var(--accent-soft); }
/* 위치처럼 갈 곳이 없는 항목. hover를 주면 눌러보고 아무 일도 안 일어난다 */
.b-cl.is-static { cursor: default; }
.b-cl.is-static:hover { border-color: var(--line); background: none; }
.b-cl-icon { width: 36px; height: 36px; flex-shrink: 0; border-radius: var(--radius);
  background: var(--bg-alt); color: var(--text-muted);
  display: flex; align-items: center; justify-content: center;
  transition: background var(--dur-2) var(--ease), color var(--dur-2) var(--ease); }
.b-cl:not(.is-static):hover .b-cl-icon { background: var(--accent); color: var(--accent-on); }
.b-cl-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; margin-right: auto; }
.b-cl-label { font-size: 10.5px; letter-spacing: .12em; color: var(--text-muted); }
/* 이메일·URL은 길다. 줄바꿈 대신 말줄임으로 잘라 카드 폭을 지킨다 */
.b-cl-value { font-size: 14px; font-weight: 600; color: var(--heading);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.b-cl-arrow { flex-shrink: 0; color: var(--text-muted); transition: color var(--dur-2) var(--ease); }
.b-cl:hover .b-cl-arrow { color: var(--accent); }

.b-cform { background: var(--bg-elev); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 32px; }
.b-cform-title { margin: 0 0 6px; font-family: var(--font-display); font-size: 19px;
  font-weight: 700; color: var(--heading); }
.b-cform-sub { margin: 0 0 24px; font-size: 13.5px; line-height: 1.65; color: var(--text-muted); }
.b-cform-error { margin-bottom: 16px; padding: 11px 14px; border-radius: var(--radius);
  background: var(--danger-soft); border: 1px solid var(--danger); color: var(--danger);
  font-size: 13.5px; }
.b-cf-field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.b-cf-field label { font-size: 10.5px; letter-spacing: .12em; color: var(--text-muted); }
.b-cf-field input, .b-cf-field textarea { padding: 11px 14px; border: 1px solid var(--line-strong);
  border-radius: var(--radius); background: var(--bg); color: var(--text);
  font-family: var(--font-body); font-size: 14.5px; outline: none; resize: vertical;
  transition: border-color var(--dur-2) var(--ease); }
.b-cf-field input:focus, .b-cf-field textarea:focus { border-color: var(--accent); }
.b-cf-field textarea { min-height: 140px; line-height: 1.7; }
.b-cf-submit { width: 100%; justify-content: center; margin-top: 4px; }

.b-cform-done { text-align: center; padding: 32px 8px; }
.b-cform-check { width: 54px; height: 54px; margin: 0 auto 18px; border-radius: 50%;
  background: var(--ok-soft); color: var(--ok);
  display: flex; align-items: center; justify-content: center; }
.b-cform-done h2 { margin: 0 0 8px; font-family: var(--font-display); font-size: 19px;
  font-weight: 700; color: var(--heading); }
.b-cform-done p { margin: 0 0 20px; font-size: 13.5px; line-height: 1.7; color: var(--text-muted); }

/* ══ 통합 에러 화면 (404 · 403 · 500 · 503 · 429) ══════════
 * 시안 07a~07c. 새 토큰이 없다 — --accent / --bg-alt / --line만 쓰므로
 * 다크 모드는 별도 규칙 없이 위 토큰 세트가 그대로 적용된다.
 * 코드별로 달라지는 건 숫자·키커·문구·부가 블록뿐이라 CSS에는 코드 분기가 없다.
 */
.b-error { display: grid; place-items: center; min-height: calc(100vh - var(--header-h) - 120px);
  padding: 64px 20px; }
.b-error-in { display: flex; flex-direction: column; align-items: center; gap: 18px;
  /* place-items:center가 자식을 max-content로 줄인다. width가 없으면 자식의 100%가
     '콘텐츠 폭'에 대해 풀려, 최근 글이 붙는 404와 안 붙는 403의 CTA 폭이 달라진다. */
  width: 100%; max-width: 520px; text-align: center; }
.b-error-code { display: flex; align-items: baseline; gap: 12px; }
.b-error-code strong { font-family: var(--font-display); font-size: 5.6rem; font-weight: 700;
  line-height: 1; letter-spacing: -.04em; color: var(--accent); }
.b-error-code em { font-style: normal; font-size: .72rem; letter-spacing: .14em;
  color: var(--text-muted); }
.b-error h1 { margin: 0; font-family: var(--font-display); font-size: 1.62rem; font-weight: 600;
  letter-spacing: -.02em; color: var(--heading); text-wrap: balance; }
.b-error p { margin: 0; font-size: .94rem; line-height: 1.75; color: var(--text-muted);
  text-wrap: pretty; }
.b-error-cta { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-top: 6px; }
/* 500 전용 참조 번호 — 사용자가 문의할 때 서버 로그와 이어붙일 유일한 실마리 */
.b-error-ref { font-family: var(--font-mono); font-size: .69rem; color: var(--text-muted);
  padding: 9px 13px; background: var(--bg-alt); border-radius: var(--radius); }
/* 404 전용 최근 글 — 여기서 되돌아갈 길을 주지 않으면 에러 페이지가 막다른 길이 된다 */
.b-error-sug { display: flex; flex-direction: column; width: 100%; margin-top: 14px;
  padding-top: 20px; border-top: 1px solid var(--line); text-align: left; }
.b-error-sug > b { font-size: .66rem; letter-spacing: .12em; font-weight: 400;
  color: var(--text-muted); padding-bottom: 6px; }
.b-error-sug a { display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 44px; padding: 9px 0; border-top: 1px solid var(--line);
  font-size: .875rem; color: var(--text); transition: color var(--dur-1) var(--ease); }
.b-error-sug a:hover { color: var(--accent); }
.b-error-sug a span { font-size: .69rem; color: var(--text-muted); }

/* ══ 푸터 ══════════════════════════════════════════════════ */
.b-footer { border-top: 1px solid var(--line); background: var(--bg-alt); }
.b-foot-inner { max-width: var(--wrap); margin: 0 auto; padding: 26px 44px; display: flex;
  align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.b-foot-brand { display: flex; align-items: center; gap: 14px; }
.b-foot-brand .b-mono { font-size: 11px; color: var(--text-muted); }
.b-foot-links { display: flex; gap: 20px; font-family: var(--font-mono); font-size: 11.5px; }
.b-foot-links a { color: var(--text-muted); transition: color var(--dur-1) var(--ease); }
.b-foot-links a:hover { color: var(--accent); }

/* ══ 드로어 (모바일 내비) ══════════════════════════════════
 * 시안 5a. v47까지는 포폴을 따라 '우측에서 열리는 다크 패널'이었지만, 블로그 시안은
 * **좌측에서 열리는 밝은 패널**이다. 방향·색이 모두 바뀌었다.
 *
 * 열고 닫는 스크립트는 바텀시트와 **같은 컨트롤러**(blog-sheet.js)를 쓴다.
 * 방향만 다르고 스크림·스크롤 잠금·Esc·포커스 처리는 동일하기 때문. 그래서
 * 마크업도 시트와 같은 계약(부모 .b-drawer[hidden] > .b-drawer-scrim + .b-drawer-body)을 따른다. */
.b-drawer { position: fixed; inset: 0; z-index: 70; display: block; }
.b-drawer[hidden] { display: none; }
.b-drawer-scrim { position: absolute; inset: 0; background: rgba(13, 18, 32, .42);
  opacity: 0; transition: opacity var(--dur-3) var(--ease); }
.b-drawer-body { position: absolute; top: 0; bottom: 0; left: 0; width: 300px; max-width: 86vw;
  display: flex; flex-direction: column; overflow-y: auto;
  background: var(--bg-elev); border-right: 1px solid var(--line);
  box-shadow: 14px 0 40px -18px rgba(13, 18, 32, .5);
  padding: 14px 16px max(20px, env(safe-area-inset-bottom));
  transform: translateX(-100%); transition: transform var(--dur-4) var(--ease-out); }
.b-drawer[data-open] .b-drawer-scrim { opacity: 1; }
.b-drawer[data-open] .b-drawer-body { transform: translateX(0); }

.b-drawer-head { display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 14px; }
.b-drawer-head .b-icon-btn { width: 44px; height: 44px; flex: none; }
.b-drawer-search { display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 12px;
  margin-bottom: 10px; border: 1px solid var(--line-strong); border-radius: var(--radius);
  background: var(--bg); color: var(--text-muted); }
.b-drawer-search input { border: 0; background: none; color: var(--text); font: inherit;
  font-size: 14px; width: 100%; outline: none; }
.b-drawer-search input::placeholder { color: var(--text-muted); }

.b-drawer-nav { display: flex; flex-direction: column; }
.b-drawer-nav a, .b-drawer-item { display: flex; align-items: center; gap: 10px;
  height: 48px; padding: 0 12px; border-radius: var(--radius);
  font-family: var(--font-display); font-size: 1.03rem; color: var(--text);
  width: 100%; text-align: left; background: none; border: 0; font-weight: 500;
  cursor: pointer; transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease); }
.b-drawer-nav a:hover, .b-drawer-item:hover { background: var(--bg-alt); }
.b-drawer-nav a.is-on, .b-drawer-item.is-on { background: var(--accent-soft); color: var(--accent); font-weight: 600; }

.b-drawer-label { margin: 16px 0 4px; padding: 0 12px; font-family: var(--font-mono);
  font-size: 10.5px; letter-spacing: .16em; color: var(--text-muted);
  border-top: 1px solid var(--line); padding-top: 16px; }
.b-drawer-cat { list-style: none; margin: 0; padding: 0; }
.b-drawer-cat a { display: flex; align-items: center; justify-content: space-between;
  height: 40px; padding: 0 12px; font-size: .875rem; color: var(--text);
  border-radius: var(--radius); transition: background var(--dur-1) var(--ease); }
.b-drawer-cat a:hover { background: var(--bg-alt); }
.b-drawer-cat .b-mono { font-size: 11.5px; color: var(--text-muted); }

/* 아래로 밀어 붙이는 꼬리 — 테마 버튼·로그인/아웃·집계 한 줄 */
.b-drawer-foot { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--line); }
.b-drawer-meta { display: block; padding: 6px 12px 0; font-family: var(--font-mono);
  font-size: 11px; color: var(--text-muted); }
.b-drawer-logout { margin: 0; }
.b-idx { font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); }
.b-toasts { position: fixed; top: 82px; right: 20px; z-index: 90; display: flex; flex-direction: column; gap: 8px; }

/* ══ 탐색(시리즈·태그·아카이브) · 페이지네이션 ═════════════ */
.b-page-head { padding: 40px 0 28px; border-bottom: 1px solid var(--line); margin-bottom: 32px; }
.b-page-head .b-mono { font-size: 11px; letter-spacing: .16em; color: var(--accent); }
.b-page-head h1 { margin: 8px 0 6px; font-family: var(--font-display); font-size: 34px;
  font-weight: 700; letter-spacing: -.02em; color: var(--heading); }
.b-page-head p { margin: 0; color: var(--text-muted); font-size: 14.5px; }
.b-section-head { display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 14px; }
.b-section-head .b-mono { font-size: 11.5px; letter-spacing: .14em; color: var(--text-muted); }

.b-pager { display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 36px; }
.b-page { min-width: 36px; height: 36px; padding: 0 10px; border-radius: var(--radius);
  border: 1px solid var(--line-strong); display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: 12.5px; color: var(--text-muted);
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.b-page:hover { border-color: var(--accent); color: var(--accent); }
.b-page.is-on { background: var(--accent); border-color: var(--accent); color: var(--accent-on); font-weight: 700; }
.b-page.is-off { opacity: .4; pointer-events: none; }

.b-rail-series { margin-top: 44px; }
.b-series-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.b-series-card { display: flex; align-items: center; gap: 15px; padding: 18px 20px;
  border-radius: var(--radius); background: var(--cover-grad); color: var(--on-dark);
  transition: transform var(--dur-2) var(--ease); }
.b-series-card:hover { transform: translateY(-2px); color: var(--on-dark); }
.b-series-n { width: 48px; height: 48px; flex: none; border-radius: var(--radius);
  background: rgba(243, 246, 252, .14); display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: 13px; font-weight: 700; color: var(--on-dark); }
.b-series-meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.b-series-name { font-size: 16px; font-weight: 700; }
.b-series-sub { font-size: 12.5px; color: var(--on-dark-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.b-series-block { margin-bottom: 44px; }
.b-series-title { font-family: var(--font-display); font-size: 20px; font-weight: 700; color: var(--heading); }
.b-series-intro { margin: 0 0 14px; font-size: 14px; color: var(--text-muted); }
.b-series-tag { font-size: 10.5px; color: var(--text-muted); }

.b-eps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.b-eps a { display: flex; gap: 16px; padding: 18px 20px; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--bg-elev); color: inherit;
  transition: border-color var(--dur-2) var(--ease); }
.b-eps a:hover { border-color: var(--accent); }
.b-ep-no { flex: none; width: 44px; font-family: var(--font-mono); color: var(--accent); font-size: 12px; }
.b-ep-body { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.b-ep-title { font-size: 16px; font-weight: 700; color: var(--heading); }
.b-ep-ex { font-size: 13.5px; color: var(--text-muted); }
.b-ep-meta { font-size: 11px; color: var(--text-muted); }

/* 태그 3단계 — 글 수 비율로 뷰(posts/views.py:tag_list)가 tier 클래스를 준다 */
.b-tagcloud { display: flex; flex-wrap: wrap; gap: 10px; }
.b-tagchip { display: inline-flex; align-items: center; gap: 8px; padding: 8px 13px;
  border-radius: var(--radius); border: 1px solid transparent; background: var(--bg-alt);
  font-size: .81rem; color: var(--text-muted);
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease); }
.b-tagchip:hover { border-color: var(--accent); color: var(--accent); }
.b-tagchip .b-mono { font-size: 11px; opacity: .8; }
.b-tagchip.t-mid { padding: 9px 15px; font-size: .875rem; background: var(--bg-elev);
  border-color: var(--line); color: var(--text); }
.b-tagchip.t-top { padding: 10px 17px; font-size: .94rem; font-weight: 600;
  background: var(--accent); border-color: var(--accent); color: var(--accent-on); }
.b-tagchip.t-top:hover { background: var(--accent-hover); color: var(--accent-on); }

.b-year { margin-bottom: 36px; }
.b-year-label { font-family: var(--font-display); font-size: 26px; font-weight: 700; color: var(--heading); }
.b-year-list { list-style: none; margin: 0; padding: 0; }
.b-year-list a { display: flex; align-items: center; gap: 14px; padding: 12px 4px;
  border-bottom: 1px solid var(--line); color: inherit; }
.b-year-list a:hover .b-year-title { color: var(--accent); }
.b-year-date { flex: none; width: 46px; font-family: var(--font-mono); font-size: 11.5px; color: var(--text-muted); }
.b-year-title { flex: 1; font-size: 15px; font-weight: 600; color: var(--heading);
  transition: color var(--dur-1) var(--ease); }

.b-related { margin-top: 40px; }
.b-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.b-postnav-none { display: flex; flex-direction: column; gap: 6px; padding: 18px;
  border: 1px dashed var(--line-strong); border-radius: var(--radius); color: var(--text-muted); }
.b-seriesnav a { border-color: var(--accent); background: var(--accent-soft); }

/* ══ 바텀시트 · 모바일 액션바 ══════════════════════════════ */
.b-actionbar { display: none; }
.b-sheet { position: fixed; inset: 0; z-index: 80; display: block; }
.b-sheet[hidden] { display: none; }
.b-sheet-scrim { position: absolute; inset: 0; background: rgba(13, 18, 32, .42);
  opacity: 0; transition: opacity var(--dur-3) var(--ease); }
.b-sheet-body { position: absolute; left: 0; right: 0; bottom: 0; max-height: 82vh; overflow-y: auto;
  background: var(--bg-elev); border-radius: 16px 16px 0 0;
  padding: 12px 20px max(24px, env(safe-area-inset-bottom));
  transform: translateY(100%); transition: transform var(--dur-4) var(--ease-out); }
.b-sheet[data-open] .b-sheet-scrim { opacity: 1; }
.b-sheet[data-open] .b-sheet-body { transform: translateY(0); }
.b-sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.b-sheet-head .b-mono { font-size: 11.5px; letter-spacing: .12em; color: var(--text-muted); }
.b-sheet .b-icon-btn { min-width: 44px; min-height: 44px; border-color: var(--line-strong); color: var(--text); }
.b-sheet ul { list-style: none; margin: 0; padding: 0; }
.b-sheet a { display: block; padding: 12px 6px; min-height: 44px; border-bottom: 1px solid var(--line);
  font-size: 15px; color: var(--text); }

/* 모바일 필터 진입 버튼 (기본 숨김 — 720 이하에서만 노출) */
.b-filter-open { display: none; align-items: center; justify-content: center; gap: 8px;
  min-height: 44px; flex: none; padding: 0 16px;
  border: 1px solid var(--accent); border-radius: var(--radius); background: var(--bg-elev);
  color: var(--accent); font: inherit; font-size: 13px; font-weight: 700; cursor: pointer; }

/* 시트 손잡이 — 끌어내릴 수 있다는 신호. 실제 드래그는 없고 시각 단서만 */
.b-sheet-grab { width: 38px; height: 4px; margin: 2px auto 10px; border-radius: 99px;
  background: var(--line-strong); }

/* ── 필터 시트 폼 (시안 3a) ────────────────────────────────
 * 인라인 칩과 달리 폼이다 — 고르는 동안 페이지가 다시 로드되지 않아야
 * 시트가 열린 채로 여러 축을 바꿀 수 있다. 적용은 하단 CTA 한 번. */
.b-fs { display: flex; flex-direction: column; gap: 18px; }
.b-fs-head { display: flex; align-items: baseline; justify-content: space-between; }
.b-fs-title { font-family: var(--font-display); font-size: 1.25rem; font-weight: 700; color: var(--heading); }
.b-fs-reset { font-size: .84rem; color: var(--text-muted); }
.b-fs-reset:hover { color: var(--accent); }
.b-fs-group { border: 0; margin: 0; padding: 0; }
.b-fs-label { padding: 0 0 8px; font-size: .78rem; color: var(--text-muted); }
.b-fs-seg { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.b-fs-chips { display: flex; flex-wrap: wrap; gap: 8px; }
/* 라디오는 숨기고 라벨을 칩처럼 그린다. 접근성은 input이 그대로 담당한다
   (:focus-visible이 input에 걸리므로 인접 span에 링을 옮겨 준다) */
.b-fs-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.b-fs-opt span { display: flex; align-items: center; justify-content: center; min-height: 44px;
  padding: 0 14px; border: 1px solid var(--line-strong); border-radius: var(--radius);
  font-size: .875rem; color: var(--text); cursor: pointer;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.b-fs-opt input:checked + span { background: var(--accent); border-color: var(--accent);
  color: var(--accent-on); font-weight: 700; }
.b-fs-opt input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
.b-fs-radios { display: flex; gap: 22px; }
.b-fs-radio { display: flex; align-items: center; gap: 9px; min-height: 44px;
  font-size: .9rem; color: var(--text); cursor: pointer; }
.b-fs-radio input { width: 20px; height: 20px; accent-color: var(--accent); }
.b-fs-cta { width: 100%; min-height: 52px; border: 0; border-radius: var(--radius);
  background: var(--accent); color: var(--accent-on); font: inherit; font-size: .95rem;
  font-weight: 700; cursor: pointer; transition: background var(--dur-1) var(--ease); }
.b-fs-cta:hover { background: var(--accent-hover); }

/* ══ 관리자 로그인 ═════════════════════════════════════════ */
.b-login-wrap { display: flex; align-items: center; justify-content: center;
  min-height: calc(100vh - var(--header-h)); padding: 40px 20px 80px; }
.b-login-card { width: min(380px, 100%); background: var(--bg-elev); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 34px 32px; box-shadow: 0 24px 60px rgba(13, 18, 32, .12); }
.b-login-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 26px; }
.b-login-kicker { font-family: var(--font-mono); font-size: .72rem; font-weight: 700; color: var(--accent);
  text-transform: uppercase; letter-spacing: .08em; margin-bottom: 5px; }
.b-login-head h1 { margin: 0; font-family: var(--font-display); font-size: 1.35rem; font-weight: 700; color: var(--heading); }
.b-login-head p { margin: 8px 0 0; font-size: 12.5px; line-height: 1.6; color: var(--text-muted); }
.b-login-close { width: 32px; height: 32px; flex: none; border-radius: var(--radius); border: 1px solid var(--line);
  background: var(--bg-alt); color: var(--text-muted); display: flex; align-items: center; justify-content: center; }
.b-login-close:hover { border-color: var(--accent); color: var(--heading); }
.b-login-msgs { margin-bottom: 16px; }
.b-login-err { margin: 0 0 8px; padding: 10px 12px; border-radius: var(--radius); font-size: 13px;
  background: var(--danger-soft); border: 1px solid var(--danger); color: var(--danger); }
.b-login-field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.b-login-field label { font-family: var(--font-mono); font-size: .72rem; font-weight: 700; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: .06em; }
.b-login-field input { padding: 11px 14px; border: 1.5px solid var(--line-strong); border-radius: var(--radius);
  background: var(--bg-elev); color: var(--text); font: inherit; font-size: .92rem; outline: none; }
.b-login-field input:focus { border-color: var(--accent); }
.b-login-submit { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%;
  margin-top: 8px; padding: 13px; border: 0; border-radius: var(--radius); background: var(--accent);
  color: var(--accent-on); font: inherit; font-size: .95rem; font-weight: 700; cursor: pointer;
  transition: background var(--dur-1) var(--ease); }
.b-login-submit:hover { background: var(--accent-hover); }

/* ══ 관리자 셸 (좌 216px 사이드바 + 본문) ══════════════════
 * 관리 화면은 공개 시안 범위 밖이다. 어두운 크롬을 유지하되 색만 새 토큰으로 맞춘다. */
.ba-shell { display: flex; min-height: 100vh; }
.ba-side { width: 216px; flex: none; background: var(--bg-elev); color: var(--text);
  border-right: 1px solid var(--line); padding: 22px 16px;
  display: flex; flex-direction: column; gap: 6px; position: sticky; top: 0; height: 100vh; }
.ba-brand { display: flex; align-items: center; gap: 7px; margin-bottom: 22px; padding: 0 8px; }
.ba-label { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .14em;
  color: var(--text-muted); padding: 0 8px 8px; }
/* 탭 래퍼는 데스크톱에서 레이아웃에 없는 것처럼 동작한다(자식이 사이드바의 직접 자식처럼 쌓임).
 * 모바일에서만 실제 컨테이너가 되어 상단 탭바로 바뀐다. */
.ba-tabs { display: flex; flex-direction: column; gap: 2px; }
/* 모바일 전용 상단 바·하단 탭바 — 데스크톱에서는 사이드바가 그 역할을 한다 */
.ba-topbar { display: none; }
.ba-tabbar { display: none; position: sticky; bottom: 0; z-index: 40; gap: 4px;
  padding: 8px 12px max(12px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line); background: var(--bg-elev); }
.ba-tabbar a { flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 4px; height: 52px; font-size: .66rem; color: var(--text-muted); }
.ba-tabbar a i { font-style: normal; font-size: 1rem; }
.ba-tabbar a.is-on { color: var(--accent); font-weight: 600; }
.ba-item { display: flex; align-items: baseline; gap: 7px; padding: 10px 12px; border-radius: var(--radius);
  font-size: 13.5px; color: var(--text-muted); border-left: 2px solid transparent;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease); }
.ba-item:hover { background: var(--bg-alt); color: var(--heading); }
.ba-item.is-on { background: var(--accent-soft); border-left-color: var(--accent);
  color: var(--accent); font-weight: 600; }
.ba-en { font-family: var(--font-mono); font-size: 10.5px; opacity: .6; }
.ba-gap { flex: 1; }
.ba-quiet { display: block; width: 100%; text-align: left; padding: 10px 12px; border: 0; border-radius: var(--radius);
  background: none; color: var(--text-muted); font: inherit; font-size: 12.5px; cursor: pointer; }
.ba-quiet:hover { background: var(--bg-alt); color: var(--heading); }
.ba-user { display: flex; align-items: center; gap: 10px; margin-top: 6px; padding-top: 14px;
  border-top: 1px solid var(--line); }
.ba-ava { width: 28px; height: 28px; flex: none; border-radius: var(--radius); object-fit: cover; }
.ba-ava-txt { display: flex; align-items: center; justify-content: center; background: var(--bg-alt);
  font-family: var(--font-mono); font-size: 11px; color: var(--heading); }
.ba-user-meta { font-size: 12.5px; color: var(--heading); line-height: 1.35; }
.ba-user-meta form { margin: 0; }
.ba-user-meta button { border: 0; background: none; padding: 0; color: var(--text-muted);
  font: inherit; font-size: 10.5px; text-decoration: underline; cursor: pointer; }
.ba-main { flex: 1; min-width: 0; background: var(--bg); }
.ba-page { padding: 32px 36px 60px; }
.ba-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  flex-wrap: wrap; margin-bottom: 26px; }
.ba-head h1 { margin: 0 0 6px; font-family: var(--font-display); font-size: 26px;
  font-weight: 700; color: var(--heading); }
.ba-head h1 span { font-size: 14px; font-weight: 400; color: var(--text-muted); }
.ba-head p { margin: 0; font-size: 13.5px; color: var(--text-muted); }
.ba-seg { display: flex; gap: 6px; align-items: center; }
.ba-seg a, .ba-seg button { padding: 6px 12px; border: 0; border-radius: var(--radius); background: none;
  font: inherit; font-size: 12.5px; font-weight: 600; color: var(--text-muted); cursor: pointer; }
.ba-seg a.is-on { background: var(--accent); color: var(--accent-on); }
.ba-card { border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg-elev); padding: 20px; }
.ba-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; margin-bottom: 20px; }
.ba-kpi-label { font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .12em;
  color: var(--text-muted); margin-bottom: 12px; }
.ba-kpi-value { font-family: var(--font-display); font-size: 32px; font-weight: 700;
  color: var(--heading); line-height: 1; }
.ba-kpi-sub { font-size: 12px; color: var(--accent); margin-top: 9px; }

/* ══ 테마 버튼 ═══════════════════════════════════════════
 * main.css의 슬라이더(.theme-track/.theme-knob)를 쓰지 않는다. 그 컴포넌트는 포폴의
 * **항상 네이비인 사이드바** 전제로 트랙이 흰색 18%·노브가 흰색이라, 밝아진 블로그
 * 면 위에서는 흰색이 흰색 위에 놓여 사실상 보이지 않는다(라이트 모드에서 실제로 밟음).
 * 프로토타입도 슬라이더가 아니라 버튼이다.
 * 아이콘·문구는 '지금 상태'가 아니라 **누르면 갈 상태**를 가리킨다. */
.b-theme-sun { display: none; }
html[data-theme="dark"] .b-theme-moon { display: none; }
html[data-theme="dark"] .b-theme-sun { display: block; }

/* 드로어·관리자 사이드바는 글자 버튼 — 좁은 화면에서 아이콘만 두면 뜻이 안 잡힌다 */
.b-drawer-theme, .ba-theme { cursor: pointer; font-family: inherit; }
.ba-theme { width: 100%; text-align: left; }

/* 스위치 — 드로어의 테마 전환용. main.css의 .theme-track/.theme-knob와 달리
   트랙을 선 색으로, 노브를 면 색으로 그려 **라이트에서도 보인다**. */
.b-switch { position: relative; flex: none; margin-left: auto; width: 38px; height: 22px;
  border-radius: 99px; background: var(--line-strong);
  transition: background var(--dur-2) var(--ease); }
.b-switch-knob { position: absolute; top: 3px; left: 3px; width: 16px; height: 16px;
  border-radius: 50%; background: var(--bg-elev); box-shadow: 0 1px 3px rgba(13, 18, 32, .35);
  transition: transform var(--dur-2) var(--ease); }
html[data-theme="dark"] .b-switch { background: var(--accent); }
html[data-theme="dark"] .b-switch-knob { transform: translateX(16px); }

/* 드로어 테마 항목 — 글자 대신 아이콘. 아이콘은 '누르면 갈 상태'를 가리킨다 */
.b-drawer-theme-ico { display: inline-flex; align-items: center; color: var(--text); }

/* 관리자 뉴스레터 노출 토글 */
.nl-toggle form { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin: 0; }
.nl-toggle-txt { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 200px; }
.nl-toggle-txt strong { font-size: .95rem; color: var(--heading); }
.nl-toggle-txt span { font-size: .82rem; color: var(--text-muted); }
.nl-switch { display: inline-flex; align-items: center; gap: 10px; min-height: 44px; cursor: pointer; }
.nl-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.nl-switch .b-switch { margin-left: 0; }
/* 체크 상태는 테마가 아니라 입력값이 정한다 — html[data-theme] 규칙과 별개로 다시 건다 */
.nl-switch input:checked + .b-switch { background: var(--accent); }
.nl-switch input:checked + .b-switch .b-switch-knob { transform: translateX(16px); }
.nl-switch input:focus-visible + .b-switch { outline: 2px solid var(--accent); outline-offset: 2px; }
.nl-switch-state { font-family: var(--font-mono); font-size: .78rem; color: var(--text-muted); }

/* ══ 태블릿 (~1099) — 2열 · 레일 접기 ══════════════════════ */
@media (max-width: 1099px) {
  .b-wrap { padding: 0 28px 56px; }
  .b-grid, .b-series-grid, .b-grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .b-article-grid { grid-template-columns: minmax(0, 640px); gap: 32px; padding: 26px 28px 0; }
  .b-rail { display: none; }
  .b-toc-inline { display: block; }
  .b-contact { gap: 32px; }
  .b-nav { display: none; }
  /* 검색은 숨기지 않고 접는다 — display:none만 하면 모바일에서 검색 진입 경로가 사라진다 */
  .b-search-toggle { display: flex; }
  .b-search { position: absolute; left: 16px; right: 16px; top: 100%; width: auto; height: 44px;
    background: var(--bg-elev); border-color: var(--line-strong);
    box-shadow: 0 10px 24px rgba(13, 18, 32, .14); display: none; z-index: 10; }
  .b-search.is-open { display: flex; }
  .b-hero { min-height: 320px; }
  .b-hero-inner { padding: 34px 30px; }
  .b-cover { min-height: 280px; }
  .b-cover-inner, .b-foot-inner { padding-inline: 28px; }

  /* 관리자 — 사이드바를 64px 아이콘 레일로 줄인다(프로토타입). 라벨은 감춘다 */
  .ba-side { width: 64px; padding: 18px 8px; }
  .ba-side .b-logo, .ba-side .b-suffix, .ba-label, .ba-en,
  .ba-quiet, .ba-user-meta { display: none; }
  .ba-tabs .ba-item { justify-content: center; padding: 10px 0; }
  .ba-page { padding: 26px 22px 60px; }
}

/* ══ 모바일 (~720) — 재배치. 축소가 아니다 ═════════════════ */
@media (max-width: 720px) {
  .b-wrap { padding: 0 18px 56px; }
  .b-header { height: 54px; padding: 0 18px; gap: 10px; }
  .b-burger { display: block; min-width: 44px; min-height: 44px; }
  .b-logout, .b-actions .b-btn { display: none; }
  .b-actions { gap: 8px; }
  /* 헤더 오른쪽은 검색 + 테마 두 개다(시안 3a). 44px 정사각형 두 개가 나란히 서면
     54px 헤더에서 로고보다 먼저 눈에 들어온다 — 34px으로 줄이고 아이콘도 함께 줄인다.
     터치 타겟 44px 권장치보다 작지만, 헤더 높이가 54px이라 그 안에서 44를 지키면
     버튼이 헤더를 거의 다 차지한다. 위아래 여백이 실제 터치 여유를 만들어 준다. */
  .b-actions .b-icon-btn { width: 34px; height: 34px; }
  .b-actions .b-icon-btn svg { width: 13px; height: 13px; }
  /* 테마 버튼은 모바일 헤더에도 남긴다 — 검색 오른쪽. 마크업상 이미 그 순서다.
     로그인 링크(a.b-icon-btn)만 접는다(드로어에 있다). */
  .b-actions > a.b-icon-btn { display: none; }
  .b-adminbar { padding: 9px 16px; flex-wrap: wrap; gap: 8px; }

  /* 히어로 — 가로 스크롤 캐러셀. 카드는 **화면 폭을 꽉 채운다**.
   * 시안 3a는 다음 장을 살짝 보이게(294px) 했지만, 아래 점 인디케이터가 이미
   * '더 있다'를 알려주므로 중복이다. 애매하게 좁아진 카드가 제목·요약만 눌러 놓는다.
   * 스냅 컨테이너라 한 번 밀면 정확히 한 장씩 넘어간다. */
  .b-hero-track { display: flex; gap: 12px; margin-top: 14px; overflow-x: auto;
    scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; }
  .b-hero-track::-webkit-scrollbar { display: none; }
  .b-hero-track > .b-hero,
  .b-hero-track > .b-hero:not(:first-child) { display: grid; flex: 0 0 100%; scroll-snap-align: start; }
  .b-hero-dots { display: flex; justify-content: center; gap: 6px; margin-top: 10px; }
  .b-hero-dot { width: 18px; height: 3px; border-radius: 99px; background: var(--line-strong);
    transition: background var(--dur-1) var(--ease); }
  .b-hero-dot.is-on { background: var(--accent); }

  /* 히어로 — 모바일은 **커버 위 오버레이** 한 장이다(시안 3a).
   *
   * v47~v53은 데스크톱 2단 카드를 세로로 접어 '이미지 150px + 그 아래 텍스트 블록'으로
   * 뒀다. 동작 목업(mockup/blog-prototype.html)이 그렇게 되어 있어 따랐던 것인데,
   * **스크린샷 시안 3a와 어긋난다.** 접힌 형태는 이미지 높이 + 텍스트 블록 높이가
   * 그대로 더해져 260px을 넘고, 텍스트가 카드 배경(--bg-elev) 위에 따로 얹혀
   * 첫 화면이 빽빽해 보인다. 두 시안이 다를 때는 **스크린샷을 정본으로 본다.**
   *
   * 그래서 세 요소를 같은 칸(1/1)에 겹쳐 쌓는다: 커버 → 그늘 → 글.
   * 데스크톱은 밝은 2단 카드라 그늘이 필요 없어 계속 숨긴다. */
  /* 높이는 200 → 160 → 128px로 두 번 줄였다(사용자 조정). 128px은 안에 들어갈 것을
     다 세면 여유가 15px 남는 값이다 — 패딩 34 + 배지줄 19 + 간격 6 + 제목 2줄 54.
     더 줄이려면 제목을 1줄로 자르거나 패딩부터 손봐야 한다. */
  .b-hero { grid-template-columns: 1fr; height: 128px; margin-top: 0; }
  .b-hero-img,
  .b-hero-shade,
  .b-hero-inner { grid-area: 1 / 1; }
  .b-hero-img { height: 100%; }
  .b-hero-shade { display: block; position: relative; background: var(--cover-shade); }
  /* 글이 커버 위로 올라오므로 색이 뒤집힌다 — 커버는 두 테마 모두 어둡다 */
  /* 아래 정렬이라 글 뭉치를 올리는 손잡이는 **바닥 패딩**이다(18 → 26px = 8px 위로).
     배지·제목이 커버 아래 모서리에 붙어 있던 것을 조금 띄운다. 남은 여유는 7px이라
     여기서 더 올리려면 높이를 되돌리거나 제목을 1줄로 잘라야 한다. */
  .b-hero-inner { position: relative; justify-content: flex-end; padding: 16px 18px 26px; }
  .b-hero-tags { margin-bottom: 6px; }
  /* FEATURED 배지는 색을 덮지 않는다 — 토큰(--accent / --accent-on)이 테마마다 알아서
     뒤집힌다. 라이트는 남색 판에 밝은 글자, 다크는 #6E9BE8 판에 어두운 글자.
     어두운 커버 위에서 남색 판의 '테두리'는 배경에 묻지만 밝은 글자가 라벨을 살리고,
     시안 3a도 같은 모습이다. 크기만 모바일에 맞춰 줄인다. */
  .b-pick { font-size: 10px; padding: 3px 7px; }
  .b-hero-meta { font-size: 10.5px; color: var(--on-cover-muted); }
  /* 높이를 160px로 줄였으므로 제목이 길면 넘친다. 아래 정렬이라 넘치면 위가 잘린다 */
  .b-hero-title { font-size: 21px; line-height: 1.28; margin-bottom: 0; color: var(--on-cover);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .b-hero-ex { display: none; }
  /* '읽기 →'는 데스크톱 시안(01c)에만 있다. 카드 전체가 링크라 모바일에서는
     한 줄을 더 쓰면서 아무것도 알려주지 않는다. */
  .b-hero-inner::after { display: none; }

  /* 필터 — 종류 칩은 줄에 남기고(가장 자주 쓴다) 카테고리·정렬만 시트로 넘긴다.
     칩이 넘치면 줄 안에서 가로 스크롤. '필터' 버튼은 오른쪽 끝 고정. */
  /* 히어로를 128px로 줄이면서 위 여백도 같이 좁아 보였다. 점 인디케이터(margin-top:10)
     바로 밑이라 칩 줄이 커버에 붙는다 — 14 → 26px으로 띄운다. */
  .b-filters { display: flex; align-items: center; gap: 10px; margin-top: 26px; }
  .b-chips { flex: 1; min-width: 0; flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none; padding: 2px 0; }
  .b-chips::-webkit-scrollbar { display: none; }
  /* 칩과 '필터' 버튼의 높이를 한 값(36px)으로 맞춘다. 칩 40 / 버튼 44로 4px 어긋나
     있던 것을 없애면서, 줄 전체를 조금 낮췄다(사용자 조정).
     ⚠ 여기서 **`.b-chips .b-chip` 같은 자손 선택자를 쓰지 말 것.** 특이도가 0-2-0이라
     아래 `.b-chip-cat { display:none }`(0-1-0)을 이기고, 순서와 무관하게 카테고리
     칩이 모바일에 되살아난다(실제로 밟음 — 필터 줄에 Data·AI·Dev…가 다시 나왔다). */
  .b-chip { flex: none; display: inline-flex; align-items: center;
    min-height: 36px; padding: 0 14px; font-size: 12.5px; }
  .b-chip-cat, .b-chip-div, .b-chip-gap, .b-count { display: none; }
  .b-chip-series { display: inline-flex; }
  .b-filter-open { display: inline-flex; min-height: 36px; padding: 0 14px; font-size: 12.5px; }

  /* 카드 — 3열 그리드에서 88px 썸네일 리스트로 */
  .b-grid, .b-grid-3, .b-series-grid { grid-template-columns: 1fr; gap: 0; margin-top: 8px; }
  .b-card { display: grid; grid-template-columns: 88px minmax(0, 1fr); gap: 14px;
    border: 0; border-top: 1px solid var(--line); border-radius: 0;
    padding: 16px 0; background: transparent; }
  .b-card:hover { transform: none; border-color: var(--line); }
  .b-card-cover { aspect-ratio: 1; border-radius: var(--radius); }
  .b-card:hover .b-card-cover > img { transform: none; }
  .b-kind, .b-edit-chip { top: 5px; left: 5px; right: auto; padding: 2px 5px; font-size: 9.5px; }
  .b-edit-chip { display: none; }
  .b-card-body { padding: 0; }
  .b-card-kicker { font-size: 10.5px; margin-bottom: 5px; }
  .b-card-body h2 { font-size: 1rem; line-height: 1.4; margin-bottom: 6px; min-height: 0; }
  .b-card-body p { display: none; }   /* 3번째 줄부터는 버린다 */
  .b-card-foot { padding-top: 8px; border-top: 0; font-size: 10.5px; justify-content: flex-start; gap: 10px; }
  .b-series-card { border-radius: var(--radius); margin-bottom: 10px; }

  .b-subscribe { flex-direction: column; align-items: stretch; padding: 22px 20px; }
  .b-sub-form { flex-direction: column; }
  .b-sub-form input { min-width: 0; }
  .b-sub-form .b-btn { min-height: 44px; justify-content: center; }

  .b-cover { min-height: 216px; }
  .b-cover-inner { padding: 0 18px 24px; }
  .b-article-grid { padding: 24px 18px 0; }
  body.blog .article-body { font-size: 1.03rem; line-height: 1.8; }
  .b-postnav { grid-template-columns: 1fr; }
  .b-postnav a.is-next { text-align: left; }
  /* 이전/다음 글 바로 아래. 이전·다음 카드와 같은 테두리를 쓰되 accent 글자로
     '되돌아가기'임을 구분한다. 44px는 터치 타겟 최소치. */
  .b-backlist { display: flex; align-items: center; justify-content: center; gap: 8px;
    min-height: 48px; margin-top: 12px; padding: 12px 18px;
    border: 1px solid var(--line-strong); border-radius: var(--radius);
    font-size: 14px; font-weight: 600; color: var(--accent);
    transition: border-color var(--dur-2) var(--ease), background var(--dur-2) var(--ease); }
  .b-backlist:active { background: var(--accent-soft); border-color: var(--accent); }
  /* 연락처 — 링크 목록이 먼저, 폼이 아래. 폼을 위에 두면 '누구에게 보내는지'를
     보기 전에 입력부터 마주친다. 카드 좌우 여백을 줄여 값 말줄임을 늦춘다. */
  .b-contact { grid-template-columns: 1fr; gap: 28px; padding-bottom: 56px; }
  .b-cl { padding: 14px 14px; min-height: 60px; }
  .b-cform { padding: 22px 18px; }
  .b-cf-field input, .b-cf-field textarea { font-size: 16px; }   /* iOS 자동 확대 방지 */

  /* 에러 화면 — CTA를 세로로 꽉 채운다. 가로로 두면 코드마다 문구 길이가 달라
     버튼 폭이 들쭉날쭉해지고, 390폭에서는 '태그로 찾기'가 두 줄로 깨진다. */
  .b-error { min-height: calc(100vh - 56px); padding: 40px 18px; }
  .b-error-code strong { font-size: 3.8rem; }
  .b-error h1 { font-size: 1.31rem; }
  .b-error p { font-size: .875rem; }
  .b-error-cta { width: 100%; flex-direction: column; }
  .b-error-cta .b-btn { width: 100%; justify-content: center; min-height: 48px; }

  .b-foot-inner { flex-direction: column; align-items: flex-start; gap: 14px; padding-inline: 18px; }
  .b-page-head { padding: 24px 0 18px; }
  .b-page-head h1 { font-size: 26px; }
  .b-pager .b-page { min-width: 44px; height: 44px; }

  /* 하단 고정 액션바 — 상세 */
  .b-actionbar { display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 55;
    background: var(--bg);
    background: color-mix(in srgb, var(--bg) 96%, transparent);
    border-top: 1px solid var(--line); padding: 8px 6px max(8px, env(safe-area-inset-bottom));
    justify-content: space-around; align-items: center; }
  .b-ab-btn { flex: 1; min-height: 44px; display: flex; flex-direction: column; align-items: center;
    justify-content: center; gap: 3px; border: 0; background: none; color: var(--text-muted);
    font: inherit; font-size: 11.5px; cursor: pointer; }
  .b-ab-btn.is-on, .b-ab-btn:active { color: var(--accent); }
  .b-article { padding-bottom: 96px; }   /* 액션바에 본문이 가리지 않게 */
  /* 목차는 모바일에서도 본문 위 접이식으로 남긴다(시안 3a: 'ON THIS PAGE · 5 / 펼치기').
     하단 액션바의 목차 버튼(바텀시트)과 둘 다 두는 이유 — 시트는 읽는 중에 점프할 때,
     이 접이식은 글에 들어오자마자 구조를 훑을 때 쓴다. */
  .b-toc-inline { display: block; margin-bottom: 18px; }

  /* ── 관리자 모바일 ──
   * 사이드바를 통째로 숨기고 **하단 탭바**로 내비를 옮긴다(프로토타입 §3-4).
   * 상단바에는 브랜드만 남긴다 — ☰를 두면 탭바와 진입경로가 중복된다. */
  .ba-topbar { display: flex; align-items: center; gap: 10px; position: sticky; top: 0; z-index: 50;
    height: 52px; padding: 0 16px; background: var(--bg); color: var(--heading);
    border-bottom: 1px solid var(--line); }
  .ba-topbar .ba-brand { margin: 0; padding: 0; }
  .ba-topbar-theme { margin-left: auto; }
  .ba-shell { display: block; min-height: 100vh; }
  .ba-side { display: none; }
  .ba-tabbar { display: flex; }
  .ba-page { padding: 18px 16px 24px; }
  .ba-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
}

/* ══ 모션 접근성 — 전역으로 한 번 꺾는다 ═══════════════════ */
@media (prefers-reduced-motion: reduce) {
  body.blog *, body.blog *::before, body.blog *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
