/* ============================================================
   print.css — 인쇄 · PDF 저장
   media="print" 로 링크되므로 파일 전체가 인쇄에만 적용된다.
   (그래서 @media print 로 한 번 더 감싸지 않는다.)

   목표: 채용 담당자가 상세 페이지를 Ctrl+P 로 뽑았을 때
   화면용 장식 없이 문서로 읽히고, 칸이 중간에서 잘리지 않게.
   ============================================================ */

@page {
  size: A4;
  margin: 16mm 14mm;
}

/* ============================================================
   1. 색 — 잉크를 아끼고 대비를 올린다
   ------------------------------------------------------------
   다크모드로 보던 중에 인쇄해도 흰 바닥·검은 글자로 나와야 한다.
   그래서 토큰을 인쇄값으로 통째로 덮는다.
   ============================================================ */

/* ⚠️ `:root` 하나로는 다크 토큰을 못 덮는다.
   tokens.css:159 의 `@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) }`
   는 특정성 (0,2,0) 이고 여기 `:root` 는 (0,1,0) 이다. 소스 순서는 특정성이
   같을 때만 보므로, print.css 를 뒤에 링크해도 진다.
   그래서 "시스템이 다크인 사람이 테마 버튼을 누른 적 없이 Cmd+P" 하면
   --text-muted 가 #a3a3a3 인 채로 흰 종이에 찍혀 캡션·메타가 거의 안 보였다
   (html/body 는 !important 라 바탕과 본문 글자만 멀쩡했다).
   같은 (0,2,0) 인 `:root:not([data-theme="light"])` 를 함께 걸어 순서로 이긴다.
   (github-76 의 정적 분석 제보 → 선택자·특정성 직접 확인 후 반영) */
:root,
:root:not([data-theme="light"]),
:root[data-theme="dark"],
:root[data-theme="light"] {
  --bg:            #fff;
  --surface:       #fff;
  --surface-2:     #fff;
  --surface-sunk:  #fff;
  --text:          #000;
  --text-muted:    #1a1a1a;
  --text-faint:    #4a4a4a;
  --border:        #bbb;
  --border-strong: #666;
  --accent:        #000;
  --accent-weak:   #fff;
  /* 절 사이 간격 — 화면 값이 인쇄로 그대로 넘어오는 유일한 간격이다.
     --sp-* 는 rem 기반이라 인쇄에서 1rem=10.5pt 로 같이 줄지만,
     --section-gap 은 clamp(72px, 10vw, 120px) 라 px·vw 기반이어서 안 줄고
     혼자 19~21mm 를 먹는다(github-b4 계측). 종이에서는 이 비대칭이 쪽을
     성기게 만들어 문서가 아니라 슬라이드처럼 보인다.
     ※ 토큰으로 덮어야 한다. `section {}` 으로 걸면 .detail-section(0,1,0)에
       져서 상세 페이지에서 죽은 규칙이 된다. */
  --section-gap:   9mm;

  --paper:         #fff;
  --paper-edge:    #bbb;

  --cat:      #666;
  --cat-tint: #fff;


  --shadow-card: none;
  --shadow-lift: none;

  color-scheme: light;
}

html, body {
  background: #fff !important;
  color: #000;
  font-size: 10.5pt;
  line-height: 1.55;
}

/* ============================================================
   2. 화면 전용 요소 제거
   ============================================================ */

.site-header,
.site-nav,
.theme-toggle,
.skip-link,
.site-footer,
/* 상세 페이지 맨 위의 '← ROBOTICS & EMBEDDED' — 화면에서 목록으로 돌아가는 길이다.
   종이에는 돌아갈 목록이 없고, 남아 있으면 웹을 그대로 뽑은 티가 난다. */
.detail-breadcrumb,
.pager {
  display: none !important;
}

/* ============================================================
   3. 레이아웃 — 화면 폭 제한을 풀고 종이 폭을 다 쓴다
   ============================================================ */

.container,
main.container {
  max-inline-size: none;
  inline-size: auto;
  margin: 0;
  padding: 0;
}

.detail { --measure: none; }

.section > p,
.detail-section > p,
.detail-section > ul:not([class]),
.contrib p,
.ts-item__val,
.ts-item > p,
.detail-oneline,
.hero__tagline,
.about__lead,
.figure__caption,
.ts-note {
  max-inline-size: none;
}

/* ============================================================
   4. 쪽 나눔
   ============================================================ */

.proj-card,
.proj-row,
.ts-item,
.contrib,
.figure,
.impact-grid > .impact-item,
.exp-table tr,
.awards li, .certs li, .education li {
  break-inside: avoid;
  page-break-inside: avoid;
}

h1, h2, h3,
.detail-section__title,
.proj-section__title,
.section__title,
.contrib__title,
.ts-item__title {
  break-after: avoid;
  page-break-after: avoid;
}

.detail-section,
.proj-section { break-before: auto; }

/* 낱줄 방지. 기본값이 2 인 브라우저도 있지만 인쇄에서는 명시해 둔다. */
p, li, dd, .ts-item__val, .impact-item__label { orphans: 2; widows: 2; }

/* Troubleshooting 의 문제·원인·해결·결과는 한 덩어리로 읽어야 뜻이 산다.
   .ts-item 에만 avoid 를 걸면 항목 안에 도판이 있을 때 <dl> 이 쪼개졌다. */
.ts-item__rows,
.contrib-side,
.contrib-side__text,
.video-embed,
.figure--pair { break-inside: avoid; page-break-inside: avoid; }

/* 수치 카드 넷은 한 줄이라 줄 전체가 같은 쪽에 있어야 한다.
   칸마다 avoid 만 걸면 줄이 쪽 경계에서 갈렸다. */
.impact-grid { break-inside: avoid; page-break-inside: avoid; }

/* 표 머리를 쪽마다 반복 */
thead { display: table-header-group; }
tr { break-inside: avoid; }
/* 짧은 표(결과표, 비교표)는 쪽 사이에 갈리지 않게 */
.table-wrap { break-inside: avoid; page-break-inside: avoid; }
/* 결과표 섹션은 제목과 표가 떨어지지 않게 통째로 */
#results { break-inside: avoid; page-break-inside: avoid; }
.detail-section__title { break-after: avoid; page-break-after: avoid; }

/* ============================================================
   5. 컴포넌트 — 화면 장식을 문서 장식으로 바꾼다
   ============================================================ */

.proj-card,
.ts-item,
.impact-grid > .impact-item {
  box-shadow: none;
  border: 0.5pt solid #999;
  border-radius: 0;
  transform: none !important;
}

/* 카드 상단 분야 바는 인쇄에서 회색 막대로 */
.proj-card::before { background: #666; }

.proj-card__impact {
  background: none;
  border: 0.5pt solid #ccc;
  border-radius: 0;
}

.impact-grid > .impact-item { border-inline-start: 2pt solid #666; }

.badge {
  border: 0.5pt solid #666;
  border-radius: 0;
  background: none;
}
.badge::before { display: none; }

.tag {
  background: none;
  border: 0.5pt solid #bbb;
  border-radius: 0;
}
.tag-more { border-style: dashed; }

.detail-links a,
.hero__links a {
  min-block-size: 0;
  padding: 0 0.4em 0 0;
  border: 0;
  font-weight: 400;
}

/* 링크 주소를 종이에 남긴다 — 인쇄물에서는 클릭할 수 없으므로.
   내부 링크(projects/...)는 주소가 길기만 해서 넣지 않는다. */
.detail-links a[href^="http"]::after,
.site-footer a[href^="http"]::after {
  content: " (" attr(href) ")";
  font-size: 8.5pt;
  font-weight: 400;
  color: #4a4a4a;
  word-break: break-all;
}
.detail-links a[target="_blank"]::after { content: " (" attr(href) ")"; }

a { color: #000; text-decoration: underline; }

/* ============================================================
   6. 도판 — 반전을 반드시 끈다
   화면에서 다크로 보던 중 인쇄하면 음화가 종이에 그대로 찍힌다.
   ============================================================ */

.figure__img--invert,
.figure__img--diagram,
.figure img {
  filter: none !important;
  background: #fff !important;
  border: 0.5pt solid #ccc;
  border-radius: 0;
}

/* 문단 사이 간격 — 화면은 1.15em(base.css)인데, 종이에서는 줄 간격이
   이미 1.55 라 문단 사이가 한 줄 반씩 벌어진다. 문서로 읽히도록 좁힌다. */
p + p { margin-block-start: 0.85em; }

.figure { margin-block: 4mm; }

/* 설계 도판 — 화면에서는 본문 폭을 다 써서 세로 109mm 가 되는데,
   그러면 BACKGROUND 한 절이 두 쪽에 걸쳐 끊긴다. 종이에서는 한 절이
   한 쪽에 들어가는 것이 먼저라 세로를 묶는다. SVG 라 줄여도 글자가
   깨지지는 않지만 실효 pt 는 같이 준다 — 이 값을 더 내리면 도판 안
   글자가 못 읽는 크기가 된다(표시 pt = 원본 font-size × 표시폭pt ÷ viewBox 폭). */
.figure img.figure__img--diagram { max-block-size: 72mm; }



/* 도판이 한 쪽을 넘지 않게 — 넘으면 통째로 다음 쪽으로 밀린다 */
.figure img { max-block-size: 150mm; object-fit: contain; }

/* 글 옆에 세운 사진(.contrib-side)은 위 규칙의 예외다.
   화면에서는 absolute + block-size:100% 로 글 높이에 맞춰 두었는데,
   인쇄에서 150mm 상한이 끼어들면 그 높이가 깨져 사진이 납작해진다.
   인쇄에서는 배치를 정상 흐름으로 되돌리고 비율만 지킨다. */
.contrib-side .figure { position: static; }
.contrib-side .figure img {
  position: static;
  inline-size: 100%;
  block-size: auto;
  max-block-size: 90mm;
  object-fit: contain;
}

/* 글자가 든 도면을 옆칸에 세우면 종이에서 못 읽는다.
   `!side` 사진 칸은 본문 폭의 42% = 74.5mm 다. 사진·스크린샷은 그래도 되지만
   단계 목록이 든 도면은 안 된다 — wc-parking-9step.svg(viewBox 1020, 최소 글자 12px)가
   그 칸에서 종이 **2.48pt** 로 찍힌다. 아무도 못 읽는다.
   (표시 pt = 원본 font-size × 표시폭pt ÷ viewBox 폭)

   그 절만 2단을 풀어 글 아래로 내리고 본문 폭을 쓴다. 74.5 → 177.4mm 로 가면
   2.48pt → 5.92pt 가 되어 본문의 다른 도면(5.19pt)과 같은 급이 된다.

   왜 `--diagram` 전체가 아니라 `--diagram-tall` 인가
   같은 클래스라도 옆칸에서 읽히는 도면이 있다. nav-robot 의
   people-fov-diagram(1168×600)·gpt-gate-diagram(640×330)은 노드 서넛짜리라
   38mm 에서도 읽힌다. 이 둘까지 전폭으로 올리면 세로가 각 +53mm 씩 늘어
   **nav-robot 이 5쪽 → 6쪽으로 회귀한다**(실측함).
   가르는 기준은 세로/가로 비다 — build.py 가 0.60 을 넘는 도판에만
   `--diagram-tall` 을 붙인다. 현재 이 클래스가 붙은 것은 9step 한 장뿐이다. */
.contrib-side:has(.figure__img--diagram-tall) {
  display: block;
}
.contrib-side:has(.figure__img--diagram-tall) > .figure {
  margin-block-start: 4mm;
}
/* 옆칸 90mm(0,2,1)·도면 72mm(0,2,2) 두 상한을 이 경우에만 푼다.
   이 선택자는 (0,4,1) 이라 둘 다 이긴다. */
.contrib-side:has(.figure__img--diagram-tall)
  .figure img.figure__img--diagram-tall {
  max-block-size: 150mm;
}

/* 아키텍처 도면 — **두 장이 한 쪽에 같이 있어야 한다.**
   전동휠체어의 V1·V2 는 나란히 놓고 비교하라고 만든 짝이라, 쪽이 갈리면
   목적 자체가 없어진다. 그런데 자연 크기로는 안 들어간다(실측):
     본문 182mm 폭에서  V1 126.6mm · V2 130.7mm · 제목 아래 시작 25.4mm
     필요 126.6 + 2(사이) + 130.7 = 259.3mm  >  남은 255.6mm   — 3.7mm 초과

   **세로가 아니라 가로로 묶는다.** `max-block-size` 로 누르면 더 긴 V2 만
   줄어 **V1 176.0mm · V2 170.6mm 로 폭이 어긋난다**(실측함). 세로로 쌓인
   두 도면의 좌우 끝이 5.4mm 어긋나면 비교하라고 만든 짝이 망가진다.
   가로 상한을 주면 둘이 같은 배율로 줄어 **폭이 176.0mm 로 정확히 같다.**

   175mm 에서 두 장이 2쪽에 같이 들어가고 아래로 3.7mm 남는다.
   도면 글자는 5.19 → **4.99pt**. 기준인 sona-arch(5.19pt)보다 0.2pt 낮지만,
   쪽이 갈리는 것보다 낫다는 판단이다(사용자 결정).
   detail.css 의 `max-block-size:none`(0,4,1)을 같은 선택자로 덮는다 —
   특정성이 낮으면 이 규칙은 통째로 죽는다. */
.detail-section .figure:has(.figure__img--arch) img.figure__img--arch {
  max-inline-size: 175mm;
  max-block-size: none;
  padding: 2mm;          /* 화면 --sp-4(3.7mm) → 2mm. 도판 넷이 7mm 를 돌려준다 */
}
.detail-section .figure:has(.figure__img--arch) {
  margin-block: 2mm;     /* 화면 4mm → 2mm */
}

/* ============================================================
   7. 표
   ============================================================ */

.exp-table { font-size: 9.5pt; }

.exp-table thead,
.exp-table tbody,
.exp-table tr,
.exp-table th,
.exp-table td {
  display: revert;   /* 모바일 카드형 전환을 되돌린다 */
}

.exp-table td::before { content: none !important; }

.exp-table tbody th,
.exp-table td {
  padding: 2mm 4mm 2mm 0;
  border-block-end: 0.5pt solid #ccc;
}

.exp-table tr {
  padding: 0;
  margin: 0;
  background: none;
  border: 0;
}

/* ============================================================
   8. 움직임 제거
   ============================================================ */

*, *::before, *::after {
  transition: none !important;
  animation: none !important;
}

/* ============================================================
   9. 수치 카드 넷 — 종이에서는 한 줄로
   ------------------------------------------------------------
   components.css 는 넷을 세우는 조건을 @media (min-width: 920px) 에
   걸어 두었다. 그런데 인쇄 미디어쿼리가 재는 폭은 A4 본문 폭
   (210mm - 좌우 14mm = 182mm ≒ 688px) 이라 920px 에 못 미친다.
   그래서 화면에서는 넷인 줄이 종이에서만 2×2 로 접혔다.
   인쇄에서는 폭이 A4 로 고정이므로 조건 없이 넷으로 박는다.

   넷으로 세우면 칸 안쪽이 좁아져(688px 기준 칸당 ≒ 164px)
   가장 긴 라벨 "LOCKED, READY, NAV, PAUSED" 가 접힌다.
   칸을 늘릴 수는 없으니 안쪽 여백과 글자를 줄여 맞춘다.
   ============================================================ */

.impact-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)) !important; }

.impact-grid > .impact-item {
  padding: 2mm 2.5mm;
  border-inline-start-width: 1.5pt;
}

.impact-grid .impact-item__num { font-size: 11pt; }
.impact-grid .impact-item__unit { font-size: 8pt; }
.impact-grid .impact-item__label { font-size: 7.6pt; line-height: 1.4; }

/* ============================================================
   10. 영상 — <video> 만 뺀다
   ------------------------------------------------------------
   <video> 는 인쇄에서 그 순간의 프레임이 찍힌다. nav-robot 의
   coex-demo.mp4 는 budget 20000 으로 3회 렌더해도 픽셀이 같았고
   (차이 0, 같은 판별식이 다른 쪽에서는 34,101 을 낸다) 찍히는 장면도
   멀쩡했지만, doori 의 영상은 서로 안 맞는 두 패널이 겹친 채
   찢어져 나왔다(github-b4 확인). 어느 파일이 어떻게 찍힐지는
   파일마다 달라 CSS 로는 가릴 수 없으므로 전부 뺀다.
   .figure--pair 로 좁히면 .figure--wide 안의 영상이 빠져나간다.

   YouTube iframe 은 인쇄에서 흰 빈 칸으로 남고 영상 제목만 흐리게,
   오른쪽이 잘린 채 찍힌다(github-3c 실측 — 크롬이 배경을 기본적으로
   인쇄하지 않으므로 검은 상자가 아니다). 잉크 낭비가 아니라 렌더가
   실패한 것처럼 보이는 게 문제다. 게다가 wheelchair-parking 과
   interactive-sound 는 페이지 머리 링크 목록에도 주소가 없어
   종이에서 영상 주소가 **완전히 사라진다**(github-b4 페이지별 확인).

   그래서 빈 칸을 접고 주소를 보인다. 주소는 생성기가 .video-url 이라는
   실제 <a> 로 심고(build.py render_video) 화면에서만 감춰 두었다.
   CSS content: attr() 로 찍으면 선택도 복사도 안 되기 때문이다 —
   이 PDF 는 채용 담당자가 주소를 눌러 보거나 옮겨 칠 문서다.
   한 곳에서 만들므로 영상이 늘어도 빠뜨릴 수 없다 — 한때 페이지별
   :has() 목록으로 하다가 nav-robot 둘만 걸고 여섯을 빠뜨린 적이 있다.
   ============================================================ */

.figure video { display: none !important; }

.video-embed {
  aspect-ratio: auto;
  background: none;
  padding: 0;
  border: 0;
}

.video-embed iframe { display: none !important; }

.video-url {
  display: block;
  font-size: 9.5pt;
  color: var(--text-muted);
  padding-block: 1mm;
  border-block-start: 0.5pt solid var(--border);
}

.video-url a { color: var(--text); text-decoration: none; }

/* 영상을 빼면 짝 도판(.figure--pair)에 사진 한 장만 남는다.
   auto-fit 이 빈 트랙을 접어 그 한 장이 본문 폭을 독차지하고,
   aspect-ratio 4/3 이라 세로 137mm — 쪽의 절반이 사진 하나가 된다.
   components.css 의 `.figure.figure--pair > img` 가 max-block-size:none 이라
   같은 특이도로 받아 높이를 묶는다. 4/3 강제도 함께 풀어 덜 잘리게 한다. */
.figure.figure--pair > img {
  aspect-ratio: auto;
  object-fit: contain;
  inline-size: auto;
  max-inline-size: 100%;
  max-block-size: 95mm;
}

/* ============================================================
   11. 가로 넘침 방지 — A4 본문 폭(182mm) 밖으로 나가는 것이 없게
   ============================================================ */

img, svg, video, iframe, table, pre {
  max-inline-size: 100%;
}

pre, code { white-space: pre-wrap; word-break: break-word; }

.detail-tags, .detail-links { flex-wrap: wrap; }

/* ============================================================
   전동휠체어 — 절이 쪽 경계에서 갈리지 않게
   ------------------------------------------------------------
   목표 두 개가 "같은 쪽에 모여 있을 것"이다. 쪽수는 기준이 아니다.
     ① Architecture 도면 2장  → 2쪽에 (위 arch 규칙이 맡는다)
     ② Contributions 4절      → 3쪽에
   ============================================================ */

/* 절 사이 간격 — 화면 --sp-7(7.4mm) 은 종이에서 과하다.
   4절이면 3번 들어가 22mm 를 먹는데, 그만큼이 도판 크기에서 빠진다. */
.contrib { margin-block-end: 2mm; }

/* 9step 도판 세로 상한.
   앞서 이 도판을 옆칸(74.5mm·2.48pt)에서 글 아래 전폭으로 내려 6.07pt 로 만들었다.
   그런데 전폭으로 내려가면 그 절 하나가 160mm 를 먹어 **Contributions 가 한 쪽에
   안 들어간다**(3쪽 여유 159mm, 필요 206mm — 실측).

   둘 다 만족하는 최댓값이 74mm 다. 이때 도판 글자는 **3.81pt**.
     · 옆칸으로 되돌리면 2.48pt 로 더 나쁘다 — 옆칸은 글 칸에 폭을 뺏겨
       도판이 83mm 를 못 넘는다(글 칸 90mm 확보 기준).
     · 전폭 + 세로 상한이 같은 높이에서 더 큰 도판을 준다. 그래서 이 방식이다.
   ⚠ 3.81pt 는 본문 기준(5.19pt)의 73% 다. 단계 목록은 **읽히지 않는다.**
     "사진을 줄여서라도 한 쪽에" 라는 지시를 따른 결과이고, 읽히게 하려면
     도판을 다시 그리거나(단계 수를 줄이거나) 절을 옮겨야 한다 — print.css 밖이다. */
.contrib-side:has(.figure__img--diagram-tall) .figure img.figure__img--diagram-tall {
  max-block-size: 74mm;
}
