/* 물밑 콘솔 — 새 셸과 보드 (2026-08-22)
 *
 * tokens.css 뒤에 온다. 여기 있는 것은 전부 신규 컴포넌트이거나, 랜딩에서만
 * 쓰는 기존 컴포넌트의 재조정이다. 다른 페이지는 아직 이 파일을 불러오지
 * 않는다 — 랜딩이 승인되면 같은 링크를 추가하는 방식으로 확산한다.
 */

/* ======================================================================
 * 1. 마스트헤드 — 한 줄에 9개를 밀어넣던 것을 3구역으로 나눈다.
 *    좌: 브랜드+내비 / 중: 검색 / 우: 모드·언어.
 *    세션 상태·환율·접속자·연결 상태는 전부 아래 테이프로 내려보냈다.
 * ================================================================== */
/* 셸(마스트헤드·탭·검색·아이콘 버튼)은 monitor.css로 옮겼다 — 2026-09-01.
 *
 * 여기 있는 동안 **약관 3장만 이 파일을 안 불러서** 머리가 옛 모양으로 남아
 * 있었다. 실측(1440px, /privacy 대 /kr): 마스트헤드 높이 36px 대 58px,
 * 좌우 여백 0 대 60px, 아래 선 없음 대 1px, search.js가 꽂는 입력칸 16px 대
 * 32px. legal.css의 주석은 "셸은 공용에서 온다"고 적어 두었는데 그 공용이
 * console.css였고 법적 페이지는 그것을 안 실었다 — 글로 쓴 원칙과 실제
 * 배선이 갈린 자리다.
 *
 * monitor.css는 **두 계열이 모두** 싣는 파일이라, 옮기면 복제 없이 갈린다. */

/* 쉬움 / 전문가 -------------------------------------------------------- */
/* 두 칸을 **같은 너비로** 잡는다. 내용 폭에 맡기면 글자 수가 곧 칸 크기가
   되어, 알약 모서리와 만나면 짧은 쪽이 원이 되고 긴 쪽만 알약이 된다 —
   고른 쪽이 클수록 커 보여서 저울이 기운 것처럼 읽힌다(운영자 제보
   2026-09-05, 폰 화면).

   실측(같은 화면에서 규칙만 갈아 끼워 잰 값):
     데스크톱  쉬움 44.5 / 전문가 54.8  →  54.8 / 54.8
     폰(≤560)  38.5×44 / 48.8×44       →  48.8×44 / 48.8×44
   폰의 38.5×44는 세로가 더 길다 — 그래서 알약이 아니라 원으로 보였다.

   영어가 더 심하다: Simple(6자) 대 Pro(3자). 로케일마다 라벨 길이가
   다르므로 폭을 글자에 맡기지 않는 쪽이 맞다. 1fr 두 칸은 넓은 쪽에
   맞춰 함께 커지므로 잘리는 라벨도 없다. */

/* ==================================================================
 * 값이 오기 전에도 자리를 잡는다 — 4G 실측(2026-08-31)
 *
 * 느린 4G(RTT 150ms · 1.6Mbps) + CPU 4배 감속에서 값이 4.5초에 도착하는데,
 * 그 순간 문서가 3,451 → 18,944px로 부풀며 화면이 872px 밀렸다
 * (CLS 1.003 · /kr, 0.523 · 홈, 1.095 · /us). 원인은 단순하다 — 값이 오기 전
 * 보드와 레인이 **0px**라서, 아래 섹션들이 첫 화면 안에 몰려 있다가
 * 한꺼번에 밀려난다.
 *
 * 그래서 첫 화면을 잡는 블록만 미리 자리를 비워 둔다. 가짜 카드는 놓지
 * 않는다 — 없는 값을 그린 것처럼 보이면 안 된다(DESIGN.md §6). 비워 둔
 * 자리는 첫 라운드가 끝나면 놓아 준다(monitor.js가 .booting을 뗀다). 값이
 * 왔으면 내용이 더 크므로 밀림이 없고, 못 왔으면 접히는데 그 자리는 이미
 * 첫 화면 밖이라 세지 않는다.
 *
 * 폰에서만 건다. 데스크톱 4G는 재 본 적이 없다.
 * ================================================================== */
@media (max-width: 700px) {
  html.booting #board-state,
  html.booting .console-section[data-rank="lead"] .state-block {
    min-height: 64vh; min-height: 64svh;
  }
  /* 넓어진 상자 한가운데에 "불러오는 중"이 뜨면 화면 절반쯤에 글자가 혼자
   * 떠 있다. 위쪽에 세워 둔다 — 값이 들어올 자리의 첫 줄과 같은 높이다. */
  html.booting #board-state,
  html.booting .console-section[data-rank="lead"] .state-block {
    place-items: start center; padding-top: var(--sp-7);
  }
}

/* ======================================================================
 * 2. 테이프 — 마스트헤드 아래 고정 한 줄. 터미널의 시세 띠.
 * ================================================================== */
.tape {
  position: sticky; top: var(--mast-h); z-index: 90;
  display: flex; align-items: center; gap: 0;
  height: var(--tape-h); overflow: hidden;
  padding: 0 max(var(--sp-4), calc((100vw - 1320px) / 2));
  /* 불투명하게 둔다. 반투명 유리로 두면 스크롤할 때 뒤의 큰 숫자가 비쳐서
   * 테이프 값과 겹쳐 읽힌다 — 얇은 띠에서 유리 질감은 얻는 게 없다. */
  background: var(--bg-deep);
  border-bottom: 1px solid var(--line);
}

/* 흐르는 칸. 같은 묶음 두 벌이 나란히 서서 함께 왼쪽으로 밀린다 — 첫 벌이
 * 빠진 자리에 둘째 벌이 들어와 이음매가 없다. 속도는 console.js가 폭에 맞춰
 * --tape-duration으로 넣는다. */
.tape-track {
  flex: 1 1 auto; min-width: 0; height: 100%; display: flex; overflow: hidden;
  /* 양 끝을 흐리게 잘라 낸다. 그냥 자르면 세션 배지 옆에서 종목명이 반쯤
   * 잘린 채 멈춰 보이는데, 페이드가 있으면 띠가 아래로 흘러 들어가는 것처럼
   * 읽힌다. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 22px, #000 calc(100% - 22px), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 22px, #000 calc(100% - 22px), transparent 100%);
}
.tape-run {
  flex: none; height: 100%; display: flex;
  animation: tape-marquee var(--tape-duration, 60s) linear infinite;
  will-change: transform;
}
@keyframes tape-marquee { to { transform: translateX(-100%); } }
/* 값을 읽으려고 올려둔 손을 존중한다 — 닿으면 멈춘다. :hover는 스크립트가
 * 없을 때의 대비책이고, 실제 정지는 console.js가 .is-paused로 건다(터치에는
 * hover가 없다). */
.tape:hover .tape-run,
.tape:focus-within .tape-run,
.tape.is-paused .tape-run { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) {
  /* 움직임을 줄여 달라고 한 사용자에게는 흐르지 않는 띠를 준다. 대신 손으로
   * 옆으로 밀 수 있게 열어 둔다. */
  .tape-run { animation: none; }
  .tape-run + .tape-run { display: none; }
  .tape-track { overflow-x: auto; scrollbar-width: none; }
  .tape-track::-webkit-scrollbar { display: none; }
}

/* 세션 배지는 monitor.js가 채운다(휴장일 달력 반영). 테이프 안에서는 알약이
 * 아니라 첫 칸처럼 보이게 한다. */
.tape .session-badge {
  flex: none; align-self: center; margin-right: var(--sp-3); padding: 0 var(--sp-4) 0 0;
  border: 0; border-right: 1px solid var(--line); border-radius: 0;
  color: var(--ink-2); font: 700 var(--fs-xs)/1 var(--sans); white-space: nowrap;
}
.tape .session-badge i { background: var(--amber); }
.tape .session-badge.open { color: var(--green); }
@media (max-width: 760px) { .tape .session-badge { display: inline-flex; } }

/* 접속자 수도 마스트헤드가 아니라 테이프에 산다. */
.tape .presence-badge {
  flex: none; margin-right: var(--sp-2); padding: 0 var(--sp-3) 0 0;
  border: 0; border-right: 1px solid var(--line); border-radius: 0;
  color: var(--ink-3); font: 600 var(--fs-xs)/1 var(--sans); white-space: nowrap;
}
.tape .presence-badge:empty { display: none; }

/* baseline 정렬은 34px 칸 안에서 글자를 위쪽에 붙여 놓는다 — 옆의 세션 배지와
 * 높이가 어긋나 보이던 원인이다. 세 조각 모두 line-height를 1로 맞추고 가운데
 * 정렬하면 배지와 같은 선에 앉는다. */
.tape-item {
  display: inline-flex; align-items: center; gap: 7px; flex: none;
  padding: 0 var(--sp-4); height: 100%; text-decoration: none; white-space: nowrap;
  border-right: 1px solid color-mix(in srgb, var(--line) 55%, transparent);
}
.tape-item:hover { background: var(--panel); color: inherit; }
.tape-item > * { line-height: 1; }
.tape-name { color: var(--ink-2); font-size: var(--fs-xs); font-weight: 600; }
.tape-value { color: var(--ink); font: 650 var(--fs-sm)/1.2 var(--num); font-variant-numeric: tabular-nums; }
.tape-delta { font: 650 var(--fs-xs)/1.2 var(--num); font-variant-numeric: tabular-nums; }
.tape-delta.up { color: var(--up); }
.tape-delta.down { color: var(--down); }
.tape-delta.flat { color: var(--ink-3); }
.tape-delta.none { display: none; }

/* ======================================================================
 * 3. 셸·섹션
 * ================================================================== */
.shell { width: min(1320px, 100%); padding: var(--sp-6) var(--sp-4) var(--sp-8); }

/* 히어로 카피는 걷어냈다. 첫 화면은 값이 차지한다. */
/* 상태줄은 제목 줄에 맞춰 선다.
 * flex-end였을 때는 왼쪽 블록의 **바닥**, 즉 설명 문단에 맞춰 내려와 있었다.
 * 제목과 나란히 서는 편이 "이 화면의 상태"라는 뜻에 맞다. */
.console-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap;
  padding-bottom: var(--sp-4); margin-bottom: var(--sp-4);
}
.console-head h1 {
  margin: 0; font-size: var(--fs-xxl); font-weight: 700; letter-spacing: -.03em;
}
.console-h1-sub { color: var(--ink-3); font-size: var(--fs-lg); font-weight: 500; letter-spacing: -.02em; }
.console-head .console-sub { margin: 4px 0 0; color: var(--ink-2); font-size: var(--fs-sm); }
.console-meta {
  display: flex; align-items: center; gap: var(--sp-3);
  color: var(--ink-3); font-size: var(--fs-xs);
  /* h1 한 줄과 같은 높이를 차지하게 해서 세로 가운데를 맞춘다. 5px 같은 숫자를
   * 박지 않고 타이포 토큰을 따라가므로 글자 크기가 바뀌어도 어긋나지 않는다
   * (실측: h1 line-height 44.8px = --fs-xxl 28px × 1.6). */
  min-height: calc(var(--fs-xxl) * 1.6);
}
.console-meta strong { color: var(--ink-2); font-family: var(--num); font-weight: 650; }
.refresh-button { padding: var(--sp-1h) 11px; border-radius: var(--r-sm); font-size: var(--fs-xs); }

.console-section { margin: var(--sp-7) 0 0; }
/* **첫 구역 위에는 떼어 놓을 것이 없다.** 이 여백은 구역과 구역 **사이**를
   가르는 값인데 첫 구역 위에도 그대로 붙어, 셸의 위 여백과 겹쳐 빈 자리가
   된다. 실측(라이브 390px, `/kr`·`/us`·`/crypto` 전부 같음): 테이프 아래끝
   92 → 첫 제목 위끝 140, **48px**이 비어 있었다(셸 16 + 구역 32).
   운영자 지적 2026-09-07: "각 탭의 최상위 섹션이 너무 위에서 떨어져서
   시작하는거같지않아? 공백이 너무 많아보여."

   `:first-child`로 가르는 것이 핵심이다 — 홈은 `main`이 값 보드로 시작해
   구역이 첫 자식이 아니므로 이 규칙이 걸리지 않고, 홈의 리듬은 그대로다
   (실측: `/kr`은 첫 자식 맞음, `/`는 아님). */
main > .console-section:first-child { margin-top: 0; }
.console-section > header {
  display: flex; align-items: baseline; gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}
/* 쪽 제목 묶음을 빼면서 첫 섹션 제목이 h1이 됐다(2026-09-04) — 같은 자리면
   같은 꼴이어야 하므로 규칙이 둘 다 받는다. 안 받으면 h1이 브라우저 기본
   여백(0.67em ~ 20px)을 써서 제목이 혼자 아래로 밀린다(폰 실측 178 vs 158). */
.console-section > header :is(h1, h2) { margin: 0; font-size: var(--fs-xl); font-weight: 700; }
.console-section > header .sec-note { color: var(--ink-3); font-size: var(--fs-sm); }
.console-section > header .sec-link { margin-left: auto; color: var(--accent); font-size: var(--fs-sm); font-weight: 600; text-decoration: none; }
.console-section > header .sec-link:hover { text-decoration: underline; }

/* 주말 섹션은 평일에 접혀 있어야 해서 <details>다. <summary>가 header 자리를
   대신하므로 같은 배치를 주고, 기본 삼각형 대신 방향 표시를 오른쪽에 둔다. */
.weekend-details > summary {
  display: flex; align-items: baseline; gap: var(--sp-3);
  margin-bottom: var(--sp-4); padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--line);
  cursor: pointer; list-style: none;
}
.weekend-details > summary::-webkit-details-marker { display: none; }
.weekend-details > summary::after {
  content: "BE"; margin-left: auto; color: var(--ink-3); font-size: var(--fs-sm);
  transition: transform .15s;
}
.weekend-details[open] > summary::after { transform: rotate(180deg); }
.weekend-details > summary h2 { margin: 0; font-size: var(--fs-xl); font-weight: 700; }
.weekend-details > summary .sec-note { color: var(--ink-3); font-size: var(--fs-sm); }

/* ======================================================================
 * 4. 보드 — 첫 화면의 대표 숫자들
 * ================================================================== */
.board { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
@media (max-width: 1080px) { .board { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .board { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); } }

.tile {
  position: relative; overflow: hidden; isolation: isolate;
  display: flex; flex-direction: column; gap: var(--sp-2);
  min-height: 158px; padding: var(--sp-4);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
  text-decoration: none; color: inherit;
  transition: border-color .15s, background .15s, transform .15s;
}
a.tile:hover { border-color: var(--line-strong); background: var(--panel-2); transform: translateY(-1px); color: inherit; }

/* 로고와 이름 사이는 **한 곳에서만** 정한다.
 *
 * 카드(`.kro-card h3`)는 블록이라 로고의 `margin-right`(6px)만 걸리는데,
 * 타일은 flex라 거기에 `gap`이 더해져 14px이 됐다 — 같은 로고가 홈에서만
 * 멀어 보였다(운영자 지적 2026-08-31, 실측 14 대 6). flex에서는 gap이
 * 그 일을 하므로 로고의 여백을 끄고, gap을 카드와 같은 값으로 맞춘다.
 * 태그는 `margin-left:auto`로 밀려나므로 이 gap은 로고↔이름에만 걸리고,
 * 로고가 없는 타일에서는 이름↔태그의 최소 간격이 된다. */
/* **자리는 움직이지 않는다.** EN에서 `Samsung Electronics`가 두 줄로 접히면서
   같은 행 두 타일의 값 기준선이 어긋났다(실측: 469 vs 442). 이 세계의 첫 번째
   약속이 한국어에서만 지켜지고 있었다. 머리에 두 줄 높이를 고정해 이름이
   길어져도 값이 같은 자리에 선다. */
.tile-head { display: flex; align-items: baseline; gap: var(--sp-1h); }
.tile-head .inline-logo { margin-right: 0; }
/* **여기에 높이를 예약하지 마라.** 영어에서 이름이 두 줄로 접히며 값 기준선이
   3px 어긋나는 것을 고치려고 두 줄 높이를 예약했다가 두 번 물렸다 —
   `.tile-head`에 걸면 그건 `align-items: baseline` 컨테이너라 로고가 10px
   내려앉고, `.tile-name`에 걸면 상자만 커지고 글자는 위에 남아 로고가 글자보다
   아래로 보인다(운영자 지적 2026-09-04, 두 번).

   교환이 나빴다. 한국어의 **모든** 타일에서 로고가 어긋나는 것을, 영어 한
   타일의 값이 3px 밀리는 것과 바꾼 셈이다. 되돌린다. 영어 기준선은 별도로
   푼다 — 이름을 자르거나 `subgrid`로 행을 맞추는 쪽이고, 둘 다 여기 높이를
   더하는 방식이 아니다. */
.tile-name { font-size: var(--fs-md); font-weight: 650; letter-spacing: -.015em; }
.tile-tag { margin-left: auto; color: var(--ink-3); font: 600 var(--fs-xs)/1.2 var(--num); font-variant-numeric: tabular-nums; }

.tile-value {
  display: flex; align-items: baseline; gap: 5px;
  font: 680 var(--fs-display)/1.05 var(--num); font-variant-numeric: tabular-nums;
  /* 0이다. -.035em은 바닥(-0.03) 밑이었고, 그보다 큰 문제는 위상이다 —
     `tabular-nums`는 **숫자만** 폭을 맞추므로 쉼표가 든 값은 `1ch` 유령
     격자에서 밀린다. 자간이 그 밀림을 누적시킨다(1,737,169에서 0.49칸
     = 12.3px). 좁은 화면 override는 이미 -.03이었다. */
  letter-spacing: 0;
}
.tile-unit { color: var(--ink-3); font-size: var(--fs-md); font-weight: 600; letter-spacing: 0; }

.tile-delta { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
/* **기준 라벨은 폰에서 늘 제 줄에 선다.**
 *
 * 칸 폭을 정하고 나니(위 `.board > .tile`) 라벨이 접히기 시작했는데, **어떤
 * 카드는 접히고 어떤 카드는 안 접혔다** — 같은 줄에서 라벨의 y가 23px 갈렸다
 * (자: ALIGN, `/semi` 실측 2026-09-09). 카드는 밖에서 맞는데 그 안이 다시
 * 어긋나는 이 저장소의 단골 무늬다.
 *
 * 남는 답이 하나다. 자를 수는 없고("잘림 자체를 없앤다"), 들쭉날쭉 접을 수도
 * 없으니 **늘 접는다.** 그러면 모든 카드가 같은 모양이라 고정한 종목이
 * 무엇이든 어긋나지 않는다.
 *
 * 값: `/semi` 어긋남 23 → 0px(타일 높이 그대로 171 — 이미 접혀 있었다),
 * 홈 어긋남 0 그대로(타일 167 → 190px). 홈에서 23px을 더 쓰는 것이 이 규칙의
 * 값이고, 그 대가로 어떤 조합을 고정해도 줄이 맞는다.
 *
 * 넓은 화면에서는 걸지 않는다 — 칸이 넓어 애초에 한 줄에 들어가고, 접으면
 * 얻는 것 없이 세로만 먹는다. */
@media (max-width: 760px) {
  .tile-delta > .tile-basis { flex-basis: 100%; }
}
.tile-change { font: 680 var(--fs-lg)/1.2 var(--num); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.tile-change.up { color: var(--up); }
.tile-change.down { color: var(--down); }
.tile-change.flat { color: var(--ink-3); }
.tile-basis { color: var(--ink-2); font-size: var(--fs-sm); }
/* 퍼센트가 **무엇에 견줬는지**를 숫자로 적는 줄.
 *
 * 라벨만으로는 안 읽혔다 — 같은 종목이 홈에서 +5.82%, 반도체 타일에서
 * +0.93%로 서고 "차이가 뭐지?"라는 질문이 왔다(운영자 2026-09-06). 둘 다
 * 맞고 재는 구간이 다를 뿐인데, 기준이 된 숫자가 옆에 있으면 뺄셈이 눈에
 * 보인다.
 *
 * 값보다 작고 조용하다 — 이 줄이 커지면 무엇이 지금 값인지 흐려진다. */
.tile-anchor {
  display: flex; align-items: baseline; gap: var(--sp-1h); flex-wrap: wrap;
  margin-top: 2px; color: var(--faint);
  font: 650 var(--fs-xs)/1.4 var(--num); font-variant-numeric: tabular-nums;
}
.tile-anchor-value { color: var(--ink-2); }
.tile-anchor-move.up { color: var(--up); }
.tile-anchor-move.down { color: var(--down); }
/* 폰에서는 **절대 변화액을 접는다.** 원화 숫자는 길어서(`기준 1,657,366원
   +96,525원`) 360px 2열 타일에서 두 줄이 되고, 그만큼 보드 전체가 길어진다
   (실측 2026-09-06: 네 장 중 셋). 크기는 바로 위 퍼센트가 이미 말하고 있으므로
   여기서 지는 짐은 **기준이 된 숫자** 하나다. */
@media (max-width: 560px) {
  .tile-anchor { gap: 5px; }
  .tile-anchor-move { display: none; }
}

/* 스파크라인은 구조가 아니라 배경이다 — 없는 타일이 있어도 줄이 어긋나지
 * 않게 절대배치로 깔았다. */
.tile-spark {
  display: flex; align-items: flex-end; gap: var(--sp-2);
  height: 46px; padding-left: var(--sp-4); opacity: .9; pointer-events: none;
}
.tile-spark svg { flex: 1 1 auto; min-width: 0; height: 100%; display: block; }
/* 기간 라벨은 선의 색을 따라가지 않는다 — 색은 방향의 신호이고 이건 축 이름이다. */
.spark-period {
  flex: none; padding-bottom: 9px;
  color: var(--ink-3); font: 650 var(--fs-xs)/1 var(--num); font-variant-numeric: tabular-nums;
}
/* **감싸는 것을 잊어도 선은 선으로 보인다.**
   `sparkline()`이 내놓는 두 path에는 칠이 없다. 감싸는 상자가 없으면 SVG
   기본값이 그려 검은 덩어리가 된다(운영자 제보 2026-09-10). 색은
   `currentColor`라 둘레 글자색을 따르고, 방향 색은 아래 `.tile-spark`가 준다. */
.spark-svg path.fill { fill: currentColor; opacity: .12; }
.spark-svg path.line { fill: none; stroke: currentColor; stroke-width: 2.25; vector-effect: non-scaling-stroke; }
.tile-spark path.fill { fill: currentColor; opacity: .12; }
.tile-spark path.line { fill: none; stroke: currentColor; stroke-width: 2.25; vector-effect: non-scaling-stroke; }
/* 추이선은 자기가 그린 30일 방향으로 물든다. 옆의 등락률과 기간이 다르므로
 * 두 색이 갈릴 수 있는데, 그건 오류가 아니라 정보다 — "오늘은 빠졌지만 한 달은
 * 올랐다". 기간은 전문가 모드의 '배경 추이선' 줄에 적어 둔다. */
/* 카드 안의 추이선. 타일과 같은 부품이지만 카드 폭에 맞춰 낮고, 카드가
 * 통째로 코인 페이지로 가는 링크라 클릭을 가로채지 않는다. */
.card-spark {
  height: 40px; padding-left: 0; margin: var(--sp-2) 0 0; opacity: 1;
  border-bottom: 1px solid var(--line);
}
.card-spark .spark-period { padding-bottom: var(--sp-1h); }

/* 검색 관심도 표.
 *
 * 순위 칸에는 숫자와 변동 배지가 함께 선다. 변동은 어제 대비이고 하루에 한 번만
 * 바뀌므로 깜빡이지 않는다 — 초 단위로 움직이면 없는 움직임을 그리는 것이다. */
/* 순위는 크기를 견주는 값이 아니라 이름표다. 오른쪽 정렬은 자릿수가 다른
   1과 10을 어긋나 보이게 하고(1~9는 오른쪽 끝, 10만 왼쪽으로 삐져나온다),
   순위 변동 배지가 붙으면 그 줄만 더 밀린다. 가운데로 둔다. */
.accessible-table th.ksi-rank, .accessible-table td.ksi-rank { text-align: center; }
.ksi-rank { white-space: nowrap; }
.ksi-rank b { font: 700 var(--fs-sm)/1 var(--num); font-variant-numeric: tabular-nums; }
.ksi-move { margin-left: 4px; font: 650 var(--fs-xs)/1 var(--num); font-variant-numeric: tabular-nums; }
.ksi-move.up { color: var(--up); }
.ksi-move.down { color: var(--down); }
/* 자리를 옮긴 줄. 눈이 그 줄을 다시 찾도록 표시하되 **중립색**으로 한다.
 *
 * 처음엔 오른 줄을 초록, 내린 줄을 빨강으로 칠했다. 라이브에서 보니 카카오가
 * ×2.02(평소의 두 배, 이 표에서 가장 강한 신호)인데 줄 전체가 빨갰다 — 수준
 * 순위가 한 칸 내려갔다는 뜻이었지만, 이 사이트에서 빨강은 "내렸다"이다.
 * 같은 색 언어로 다른 두 주장을 하면 독자는 어느 쪽인지 알 수 없다.
 *
 * 방향은 ▲▼ 배지가 말한다 — 그건 자기가 설명하는 것에 붙어 있다. 줄은 "여기가
 * 움직였다"만 말하면 된다. */
.kridx-table tr.rank-up td, .kridx-table tr.rank-down td {
  background: color-mix(in srgb, var(--ink) 4%, transparent);
}
/* 실은 셀 높이를 통째로 쓴다 — 8-K 피드와 같은 모양이다. 항목마다 끊어 봤다가
   운영자 판정으로 되돌렸다(2026-09-08, "전이 더 나아"). 그쪽만 되돌리고 여기를
   두면 같은 표시가 화면마다 다르게 서므로 함께 되돌린다. */
.kridx-table tr.rank-up td:first-child, .kridx-table tr.rank-down td:first-child {
  box-shadow: inset 2px 0 0 var(--faint);
}
/* 기준 종목 표시. 100의 출처를 밝히지 않으면 100이 절댓값처럼 읽힌다. */
.ksi-anchor-tag {
  padding: 1px 5px; border: 1px solid var(--line); border-radius: var(--r-pill);
  color: var(--faint); font: 650 var(--fs-xs)/1.4 var(--num); font-variant-numeric: tabular-nums;
  vertical-align: middle;
}
/* 정렬 토글은 헤더가 아니라 본문 위에 선다 — margin-left:auto를 되돌린다. */
#ksi-sort { margin: 0 0 var(--sp-3); }
/* 쉬움 모드의 한 줄. 숫자가 무슨 뜻인지 그 자리에서 말한다 — 용어 사전으로
   보내면 대부분 안 간다.
 *
 * 좌우 여백은 **패널 안에서만** 준다. 이 한 줄은 두 곳에 선다 — /kr에서는
 * 패널 안(표가 패널 가장자리까지 가므로 이 줄에도 같은 여백이 필요하다),
 * 종목 페이지에서는 섹션 안(제목·부제와 왼쪽을 맞춰야 한다). 패널용 여백을
 * 공통으로 두었더니 종목 페이지에서 이 줄만 안쪽으로 밀려 있었다.
 * 아래 여백도 0이라 바로 밑 카드에 붙어 있었다 — `.sub`와 같은 12px을 준다.
 * (2026-08-27 운영자 지적) */
.ksi-help { margin: 0 0 var(--sp-3); color: var(--muted); font-size: var(--fs-sm); }
.panel .ksi-help { padding: var(--sp-3) var(--panel-inset) 0; margin: 0; }
/* 시장 전체 흐름. 개별 배수에서 빠진 정보라 표 위에 둔다 — 표를 읽기 전에
   "오늘은 다들 식은 날인가"를 먼저 알아야 각 줄이 제 뜻으로 읽힌다. */
.ksi-market { padding: var(--sp-2) var(--panel-inset) 0; margin: 0; font-size: var(--fs-xs); }
.ksi-market.up { color: var(--up); }
.ksi-market.down { color: var(--down); }
/* 쉬움 모드의 용어 다리. 크립토는 값이 어려운 게 아니라 **말**이 어렵다 —
   "미결제약정"을 처음 보는 사람에게 그건 글자다. 설명을 한 줄 더 쓰는 대신
   이미 있는 용어 사전으로 보낸다(35개 항목, 서버 렌더). */
.term-hints { margin: calc(-1 * var(--sp-1h)) 0 var(--sp-3); color: var(--faint); font-size: var(--fs-sm); }
/* 음수 위 여백은 **바로 위가 `.section-copy`일 때만** 뜻이 있다 — 그 줄에
   바짝 붙이려고 준 값이다. 다른 것이 앞에 오면(접기 버튼, 더 보기 버튼)
   그 위로 6px 올라타 글자가 겹친다(2026-08-30 운영자 제보: 접기 버튼과
   용어 줄이 겹침). 앞의 것이 무엇이냐에 따라 여백을 되돌린다. */
:not(.section-copy) + .term-hints { margin-top: var(--sp-2); }
.term-hints a { color: var(--muted); text-decoration: none; border-bottom: 1px dotted var(--line-strong); }
.term-hints a:hover { color: var(--accent); border-bottom-color: var(--accent); }

.tile-spark.up { color: var(--up); }
.tile-spark.down { color: var(--down); }
.tile-spark.flat { color: var(--ink-3); }

/* 값이 바뀔 때의 깜빡임.
 *
 * 5초마다 조용히 글자만 갈아 끼우면 화면이 멈춰 있는 것처럼 보인다. 방향에
 * 맞춰 짧게 물들이되, 등락률 쪽은 이미 색을 갖고 있으므로 색은 건드리지 않고
 * 번짐만 준다. 움직임을 줄여 달라고 한 사용자에게는 아무 일도 일어나지 않는다. */
/* 계기판 — 자리마다 0~9 띠를 세워 두고 바뀐 자리만 굴린다.
 *
 * 자리 폭을 1ch로 고정해 굴러가는 동안에도 숫자가 좌우로 밀리지 않는다(값이
 * 흔들리면 읽기가 더 어려워진다). 띠는 overflow로 잘라 한 자리만 보인다. */
.is-odo { display: inline-flex; align-items: flex-end; }
/* 진짜 값 — 눈에는 안 보이고 스크린리더·복사·검색에는 그대로 잡힌다. */
.odo-readable {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; border: 0; overflow: hidden; white-space: nowrap;
  clip: rect(0 0 0 0); clip-path: inset(50%);
}
.odo-reel { display: inline-flex; align-items: flex-end; }
.odo-d {
  display: inline-block; overflow: hidden;
  width: 1ch; height: 1em; line-height: 1; vertical-align: bottom;
}
.odo-strip {
  display: block;
  /* 자리마다 도는 시간이 다르다(왼쪽부터 잠긴다) — 실제 길이는 JS가 이 자리에
     인라인으로 적는다. 여기 값은 그것이 없을 때의 바닥이다. */
  transition: transform 420ms cubic-bezier(.14, .72, .16, 1);
}
/* `will-change`는 **도는 동안에만** 붙는다. 상시 애니메이션이 아니라 값이 바뀔
   때 한 번 도는 전이라, 멈춘 뒤에도 합성 레이어를 붙들고 있을 이유가 없다 —
   그래서 클래스가 떨어지면 힌트도 함께 떨어진다. */
.odo-d.is-spinning .odo-strip { will-change: transform; }
/* 빠른 가운데가 가장 흐리고 멈추는 순간 선명해진다. 속도를 흉내 내는 장식이
   아니라 **멈춤을 읽히게 하는 대비**다 — 초점이 돌아오는 것이 곧 확정이다. */
@keyframes odo-blur {
  0%, 100% { filter: blur(0); }
  40% { filter: blur(.5px); }
}
.odo-strip i { display: block; height: 1em; line-height: 1; font-style: normal; }
.odo-s { display: inline-block; line-height: 1; vertical-align: bottom; }

@media (prefers-reduced-motion: reduce) {
  .odo-strip { transition: none; animation: none; }
}

@keyframes console-tick-up {
  0% { color: var(--up); }
  100% { color: inherit; }
}
@keyframes console-tick-down {
  0% { color: var(--down); }
  100% { color: inherit; }
}
/* 깜빡임은 굴림과 함께 간다. 굴림은 위치를, 깜빡임은 색을 건드리므로 겹쳐도
 * 서로를 지우지 않고, 자릿수가 바뀌어 굴리지 못할 때는 이쪽만 남는다.
 * 테이프는 이미 옆으로 흐르고 있어 자리 굴림 없이 깜빡임만 쓴다. */
/* 참고가도 같은 움직임을 쓴다 (2026-09-04). 새 규칙을 만들지 않는다 —
 * 같은 뜻(값이 방금 바뀌었다)이면 화면에서 같은 말을 해야 한다. */
/* 1.2초는 굴림에 맞춘 길이다(6자리 회전이 1.5초). 0.7초로 두면 숫자가 아직
   도는 중에 색이 꺼져, 방금 온 값이 아니라 지나간 값처럼 읽힌다. */
.tile-value.tick-up, .tape-value.tick-up,
.mood-ref-pct.tick-up, .mood-lead-pct.tick-up { animation: console-tick-up 1.2s ease-out; }
.tile-value.tick-down, .tape-value.tick-down,
.mood-ref-pct.tick-down, .mood-lead-pct.tick-down { animation: console-tick-down 1.2s ease-out; }
/* 움직임은 줄이되 신호는 남긴다. 자리 굴림은 JS에서 아예 꺼지고, 여기서는
   후광 없이 색만 한 번 더 느리게 스친다 — "값이 방금 바뀌었다"까지 지우면
   그건 적은 모션이 아니라 없는 피드백이다(움직이지 않는 색은 모션이 아니다). */
@keyframes console-tick-up-quiet { 0% { color: var(--up); } 100% { color: inherit; } }
@keyframes console-tick-down-quiet { 0% { color: var(--down); } 100% { color: inherit; } }
@media (prefers-reduced-motion: reduce) {
  .tile-value.tick-up, .tape-value.tick-up,
  .mood-ref-pct.tick-up, .mood-lead-pct.tick-up { animation: console-tick-up-quiet 1.1s linear; }
  .tile-value.tick-down, .tape-value.tick-down,
  .mood-ref-pct.tick-down, .mood-lead-pct.tick-down { animation: console-tick-down-quiet 1.1s linear; }
}

/* 발판 — 추이선과 상세를 아래에 쌓는다. 타일 폭 끝까지 선이 닿게 좌우 여백을
 * 되돌린다. */
.tile-foot { margin: auto calc(var(--sp-4) * -1) calc(var(--sp-4) * -1); }
@media (max-width: 560px) { .tile-foot { margin: auto calc(var(--sp-3) * -1) calc(var(--sp-3) * -1); } }

/* ── 같은 줄의 타일은 같은 자리에서 같은 높이로 선다 ──────────────────────
 *
 * 위 `.tile-name` 주석이 적어 둔 그 길이다("subgrid로 행을 맞추는 쪽"). 높이를
 * 더하는 길은 두 번 물렸다 — 로고가 내려앉거나, 상자만 커지고 글자가 위에 남았다.
 *
 * subgrid는 높이를 더하지 않는다. 그 줄에서 가장 높은 머리가 트랙을 정하고
 * 나머지는 그 트랙 안에서 **제 기준선 그대로** 선다. 이름이 두 줄이 되어도
 * 옆 타일의 값이 안 밀린다(실측 `#smm-grid` 390px: 20.8px → 0).
 *
 * 자리를 이름으로 못 박는다. `.tile-anchor`는 어떤 타일에만 있어서, 자동
 * 배치에 맡기면 그 타일만 아래가 한 칸씩 밀린다 — 고치려던 것과 같은 어긋남이
 * 다시 생긴다. 없는 타일은 그 트랙을 비워 둔다.
 *
 * `.tile-foot`의 `margin-top: auto`는 flex에서 발판을 바닥으로 밀던 것이다.
 * 트랙이 정해진 뒤로는 발판이 이미 마지막 트랙이라 그 밀기가 필요 없고, 남겨
 * 두면 트랙 안에서 한 번 더 밀려 위가 뜬다.
 *
 * subgrid를 모르는 브라우저는 이 블록을 통째로 건너뛴다 — 지금처럼 flex로
 * 쌓인다. 못 맞추는 것이지 깨지는 것이 아니다. */
@supports (grid-template-rows: subgrid) {
  .board > .tile {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span 5;
    row-gap: var(--sp-2);
    /* **칸 폭을 정해야 한다** (운영자 제보 2026-09-09: 「직전 미국 종가 대비」가
       잘린다).

       격자의 기본 칸은 `auto`, 곧 `max-content`다. 그래서 `.tile-delta`가
       179px 카드 안에서 197px로 서고 18px이 밖으로 나가 `overflow: hidden`에
       잘렸다 — 글자 중간이 끊겨 보인다.

       `flex-wrap: wrap`은 이미 있었는데 접히지 않았다. 컨테이너가 안 좁혀지면
       접힐 이유가 없기 때문이다. `min-width: 0`을 타일·행·자식에 걸어도 아무
       일이 없다(실측) — 문제가 flex 최소 크기가 아니라 격자 칸이라서다.

       `1fr`만으로는 안 된다. 최소 크기가 여전히 `max-content`다 —
       `minmax(0, 1fr)`이라야 한다. 아래 `.kro-grid`가 같은 함정을 이미 적어
       두었고, 거기서는 고쳤는데 여기서는 안 했다.

       실측(390px): 잘린 글자 4 → 0 · delta 197 → 153px · 타일 148 → 171px.
       라벨이 두 줄로 접혀 23px을 더 쓰지만, 그게 자르지 않는 값이다. 한 줄의
       타일 넷이 전부 171로 함께 커지므로 정렬은 그대로다(subgrid가 하는 일). */
    grid-template-columns: minmax(0, 1fr);
  }
  /* 머리는 트랙 높이로 늘어나지 않는다. 옆 칸 이름이 두 줄이면 트랙이 두 줄 높이가
     되는데, 늘어난 머리 안에서 한 줄 이름은 첫 줄에 서고 로고(`align-self: center`)만
     가운데로 내려가 반 줄(10.4px) 어긋났다 — SMH 옆 NCLD(운영자 지적 2026-09-12,
     390 · 360px 실측). 값 이하 트랙은 그대로라 옆 타일의 값 기준선은 안 밀린다. */
  .board > .tile > .tile-head { grid-row: 1; align-self: start; }
  .board > .tile > .tile-value { grid-row: 2; }
  .board > .tile > .tile-delta { grid-row: 3; }
  .board > .tile > .tile-anchor { grid-row: 4; }
  .board > .tile > .tile-foot { grid-row: 5; margin-top: 0; }
  /* 유령 칸(편집 중 자리표시)과 안내 칸은 트랙을 나눠 쓸 속이 없다. */
  .board > .tile.is-ghost, .board > .my-board-empty { grid-row: auto / span 5; }
}

@media (max-width: 560px) {
  /* 2열을 유지하되 값 크기를 폭에 맡긴다. 원화 7자리(1,739,718 KRW)가 한 칸에
   * 들어가야 하는데, 22px 고정으로는 358px 화면에서 잘렸다. clamp로 화면이
   * 좁아지는 만큼만 줄어들고 넓으면 22px에서 멈춘다. */
  .tile { min-height: 124px; padding: var(--sp-3); }
  /* 폰에서 이 값이 페이지의 네 번째로 큰 글자였다(critique 2026-09-04):
     카운트다운 28 > 어제 S&P500 등락률 22/800 > 구역 제목 22 > 값 19.5/680.
     사용자가 물으러 온 것이 어제 남의 지수보다 작으면 안 된다. */
  /* 폰에서는 이름을 한 줄로 묶는다.
   *
   * 172px 칸에서 `Samsung Electronics`가 두 줄로 접히면 그 타일만 로고가 11.3px,
   * 값이 21px 내려간다(실측 390px/en). 데스크톱은 칸이 넓어 안 접히므로 여기서만
   * 건다 — 높이를 예약하는 방식은 두 번 물렸다(로고가 따라 내려온다).
   *
   * 자르는 대가는 종목코드가 갚는다. 이름 오른쪽에 `005930`이 늘 서 있고,
   * 타일 전체가 그 종목 페이지로 가는 링크다. */
  /* 한 줄로 자르면서 "자르는 대가는 종목코드가 갚는다"고 적어 뒀는데, 14줄
     아래(`440px`)에서 그 종목코드를 숨긴다. 폰 세 폭(412·390·360)이 전부 그
     아래라 **대가를 갚는 쪽이 화면에 없었다.** 실측 360: "S&P 500 퍼프 실현
     변동성 (20일)"이 115px 칸에서 62px(35%) 잘렸고, EN 390에서는 220px 중
     90px이 잘렸다.

     코드를 되살리는 것으로는 안 풀린다 — 이름 자체가 칸보다 길다. 한 줄을 더
     쓴다. 두 줄까지 허용하고 그 뒤에만 자른다. */
  .tile-name {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    overflow: hidden; min-width: 0;
  }
  /* 바닥이 24px이었는데 그건 **한국어로 잰 값**이다. EN에서 "1,735,130KRW"가
     360px 타일의 안쪽 상자를 6.11px 넘어섰고(390에서는 여유가 0.77px — 글자
     하나), 이 컴포넌트가 바로 DESIGN.md가 "이 세계의 서명"이라 부르는 자리다.
     자간도 함께 되돌린다: -.05em은 문서 램프의 바닥(-.03em)과 craft floor
     (-.04em) 둘 다를 넘고, 44px에서는 글자 사각형이 실제로 겹쳤다(문자 진행
     26.64px 대 글자 상자 26.66px). `tabular-nums`로 자리를 맞추려는 값에
     9.1% 압축을 거는 것은 그 목적과 정면으로 어긋난다. */
  .tile-value { font-size: clamp(21px, 6.6vw, 30px); letter-spacing: -.03em; }
  .tile-unit { font-size: var(--fs-sm); }
  .tile-change { font-size: var(--fs-md); }
  .tile-basis { font-size: var(--fs-xs); }
  .tile-delta { gap: var(--sp-1h); }
  .tile-name { font-size: var(--fs-sm); }
  .tile-spark { height: 34px; padding-left: var(--sp-3); gap: var(--sp-1h); }
  /* `.card-spark`는 위에서 이미 `padding-left: 0`을 선언해 뒀는데, 바로 윗줄
     `.tile-spark`가 같은 (0,1,0)이면서 **뒤에 서서** 그 0을 덮었다. 카드는
     타일과 달리 제 여백을 스스로 내므로 12px이 한 번 더 들어가면 '29일'만
     혼자 오른쪽에서 시작한다(실측 412·390·360px 모두 카드 25px / 라벨 37px).
     겹치는 두 규칙 중 뒤에 선 쪽에서 되돌린다. */
  .card-spark { padding-left: 0; }
  .spark-period { padding-bottom: var(--sp-1h); }
}
/* 아주 좁은 화면에서는 종목코드를 줄이는 대신 뺀다 — 12px 바닥을 지키려고
 * 읽히지 않는 크기로 밀어 넣지 않는다. 코드가 필요하면 타일을 누르면 된다. */
@media (max-width: 440px) { .tile-tag { display: none; } }

/* ======================================================================
 * 4b. S&P 500 히트맵 — 홈에서도 본다 (TradingView 외부 위젯, 화면에 들어오면 로드)
 * ================================================================== */
.console-section > header .segmented { margin-left: auto; }
.tv-panel { padding: 0; overflow: hidden; border: 0; border-radius: 0; box-shadow: none; }
/* overflow: hidden — 위젯 iframe은 로드 시점의 픽셀 높이를 고집하는데,
 * 폰에서 vh가 URL 바 개폐로 출렁이면 호스트만 줄어들어 iframe이 아래로
 * 흘러 캡션 글자를 덮었다(실기기 제보 2026-08-31 · 헤드리스에선 vh가
 * 안 출렁여 재현 불가). 넘침은 덮는 대신 잘린다. */
/* **바닥값 500px는 TradingView가 정한다.** 위젯은 자기 아래 크롬(로고 칩 +
 * 색 범례, 합 ~56px)을 고정 높이로 그리는데, 호스트가 짧으면 그 크롬이
 * iframe을 넘쳐 잘린다. 실측(412px 폭, mulmit.com):
 *
 *     호스트 434px  범례·로고 없음 — 타일이 바닥까지 닿는다
 *     호스트 470px  똑같이 잘림
 *     호스트 500px  범례·로고 온전
 *     호스트 567px  온전
 *
 * 운영자 제보(2026-09-01)의 "왜 이렇게 잘려서 나와?"가 이것이다 — 폰에서
 * 62svh가 430px대를 만들고 있었다. 62%는 그대로 두되 바닥을 올린다. */
.tv-panel .tradingview-host { height: min(560px, max(500px, 62vh)); overflow: hidden; }
.tv-panel .tradingview-widget-container,
.tv-panel .tradingview-widget-container__widget { height: 100%; }
.tv-panel .panel-footer { display: flex; gap: var(--sp-2); padding: 10px var(--sp-4); }
/* 캡션은 패널 안(padding 0)에 서므로 좌우 여백을 스스로 낸다 — 각주와 정렬. */
/* 들여쓰기는 푸터의 글자와 같은 선 — 푸터는 마진 16(monitor.css) +
 * 패딩 16(위 규칙)이라 합이 32(--sp-6)다. 16으로 두면 한 계단 왼쪽에 서서
 * 어긋나 보였다(운영자 제보 2026-08-31, 실측 173 vs 189px). */
.tv-panel .tv-caption { margin: 0; position: relative; }
/* --- 히트맵 전체화면 -----------------------------------------------------
 * 규격은 `tvchart.js`가 정한 것과 같다(종목·코인 페이지의 차트 단추). 홈은
 * 그 파일을 싣지 않으므로 규칙만 여기 다시 적는다 — 같은 기능이 페이지마다
 * 다른 물건으로 보이지 않게.
 *
 * **제 줄을 만들지 않는다.** 이미 있는 줄(1D·1W·1M·1Y 탭 줄)의 오른쪽 끝에
 * 앉는다. 제 줄을 만들면 네모 하나를 위해 폭 전체짜리 빈 줄이 선다.
 *
 * 줄 안에서는 박스를 버린다 — 글자 탭이 늘어선 줄에 테두리 두른 네모가 끼면
 * 그것만 다른 세계에서 온 것처럼 보인다. 손가락 크기는 테두리가 아니라
 * 패딩이 지킨다: 눌리는 면은 44px인데 보이는 것은 글자뿐이다. */
.console-section > header .tv-fs-inline {
  display: inline-flex; align-items: center; gap: 5px;
  /* 마우스 자리에서도 바닥값은 있다 — 자가 44x14를 잡았다(TAP, 1440px).
     옆 탭이 30px이라 24px은 줄 높이를 안 바꾸면서 문턱을 넘는다. */
  min-height: var(--tap-min); padding: 0 2px;
  border: 0; background: none; border-radius: 0; cursor: pointer;
  color: var(--ink-3); font: 700 var(--fs-xs)/1 var(--sans);
}
.console-section > header .tv-fs-inline:hover { color: var(--ink); }
/* 손가락 크기는 **옆 탭과 같은 breakpoint에서** 온다. 44px을 늘 걸었더니
   데스크톱 머리줄이 44 → 55px로 커졌다(실측 1440px) — 29px짜리 탭 옆에서 혼자
   큰 것은 `tvchart.js`가 "그것만 다른 세계에서 온 것처럼 보인다"로 되돌린
   모양이다. `.segmented button`이 560px에서 44로 커지므로 여기도 거기서 커진다. */
@media (max-width: 560px) {
  .console-section > header .tv-fs-inline { min-height: var(--tap-control); }
}
/* 탭과 단추를 한 상자에 담는다. 폰에서 `.segmented`는 `width: 100%`에
   `order: 3`이라(monitor.css) 그 줄에 남는 자리가 0이다 — 단추를 머리줄에 그냥
   붙이면 폭 전체짜리 줄이 하나 더 선다(실측 390px: 113 → 168px). 상자가 탭이
   갖던 자리·순서·아래 여백을 그대로 받고, 탭은 상자 안에서 줄어든다. */
/* --- 히트맵 머리줄 — **빈 줄을 만들지 않는다** -------------------------
 *
 * 네 판을 거쳤다(monitor.js `addHeatmapFullscreen` 주석에 같이 적었다).
 * 마지막 문제는 단추를 탭 아래로 내렸더니 **폭 전체짜리 줄에 네모 하나**만
 * 남은 것이었다 — 실측 390px: 탭 아래 8 + 단추 44 + 맵까지 28 = 80px이 거의
 * 비었다("공백이 너무 커", 운영자 2026-09-09).
 *
 * 그래서 제목 아래 있던 용어 줄을 그 줄로 내려 단추와 나란히 세운다. 줄 수는
 * 그대로 셋이고, 단추는 탭 아래 오른쪽에 있고, 빈 자리가 없다. 차트 상세가
 * 고지 줄과 단추를 한 행에 세운 것과 **같은 짜임**이다.
 *
 * **flex가 아니라 격자다.** 감기게 두면 어느 것이 어느 줄에 앉을지를 폭이
 * 정해서 화면 크기마다 달라진다. `.segmented`가 `order: 3`·`width: 100%`를
 * 들고 있어서 더 그렇다 — 격자에서는 그 값들이 자리를 못 바꾼다.
 *
 * 용어 줄은 쉬움 모드에서만 선다(`easy-only`). 전문가 모드에서는 그 칸이 비고
 * 단추만 남는데, 그쪽은 원래 더 촘촘한 화면이라 그대로 둔다. */
.console-section > header:has(.tv-fs-inline) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: var(--sp-3); row-gap: var(--sp-2);
}
.console-section > header:has(.tv-fs-inline) > :is(h1, h2) {
  grid-column: 1 / -1; grid-row: 1;
}
.console-section > header:has(.tv-fs-inline) > .segmented {
  grid-column: 1 / -1; grid-row: 2;
  width: auto; margin: 0; order: 0;
}
.console-section > header:has(.tv-fs-inline) > .term-hints {
  grid-column: 1; grid-row: 3; margin: 0;
}
/* 격자 칸 안에서 오른쪽 끝으로 붙이는 것은 `justify-self`다 — `margin-left: auto`가
   아니다. */
.console-section > header:has(.tv-fs-inline) > .tv-fs-inline {
  grid-column: 2; grid-row: 3; justify-self: end; margin-left: 0;
}
/* 아이콘은 글자를 따라 커진다(1em 기준) — 나머지 아이콘 체계와 같은 규칙. */
.tv-fs-glyph { width: 1.15em; height: 1.15em; flex: 0 0 auto; }
/* 전체화면 — **섹션째** 올린다.
 *
 * 판만 올리면 나가는 단추(머리줄에 있다)가 그 밖에 남아 손이 안 닿는다.
 * 섹션이면 머리줄이 같이 가서 나가는 단추도 기간 탭도 거기서 그대로 쓴다.
 * 판 안의 출처 표기도 판과 함께 남는다 — 지워서는 안 되는 줄이다.
 *
 * 맵의 높이 규칙(`max(500px, 62svh)`)은 여기서 푼다. 62%를 쓸 이유가 없는
 * 자리이고, 애초에 그 62%가 이 화면을 만든 이유다. */
.console-section:fullscreen,
.console-section.tv-fs-fallback {
  display: flex; flex-direction: column; gap: 0;
  margin: 0; padding: 0; background: var(--bg); border-top: 0;
}
/* 맵은 폭을 다 쓴다 — 여백은 머리줄만 갖는다. */
/* 클래스를 두 번 쓴 것은 오타가 아니다. `.console-section[data-rank="lead"] >
   header { padding-top: 0 }`(2656행)이 같은 특이도로 **뒤에** 있어서 위쪽 여백을
   0으로 덮는다 — 히트맵 섹션이 `data-rank="lead"`다. 아래 제목 규칙도 같은
   이유로 클래스를 두 번 쓴다. */
.console-section.console-section:fullscreen > header,
.console-section.console-section.tv-fs-fallback > header {
  margin: 0;
  /* **위쪽은 더 준다.** 전체화면에서는 상태바가 사라져 내용이 화면 맨 위에서
     시작한다 — 12px은 그 자리에서 너무 붙고(운영자 2026-09-09 "너무
     올라가있어"), 노치·카메라가 있는 기기도 있다. 안전영역이 더 크면 그쪽을
     쓴다(`env`는 폴백을 함께 적어야 값이 없을 때 선언이 죽지 않는다). */
  padding: max(var(--sp-5), env(safe-area-inset-top, 0px)) var(--sp-3) var(--sp-3);
  flex-wrap: nowrap; align-items: center;
}
/* **머리줄은 한 줄이다.** 폰 기본값은 탭이 `width: 100%`라 두 줄이 되고, 그
   두 줄이 전체화면에서 맵이 못 쓰는 높이가 된다(실측 390px: 맵이 74%에서
   멈췄다). 여기서는 제목이 줄고 줄어들 자리를 내준다 — 지금 무엇을 보고
   있는지는 위젯 자기 머리 막대도 말한다. */
/* 클래스를 두 번 쓴 것은 오타가 아니다. `world.css:568`이 같은 자리를 같은
   특이도로 잡고 있고 **나중에 실린다**(monitor -> tokens -> console -> world).
   이 한 줄만 그쪽을 넘어야 해서 특이도를 한 단 올린다. */
.console-section.console-section:fullscreen > header :is(h1, h2),
.console-section.console-section.tv-fs-fallback > header :is(h1, h2) {
  font-size: var(--fs-lg); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* **탭은 안 줄어든다 — 줄어드는 쪽은 제목이다.**
   전체화면 머리줄이 한 행이라 셋이 자리를 다툰다. 탭이 눌리면 "1W"가 두 줄로
   접히고 "1Y"가 잘린다(실측 390px 사진) — 기간은 네 글자 다 보여야 한다.
   격자에서 `auto` 칸은 내용만큼만 서므로 제목 칸(`minmax(0, 1fr)`)이 줄어든다. */
/* 전체화면 — **나가는 단추는 제목과 같은 줄, 탭은 그 아래.**
 *
 * 처음에는 셋을 한 행에 세웠다(줄을 아끼려고). 그러면 폰 폭에서 세 덩이가 딱
 * 붙어 설 자리밖에 없어 「닫기」가 「1Y」 바로 옆에 앉는다 — 운영자 2026-09-09:
 * "닫기버튼이 1d 1w 1m 옆에있어서 디자인적으로 align안맞는 느낌".
 *
 * 열을 바꿔 가운데를 넓히는 길은 재 보고 접었다: 390px에서 제목 150 + 탭 106 +
 * 닫기 64 + 여백 24 = 344로, 366 안에 남는 자리가 22px뿐이다. 양쪽 11px은
 * 눈에 안 띈다.
 *
 * 그래서 **행으로 나눈다.** 창을 닫는 단추가 제목 줄 오른쪽 끝에 서는 것은
 * 대화상자의 기본 짜임이고, 폭이 얼마든 탭과 안 붙는다. 줄이 하나 늘지만 직전
 * 판에서 용어 줄을 내려 머리줄을 줄여 둔 여유가 그 값을 낸다. */
.console-section:fullscreen > header:has(.tv-fs-inline),
.console-section.tv-fs-fallback > header:has(.tv-fs-inline) {
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center; row-gap: var(--sp-2);
}
.console-section:fullscreen > header:has(.tv-fs-inline) > :is(h1, h2),
.console-section.tv-fs-fallback > header:has(.tv-fs-inline) > :is(h1, h2) {
  grid-column: 1; grid-row: 1;
}
.console-section:fullscreen > header:has(.tv-fs-inline) > .tv-fs-inline,
.console-section.tv-fs-fallback > header:has(.tv-fs-inline) > .tv-fs-inline {
  grid-column: 2; grid-row: 1;
}
/* 탭은 아래 줄을 통째로 쓴다 — 제자리 머리줄과 같은 규칙이라 두 상태가 같은
   자리를 갖는다(제자리는 2행, 여기서도 2행). */
.console-section:fullscreen > header:has(.tv-fs-inline) > .segmented,
.console-section.tv-fs-fallback > header:has(.tv-fs-inline) > .segmented {
  grid-column: 1 / -1; grid-row: 2; width: auto;
}
.console-section:fullscreen > header .segmented button,
.console-section.tv-fs-fallback > header .segmented button { white-space: nowrap; }
/* 용어 줄은 접는다 — 전체화면은 맵을 보러 들어온 자리다. */
.console-section:fullscreen > header .term-hints,
.console-section.tv-fs-fallback > header .term-hints { display: none; }
.console-section:fullscreen .tv-panel,
.console-section.tv-fs-fallback .tv-panel {
  flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column;
}
.console-section:fullscreen .tradingview-host,
.console-section.tv-fs-fallback .tradingview-host {
  flex: 1 1 auto; height: auto; min-height: 0; border-radius: 0;
}
/* 네이티브 전체화면이 안 되는 곳(iOS 사파리는 임의 요소를 지원하지 않는다)의
   대체. 화면을 덮는다 — 주소창은 남지만 맵이 폭과 높이를 다 쓴다. */
.console-section.tv-fs-fallback {
  position: fixed; inset: 0; z-index: 9999;
  height: 100dvh; max-height: none;
}
@media (max-width: 760px) {
  /* 셸(마스트헤드·탭·검색)의 좁은 화면 규칙도 monitor.css로 갔다 — 2026-09-01.
   * 여기 남은 것은 콘솔 고유(테이프·모드 스위치·shell 여백)뿐이다. */
  /* svh — URL 바가 접혀도 안 변하는 작은 뷰포트 높이. vh는 폴백. */
  .tv-panel .tradingview-host { height: max(500px, 62vh); height: max(500px, 62svh); }
  .console-section > header { flex-wrap: wrap; }
  .console-section > header .segmented { margin-left: 0; }
}

/* ======================================================================
 * 4c. 24시간 참고가 카드 = 보드 타일
 *
 * renderKrOvernight는 그대로 둔다 — 카드가 이미 이름·큰 값·등락·근거표라는
 * 같은 뼈대를 갖고 있어서, 껍데기만 타일 시스템에 맞추면 된다. /kr에 별도
 * 보드를 두지 않는 이유이기도 하다(같은 값을 두 번 그리게 된다).
 * ================================================================== */
.kro-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
@media (max-width: 1080px) { .kro-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .kro-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); } }

.kro-card {
  display: flex; flex-direction: column; gap: var(--sp-1h);
  padding: var(--sp-4); border-radius: var(--r-md); box-shadow: none;
}
/* 위쪽 색 띠를 되돌리던 규칙은 `monitor.css`에서 띠 자체를 지우면서 없앴다 —
 * 여기서 `border-top`을 못 박으면 호버의 파란 테두리가 위쪽만 안 칠해진다. */
.kro-card h3 { font-size: var(--fs-md); font-weight: 650; letter-spacing: -.015em; }
.kro-card h3 a { text-decoration: none; }
.kro-card h3 a:hover { color: var(--accent); text-decoration: underline; }
/* 티커는 글이 아니라 식별자다. 여기는 진짜 등폭이 맞다. */
/* `font:` 단축이 `font-variant-numeric`을 지운다(The Shorthand Resets Tabular
   Rule). `monitor.css`가 같은 선택자에 켜 두지만 먼저 로드돼 진다. 등폭
   스택이라 눈에 띄는 피해는 없지만, 이 저장소에서 이 규칙을 지키지 않은
   마지막 한 곳이었다. */
.kro-sym { font: 600 var(--fs-xs)/1.2 var(--mono); font-variant-numeric: tabular-nums; letter-spacing: .02em; }
.kro-price {
  margin: var(--sp-2) 0 0;
  font: 680 var(--fs-display)/1.05 var(--num); font-variant-numeric: tabular-nums;
  /* 0이다. -.035em은 바닥(-0.03) 밑이었고, 그보다 큰 문제는 위상이다 —
     `tabular-nums`는 **숫자만** 폭을 맞추므로 쉼표가 든 값은 `1ch` 유령
     격자에서 밀린다. 자간이 그 밀림을 누적시킨다(1,737,169에서 0.49칸
     = 12.3px). 좁은 화면 override는 이미 -.03이었다. */
  letter-spacing: 0;
}
/* 숫자와 문장이 한 줄에 섞여 있다 — 모노로 두면 한글이 대체 글꼴로 빠져 줄이
 * 들쭉날쭉해진다. 본문 글꼴에 자리폭 숫자만 켠다. */
.kro-vs { font: 650 var(--fs-sm)/1.45 var(--sans); font-variant-numeric: tabular-nums; }
.kro-vs-ref { margin-top: 2px; font: 600 var(--fs-xs)/1.45 var(--sans); font-variant-numeric: tabular-nums; }
.kro-meta { margin-top: auto; padding-top: var(--sp-2); gap: 3px; }
.kro-meta dt { color: var(--ink-3); font: 500 var(--fs-xs)/1.5 var(--sans); }
.kro-meta dd { color: var(--ink-2); font: 600 var(--fs-xs)/1.5 var(--num); font-variant-numeric: tabular-nums; }
.kro-badges {
  align-self: start; align-items: flex-start; align-content: flex-start;
  margin-top: var(--sp-2);
}
.kro-badges .status-badge { flex: 0 0 auto; width: max-content; }

/* 공식 종가가 직전 세션보다 늦으면 두 줄의 주·보조가 뒤바뀐다.
 *
 * monitor.js의 overnightReference()가 그렇게 판정하면 카드에 .kro-ref-primary가
 * 붙는다. 그때는 "8/21 15:30 이후"가 장 마감 이후 움직임을 말하는 값이고,
 * "8/20 종가 대비"는 이미 끝난 정규장 하루를 포함한 값이라 뒤로 간다.
 * 마크업 순서는 그대로 두고 flex order로만 바꾼다. */
.kro-card.kro-ref-primary .kro-vs-ref {
  order: 1; margin-top: 0;
  font: 650 var(--fs-sm)/1.45 var(--sans); font-variant-numeric: tabular-nums;
}
.kro-card.kro-ref-primary .kro-vs {
  order: 2; margin-top: 2px;
  font: 600 var(--fs-xs)/1.45 var(--sans);
}
.kro-card.kro-ref-primary .kro-meta { order: 3; }
.kro-card.kro-ref-primary .kro-badges { order: 4; }

.kro-official-strip { margin-top: var(--sp-4); font-size: var(--fs-xs); }
.kro-official-strip .kro-strip-label { font-size: var(--fs-xs); }
.kro-strip-item small, .kro-strip-item em { font-size: var(--fs-xs); }
.kro-strip-item strong { font-size: var(--fs-sm); }
.kro-footer { margin-top: var(--sp-3); }
.kro-footer p { width: 100%; max-width: none; }
/* 이 둘은 방법·한계를 말하는 **문장**이라 tokens.css의 산문 단계를 따른다.
   여기서 --fs-xs로 못박으면 특정도(0,2,0)로 그 단계를 이겨 버린다. */
.kro-footer .kro-method, .kro-footer .kro-disclaimer { font-size: var(--fs-sm); color: var(--ink-3); }

/* 계산 방법은 전문가 모드에서만 펼친다.
 *
 * /crypto의 시장 국면은 게이지보다 방법 설명이 면적을 더 쓰고 있었다. 방법은
 * 값을 검증하려는 사람에게 필요한 글이고, 한계를 알리는 고지(.kro-disclaimer)는
 * 누구에게나 필요한 글이다 — 접는 것은 앞쪽뿐이다.
 *
 * **섹션을 하나하나 적는다.** `.kro-method`는 계산 방법 말고 출처 표기에도
 * 쓰인다(바이오의 ClinicalTrials.gov·PubMed·Federal Register attribution).
 * 그건 약관상 표시 의무가 걸린 문구라 어떤 모드에서도 숨기면 안 된다. 여기
 * 나열된 것은 전부 Mulmit이 스스로 계산한 값의 방법 설명뿐이다. */
/* 주말 신호 카드·고지도 같은 바닥 위로. */
/* 왼쪽 들여쓰기를 되돌린다. monitor.css에 `margin: 11px 0 0 42px`가 박혀
 * 있어 이 문단만 42px 오른쪽에서 시작했고, 바로 아래 서랍 제목과 세로선이
 * 어긋났다(운영자 2026-09-03). 폰에서는 이미 0으로 되돌리고 있었는데
 * (monitor.css:501) 데스크톱에는 그 규칙이 없었다. */
/* 한 줄에 한국어 112자(1287px = 180ch)가 앉아 있었다. 눈이 다음 줄 첫 글자를
   못 찾는 길이다 — DESIGN.md가 Caption을 "읽으라고 쓴 줄"이라 부르는데, 읽으라고
   쓴 줄이 가장 긴 줄이었다. 이 저장소에 이미 답이 있다(`.weekend-answer` 68ch,
   `.pulse-say` 88ch) — 그 상한이 여기까지 안 왔을 뿐이다. */
.weekend-disclaimer {
  margin-left: 0; max-width: none;
  font-size: var(--fs-xs); color: var(--ink-2); line-height: 1.6;
}

.ev-model-row {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-1h) var(--sp-3);
  margin-bottom: var(--sp-3);
}
.ev-model-row #ev-model,
.ev-model-row .term-hints { margin: 0; }

@media (max-width: 560px) {
  .kro-card { padding: var(--sp-3); }
  /* .crypto-card .kro-price가 monitor.css에서 24px로 못박혀 있어 선택자 무게를
   * 맞춰 준다 — 안 그러면 $77,323.00이 388px 화면에서 잘린다(실측). */
  .kro-price,
  .crypto-card .kro-price { font-size: clamp(16px, 5vw, 22px); letter-spacing: -.03em; }
  .kro-card h3 { font-size: var(--fs-sm); }
  .kro-vs { font-size: var(--fs-xs); }
}

/* ======================================================================
 * 5. 고지 — 8px 회색 네 줄 대신 접히는 한 줄
 * ================================================================== */
.disclose {
  margin-top: var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--panel);
}
/* DESIGN.md가 정한 자리다 — 해석·방법 문장은 라벨보다 한 단 위(13px)에 둔다.
   "읽으라고 쓴 줄이 훑는 줄과 같은 크기면 안 읽힌다." 이 화면에서 가장 읽혀야
   할 문단이 정확히 그 크기에 있었다. */
.disclose > summary {
  padding: 9px var(--sp-3); cursor: pointer; list-style: none;
  color: var(--ink-2); font-size: var(--fs-sm); font-weight: 600;
}
.disclose > summary::-webkit-details-marker { display: none; }
/* 삼각형은 유니코드가 아니라 마스크로 그린다(tokens.css의 `--ico-caret`).
   글꼴에 따라 모양·크기·기준선이 달라지던 것을 없앤다. */
.disclose > summary::before {
  content: ""; display: inline-block; width: 1em; height: 1em;
  margin-right: 5px; vertical-align: -.125em;
  background-color: var(--ink-3);
  -webkit-mask: var(--ico-caret) center / contain no-repeat;
  mask: var(--ico-caret) center / contain no-repeat;
  transition: transform .15s ease;
}
.disclose[open] > summary::before { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) {
  .disclose > summary::before { transition: none; }
}
.disclose > summary:hover { color: var(--ink); }
.disclose .disclose-body {
  padding: 0 var(--sp-3) var(--sp-3);
  color: var(--ink-2); font-size: var(--fs-xs); line-height: 1.7;
}
/* 섹션 설명은 뺀다. 이 규칙은 `.disclose` 안의 산문 간격을 잡으려는 것인데,
   후손 셀렉터라 접힘 안에 들어앉은 `.dashboard-section`의 `.section-copy`까지
   붙잡았다. 게다가 (0,2,1)로 `.dashboard-section > .section-copy`(0,2,0)를
   특정도에서 이겨서, 데스크톱에서 부제의 42px 들여쓰기가 통째로 사라졌다 —
   제목은 번호 칩만큼 밀려 있는데 부제만 왼쪽 끝에 붙어 −42px이 됐다
   (2026-08-30 실측, /us 1280px). */
/* 접힌 글 상자도 같은 상한을 받는다 — 펼치면 그 안이 본문이다. */
/* 접힌 판을 펼치면 요약 바로 아래에 **48px 빈자리**가 남았다(실측 /us·/crypto·
   /kr 공통). `.console-section`의 위 여백은 페이지 흐름에서 구역을 떼어 놓으라고
   준 것인데, 접힌 상자 안에서는 뗄 앞이 없다 — 요약이 곧 그 구역의 제목이다.
   첫 아이만 여백을 거둔다. */
.disclose .disclose-body > :first-child { margin-top: 0; }
.disclose .disclose-body p { max-width: var(--measure); }
.disclose .disclose-body p:not(.section-copy) { margin: 0 0 var(--sp-1h); }
.disclose .disclose-body p:last-child { margin-bottom: 0; }

/* 글자 표는 왼쪽에서 읽는다.
 * `.accessible-table`의 기본은 전 열 우측 정렬이라 의원 이름과 종목명이
 * 오른쪽 끝에 매달려 있었다. 숫자 열(.num)만 우측에 두고 나머지는 되돌린다.
 * 값이 대부분 숫자인 표(상관행렬·섹터)는 건드리지 않으려고 섹션으로 좁혔다. */
#us-ptr .accessible-table th:not(.num), #us-ptr .accessible-table td:not(.num),
#us-events .accessible-table th:not(.num), #us-events .accessible-table td:not(.num),
#econ-calendar .accessible-table th:not(.num), #econ-calendar .accessible-table td:not(.num),
#kr-events .accessible-table th:not(.num), #kr-events .accessible-table td:not(.num),
#kr-pension .accessible-table th:not(.num), #kr-pension .accessible-table td:not(.num),
#kr-holdings .accessible-table th:not(.num), #kr-holdings .accessible-table td:not(.num),
#kr-leaders .accessible-table th:not(.num), #kr-leaders .accessible-table td:not(.num) {
  text-align: left;
}

/* 표는 내용 폭까지만 넓힌다.
 * `width:100%`면 남는 폭이 모든 열에 고루 퍼진다. 코스피 지수군은 내용이
 * 566px인데 1286px로 늘어나 있었다 — 값 하나가 제 머리글에서 200px 떨어져
 * 앉아, 눈이 한 행을 끝까지 따라가지 못했다(실측 2026-08-23).
 * 남는 폭을 한 열에 몰아주는 방법도 써 봤지만 더 나빴다. 긴 글 열이 부풀면
 * 그 뒤의 열(원문 링크·지역·유형)이 본문에서 700px 밀려난다. 남는 폭은
 * 표 안이 아니라 표 밖에 둔다. */
.accessible-table { width: auto; max-width: 100%; }

/* 예외: 보드 카드는 표가 곧 카드 내용이다. 카드 폭은 격자가 정해 주므로 그
 * 안에서는 채우는 쪽이 맞다 — 내용 폭으로 두면 카드마다 오른쪽 3분의 1이
 * 테두리 안에서 빈 채로 남는다. */
.cboard-card .accessible-table { width: 100%; }

/* 게이지 패널(스트레스·심리·공포탐욕)과 뉴스 목록의 안쪽 여백.
 *
 * 이 둘만 패널 테두리에서 1~3px 떨어져 있었다 — 나머지 화면이 17px로 정렬된
 * 뒤라 이 패널만 왼쪽으로 쏠려 보였다. 표에 준 여백(바깥쪽 셀 padding)은
 * 여기서 이중이 되므로 되돌린다.
 *
 * 게이지 막대와 차트도 함께 들여쓴다. 글은 17px인데 막대만 0px이면 그건
 * "full-bleed 의도"가 아니라 어긋난 것으로 읽힌다. */
.stress-panel { overflow: hidden; padding: 22px 24px; border-radius: 16px; }
.stress-panel > div:not(.state-block) { padding: 0 var(--panel-inset) var(--sp-3); }
.stress-panel .accessible-table th:first-child,
.stress-panel .accessible-table td:first-child { padding-left: 0; }
.stress-panel .accessible-table th:last-child,
.stress-panel .accessible-table td:last-child { padding-right: 0; }
@media (max-width: 620px) { .stress-panel { padding: 18px; } }
.panel > .crypto-news { padding: 0 var(--panel-inset); }
/* 영상 격자도 같은 여백을 받아야 한다. 이 줄이 없어서 카드가 패널 테두리에
 * 그대로 붙어 있었다(실측: 좌우 여백 1px — 테두리 두께가 전부였다).
 * 목록과 달리 격자는 위아래로도 카드가 닿으므로 네 방향 모두 준다. */
.panel > .news-videos { padding: var(--panel-inset); }
.page-landing #nvid-footer { display: none !important; }
.nvid-source { margin-left: auto; color: var(--accent); text-decoration: none; }
.nvid-source::before { content: "출처 · "; color: var(--ink-3); }
html[data-lang="en"] .nvid-source::before { content: "Source · "; }
@media (max-width: 560px) { .nvid-source { margin-left: 0; } }
/* 출처·방법 표기는 패널 바닥에 그냥 놓여 있어 테두리에 닿았다(실측 /bio 4곳).
 * 약관상 표시 의무가 있는 줄이라 더더욱 제대로 앉아야 한다. */
.panel > .kro-method, .panel > .kro-disclaimer,
.panel > div > .kro-method, .panel > div > .kro-disclaimer {
  padding-left: var(--panel-inset); padding-right: var(--panel-inset);
}
/* 푸터 안에서 **간격을 말하는 곳은 `gap` 하나**다.
 *
 * `.panel-footer`는 `flex-wrap: wrap`이라 줄이 나뉘고, 남는 세로 자리가 줄
 * 사이로 퍼진다. 거기에 `<p>`의 브라우저 기본 여백(1em ≈ 13px)까지 얹히면
 * 바닥이 눈에 띄게 벌어진다 — 실측 `/crypto` 뉴스 푸터 **150px**, 같은 화면의
 * 다른 푸터는 43·62·101px(운영자 제보 2026-09-08 "맨 아래 공백이 너무 크다").
 *
 * 어떤 푸터는 이미 0이었다. 접힘 상자(`.disclose`) 안에 들면 그쪽 규칙이
 * 걷어 주기 때문인데, 그건 우연이지 규칙이 아니다 — 같은 부품이 어디에 놓이냐로
 * 여백이 갈리면 다음 자리에서 또 벌어진다. 푸터 쪽에서 한 번에 정한다. */
.panel-footer > p { margin: 0; }

/* 테두리 안쪽 여백.
 * `.panel`은 padding이 0이고 표의 셀 padding 10px에만 기대고 있었다. 그래서
 * 패널 왼쪽 629px에 "대표 지수"가 630px — 글자가 테두리에 닿았다(실측
 * 2026-08-23). 표 자체는 행 구분선을 끝까지 긋는 편이 나으니 full-bleed로
 * 두고, 바깥쪽 셀의 padding으로 같은 들여쓰기를 만든다.
 * 카드 안의 작은 표(.cboard-card)는 카드가 이미 안쪽 여백을 갖고 있어 뺀다. */
.panel .accessible-table th:first-child, .panel .accessible-table td:first-child { padding-left: var(--panel-inset); }
.panel .accessible-table th:last-child, .panel .accessible-table td:last-child { padding-right: var(--panel-inset); }
/* 직계 자식만 잡으면 한 겹 더 들어간 푸터를 놓친다(실측: crypto-volatility의
 * `.panel > div > footer`). 자손 선택으로 바꾼다. */
/* 아래 여백도 함께 준다. 기본 규칙이 `padding: 10px 0 0`이라 바닥이 0이었고,
 * 출처·기준 문구가 패널 테두리 위에 그대로 앉아 있었다 — 실측으로 마지막
 * 글줄 아래가 3~8px(글자에 따라 다름)이었다. 12px을 주면 어느 섹션이든
 * 15px로 고르게 선다. 좌우만 손보고 아래를 빠뜨렸던 자리다. */
.panel .panel-footer { padding-left: var(--panel-inset); padding-right: var(--panel-inset); padding-bottom: var(--sp-3); }
#kridx-body .kridx-group { padding-left: var(--panel-inset); }

/* 지수군은 표 둘이 나란히 선다. 세로로 쌓으면 오른쪽 절반이 빈 채 길어진다.
 * auto-fit이라 묶음이 하나뿐이거나 화면이 좁으면 저절로 한 줄이 된다. */
/* 최소 트랙을 `min(520px, 100%)`로 감싼다. 그냥 520px이면 그보다 좁은 화면
 * (폰 366~390px)에서 트랙이 컨테이너를 뚫고 나가 표의 스크롤 컨테이너 자체가
 * 화면 밖까지 이어진다 — 안쪽 가로 스크롤을 끝까지 당겨도 마지막 열들이
 * 영영 화면에 들어오지 못했다(안드로이드 실측 2026-08-26). */
#kridx-body { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(520px, 100%), 1fr)); gap: 0 var(--sp-6); align-items: start; }
/* 기준일 — 표 바로 위. 값이 언제 것인지는 값 옆에 있어야 읽힌다. */
/* 기준일 줄도 판 안쪽 레일에 선다.
 *
 * 아래 `.kridx-group`은 `--panel-inset`(16px)을 받는데 이 줄만 0이었다. 그래서
 * 글자가 판 경계에 그대로 붙고, 바로 아래 "대표 지수"는 16px 안쪽에서 시작해
 * 왼쪽 모서리가 둘이 됐다(운영자 2026-09-06: "카드 경계에 너무 딱붙어있어").
 * 실측: 기준 줄 텍스트 left 629.5 · 그룹 제목 645.5.
 *
 * 왼쪽 모서리를 하나로 모으는 규칙에서 이 줄만 빠져 있었다. */
/* 위쪽도 같은 이야기다(운영자 2026-09-06: "위에 너무 딱붙어있고"). 왼쪽 모서리는
   위에서 고쳤는데 **위 여백이 0이라** 글자가 판 천장에 붙어 있었다. 판 안의 다른
   머리줄(`.panel .ksi-help`)이 쓰는 12px과 같은 값을 준다 — 같은 자리의 같은
   종류 간격이다. 아래 10px도 눈금 밖이라 12로 맞춘다. */
/* 순위 표도 같은 자리에 같은 줄을 세운다(2026-09-08). 같은 물음("이 숫자
   언제 것인가")에 답하므로 모양이 갈리면 안 된다. `grid-column`은 격자가 아닌
   판에서는 그냥 무시된다. */
.kridx-basis, .krl-basis {
  grid-column: 1 / -1; margin: 0 0 var(--sp-3);
  padding: var(--sp-3) var(--panel-inset) 0;
  color: var(--muted); font-size: var(--fs-xs);
}
/* 표 위의 "지금" 한 줄.
   확정 종가 표(T+1) 위에서 살아 있는 참고가를 말하는 자리다. 표보다 **먼저**
   읽혀야 하므로 제목 바로 아래 서고, 값은 본문보다 한 단 크게 둔다 — 그러나
   보드 타일(38px)만큼 크지는 않다. 여기는 표의 머리말이지 이 화면의 대표
   숫자가 아니다. 기준 문구는 같은 줄 끝에 회색으로 붙어, 좁은 폭에서는
   자연스럽게 아랫줄로 접힌다. */
.kridx-now {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: var(--sp-1) var(--sp-2); margin: 0 0 var(--sp-3);
}
.kridx-now small { color: var(--muted); font-size: var(--fs-xs); }
.kridx-now b {
  font-size: var(--fs-lg); font-weight: 700;
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
}
.kridx-now em {
  font-style: normal; font-weight: 650; font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
}
/* 방향색은 `--up`/`--down`으로 부른다. 바로 아래 표가 `--green`/`--red`(같은
   값)를 쓰지만, 등락색을 로케일 기본값으로 바꾸는 날 갈리는 것은 방향 토큰
   쪽이다 — 새로 쓰는 줄은 그쪽에 건다. */
.kridx-now em.up { color: var(--up); }
.kridx-now em.down { color: var(--down); }
/* 기준 문구에 왼쪽 여백을 따로 주지 않는다 — 규칙이 빠진 것이 아니라 뺀
   것이다. 폰 폭에서는 이 줄이 항상 접혀 기준 문구가 **두 번째 줄의 첫
   글자**가 되고(실측 412·390·360·320 전부), 그때 여백은 12px 레일을 4px
   어긋나게 만든다. 한 줄 안의 간격은 flex gap이 이미 8px 준다. */
#kridx-body .kridx-block { min-width: 0; }
#kridx-body .kridx-block .kridx-group { margin-top: var(--sp-4); }

/* 지표 자세히 보기 — 기존 대시보드 섹션들을 통째로 담는 큰 서랍.
 * 쉬움에서는 닫혀 있고 전문가에서는 열린다(data-mode-open). 닫혀 있어도 본문은
 * DOM에 있어 검색엔진은 그대로 읽는다. */
.disclose-deep > summary { padding: 13px var(--sp-4); font-size: var(--fs-sm); }
.disclose-deep .deep-body { padding: 0 var(--sp-4) var(--sp-4); }
.disclose-deep .dashboard-section { margin: var(--sp-6) 0 0; }
.disclose-deep .dashboard-section:first-of-type { margin-top: var(--sp-4); }
.disclose-deep .jump-nav { position: static; margin: var(--sp-3) 0 0; }

/* 위험 표시는 접지 않는다 — 다만 주황 알약 세 개가 나란히 서면 그것대로
 * 소음이라, 테두리만 남긴 조용한 칩으로 바꾼다. */
/* 아래 여백이 0이라 카드 격자가 배지 줄 바로 아래 붙어 있었다
 * (실측: 배지 bottom 394px = 카드 top 394px). */
.risk-strip { gap: var(--sp-1h); margin: var(--sp-3) 0 var(--sp-4); }

/* 배지.
 * 예전에는 8.5px 등폭 + `text-transform: uppercase`였다. 한글에 대문자 변환은
 * 아무 일도 하지 않으면서 자간만 늘리고, 등폭 스택의 한글은 대체 글꼴로
 * 빠진다 — "저유동성 가능"이 제 카드 안에서 혼자 다른 글꼴이었다.
 * 심각도는 테두리 색이 아니라 **옅은 바탕**으로 말한다. 어두운 배경에서
 * 1px 색 테두리는 거의 보이지 않는데, 그렇다고 진하게 하면 배지가 카드보다
 * 크게 소리친다. */
.status-badge {
  min-height: 22px; padding: 3px 9px;
  border: 1px solid transparent; border-radius: var(--r-pill);
  background: var(--panel-3); color: var(--ink-2);
  font: 550 var(--fs-xs)/1.4 var(--sans); letter-spacing: 0; text-transform: none;
  /* 접힌다. `nowrap`이면 좁은 카드에서 글자가 상자 밖으로 그려진다 —
     `max-width`로 상자만 줄이면 상자는 들어가고 글자만 삐져나와서, 재보면
     "안 넘친다"가 나오는데 화면에서는 넘치는 상태가 된다(2026-08-30 실측:
     한국어는 들어가고 영어 "Thin trading · price can jump"가 카드 170px를
     176px로 넘겼다).

     자르지 않고 접는 이유는 이 칩이 "실제 체결가 아님" 계열의 정직성 표기라서다.
     `text-overflow: ellipsis`로 끝을 숨기면 경고의 절반만 남는다. */
  max-width: 100%; white-space: normal; text-align: center;
}
.status-badge.fresh { color: var(--green); background: color-mix(in srgb, var(--green) 14%, transparent); }
.status-badge.stale, .status-badge.warn {
  color: var(--amber); background: color-mix(in srgb, var(--amber) 14%, transparent);
}
.status-badge.error { color: var(--red); background: color-mix(in srgb, var(--red) 14%, transparent); }
.status-badge.info { color: var(--accent); background: var(--accent-soft); }

/* 섹션 머리의 고지 칩은 사건이 아니라 **상시** 표시다. 심각도 배경을 그대로
 * 받으면 호박색 알약 셋이 늘 켜져 있어, 정작 카드 안의 경고가 묻힌다.
 * 여기서는 조용한 윤곽선으로 되돌린다. */
/* 연중 최고 대비는 정의상 0 이하다. 등락색(빨강)을 쓰면 "오늘 떨어졌다"로
 * 읽힌다 — 그날의 움직임이 아니라 고점에서의 거리다. 조용한 잉크로 둔다. */
.kridx-table td.peak { color: var(--ink-3); }

/* /score 카드의 인라인 배지 — 클래스만 있고 규칙이 없어 일반 텍스트로
   보이던 것(2026-08-27 라이브 실측). status-badge와 같은 토큰을 쓴다. */
.score-new, .score-halted, .score-landed, .score-arriving {
  display: inline-block; padding: 1px 7px; margin-left: 4px;
  border-radius: var(--r-pill); vertical-align: 1px;
  font: 600 var(--fs-xs)/1.5 var(--sans); white-space: nowrap;
}
.score-new { color: var(--accent); background: var(--accent-soft); }
.score-halted { color: var(--amber); background: color-mix(in srgb, var(--amber) 14%, transparent); }
/* 카드가 왜 판에 있는지 — 결과가 막 나온 것과 갓 도착한 것. 셋이 한 표에
   섞이므로 표시가 없으면 빈 칸의 이유를 읽는 사람이 매번 다시 묻는다. */
.score-landed { color: var(--ink-2); background: var(--panel-3); border: 1px solid var(--line-strong); }
.score-arriving { color: var(--faint); background: transparent; border: 1px dashed var(--line); }

.risk-strip .status-badge {
  padding: 4px 10px;
  color: var(--ink-3); background: transparent; border-color: var(--line-strong);
}

/* "지금 몇 명이 보고 있다"는 살아 있다는 신호다. 숫자만 있으면 화면에 박힌
 * 글자로 읽혀서, 맥박 하나를 붙인다. 움직임을 원치 않는 사람에게는 켜진 점만
 * 남는다. */
.presence-badge { gap: var(--sp-1h); padding: 4px 10px; font: 600 var(--fs-xs)/1.4 var(--sans); }
.presence-badge::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--green); box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 60%, transparent);
  animation: presence-pulse 2.4s ease-out infinite;
}
@keyframes presence-pulse {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 55%, transparent); }
  70% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--green) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--green) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) { .presence-badge::before { animation: none; } }

/* KO/EN을 DOM에 함께 담고 골라 보여준다. legal.css와 같은 규칙이며, 같은
 * 이유로 [lang="en"]이 아니라 클래스를 쓴다 — lang 속성으로 셀렉트하면
 * <html lang="en">에 걸려 문서 전체가 사라진다. */
.lang-en { display: none; }
html[data-lang="en"] .lang-ko { display: none; }
html[data-lang="en"] .lang-en { display: revert; }

/* ======================================================================
 * 6. 용어 — 점선 밑줄 + 팝오버
 * ================================================================== */
.term {
  padding: 0 1px; border: 0; background: none; cursor: help; font: inherit;
  color: var(--ink);
  border-bottom: 1px dashed color-mix(in srgb, var(--accent) 65%, transparent);
}
.term::after { content: "ⓘ"; margin-left: 2px; color: var(--accent); font-size: .85em; vertical-align: .05em; }
.term:hover, .term[aria-expanded="true"] { color: var(--accent); border-bottom-color: var(--accent); }

.term-pop {
  position: absolute; z-index: 200; width: min(340px, calc(100vw - 24px));
  padding: var(--sp-4); background: var(--panel-2);
  border: 1px solid var(--line-strong); border-radius: var(--r-md); box-shadow: var(--shadow);
}
.term-pop h3 { margin: 0 0 var(--sp-1h); font-size: var(--fs-md); font-weight: 700; }
.term-pop .term-def { margin: 0 0 var(--sp-3); color: var(--ink); font-size: var(--fs-md); line-height: 1.65; }
.term-pop dl { margin: 0; display: grid; gap: var(--sp-2); }
.term-pop dt { color: var(--accent); font-size: var(--fs-xs); font-weight: 700; }
.term-pop dd { margin: 2px 0 0; color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.6; }
.term-pop .term-more {
  display: inline-block; margin-top: var(--sp-3);
  color: var(--accent); font-size: var(--fs-xs); font-weight: 700; text-decoration: none;
}
.term-pop .term-more:hover { text-decoration: underline; }
.term-pop .term-close {
  position: absolute; top: 6px; right: 6px; width: 26px; height: 26px;
  border: 0; border-radius: var(--r-sm); background: transparent; color: var(--ink-3); cursor: pointer;
  font-size: var(--fs-md); line-height: 1;
}
.term-pop .term-close:hover { background: var(--panel-3); color: var(--ink); }

@media (max-width: 560px) {
  /* 모바일에서는 하단 시트로 — 좁은 화면에서 떠 있는 말풍선은 잘린다. */
  .term-pop {
    position: fixed; inset: auto 0 0 0; width: 100%;
    border-radius: var(--r-lg) var(--r-lg) 0 0; border-bottom: 0;
    padding-bottom: var(--sp-6);
  }
}

/* ======================================================================
 * 6b. 용어 사전 페이지
 * ================================================================== */
.glossary .console-head { border-bottom: 1px solid var(--line); }
.glossary-index {
  display: flex; flex-wrap: wrap; gap: var(--sp-1h);
  margin: var(--sp-4) 0 0; padding: var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel);
}
.glossary-chip {
  padding: 5px 10px; border: 1px solid var(--line); border-radius: var(--r-pill);
  color: var(--ink-2); font-size: var(--fs-xs); font-weight: 600; text-decoration: none;
}
.glossary-chip:hover { color: var(--ink); border-color: var(--accent); background: var(--panel-2); }

.term-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
@media (max-width: 900px) { .term-list { grid-template-columns: 1fr; } }

.term-entry {
  position: relative;
  padding: var(--sp-4); border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--panel);
  /* 목차에서 눌러 내려왔을 때 고정 헤더 밑으로 숨지 않게. */
  scroll-margin-top: calc(var(--mast-h) + var(--sp-4));
}
.term-entry:target { border-color: var(--accent); background: var(--panel-2); }
.term-entry h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-lg); font-weight: 700; }
.term-entry .term-def { margin: 0 0 var(--sp-3); color: var(--ink); font-size: var(--fs-md); line-height: 1.7; }
.term-entry dl { margin: 0; display: grid; gap: var(--sp-2); }
.term-entry dt { color: var(--accent); font-size: var(--fs-xs); font-weight: 700; }
.term-entry dd { margin: 2px 0 0; color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.65; }

/* ── 같은 줄의 용어 카드는 같은 자리에서 같은 높이로 선다 ────────────────
 *
 * 실측 PC 1440: 제목이 한 줄인 카드와 두 줄인 카드가 나란히 서면 그 아래
 * 정의·설명이 통째로 22.1px 어긋난다(한 화면에 17건). 눈에는 오른쪽 카드가
 * 아래로 처진 것으로 보인다.
 *
 * `.metric-card`·`.tile`과 같은 처방인데 **한 겹 더 깊다.** 카드 속 내용이
 * 언어별 상자 안에 있어서, 카드가 부모의 트랙을 나눠 받고 그 상자가 다시
 * 나눠 줘야 한다.
 *
 * **언어 상자에 `display`를 함부로 주지 않는다.** `.lang-en { display: none }`이
 * 언어 토글의 전부다 — 여기서 `display: grid`를 주면 영어 원문이 한국어와 함께
 * 뜬다. 토글과 같은 조건으로 갈라 지금 보이는 쪽에만 준다. */
@supports (grid-template-rows: subgrid) {
  .term-list > .term-entry {
    display: grid; grid-template-rows: subgrid; grid-row: span 3; row-gap: 0;
  }
  html:not([data-lang="en"]) .term-list > .term-entry > .lang-ko,
  html[data-lang="en"] .term-list > .term-entry > .lang-en {
    display: grid; grid-template-rows: subgrid; grid-row: 1 / span 3; row-gap: 0;
  }
  .term-entry h3 { grid-row: 1; }
  .term-entry .term-def { grid-row: 2; }
  .term-entry dl { grid-row: 3; }
}
.term-anchor {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  color: var(--ink-3); font: 700 var(--fs-sm)/1 var(--num); font-variant-numeric: tabular-nums; text-decoration: none; opacity: 0;
}
.term-entry:hover .term-anchor, .term-anchor:focus-visible { opacity: 1; }
/* 호버가 없는 기기에서는 이 앵커가 **영원히** 안 뜬다 — 폰에서 48개가 닿을 수
   없는 자리로 남아 있었다(실측 2026-09-04). 조용히 켜 둔다. 흐리게 만들지
   않는 이유는 `--ink-3`을 더 내리면 대비가 무너지기 때문이다. */
@media (hover: none) {
  .term-anchor { opacity: 1; }
}
.term-anchor:hover { color: var(--accent); }

.glossary .console-section { margin-top: var(--sp-6); }

/* ======================================================================
 * 7. 존 카드 · 피드 조정
 * ================================================================== */
.zone-links { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3); }
@media (max-width: 900px) { .zone-links { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.zone-link-card {
  display: flex; flex-direction: column; gap: var(--sp-1h);
  padding: var(--panel-inset); background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r-md); text-decoration: none; color: inherit;
  transition: border-color .15s, background .15s;
}
.zone-link-card:hover { border-color: var(--accent); background: var(--panel-2); color: inherit; }
.zone-link-card strong { font-size: var(--fs-md); font-weight: 650; }
.zone-link-card span { color: var(--ink-3); font-size: var(--fs-sm); line-height: 1.55; }
.zone-link-card .zone-mini {
  margin-top: auto; padding-top: var(--sp-2);
  color: var(--ink-2); font: 600 var(--fs-xs)/1.6 var(--num); font-variant-numeric: tabular-nums;
}
.zone-link-card .zone-mini small { font-size: var(--fs-xs); color: var(--ink-3); }

/* 피드 — 9~10px로 깔려 있던 메타를 전부 12px 바닥 위로 올린다. 날짜·출처·태그가
 * 본문보다 작아야 할 이유는 있지만, 읽히지 않을 만큼 작아야 할 이유는 없다. */
/* 같은 패널 안의 푸터가 var(--sp-4)라 14px이면 행 글자가 푸터 글자보다
 * 2px 안쪽에 선다. 눈에 잘 안 띄지만 줄이 두 개 있으면 보인다. */
#feed-body { column-gap: 11px; }
.feed-row { padding: 10px var(--panel-inset); column-gap: 11px; }
.feed-row, .feed-item, .feed-text { font-size: var(--fs-sm); }
.feed-date { font-size: var(--fs-xs); color: var(--ink-3); }
.feed-tag { padding: 3px 8px; font-size: var(--fs-xs); }
.feed-domain { font-size: var(--fs-xs); color: var(--ink-3); }
.feed-move { padding: 2px 8px; font-size: var(--fs-xs); }
.feed-hub { font-size: var(--fs-xs); color: var(--ink-3); }
/* 필터 칩의 왼쪽 면을 아래 날짜 열과 같은 레일에 둔다. */
.panel > .feed-filter {
  padding: var(--sp-3) var(--panel-inset) 0;
  margin-bottom: 0;
}
/* 이 들여쓰기는 `/news`의 것이다 — 거기서는 헤더가 판 안에 선다.
   홈에서는 헤더가 판 **밖**에 서므로 같은 16px이 제목만 오른쪽으로 민다:
   섹션 h2 여섯 개의 x가 12·12·12·**28**·12·12였다(412·390·360 전부).
   제목이 자기 패널(x=12)보다 오른쪽에 있는 상태다. 홈에서는 걷는다. */
body:not(.page-landing) #signal-feed > header { padding-inline: var(--sp-4); }
.feed-filter button, .feed-upcoming a, .feed-upcoming span { font-size: var(--fs-xs); }
@media (max-width: 560px) {
  /* 좁은 화면에서 등락 칩과 허브 링크가 줄 밖으로 밀려 가로 스크롤을 만들었다.
   * 한 줄을 고집하지 말고 접히게 둔다 — 이제 꼬리 칸(.feed-main) 안에서 접힌다. */
  .feed-hub { margin-left: 0; }
}

/* 데이터 원칙 블록은 랜딩 맨 아래로 내리고 조용하게. */
.methodology { margin-top: var(--sp-7); padding-top: var(--sp-5); border-top: 1px solid var(--line); }
.methodology h2 { font-size: var(--fs-lg); }
.method-grid article strong { font-size: var(--fs-sm); }
.method-grid article p { color: var(--ink-3); font-size: var(--fs-xs); }
/* 출처 표기에는 끊을 곳 없는 긴 기관명·URL이 들어온다. 좁은 화면에서 이게
 * 페이지 전체에 가로 스크롤을 만들고 있었다(318px 실측). */
/* 이 자리가 사이트에서 가장 나쁜 기하였다 — **가장 작은 글자 × 가장 긴 줄**
 * (12px에 238 한글자/줄, 데스크톱 실측). 그런데 여기 실리는 것이 FRED 서면
 * 승인 문구와 KRX 전제조건, 곧 계약이 읽히기를 요구하는 문장이다.
 * `tokens.css`가 이 계열을 12→13px로 올린 이유와 같은 이유로 폭을 준다. */
.attribution { width: 100%; overflow-wrap: anywhere; }
.attribution a { word-break: break-word; }

/* 손가락 자리 24px 바닥 — 규칙 본체와 근거는 `monitor.css`의 같은 이름 블록에
   있다. `.bio-cat-what`은 이 파일의 부품이라 여기 쓴다(두 파일에 걸친 클래스를
   늘리지 않는다는 `test_stylesheet_split.py`의 계약). */
.bio-cat-what a { padding-block: 3px; min-height: 24px; }

.site-footer { margin-top: var(--sp-6); color: var(--ink-3); font-size: var(--fs-xs); }
.site-footer p, .site-footer nav a { font-size: var(--fs-xs); }

/* ======================================================================
 * 8. 좁은 화면
 * ================================================================== */
@media (max-width: 760px) {
  /* 두 줄로 접는다: [로고 · 검색 · 모드 · 언어] / [탭]. 세 줄이 되면 첫 화면의
   * 3분의 1을 머리말이 먹는다. */
  /* 좁은 화면에서 고정 띠까지 붙어 있으면 볼 수 있는 높이가 얼마 안 남는다. */
  .tape { top: 0; position: static; }
  .console-head { padding-bottom: var(--sp-3); }
  .console-head h1 { font-size: var(--fs-xl); }
  .console-meta { flex-wrap: wrap; gap: var(--sp-2); min-height: 0; }
  .refresh-button { white-space: nowrap; }
}

@media (max-width: 560px) {
  /* 로고는 마크만 남긴다. 워드마크까지 두면 검색·모드·언어가 다음 줄로 밀려
   * 머리말이 다시 세 줄이 된다. 좌우 여백도 16 → 12로 줄여 한 줄에 담는다
   * (356px 화면에서 실측: 320px가 필요한데 309px밖에 없었다). */
  .shell { padding-left: 12px; padding-right: 12px; }
  /* 첫 제목까지 32px을 비우고 있었다. 폰은 머리말·띠가 이미 위쪽 90px을
     쓰고 있어서, 그 아래 32px은 화면 첫 정보를 한 뼘 더 밀어낸다
     (운영자 2026-09-06). 16으로 내린다 — 데스크톱은 그대로 32다. */
  .shell { padding-top: var(--sp-4); }
  .tape { padding-left: 12px; padding-right: 12px; }
}

/* 아주 좁은 화면(≤400px)에서는 단위 글자를 한 칸 낮춘다 — 원화 7자리와 KRW가
 * 같은 줄에 들어가야 한다. */
@media (max-width: 400px) {
  .tile-unit { font-size: var(--fs-xs); }
}

/* 320px대(구형 iPhone SE)에서는 검색칸을 한 번 더 줄여야 머리말이 두 줄로
 * 유지된다. 포커스하면 넓어지므로 입력에는 지장이 없다. */
/* ===== 경제 캘린더 =========================================================
 * 달력으로 보는 이유는 "빈 날"이 정보이기 때문이다. 표에서는 8월 26일 다음이
 * 9월 4일이라는 사실이 두 줄로만 보이지만, 격자에서는 그 사이 여드레가
 * 눈으로 보인다. 넓은 화면은 칸 안에 이름을, 좁은 화면은 점만 찍고 이름은
 * 격자 아래 목록에서 읽는다 — 48px 칸에 글자를 넣으면 둘 다 못 읽는다. */
.calendar-panel {
  display: grid; grid-template-columns: minmax(0, 2.35fr) minmax(270px, .8fr);
  align-items: stretch; overflow: hidden; border-radius: var(--r-lg);
}
.calendar-panel > #cal-body { min-width: 0; }
.calendar-panel > #cal-upcoming { min-width: 0; border-left: 1px solid var(--line); }

/* 홈에서는 오늘 이후 세 건이 본문이다. 월간 격자와 전체 표는 같은 데이터를
 * 탐색하는 보조 도구라 한 단계 뒤에 둔다. */
.cal-brief { padding: var(--sp-5) 0 var(--sp-3); }
.cal-brief > h3 {
  margin: 0; padding: 0 var(--panel-inset) var(--sp-3); color: var(--ink);
  font: 700 var(--fs-lg)/1.3 var(--sans);
}
.cal-brief-list { margin: 0; padding: 0; list-style: none; }
.cal-brief-list li + li { border-top: 1px solid var(--line); }
.cal-brief-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline; gap: 4px var(--sp-2); min-height: 76px;
  padding: var(--sp-3) var(--panel-inset);
  color: inherit; text-decoration: none;
}
.cal-brief-row:hover .cal-brief-copy strong { color: var(--accent); }
.cal-brief-date {
  grid-column: 1; color: var(--accent); font: 650 var(--fs-sm)/1.35 var(--sans);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.cal-brief-copy { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cal-brief-copy strong {
  color: var(--ink); font-size: var(--fs-md); font-weight: 650; line-height: 1.35;
  word-break: keep-all; transition: color 120ms ease-out;
}
.cal-brief-copy small { color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.4; }
.cal-brief-meta { display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-1h); }
.cal-brief-dday {
  grid-column: 2; grid-row: 1; min-width: 2.75rem; color: var(--ink-2); font: 700 var(--fs-xs)/1.4 var(--num);
  font-variant-numeric: tabular-nums; text-align: right;
}
.cal-brief-dday.is-now { color: var(--accent); }
.cal-brief-empty { padding: var(--sp-4) 0; color: var(--ink-3); font-size: var(--fs-sm); }

.cal-month-fold, .cal-all { border-top: 1px solid var(--line); }
.cal-month-fold > summary, .cal-all > summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  min-height: 48px; padding: 0 var(--panel-inset); color: var(--ink-2);
  font-size: var(--fs-sm); font-weight: 600; cursor: pointer; list-style: none;
}
.cal-month-fold > summary::-webkit-details-marker,
.cal-all > summary::-webkit-details-marker { display: none; }
.cal-month-fold > summary::after, .cal-all > summary::after {
  content: ""; width: 14px; height: 14px; flex: none; background: currentColor;
  mask: var(--ico-caret) center / contain no-repeat; transition: transform 160ms ease-out;
}
.cal-month-fold[open] > summary::after, .cal-all[open] > summary::after { transform: rotate(180deg); }
.cal-month-fold > summary:hover, .cal-all > summary:hover { color: var(--ink); }
.cal-month-count {
  margin-left: auto; color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.cal-month-body { border-top: 1px solid var(--line); }
.cal-nav {
  display: flex; align-items: center; gap: var(--sp-2);
  min-height: 64px; padding: var(--sp-3) var(--panel-inset); border-bottom: 1px solid var(--line);
}
.cal-step, .cal-jump {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 30px; height: 30px; padding: 0 var(--sp-2);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--panel-2); color: var(--ink-2);
  font: 500 var(--fs-sm)/1 var(--sans); cursor: pointer;
}
.cal-step { font-size: var(--fs-lg); }
.cal-step:hover:not(:disabled), .cal-jump:hover { border-color: var(--accent); color: var(--ink); }
/* 투명도로 비활성을 말하지 않는다 — .3이면 실효 대비가 1.98:1까지 떨어진다
   (2026-09-04 실측). 잉크를 한 단 내리고 테두리를 죽여 같은 뜻을 만든다. */
.cal-step:disabled { color: var(--ink-3); border-color: var(--line); cursor: default; }
.cal-month {
  margin: 0; min-width: 8.5em; text-align: center;
  color: var(--ink); font: 700 var(--fs-xl)/1.2 var(--sans); font-variant-numeric: tabular-nums;
}
.cal-legend { display: flex; gap: var(--sp-2); margin-left: auto; flex-wrap: wrap; }
/* 일정 종류는 값이 아니라 두 개뿐인 범주다. 월간 범례·다가오는 일정·모바일
   목록·전체 표가 같은 꼴을 써야 사용자가 색을 다시 배우지 않는다. 상승/하락
   색은 빌리지 않고, 기존 달력 범주색인 파랑(지표)·금색(정책)을 유지한다. */
.cal-kind-tag {
  display: inline-flex; align-items: center; gap: var(--sp-1h); width: max-content;
  min-height: 22px; padding: 1px 8px; border: 1px solid color-mix(in srgb, var(--accent) 42%, var(--line));
  border-radius: var(--r-pill); background: color-mix(in srgb, var(--accent) 10%, var(--panel-2));
  color: var(--accent); font: 650 var(--fs-xs)/1.35 var(--sans); white-space: nowrap;
}
.cal-kind-tag::before { content: ""; width: 6px; height: 6px; flex: none; border-radius: 50%; background: currentColor; }
.cal-kind-tag.is-policy {
  border-color: color-mix(in srgb, var(--amber) 42%, var(--line));
  background: color-mix(in srgb, var(--amber) 10%, var(--panel-2)); color: var(--amber);
}
.cal-key { font-size: var(--fs-xs); }

/* 첫 행(요일)만 내용 높이로 두고, 날짜 행은 전부 최소 74px. 명시 행을 하나만
 * 두면 나머지는 암시 행이 되어 grid-auto-rows가 걸린다. */
.cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  grid-template-rows: auto; grid-auto-rows: minmax(70px, auto);
  /* 칸 안쪽 padding(6px)과 합쳐 글자가 테두리+17px에 서게 한다 — 위의 달 이름과
   * 같은 줄에 맞추기 위해서다. 예전에는 달 이름 17px, 날짜 7px로 어긋났다. */
  padding: 0 10px; }
.cal-weekday {
  padding: var(--sp-2) var(--sp-1h); border-bottom: 1px solid var(--line);
  /* 요일 이름은 --sans로. --mono 스택에는 한글이 없어 "일 월 화"가 대체 글꼴로
   * 떨어지면서 자간과 굵기가 혼자 어긋났다. */
  color: var(--ink-3); font: 650 var(--fs-xs)/1 var(--sans); letter-spacing: .06em;
}
.cal-weekday.is-sun { color: var(--cal-sun); }
.cal-weekday.is-sat { color: var(--cal-sat); }

.cal-cell {
  display: flex; flex-direction: column; gap: 4px;
  padding: var(--sp-1h);
  border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.cal-cell:nth-child(7n) { border-right: 0; }
.cal-cell.is-blank { background: rgba(0, 0, 0, .16); }
/* 지난 날짜도 마찬가지다 — .45에서 2.90:1이었다. 면을 한 단 어둡게 하고
   글자를 --ink-3로 내리면 "지났다"는 여전히 읽히면서 대비가 산다. */
.cal-cell.is-past { background: color-mix(in srgb, var(--bg) 40%, transparent); }
.cal-cell.is-past .cal-n, .cal-cell.is-past .cal-daynum { color: var(--ink-3); }
.cal-cell.is-today { background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent); }
.cal-daynum { display: flex; align-items: center; gap: var(--sp-1h); }
.cal-n { color: var(--ink-2); font: 600 var(--fs-sm)/1.2 var(--num); font-variant-numeric: tabular-nums; }
.cal-cell.is-sun .cal-n { color: var(--cal-sun); }
.cal-cell.is-sat .cal-n { color: var(--cal-sat); }
.cal-cell.is-today .cal-n { color: var(--ink); }
.cal-dday {
  padding: 1px 5px; border-radius: var(--r-pill); background: var(--panel-3);
  color: var(--ink-3); font: 650 var(--fs-xs)/1.5 var(--num); font-variant-numeric: tabular-nums;
}
.cal-dday.is-now { background: var(--accent); color: var(--accent-ink); }

/* 왼쪽 3px 띠를 걷고 범주 색을 **테두리 전체**로 옮겼다(2026-09-04).
   색이 말하는 것(발표 종류)은 그대로 남고, 생성 UI의 표식만 사라진다. */
.cal-chip {
  display: block; padding: 4px var(--sp-2); border: 0; border-radius: var(--r-sm);
  background: color-mix(in srgb, var(--accent) 10%, var(--panel-2));
  color: var(--ink-2); font-size: var(--fs-xs); line-height: 1.35;
  text-decoration: none; overflow-wrap: anywhere;
}
.cal-chip.is-policy { background: color-mix(in srgb, var(--amber) 11%, var(--panel-2)); }
.cal-chip:hover { background: var(--panel-3); color: var(--ink); }
.cal-dots { display: none; gap: 3px; }
.cal-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--accent); }
.cal-dots i.is-policy { background: var(--amber); }

.cal-agenda { display: none; margin: 0; padding: 0; list-style: none; }
/* 날짜와 제목은 **글자의 밑선**으로 맞춘다 (운영자 2026-09-04, 폰).
   날짜는 --fs-xs, 제목은 --fs-sm이다. 격자의 기본은 칸을 늘리는 것이라
   두 글자가 각자 제 상자 위쪽에서 시작했고, 크기가 다르니 밑선이 어긋나
   날짜가 살짝 떠 보였다. 한 줄 안에서는 밑선이 같아야 한 줄로 읽힌다. */
.cal-agenda li {
  display: grid; grid-template-columns: 8.25rem minmax(0, 1fr); gap: 2px var(--sp-3);
  align-items: baseline;
  padding: var(--sp-3) var(--panel-inset); border-bottom: 1px solid var(--line);
}
.cal-agenda-date {
  grid-column: 1; grid-row: 1;
  color: var(--ink-3); font: 600 var(--fs-xs)/1.4 var(--sans); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* 왼쪽 면을 지우던 줄을 걷는다(운영자 제보 2026-09-06, 폰).
   `border-left: 0`은 칩이 **왼쪽 3px 띠**로 범주를 말하던 시절의 잔재다.
   2026-09-04에 그 띠를 걷고 색을 테두리 전체로 옮겼는데 이 override만 남아,
   위·오른쪽·아래만 있고 왼쪽이 뚫린 상자가 됐다(실측: border-left 0px none,
   나머지 세 면 1px solid). 상자로 그릴 거면 네 면이 다 있어야 상자다.
   `padding: 0`도 같은 잔재라 글자가 테두리에 붙어 있었다 — 칩의 값을 쓴다. */
.cal-agenda-name {
  grid-column: 2; grid-row: 1;
  min-width: 0; padding: 0; background: none;
  font-size: var(--fs-sm); line-height: 1.4;
}
.cal-agenda-name.is-policy { background: none; }
.cal-agenda-name:hover { background: none; }
.cal-agenda-kind {
  grid-column: 2; grid-row: 2; display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-1h);
  color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.4;
}
.cal-agenda-empty { padding: var(--sp-5) var(--panel-inset); color: var(--ink-3); font-size: var(--fs-sm); text-align: center; }

.cal-all { border-bottom: 0; }
.cal-all .table-scroll { padding: 0 0 var(--sp-3); border-top: 1px solid var(--line); }

/* 최근 발표 — 캘린더 격자 위에 서는 BLS 헤드라인(app/econ_release.py).
   값은 중립 잉크다(DESIGN.md "값은 색을 입지 않는다"). CPI가 오르는 것은 좋은
   일도 나쁜 일도 아니라서 등락색을 쓰지 않는다 — 지난달은 한 단 낮은 잉크로만.
   숫자 옆에 "만 명"이 붙으므로 --sans에 tabular-nums를 다시 건다(단축 속성이 끈다). */
.calendar-panel > .er { min-width: 0; border-top: 0; border-left: 1px solid var(--line); }
.er-title {
  margin: 0; padding: var(--sp-5) var(--panel-inset) var(--sp-2);
  color: var(--ink); font: 700 var(--fs-lg)/1.3 var(--sans);
}
.er-list {
  display: grid; grid-template-columns: minmax(0, 1fr);
  margin: 0; padding: 0; list-style: none;
}
.er-item { min-width: 0; padding: var(--sp-3) var(--panel-inset); border-top: 1px solid var(--line); }
.er-item.er-primary {
  display: grid; grid-template-columns: minmax(0, 1fr);
  align-items: start; gap: var(--sp-3); padding-top: var(--sp-2); padding-bottom: var(--sp-5);
  border-top: 0;
}
.er-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 2px var(--sp-2); }
.er-item.er-primary .er-head { flex-direction: column; align-items: flex-start; }
.er-name { color: var(--ink); font: 650 var(--fs-md)/1.35 var(--sans); word-break: keep-all; }
.er-when { color: var(--ink-3); font: 500 var(--fs-xs)/1.4 var(--sans); font-variant-numeric: tabular-nums; }
.er-figs {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-2) var(--sp-3); margin: var(--sp-2) 0 0;
}
.er-item.er-primary .er-figs { margin: 0; }
.er-fig { min-width: 0; }
.er-fig dt { color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.35; word-break: keep-all; }
.er-fig dd { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--sp-1h); margin: 2px 0 0; }
.er-val { color: var(--ink); font: 650 var(--fs-lg)/1.2 var(--sans); font-variant-numeric: tabular-nums; white-space: nowrap; }
.er-prev { color: var(--ink-3); font: 500 var(--fs-xs)/1.3 var(--sans); font-variant-numeric: tabular-nums; white-space: nowrap; }
.er-meta { margin: var(--sp-2) 0 0; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.45; }
.er-item.er-primary .er-meta { justify-self: start; margin: 0; white-space: normal; }
.er-meta a { color: inherit; text-underline-offset: 2px; }
.er-next {
  margin: 0; padding: var(--sp-2) var(--panel-inset); border-top: 1px solid var(--line);
  color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.5;
}
.er-next.is-live { color: var(--ink-2); }
/* 최근 하나 아래로 접힌 지난 발표. */
.er-more { border-top: 1px solid var(--line); }
.er-more > summary {
  min-height: 44px; padding: 0 var(--panel-inset); color: var(--ink-2);
  font-size: var(--fs-sm); cursor: pointer;
}
.er-more > summary:hover { color: var(--ink); }
@media (max-width: 980px) {
  .calendar-panel { grid-template-columns: minmax(0, 1fr); }
  .calendar-panel > #cal-upcoming { border-left: 0; border-top: 1px solid var(--line); }
}

/* 좁은 화면: 칸은 날짜와 점만, 이름은 아래 목록에서. */
@media (max-width: 760px) {
  .cal-brief { padding-top: var(--sp-4); }
  .cal-brief-row { min-height: 66px; }
  .cal-brief-date { font-size: var(--fs-sm); }
  .cal-brief-copy strong { font-size: var(--fs-md); }
  .cal-brief-dday { min-width: 2.75rem; font-size: var(--fs-xs); }
  .er-item.er-primary {
    grid-template-columns: minmax(0, 1fr); gap: var(--sp-3);
    padding-top: var(--sp-2);
  }
  .er-item.er-primary .er-head { flex-direction: row; align-items: baseline; }
  .er-item.er-primary .er-meta { justify-self: start; }
  .cal-cell { min-height: 54px; gap: 3px; padding: 5px 4px; }
  /* 격자 안의 칩만 숨긴다. 아래 목록의 이름(.cal-agenda-name)도 같은
   * .cal-chip이라 통째로 숨기면 좁은 화면에서 일정 이름이 사라진다. */
  .cal-cell .cal-chip { display: none; }
  .cal-dots { display: flex; }
  .cal-agenda { display: block; }
  .cal-weekday { padding: var(--sp-2) 4px; text-align: center; }
  .cal-daynum { justify-content: center; }
  .cal-dday { display: none; }
  .cal-dots { justify-content: center; }
  .cal-legend { width: 100%; margin: 4px 0 0; order: 9; }
  .cal-month { min-width: 0; flex: 1; font-size: var(--fs-md); }
  .cal-nav { flex-wrap: wrap; }
}

/* 종목코드는 제 열에 선다. 회사명과 한 칸에 붙어 있을 때는 굵기·글꼴이 달라
 * 어디까지가 코드인지 눈이 매번 다시 쟀다. */
.krp-code { color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* 홈의 "종목 더 보기" — 요약이 전부가 아니라는 표시. */
.kro-more { margin: var(--sp-3) 0 0; font-size: var(--fs-sm); }
.kro-more a { color: var(--accent); text-decoration: none; font-weight: 550; }
.kro-more a:hover { text-decoration: underline; }

/* ===== 전용 신호 피드 /news ================================================
 * 본문은 서버가 렌더한다. 여기서는 배치만 한다 — JS가 꺼져 있어도(크롤러가
 * 읽는 상태가 그렇다) 목록이 그대로 읽혀야 한다. */
.news-filter { display: flex; gap: var(--sp-1h); flex-wrap: wrap; margin: 0 0 var(--sp-4); }
.news-filter button {
  display: inline-flex; align-items: center; gap: var(--sp-1h);
  padding: 5px 11px; border: 1px solid var(--line-strong); border-radius: var(--r-pill);
  background: transparent; color: var(--ink-3);
  font: 550 var(--fs-xs)/1.5 var(--sans); cursor: pointer;
}
.news-filter button b { color: var(--ink-2); font-weight: 650; font-variant-numeric: tabular-nums; }
.news-filter button:hover { border-color: var(--accent); color: var(--ink); }
.news-filter button.active { border-color: var(--accent); background: var(--accent-soft); color: var(--ink); }

.news-list { list-style: none; margin: 0; padding: 0; }
.news-row {
  display: grid; grid-template-columns: 84px 1fr; gap: var(--sp-3);
  align-items: start; padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line);
}
.news-row:last-child { border-bottom: 0; }
.news-row[hidden] { display: none; }
.news-body { min-width: 0; }
.news-title { margin: 0; font-size: var(--fs-sm); line-height: 1.5; }
.news-title a { color: var(--ink); text-decoration: none; font-weight: 550; }
.news-title a:hover { color: var(--accent); text-decoration: underline; }
.news-meta {
  display: flex; gap: var(--sp-3); flex-wrap: wrap; margin: 4px 0 0;
  color: var(--ink-3); font-size: var(--fs-xs);
}
.news-meta time { font-variant-numeric: tabular-nums; }
.news-hub { color: var(--accent); text-decoration: none; }
.news-hub:hover { text-decoration: underline; }
.news-empty { padding: var(--sp-6) var(--panel-inset); color: var(--ink-3); font-size: var(--fs-sm); text-align: center; }

@media (max-width: 560px) {
  .news-row { grid-template-columns: 1fr; gap: var(--sp-2); }
}

/* 주제별로 보기(news_topics.py) — 있는 lane 출력을 주제로 묶은 카드. 목록 위에 선다.
 * 카드 폭의 바닥은 `min(100%, 280px)` — 360px 폰에서 한 줄, 넓으면 서너 장이 나란히.
 * 100%를 안 걸면 좁은 폭에서 280px 바닥이 셸을 밀어낸다. */
.news-topics { margin: 0 0 var(--sp-5); }
.news-topics > header { margin-bottom: var(--sp-3); }
.news-topics h2 { margin: 0; font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.01em; color: var(--ink); }
/* 카드는 제 높이만 쓴다 — 늘이면 한 줄짜리 카드가 옆 카드 높이(520px)만큼 텅 빈다
   (1440px 실측). 바닥 340px이면 1280 · 1440에서 세 칸이다. */
.nt-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr));
  gap: var(--sp-3); align-items: start;
}
.nt-card {
  min-width: 0; padding: var(--sp-3) var(--sp-4);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
}
.nt-card h3 { margin: 0 0 var(--sp-2); font-size: var(--fs-md); font-weight: 700; color: var(--ink); }
.nt-list { list-style: none; margin: 0; padding: 0; }
.nt-line { padding: var(--sp-1h) 0; }
.nt-line + .nt-line { border-top: 1px solid var(--line); }
/* 두 줄에서 자른다 — 공시 요약이 서너 줄씩이라 폰에서 카드 하나가 화면 반을 넘었다.
   온전한 글은 원문 링크가 갖는다(홈 '지금 이슈'의 제목도 두 줄에서 자른다). */
.nt-title {
  margin: 0; color: var(--ink); font-size: var(--fs-sm); line-height: 1.5; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.nt-title a { color: inherit; text-decoration: none; }
.nt-title a:hover { color: var(--accent); text-decoration: underline; }
.nt-kind { margin-right: var(--sp-1h); color: var(--accent); font-size: var(--fs-xs); font-weight: 650; }
.nt-who { margin-right: var(--sp-1); font-weight: 650; }
.nt-meta { margin: 2px 0 0; color: var(--ink-3); font-size: var(--fs-xs); overflow-wrap: anywhere; }
.nt-meta a { color: var(--ink-3); }
.nt-meta a:hover { color: var(--accent); }
.news-topics .nt-note { margin: var(--sp-2) 0 0; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.5; }

/* ===== 알림 설정 카드 ======================================================
 * 체크박스 줄은 통째로 누를 수 있어야 한다 — 폰에서 12px짜리 네모를 겨냥하게
 * 두면 켜고 끄는 일 자체가 실수가 된다. 그래서 <label>이 줄 전체를 감싼다. */
.push-settings { padding: var(--sp-4); }
/* h2가 13px이면 h3(17)보다 작다 — 단이 뒤집힌다. 곁판 제목 단으로. */
.push-settings h2 { margin: 0; font-size: var(--fs-lg); font-weight: 650; color: var(--ink); }
.push-intro { margin: var(--sp-2) 0 var(--sp-3); color: var(--muted); font-size: var(--fs-xs); line-height: 1.6; }
.push-topics { list-style: none; margin: 0; padding: 0; }
.push-topic + .push-topic { border-top: 1px solid var(--line); }
.push-topic label {
  display: grid; grid-template-columns: auto 1fr; gap: var(--sp-3);
  align-items: start; padding: var(--sp-3) 0; cursor: pointer;
}
/* 16px이었다 — 이 저장소가 정한 손가락 바닥 24 아래다(자 실측 2026-09-08,
   `/news` 양쪽 뷰포트). 라벨 전체가 눌리니 **누를 수는 있었지만**, 눈이
   겨냥하는 것은 라벨이 아니라 네모다. 24가 되면 첫 줄과 높이가 맞아 위 여백도
   필요 없다. */
.push-topic input { width: 24px; height: 24px; accent-color: var(--accent); }
.push-topic input:disabled { cursor: not-allowed; }
.push-topic b { display: block; font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.push-rule { display: block; margin-top: 2px; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.5; }
.push-note { display: block; margin-top: 4px; color: var(--muted); font-size: var(--fs-xs); line-height: 1.5; }
.push-status { margin: var(--sp-3) 0 0; color: var(--muted); font-size: var(--fs-xs); line-height: 1.6; }

/* ===== 바이오 =============================================================
 * 시장을 구역으로 나눈다. 한 화면에서 한국과 글로벌이 번갈아 나오면, 국내
 * 종목을 보는 사람은 매번 자기 것을 눈으로 골라내야 한다. */
.bio-zone { margin: var(--sp-7) 0 0; }
.bio-zone > .zone-head {
  display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap;
  padding-bottom: var(--sp-3); margin-bottom: var(--sp-2);
  border-bottom: 2px solid var(--line-strong);
}
.bio-zone > .zone-head h2 {
  margin: 0; color: var(--ink); font-size: var(--fs-xl); font-weight: 700; letter-spacing: -.03em;
}
.bio-zone .console-section { margin-top: var(--sp-5); }

/* 다가오는 결정 — 날짜·내용·종류 세 칸. 날짜가 맨 왼쪽에 고정폭으로 서야
 * 목록을 세로로 훑을 때 눈이 한 줄을 탄다. */
.bio-cat { list-style: none; margin: 0; padding: 0; }
.bio-cat-row {
  display: grid; grid-template-columns: 160px 1fr auto; gap: var(--sp-3) var(--sp-4);
  align-items: start; padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line);
}
.bio-cat-row:last-child { border-bottom: 0; }
.bio-cat-when { display: flex; flex-direction: column; gap: 3px; }
.bio-cat-when strong {
  color: var(--ink-2); font: 600 var(--fs-sm)/1.3 var(--num); font-variant-numeric: tabular-nums;
}
.bio-cat-dday {
  align-self: flex-start; padding: 1px var(--sp-1h); border-radius: var(--r-pill);
  background: var(--panel-3); color: var(--ink-3);
  font: 650 var(--fs-xs)/1.5 var(--num); font-variant-numeric: tabular-nums;
}
/* 2주 안이면 지금 챙길 일이다. 그때만 색을 쓴다 — 전부 물들이면 신호가 아니다. */
.bio-cat-row.is-near .bio-cat-dday { background: var(--accent); color: var(--accent-ink); }
.bio-cat-what { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.bio-cat-what a {
  color: var(--ink); font-size: var(--fs-sm); font-weight: 550; line-height: 1.45; text-decoration: none;
}
.bio-cat-what a:hover { color: var(--accent); text-decoration: underline; }
/* 자문위 안건 설명은 문장이다 — tokens.css의 산문 단계를 따른다.
   같은 특정도라 여기서 --fs-xs로 두면 나중에 실리는 이 파일이 이긴다. */
.bio-cat-what small { color: var(--ink-3); font-size: var(--fs-sm); line-height: 1.5; }
.bio-cat-tags { display: flex; gap: var(--sp-1h); flex-wrap: wrap; justify-content: flex-end; }
.bio-cat-empty { padding: var(--sp-5) var(--sp-4); color: var(--ink-3); font-size: var(--fs-sm); text-align: center; }

@media (max-width: 760px) {
  .bio-cat-row { grid-template-columns: 1fr; gap: var(--sp-2); }
  .bio-cat-when { flex-direction: row; align-items: center; gap: var(--sp-2); }
  .bio-cat-tags { justify-content: flex-start; }
}

/* 국민연금 국내주식 포트폴리오 — 도넛 + 범례.
 *
 * 좁은 화면에서는 도넛 아래로 범례가 내려간다. 범례를 도넛 옆에 억지로 붙여
 * 두면 21줄이 세로로 눌려 읽을 수 없게 된다. */
/* `.panel`은 스스로 여백을 주지 않는다 — 내용 종류마다 규칙을 따로 준다는 것이
 * 이 파일의 관용구다(위 `.news-videos`·`.kro-method` 주석 참조). 그 규칙을 안
 * 받아서 요약·표 제목이 패널 테두리에 그대로 붙어 있었다(실측 2026-08-25:
 * 왼쪽 여백 1px, 테두리 두께가 전부였다). 표는 셀에 이미 여백이 있으므로
 * `.table-scroll`은 그대로 두고 나머지만 앉힌다. */
.panel > #krpf-body > .krpf-wrap,
.panel > #krpf-body > .krpf-stats,
.panel > #krpf-body > .krpf-caption,
.panel > #usm-body > .usm-grid {
  padding-left: var(--sp-4); padding-right: var(--sp-4);
}
.panel > #krpf-body > .krpf-wrap { padding-top: var(--sp-4); }
.panel > #usm-body > .usm-grid { padding-top: var(--sp-4); padding-bottom: var(--sp-2); }

.krpf-wrap {
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
  align-items: center; justify-content: center;
}
.krpf-donut { width: 300px; height: 300px; flex: 0 0 auto; }
/* 조각의 움직임.
 *
 * 호버한 조각을 **바깥으로 민다**. 방향은 조각의 한가운데 각도이고 그 값은
 * 그리는 쪽이 `--dx`/`--dy`로 심어 준다 — 이동만 쓰므로 SVG에서 까다로운
 * 회전 원점을 잡을 필요가 없다.
 *
 * 처음 그릴 때는 조각이 차례로 피어난다. 스물한 개가 한꺼번에 나타나면 무엇이
 * 몇 개인지 눈이 못 따라간다. */
.krpf-slice, .usm-slice {
  stroke: var(--panel-2); stroke-width: 1;
  transition: opacity .14s ease, transform .18s cubic-bezier(.2,.8,.3,1);
}
.krpf-donut.is-hovering .krpf-slice,
.usm-donut.is-hovering .usm-slice { opacity: .38; }
.krpf-donut .krpf-slice.is-active,
.usm-donut .usm-slice.is-active {
  opacity: 1; transform: translate(var(--dx), var(--dy));
}
/* 범례 줄도 같이 살아난다. 색만으로 스물한 개를 짝지으라고 두면 범례가 장식이 된다. */
.krpf-legend li.is-active, .usm-legend li.is-active { outline: none; }
.krpf-legend li.is-active .krpf-legend-name,
.usm-legend li.is-active .krpf-legend-name { color: var(--ink); }
.krpf-legend li.is-active .krpf-legend-pct,
.usm-legend li.is-active .krpf-legend-pct { color: var(--ink); }
.krpf-legend li, .usm-legend li { transition: color .12s ease; cursor: default; }
.krpf-legend li:focus-visible, .usm-legend li:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-sm);
}
/* 가운데 글자는 조각을 가리킬 때 바뀐다 — 값이 튀어 보이지 않게 짧게 이어 준다. */
.krpf-center-value, .usm-center-value, .krpf-center-label, .usm-center-label {
  transition: opacity .12s ease;
}
/* 움직임을 원하지 않는 사람에게는 결과만 준다. */
@media (prefers-reduced-motion: reduce) {
  .krpf-slice, .usm-slice { animation: none; transition: opacity .1s ease; }
  .krpf-donut .krpf-slice.is-active,
  .usm-donut .usm-slice.is-active { transform: none; }
}
.krpf-center-value {
  font-family: var(--num); font-size: 22px; font-weight: 650; fill: var(--ink);
}
.krpf-center-label { font-family: var(--sans); font-size: var(--fs-xs); fill: var(--ink-3); }

/* 범례를 마음껏 늘리면 넓은 화면에서 다섯 열로 퍼져 1,000px을 먹고, 그 옆의
 * 도넛이 구석에 박힌 것처럼 보인다(2026-08-24 로컬에서 눈으로 확인). 최대 폭을
 * 묶어 두면 셋 열에서 멈추고 그림과 범례가 한 덩어리로 읽힌다. */
.krpf-legend {
  list-style: none; margin: 0; padding: 0; flex: 1 1 300px; max-width: 900px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 2px var(--sp-4); min-width: 0;
}
.krpf-legend li {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-xs); padding: 3px 0; min-width: 0; min-height: 24px;
}
.krpf-dot { width: 9px; height: 9px; border-radius: var(--r-sm); flex: 0 0 auto; }
.krpf-legend-name {
  color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.krpf-legend-pct {
  margin-left: auto; font-family: var(--num); color: var(--ink-3); flex: 0 0 auto;
}

.krpf-stats {
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
  margin: var(--sp-4) 0 0; padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
}
.krpf-stats dt { font-size: var(--fs-xs); color: var(--ink-3); margin: 0 0 2px; }
.krpf-stats dd {
  margin: 0; font-family: var(--num); font-size: var(--fs-sm); color: var(--ink);
}
.krpf-caption {
  margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-xs); color: var(--ink-3);
}
/* 다섯 칸뿐이라 내용 폭에 맡기면 표가 패널 왼쪽 400px에 몰린다. */
.krpf-table { width: 100%; max-width: 860px; }
.krpf-table td:nth-child(2), .krpf-table th:nth-child(2) { text-align: left; }
/* 순위 칸을 좁히고 왼쪽에 붙인다.
 *
 * `width:100%`인 표는 남는 폭을 칸마다 나눠 주는데, 그러면 첫 칸이 넓게
 * 벌어지고 그 안에서 오른쪽 정렬된 숫자가 안쪽으로 밀린다. 표 제목
 * (`평가액 상위 50종목`)은 패널 여백에 그대로 앉아 있으니 둘이 어긋나 보인다.
 * 첫 칸을 좁혀 왼쪽에 붙이면 순위·종목명이 표 제목과 같은 선에서 시작한다. */
.krpf-table th:first-child, .krpf-table td:first-child {
  width: 3em; text-align: left;
}
.krpf-asof { color: var(--ink-2); }

@media (max-width: 520px) {
  .krpf-donut { width: 240px; height: 240px; }
  .krpf-legend { grid-template-columns: 1fr; }
}

/* 13F 기관 포트폴리오 — 운용자 카드 격자.
 *
 * 카드가 여섯이라 국민연금처럼 도넛 하나를 크게 놓을 수 없다. 카드마다 작은
 * 도넛 + 상위 여덟 줄만 세우고, 나머지는 SEC 원문 링크로 넘긴다. */
.usm-grid {
  display: grid; gap: var(--sp-4);
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
.usm-card {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-4); min-width: 0;
  border: 1px solid var(--line); border-radius: var(--r-md); background: var(--panel-2);
}

/* 사람 이름이 제목이고 신고자 이름이 그 아래 근거다. 카드를 찾아 읽는 사람은
 * "버크셔"가 아니라 "버핏"을 찾는다. */
.usm-card-head { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.usm-names { display: flex; flex-direction: column; gap: 1px; min-width: 0; }

/* 얼굴. 사진이 없는 사람은 같은 크기의 이니셜 원이 자리를 채운다 — 넷만
 * 사진이고 둘은 비어 있으면 격자가 어긋나 보인다. */
.usm-portrait {
  flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%;
  overflow: hidden; background: var(--panel); border: 1px solid var(--line);
}
.usm-portrait img { width: 100%; height: 100%; object-fit: cover; display: block; }
.usm-portrait.is-initials {
  display: flex; align-items: center; justify-content: center;
  font-family: var(--num); font-size: var(--fs-sm); font-weight: 650;
  color: var(--ink-3); letter-spacing: .02em;
}
.usm-credit { display: block; width: 100%; color: var(--ink-3); line-height: 1.6; }
.usm-credit a { color: var(--ink-3); text-decoration: underline; text-underline-offset: 2px; }
.usm-card-head h2, .usm-card-head h3 {
  margin: 0; font-size: var(--fs-lg); line-height: 1.25; letter-spacing: -.01em;
  font-weight: 650; color: var(--ink);
}
.usm-fund { margin: 0; font-size: var(--fs-xs); color: var(--ink-3); }

.usm-donut { width: 190px; height: 190px; align-self: center; }
.usm-center-value {
  font-family: var(--num); font-size: 15px; font-weight: 650; fill: var(--ink);
}
.usm-center-label { font-family: var(--sans); font-size: var(--fs-xs); fill: var(--ink-3); }

.usm-legend { list-style: none; margin: 0; padding: 0; min-width: 0; }
/* 국내 쌍둥이(`.krpf-legend li`)는 `padding: 3px`인데 여기만 2px이라 높이가
   23.2px으로 앉았다 — 24px 바닥에서 **1px 모자랐다**(WCAG 2.5.8 AA, 17개 화면
   전수 측정 2026-09-05에서 유일하게 걸린 자리). 이 줄들은 `tabindex="0"`이라
   진짜 타겟이다. 여백을 맞추는 대신 바닥을 **명시**한다 — 글꼴이나 줄높이가
   바뀌어도 다시 미끄러지지 않게. */
.usm-legend li {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-xs); padding: 3px 0; min-width: 0; min-height: 24px;
}
/* 종목 얼굴(로고·글자판). 줄의 `gap`이 간격을 정하므로 `.inline-logo`의 오른쪽
   여백을 뺀다 — 두 벌이면 점·얼굴·이름 사이가 고르지 않다. `기타` 줄은 회사가
   아니라 얼굴 대신 같은 폭의 빈칸을 둔다. */
.usm-legend .inline-logo, .usm-change-names .inline-logo { margin-right: 0; }
.usm-face-gap { flex: 0 0 auto; width: 1.15em; }

/* 배지는 전부 수치에서 계산된다. 경고 톤은 "틀렸다"가 아니라 "이 그림을 읽을
 * 때 알아야 하는 사정이 있다"는 뜻이다. */
.usm-badges {
  list-style: none; display: flex; flex-wrap: wrap; gap: 4px; margin: 0; padding: 0;
}
.usm-badge {
  font-size: var(--fs-xs); padding: 2px 7px; border-radius: var(--r-pill);
  border: 1px solid var(--line); color: var(--ink-3);
}
.usm-badge-warn { color: var(--ink-2); border-color: var(--ink-3); }

.usm-note {
  margin: 0; font-size: var(--fs-xs); line-height: 1.5; color: var(--ink-3);
  padding-left: var(--sp-3); border-left: 2px solid var(--line);
}
.usm-card-foot { margin: auto 0 0; font-size: var(--fs-xs); }
.usm-failed { color: var(--ink-3); }

@media (max-width: 420px) {
  .usm-grid { grid-template-columns: 1fr; }
}

/* 현재 구성은 항상 보이고, 직전 분기 변화는 사용자가 요청할 때만 열린다. */
.usm-change-fold { margin: 0; border-top: 1px solid var(--line); }
.usm-change-fold > summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  min-height: 44px; color: var(--ink-2); font-size: var(--fs-sm); font-weight: 600;
  cursor: pointer; list-style: none;
}
.usm-change-fold > summary::-webkit-details-marker { display: none; }
.usm-change-fold > summary::after {
  content: ""; width: 14px; height: 14px; flex: none; background: currentColor;
  mask: var(--ico-caret) center / contain no-repeat; transition: transform 160ms ease-out;
}
.usm-change-fold[open] > summary::after { transform: rotate(180deg); }
.usm-change-fold > summary:hover { color: var(--ink); }
.usm-changes {
  display: flex; flex-direction: column; gap: var(--sp-1h);
  padding: var(--sp-3) 0; border-top: 1px solid var(--line);
}
.usm-changes-when { margin: 0; font-size: var(--fs-xs); color: var(--ink-3); }
.usm-change-counts {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2px var(--sp-3);
}
.usm-change-counts li {
  display: flex; justify-content: space-between; gap: var(--sp-2);
  font-size: var(--fs-xs); color: var(--ink-3);
}
.usm-change-counts b { font-family: var(--num); color: var(--ink-2); font-weight: 650; }
.usm-change-names { list-style: none; margin: 0; padding: 0; min-width: 0; }
.usm-change-names li {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-xs); padding: 1px 0; min-width: 0;
}
.usm-change-sign {
  flex: 0 0 auto; width: 9px; text-align: center;
  font-family: var(--num); color: var(--ink-3);
}
/* 폴백 색을 뺐다 — #4ade80·#f87171은 --up/--down과 거의 같은데 값이 달랐다.
   신호색이 둘씩 존재하면 그건 더 이상 신호가 아니다. 토큰은 tokens.css가
   언제나 정의하므로 폴백이 쓰일 경로 자체가 없었다. */
.usm-change-added .usm-change-sign { color: var(--green); }
.usm-change-dropped .usm-change-sign { color: var(--red); }
.usm-change-note { margin: var(--sp-2) 0 0; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.6; }

/* "화면에 보이면 불러옵니다"는 정적 마크업이라 `sayState()`가 닿지 않는다.
   그 자리도 기호를 갖는다 — 상태 블록 중 이것만 맨 글자로 남으면 오히려
   빠뜨린 것처럼 보인다. */
.state-block[data-i18n="status.viewport"]::before {
  content: ""; display: inline-block; width: 18px; height: 18px;
  margin-right: var(--sp-2); vertical-align: -.2em;
  background-color: currentColor; opacity: .85;
  -webkit-mask: var(--ico-eye) center / contain no-repeat;
  mask: var(--ico-eye) center / contain no-repeat;
}

/* 흐름 그림 — 시간 순서가 있는 규칙은 문장보다 **선**이 낫다.
 *
 * `/score`의 채점 규칙(공시일 → 기준가 동결 → +21/+63/+126 영업일)이 순전히
 * 글로만 서 있었다. 세 문단을 읽어야 "언제 무엇이 고정되는지"가 잡혔고,
 * "왜 어떤 카드는 기준가 대기인가"는 다시 한 문단이 필요했다.
 *
 * 그림이라고 이미지를 쓰지 않는다 — 선과 점은 CSS가 그린다. 이미지는
 * 다크 테마·언어·글자 크기를 따라오지 못하고, 크롤러가 못 읽는다.
 * 여기 서는 것은 **목록**이라 낭독기에는 다섯 단계로 그대로 읽힌다. */
.flow { margin: var(--sp-4) 0 var(--sp-5); }
.flow figcaption {
  /* 눈금 라벨(16:00 ET 등)이 레일 위 8px에 서므로(아래 ::after) 그 띠의
   * 자리까지 캡션 여백이 낸다 — 12px일 때 라벨이 선을 1px 넘어 겹쳐
   * "잘린 것처럼" 보였다(운영자 제보 2026-08-31, /us 데스크톱). */
  margin-bottom: var(--sp-5); color: var(--faint); font-size: var(--fs-xs);
}
/* 칸 수를 박지 않는다 — 그림마다 단계가 다르다(채점 5, 장 밖 3, 파이프라인 4).
   `repeat(5, …)`로 두었더니 네 단계짜리에서 오른쪽 한 칸이 비었다(실측). */
.flow-track {
  display: grid; gap: var(--sp-3); margin: 0; padding: 0; list-style: none;
  grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
}
.flow-step {
  position: relative; padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
}
/* 눈금 점. 값이 고정되는 자리만 액센트다 — 나머지는 재는 자리다. */
.flow-step::before {
  content: ""; position: absolute; top: -5px; left: 0;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--panel); box-shadow: 0 0 0 2px var(--line-strong);
}
.flow-step.is-anchor { border-top-color: var(--accent); }
/* "이 화면이 지금 보는 자리" — 선명한 테두리와 presence와 같은 2.4s 리듬으로
 * 표시한다. 뜻이 "지금"이라 쉬지 않아도 정직하다. */
.flow-step.is-anchor::before {
  background: var(--accent);
  box-shadow: none; outline: 2px solid var(--accent);
  animation: anchor-breathe 2.4s ease-in-out infinite;
}
@keyframes anchor-breathe { 50% { transform: scale(1.3); } }
@media (prefers-reduced-motion: reduce) { .flow-step.is-anchor::before { animation: none; } }
.flow-step::after {
  /* 라벨 바닥이 레일에서 --sp-2(8px) 떨어진다 — 밀착 규칙. -.9em일 때는
   * 12px 라벨이 -10.8~+1.2에 걸쳐 선을 넘었다. 세로(≤720) 모드는 자체
   * top: 0 이 있어 이 값을 받지 않는다. */
  content: attr(data-mark); position: absolute; top: calc(-1em - var(--sp-2)); right: 0;
  color: var(--faint); font: 700 var(--fs-xs)/1 var(--num);
  font-variant-numeric: tabular-nums;
}
.flow-step.is-anchor::after { color: var(--accent); }
.flow-step b { display: block; color: var(--ink); font-size: var(--fs-sm); font-weight: 700; }
/* `>`가 요점이다. `.flow-step span`으로 쓰면 (0,1,1)이라 안쪽 `.lang-en`의
   `display: none`(0,1,0)을 이겨 **한국어와 영어가 같이 선다**(실측 2026-08-31,
   /kr 흐름 그림). 언어 스팬은 손자라 직계 자식 선택자에 걸리지 않는다. */
.flow-step > span { display: block; margin-top: 4px; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.6; }
.flow-step em { color: var(--ink-2); font-style: normal; font-weight: 600; }
.flow-note {
  margin: var(--sp-4) 0 0; color: var(--ink-2); font-size: var(--fs-xs); line-height: 1.7;
}

/* 폰에서는 다섯 칸이 서면 한 칸이 글자 두 개 폭이 된다. 세로로 세우고
   선을 왼쪽으로 옮긴다 — 순서는 그대로 읽힌다. */
@media (max-width: 720px) {
  .flow-track { grid-auto-flow: row; grid-auto-columns: auto; gap: 0; }
  .flow-step {
    padding: 0 0 var(--sp-4) var(--sp-4);
    border-top: 0; border-left: 1px solid var(--line);
  }
  .flow-step:last-child { padding-bottom: 0; border-left-color: transparent; }
  .flow-step::before { top: 2px; left: -5px; }
  .flow-step.is-anchor { border-left-color: var(--accent); }
  /* 눈금 값은 제목과 같은 줄에 선다. `float`로 두면 마지막 자식이라
     문단 아래로 떨어지고, 마지막 단계에서는 아래 문단과 겹친다(실측). */
  .flow-step::after { top: 0; right: 0; }
}


/* 종목 표식. 로고가 아니라 글자를 쓰는 이유는 `console.js`의 주석에 있다.
 * 색조를 종목마다 나누지 않는다 — 초록 티커가 "오른 종목"으로 읽힌다. */
/* 로고가 붙으면 상자가 왼쪽으로 조금 열린다. 없는 종목은 글자만 — 두 모양이
 * 목록에서 섞이는 것은 감수한다. 없는 로고를 지어내는 것보다 낫다. */
.ticker-mark.has-logo { justify-content: flex-start; gap: .38em; padding-left: var(--sp-1); }
/* 회사 표식의 둥글기는 **비율**이다.
 *
 * 6px 고정이었다. 그 값이 종목 페이지의 30px 판에서는 20%(사각으로 읽힌다)인데
 * 칩의 15.6px에서는 38%라 **거의 원**이 된다 — 같은 로고가 자리마다 다른 모양이
 * 됐다(운영자 2026-09-06: "어떤건 타원이고"). 비율로 두면 어느 크기에서나 같은
 * 모서리로 읽힌다.
 *
 * 26%는 둥근 사각(스쿼클)과 원 사이에서 사각 쪽이다. 진짜로 동그란 마크(삼성
 * 전자·LG에너지솔루션·비트코인)는 자기 그림이 원이라 그대로 원으로 보이고,
 * 판형 마크는 사각으로 보인다 — 그 차이는 브랜드의 것이지 우리 것이 아니다.
 *
 * **종목 페이지 제목 옆(`.hero-logo`)은 여기서 뺀다.** 거기에는 가로로 긴
 * 워드마크가 설 수 있는데, 비율 둥글기는 가로 26%·세로 26%를 각각 잡아 모서리가
 * **타원**이 된다. 그 자리는 높이가 30px(폰 24px)로 못 박혀 있으므로 같은 비율의
 * px 값을 `stock.html`에서 직접 준다. */
.ticker-logo, .inline-logo, .letter-mark { border-radius: 26%; }
.ticker-logo {
  flex: 0 0 auto; width: 1.3em; height: 1.3em; object-fit: contain;
}
/* 마크가 없는 회사의 판. **진짜 로고와 같은 자리·같은 크기·같은 둥글기**여야
 * 목록에서 한 종류로 읽힌다 — 조금이라도 다르면 "로고 없음"이 다시 보인다.
 *
 * 글자는 흰색 하나로 고정한다. 판 색이 이미 회사를 가르므로 글자까지 색을
 * 지면 읽을 것이 둘이 된다. 판은 어둡게 잡혀 있어 흰 글자가 AA를 넘는다.
 *
 * 글꼴은 본문(`--sans`)이다. 여기 들어가는 것은 티커가 아니라 **회사 이름의
 * 첫 글자**라 식별자가 아니고, 한글이 등폭 스택에서 대체 글꼴로 빠지던
 * 실측(`tests/frontend/test_typography.py`)이 그대로 걸린다. */
/* **`inline-block`이다. `inline-flex`가 아니다.**
 *
 * 인라인 flex 상자의 밑선은 **속 항목의 글자 밑선**이고, 이미지의 밑선은
 * 상자의 아래 모서리다. 둘에 같은 `vertical-align`을 줘도 같은 데 서지 않는다
 * — 카드 제목(`display:block`)에서 실측했더니 진짜 마크는 −0.6px, 판은
 * +3.8px이라 판만 아래로 처졌다(운영자 2026-09-06: "다 로고가 아래로 살짝
 * 내려가있어서 종목명이랑 align도 안되어있어").
 *
 * `overflow:hidden`인 `inline-block`은 밑선이 아래 모서리다 — 이미지와 같다.
 * 그래서 가운데 맞춤은 **속 칸이** 진다. */
.letter-mark {
  flex: 0 0 auto; width: 1.3em; height: 1.3em;
  display: inline-block; color: var(--on-scrim, #fff); overflow: hidden;
}
/* 글자는 **속 칸**이 진다. 판의 `1.3em`은 자기 글꼴 크기를 기준으로 잡히므로,
 * 같은 요소에서 글꼴을 줄이면 판까지 줄어든다(실측 2026-09-06: 15.6px여야 할
 * 판이 11px로 섰다). 판은 부모의 em을 그대로 쓰고 글자만 안에서 줄인다. */
/* 글자는 판의 70% 안팎이어야 한 글자로 읽힌다. 판이 1.3em이므로 .9em이 그
 * 비율이다(20px 칩에서 판 15.6px · 글자 10.8px). 처음 .68em으로 잡았더니
 * 8.2px이라 한글이 뭉갰다(실측 2026-09-06).
 *
 * 12px 바닥의 예외다. 그 규칙은 **읽으라고 쓴 글**을 위한 것이고, 이 글자는
 * 회사 이름이 바로 옆에 있는 장식이다(`aria-hidden`). 로고 그림에 12px 바닥을
 * 적용하지 않는 것과 같은 이유다. */
.letter-mark > span {
  display: flex; height: 100%; align-items: center; justify-content: center;
  font: 700 .9em/1 var(--sans); letter-spacing: -.02em;
}
/* 로마자 두 자는 한 자보다 좁아야 판 안에 든다. */
.letter-mark[data-len="2"] > span { font-size: .68em; letter-spacing: -.05em; }
/* 칩 밖(타일·카드)에서는 판이 `.inline-logo`를 **같이 입는다**(`faceFor`가
 * 붙인다). 자리·여백 규칙이 한 곳에 남아야 진짜 마크와 판이 같은 줄에 선다 —
 * 여기서 규칙을 따로 쓰면 두 벌이 되고, 한쪽만 고치는 날이 온다. */
.letter-mark.inline-logo { width: 1.15em; height: 1.15em; }
/* 종목 페이지 제목 옆. 진짜 마크(`.hero-logo`)와 같은 높이로 서야 한 종류로
 * 읽힌다 — 거기서 높이를 정하므로 판은 가로만 같게 못 박는다. */
.stock-head .letter-mark.hero-logo { width: 30px; height: 30px; }
@media (max-width: 560px) {
  .stock-head .letter-mark.hero-logo { width: 24px; height: 24px; }
}
.stock-head .letter-mark.hero-logo > span { font-size: 19px; }
.stock-head .letter-mark.hero-logo[data-len="2"] > span { font-size: 14px; }
@media (max-width: 560px) {
  .stock-head .letter-mark.hero-logo > span { font-size: 15px; }
  /* 12px 바닥은 여기서도 지킨다. 24px 판에 로마자 두 자면 꽉 차지만, 바닥을
   * 뚫느니 자간을 더 조인다 — 예외 목록을 넓히는 것보다 이쪽이 싸다. */
  .stock-head .letter-mark.hero-logo[data-len="2"] > span {
    font-size: 12px; letter-spacing: -.06em;
  }
}
/* 칩 밖의 로고 — 보드 타일과 코인 카드의 이름 앞. 글자 크기를 따라간다.
 *
 * 두 자리의 조판이 다르다. 코인 카드는 블록 안의 인라인이라 `vertical-align`이
 * 듣고, 보드 타일은 `display:flex; align-items:baseline`이라 **듣지 않는다** —
 * flex 항목에는 vertical-align이 적용되지 않는다. 이미지의 밑선은 아래
 * 모서리라, baseline에 매달리면 글자 중심보다 위로 뜬다(실측 2026-08-31:
 * 타일에서 −3.6px, 운영자 지적). `align-self`는 flex 부모에서만 효력이 있고
 * 블록 부모에서는 무시되므로 둘을 한 규칙으로 덮는다. */
.inline-logo {
  flex: 0 0 auto; width: 1.15em; height: 1.15em; margin-right: .4em;
  object-fit: contain;
  vertical-align: -.2em; align-self: center;
}

/* 국기·품목 표식(`logos.js`의 MARK_SVG). 회사 로고가 없는 카드가 서는 자리라
   크기도 정렬도 로고와 같아야 한다 — 위 주석의 flex baseline 함정이 SVG에도
   그대로 걸린다. `color`는 currentColor로 그리는 마크(환율·변동성)가 쓴다.
   국기는 자기 색을 갖고 있어서 영향받지 않는다. */
.inline-mark {
  flex: 0 0 auto; width: 1.15em; height: 1.15em; margin-right: .4em;
  vertical-align: -.2em; align-self: center;
  color: var(--muted);
}
/* 국기만 `<img>`로 온다(`logos.js`의 MARK_IMAGE).

   처음엔 **높이**를 맞추고 폭을 놓아뒀다. 나란히 섰을 때 무게가 같아 보이는
   쪽이 높이라고 봤는데, 실제 화면에서는 아니었다 — 성조기(19:10)가 태극기
   (3:2)보다 **27% 넓어** 혼자 긴 띠로 읽혔다(운영자 모바일 실측 2026-09-02:
   "미국 국기만 가로가 너무 길어").

   그래서 **폭을 맞추고 높이를 놓아둔다.** 카드 제목은 가로로 흐르는 줄이라
   표식이 차지하는 가로 자리가 같아야 줄이 가지런하고, 세로 차이는 가운데
   정렬이 흡수한다. 비율은 각자 지킨다(`height: auto`, 찌그러뜨리지 않는다).
   폭은 다른 마크(금·환율·변동성)와 같은 1.15em이라 여섯 카드가 한 자에 선다.

   흰 깃면이 어두운 판에 뜨지 않게 아주 옅은 테두리를 두른다. */
img.inline-mark {
  width: 1.15em; height: auto;
  /* **짧은 변의 26%.** 회사 마크와 같은 규칙이다(거기는 정사각이라 변이 곧
   * 짧은 변이다). 고정 px이던 시절에는 6px이 국기 높이 11.5px의 **52%**를
   * 먹어 거의 타원이 됐다(운영자 2026-09-06: "성조기가 아직 타원인데?",
   * "태극기도"). 비율(`26%`)로 주면 가로·세로를 각각 26%로 잡아 이번엔
   * 모서리가 진짜 타원이 되므로, 짧은 변에서 계산한 길이를 준다.
   *
   * 국기는 3:2다 — 태극기가 그 비율이고 성조기를 거기 맞춰 잘랐다(아래 주석).
   * 그래서 높이는 `1.15em / 1.5`이고 그 26%가 이 값이다. */
  border-radius: calc(1.15em / 1.5 * .26);
  box-shadow: 0 0 0 .5px rgb(0 0 0 / .45);
}
/* 성조기만 태극기와 같은 3:2로 맞춘다.
 *
 * 폭을 맞췄더니 이번엔 성조기가 납작해 보였다(운영자 2026-09-03: "아직도 미국
 * 국기가 너무 가로로 퍼져있는 느낌"). 원인은 크기가 아니라 **비율**이다 —
 * 성조기 19:10, 태극기 3:2라 같은 폭에서 성조기가 27% 낮다.
 *
 * 비율은 자르지 않고는 못 맞춘다. 그래서 **자를 곳을 고른다.** 태극기를 정사각
 * 이나 4:3으로 깎으면 네 모서리의 사괘가 잘린다 — 그 사괘 때문에 원본 국기로
 * 바꾼 것이라 도로 없애는 셈이다. 반면 성조기의 깃봉 반대편은 **같은 줄무늬가
 * 반복될 뿐**이라, 21%를 덜어 내도 잃는 정보가 없다. 캔톤(별)은 왼쪽 40%에
 * 있으므로 `object-position: left`로 온전히 남는다.
 *
 * 즉 태극기는 손대지 않고, 성조기만 정보가 없는 쪽을 줄인다. */
img.inline-mark--us {
  height: calc(1.15em / 1.5);
  object-fit: cover;
  object-position: left;
}
.tile-head .inline-mark { margin-right: 0; }

.ticker-mark {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto; min-width: 4.4em; height: 1.9em; padding: 0 var(--sp-1h);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--panel-2); color: var(--ink);
  /* `.82em`은 상대값이라 15px 부모에서 12.3px, 13px 부모에서는 10.66px가
     된다 — 12px 바닥을 뚫는데, `tokens.css`의 교정층은 절대 크기 선택자만
     알고 있어 이걸 못 본다. 크기를 못 박는다.

     글꼴은 `var(--num)` 그대로 둔다. `.kro-sym`과 같은 일(식별자)을 하므로
     등폭으로 모으고 싶지만, `tests/frontend/test_typography.py`의 허용 목록은
     한글이 등폭 스택에서 대체 글꼴로 빠지던 실측이 만든 계약이다.
     짐작으로 넓히지 않는다. */
  font: 750 var(--fs-xs)/1.2 var(--num); font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
}

/* 주말 참고가 페이지.
 *
 * 이 페이지는 표보다 **글**이 절반이다 — 사람들이 검색창에 친 질문에 답하는
 * 것이 목적이기 때문이다. 그래서 읽기 폭을 묶는다: 패널 폭을 그대로 쓰면 한
 * 줄이 1,100px을 넘어 눈이 줄을 놓친다. */
.weekend-answer { padding: var(--sp-4); max-width: var(--measure); }
.weekend-answer h3 {
  margin: var(--sp-5) 0 var(--sp-2); font-size: var(--fs-md); color: var(--ink);
}
.weekend-answer h3:first-child { margin-top: 0; }
.weekend-answer p { margin: 0; line-height: 1.75; color: var(--ink-2); }
.weekend-answer em { color: var(--ink); font-style: normal; }
.weekend-faq { margin-top: var(--sp-5); }

/* 이 캡션은 **보이라고** 쓴 것이다.
 *
 * 표 캡션의 기본은 스크린리더 전용이다(`monitor.css`의
 * `.accessible-table caption`이 1px 상자에 `clip`으로 접는다). 그런데 그 규칙은
 * (0,1,1)이고 이 클래스는 (0,1,0)이라, 여기서 준 여백·색·정렬만 살아남고
 * `position`·`width`·`clip`은 접힌 채로 이겼다. 결과: `/score`와 `/weekend`의
 * 캡션이 32×24 상자로 접혀 첫 행 위에 겹쳐 서 있었다(실측 2026-08-30, 운영
 * 사이트 412px). `clip` 덕에 눈에는 안 보였지만 — 그래서 더 나빴다.
 *
 * `/score`에서 그 캡션은 **기준일을 적는 유일한 자리**다. 공시일 종가를
 * 동결해 채점하는 표에서 "언제 기준인가"가 화면 어디에도 없었다.
 *
 * 접는 규칙을 이기려면 같은 (0,1,1) 이상이어야 한다. */
.accessible-table caption.weekend-caption,
.weekend-caption {
  position: static; width: auto; height: auto; overflow: visible; clip: auto;
  caption-side: top; text-align: left; padding: var(--sp-4) var(--sp-4) var(--sp-2);
  color: var(--ink-3); font-size: var(--fs-xs);
}
.weekend-table { width: 100%; max-width: 860px; }
.weekend-table td small { display: block; color: var(--ink-3); font-size: var(--fs-xs); }
.weekend-table td.up { color: var(--up); }
.weekend-table td.down { color: var(--down); }
/* 공모 예정. 태그와 주석은 값 옆에 붙는 작은 글자라 숫자 자리폭을 방해하지
   않게 인라인으로 둔다. 지난 청약은 지우지 않고 흐리게 둔다 — "지난주에 뭐가
   있었나"도 같은 화면의 질문이다.

   이 규칙도 섹션과 함께 PR #155에 딸려 지워졌다가 2026-09-08에 돌아왔다.
   **모양만 남고 화면이 없으면 아무도 모르지만, 화면만 살리고 모양이 없으면
   태그가 맨 글자로 나온다** — 되살릴 때는 둘을 같이 센다. */
.kripo-tag {
  padding: 1px var(--sp-1h); border: 1px solid var(--line); border-radius: 999px;
  color: var(--faint); font-size: var(--fs-xs); vertical-align: middle;
}
.kripo-note { color: var(--faint); font-size: var(--fs-xs); }
.usipo-sic { color: var(--muted); font-size: var(--fs-xs); }
.kridx-table tr.is-past { color: var(--ink-3); }
.kridx-table tr.is-past .kripo-note { color: var(--ink-3); }

.weekend-empty {
  padding: var(--sp-5) var(--sp-4); color: var(--ink-3); text-align: left;
}

/* --- 모바일은 값이 먼저다 (안드로이드 실기기 피드백 2026-08-26·27) -------------
 *
 * 폰에서 인트로 문단과 섹션 설명이 첫 화면을 다 차지해, 가격에 닿기 전에
 * 글부터 두 화면을 지나야 했다.
 *
 * - 인트로 문단(.console-sub)은 폰에서 **아예 뺀다**(운영자 결정 2026-08-27).
 *   처음엔 2줄 클램프로 접었는데, 킥커("장 밖의 값 · 공시 · 지수")가 이미
 *   같은 말을 하고 있어 문장이 중간에 끊긴 두 줄은 자리만 차지했다.
 * - 섹션 설명(.section-copy)은 **두 줄로 접는다** — 값의 성격("현물 아님" 류)을
 *   말하는 문장이라 뺄 수는 없고, 클램프면 문서에 전문이 남아 모바일 우선
 *   색인과 보조기기 모두 그대로 읽는다.
 * - 섹션 사이 세로 여백(48px)도 폰에서는 줄인다 — 새로고침 줄과 첫 섹션
 *   제목 사이가 손가락 두 마디였다.
 *
 * 경고 칩(.risk-strip)은 접지 않는다 — "실제 체결가 아님" 같은 표기는
 * 정직성 의무라 값보다 먼저 보여야 한다. 칩은 이미 압축형이다.
 * 데스크톱과 넓은 화면은 이 블록 밖이라 그대로다. */
@media (max-width: 560px) {
  .console-head .console-sub { display: none; }
  .console-section .section-copy {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
  }
  /* 접는 결정은 그대로 두되 펼 수단을 준다. 접힌 문장에 "해석·방향 판정은
     하지 않습니다" 같은 정직성 문구가 들어 있어, 크롤러와 보조기기만 읽고
     폰 사용자는 못 읽는 상태로 두면 안 된다(2026-08-30 운영자 지적). */
  .console-section .section-copy.is-open {
    display: block;
    -webkit-line-clamp: unset;
    line-clamp: unset;
    overflow: visible;
  }
  .section-copy-more {
    display: inline-flex; align-items: center; gap: 4px;
    /* 아래 여백 12에 `.term-hints`의 8이 더해져 20px이 됐다 — 접기 버튼
       하나가 제 글자 높이(18)보다 넓은 빈칸을 아래에 깔고 있었다
       (운영자 제보 2026-09-06, /kr·공시 속보·13F 세 곳에서 같은 모양).
       4로 내려 합을 12px로 만든다. 위쪽 -8은 그대로 둔다 — 그건 이 버튼을
       제가 펴는 문장에 붙여 두려고 준 값이다. */
    margin: -8px 0 4px; padding: 4px 0;
    border: 0; background: none; color: var(--accent);
    font: 550 var(--fs-xs)/1.5 var(--sans); cursor: pointer;
  }
  /* 크기를 따로 주지 않는다 — 버튼 글자(12px)를 그대로 따르게 두면
     타이포 하한선을 지키면서 장식만 한다. */
  .section-copy-more::after {
    content: ""; display: inline-block; width: 1em; height: 1em;
    margin-left: 3px; vertical-align: -.125em; opacity: .7;
    background-color: currentColor;
    -webkit-mask: var(--ico-caret) center / contain no-repeat;
    mask: var(--ico-caret) center / contain no-repeat;
    transform: rotate(90deg); transition: transform .15s ease;
  }
  .section-copy-more[aria-expanded="true"]::after { transform: rotate(-90deg); }
  .console-head { padding-bottom: var(--sp-2); margin-bottom: var(--sp-3); }
  .console-section { margin-top: var(--sp-5); }
}

/* 첫 섹션이 자기 h2를 갖는 페이지(/kr·/crypto)는 h1 블록을 접는다 —
   활성 탭이 이미 위치를 말하고 있어 제목이 두 번 쌓였다. 폰 결정
   (2026-08-27)을 전 폭으로 확장(운영자 2026-08-31): 데스크톱에서도 h1과
   부제가 첫 값을 ~120px 밀어내고 있었다. 탭을 켜면 값이 보여야 한다.
   h1은 DOM에 남는다 — 색인은 이미 모바일 뷰(접힘) 기준이라 무변.
   갱신·새로고침 줄은 monitor.js가 첫 섹션 제목 아래로 옮긴다(/us와 같은
   순서). :has 미지원 브라우저에서는 원래 자리에 남는다. */
/* 2026-09-03 정정. 위 글은 "h1은 DOM에 남는다"고 적었지만, 숨긴 글자는
 * 색인에도 낭독에도 남지 않는다. 실제로 /kr·/crypto·/bio는 heading
 * 아웃라인이 H2부터 시작하고 있었다 — 페이지에 제목이 없는 셈이다.
 *
 * 아끼려던 것은 세로 자리였으니, 아끼는 대상을 제목이 아니라 **설명
 * 문단**으로 바꾼다. 첫 값을 밀어내던 ~120px의 대부분이 그 문단이었고,
 * 제목 한 줄은 30px대다. 문단은 폰에서만 접고 넓은 화면에서는 편다.
 *
 * `:not(:has(.console-meta))` 두 줄은 걷었다 — 갱신 줄이 어느 쪽에도
 * 없으므로(2026-09-03) 그 규칙은 이제 머리를 통째로 감춘다. */
.console-head.head-collapse-mobile .console-sub { display: none; }
@media (min-width: 901px) {
  .console-head.head-collapse-mobile .console-sub { display: block; }
}
.console-head.head-collapse-mobile { padding-bottom: var(--sp-3); margin-bottom: var(--sp-3); }

/* ======================================================================
 * 8. 탭 타깃 바닥 — WCAG 2.2 AA (24×24)
 *
 * 감사 실측(412px): 인라인 링크 열두 갈래가 24px 아래였다. 대부분 **높이**가
 * 문제였다 — 글자 크기가 12~13px이라 줄 상자가 14~23px밖에 안 됐다.
 * `a.news-hub`는 폭이 **7px**이었다(종목코드 링크 하나가 글자 한 자였다).
 *
 *   a.news-hub 7×19 · td a 15×14 · .kro-sym 51×14 · .kro-detail 22×15
 *   .cboard-sym 16×15 · .feed-hub 34×16 · .cal-chip 252×18 · .nvid-title 354×19
 *   .term 55×20 · .feed-text 126×21 · .feed-move 48×22 · .coin-tag 57×23
 *
 * 44×44(AAA)를 전부에 강요하지 않는 이유: 이 화면은 값이 빽빽한 콘솔이고,
 * 표 안 링크를 44px로 키우면 한 화면에 들어가는 행이 절반이 된다. AA 기준인
 * 24px을 바닥으로 삼고, **가장 많이 눌리는 마스트헤드 컨트롤에만** 44px
 * 히트 영역을 따로 준다(아래).
 *
 * 보이는 크기는 그대로 둔다 — `min-height`와 세로 여백만 준다. */
.news-hub, .kro-sym, .kro-detail, .cboard-sym, .feed-hub, .feed-text,
.feed-move, .coin-tag, .cal-chip, .nvid-title, .term, .issue-src,
.kro-card h3 a, .crypto-card h3 a, .site-footer nav a, .weekend-symbol a,
.accessible-table td a, .accessible-table th a, .term-anchor,
/* 표가 여덟 계열로 갈라져 있어서 이 바닥이 `.accessible-table` 한 벌에만 걸려
   있었다 — 나머지 일곱 계열의 링크는 15px로 서 있었다(실측 2026-09-17:
   /score 132곳 · /news 89곳 · /analytics 50곳 · /us 48곳).
   **계열 이름을 여덟 개 적지 않는다** — 전부 `.table-scroll` 안에 산다.
   한 줄이면 다음에 생길 아홉째 표도 바닥을 그냥 받는다. */
.table-scroll td a, .table-scroll th a, .scr-table td a, .stock-news a, .coin-news a,
/* 홀로 선 CTA — 문장 속 링크가 아니라 독립 동작인데 높이가 14~21px이었다
   (실측 2026-09-04: 홈 2곳 · `/us` 6곳).
   `monitor.css`에 `padding-block + min-height`로 한 번 손댔는데 **안 먹었다** —
   이것들은 진짜 `display: inline`이고, 비대체 인라인 요소에는 `min-height`가
   적용되지 않으며 세로 여백이 줄 상자를 키우지도 않는다. 여기 목록이
   `inline-flex`로 바꾸기 때문에 이 자리가 맞다. */
.kro-more a, .kro-method a, .usm-card-foot a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  min-width: 24px;
  justify-content: center;
}
/* 문장 안에서 흐르는 것들은 가운데 정렬을 하면 안 된다 — 왼쪽에 붙어야 한다. */
.feed-text, .nvid-title, .cal-chip, .term { justify-content: flex-start; }

/* ── 같은 줄의 카드는 같은 자리에서 같은 높이로 선다 ──────────────────────
 *
 * 이름을 안 자르기로 한 순간(위 ③) 긴 이름 카드의 머리는 두 줄이 된다. 그
 * 카드만 높아지면 같은 격자 줄의 옆 카드와 값이 어긋난다 — 운영자가 어제 짚은
 * "한쪽은 올라가있고"가 그대로 돌아온다.
 *
 * subgrid는 그 교환을 없앤다. 같은 줄의 카드가 부모의 줄 트랙을 함께 쓰므로
 * 머리 트랙의 높이는 그 줄에서 가장 높은 머리가 정하고 나머지가 따라간다.
 * 이름은 두 줄로 흐르고 값은 한 선에 선다. **높이를 미리 예약하지 않는다** —
 * 어느 이름이 올지 모르는데 바닥을 박는 방식은 이 저장소에서 두 번 물렸다.
 *
 * **머리만 나눠 쓴다.** 처음엔 카드의 일곱 자리를 전부 이름으로 박았다가
 * 되돌렸다 — 자가 바로 잡았다:
 *
 *     EMPTY  #kro-grid > .kro-card   내용 아래 57px 빈칸
 *
 * `.kro-card`의 자식이 격자마다 다르고, 한 격자 안에서도 다르다(실측):
 *
 *     #kro-grid    머리 · 값 · 종가대비 · [프리미엄]   ← 넷째는 여섯 중 둘에만
 *     #uso-grid    머리 · 값 · 등락 · 추이선
 *     #ctape-grid  머리 · 값 · 등락 · 추이선 · 배지
 *     #ckim-grid   머리 · 값 · 등락 · 표
 *
 * 자리를 다 박으면 프리미엄이 없는 넷이 그 트랙을 **비운 채로** 세로 자리를
 * 낸다. 줄은 맞지만 카드마다 57px씩 빈다 — 운영자가 싫다고 한 바로 그 빈칸을
 * 줄맞춤과 맞바꾸는 셈이다.
 *
 * 그런데 어긋남의 원인은 하나뿐이었다: **머리가 한 줄이냐 두 줄이냐.** 아래
 * 조각들은 카드마다 개수만 다르지 높이는 같다. 그러니 머리 트랙 하나만 나눠
 * 쓰면 되고, 그 아래는 각자 흐르게 두면 빈칸이 안 생긴다.
 *
 * `span 2`로 잡고 머리만 1번에 박는다. 나머지는 2번부터 자동으로 내려가는데,
 * span을 넘는 줄은 **그 카드의 암묵 트랙**이라 옆 카드와 나눠 갖지 않는다.
 *
 * subgrid를 모르는 브라우저는 이 블록을 통째로 건너뛴다 — 이름은 여전히 안
 * 잘리고, 줄맞춤만 못 한다. */
@supports (grid-template-rows: subgrid) {
  .kro-grid > .kro-card {
    display: grid; grid-template-rows: subgrid; grid-row: span 7; row-gap: 0;
    /* **칸 폭을 정하지 않으면 가로 스크롤이 생긴다.** 격자의 기본 칸은 `auto`,
       곧 `max-content`다 — 안 접히는 심벌(`HYPE-PERP`) 하나가 칸을 넓히고 카드의
       `min-width: 0`은 그 위에서 아무 일도 못 한다. 실측: `/crypto` 폰 390에서
       페이지 scrollWidth 421. `1fr`만으로는 안 된다(최소 크기가 여전히
       `max-content`다) — `minmax(0, 1fr)`이라야 한다. */
    grid-template-columns: minmax(0, 1fr);
    /* 머리 아래 줄들은 **제 높이로** 쌓인다. 암묵 트랙의 기본은 `auto`이고,
       카드가 그 줄에서 제일 높은 카드만큼 늘어나면 남는 높이를 그 줄들 사이로
       나눠 넣는다 — 상자는 맞았는데 값만 내려앉는 그 모양이다(실측 /kr 390:
       값 20 ↔ 29). 남는 자리는 카드 아래에 모은다. */
  }
  /* **자리를 다 박는다 — 주석이 권한 `span 2`는 실측에서 더 나빴다.**
   *
   * 위 주석은 "머리만 나눠 쓰고 나머지는 흐르게 두면 빈칸이 안 생긴다"고
   * 적어 두었다. 그대로 해 봤더니 자가 이렇게 답했다(2026-09-08 실측):
   *
   *     span 7 → span 2 :  /kr 97 → 82 (OVERLAP 7) · /crypto 100 → 82 (35)
   *                        /us 100 → 82 (24) · 홈 82
   *
   * subgrid에서 span을 넘는 자식은 **암묵 트랙**을 얻는데, 그 트랙은 카드가
   * 부모에게서 받은 자리 밖으로 자란다 — 옆 카드와 안 나눠 갖는 것은 맞지만
   * 아래 줄의 카드 위로 겹친다. 주석의 전제가 틀렸다.
   *
   * 그래서 일곱을 다 박는다. 대가인 꼬리 빈칸은 트랙이 아니라 **카드 바닥**
   * 에서 걷는다(아래 `align-content`). */
  .kro-grid > .kro-card > header { grid-row: 1; }
  .kro-grid > .kro-card > .kro-price { grid-row: 2; }
  .kro-grid > .kro-card > .kro-vs-ref { grid-row: 3; }
  .kro-grid > .kro-card > .kro-vs { grid-row: 4; }
  .kro-grid > .kro-card > .tile-spark { grid-row: 5; }
  .kro-grid > .kro-card > .kro-badges { grid-row: 6; }
  /* subgrid의 row-gap은 카드 정렬을 위해 0이다. 그래서 가격 다음에 처음 오는
     등락·기준 시각 줄에만 내부 여백을 주어 큰 숫자에 붙지 않게 한다. */
  .kro-grid > .kro-card > .kro-price + .kro-vs,
  .kro-grid > .kro-card > .kro-price + .kro-vs-ref {
    padding-top: var(--sp-1h);
  }
  /* **자동 여백이 못 박은 자리를 이긴다.**
   *
   * `.kro-meta`는 기본 규칙에서 `margin-top: auto`다 — subgrid가 없던 때 표를
   * 카드 바닥으로 밀어 두던 장치다. 그런데 자동 여백은 `align-self`보다 세서,
   * 줄을 7번에 못 박아 놓아도 상자가 트랙 **바닥**에 붙는다. 트랙 높이는 그
   * 줄에서 가장 큰 표가 정하므로, 표가 짧은 카드일수록 더 아래에서 시작한다.
   *
   * 실측(`/crypto` 390px, 솔라나 ↔ 리플): 트랙 153px 안에서 표 144px ↔ 126px,
   * 시작 y가 2324 ↔ 2342 — **18px**. 자가 짚은 그 값이다.
   *
   * 트랙이 이미 자리를 정하므로 여기서는 밀 이유가 없다. */

  /* ── 표도 줄을 나눠 쓴다 ────────────────────────────────────────────────
   *
   * 상자를 트랙에 앉히고 나니 어긋남이 **그 안**으로 옮겨 갔다(자: `[3]` →
   * `[3][2]`·`[3][3]`, 각 18px). 앞 줄의 이름표가 한쪽 카드에서만 두 줄로
   * 접히면 그 아래 줄이 통째로 밀린다 — 오늘 `.usm-changes`·`.metric-hints`
   * 에서 만난 것과 같은 종류다. 카드가 밖에서 하는 일을 한 단 안에서 또 한다.
   *
   * 네 줄인 이유: `.kro-meta`를 만드는 곳은 김프 카드 한 군데뿐이고
   * (monitor.js `renderCryptoKimchi`), 늘 네 줄이다 — 업비트 24시간 · 오라클 ·
   * 공식환율 프리미엄 · 거래대금. 조건부 자식이 없으니 셋 다 세고 박을 수 있다.
   *
   * `#ckim-grid`로 좁힌다. 같은 `.kro-grid`라도 `/kr`·원유·테이프 격자에는
   * 이 표가 없어서 트랙 셋을 괜히 얻는다. */
  /* 김프 격자만 자식이 **넷으로 고정**이라(머리 · 값 · 등락 · 표) 전부 박아도
   * 빈 트랙이 안 생긴다. 자리를 박아야 하는 이유는 아래 표에 있다. */
  #ckim-grid > .kro-card { grid-row: span 10; }
  #ckim-grid > .kro-card > header { grid-row: 1; }
  #ckim-grid > .kro-card > .kro-price { grid-row: 2; }
  #ckim-grid > .kro-card > .kro-vs { grid-row: 4; }
  #ckim-grid > .kro-card > .kro-badges { grid-row: 6; }
  #ckim-grid > .kro-card > .kro-meta {
    grid-row: 7 / span 4; align-content: start;
    /* 자동 여백은 `align-self`보다 세서, 줄을 못 박아도 상자를 트랙 **바닥**에
       붙인다. 표가 짧은 카드일수록 더 아래에서 시작했다(실측 390px, 솔라나 ↔
       리플: 트랙 153px 안에서 144 ↔ 126, 시작 y 2324 ↔ 2342 — 18px). */
    margin-top: 0;
    display: grid; grid-template-rows: subgrid; row-gap: 3px;
  }
  #ckim-grid .kro-meta > div:nth-child(1) { grid-row: 1; }
  #ckim-grid .kro-meta > div:nth-child(2) { grid-row: 2; }
  #ckim-grid .kro-meta > div:nth-child(3) { grid-row: 3; }
  #ckim-grid .kro-meta > div:nth-child(4) { grid-row: 4; }
}

/* 카드 제목은 이 목록에서 **되돌린다** (운영자 제보 2026-09-07: "종목명이
   2줄씩 차지하고 로고가 따로노는 느낌"— /kr·반도체·암호화폐 셋 다).

   `inline-flex`는 원자적이다. 줄 안에서 쪼개지지 않으므로, 이름이 로고 옆에
   안 들어가면 **통째로 다음 줄로 내려간다** — 그러면 첫 줄에 로고만 남는다.
   실측 라이브 `/crypto` 390px: 로고 y=817, `하이퍼리퀴드 (HYPE)` 링크 y=836.2.
   이름이 두 줄이 되는 것이 문제가 아니라, 이름이 로고를 두고 떠나는 것이
   문제였다.

   인라인으로 돌아오면 이름은 로고 옆에서 시작해 아래로 흐른다 — 로고가
   이름을 잃지 않는다.

   **행간이 표적을 키우지는 않는다**(2026-09-08 정정). 여기 "링크의 히트 영역은
   줄 상자이므로 15 × 1.65 = 24.8px로 AA 바닥 위에 선다"고 적혀 있었는데,
   `elementFromPoint`로 위아래를 한 픽셀씩 밀어 보니 **16px에서 끝났다**
   (`a.kro-detail`, 폰 390). 비대체 인라인 요소의 히트 영역은 글자 상자이고
   반 행간은 거기 안 들어간다.

   그래도 이 링크의 표적은 24px을 넘는다 — 이유가 다르다. `.kro-hub-link::after`
   가 카드를 통째로 덮어(`inset: 0`) **카드 전체가 눌린다.** 그것이 AA를 지키는
   실제 장치다. 그 덮개를 걷을 일이 생기면 표적 크기를 따로 마련해야 한다. */
.kro-detail, .kro-card h3 a, .crypto-card h3 a {
  display: inline; line-height: 1.65;
}

/* 탭은 폭이 모자랐다(홈 31px). 내비가 가로로 흐르므로 실제 폭을 넓히는 편이
 * 싸다 — 히트 영역만 넓히는 수법은 **옆 탭과 겹쳐서 안 먹는다**(실측:
 * 중심에서 좌우 21px 지점을 찍으면 옆 탭의 영역이 위에 있다). */
.view-tab { min-width: 44px; justify-content: center; }

/* 홀로 서 있는 아이콘 컨트롤만 히트 영역을 44×44로 넓힌다. 보이는 크기는
 * 그대로라 마스트헤드가 안 자란다 — 마스트헤드를 키우면 첫 화면의 값이
 * 그만큼 밀려난다.
 *
 * 왜 이것들만인가: 가짜 요소로 넓히는 수법은 **주변에 빈 자리가 있을 때만**
 * 듣는다. 붙어 있는 것끼리(탭, 모드 스위치) 서로 넓히면 나중에 그려진 쪽이
 * 앞을 가려 조용히 실패한다 — 재서 확인했다. 그래서 브랜드·탭에는 안 쓴다.
 * `.cal-step`(‹ ›)에도 붙여 봤지만 네 방향 전부 안 먹어서(무엇이 위를 덮는지
 * 더 파지 않았다) 뺐다 — 30×30이라 AA 기준(24)은 이미 넘는다. */
.icon-button { position: relative; }
.icon-button::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: max(100%, 44px);
  transform: translate(-50%, -50%);
}

/* ======================================================================
 * 9. 편집 — 에디토리얼 절제 (DESIGN.md §5)
 *
 * 콘솔 페이지는 20~47장짜리 세로 스크롤인데 길잡이가 16장 중 2장뿐이었고,
 * 섹션이 전부 같은 모양으로 쌓여 있었다. 세 방향을 만들어 재 본 결과 —
 *
 *   손대기 전       18,869px   정직성 문장 5/5   길잡이 없음
 *   고밀도 터미널   15,844px   정직성 문장 0/5 ← 지워서 벌었다
 *   에디토리얼       7,881px   정직성 문장 5/5   길잡이 있음
 *
 * 접힌 것은 지워진 것이 아니다. 본문은 DOM에 그대로 두고 감추기만 한다.
 * ================================================================== */

/* --- 등급 -------------------------------------------------------------
 * 주력은 페이지가 `data-rank="lead"`로 선언한다. 나머지는 참고다. */
/* 등급은 **선이 아니라 공백과 무게**로 말한다.
 *
 * 처음에는 주력 섹션 위에 `2px solid var(--ink)` 가로선을 그었다. 다크 화면에서
 * `--ink`(#eff3f7)는 값보다 밝아서, 화면에서 가장 센 요소가 구분선이 됐다 —
 * 운영자 지적(2026-08-30): "너무 튀고 올드한 느낌". 맞다. Trust 60 · Calm 25가
 * 방향인데 구분선이 데이터보다 크게 말하면 안 된다.
 *
 * 그래서 주력에는 **선을 긋지 않고 공백을 준다**(--sp-7). 조용한 쪽이 오히려
 * 위계가 높다. 참고 섹션만 잔선(--line) 하나로 묶어 흐름을 만든다. */
.console-section[data-rank="lead"] { margin-top: var(--sp-7); }
.console-section[data-rank="lead"] > header { padding-top: 0; }
/* 참고 섹션은 잔선 하나로 묶는다. 안쪽은 넉넉히 — 줄이 위아래를 두르고
 * 있는데 안이 좁으면 갇힌 것처럼 읽힌다(운영자 2026-09-03: "답답해 보여").
 * 제목의 밝기는 낮추지 않는다: 등급은 밝기가 아니라 여백이 말한다. */
.console-section:not([data-rank="lead"]) > header {
  border-top: 1px solid var(--line); padding-top: var(--sp-5);
}

/* --- 접기 -------------------------------------------------------------
 * 제목·리드·정직성 배지만 남긴다. 고지는 접기의 대상이 아니다. */
/* **모드에 걸지 않는다.** 처음에는 쉬움에서 접었는데, 그건 설계 의도를
   거꾸로 구현한 것이었다 — 쉬움은 "데이터를 덜 준다"가 아니라 "데이터는 다
   주되 이해를 돕는다"다(운영자, 2026-08-30). 초심자에게서 값을 빼앗는 접기는
   손해로 읽힌다.

   그래서 접기는 **모드와 무관한 사용자 조작**이다. 기본은 펼침 — 아무도
   손해 보지 않는다. 긴 화면은 길잡이 레일이 다루고, 접기는 다 본 섹션을
   치우고 싶은 사람의 선택지로 남는다. 접은 상태는 페이지마다 기억한다. */
/* 접기 버튼은 뺐다 (2026-08-30).
 *
 * #42에서 넣고 #44에서 모드와 떼어 "다 본 섹션을 치우고 싶은 사람의 선택지"로
 * 남겼는데, 그 #44의 근거가 이미 이렇게 적고 있었다 — **긴 화면은 길잡이
 * 레일이 다룬다, 접기가 아니라.** 남은 버튼은 제 몫을 레일에 넘기고도
 * 섹션마다 서 있는 44px 알약이었다(실측: 28개, /crypto는 문서의 4.7%).
 *
 * 운영자가 "접기 펼치기 없애기로 한 거 아니었나?"라고 물은 것이 답이다.
 * 설계를 쓴 사람이 없앤 걸로 기억한다면, 그 컨트롤은 이미 아무 일도 하고
 * 있지 않았다. 길이는 레일이, 이해는 용어 줄과 설명이 맡는다. */

.section-rail {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 500;
  display: flex; gap: 2px;
  padding: var(--sp-1) var(--sp-2) calc(var(--sp-1) + env(safe-area-inset-bottom));
  overflow-x: auto; scrollbar-width: none;
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  backdrop-filter: blur(10px); border-top: 1px solid var(--line);
}
.section-rail::-webkit-scrollbar { display: none; }
/* 제목이 길면 CSS가 자른다 — 말줄임표까지 붙여서.
 * 예전에는 JS가 `name.slice(0, 16)`으로 잘랐다. 그러면 "한국 기업 공시 속보
 * (주요사"처럼 말 중간에서 끊기면서 **잘렸다는 표시가 없다**(실측 2026-08-30,
 * /kr에서 3개). 온전한 제목은 `aria-label`에 남아 낭독기에 그대로 간다. */
.section-rail a {
  flex: 0 0 auto; display: inline-flex; align-items: center;
  min-height: 34px; padding: 0 var(--sp-3); border-radius: var(--r-pill);
  max-width: 18ch; text-decoration: none;
  color: var(--ink-2); font: 600 var(--fs-xs)/1 var(--sans);
}
/* 말줄임표는 **안쪽 span**이 단다. `text-overflow`는 블록 컨테이너의 인라인
 * 내용에만 걸리는데 칩은 `inline-flex`라, 링크에 직접 걸면 글자는 잘리고
 * 점 세 개는 안 붙는다(실측 2026-08-30: "한국 기업 공시 속보 (2"에서 끝났다).
 * 안쪽 상자가 잘리면 링크의 좌우 여백도 그대로 남는다. */
.section-rail a > span {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.section-rail a:hover { color: var(--ink); background: var(--panel-2); }
.section-rail a.is-here { background: var(--accent); color: var(--accent-ink); }
/* 길잡이가 말하는 것은 **하나뿐이다: 지금 어디인가.**
 *
 * 한동안 편집 등급(lead/aside)을 칩에도 비췄다. 처음엔 `opacity: .6`으로,
 * 지적을 받고 색 한 단으로. 운영자가 다시 물었다 — "굳이 흐리게 나눌 필요가
 * 있어? 무슨 효과가 있는데?" 재 보니 효과가 거의 없었다.
 *
 *   /kr      LLLAAAAAAA   ← lead가 전부 앞
 *   /crypto  LLLAAAAAAAA  ← 전부 앞
 *   /        LLLLLA       ← 6개 중 5개가 lead, 구별이 사라짐
 *   /us      LAALAALAA    ← 여기서만 섞인다
 *   /bio     LLAALAA
 *
 * 다섯 중 셋은 **칩 순서가 이미 말하고 있었다.** 홈은 등급이 사실상 없다.
 * 섞이는 두 페이지에서도, 목적지를 고르는 순간에 "이건 부차 섹션"이라는
 * 정보로 할 수 있는 일이 없다 — 갈지 말지는 이름이 정한다.
 *
 * 값은 그대로인데 값을 치른 쪽은 컸다: AA 미달(3.01)을 만들었고, 절반이
 * 흐린 막대는 "여긴 못 간다"로 읽혔다. 등급이 뜻을 갖는 자리는 본문의 간격과
 * 머리말이다(DESIGN.md §5) — 이동 수단이 아니다. 칩은 전부 같은 밝기다. */
/* 레일이 가리는 만큼 본문 아래를 비운다. 레일 자신은 안전 영역만큼 더
   두꺼워지므로(홈 인디케이터가 있는 기기), 같은 식을 여기서도 쓴다 — 52px로
   못 박아 두면 그런 기기에서 마지막 줄이 레일 뒤에 숨는다. */
/* 띠는 두 겹이다 — `.section-rail` 43px 위에 `.view-switch` 53px, 합 95.3px(실측
   2026-09-06, 412px). 이 기본 규칙은 52px만 비워 두고 있어서 한 겹치를 놓쳤다.
   폰에서는 아래 560px 블록의 `--pagebar-h + 52`(=104px)가 이겨서 실제로는
   모자란 적이 없었지만, 그 블록이 안 걸리는 폭에서는 마지막 줄이 띠 뒤로 들어간다.
   두 값이 같은 사실을 말하도록 기본 쪽도 두 겹으로 맞춘다.

   덧붙여, 이 여백은 **문서 끝**만 지킨다. 스크롤 도중 띠가 값을 덮는 것은
   고정 띠의 성질이라 여백으로는 못 고친다 — 첫 화면에서 보드 3행이 반만 보이는
   문제는 크롬 24.1%를 줄이는 판단이지 이 줄의 일이 아니다. */
body:has(.section-rail) { padding-bottom: calc(96px + var(--sp-4) + env(safe-area-inset-bottom)); }

@media (min-width: 1081px) {
  /* 넓은 화면은 한 화면에 더 담기므로 레일이 덜 필요하다. 자리만 덜 차지하게. */
  .section-rail { padding-inline: max(var(--sp-4), calc((100vw - 1320px) / 2)); }
}

/* --- 히트맵 활성화 막 · 4판 (2026-08-31) --------------------------------
 * 운영자: "클릭하여 조작하기 다시 넣어줘, 단 글자가 히트맵을 가리지 않게."
 * 1판과 다른 점 — 막은 완전 투명(디밍·문구 없음)이고 안내는 맵 **밖**의
 * 캡션 줄(.tv-caption)이 한다. hover 피드백은 1px 안쪽 링 — 면을 덮지 않는다. */
/* 위젯의 **하얀 네 모서리**가 알약을 뚫고 나오던 것 (운영자 제보 2026-09-07:
   "s&p500 히트맵도 박스뚫고 꼭짓점이 뾰족한 하얀색임").

   테를 그리는 것은 `.tv-shield`(`border-radius: var(--r-md)`)인데, 정작 위젯을
   담은 상자에는 반경이 없었다. `overflow: hidden`은 이미 걸려 있었지만 자를
   모양이 사각형이라 아무것도 안 잘렸다 — 자르고는 있는데 곡선을 모르는 상태.
   같은 반경을 준다.

   2026-09-06에 이 흰 점을 위젯 설정(`isTransparent`)으로 고치려다 실패했다.
   교차 출처 iframe 안은 우리 CSS가 못 닿는다 — 닿는 것은 **우리 쪽 상자**뿐이고,
   그 상자가 자르면 된다. */
.tv-panel .tradingview-host { position: relative; border-radius: var(--r-md); }
.tv-panel .tradingview-host:not(.tv-active) .tradingview-widget-container { pointer-events: none; }
/* **조작 중에는 제스처를 위젯이 갖는다 — 터치는 휠과 다른 문제다.**
 *
 * 휠은 `isZoomEnabled: false`로 정리했다(#247). 터치는 그 뒤에 남아 있었다:
 * 막을 열고 맵을 끌면 위젯이 팬을 하면서 **페이지도 같이 스크롤된다**
 * (운영자 제보 2026-09-08, 폰). 아이프레임이 `preventDefault`를 하지 않으니
 * 브라우저가 기본 동작을 함께 수행한다. `pointer-events`는 누가 이벤트를
 * 받는지를 정할 뿐, 브라우저의 기본 스크롤을 막지 못한다.
 *
 * **잠겨 있을 때는 그대로 둔다** — 그때 페이지가 스크롤되는 것이 막의 존재
 * 이유다. 조작 중일 때만 건다. 나가는 길은 이미 화면에 있다(캡션: "밖을
 * 누르면 잠금", `pointerdown` 바깥 클릭으로 release).
 *
 * 아이프레임에도 같이 건다 — 터치는 그 안에서 시작하므로 바깥 상자에만
 * 걸면 브라우저에 따라 안 먹는다. */
.tv-panel .tradingview-host.tv-active,
.tv-panel .tradingview-host.tv-active iframe { touch-action: none; }
.tv-shield {
  position: absolute; inset: 0; z-index: 2;
  border: 0; border-radius: var(--r-md); background: transparent; padding: 0;
  cursor: pointer;
}
.tv-shield:focus-visible { box-shadow: inset 0 0 0 1px var(--accent); }
@media (hover: hover) {
  .tv-shield:hover { box-shadow: inset 0 0 0 1px var(--accent); }
}
.tv-shield:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* 잠금 상태가 곧 행동 유도다 — 액센트로 세우고, 조작 중에는
 * 상태 표시로 내려앉는다(운영자: "지금 발견하기 어려워", 2026-08-31).
 * 색과 굵기만 써서 차트 위에서도 또렷하게 읽히게 한다. */
.tv-caption {
  margin: 0; cursor: pointer;
  color: var(--accent); font-size: var(--fs-sm); font-weight: 650;
}
.tv-caption.is-active {
  color: var(--ink-2); font-weight: 500;
}

/* --- 이어보기 칩 (3차 감사 W-4, 2026-08-31) ----------------------------
 * 재방문은 항상 홈 0px에서 시작한다. 마지막으로 본 섹션 하나를 홈 머리
 * 위에 되돌아가는 칩으로 둔다. console.js setupResume()가 만들고,
 * localStorage에만 남는다 — 서버는 모른다. */
.resume-chip {
  display: inline-flex; align-items: center; gap: var(--sp-1h);
  margin: 0 0 var(--sp-3); padding: var(--sp-1h) var(--sp-3);
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--panel); color: var(--ink-2);
  font: 650 var(--fs-xs)/1 var(--num); font-variant-numeric: tabular-nums;
  text-decoration: none; min-height: 24px;
}
.resume-chip b { color: var(--accent); font-weight: 650; }
.resume-chip:hover { border-color: var(--line-strong); color: var(--ink); }

/* --- 오늘 공시 요약 진입 (3차 감사 W-2, 2026-08-31) ---------------------
 * 홈 보드 바로 아래. monitor.js renderDisclosureBrief()가 피드에서 오늘
 * 것만 세어 세운다 — 0건이면 서지 않는다. */
.disclosure-brief {
  display: flex; align-items: center; gap: var(--sp-2);
  /* 아래 여백이 0이라 다음 판과 **테두리끼리 맞닿아** 있었다(실측: 두 상자
     사이 0.0px). 카드 둘이 붙으면 한 덩어리로 읽혀 "오늘 공시"가 아래 피드의
     머리처럼 보인다 — 운영자 지적 2026-09-07. 위아래를 같은 값으로 준다. */
  margin: var(--sp-3) 0; padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--panel); text-decoration: none;
}
.disclosure-brief b { flex: none; color: var(--ink); font: 650 var(--fs-md)/1.2 var(--num); font-variant-numeric: tabular-nums; }
.disclosure-brief span { min-width: 0; color: var(--ink-3); font: 500 var(--fs-xs)/1.4 var(--num); font-variant-numeric: tabular-nums; }
.disclosure-brief i { margin-left: auto; color: var(--accent); font-style: normal; }
.disclosure-brief:hover { border-color: var(--line-strong); }
.disclosure-brief:active { background: var(--panel-2); }

/* --- 눌림 (2026-08-31, 모션 트랙) --------------------------------------
 * 폰에는 hover가 없다. 여태 모든 마이크로 피드백이 hover에 걸려 있어서
 * 손가락으로 누르는 동안 화면이 아무 반응도 하지 않았다(:active 규칙 0개
 * 실측) — 토스가 pressed를 버튼 상태 계약에 명문화하는 이유다.
 * 누르는 동안만 4% 가라앉는다. transform이라 리플로우가 없고, 전환을 걸지
 * 않아 즉각 반응한다 — 즉각적인 상태 변화라 reduced-motion과도 무관하다.
 * 넓은 행(summary)은 가라앉는 대신 면을 한 단 올린다 — 큰 상자가 줄어드는
 * 것은 눌림이 아니라 오류처럼 읽힌다. monitor.css 전용 컨트롤 셋의 눌림은
 * 그 파일 끝에 있다(겹침 기준선 — test_stylesheet_split). */
.view-tab:active, .icon-button:active, .refresh-button:active,
.feed-filter button:active, .news-filter button:active,
.cal-step:active, .section-rail a:active, .brand:active,
.resume-chip:active {
  transform: scale(.96);
}
.disclose > summary:active { background: var(--panel-2); }

/* --- 페이지 탭을 하단으로 (3차 감사 W-6, 운영자 승인 2026-08-31) --------
 * 페이지 전환(상단 탭)과 섹션 점프(하단 레일)가 화면의 반대 극이었다 —
 * 한 손 조작에서 가장 자주 쓰는 컨트롤이 엄지에서 가장 멀었다. 폰에서는
 * 탭 줄을 하단 고정 바로 내린다. **같은 요소를 CSS로만 옮긴다** — 마크업·
 * i18n·활성 상태는 그대로고, 데스크톱(>760px)은 상단 그대로다.
 * 층 구조(아래에서 위로): 페이지 탭 바 → 섹션 레일 → 본문.
 * 안전영역(제스처 바) 몫은 맨 아래 층인 탭 바가 낸다. */
/* 갱신 2026-09-06 — **폰에는 고정 띠가 하나뿐이다.**
 *
 * 운영자 제보: "네비게이션 바도 2개야. 스크롤하면 하나가 내려가긴 하지만."
 * 그 "내려간다"가 이 절이 지고 있던 보상이었다 — 두 층을 쌓아 놓고 읽는
 * 동안 한 층을 감추는 것으로 무마했다. 감춰야 무마되는 층은 처음부터
 * 한 층 많은 것이다.
 *
 * 실측(412·390·360px, 이 판 직전):
 *   · 레일 아래끝 792 · 탭 바 위끝 791 → 두 띠가 **1px 겹쳐** 있었다
 *     (레일의 `bottom`은 52px인데 탭 바 실제 높이는 53px = 52 + 위 테두리).
 *   · `body { padding-bottom: 104px }` — 844px 화면의 **12.3%**를 고정
 *     크롬이 먹었다.
 *   · 레일 내용 폭 417px > 창 345px(360px 화면) → 6칸 중 마지막은 늘 화면 밖.
 *
 * 그래서 폰에서는 레일을 내린다. 데스크톱(>760px)은 그대로 — 거기서는 탭이
 * 마스트헤드에 있으므로 레일이 유일한 고정 띠이고, 겹칠 것이 없다.
 * `is-away`(읽는 동안 접기)는 함께 걷었다. 겹칠 층이 없으면 접을 이유도
 * 없다.
 *
 * 갱신 2026-09-07 — **대신 세웠던 구역 칩·시트도 걷었다**(운영자: "구역으로
 * 바로가지는거 그냥 없애자"). 구역 제목 줄마다 서 있던 `구역 ⌄`는 이 화면들이
 * 위에서 아래로 읽히는 글이라는 사실과 맞지 않았다 — 읽는 자리마다 "어디로
 * 갈까"를 묻는 컨트롤이 서 있었다. 폰의 이동은 하단 탭 바 하나가 맡는다. */
@media (max-width: 760px) {
  .section-rail { display: none; }
  /* monitor.css의 같은 규칙과 **같은 식**이어야 한다. console.css가 뒤에
   * 실려 이기므로, 한쪽만 고치면 레일이 있는 페이지에서만 마지막 줄이
   * 알약 밑으로 들어간다(실측: 여백 62 대 알약이 먹는 자리 86). */
  body:has(.section-rail) {
    padding-bottom: calc(
      var(--pagebar-h) + var(--pagebar-inset) * 2 + env(safe-area-inset-bottom, 0px)
    );
  }
}

/* 표를 그림으로 내보내는 버튼. 패널 꼬리의 출처·부인 옆에 선다 — 이 표가
 * 무엇이고 어디서 왔는지 읽은 자리에서 퍼가게 한다. */
.share-host { margin-left: auto; }
.share-shot {
  padding: var(--sp-1h) var(--sp-3); border: 1px solid var(--line-strong); border-radius: var(--r-pill);
  background: var(--panel-2); color: var(--ink-2);
  font: 650 var(--fs-xs)/1 var(--sans); cursor: pointer;
}
.share-shot:hover { color: var(--ink); border-color: var(--accent); }
.share-shot[disabled] { opacity: .5; cursor: default; }

/* --- 24시간 열려 있는 시장 (`/markets`) ---------------------------------
 * 표가 일곱 묶음이고 100줄이 넘는다. 종목 이름과 티커를 한 칸에 붙여 가로를
 * 아끼고(폰에서 네 열이 들어가야 한다), 얇은 시장 표시는 이름 옆에 작게 —
 * 지우지 않고 말해 주는 것이 이 화면의 규칙이라서. */
.mkt-table { width: 100%; }
.mkt-table th[scope="row"] { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1h); }
.mkt-name { font-weight: 650; }
.mkt-ticker {
  color: var(--ink-3); font: 500 var(--fs-xs)/1 var(--num);
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
}
.mkt-thin {
  padding: 1px var(--sp-1h); border-radius: var(--r-pill);
  background: var(--panel-2); color: var(--ink-3);
  font: 600 var(--fs-xs)/1.5 var(--sans);
}
.mkt-table { width: 100%; }
/* 등락 색은 이 표에도 붙인다 — `.up`/`.down`은 컴포넌트마다 따로 선언돼 있다. */
.mkt-table .up { color: var(--up); }
.mkt-table .down { color: var(--down); }
/* 추이선 칸. 값이 없으면 빈 칸이고 표는 그대로 선다.
 * 폰에서는 좁힌다 — 실측(412px): 이 칸이 112px로 가장 넓어 거래대금이 표
 * 밖으로 밀렸다. 선은 모양만 읽히면 되므로 폭을 양보한다. */
.mkt-spark { width: 96px; padding-top: var(--sp-1); padding-bottom: var(--sp-1); }
.mkt-spark svg { display: block; width: 100%; height: auto; }
@media (max-width: 560px) { .mkt-spark { width: 56px; } }
.mkt-spark svg.up { color: var(--up); }
.mkt-spark svg.down { color: var(--down); }
.markets-summary b { color: var(--ink); }
/* 묶음이 일곱이라 제목 옆의 개수·거래대금이 길잡이가 된다. */
.markets-page .console-section > header .sec-note { font-variant-numeric: tabular-nums; }

/* ======================================================================
   섹션 등급 — lead · standard · archive (2026-09-03)

   전부가 주인공이면 주인공이 없다. 홈은 여섯 장 중 다섯이 `lead`였고,
   `data-rank`는 저장소 전체에 `lead` 한 값뿐이었다.

   archive는 새로 만들지 않는다 — `.disclose-deep` + `data-mode-open`이
   이미 그 일을 하고 있었고(`console.js` applyMode), /us는 그 덕에 쉬움이
   전문가의 57.5%였다. 없던 곳(/kr·홈)에 같은 서랍을 가져다 썼다.
   ====================================================================== */

/* lead는 지금 그대로가 기준이다. standard는 한 단 조용하게 — **위 여백**으로만
 * 낮춘다.
 *
 * 처음에는 제목을 --fs-lg + --ink-2로 함께 낮췄다. 운영자 판정(2026-09-03):
 * 작고 어두운 제목이 위아래 잔선 사이에 갇혀 화면이 답답해 보인다. 맞다 —
 * 등급을 두 축(크기·밝기)으로 동시에 말하면 "조용함"이 아니라 "흐림"이 된다.
 * 제목은 lead와 같은 크기·밝기로 두고, 차이는 위 여백에만 남긴다. */
.console-section[data-rank="standard"] { margin-top: var(--sp-6); }

/* 폰 하단 바의 비례 분배를 **되돌린다** (2026-09-06).
 *
 * 2026-09-03에 여기 `.view-tab { flex: 1 1 auto }`가 들어왔다. 근거는
 * "`/score`가 여섯 번째 탭으로 들어와 360px에서 글자가 칸을 넘는다"였다.
 * 그 여섯째 탭은 지금 없다 — 20장 전부 정확히 다섯이다(실측 2026-09-06,
 * `grep -c view-tab app/static/*.html`). 근거가 사라진 규칙만 남아 있었다.
 *
 * 값은 그대로 치르고 있었다. 비례 분배는 칸 너비를 글자 길이에 묶으므로
 * 눈금이 사라진다 — 실측(412px): 홈 48.5 · 한국 60.5 · 미국·글로벌 99.3 ·
 * 암호화폐 84.3 · 종목 검색 88.5. 최대가 최소의 **2.05배**이고, 첫 칸은
 * x=0에 붙어 라벨이 본문 좌측 레일(16px)과 10px 어긋났다. 운영자가 폰
 * 스크린샷으로 "픽셀이랑 align 안 맞는다"고 짚은 자리가 여기다.
 *
 * 균등으로 돌아가되 글자가 넘치지 않게 하는 것은 **이름 쪽**에서 푼다 —
 * 하단 바는 짧은 이름을 쓰고(`.view-tab-name.is-short`) 뜻은 아이콘이
 * 함께 진다. 12px 바닥은 그대로다.
 *
 * 2026-09-11 — 여섯째 탭(`/league`, 운영자 판정)이 들어왔다가 같은 날 다시
 * 다섯으로 줄였다. 운영자: "무조건 5개로 유지해야해" · "pc랑 모바일 모두
 * 종목검색이 제일 오른쪽에 있어야해". 뺀 것은 코인이다 — 7일 조회(9/5~11)가
 * 홈 2,879 · 한국 887 · 글로벌 594 · 코인 202 · 검색 42 · 리그 3(개설 첫날).
 * 검색은 맨 오른쪽에 두라는 칸이고 리그는 막 올린 칸이라, 뺄 수 있는 칸이
 * 코인뿐이었다. 코인은 홈 "더 깊이 보기" 카드로 간다.
 * 순서: 홈 · 한국 · 글로벌 · AI 리그 · 종목 검색 (tests/frontend/test_tab_bar.py). */

/* ======================================================================
   첫 화면 — 값이 가운데, 사건이 옆 (2026-09-03, 운영자 요청)

   처음엔 전폭 밴드로 얹었다가 값 카드 6장이 화면 밖으로 밀렸다. 운영자가
   그것을 짚었다 — "이럴거면 그냥 SK하이닉스, 삼성 가격 카드 보여주는 훨씬
   낫지." 원래 요청도 "맨위 **사이드**"였고, 나는 사이드가 아니라 머리에
   얹었던 것이다.

     지금 시장 (h1)
     [ 어제 장 · 칩 줄 · 한 문장 ]                    ← 한 줄 띠, 높이 고정
     [ 값 카드 6장            | 지금 이슈 ]           ← 값이 넓고, 사건이 옆
   ====================================================================== */

/* ======================================================================
   어제 장 — 한 줄 띠에서 **읽는 자막**으로 (2026-09-03 고도화)

   처음엔 칩 줄 옆에 문장을 끼워 넣고 한 줄로 잘랐다. 셋이 틀렸다 —
   눌러야 문장이 다 보였고(자막인데 클릭을 요구했다), 12px 회색이라
   부각이 안 됐고, 칩 뒤에서 시작해 "어제 장"과 세로선이 어긋났다.

   다시: 줄을 **쌓고** 왼쪽을 한 선으로 맞춘다. 문장은 자르지 않고 본문
   크기로 올린다. 이 띠에서 숫자는 칩이 말하고 **문장이 주인공**이다 —
   그러라고 만든 레인이다(어제 장 한 문장).
   ====================================================================== */

.pulse-strip {
  display: block;
  margin: var(--sp-3) 0 var(--sp-4);
  padding: var(--sp-3) 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.pulse-strip[hidden] { display: none; }

.pulse-strip > header {
  display: flex; align-items: baseline; gap: var(--sp-2);
  margin-bottom: var(--sp-2);
}
.pulse-strip > header h2 {
  margin: 0; font-size: var(--fs-sm); font-weight: 700; color: var(--ink-2);
  letter-spacing: -0.01em; white-space: nowrap;
}
.pulse-when { color: var(--ink-3); font-size: var(--fs-xs); white-space: nowrap; }

.pulse-strip .pulse-foot {
  margin: var(--sp-2) 0 0; padding: 0; border: 0;
  color: var(--ink-3); font-size: var(--fs-xs);
}

.mood-list { margin: 0; padding: 0; list-style: none; }
/* 쌓는다. 모든 줄의 왼쪽이 "어제 장"과 같은 선에서 시작한다. */
.mood-row { display: flex; flex-direction: column; gap: var(--sp-2); }

/* 칩 줄은 한 줄로 흐른다 — 좁아지면 가로로 스크롤할 뿐 줄을 늘리지 않는다. */
.pulse-chips {
  display: flex; gap: var(--sp-1h);
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.pulse-chips::-webkit-scrollbar { display: none; }
.pulse-chip {
  display: inline-flex; align-items: baseline; gap: var(--sp-1);
  /* 12px 글자에 세로 2px은 글자가 테두리에 붙는다. 손가락 자리 24px 바닥과도
     맞물린다 — 4px씩이면 12 + 8 + 테두리 2 = 22, 여기에 줄 상자가 더해져 24를
     넘긴다(검출기 cramped-padding, 실측 홈 5곳). */
  padding: 4px var(--sp-2);
  background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--r-pill);
  color: var(--ink-2); font-size: var(--fs-xs); white-space: nowrap;
}
.pulse-pct { font-variant-numeric: tabular-nums; font-weight: 700; }
.pulse-pct.up { color: var(--up); }
.pulse-pct.down { color: var(--down); }
.pulse-pct.flat { color: var(--ink-3); }

/* 문장 — 자르지 않는다. 본문 크기, 본문 색.
 * 읽으라고 만든 줄이라 훑는 줄과 크기가 같으면 안 된다. */
.pulse-say {
  max-width: 88ch;
  color: var(--ink); font-size: var(--fs-md); line-height: 1.6;
  letter-spacing: -0.005em;
}
.pulse-say p { margin: 0; }

.pulse-more { align-self: flex-start; }
.pulse-more > summary { padding: 0; color: var(--accent); font-size: var(--fs-xs); cursor: pointer; }
.pulse-more[open] > summary { margin-bottom: var(--sp-2); }
.pulse-more-body { padding-top: var(--sp-1h); }

/* --- 펼침 안의 표·헤드라인 (origin/main 규칙을 되살림) ------------------ */
.mood-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-1) var(--sp-2); }
.mood-date { color: var(--ink); font: 700 var(--fs-sm)/1.5 var(--num); font-variant-numeric: tabular-nums; letter-spacing: .02em; }
.mood-coverage { color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.5; }
/* 표: 시장 라벨은 왼쪽 열에 세우고 칸은 오른쪽에서 줄바꿈한다 — 칸이 세 줄로 꺾여도(360px 미국 7칸)
 * "미국"이 첫 칸 사이에 끼지 않는다. 칸은 "라벨 ±%"가 붙은 한 덩어리라 라벨과 값이 갈리지 않는다. */
.mood-figures { margin-top: var(--sp-2); display: grid; row-gap: var(--sp-1h); }
.mood-figure-row { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: var(--sp-3); align-items: baseline; }
.mood-figure-market {
  min-width: 2.2em; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.5; font-weight: 600; letter-spacing: .04em;
}
.mood-figure-cells { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-3); }
.mood-figure { display: inline-flex; align-items: baseline; gap: var(--sp-1); white-space: nowrap; }
.mood-figure-label { color: var(--ink-2); font-size: var(--fs-xs); line-height: 1.5; }
.mood-figure-pct { font: 600 var(--fs-sm)/1.5 var(--num); font-variant-numeric: tabular-nums; }
.mood-figure-pct.up, .mood-pct.up { color: var(--up); }
.mood-figure-pct.down, .mood-pct.down { color: var(--down); }
.mood-figure-pct.flat { color: var(--ink-3); }
.mood-sentence {
  margin: var(--sp-2) 0 0; color: var(--ink);
  font-size: var(--fs-lg); line-height: 1.55; font-weight: 500; text-wrap: pretty;
}
/* 문장은 **흐른다** (운영자 2026-09-07: "오른쪽이 공백이 많이 남네").
 *
 * 마침표마다 줄을 세우면 문장 끝마다 오른쪽이 통째로 빈다. 카드가 536 →
 * 496px로 좁아진 지금은 그 손해가 크다 — 실측 첫 줄이 상자의 절반만 쓰고
 * 끊겼다. 이어 붙이면 같은 줄 수에 상자를 채운다. 마침표 뒤 사이 한 칸은
 * 쪼갤 때 없어졌으므로 여기서 되돌린다. */
.mood-line { display: inline; }
.mood-line + .mood-line::before { content: " "; }
.mood-pct { font-variant-numeric: tabular-nums; font-weight: 600; }
.mood-facts { margin-top: var(--sp-2); }
.mood-fact-list { margin: 0; padding-left: 1.1em; color: var(--muted); font-size: var(--fs-sm); line-height: 1.6; }
.mood-fact-list li + li { margin-top: var(--sp-1); }
.mood-headlines-label { margin: var(--sp-2) 0 var(--sp-1); color: var(--ink-3); font-size: var(--fs-xs); font-weight: 600; }
.mood-headlines { list-style: none; margin: 0; padding: 0; color: var(--muted); font-size: var(--fs-sm); line-height: 1.5; }
.mood-headlines li + li { margin-top: var(--sp-1); }
.mood-headline-title { color: var(--ink-2); text-decoration: none; }
a.mood-headline-title { color: var(--accent); }
.mood-headline-domain { margin-left: var(--sp-1h); color: var(--ink-3); font: 500 var(--fs-xs)/1.5 var(--num); font-variant-numeric: tabular-nums; }

.pulse-heads {
  list-style: none; margin: var(--sp-3) 0 0; padding: 0;
  color: var(--muted); font-size: var(--fs-sm); line-height: 1.5;
}
.pulse-heads li + li { margin-top: var(--sp-1); }

@media (max-width: 900px) {
  .pulse-strip { margin: var(--sp-2) 0 var(--sp-3); padding: var(--sp-2) 0; }
  .pulse-say { font-size: var(--fs-sm); }
}

/* --- 격자: [어제 장 | 이슈] / [값 전체 폭] ------------------------------
 *
 * 셋을 한 격자에 넣는 이유는 **폰에서 순서를 바꾸기 위해서**다. 값이
 * 이슈보다 먼저 와야 한다는 규칙은 폭이 좁아졌다고 사라지지 않는데,
 * 값이 격자 밖에 있으면 CSS로는 그 순서를 못 만든다. */
.home-lede {
  display: grid;
  /* 셋이 **똑같이** 나눠 갖는다 (운영자 2026-09-07: "그냥 이 3개 카드가 모두
     같은 사이즈로 바꾸는게 디자인적으로 예쁠거같아").
     내용 양으로 폭을 저울질하던 것을 그만둔다 — 폭이 저마다 다르면 셋이 한 줄에
     서도 세 종류로 읽힌다. 1440px에서 419px씩이다. */
  /* **칸을 세지 않는다.** 전에는 이름 붙인 영역으로 조합을 열거했는데
     (`"mood private issues"`와 `:has()` 세 벌), 이 띠의 자식은 이제 다섯이고
     이름은 셋뿐이라 이름 없는 카드가 암시적 칸으로 흘렀다. 어제 장이 쉬는
     날 폰에서 `지금 이슈`가 **24px**이 되어 글자가 한 자씩 세로로 섰고,
     데스크톱에서는 같은 이유로 800px 구멍이 났다(운영자 제보 2026-09-17).

     자동 배치는 숨은 카드를 아예 세지 않는다 — `[hidden]`은 `display: none`
     이라 칸을 만들지 않는다. 남는 것들이 같은 폭으로 나눠 갖고, 폭이 모자라면
     줄이 바뀐다. 조합을 적을 필요가 없어진다. */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: var(--sp-3) var(--sp-4);
  align-items: start;
  /* 위 여백이 없어 값 구역과 **0.0px으로 맞닿아** 있었다(실측 라이브 390px:
     `.home-values` 아래끝 910.5 = `.home-lede` 위끝 910.5). 눈에 걸린 것은
     값 구역의 마지막 자식인 "이 가격은 어떻게 계산한 값인가요?" 서랍이었지만,
     붙어 있던 것은 서랍이 아니라 **두 구역**이다 — 넓은 화면에서 이 격자가
     세 판을 나란히 세우면 서랍 하나가 셋 모두에 붙는다(운영자: "pc는 더 심해").

     이 페이지의 구역 사이는 32px이다(실측: 히트맵·미국 야간·캘린더·피드 전부
     `margin-top: 32px`). 여기만 0이었다. 같은 값을 준다 — 아래 24px과는
     병합되므로 리듬이 더 벌어지지는 않는다. */
  margin-top: var(--sp-6);
  margin-bottom: var(--sp-5);
}
/* 두 자식이 다 숨으면 이 격자는 **높이 0으로 남는다.** 그런데 자기 마진은
   그대로 갖고, `display: grid`라 형제와 마진 병합도 안 된다 — 제목과 다음
   섹션 사이가 48이어야 할 자리에서 12+48=60이 됐다(실측). 보이지 않는 것이
   간격을 만들면 리듬은 이유 없이 흔들린다. 아무것도 안 실렸으면 서지 않는다. */
.home-lede:not(:has(> :not([hidden]))) { display: none; }
/* 비상장 두 장 — **보드 타일과 같은 카드** (운영자 2026-09-07).
 *
 * 한 번 목록으로 물러섰다가 되돌아왔다. 그때 값이 잘린 이유는 카드 꼴이 아니라
 * **칸이 200px이었던 것**이다("$1,484.10" → "$1,484.1"). 카드를 쓰되 칸을 값이
 * 들어갈 만큼 준다 — 아래 격자의 `minmax(320px, 360px)`이 그 값이다.
 *
 * 추이선은 없다. 띠의 한 칸이라 보드 타일보다 좁고, 선을 넣으면 값이 눌린다 —
 * 추이는 클릭해 들어가는 상세 페이지가 맡는다. */
/* 카드가 **남는 높이를 채운다** (운영자 2026-09-07: "공백 안남게").
 *
 * 처음엔 카드가 제 크기(158px×2)를 주장해 띠 높이를 이 칸이 정했고, 나머지 둘이
 * 그 높이로 늘어나 바닥에 194px씩 남았다(실측). 바닥선을 맞추는 규칙은 그대로
 * 두되(2026-09-03 ④), **높이를 정하는 쪽을 바꾼다** — 이 칸은 따라가는 쪽이다.
 *
 * `1fr` 두 줄이면 카드가 칸을 반씩 나눠 갖는다. 세 장이 되면 셋으로 나뉜다. */
.hp-tiles {
  display: grid; gap: var(--sp-2);
  height: 100%; grid-auto-rows: minmax(0, 1fr);
}
/* 카드 안쪽을 한 단 줄인다. 보드 타일은 넓은 격자에서 숨 쉬는 값이고, 띠의
 * 한 칸에서는 그 여백이 곧 **다른 두 카드의 바닥 공백**이 된다 — 이 칸이
 * 높이를 정하는 쪽이 되면 안 된다(운영자 2026-09-07). */
.hp-tiles .tile { margin: 0; min-height: 0; padding: var(--sp-3); gap: var(--sp-1h); }
/* 값은 `--fs-display`(38)에서 `--fs-xxl`(28)로. 보드 타일의 38은 3열 격자에서
 * 한 화면을 대표하는 크기이고, 띠의 한 칸에서는 그 크기가 곧 옆 카드 두 장의
 * 바닥 공백이 된다. 28도 이 화면에서 두 번째로 큰 숫자다. */
.hp-tiles .tile-value { font-size: var(--fs-xxl); }
/* 추이선 자리를 아예 걷는다. 값이 없으면 그 칸은 "30일 계열 없음"이라는 글자만
   46px 차지하고, 두 장이면 108px이 그 말에 쓰인다 — 카드 두 장이 띠를 485px로
   밀어 올려 옆 카드에 다시 구멍을 냈다(실측). 추이는 상세 페이지가 맡는다. */
.hp-tiles .tile-foot { display: none; }
.home-values { grid-area: values; min-width: 0; }

/* **반대쪽 규칙이 없었다** (2026-09-07 운영 사고).
 *
 * 위 규칙만 있으니, 어제 장이 못 서는 날에는 격자가 `"mood issues"` 그대로
 * 남아 왼쪽 1fr 칸이 빈 채로 자리를 차지했다. 실측(1280px): 띠 1233px 중
 * 이슈는 오른쪽 400px, **왼쪽 833px가 흰 구멍**. 폰(390px)에서는 한 줄이라
 * 아무 일도 없어서 눈에 안 띄었다.
 *
 * 원인은 상류였다 — Anthropic이 529를 돌려줘 그날 문장이 안 쓰였다. 상류가
 * 잠깐 붐빈 것이 홈 맨 위를 비우면 안 된다. */
   이 세 벌은 2026-09-17에 걷었다. 조합을 적는 방식 자체가 원인이었다 —
 * 카드가 하나 늘 때마다 새 조합이 생기고, 안 적힌 조합은 조용히 깨진다.
 * 위의 `auto-fit`이 셋을 한꺼번에 대신한다. */

/* 제목이 **카드 안으로** 들어가면서 이 규칙은 사라졌다 (2026-09-07).
 *
 * 전에는 제목이 띠 위에 따로 서 있어서, 이야기가 없는 날 제목만 남고 그
 * 아래 빈칸이 제목의 내용처럼 읽혔다 — `:has()`로 함께 감췄다. 이제 제목은
 * `#market-mood` 안에 있어 카드가 감춰지면 같이 사라진다. 규칙으로 지키던
 * 것을 구조가 지킨다. */

/* 제목도 형제들과 같은 크기다. `.pulse-strip > header h2`(12px)는 전폭
 * 띠 시절의 라벨이라 카드 제목으로는 두 단 낮다 — 옆 칸이 17px인데 이 칸만
 * 12px이면 셋이 같은 줄에 서도 층이 어긋난다. */
.home-lede > .pulse-strip > header { margin-bottom: var(--sp-3); flex-wrap: wrap; }
/* 기준 줄은 형제들보다 길다("9월 7일 (월) 국내장 · 15:30 KST 마감 · 확정 전
 * 참고가"). `.pulse-when`의 nowrap을 그대로 두면 폰에서 제목 옆에 억지로 서서
 * 머리가 131px까지 자랐다(360px 실측). 줄을 바꾸게 둔다. */
.home-lede > .pulse-strip > header .pulse-when { white-space: normal; }
.home-lede > .pulse-strip > header h2 {
  font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.01em;
  color: var(--ink); white-space: normal;
}
@media (min-width: 900px) {
  .home-lede > .pulse-strip > header h2 { font-size: var(--fs-lg); }
}

/* 나란히 서므로 어제 장도 이슈와 같은 카드로 — 한쪽만 테두리가 없으면
 * 둘이 다른 종류로 읽힌다. */
.pulse-strip {
  display: flex; flex-direction: column; min-width: 0;
  margin: 0; padding: var(--sp-3) var(--sp-4);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
}

/* 이슈 칸도 카드다 — 어제 장과 나란히 서므로 같은 옷을 입는다.
 * (격자 규칙을 갈아 끼우면서 이 블록을 한 번 잘라 먹었다.) */
.pulse-side {
  display: flex; flex-direction: column; min-width: 0;
  padding: var(--sp-3) var(--sp-3) var(--sp-2);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-md);
}
.pulse-side[hidden] { display: none; }
.pulse-side > header { display: flex; align-items: baseline; gap: var(--sp-2); margin-bottom: var(--sp-2); }
/* 곁판 제목은 구역 제목(22)보다 한 단 아래다 — 좁은 열에 서고, 옆의
   `h2.lede-title`(22)과 같은 단으로 읽히면 안 된다. 15는 h3 단 아래였다. */
/* The Two Rungs Rule: 17은 **좁은 열에 서는 곁판 제목**에만 허용된다.
   390px에서 `.pulse-side`는 354px — 셸 전체 폭이고 22px 형제들과 같다.
   그 폭에서 이 제목만 작아지면 규칙이 막으려던 바로 그 증상이 된다
   ("스크롤하다 보면 구역 제목이 이유 없이 작아진다"). 실제로 곁판이 되는
   폭에서만 내린다. */
.pulse-side > header h2 { margin: 0; font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.01em; }
@media (min-width: 900px) {
  .pulse-side > header h2 { font-size: var(--fs-lg); }
}
.pulse-side .pulse-foot {
  margin-top: var(--sp-2); padding-top: var(--sp-2);
  border-top: 1px solid var(--line);
  color: var(--ink-3); font-size: var(--fs-xs);
}

.pulse-side .issue-list { margin: 0; padding: 0; list-style: none; }
.pulse-side .issue-row {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: subgrid;
  align-items: start; row-gap: var(--sp-1h);
  padding: var(--sp-1h) var(--sp-1); border-radius: var(--r-sm);
}
.pulse-side .issue-row + .issue-row { border-top: 1px solid var(--line); }
/* 순위는 **왼쪽 끝에서 시작한다** (운영자 2026-09-07: "지금 이슈랑 세로
 * align이 맞으면 좋겠어"). 20px 칸에 오른쪽 맞춤이면 한 자리 숫자가 칸 끝에
 * 붙어 제목보다 13px 안쪽에서 시작한다 — 홈 띠는 넷까지라 두 자리가 올 일이
 * 없으므로 자릿수를 맞출 이유도 없다. */
.pulse-side .issue-rank {
  color: var(--ink-3); font-size: var(--fs-sm); font-weight: 700;
  font-variant-numeric: tabular-nums; text-align: left;
}
.pulse-side .issue-row:nth-child(1) .issue-rank { color: var(--accent); }
.pulse-side .issue-title {
  margin: 0; color: var(--ink); font-size: var(--fs-md); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pulse-side .issue-sources {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1);
  margin-top: 3px; font-size: var(--fs-xs);
}
.pulse-side .issue-age { color: var(--ink-3); }
/* 옆칸은 좁다 — 출처 칩은 둘까지만 보이고 나머지는 +n이 센다. */
.pulse-side .issue-sources .issue-src:nth-of-type(n + 3) { display: none; }

/* --- 순위 이동 --------------------------------------------------------- */
/* 배지는 **제 글자만큼만** 선다. 격자 칸이라 그냥 두면 기본값 `stretch`로
 * 칸 폭 전체에 늘어나고, 글자는 그 안에서 왼쪽에 붙는다 — 배경이 있는 NEW만
 * 그게 눈에 보여 "상자 가운데가 아닌 글자"가 된다(실측 2026-09-06 · 390px:
 * 칸 48.4px · 글자 29.0px · 왼쪽 4px 대 오른쪽 15.4px). 시각 표기(`.issue-age`)는
 * 배경이 없어 같은 늘어남이 안 보였을 뿐 같은 칸이다.
 *
 * `letter-spacing`은 **마지막 글자 뒤에도** 붙는다. 하나가 남으면 글자가 그만큼
 * 왼쪽으로 치우치므로 오른쪽 여백에서 같은 값을 뺀다.
 *
 * 아래·위 여백이 1px 다른 것도 일부러다. NEW·▲2에는 **밑꼬리가 없어서**
 * 글자 상자를 정확히 가운데 두면 획이 1px 떠 보인다(실측: 상자 위에서 획까지
 * 4px · 획 아래에서 상자까지 5px). 재서 나온 만큼 내린다 — 상자가 아니라
 * **획**이 가운데여야 눈이 가운데로 읽는다. */
.issue-move {
  justify-self: start;
  padding: 3px var(--sp-1h) 2px; border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* 화살표와 계단 수 사이 (운영자 2026-09-07: "너무 딱붙어있는거 같아").
   한 문자열이던 것을 갈라 이 한 군데에만 여백을 준다 — `letter-spacing`은
   마지막 글자 뒤와 두 자리 수 사이까지 함께 벌린다.

   3px이다. 2px은 12px 글리프 옆에서 여전히 붙어 보이고, 4px이면 배지 안에서
   두 덩이가 따로 노는 것으로 읽힌다. `font-style`을 되돌리는 것은 `i`를
   기울이지 않으려는 것뿐이다 — 여기 `i`는 강조가 아니라 방향 표시다. */
.issue-move-dir { font-style: normal; margin-right: 3px; }
.issue-move-up { color: var(--up); background: color-mix(in srgb, var(--up) 14%, transparent); }
.issue-move-down { color: var(--down); background: color-mix(in srgb, var(--down) 14%, transparent); }
.issue-move-new { color: var(--accent); background: var(--accent-soft); }

/* 자리를 옮긴 줄만 한 번 밝아진다. 색이 아니라 **밝기**로 말한다 —
 * 등락색을 빌려 쓰면 "올랐다"로 읽힌다. 순위는 등락이 아니다. */
.issue-moved { animation: issue-flash 1.1s ease-out 1; }
.issue-moved .issue-rank { animation: issue-rank-pop .52s cubic-bezier(.16,1,.3,1); }
@keyframes issue-flash {
  0% { background: color-mix(in srgb, var(--accent) 18%, transparent); }
  100% { background: transparent; }
}
@keyframes issue-rank-pop {
  0% { transform: scale(.78); opacity: .45; }
  65% { transform: scale(1.12); }
  100% { transform: none; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .issue-moved, .issue-moved .issue-rank { animation: none; }
}

/* --- 폰 ---------------------------------------------------------------- */
@media (max-width: 900px) {
  /* 폰: 한 단. 순서는 자식 순서가 정한다 — 어제 장 → 비상장 → 지금 이슈.
     이름 붙인 영역으로 적던 시절 이 줄에 `private`이 빠져 있었고, 그래서
     비상장 카드가 자리를 가로채 `지금 이슈`가 24px로 눌렸다(2026-09-17). */
  .home-lede {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-4);
  }
  /* 폰에서도 넷을 다 보인다 — 카드가 전체 폭이라 자리가 있고, 수가 화면마다
   * 다르면 "왜 여기선 셋이지"가 생긴다. */
  .pulse-strip { padding: var(--sp-3); }
  .pulse-say { font-size: var(--fs-sm); }
}

/* 출처 칩 — origin/main에서 가져온다. 내 JS(issues.js sourceChip)가
 * 여전히 이 클래스를 붙이므로, 규칙이 없으면 칩이 맨몸으로 선다.
 * 티어 색(t1/t3)은 출처의 격을 말한다 — 로이터와 지역지를 같은 색으로
 * 그리면 순위의 근거가 화면에서 사라진다. */
.issue-src {
  max-width: 100%; padding: 0 var(--sp-2); border-radius: var(--r-pill);
  background: var(--panel-2); color: var(--ink-2); text-decoration: none;
  font: 500 var(--fs-xs)/1.5 var(--num); font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.issue-src-kr_filing, .issue-src-us_filing { background: transparent; border: 1px solid var(--line-strong); }
.issue-src-t1 { font-weight: 700; color: var(--ink); }
.issue-src-t3, .issue-src-more { color: var(--ink-3); }

/* ======================================================================
   첫 화면 두 카드 — 고도화 (2026-09-03, 운영자 지적)

   지적 넷을 우선순위대로 반영한다.
   ① 면책이 콘텐츠만큼 자리를 먹었다 → 카드 안에는 "자세히" 하나.
   ② `<details>`가 브라우저 기본값이었다 → 다른 컨트롤과 같은 옷을 입힌다.
      ("제품 느낌 안 남"의 절반이 이 한 줄이었다는 지적이 맞다.)
   ③ 칩에 위계가 없었다 → 국내/해외 라벨을 붙이고 넘칠 때 신호를 준다.
   ④ 두 카드의 바닥선이 105px 어긋났다 → 같은 높이로 세운다.
   ====================================================================== */

/* ④ 나란한 두 카드는 바닥선을 맞춘다. start면 내용 길이대로 들쭉날쭉해진다. */
.home-lede { align-items: stretch; }
.home-lede > .pulse-strip,
.home-lede > .pulse-side { height: 100%; }
.pulse-strip .pulse-body,
.pulse-side .pulse-body { flex: 1 1 auto; }

/* ② 접힘 컨트롤 — 브라우저 기본 삼각형을 걷고 이 화면의 컨트롤로. */
.pulse-more > summary,
.pulse-info > summary {
  display: inline-flex; align-items: center; gap: var(--sp-1h);
  width: max-content;
  padding: 3px var(--sp-2) 3px var(--sp-2);
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--panel-2);
  color: var(--ink-2); font-size: var(--fs-xs); font-weight: 600;
  cursor: pointer; list-style: none;
}
.pulse-more > summary::-webkit-details-marker,
.pulse-info > summary::-webkit-details-marker { display: none; }
.pulse-more > summary::after,
.pulse-info > summary::after {
  content: ""; width: 11px; height: 11px;
  background-color: currentColor;
  -webkit-mask: var(--ico-caret) center / contain no-repeat;
  mask: var(--ico-caret) center / contain no-repeat;
  transform: rotate(90deg); transition: transform .15s ease;
}
.pulse-more[open] > summary::after,
.pulse-info[open] > summary::after { transform: rotate(-90deg); }
.pulse-more > summary:hover,
.pulse-info > summary:hover { color: var(--ink); border-color: var(--line-strong); }

/* ① 면책은 "자세히" 안으로. 카드 바닥에 두 줄로 깔려 있던 것이
 *   콘텐츠만큼 자리를 먹고 있었다. */
.pulse-strip .pulse-foot,
.pulse-side .pulse-foot {
  margin-top: var(--sp-2); padding-top: var(--sp-2);
  border-top: 1px solid var(--line);
}
.pulse-info-body {
  margin-top: var(--sp-2);
  color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.6;
}
.pulse-info-body p { margin: 0; }
.pulse-info-body p + p { margin-top: var(--sp-1h); }

/* ③ 칩 위계 — 국내/해외 라벨을 달고, 넘치면 넘친다고 말한다. */
.pulse-chip-box { display: flex; flex-direction: column; gap: var(--sp-1h); }
.pulse-chip-group {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  align-items: center; column-gap: var(--sp-2); min-width: 0;
}
.pulse-chip-label {
  color: var(--ink-3); font-size: var(--fs-xs); font-weight: 700;
  white-space: nowrap;
}
/* 오른쪽 끝이 잘려 보이던 것 — 잘린 게 아니라 **흐르는** 것이라고 말한다.
 * 페이드가 없으면 깨진 화면으로 읽힌다(운영자 지적). */
.pulse-chip-group .pulse-chips {
  min-width: 0;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent);
}
.pulse-chip-group .pulse-chips:not([data-overflow]) {
  -webkit-mask-image: none; mask-image: none;
}

/* ④ 이슈 줄 — 높이를 고르게. "+8"이 혼자 줄을 차지해 리듬이 깨졌다. */
.pulse-side .issue-sources { flex-wrap: nowrap; overflow: hidden; }
.pulse-side .issue-title { -webkit-line-clamp: 2; min-height: 2.8em; }

/* 출처와 **종류**는 모양이 달라야 한다. SEC 8-K는 출처가 아니라 공시 유형인데
 * 도메인 칩과 똑같이 생겨 있었다. */
.pulse-side .issue-kind {
  border-style: solid; border-width: 1px;
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  color: var(--accent); background: var(--accent-soft);
  border-radius: var(--r-sm);
}
.pulse-side .issue-src-more { color: var(--ink-3); }

/* 푸터로 모인 공급자 인용 — 링크가 줄줄이 파랗게 서지 않도록 조용히. */
.attribution-line { margin: var(--sp-1h) 0 0; }

/* ======================================================================
   어제 시장 요약 — 글로벌과 한국을 가른다 (2026-09-03, 운영자 목업)

   한 덩어리 문장으로는 "미국은 …, 반면 국내는 …"이 붙어 읽기 어려웠다.
   시장마다 **대표 지수를 크게** 세우고 그 아래 그 시장 이야기를 둔다.
   데이터가 축을 준다 — `figures[].market`.
   ====================================================================== */

/* 첫 화면의 두 제목("어제 시장 요약" · "지금 시장")은 섹션 제목과 같은 급이다
 * — 같은 급이면 같은 크기로 선다(운영자 2026-09-03: "아까랑 똑같이"). 작게
 * 두었더니 아래 섹션 제목보다 작아져서 첫 화면이 곁다리처럼 읽혔다. */
.lede-title {
  display: flex; align-items: baseline; gap: var(--sp-2);
  margin: var(--sp-4) 0 var(--sp-2);
  font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.02em;
}
/* 자간은 **길이로** 상속된다. 부모 `.lede-title`의 -0.02em은 22px에서
   -0.44px이고, 그것이 12px인 이 자식에게 오면 -0.0367em — 바닥 아래다.
   자간을 쓰는 규칙은 크기가 섞인 상자가 아니라 잎에 적어야 한다. */
.lede-title-when { color: var(--ink-3); font-size: var(--fs-xs); font-weight: 500; letter-spacing: 0; }

.pulse-strip > .pulse-body { display: block; }
.mood-row { display: flex; flex-direction: column; gap: var(--sp-4); }

.mood-market { display: flex; flex-direction: column; gap: var(--sp-1h); }
/* 늘어나는 자리는 **맨 아래**다 (운영자 2026-09-07: "왼쪽이 너무 남는데").
 *
 * 카드 높이는 셋 중 가장 큰 것에 맞춰진다(2026-09-03 ④ — 바닥선을 맞추는
 * 규칙이고 그건 그대로 둔다). 문제는 남는 높이가 격자 행에 **고루** 퍼져
 * 문장과 칩 사이에 구멍이 생겼다는 것이다(실측 37px).
 *
 * 내용을 위로 모으면 남는 자리는 카드 끝에 한 번 생긴다 — 같은 여백이라도
 * 글 사이의 구멍보다 낫다. */
/* 한 카드가 되면서 슬랙이 **문장 행**으로 갔다 (운영자 2026-09-07: "왼쪽이 너무
   남는데").

   두 칸 시절의 `auto auto 1fr auto`는 옳았다 — 가운데 1fr이 남는 높이를 먹어
   두 칸의 칩이 같은 높이에 섰다. 칸이 하나가 된 지금 그 1fr은 **문장과 칩 사이에
   구멍**을 만든다. 실측: 문장 74px짜리가 169px 트랙에 앉아 95px이 비었다.

   한 칸일 때는 슬랙을 **맨 끝**으로 보낸다. 행이 하나 늘어 마지막이 1fr을
   먹으므로 내용은 위로 모이고 남는 자리는 카드 끝에 한 번 생긴다. */
/* (규칙은 파일 끝에 — 뒤에 오는 미디어쿼리가 이기기 때문이다.) */
.mood-market + .mood-market {
  padding-top: var(--sp-4); border-top: 1px solid var(--line);
}
.mood-market-head { display: flex; flex-direction: column; gap: 2px; }
.mood-market-name {
  margin: 0; color: var(--ink-3);
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .02em;
}
/* 대표 지수는 이 카드에서 가장 큰 글자다 — 훑는 눈이 여기 먼저 닿아야 한다. */
.mood-lead { display: flex; align-items: baseline; gap: var(--sp-2); margin: 0; }
.mood-lead-name { color: var(--ink); font-size: var(--fs-lg); font-weight: 700; }
.mood-lead-pct {
  font-size: var(--fs-xl); font-weight: 800; font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.mood-lead-pct.up { color: var(--up); }
.mood-lead-pct.down { color: var(--down); }
.mood-lead-pct.flat { color: var(--ink-3); }
/* 방향을 색 하나로만 말하지 않는다 — 색을 못 가리는 눈에도 화살표는 보인다. */
.mood-lead-pct.up::after { content: " \25B2"; font-size: .72em; }
.mood-lead-pct.down::after { content: " \25BC"; font-size: .72em; }

.mood-points {
  margin: var(--sp-1) 0 0; padding-left: var(--sp-4);
  color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.6;
}
.mood-points li + li { margin-top: 2px; }

.mood-market .pulse-chips { margin-top: var(--sp-1h); }

/* ---- 지금 이슈: 출처를 뺀 줄 ------------------------------------------
 * 도메인도 공시 칩도 화면에서 뺐다(운영자 판정). 남는 것은 순위·제목·시각과
 * 원문으로 가는 "자세히" 하나 — 약관이 요구하는 링크는 그것이 진다. */
.pulse-side .issue-sources {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-2); margin-top: 3px; font-size: var(--fs-xs);
}
.pulse-side .issue-open {
  display: inline-flex; align-items: center; gap: 3px;
  color: var(--ink-3); text-decoration: none; white-space: nowrap;
}
.pulse-side .issue-open::after {
  content: ""; width: 10px; height: 10px;
  background-color: currentColor;
  -webkit-mask: var(--ico-caret) center / contain no-repeat;
  mask: var(--ico-caret) center / contain no-repeat;
}
.pulse-side .issue-open:hover { color: var(--accent); }

@media (max-width: 900px) {
  /* 제목을 본문 크기로 줄이지 않는다 (2026-09-04).
     `--fs-md`(15)는 본문 크기라, 폰에서 이 페이지의 h1이 뒤따르는 h2들(22)보다
     **작아지는** 역전이 났다. 계단은 h1=28(좁은 화면 22) · h2=22이므로 여기서는
     22가 맞다. 뒤에 붙는 기준일(`.lede-title-when`)이 좁은 화면에서 같은 줄에
     못 서면 아래로 내려가게 wrap을 연다. */
  .lede-title { margin: var(--sp-3) 0 var(--sp-2); font-size: var(--fs-xl); flex-wrap: wrap; }
  .mood-row { gap: var(--sp-3); }
  .mood-market + .mood-market { padding-top: var(--sp-3); }
}

/* ======================================================================
   첫 화면 두 카드 — 면을 줄이고 위계를 세운다 (2026-09-03 v6)

   "구조는 마음에 드는데 전체 디자인이 마음에 안 든다"의 원인은 **면의 수**다.
   카드(테두리+배경) 안에 칩(테두리+배경), 그 옆에 버튼(테두리+배경)이
   겹쳐 첫 화면에 상자가 열 개 넘게 섰다. 카드만 면으로 두고 안쪽은
   선과 크기로 말한다.
   ====================================================================== */

.pulse-strip, .pulse-side {
  padding: var(--sp-5);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}

/* --- 어제 시장 요약 ---------------------------------------------------- */
.lede-title { margin: var(--sp-5) 0 var(--sp-3); }

.mood-row { gap: var(--sp-5); }
.mood-market + .mood-market { padding-top: var(--sp-5); }

.mood-market-name {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .06em;
  text-transform: none; color: var(--ink-3);
}
.mood-market-head { gap: var(--sp-1); }

/* 대표 지수가 이 카드의 주인공이다 — 다른 어떤 글자보다 커야 한다. */
/* **줄이 모자라면 접힌다 — 글자를 부수지 않는다** (2026-09-04 실측, 1118px).
 * `.mood-market`에 `min-width: 0`이 걸려 있어(폰 넘침을 막은 규칙) 이 줄은
 * 내용보다 좁아질 수 있다. 그때 이름과 배지가 음절 단위로 쪼개져 "코스피 / 200",
 * "참고 / 가"가 됐다. 줄바꿈을 허용해 배지가 아랫줄로 내려가게 하고, 이름은
 * 통째로 둔다 — 이름은 길어야 열 글자라 넘칠 일이 없다. */
.mood-lead { align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.mood-lead-name {
  font-size: var(--fs-lg); font-weight: 700; color: var(--ink-2);
  letter-spacing: -0.01em; white-space: nowrap;
}
/* 어제 값이 오늘 값보다 크면 안 된다. 800은 이 페이지에서 가장 굵은
   무게였고, 그게 하필 **어제 미국 지수**에 붙어 있었다. */
.mood-lead-pct { font-size: var(--fs-xl); font-weight: 700; letter-spacing: -0.03em; }
.mood-lead-pct.up::after, .mood-lead-pct.down::after { font-size: .6em; }

/* 문장은 글머리표를 버리고 들여쓰기만 — 점 하나가 면을 하나 더 만든다. */
.mood-points { margin: var(--sp-2) 0 0; padding: 0; list-style: none; }
.mood-points li { color: var(--ink-2); font-size: var(--fs-md); line-height: 1.65; }
.mood-points li + li { margin-top: var(--sp-1h); }

/* 칩은 테두리를 버린다. 카드 안에서 또 상자가 되지 않게. */
.pulse-chip {
  padding: 2px var(--sp-2);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  border: 0; border-radius: var(--r-sm);
  color: var(--ink-3);
}
.mood-market .pulse-chips { margin-top: var(--sp-3); gap: var(--sp-1); }

/* --- 지금 이슈 --------------------------------------------------------- */
.pulse-side > header { margin-bottom: var(--sp-3); }
/* 네 칸이다 — 순위 · 갈래 · 제목 · 표식. 표식을 칸으로 잡아 두지 않으면
 * 자리가 모자랄 때 제 줄로 밀려 줄 리듬이 깨진다(실측: 3번만 두 줄이 됐다).
 * 갈래도 칸이다(2026-09-04): `auto`는 격자에서 **줄을 가로질러** 가장 넓은
 * 것에 맞춰지므로, 갈래 이름이 2자든 5자든 제목은 한 세로선에서 시작한다. */
.pulse-side .issue-row {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: subgrid;
  align-items: baseline; column-gap: var(--sp-2);
  padding: var(--sp-3) 0;
}

/* `subgrid`를 모르는 브라우저에는 칸을 손으로 잡아 준다. 정확히 같아지지는
 * 않지만 제목이 한 줄로 무너지는 것보다 낫다. */
@supports not (grid-template-columns: subgrid) {
  .pulse-side .issue-list { display: block; }
  .pulse-side .issue-row {
    grid-template-columns: auto minmax(3.6rem, auto) minmax(0, 1fr) auto;
  }
}
.pulse-side .issue-row + .issue-row { border-top: 1px solid var(--line); }
/* 순위는 **왼쪽 끝에서 시작한다** (운영자 2026-09-07: "지금 이슈랑 세로
 * align이 맞으면 좋겠어"). 20px 칸에 오른쪽 맞춤이면 한 자리 숫자가 칸 끝에
 * 붙어 제목보다 13px 안쪽에서 시작한다 — 홈 띠는 넷까지라 두 자리가 올 일이
 * 없으므로 자릿수를 맞출 이유도 없다. */
.pulse-side .issue-rank {
  color: var(--ink-3); font-size: var(--fs-sm); font-weight: 700;
  font-variant-numeric: tabular-nums; text-align: left;
}
.pulse-side .issue-row:nth-child(1) .issue-rank { color: var(--accent); }

/* 제목과 시각이 한 줄에 산다 — 시각이 제 줄을 차지하면 줄마다 한 칸을 버린다. */
.pulse-side .issue-title {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  margin: 0; min-height: 0;
  color: var(--ink); font-size: var(--fs-sm); line-height: 1.5;
  -webkit-line-clamp: initial; overflow: visible;
}
.pulse-side .issue-sources {
  color: var(--ink-3); font-size: var(--fs-xs); white-space: nowrap;
}
.pulse-side .issue-body { min-width: 0; }

/* NEW·순위 이동은 제목 뒤에 조용히. 늘어나지 않고 제 글자만큼만 선다. */
.pulse-side .issue-move {
  justify-self: start;
  margin-left: var(--sp-1h); line-height: 1;
  padding: 3px calc(var(--sp-1) - .04em) 2px var(--sp-1);
  background: none; border-radius: var(--r-sm);
  /* 12px가 바닥이다 — 작게 보이고 싶으면 크기가 아니라 색을 낮춘다. */
  font-size: var(--fs-xs); letter-spacing: .04em;
}
.issue-move-new { color: var(--accent); background: var(--accent-soft); }

/* --- 폰 --------------------------------------------------------------- */
@media (max-width: 900px) {
  .pulse-strip, .pulse-side { padding: var(--panel-inset); }
  .mood-row { gap: var(--sp-4); }
  .mood-market + .mood-market { padding-top: var(--sp-4); }
  .mood-lead-pct { font-size: var(--fs-lg); }
  .mood-points li { font-size: var(--fs-md); }
}

/* ======================================================================
   어제 시장 요약 — 두 시장을 나란히 (2026-09-03 v7)

   위아래로 쌓으니 왼쪽 카드가 오른쪽의 두 배 높이가 됐고, 바닥선을 맞추느라
   오른쪽에 **빈 면**이 크게 남았다. 오른쪽을 늘려 맞출 일이 아니라 왼쪽을
   낮출 일이다 — 글로벌과 한국은 **견주는 짝**이라 나란히 서는 게 뜻에도 맞다.
   ====================================================================== */
@media (min-width: 901px) {
  .mood-row {
    /* 칸 수는 **자식 수가 정한다.** 두 칸으로 못박으면 한국 칸이 빠지는
     * 아침(`latest_markets`가 뒤처진 시장을 뺀다)에 왼쪽 절반만 찬다 —
     * 실측으로 확인했다(행 535px에 칸 256px). 흐름으로 두면 셀 것이 없다. */
    display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
    gap: var(--sp-5);
  }
  /* 나란히 서면 위쪽 선이 아니라 **가운데 선**이 둘을 가른다.
   *
   * 그 선은 틈의 **가운데**에 서야 한다. 두 번째 칸의 왼쪽 테두리로 그리면
   * 선이 틈의 끝에 서고(실측 1538px: 선 1077px, 줄의 가운데 1065px — 12px
   * 오른쪽), 왼쪽 칸은 글이 제 상자 끝까지 가는데 오른쪽 칸만 24px 물러나
   * 있어 글 너비도 399 대 375로 어긋났다. 테두리 대신 틈 한가운데에 한 줄을
   * 세우면 두 칸이 선에서 똑같이 12px씩 떨어지고 너비도 같아진다. */
  .mood-market + .mood-market {
    position: relative;
    padding-top: 0; padding-left: 0;
    border-top: 0; border-left: 0;
  }
  /* 선은 **상자**가 아니라 **글**의 가운데에 선다 (운영자 2026-09-03, 네 번째).
   *
   * 틈 한가운데(-12px)에 두면 기하학적으로는 정중앙이 맞다 — 1280px 실측에서
   * 줄의 가운데도 선도 425px, 어긋남 0이었다. 그런데도 오른쪽으로 쏠려 보인다.
   * 잉크를 재면 이유가 나온다: 왼쪽 칸의 글은 상자 끝(413px)까지 못 가고
   * 383px에서 꺾이는데, 오른쪽 칸의 글은 상자 왼끝(437px)에서 바로 시작한다.
   * **한글은 오른쪽 끝이 늘 들쭉날쭉하고 다음 칸은 늘 칼같이 시작한다** —
   * 그날 문장이 무엇이든 이 비대칭은 남는다. 눈이 재는 가운데는 (383+437)/2 =
   * 410px이고, 운영자가 그은 선이 바로 거기였다.
   *
   * 그래서 선을 왼쪽 칸의 **오른쪽 끝**에 세운다(틈 하나만큼 왼쪽). 상자로는
   * 12px 치우치지만 글로는 가운데다. 화면은 글을 보지 상자를 보지 않는다. */
  .mood-market + .mood-market::before {
    content: ""; position: absolute; top: 0; bottom: 0;
    left: calc(var(--sp-5) * -1); width: 1px; background: var(--line);
  }
}

/* 나란히 서면서 칸이 좁아졌다 — 칩은 가로로 흐르는 대신 줄바꿈한다.
 * 좁은 칸에서 가로 스크롤은 손가락에 안 잡힌다. */
/* 칩도 넓이를 **나눠 가진다** (운영자 지적 2026-09-04).
 *
 * 이름 길이(엔비디아 4자 · 반도체 5종 6자)와 퍼센트 자릿수가 칩마다 달라
 * 줄바꿈한 칩들의 오른쪽 끝이 들쭉날쭉했다. 두 칸으로 나누면 칩 넓이가 같아지고
 * 이름은 왼쪽, 퍼센트는 오른쪽 끝에 서서 숫자가 세로로 맞는다 — 칩이 아니라
 * 작은 표로 읽힌다. 폰(<901px)은 그대로 가로로 흐른다. */
@media (min-width: 901px) {
  .mood-market .pulse-chips {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    justify-content: stretch; overflow: visible;
    -webkit-mask-image: none; mask-image: none;
  }
  /* **칸을 다 쓴다** (운영자 2026-09-07: "오른쪽이 공백이 많이 남네").
   *
   * 전에는 `max-content` 네 칸이라 칩 넷이 272px만 차지하고 오른쪽 174px이
   * 비었다(446px 상자 실측). 한때 그 모양을 고른 이유는 `1fr`로 늘리면 이름과
   * 퍼센트 사이가 벌어져 알약이 늘어난 것처럼 보였기 때문인데, 그건 칩이 한
   * 줄에 넷일 때 이야기다. 지금은 두 칸씩이라 벌어지는 폭이 절반이고, 대신
   * 퍼센트가 두 세로선에 맞춰 서서 작은 표로 읽힌다. */
  .mood-market .pulse-chip { display: flex; min-width: 0; }
  .mood-market .pulse-pct { margin-left: auto; text-align: right; }
}
/* NEW는 제목 끝에 붙는다 — 줄을 새로 만들지 않는다. */
.pulse-side .issue-move { margin-left: 0; }

/* 이슈 목록은 칸 안에서 고르게 퍼진다. 넷만 올 때 위에 몰려 서면
 * 아래가 "고를 것이 없다"로 읽힌다. */
.pulse-side .pulse-body { display: flex; flex-direction: column; }
/* **칸의 주인은 목록이다.** 줄마다 따로 격자를 세우면 `auto` 칸은 그 줄
 * 안에서만 넓이를 잰다 — 갈래 이름이 2자든 5자든 제목 시작점이 줄마다
 * 달라졌다(실측 2026-09-04: 61·76·91·96px). 목록이 칸을 잡고 줄은
 * `subgrid`로 그 칸을 빌려 쓰면, 넓이는 가장 넓은 갈래 하나가 정하고
 * 제목은 한 세로선에서 시작한다. 줄이 제 상자를 잃지 않으므로 테두리·
 * 여백·hover는 그대로다. */
/* 순위 칸은 **숫자만큼만** 잡는다 (운영자 2026-09-07: "순위 숫자가 왼쪽으로
   가면서 지정학같은 티커와 실제 문장도 너무 떨어져있는 느낌이야 — 같이
   왼쪽으로 살짝 옮겨줘").

   20px으로 못 박아 두면 한 자리 숫자(실측 390px에서 약 7px)가 든 칸에 13px이
   빈 채로 남고, 그만큼 갈래와 문장이 통째로 오른쪽으로 밀린다. 홈 띠는 넷까지라
   두 자리가 올 일이 없으므로 자리를 미리 잡을 이유가 없다. `auto`는 격자에서
   **줄을 가로질러** 가장 넓은 것에 맞춰지므로 네 줄의 숫자는 그대로 한 세로선에
   선다 — 갈래 칸이 이미 같은 이유로 `auto`다. */
.pulse-side .issue-list {
  display: grid; grid-template-columns: auto auto minmax(0, 1fr) auto;
  column-gap: var(--sp-2); align-content: space-between; height: 100%;
}
/* 남는 자리에는 더 볼 곳을 가리킨다 — 태그나 요약을 지어내지 않는다. */
.pulse-side .pulse-foot { border-top: 1px solid var(--line); }
.issue-more {
  display: inline-flex; align-items: center; gap: var(--sp-1h);
  color: var(--ink-3); font-size: var(--fs-xs); text-decoration: none;
}
.issue-more::after {
  content: ""; width: 11px; height: 11px; background-color: currentColor;
  -webkit-mask: var(--ico-caret) center / contain no-repeat;
  mask: var(--ico-caret) center / contain no-repeat;
}
.issue-more:hover { color: var(--accent); }

/* ======================================================================
   빈 면은 "늘려서 맞추기"가 만든 것이었다 (2026-09-03 v8)

   시소였다 — 요약을 낮추니 이슈가 비고, 이슈를 채우니 요약이 비었다.
   원인은 어느 한쪽의 내용이 아니라 **자란 쪽에 맞춰 상자를 늘리는 것**이다.
   늘리지 않는다. 카드는 제 내용만큼만 선다.

   한 판으로 합치는 안도 해 봤는데, 값 카드까지 같은 격자에 있어서 판이
   그것까지 감쌌다(실측 877px). 마크업을 한 겹 더 만들면 폰에서 값을
   이슈보다 먼저 세울 수 없다 — 그건 못 내주는 규칙이라 접었다.

   바닥선은 내용이 다르면 다르다. 그게 정직한 높이다.
   ====================================================================== */

/* 바닥선을 맞춘다(운영자 2026-09-03). 한때 늘리기를 그만뒀던 이유는 한쪽이
 * 반쯤 비었기 때문인데, 그건 **높이 차가 145px일 때** 이야기였다. 폭 비율을
 * 고치고 참고가 줄이 붙은 지금은 차이가 42px·-6px(1050·1260px 실측)라
 * 늘려 맞추는 값이 싸다. 다시 벌어지면 그때 다시 판단한다. */
.home-lede { align-items: stretch; }
.home-lede > .pulse-strip,
.home-lede > .pulse-side { height: 100%; }
.pulse-side .issue-list { height: auto; align-content: start; }
.pulse-side .pulse-foot { border-top: 0; margin-top: 0; padding-top: 0; }

/* 각주가 비면 자리도 없다 — 고지를 푸터로 옮긴 뒤 빈 상자만 남아 카드
 * 아래에 71px이 떠 있었다(실측). :empty로 접는다. */
.pulse-strip .pulse-foot:empty,
.pulse-side .pulse-foot:empty { display: none; }

/* 이슈 갈래 — 제목 앞에 조용히. 출처 칩을 걷어낸 자리에 들어오므로
 * 그때만큼 무거우면 안 된다. 색은 주지 않는다(색은 등락과 액센트의 몫). */
.pulse-side .issue-tag {
  padding: 1px var(--sp-1h);
  background: color-mix(in srgb, var(--ink) 8%, transparent);
  border-radius: var(--r-sm);
  color: var(--ink-2); font-size: var(--fs-xs); font-weight: 600;
  text-align: center; white-space: nowrap;
}
/* 갈래가 없는 줄도 칸은 세운다 — 다만 빈 상자를 보여 주지는 않는다. */
.pulse-side .issue-tag:empty { background: none; padding: 1px 0; }

/* ======================================================================
   마감 — 대비 · 전이 · 여백 (2026-09-03)
   ====================================================================== */

/* 1) 본문은 본문 잉크로. 재 보니 `--ink-2`도 9.62:1이라 접근성 문제는
 *    아니었다 — 카드의 **본문**인데 보조 잉크를 입고 있던 것이 문제다.
 *    본문 --ink(16.43:1) · 라벨 --ink-3(6.09:1)로 층을 벌린다. */
.mood-points li { color: var(--ink); }
.pulse-say { color: var(--ink); }

/* 2) 한 칸 안의 간격을 하나로. 6·8·12px이 섞여 있었다 — 요소마다 margin을
 *    주면 다음 사람이 하나를 고칠 때 나머지와 어긋난다. */
.mood-market { gap: var(--sp-3); }
.mood-market-head { gap: var(--sp-1); }
.mood-points { margin: 0; }
.mood-market .pulse-chips { margin-top: 0; }

/* 3) 손이 닿는 것은 손이 닿았다고 말한다. 움직임은 아주 짧게 —
 *    이 화면에서 모션은 데이터의 사건일 때만 크다(DESIGN.md §2.6). */
.pulse-chip, .pulse-side .issue-row {
  transition: background-color .14s ease, color .14s ease;
}
.pulse-chip:hover { background: color-mix(in srgb, var(--ink) 12%, transparent); color: var(--ink-2); }
/* **반응은 누를 수 있는 줄만 한다.** 기사가 없는 줄까지 밝아지면 그건 다시
   거짓말이다(운영자 2026-09-08 "클릭도 안되는데 클릭될거같은 모션"). */
.pulse-side .issue-row.is-openable {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) {
  .pulse-side .issue-row.is-openable:hover .issue-title { color: var(--accent-text); }
}
/* 꼬리 칸 — 시각·NEW·▲▼와 펼침 표시가 한 칸을 나눠 쓴다.
 *
 * **오른쪽부터 채운다.** 격자 칸이라 이 상자는 줄마다 같은 폭으로 늘어나는데
 * (실측 390px: 다섯 줄 다 259~365), 안쪽이 왼쪽부터 차면 펼침 화살표가 **앞에
 * 오는 글자 길이만큼 밀린다.** 실측: x가 301·301·306·333·306으로 32px 어긋났고,
 * 「47분 전 ▼3」이 붙은 줄이 제일 멀리 갔다(운영자 제보 2026-09-09: "펼치기
 * 화살표들이 정렬이 안되고 삐뚤빼뚤이야 특히 4번").
 *
 * 화살표는 언제나 마지막 자식이므로, 끝에서부터 채우면 줄마다 같은 자리에 선다.
 * 시각도 오른쪽 맞춤이 되는데 그쪽이 맞다 — 세로선이 하나 서는 쪽이 목록으로
 * 읽힌다.
 *
 * 셰브런을 격자의 다섯 번째 칸으로 빼는 길은 이미 기각됐다(아래 `issue-tail`
 * 주석): 네 칸이 이미 차 있어 제 줄로 밀리고 접힌 줄마다 40px을 버린다. */
.pulse-side .issue-tail {
  display: inline-flex; align-items: center; justify-content: flex-end;
  gap: var(--sp-1h); white-space: nowrap;
}
/* 시각 옆에 설 때는 **알약을 벗는다.**
 *
 * 처음에는 세로로 쌓았다(꼬리 칸이 79 -> 117px로 넓어져 화살표 없는 줄의
 * 제목까지 밀리는 것을 피하려고). 그런데 쌓으니 "2시간 전" 밑에 알약이 하나
 * 더 붙어 두 덩이로 읽혔다(운영자 2026-09-09: "겹쳐서 안어울려 디자인도
 * 이상하고").
 *
 * 배경·여백을 걷으면 시각 옆의 색 글자가 된다 — 한 줄로 읽히고, 알약 여백이
 * 빠져 넓어지는 폭도 절반이다(실측: 117 -> 103px). NEW는 그대로 알약이고
 * 혼자 선다. */
.pulse-side .issue-move.issue-move-bare {
  background: none; padding: 0; border-radius: 0;
  font-size: var(--fs-xs);
}
/* 펼침 표시. 오른쪽 끝 시각·NEW 옆에 조용히 선다. */
/* **짚는 자리와 보이는 크기는 다른 것이다.**
   20×20으로 만들었다가 "잘 안 눌려"를 들었다(운영자 2026-09-08). 이 저장소가
   정한 바닥은 24×24(PRODUCT.md 접근성 · 2.5.8)이고 20은 그 밖이었다 —
   어제 화면을 재던 자의 TAP 규칙에 내가 걸렸다. 짚는 상자는 32로 키우고
   화살표는 6px 그대로 둔다. */
.pulse-side .issue-toggle {
  align-self: center; width: 32px; height: 32px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; cursor: pointer; color: var(--ink-3);
  border-radius: var(--r-sm);
}
.pulse-side .issue-toggle:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.pulse-side .issue-toggle::before {
  content: ""; display: block; width: 6px; height: 6px; margin: 0 auto;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform .18s ease;
}
.pulse-side .issue-row.is-open .issue-toggle::before { transform: translateY(1px) rotate(225deg); }
.pulse-side .issue-row.is-openable:hover .issue-toggle { color: var(--ink); }
/* 펼친 목록은 줄의 모든 칸을 가로지른다. **제목이 주인공이고 도메인은 뒤에
   흐리게** — 고르는 기준은 매체가 아니라 무엇을 말하는 기사인가다.

   제목 칸(`3 / -1`)에 맞추고 옅은 판을 깔아 봤다가 되돌렸다(운영자 2026-09-08:
   "이슈쪽은 전 디자인이 나아"). 글자 세로선은 정확히 맞았지만(제목 1051 ·
   첫 기사 1051) 목록이 좁아져 제목이 더 일찍 잘렸고, 판이 줄 안에 또 하나의
   상자를 만들었다. 재는 것으로는 안 갈리는 교환이라 실물을 본 사람이 정한다 —
   **다시 옮기기 전에 물어볼 것.** */
.pulse-side .issue-srcs {
  grid-column: 1 / -1; margin: 0;
  padding: 0 0 0 var(--sp-2); list-style: none;
  border-left: 2px solid var(--line);
  max-height: 0; opacity: 0; overflow: hidden; visibility: hidden;
  transform: translateY(-4px);
  transition: max-height .24s cubic-bezier(.16,1,.3,1), opacity .16s ease,
    transform .24s cubic-bezier(.16,1,.3,1), margin .24s ease;
}
.pulse-side .issue-srcs.is-visible {
  margin: var(--sp-2) 0 var(--sp-1); max-height: 720px;
  opacity: 1; visibility: visible; transform: none; overflow-y: auto;
}
/* **제목 한 줄 · 도메인 같은 줄 오른쪽.**
   앞 판은 제목이 3줄까지 흐르고 도메인이 제 줄을 하나 더 먹어, 네 건이면
   12줄이 같은 굵기로 쌓였다 — 고르라고 편 목록인데 고를 단서가 없었다
   (운영자 2026-09-08 "디자인도 너무 마음에 안들어").
   목록에서 읽는 것은 "무엇에 대한 기사인가"지 문장 전체가 아니다. */
.pulse-side .issue-src-item + .issue-src-item { border-top: 1px solid var(--line); }
.pulse-side .issue-src-link {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline; gap: var(--sp-2);
  min-height: 40px; padding: var(--sp-2) 0; text-decoration: none;
}
.pulse-side .issue-src-title {
  color: var(--ink); font-size: var(--fs-sm); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* 도메인은 "어디 기사인가" 한 마디다 — 제 줄을 주면 높이가 두 배가 된다. */
.pulse-side .issue-src-domain {
  color: var(--ink-3); font-size: var(--fs-xs); white-space: nowrap;
}
.pulse-side .issue-src-link:hover .issue-src-title { color: var(--accent); }
.pulse-side .issue-src-link:hover .issue-src-domain { color: var(--ink-2); }

/* 순위가 바뀌어도 한 이슈에 반응을 모은다. 별도 카드로 둘러싸지 않고 선 하나로
   목록과 나눈다 — 같은 이슈 판의 참여 영역이지 또 하나의 콘텐츠 카드가 아니다. */
.pulse-side .issue-spotlight {
  margin: 0 0 var(--sp-3); padding: 0 0 var(--sp-4);
  border-bottom: 1px solid var(--line);
}
.pulse-side .issue-spotlight[hidden] { display: none; }
.pulse-side .issue-sentiment {
  width: 100%;
}
.pulse-side .issue-sentiment-head { display: grid; gap: var(--sp-1h); }
.pulse-side .issue-sentiment-topic {
  margin: 0; color: var(--ink); font-size: var(--fs-md); font-weight: 700; line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pulse-side .issue-sentiment-question { margin: 0; color: var(--ink-3); font-size: var(--fs-xs); }
.pulse-side .issue-sentiment-options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); margin-top: var(--sp-2); }
.pulse-side .issue-sentiment-option {
  position: relative; isolation: isolate; overflow: hidden;
  min-height: 40px; padding: var(--sp-2) var(--sp-3);
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: transparent; color: var(--ink-2); cursor: pointer;
  font: inherit; font-size: var(--fs-xs); font-weight: 650;
  -webkit-tap-highlight-color: transparent;
}
.pulse-side .issue-sentiment-option::before {
  content: ""; position: absolute; z-index: -1; inset: 0 auto 0 0; width: var(--share, 0%);
  background: color-mix(in srgb, var(--tone) 15%, transparent);
}
.pulse-side .issue-sentiment-option.is-bull { --tone: var(--up); }
.pulse-side .issue-sentiment-option.is-bear { --tone: var(--down); }
.pulse-side .issue-sentiment-option:hover:not(:disabled) { border-color: var(--ink-3); color: var(--ink); }
.pulse-side .issue-sentiment-option[aria-pressed="true"] { border-color: var(--tone); color: var(--ink); }
.pulse-side .issue-sentiment-option:disabled { cursor: wait; opacity: .62; }
.pulse-side .issue-sentiment-option:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pulse-side .issue-sentiment-pct { color: var(--ink); font-variant-numeric: tabular-nums; }
.pulse-side .issue-sentiment-meta { margin: var(--sp-1h) 0 0; color: var(--ink-3); font-size: var(--fs-xs); }
.pulse-side .issue-sentiment-meta.is-error { color: var(--down); }
@media (prefers-reduced-motion: reduce) {
  .pulse-side .issue-toggle::before, .pulse-side .issue-srcs { transition: none; }
}
/* 줄 배경이 칸 가장자리까지 닿게 — 안쪽만 밝아지면 띠가 잘려 보인다. */
.pulse-side .issue-row {
  margin-inline: calc(-1 * var(--sp-2));
  padding-inline: var(--sp-2);
  border-radius: var(--r-sm);
}
.pulse-side .issue-row + .issue-row { border-top: 1px solid var(--line); }

@media (prefers-reduced-motion: reduce) {
  .pulse-chip, .pulse-side .issue-row { transition: none; }
}
}

}

/* 참고가 칸 — 공식값 자리가 아니라는 것이 한눈에 보여야 한다. */
.mood-ref-badge {
  align-self: center; margin-left: var(--sp-1h); padding: 1px var(--sp-1h);
  background: color-mix(in srgb, var(--amber) 16%, transparent);
  border-radius: var(--r-sm);
  color: var(--amber); font-size: var(--fs-xs); font-weight: 700; white-space: nowrap;
}
/* 날짜가 다른 칸의 그 날짜. 시장 이름 옆에 조용히 — 이름보다 크면 안 되고,
 * 안 보이면 두 칸이 같은 날인 줄 읽힌다. */
.mood-market-when {
  margin-left: var(--sp-1h);
  color: var(--ink-3); font-size: var(--fs-xs); font-weight: 600;
}
.mood-market-ref .mood-lead-pct { font-weight: 700; }

/* 참고가 한 줄 — 확정값 아래에 붙는다. 확정값과 무게를 겨루면 안 되므로
 * 크기는 작고, 대신 표식(참고가)이 색을 갖는다. */
.mood-ref-line {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1h);
  margin: 0; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.5;
}
.mood-ref-name { color: var(--ink-2); }
.mood-ref-pct { font-variant-numeric: tabular-nums; font-weight: 700; }
.mood-ref-pct.up { color: var(--up); }
.mood-ref-pct.down { color: var(--down); }
.mood-ref-pct.flat { color: var(--ink-3); }
.mood-ref-tail { color: var(--ink-3); }

/* 남는 높이를 **버리지 않고 쓴다** (2026-09-03).
 *
 * 이슈는 4~6개로 오가서 두 카드의 자연 높이가 매번 다르다. 바닥선을 맞추면
 * 늘 한쪽에 빈 면이 생기고, 그 자리가 회차마다 왼쪽↔오른쪽으로 옮겨 다녔다
 * (세 번 겪었다). 늘리기를 그만두면 바닥선이 어긋나고, 맞추면 빈 면이 남는다.
 *
 * 그래서 빈 면을 없애는 대신 **쓴다.** 칩 줄을 칸 바닥에 앉히면 남는 높이가
 * 문장과 칩 **사이 한 곳**으로 모인다 — 흩어진 여백이 아니라 한 칸의 숨이라
 * 의도한 것으로 읽힌다. 칩이 없는 칸은 문장이 그 자리를 갖는다. */
.mood-market > .pulse-chips { margin-top: auto; }

/* 참고가는 큰 숫자 바로 아래에 붙는다 (운영자 2026-09-04) — 카드 바닥이
 * 아니라 머리 안이다. "코스피 -3.99%"와 "오늘 코스피 200 +0.55%"는 같은
 * 질문에 답하므로 떨어져 있으면 안 된다. 바닥에 앉는 것은 이제 칩뿐이라
 * 둘이 남는 높이를 나눠 갖던 문제도 함께 사라졌다. */
.mood-market-head > .mood-ref-line { margin-top: var(--sp-1h); }

/* 높이를 카드 바닥까지 **잇는다.** 칩에 margin-top:auto를 줘도 그 칸이
 * 카드 높이만큼 서 있지 않으면 밀 자리가 없다 — 실측에서 칸은 504px에서
 * 끝나는데 카드는 627px이었다. 체인: 카드 → 본문 → 목록 → 행 → 칸. */
.pulse-strip > .pulse-body { display: flex; }
/* 목록은 **세로**다. 남은 문장 줄(`.mood-say`)이 생기면 가로 flex에서는 그것이
 * 시장 줄 옆에 서 버린다 — 칸을 빼앗기던 병이 자리만 옮겨 되풀이된다. */
.mood-list { flex: 1 1 auto; display: flex; flex-direction: column; }
.mood-row { flex: 1 1 auto; }
/* 비면 자리도 없다 — 한국어에는 남은 문장이 없고 영어에만 있는 회차가 있다. */
.mood-say:not(:empty) { margin-top: var(--sp-3); }

/* ======================================================================
   칩은 배경으로 서고, 선을 두르지 않는다 (2026-09-03)

   실측(1240px, 보이는 테두리만): /us는 상자 340개 중 **307개가 겹쳐** 있었고
   대부분이 칩이었다(status-badge 89 · hint-chip 44 · ticker-mark 30 ·
   ev-kind 30 · ev-by-mark 28). 배경이 이미 모양을 만드는데 그 위에 선을 한
   겹 더 두른 것이다.

   진짜 카드(.metric-card · .cvol-card · .cboard-card)는 그대로 둔다 —
   면이 하나뿐인 것은 상자가 아니라 카드다.
   ====================================================================== */

/* `.hint-chip` · `.ev-kind` · `.ev-by-mark`는 monitor.css에만 있는 클래스라
 * 여기서 덮으면 두 파일에 걸치게 된다(test_stylesheet_split이 막는다).
 * 새 규칙이 아니라 있는 선언을 고치는 일이므로 원래 자리에서 걷었다. */
.ticker-mark,
.usm-badge,
.coin-tag,
.status-badge,
/* 변형은 각자 테두리 색을 갖는다(monitor.css) — 더 구체적이라 위 규칙을
 * 이긴다. 넷 다 이미 14% 배경을 깔고 있어 선은 덤이었다(실측: /us에
 * 89개가 남아 있었다). */
.status-badge.fresh,
.status-badge.stale,
.status-badge.warn,
.status-badge.info,
.status-badge.error { border-color: transparent; }

/* 배경이 없던 칩만 배경을 준다 — 테두리를 걷으면 사라지기 때문이다.
 * (주황 알약 셋이 나란히 서면 소음이라 선만 남겼던 자리다. 조용함은
 *  선이 아니라 낮은 대비에서 온다.) */
.risk-strip .status-badge {
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  border-color: transparent;
}

/* 손이 닿는 것은 닿았다고 말한다 — 홈과 같은 0.14s. */
.ticker-mark, .status-badge,
.accessible-table tbody tr, .kridx-table tbody tr {
  transition: background-color .14s ease, color .14s ease;
}
.accessible-table tbody tr:hover,
.kridx-table tbody tr:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); }
a.ticker-mark:hover { background: color-mix(in srgb, var(--ink) 12%, transparent); }

@media (prefers-reduced-motion: reduce) {
  .ticker-mark, .status-badge,
  .accessible-table tbody tr, .kridx-table tbody tr { transition: none; }
}

/* 이슈 칸의 자리는 **넷으로 잡아 둔다** (2026-09-03).
 *
 * `slice(0, 4)`는 상한이라 없는 것을 만들지 못한다. 레인이 주는 수는 재료와
 * 검증 문턱에 따라 2~6개로 오간다(실측: 재료 61개에 통과 2개인 회차도 있다).
 * 그때마다 카드 높이가 달라지면 옆 칸과의 관계가 회차마다 흔들린다.
 *
 * 그래서 **수가 아니라 자리를 고정한다.** 넷이 설 높이를 늘 잡아 두면
 * 둘이 와도 카드가 줄지 않는다. 남는 자리는 "오늘은 둘뿐"이라는 사실이지
 * 레이아웃 사고가 아니다 — 그리고 그 자리는 늘 같은 곳에 있다.
 *
 * 한 줄 47px 실측(제목 한 줄 + 위아래 12px). 두 줄짜리 제목이 오면 그만큼
 * 늘어난다 — min이라 위로만 열린다. */
.pulse-side .issue-list { min-height: calc(4 * 47px); }

/* 어제 장이 못 서는 날, 이슈가 폭을 다 쓰면 **구멍이 카드 안으로 옮겨 온다.**
 *
 * 실측(1280px, 2026-09-07): 카드 1233px에서 제목은 300px에서 끝나는데
 * "6시간 전"은 1230px에 붙는다 — 그 사이가 통째로 빈다. 늘리는 것은 빈칸을
 * 없앤 게 아니라 옮긴 것이다.
 *
 * 그래서 넓어지면 **두 단으로 접는다.** 네 줄이 두 줄이 되고 한 줄이 약
 * 600px을 쓴다 — 제목과 시각이 서로를 놓치지 않는 폭이다. 좁은 화면은
 * 손대지 않는다: 거기서는 한 단이 이미 옳고, 애초에 이 사고가 안 보였던
 * 이유도 그것이다.
 *
 * 순서는 왼→오른쪽이다(1 2 / 3 4). 아래로 읽히게 하려면 줄 수를 알아야
 * 하는데 이슈 개수는 매번 다르다 — 모르는 것에 기대는 규칙은 안 만든다.
 *
 * 문턱은 680px이다. 어느 문턱을 잡든 **그 바로 아래**에 한 단이 제일 넓어지는
 * 폭이 생기므로(900으로 뒀을 때 899px에서 한 줄이 834px였다), 두 단이 원래
 * 카드 폭(300~400px)을 지키는 가장 낮은 자리로 내렸다 — 680px에서 한 단은
 * 305px이다. 그 아래는 한 단이 650px을 안 넘는다. */
/* **형제가 아니라 자기 폭으로 정한다.** 전에는 "어제 장이 숨었으면 넓겠지"로
   추측했는데(`:has()`), 그 추측은 띠가 이름 붙인 영역을 버리는 순간 틀렸다.
   카드에 컨테이너를 걸고 카드가 실제로 넓을 때만 두 단으로 간다.
   문턱 620px은 한 단이 300px 아래로 눌리지 않는 가장 낮은 자리다. */
.home-lede > .pulse-side { container-type: inline-size; container-name: issuecard; }
@container issuecard (min-width: 620px) {
  .pulse-side .issue-list {
    grid-template-columns: 20px auto minmax(0, 1fr) auto var(--sp-5) 20px auto minmax(0, 1fr) auto;
    /* 두 줄이면 충분하다 — 네 줄치를 잡아 두면 아래가 그만큼 빈다. */
    min-height: calc(2 * 47px);
  }
  .pulse-side .issue-row:nth-child(odd) { grid-column: 1 / 5; }
  .pulse-side .issue-row:nth-child(even) { grid-column: 6 / 10; }
  /* 오른쪽 단의 첫 줄은 위에 아무것도 없다 — 선을 그으면 왼쪽 단과 어긋난다. */
  .pulse-side .issue-row:nth-child(2) { border-top: 0; }

  .pulse-side .issue-pulse-body {
    display: grid; grid-template-columns: minmax(0, 1.45fr) minmax(260px, .8fr);
    align-items: stretch; gap: var(--sp-5);
  }
  .pulse-side .issue-spotlight {
    grid-column: 2; grid-row: 1; margin: 0; padding: var(--sp-1) 0 var(--sp-1) var(--sp-5);
    border-bottom: 0; border-left: 1px solid var(--line);
    display: flex; align-items: center;
  }
  .pulse-side .issue-spotlight[hidden] { display: none; }
  .pulse-side .issue-pulse-body .issue-list {
    grid-column: 1; grid-row: 1;
    grid-template-columns: auto auto minmax(0, 1fr) auto;
    min-height: calc(4 * 47px);
  }
  .pulse-side .issue-pulse-body .issue-row:nth-child(n) { grid-column: 1 / -1; }
  .pulse-side .issue-pulse-body .issue-row:nth-child(2) { border-top: 1px solid var(--line); }
}

/* ======================================================================
   서랍 안의 서랍은 카드가 아니라 줄이다 (2026-09-03)

   /kr 물밑 카드는 값 아래에 넷을 쌓고 있었다 — 용어 링크줄 · 근거 표 ·
   출처 문단 · 계산법 서랍. 홈과 /us는 이미 칩 + 서랍 하나인데 이 카드만
   그대로였다. 셋을 서랍 안으로 접었는데, `.disclose`는 면과 선을 갖고
   있어서 그대로 넣으면 상자 안에 상자가 선다. 안쪽은 면을 벗고 윗선
   하나로만 갈린다 — 칩에서 테두리를 걷은 것과 같은 이유다.
   ====================================================================== */

.disclose .disclose-body > .disclose {
  margin-top: var(--sp-3);
  border: 0; border-top: 1px solid var(--line); border-radius: 0;
  background: none;
}
.disclose .disclose-body > .disclose > summary,
.disclose .disclose-body > .disclose .disclose-body { padding-left: 0; padding-right: 0; }

/* 용어줄과 출처는 서랍 본문의 마지막 두 줄이다 — 본문과 같은 잉크로 두면
   설명이 어디서 끝나는지 안 보인다. */
.disclose .disclose-body > .term-hints { margin: var(--sp-3) 0 0; }
.disclose .disclose-body > .kro-footer { margin-top: var(--sp-3); }

/* 머리에서 내려온 문장 (2026-09-03). `.console-sub`는 `.console-head` 안에서만
   꼴을 받고 있었는데, 홈에선 이 문장이 값 위 h1 아래로 내려왔다.

   `.section-copy`를 쓰지 않았다 — 그 클래스에는 근거·권리 문구가 섞여 있어
   모드로 감추면 고지가 사라지고, test_reading_modes가 그것을 막는다. 이 문장은
   제품의 전제일 뿐이라 쉬움 모드에만 둔다. */
.home-values > .console-sub {
  margin: 4px 0 var(--sp-4); color: var(--ink-2); font-size: var(--fs-sm);
}

/* 딱지를 뗀 갱신 값 — 이제 줄 전체라 굵을 이유가 없다. */
.console-meta .updated-at { font-weight: 500; }

/* 뉴스 줄의 종목 칩 (운영자 2026-09-03).
   코드만 있고 이름이 없었고("000660 −4.73%"), 이름과 값이 붙어 있어
   한 낱말처럼 읽혔다. 이름은 중립 잉크로 앞에 서고, 값만 등락 색을
   입는다 — 붉은 회사 이름은 회사가 붉다는 말처럼 읽힌다. */
/* **줄이 좁아지면 이름이 접힌다 — 숫자는 안 접힌다.**
 * 날짜가 들어와 칩이 한 조각 길어졌다. `flex: 0 0 auto`(monitor.css)면 칸을
 * 넘어서라도 안 줄어들어, 360px에서 12px을 삐져나갔다(실측 2026-09-08).
 * 줄어들 수 있게 열고, 줄어드는 몫은 **이름**에만 준다 — 날짜 없는 퍼센트나
 * 퍼센트 없는 날짜는 반쪽 사실이라 자를 수 없다. */
.feed-move { display: inline-flex; align-items: baseline; gap: var(--sp-1h);
  flex: 0 1 auto; min-width: 0; max-width: 100%; }
.feed-move-name { font-weight: 700; color: var(--ink-2);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 값이 아니라 값에 붙은 이름표다 — 등락색을 따라가지 않는다. */
.feed-move-when { font-style: normal; font-weight: 600; color: var(--faint); flex: 0 0 auto; }
.feed-move-pct { font-weight: 700; flex: 0 0 auto; }

/* 줄 길이를 고르게 (운영자 2026-09-03, 세 번째 지적).
 *
 * 선은 실측으로 정중앙이다(줄의 가운데 1065px · 선 1065px · 어긋남 0, 두 칸
 * 너비 399/399). 그런데도 오른쪽으로 밀려 보이는 것은 **잉크** 때문이다:
 * 왼쪽 문단은 한 줄이 일찍 꺾여 오른쪽에 큰 구멍을 남기고, 오른쪽 문단은
 * 상자 끝까지 찬다. 가운데를 눈이 잉크로 재니 선이 오른쪽에 있는 것처럼
 * 읽힌다.
 *
 * 상자는 이미 대칭이므로 고칠 것은 줄바꿈이다. `text-wrap: balance`는 두세
 * 줄짜리 문단의 줄 길이를 고르게 나눠 그 구멍을 없앤다. 못 알아듣는
 * 브라우저에서는 지금과 같다 — 잃는 것이 없다. */
.mood-points li, .mood-line, .pulse-say .mood-line { text-wrap: balance; }

/* **낱말 가운데서 끊지 않는다** (운영자 지적 2026-09-04).
 *
 * 브라우저 기본값(`word-break: normal`)은 한글을 음절 단위로 끊는다 — 라틴 문자와
 * 달리 한글은 어디서나 줄을 바꿔도 되는 글자로 취급되기 때문이다. 그래서 "국채
 * 금리가 내린"이 "국채 금리 / 가 내린"으로 잘렸다. `keep-all`은 띄어쓰기에서만
 * 끊는다. 대신 한 낱말이 칸보다 길면 넘치므로 `overflow-wrap`을 안전판으로 둔다. */
.mood-points li, .mood-line, .pulse-say .mood-line {
  word-break: keep-all; overflow-wrap: break-word;
}

/* 두 칸의 칩이 **같은 줄에 서게** (운영자 2026-09-03).
 *
 * 두 칸을 따로 세우고 각자 바닥에 붙이면, 바닥에 붙는 덩이의 높이가 달라서
 * 칩 줄의 높이가 어긋난다 — 실측에서 헬스케어가 반도체 5종보다 11px 위에
 * 있었다(왼쪽은 칩 두 줄, 오른쪽은 칩 한 줄 + 참고가 한 줄).
 *
 * 칸마다 바닥을 재는 대신 **줄 자리를 함께 쓴다.** `subgrid`로 두 칸이
 * 같은 행 트랙에 올라타면 제목·문장·칩·참고가가 각각 같은 높이에 선다.
 * 가운데 1fr 트랙이 남는 높이를 먹어 칩 덩이를 아래로 민다. */
@media (min-width: 901px) {
  .mood-row { grid-template-rows: auto auto 1fr auto; }
  .mood-market {
    display: grid; grid-row: 1 / -1; grid-template-rows: subgrid; gap: 0;
  }
  .mood-market > .mood-market-head { grid-row: 1; }
  .mood-market > .mood-points { grid-row: 2; margin: var(--sp-3) 0 0; }
  /* 칩 줄은 **위에 붙는다.** 두 칸이 같은 행 트랙을 쓰는데, 왼쪽이 두 줄이면
   * 트랙도 두 줄 높이가 된다. 격자는 기본이 늘리기라 오른쪽 칩 하나가 그
   * 높이를 혼자 다 먹어 상자가 커졌다(운영자 지적 2026-09-03). */
  /* 참고가가 머리로 올라가면서 줄이 넷으로 줄었다 — 칩이 마지막이고,
   * 두 칸이 같은 높이에서 바닥에 붙는다는 결론은 그대로다. */
  .mood-market > .pulse-chips {
    grid-row: 4; margin-top: var(--sp-3);
    align-content: flex-start; align-items: flex-start;
  }
}

/* 줄어들 수 있어야 넘치지 않는다 (2026-09-03, 폰 실측).
 *
 * 390px에서 문서가 493px이 됐다 — 가로로 스크롤되고 손가락에 확대가 잡혔다.
 * 범인은 칩 줄이다. `.pulse-chips`는 `overflow-x: auto`를 갖고 있지만, 플렉스
 * 항목의 기본 `min-width: auto`가 **안쪽 내용의 최소 너비를 위로 밀어 올린다.**
 * 칩 넷이 한 줄에 464px이라 그 값이 .mood-market → .mood-row → .mood-list를
 * 차례로 464px로 만들었고, 카드(317px)를 뚫고 나갔다.
 *
 * 사슬 전체에 `min-width: 0`을 주면 각자 줄어들 수 있고, 그제야 칩 줄의
 * `overflow-x: auto`가 제 일을 한다. `.pulse-strip`에는 이미 있던 규칙인데
 * 안쪽 사슬이 빠져 있었다. */
.mood-list, .mood-row, .mood-market, .pulse-chips, .mood-points { min-width: 0; }

/* 첫 제목은 띠 바로 아래에서 시작한다 (운영자 2026-09-04: "공백이 너무 커").
 *
 * 폰 실측(390px): 띠가 126px에서 끝나는데 첫 제목이 182px에서 시작했다 —
 * 셸의 위 여백(32px)에 제목 자신의 위 여백(24px)이 더해진 값이다. 두 여백은
 * 서로를 모른 채 각자 자기 몫을 주장한다.
 *
 * 셸의 여백은 남기고(값과 화면 끝이 붙으면 답답하다) **첫 아이의 위 여백만**
 * 걷는다. 쪽마다 첫 아이가 다르므로(제목·섹션·칩) 종류를 가리지 않는다. */
.shell > :first-child { margin-top: 0; }
/* 첫 섹션이 참고 등급이면 머리에 잔선과 위 여백이 붙는다 — 맨 위에서는
   가를 것이 없으므로 둘 다 걷는다(폰 실측 178 → 158px). */
.shell > .console-section:first-child { padding-top: 0; }
.shell > .console-section:first-child > header { padding-top: 0; border-top: 0; }
.shell > :first-child .lede-title:first-child,
.shell > :first-child > .console-section:first-child { margin-top: 0; }

/* ======================================================================
 * 손가락이 닿는 크기 (2026-09-04 감사)
 *
 * 390px 실측에서 44px 미만 인터랙티브 요소가 페이지당 118~303개였다. 이
 * 제품의 1순위 사용자는 마감 후·주말에 **폰으로** 오는 사람이라 여기가
 * 실제 사용 장면이다.
 *
 * 밀도는 이 제품의 성격이므로 **보이는 크기는 그대로 두고 닿는 자리만**
 * 넓힌다. 좁은 화면에서만 적용해 데스크톱의 촘촘함은 잃지 않는다.
 * 문단 안 인라인 링크는 건드리지 않는다(WCAG 2.5.8의 inline 예외).
 * ====================================================================== */
/* 세그먼티드는 밑줄 컨트롤이라 눌림에서 빠진다. 4% 줄이면 밑줄이 칸보다
   짧아져 "선택된 칸"의 폭이 흔들린다 — 줄어드는 것이 상태를 말하는 선이면
   그 선을 건드리지 않는다. 대신 글자가 잉크로 올라온다. */
.segmented button:active { color: var(--ink); }

@media (max-width: 560px) {
  /* 달력 이동 버튼: 30×30 → 44×44 */
  .cal-step, .cal-jump { min-width: 44px; height: 44px; }

  /* 기간·정렬 토글, 그리고 쉬움/전문가 토글: 높이 29 → 44.
     둘은 같은 꼴인데 클래스가 다르다(.segmented / .mode-switch). */
  .segmented button { min-height: 44px; }

  /* 마스트헤드 컨트롤 */
  .icon-button, .refresh-button { min-height: 44px; min-width: 44px; }
  .brand { min-height: 44px; }
  /* `.site-search-input`은 monitor.css가 이미 정의한다 — 여기 쓰면 같은
     클래스가 두 파일에 걸리고 어느 쪽이 이기는지 읽는 사람이 알 수 없다
     (tests/frontend/test_stylesheet_split.py). 그 규칙은 monitor.css의 560px 블록에. */

  /* 푸터 내비: 글자 위치는 그대로, 위아래로만 자리를 넓힌다.
   *
   * 44는 AAA(2.5.5)라 이 밀도에서 목록을 두 배로 늘린다 — 이 파일이 24px을
   * 바닥으로 고른 이유가 바로 그것인데(monitor.css의 손가락 자리 주석) 꼬리말
   * 에서만 44로 되돌아가 있었다. 그 결과 링크 상자가 44px씩 쌓여, 글자는
   * 19px인데 줄 사이가 52px이 됐다 — 링크 줄 · 링크 줄 · contact · 고지
   * 네 덩이가 서로 떨어져 보인 것이 이것이다(운영자 제보 2026-09-06).
   *
   * 32로 내린다. WCAG 2.2 AA(2.5.8)의 24를 8px 여유로 넘고, 줄 사이는
   * 52 → 40px이 된다. 보이는 글자 크기는 그대로다. */
  .site-footer nav { gap: var(--sp-2) var(--sp-4); }
  .site-footer nav a {
    display: inline-flex; align-items: center; min-height: 32px;
  }

  /* 뷰 탭은 이미 57px이라 그대로 둔다. */
}

/* 공시 판정 칩 (2026-09-07)
   =======================================================================
   호재·악재는 이 사이트가 값에 쓰는 색과 같은 뜻이다 — 오른 쪽과 내린 쪽.
   다른 색을 새로 만들면 같은 화면에서 두 벌의 색 언어가 돌아간다.

   **글자는 신호색을 입지 않는다.** 액센트 글자를 워시에 얹어 4.10:1이 됐던
   자리가 이 저장소에 이미 있다(world.css §칩). 색은 왼쪽 3px 띠가 들고
   글자는 `--ink`로 둔다 — 대비는 14:1이고 눈은 띠에서 방향을 읽는다.

   중립은 색이 없다. 판정이 "어느 쪽도 아니다"인데 색을 주면 그것도 신호가 된다. */
.ev-tone {
  display: inline-flex; align-items: center;
  margin-right: var(--sp-2); padding: 1px var(--sp-2);
  border-left: 3px solid var(--line); border-radius: var(--r-sm);
  background: var(--panel-2); color: var(--ink);
  font: 700 var(--fs-xs)/1.5 var(--sans); white-space: nowrap; vertical-align: 2px;
}
/* 국내 목록에서는 **1행**(`.ev-head`)에 선다(2026-09-16). 거기서는 이 규칙의
   `margin-right`도 `vertical-align`도 아무 일을 안 한다 — 그 줄은 flex라 사이는
   `gap`이 만들고 정렬은 baseline이 맡으며, 칩 오른쪽에 오는 `.ev-meta`는
   `margin-left: auto`로 이미 끝까지 밀려 있다. 그래서 덮어쓰지 않는다.

   덮어쓰려면 `.ev-head .ev-tone`이라 써야 하는데, 그러면 `ev-head`가 두 파일에
   걸친다(`tests/frontend/test_stylesheet_split.py`가 그걸 막는다 — 한 클래스가
   두 파일에 나뉘면 어느 쪽이 이기는지 읽는 사람이 알 수 없다). */
.ev-tone-favourable { border-left-color: var(--up); }
.ev-tone-adverse { border-left-color: var(--down); }
/* `지분 희석`은 방향이 아니라 사실이라 **색을 안 든다** — 위 규칙("중립은 색이
   없다")이 그대로 선다. 기본 `--line` 띠를 그대로 쓰므로 선언이 따로 필요하진
   않지만, 다음 사람이 "빠뜨렸나" 하고 색을 채우지 않도록 여기 적어 둔다. */
.ev-tone-dilution { border-left-color: var(--line); }

/* 칩 앞머리 — 어느 장의 값인가 (2026-09-07)
   어제 장 카드를 하나로 합치면서 미국·국내 지표가 한 줄에 섞였다. 이름만으로는
   "커뮤니케이션서비스"가 어느 장인지 알 수 없다. 값보다 작고 흐리게 둔다 —
   읽는 순서는 여전히 이름 → 값이고, 이건 그 앞의 꼬리표다. */
.pulse-chip-market {
  margin-right: 5px; color: var(--faint);
  font: 700 var(--fs-xs)/1 var(--sans); font-style: normal; letter-spacing: .02em;
}

/* 세 칸은 **넓을 때만** 선다 (실측 2026-09-07).
 *
 * 1024px에서 셋을 나란히 세웠더니 어제 요약이 **285px**로 눌렸다 — 그 폭에는
 * 문장이 안 들어간다. 중간 폭에서는 요약이 한 줄을 다 쓰고, 비상장과 이슈가
 * 그 아래 나란히 선다. 폰은 셋 다 세로다.
 *
 *     ≥1180px   요약 | 비상장 | 이슈
 *     901~1179  요약
 *               비상장 | 이슈
 *     ≤900px    셋 다 세로
 */
/* 3열의 하한은 **칩이 들어가는 폭**이다 (2026-09-07).
 *
 * 셋이 똑같이 나눠 갖게 되면서 어제 요약이 496 → 419px가 됐다. 1440·1280px은
 * 여유가 있는데 1180px에서 카드가 367px이 되자 "국내 EWY (한국 ETF) +4.73%"이
 * 11px 넘쳤다 — 칩은 `nowrap`이라 줄이 안 바뀌고 그냥 삐져나온다.
 *
 * 그 폭에서는 3열을 포기하는 편이 낫다. 두 줄 배치는 이미 있고, 어제 요약이
 * 전폭을 쓰므로 칩이 편하다. 문턱을 1180 → 1280으로 올린다. */
@media (max-width: 1279px) {
  .home-lede { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 어제 요약은 칩이 `nowrap`이라 좁은 칸에서 삐져나온다 — 한 줄을 다 준다.
     `1 / -1`은 몇 장이 서 있든 맞는다. 이름 붙인 영역과 달리 조합을 안 센다. */
  .home-lede > .pulse-strip { grid-column: 1 / -1; }
}
@media (max-width: 900px) {
  .home-lede { grid-template-columns: minmax(0, 1fr); }
}

/* 홈 첫 요약은 세 카드가 아니라 하나의 흐름으로 읽힌다. 바깥 면 하나 안에서
 * 내용 종류만 가는 선으로 나눈다. */
.home-lede {
  gap: 1px; overflow: hidden; padding: 0;
  background: var(--line); border: 1px solid var(--line); border-radius: var(--r-lg);
}
.home-lede > .pulse-strip, .home-lede > .pulse-side {
  margin: 0; border: 0; border-radius: 0; background: var(--panel);
}
/* 어제 장과 비상장 패널이 모두 비면 이슈 혼자 세 칸 중 하나에 갇히지 않는다.
   이때만 바깥 판 전체를 쓰고, 안에서는 목록과 12시간 투표가 나란히 선다. */
.home-lede:not(:has(> .pulse-strip:not([hidden]))):not(:has(> #home-private:not([hidden])))
  > #live-issues:not([hidden]) { grid-column: 1 / -1; }
.home-lede .hp-tiles { gap: 0; }
.home-lede .hp-tiles .tile {
  padding: var(--sp-3) 0; border: 0; border-radius: 0; background: transparent;
}
.home-lede .hp-tiles .tile + .tile { border-top: 1px solid var(--line); }

@media (max-width: 900px) {
  .home-lede { gap: 1px; }
}

/* --- 두 번째 줄: 오늘의 질문과 한 마디 -------------------------------------
 *
 * 운영자 아이디어(2026-09-10): "투자자 명언도 보여주면 좋을거같아 … 오늘이나
 * 내일 또는 이번주 경제 이벤트가 뭐있는지 정도도 같이".
 *
 * 위 세 칸 띠에 끼우지 않는다 — 셋이 같은 폭 · 같은 바닥선으로 서도록 여러 번
 * 맞춘 자리다(2026-09-07). 아래에 한 줄을 더 두고, 넓은 화면에서는 위 띠의 세
 * 기둥에 맞춘다(말이 두 칸 · 일정이 한 칸). 좁아지는 문턱도 위 띠와 같다. */
.home-aside {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-5);
  align-items: stretch;
  margin-bottom: 0;
}
.home-aside:not(:has(> :not([hidden]))) { display: none; }
#home-quote {
  grid-column: auto; padding: var(--sp-5) 0 0;
  background: transparent; border: 0; border-radius: 0;
}
.home-aside #home-quote > header { margin-bottom: var(--sp-4); }
.home-aside .pulse-foot {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 2px var(--sp-2);
}

/* 공용 disclose 규칙보다 뒤에서 홈 캘린더의 평평한 행을 확정한다. */
.calendar-panel .cal-all, .calendar-panel .er-more {
  margin: 0; border: 0; border-top: 1px solid var(--line); border-radius: 0; background: transparent;
}
.calendar-panel .cal-all > summary, .calendar-panel .er-more > summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  min-height: 48px; padding: 0 var(--panel-inset); color: var(--ink-2);
  font-size: var(--fs-sm); font-weight: 600; list-style: none;
}
.calendar-panel .cal-all > summary::before,
.calendar-panel .er-more > summary::before { display: none; }
.calendar-panel .cal-all > summary::after,
.calendar-panel .er-more > summary::after {
  content: ""; width: 14px; height: 14px; flex: none; background: currentColor;
  mask: var(--ico-caret) center / contain no-repeat; transition: transform 160ms ease-out;
}
.calendar-panel .cal-all[open] > summary::after,
.calendar-panel .er-more[open] > summary::after { transform: rotate(180deg); }

/* 말 — 한국어 화면은 우리말을 크게, 원문을 작게 그 아래에. 옮긴 말만 있으면
   원문을 확인할 길이 없다. 영어 화면은 원문만 싣는다. */
.hq-figure { margin: 0 0 var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); }
.hq-said {
  margin: 0; max-width: 54ch; color: var(--ink); font-size: clamp(var(--fs-lg), 2vw, var(--fs-xl)); font-weight: 600; line-height: 1.55;
  word-break: keep-all; overflow-wrap: anywhere;
}
.hq-said::before { content: "\201C"; }
.hq-said::after { content: "\201D"; }
.hq-original { margin: 0; color: var(--ink-3); font-size: var(--fs-sm); line-height: 1.5; font-style: italic; }
.hq-who { color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.5; }
.hq-who strong { color: var(--ink); font-weight: 600; }
.hq-who a { color: inherit; text-underline-offset: 2px; }
/* 리그 자리 — 카드 아래끝에 붙는다. 말이 짧은 날에도 줄의 자리가 같다.
   숫자만 색을 입힌다 — 문장 전체가 붉거나 푸르면 등락이 아니라 경고로 읽힌다. */
.hq-seat {
  display: block; margin-top: auto; padding: var(--sp-2) var(--sp-3);
  background: var(--panel-2); border-radius: var(--r-sm);
  color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.5; text-decoration: none;
  /* "12자리 중 / 5위 →"처럼 끝 낱말 하나가 혼자 떨어졌다(390px 실측). */
  word-break: keep-all; text-wrap: pretty;
}
.hq-seat:hover { color: var(--ink); }
.hq-seat b { font-variant-numeric: tabular-nums; }
.hq-seat .up { color: var(--up); }
.hq-seat .down { color: var(--down); }
/* 알고 계셨나요 — 표에서 계산한 팩트 한 줄(investor_facts.py). */
.hq-fact { margin: var(--sp-2) 0 0; color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.5; word-break: keep-all; }
.hq-fact b { margin-right: var(--sp-1h); color: var(--accent); font-weight: 650; }

/* 홈은 섹션을 얇은 선으로 반복해서 자르지 않는다. 카드와 패널이 이미 내용의
 * 경계를 말하므로, 섹션 사이는 일정한 공백 하나만 쓴다. */
.page-landing .console-section[data-rank] { margin-top: var(--sp-6); }
.page-landing #constituent-heatmap { margin-top: var(--sp-3); }
.page-landing .console-section:not([data-rank="lead"]) > header {
  padding-top: 0; border-top: 0;
}

/* --- 오늘의 질문 (questions.py) ----------------------------------------------
 *
 * 운영자 아이디어(2026-09-11). 두 번째 줄의 맨 위 한 칸을 통째로 쓰고, 안에서 질문을
 * 나란히 세운다(넓으면 셋, 좁으면 하나씩). 보기 단추가 곧 막대다 — 고르기 전에는 빈
 * 단추, 고른 뒤에는 같은 자리에 분포가 차오른다. 자리가 바뀌지 않으니 누른 손가락
 * 밑에서 화면이 밀리지 않는다. */
#home-ask { grid-column: 1 / -1; }
.ask-list {
  display: grid; gap: var(--sp-3) var(--sp-4);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
/* 나란히 선 질문끼리 제목 · 설명 · 첫 단추가 같은 높이에 선다 — 한 칸이 목록의 세 줄을
   나눠 쓴다(subgrid). 바닥 맞춤(`margin-top: auto`)으로 두었더니 보기가 둘인 코스피의
   첫 단추가 옆 칸보다 50px 아래에 섰다(1440px 실측). 셋째 줄은 보기와 안내 줄을 한
   상자(.ask-body)로 받는다 — 둘을 따로 두면 보기가 적은 칸에서 둘 사이가 벌어진다.
   subgrid를 모르는 브라우저는 세 줄을 그냥 쌓는다. */
.ask-item {
  display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: var(--sp-2);
  min-width: 0; padding-top: var(--sp-2); border-top: 1px solid var(--line);
}
.ask-q {
  grid-row: 1; margin: 0; color: var(--ink); font-size: var(--fs-md); font-weight: 650;
  line-height: 1.45; word-break: keep-all; overflow-wrap: anywhere;
}
/* 둘째 줄은 설명과 AI의 답을 한 상자로 받는다 — AI 줄이 있는 칸과 없는 칸이 나란히
   서도 셋째 줄(단추)은 같은 높이에서 시작한다. */
.ask-sub { grid-row: 2; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ask-detail { margin: 0; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.5; word-break: keep-all; }
/* AI의 답 — 참여자의 분포가 아니라 맞상대의 패라 고르기 전에도 보인다. 문장이라 색은 없다. */
.ask-ai {
  margin: 0; color: var(--ink-2); font-size: var(--fs-xs); line-height: 1.5;
  font-variant-numeric: tabular-nums; word-break: keep-all;
}
.ask-body { grid-row: 3; align-self: start; display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.ask-options { display: grid; gap: var(--sp-1h); }
.ask-options.is-pair { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.ask-option {
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  width: 100%; min-height: 44px; padding: 0 var(--sp-3);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--panel-2); color: var(--ink);
  font: inherit; font-size: var(--fs-md); line-height: 1.3; text-align: left; cursor: pointer;
}
.ask-option:hover:not(:disabled) { border-color: var(--accent); }
.ask-option:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ask-option:disabled { cursor: default; }
/* 고른 것은 동작색(선택)으로 말한다 — 테두리와 굵기. 글자는 늘 잉크다. */
.ask-option[aria-pressed="true"] { border-color: var(--accent); font-weight: 700; }
/* 막대는 단추 안의 면이다. 새 틴트면이므로 잉크 대비를 다시 쟀다(Tinted-Surface Rule). */
.ask-fill {
  position: absolute; inset: 0 auto 0 0; z-index: -1; width: var(--share, 0%);
  background: color-mix(in srgb, var(--ink-3) 24%, transparent);
  transition: width 420ms ease-out;
}
.ask-option[aria-pressed="true"] .ask-fill { background: color-mix(in srgb, var(--accent) 28%, transparent); }
@media (prefers-reduced-motion: reduce) { .ask-fill { transition-duration: 1ms; } }
.ask-label { min-width: 0; overflow-wrap: normal; word-break: normal; }
.ask-glyph { margin-right: var(--sp-1h); font-size: var(--fs-xs); }
.ask-glyph.up { color: var(--up); }
.ask-glyph.down { color: var(--down); }
.ask-result { display: inline-flex; flex: none; align-items: baseline; gap: 5px; white-space: nowrap; }
.ask-pct { font-variant-numeric: tabular-nums; font-weight: 700; }
.ask-votes { color: var(--ink-3); font-size: var(--fs-xs); font-weight: 500; font-variant-numeric: tabular-nums; }
.ask-meta { margin: 0; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.5; word-break: keep-all; }
.ask-past { margin-top: var(--sp-3); padding-top: var(--sp-2); border-top: 1px solid var(--line); }
.ask-past-title { margin: 0 0 var(--sp-1h); color: var(--ink-3); font-size: var(--fs-xs); font-weight: 700; }
/* 지난 결과도 위 질문과 같은 칸으로 선다. 한 줄에 질문 · 결과를 양 끝으로 벌렸더니
   1440px에서 결과가 질문에서 1,000px 떨어졌다 — 눈이 줄을 건너가다 옆 줄로 샌다. */
.ask-past-list {
  display: grid; gap: var(--sp-2) var(--sp-4); margin: 0; padding: 0; list-style: none;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}
.ask-past-list li {
  display: flex; flex-direction: column; gap: 2px; min-width: 0;
  color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.5; word-break: keep-all;
}
.ask-past-q { color: var(--ink); }
.ask-past-verdict { font-variant-numeric: tabular-nums; }
/* "· 적중" 한 낱말이 혼자 다음 줄로 떨어졌다(360px 실측) — 마지막 줄을 고르게. */
.ask-past-sub { color: var(--ink-3); font-size: var(--fs-xs); text-wrap: pretty; }
#home-ask-foot { text-wrap: pretty; }
/* 링크가 혼자 다음 줄로 떨어졌다(390·360px 실측) — 가운뎃점과 한 덩어리로 옮긴다. */
.ask-foot-tail { white-space: nowrap; }
.ask-foot-link { color: inherit; text-underline-offset: 2px; }
@media (max-width: 520px) {
  html[data-lang="en"] .ask-options.is-pair { grid-template-columns: 1fr; }
}

/* 칩 넷을 **한 줄로** (운영자 2026-09-07: "왼쪽이 너무 남는데")
   =======================================================================
   두 칸 격자는 어제 장 카드가 띠의 **절반**이던 시절의 규칙이다(퍼센트를
   세로로 맞춰 "작은 표로 읽히게" 한 판단은 그대로 옳다). 카드를 하나로 합치면서
   폭이 553px이 됐는데 칩은 여전히 2×2로 왼쪽에만 뭉쳐, 카드 오른쪽 절반이
   통째로 비었다 — 운영자가 본 그 빈 자리다.

   숫자를 세로로 맞추는 성질은 유지한 채 칸만 넷으로 편다. 좁아지면 위의
   두 칸 규칙으로 돌아간다. */
/* 칩을 넷씩 한 줄에 놓는 규칙이 있었다. 지웠다 — 이제 못 맞는다.
   비상장 칸을 400px로 넓히면서(운영자 2026-09-07: "어제 시장요약이 너무 많이
   잡아먹는다") 어제 요약이 496px에서 멈춘다. 셸에 최대 너비가 있어 1920px에서도
   그대로 496px이다. 칩 넷은 483px에 좌우 여백까지 원하니 어느 폭에서도 안 든다.
   문턱을 올려 봐야 영영 안 켜지는 규칙만 남는다. 두 칸 격자가 실제 모양이다. */



/* 한 칸일 때 슬랙은 **맨 끝**으로 (운영자 2026-09-07: "왼쪽이 너무 남는데")
   =======================================================================
   두 칸 시절의 `auto auto 1fr auto`는 옳았다 — 가운데 1fr이 남는 높이를 먹어
   두 칸의 칩이 같은 높이에 섰다. 칸이 하나가 된 지금 그 1fr은 **문장과 칩 사이에
   구멍**을 만든다. 실측(1440px): 문장 74px짜리가 169px 트랙에 앉아 95px이 비었고,
   비상장이 카드 꼴이 되어 띠가 451px이 되자 205px까지 벌어졌다.

   이 파일 뒤쪽 `@media (min-width: 901px)`가 `.mood-row`의 트랙을 정하므로,
   덮으려면 **그 뒤에** 같은 조건으로 와야 한다. */
@media (min-width: 901px) {
  .mood-row-one { grid-template-rows: auto auto auto auto 1fr; }
}

/* --- 차트 머리줄 — 전체화면 단추는 **고지 줄과 같은 높이**에 선다 ---------
 *
 * 운영자 2026-09-09: "차트 전체화면 버튼도 좀 아래 … 와 비슷한 높이로".
 * 제목 줄 오른쪽 끝에 있던 것을 한 줄 내린다.
 *
 * `tvchart.js`가 "제 줄을 만들지 않는다 … 실측 52px"로 적어 둔 것과 반대
 * 방향처럼 보이지만 아니다 — 그 규칙은 **빈 줄**을 막으려던 것이고, 여기서는
 * 이미 있는 줄(고지 줄)에 나란히 앉는다. 그래서 늘어나는 높이가 0이다.
 *
 * **flex-wrap이 아니라 격자다.** 감기게 두면 어느 것이 어느 줄에 앉을지를 폭이
 * 정해서 화면 크기마다 달라진다. 행·열을 글로 못 박으면 360px에서도 1440px에서도
 * 같은 자리다.
 *
 * 세 페이지가 같은 모양을 쓴다(`/crypto/<코인>` · `/stock/<코드>` · `/asset/*`).
 * `/asset/*`만 기간 단추가 하나 더 있어 1행 2열을 쓴다.
 *
 * **순서로 이긴다고 이기는 것이 아니다.** 페이지 안 `<style>`은 `<head>` 맨
 * 앞이라 외부 시트에 지지만, 그건 특이도가 같을 때다. `#sec-chart .chart-heading`
 * 은 id가 붙어 (1,1,0)이라 여기 (0,1,0)을 이겼다 — 실측에서 격자가 통째로
 * 무시되고 제목이 37px 폭으로 접혔다. 그래서 그쪽 `display: flex` 선언을
 * 지우고 자리 규칙을 이 한 곳으로 모았다(두 곳에 두면 한쪽만 고치는 날이 온다). */
:is(.chart-heading, .asset-chart-head) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  column-gap: var(--sp-3); row-gap: var(--sp-1);
}
:is(.chart-heading, .asset-chart-head) > :is(h1, h2) { grid-column: 1; grid-row: 1; margin: 0; }
:is(.chart-heading, .asset-chart-head) > .asset-ranges {
  grid-column: 2; grid-row: 1; margin-left: 0;
}
:is(.chart-heading, .asset-chart-head) > .sub { grid-column: 1; grid-row: 2; margin: 0; }
/* 오른쪽 끝에 붙는다. `margin-left: auto`는 격자 칸 안에서 뜻이 없다 —
   칸을 채우는 것은 `justify-self`다. */
:is(.chart-heading, .asset-chart-head) > .chart-tools {
  grid-column: 2; grid-row: 2; justify-self: end; margin-left: 0;
}
/* 고지 줄이 비어 있는 화면(`/stock`·`/asset`은 JS가 채운다)에서도 단추는
   제 줄에 선다 — 빈 `<p>`가 2행을 잡고 있기 때문이다. */

/* ======================================================================
 * 옵션 사다리 (`#kr-options`, 종목 페이지 `#sec-options`)
 *
 * 콜은 왼쪽으로, 풋은 오른쪽으로 자라는 막대 — 행사가가 가운데 축이다. 360px에서
 * 다섯 칸이 한 줄에 서야 하므로 숫자 칸은 내용만큼, 막대는 남는 폭을 나눠 갖는다.
 * 색은 관습(콜=상승색, 풋=하락색)이지 판단이 아니다 — 문구가 그 차이를 말한다.
 * ====================================================================== */
/* **판은 여백을 안 준다 — 안쪽 것이 `--panel-inset`을 쓴다.**
 *
 * `.panel`은 테두리·모서리·바탕만 갖는다(monitor.css:440). 여백을 판에 주면
 * 표가 판 끝까지 못 가고, 가로 스크롤도 여백 안에서만 돈다 — 그래서 이
 * 저장소는 안쪽 것에 레일을 건다(`.panel .accessible-table td:first-child`,
 * `.panel > .news-videos` 등이 전부 그렇다).
 *
 * 옵션 판이 그 레일을 안 걸어서 글자가 카드 왼쪽 경계에 붙었다(운영자 제보
 * 2026-09-09: "글자가 카드 왼쪽 경계에 붙어있어서 보기안좋다"). 실측 390px:
 * 판 12~378인데 「풋/콜 미결제 비율」과 사다리가 13에서 시작했다 — 1px이다.
 *
 * 표는 뺀다. 셀에 이미 레일이 걸려 있고(`.panel .accessible-table`), 여기에
 * 또 주면 두 번 들어가면서 가로 스크롤이 여백 안에 갇힌다. */
#krop-panel > #krop-basis,
#krop-panel > div > :not(.table-scroll) { padding-inline: var(--panel-inset); }
/* 첫 줄은 판 위쪽에도 자리를 준다 — 위가 붙으면 옆을 띄운 값이 안 보인다. */
#krop-panel > #krop-basis { padding-top: var(--sp-3); }
.krop-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--sp-3); margin: var(--sp-3) 0 var(--sp-4); }
@media (max-width: 720px) { .krop-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); } }
.krop-stat { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.krop-stat small { font-size: var(--fs-xs); color: var(--ink-3); }
.krop-stat strong { font: 650 var(--fs-lg)/1.15 var(--num); font-variant-numeric: tabular-nums; letter-spacing: 0; }
.krop-stat strong.up { color: var(--up); }
.krop-stat strong.down { color: var(--down); }
.krop-why { font-size: var(--fs-xs); line-height: 1.4; color: var(--ink-2); }
.krop-ladder-title, .krop-maxoi, .krop-history-label, .krop-stocks-note { margin: var(--sp-2) 0; font-size: var(--fs-xs); color: var(--ink-2); line-height: 1.45; }
.krop-ladder { display: flex; flex-direction: column; gap: 2px; font-variant-numeric: tabular-nums; }
.krop-row { display: grid; grid-template-columns: minmax(3.4em, auto) minmax(0, 1fr) minmax(4.6em, auto) minmax(0, 1fr) minmax(3.4em, auto); align-items: center; gap: var(--sp-1); min-height: 18px; font-size: var(--fs-xs); }
.krop-head { color: var(--ink-3); border-bottom: 1px solid var(--line); padding-bottom: 2px; margin-bottom: 2px; }
.krop-head span:first-child, .krop-num:first-child { text-align: right; }
.krop-head span:last-child, .krop-num:last-child { text-align: left; }
.krop-num { color: var(--ink-2); font-family: var(--num); }
.krop-strike { text-align: center; color: var(--ink); font-family: var(--num); }
.krop-bar { display: block; height: 10px; min-width: 0; position: relative; }
.krop-bar i { display: block; height: 100%; border-radius: 2px; opacity: .78; }
.krop-bar.call { text-align: right; }
.krop-bar.call i { margin-left: auto; background: var(--up); }
.krop-bar.put i { background: var(--down); }
.krop-row.is-spot { background: var(--panel-3); border-radius: 3px; }
.krop-row.is-spot .krop-strike { font-weight: 700; }
.krop-history { margin-top: var(--sp-3); }
.krop-term, .krop-rank-title { margin: var(--sp-2) 0; font-size: var(--fs-xs); color: var(--ink-2); line-height: 1.45; }
.krop-controls { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); align-items: center; margin: var(--sp-2) 0; }
.krop-controls .segmented { margin: 0; }
/* 만기 수는 데이터에 따라 늘어난다. 아주 좁은 폰에서는 페이지가 아니라 이 줄만 민다. */
.krop-expiry { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.krop-expiry::-webkit-scrollbar { display: none; }
.krop-rank th, .krop-rank td { font-size: var(--fs-xs); white-space: nowrap; }
/* 폰에서는 거래대금 칸을 접는다. 내가격 확률 칸이 늘면서 360·412px에서 표가 27·31px
   넘쳤다(열 추가 전에는 딱 맞았다). 순위를 거래량으로 매기므로 거래대금은 보조 값이다. */
@media (max-width: 480px) { .krop-rank .col-value { display: none; } }
.krop-rank th[scope="row"].up { color: var(--up); }
.krop-rank th[scope="row"].down { color: var(--down); }
/* 옵션 가격이 매긴 확률 — 분포 곡선 · 범위 띠 · 수준표. 띠는 신호(등락)도 동작(파랑)도 아니라서
   잉크 단계만 쓴다(DESIGN: The Category Does Not Borrow Rule). 숫자는 SVG가 아니라 아래 HTML에 둔다 —
   viewBox 안의 글자는 폰 폭에서 12px 밑으로 줄어든다. */
.krop-prob { margin: var(--sp-4) 0 var(--sp-2); padding-top: var(--sp-3); border-top: 1px solid var(--line); }
/* `.qtr-chart`(max-height 260px)가 이 파일에서 뒤에 선다 — 두 클래스로 이긴다. */
.krop-prob .krop-prob-chart { max-height: 180px; }
.krop-prob-chart .band95 { fill: var(--ink-3); opacity: .16; }
.krop-prob-chart .band68 { fill: var(--ink-2); opacity: .3; }
.krop-prob-chart .curve { fill: none; stroke: var(--ink-2); stroke-width: 1.5; }
.krop-prob-chart .axis { stroke: var(--line-strong); }
.krop-prob-chart .tick { stroke: var(--ink-3); }
.krop-prob-chart .spot { stroke: var(--ink); stroke-dasharray: 4 3; stroke-opacity: .75; }
.krop-prob-legend { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3); margin: var(--sp-1) 0 var(--sp-2); font-size: var(--fs-xs); line-height: 1.4; color: var(--ink-2); }
.krop-prob-legend span { display: inline-flex; align-items: center; gap: var(--sp-1); }
.krop-prob-legend i { display: inline-block; width: 12px; height: 8px; }
.krop-prob-legend i.band68 { background: var(--ink-2); opacity: .45; }
.krop-prob-legend i.band95 { background: var(--ink-3); opacity: .25; }
.krop-prob-legend i.spot { width: 0; height: 10px; border-left: 1px dashed var(--ink); }
.krop-stats.krop-prob-stats { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); margin: var(--sp-2) 0; }
@media (max-width: 720px) { .krop-stats.krop-prob-stats { grid-template-columns: minmax(0, 1fr); } }
/* 넓은 화면에서 곡선이 가운데로 떠 글과 어긋나지 않게 — 곡선과 범위 칸을 한 폭으로 묶는다. */
.krop-prob .qtr-chart-wrap, .krop-prob .krop-prob-stats { max-width: 46rem; }
/* 분기로 보는 재무 (`#sec-quarters`) — 막대 + 전년 동기 선. 그림은 viewBox로 폭을 따라간다. */
.qtr-metric { margin: var(--sp-2) 0; flex-wrap: wrap; }
.qtr-what { margin: var(--sp-2) 0; font-size: var(--fs-xs); color: var(--ink-2); line-height: 1.45; }
.qtr-chart-wrap { margin: var(--sp-2) 0; }
.qtr-chart { display: block; width: 100%; height: auto; max-height: 260px; color: var(--ink); }
.qtr-strip th, .qtr-strip td { font-size: var(--fs-xs); white-space: nowrap; }
.qtr-h3 { margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-sm); font-weight: 650; }

/* AI 예측 벤치마크 성적표(/score). 표 자체는 옆 집계 표와 같은 옷을 입는다 —
   새 표 모양을 만들면 같은 페이지에 표가 두 종류가 된다. 여기 있는 것은
   그 표가 **말하지 못하는 상태**를 위한 것뿐이다. */
.score-bench-empty,
.score-bench-note { color: var(--muted); margin: var(--sp-2) 0 0; }
/* 예측자 칸은 **식별자**다. `.accessible-table th`의 대문자 변환이 걸리면
   `model:claude-opus-5`가 `MODEL:CLAUDE-OPUS-5`로 그려진다 — 화면이 값을
   고쳐 쓴 것이고, 성적표에서 그건 다른 참가자의 이름이 된다. */
.score-bench-table tbody th {
  text-transform: none; color: var(--ink-2); overflow-wrap: anywhere;
}
/* 값이 없는 칸. 숫자 자리에 문장이 오므로 크기를 낮춰 표의 축을 안 흔든다. */
.score-bench-wait { font-size: .82em; color: var(--muted); white-space: nowrap; }
.score-bench-method { margin-top: var(--sp-3); }
.score-bench-method > summary { cursor: pointer; color: var(--muted); font-size: .9em; }
.score-bench-method ul { margin: var(--sp-1h) 0 0; padding-left: var(--sp-4); }
/* 프롬프트 전문. **접혀 있어도 본문이다** — 방법론 공개가 "객관적 근거"의
   실체라(docs/inquiries/LEGAL_MODEL_BENCHMARK.md §7-2) 글자로 있어야 한다.
   긴 줄은 표처럼 자기 안에서 굴린다: 판 전체가 가로로 밀리면 안 된다. */
.score-bench-prompt {
  margin: var(--sp-3) 0 0;
  padding: var(--sp-3);
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel-2);
  color: var(--muted);
  font-size: .82em;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* --- 색인용 본문 (`/bio`·`/semi`) --------------------------------------
 *
 * 서버가 넣고, 진짜 섹션이 하나라도 선 뒤에 스크립트가 지운다. 대개 안 보이지만
 * **보일 때가 있다** — lane이 꺼졌거나 값이 아직 없거나 JS가 실패한 사람이다.
 * 그때 사람이 읽을 수 있어야 하므로 진짜 섹션과 같은 리듬을 준다.
 *
 * `#ssr-body`가 아니라 클래스로 잡는 이유: `/stock`·`/asset`이 페이지 안에
 * 자기 `#ssr-body` 규칙을 이미 갖고 있는데, 이 파일이 나중에 실리므로 같은
 * 특이도면 그쪽을 덮는다. 두 화면의 생김새를 건드리지 않으려고 이름을 나눈다.
 * ==================================================================== */
.ssr-lane { margin: 0 0 var(--sp-5); }
.ssr-lane p {
  margin: 0 0 var(--sp-2);
  color: var(--muted); font-size: var(--fs-sm); line-height: 1.5;
}
.ssr-lane table {
  width: auto; max-width: 100%; border-collapse: collapse;
  font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
}
.ssr-lane caption { text-align: left; margin: 0 0 var(--sp-1h); font-weight: 700; color: var(--ink); }
.ssr-lane :is(th, td) { padding: 4px 10px 4px 0; text-align: left; white-space: nowrap; }
.ssr-lane th { color: var(--ink-3); font-weight: 600; }
/* 표가 넓으면 판 밖으로 나가지 않고 제 안에서 흐른다 — 자의 OVF 규칙과 같은 답. */
.ssr-lane { overflow-x: auto; }

/* ======================================================================
 * 모의투자 리그(/league) — 2026-09-11 전면 개편
 *
 * 첫 판은 표가 1,300px 판 안에 250px로 뭉쳐 섰고 숫자가 이름에 붙었다(운영자 제보
 * "테이블은 다 깨져있고 숫자들은 테이블이랑 붙어있고"). 원인은 둘이었다 —
 * `.table-scroll`의 `max-width: max-content`가 표를 내용 폭으로 묶었고, 세 칸짜리
 * 폰 표를 넓은 화면에도 그대로 냈다.
 *
 * 답은 **폭마다 칸 수가 다른 한 표**다. 넓은 화면 일곱 칸 · 태블릿(≤1080) 여섯 칸 ·
 * 폰(≤760, world.css의 표 규칙과 같은 경계) 세 칸. 같은 값이 `league-wide`(넓은 화면
 * 칸)와 `league-sub`(폰의 칸 안 작은 줄) 두 벌로 있고, 둘 다 `display`로 갈려 한 화면에
 * 함께 보이지 않는다. 남는 폭은 한 칸이 받는다 — 순위표는 추이, 매매 내역은 종목.
 *
 * 세계의 문법은 그대로다: 값은 중립 잉크, 색은 등락 둘뿐, 그림자 없음, 값이 없는
 * 자리는 꺼진 셀, 구획은 1px 선. 판 안의 격자(보유 · 규칙)는 카드를 겹치지 않고
 * 머리카락 선으로 가른다 — 첫 줄 · 첫 칸의 선은 판이 잘라 낸다.
 * ====================================================================== */

/* 판을 채운다. monitor.css의 `max-width: max-content`는 좁은 표가 넓은 상자 안에
   떠 있지 않게 한 규칙이고 그 판정은 맞다 — 이 페이지의 표는 칸이 폭을 나눠 쓰도록
   짜여 있어 상자를 판에 맞춘다. */
.league-page .table-scroll { max-width: none; }

/* --- 방법 — 리그 한 문장 · 세 원칙 · 규칙 띠 ------------------------------ */
.league-method-panel { padding: var(--sp-5) var(--panel-inset) var(--panel-inset); }
.league-lede {
  margin: 0 0 var(--sp-5); max-width: 62ch;
  color: var(--ink); font-size: var(--fs-lg); line-height: 1.6;
}
.league-method {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 0; padding: 0; list-style: none;
}
.league-method > li { min-width: 0; padding: 0 var(--sp-5); border-left: 1px solid var(--line); }
.league-method > li:first-child { padding-left: 0; border-left: 0; }
.league-method > li:last-child { padding-right: 0; }
.league-method strong {
  display: block; margin-bottom: var(--sp-1h);
  color: var(--ink); font-size: var(--fs-md); font-weight: 650; line-height: 1.35;
}
.league-method p { margin: 0; color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.65; }
.league-spec {
  display: flex; flex-wrap: wrap; gap: var(--sp-3) 0;
  margin: var(--sp-5) 0 0; padding: var(--sp-4) 0 0; border-top: 1px solid var(--line);
}
.league-spec > div { display: flex; flex-direction: column; gap: 3px; padding: 0 var(--sp-5); border-left: 1px solid var(--line); }
.league-spec > div:first-child { padding-left: 0; border-left: 0; }
.league-spec dt, .league-status dt {
  color: var(--ink-3); font: 650 var(--fs-xs)/1.2 var(--sans); letter-spacing: .04em;
}
.league-spec dd {
  margin: 0; color: var(--ink); font: 600 var(--fs-md)/1.25 var(--num);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.league-spec-note { margin: var(--sp-3) 0 0; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.5; }
@media (max-width: 900px) {
  .league-method { grid-template-columns: 1fr; }
  .league-method > li,
  .league-method > li:last-child { padding: var(--sp-3) 0; border-left: 0; border-top: 1px solid var(--line); }
  .league-method > li:first-child { padding-top: 0; border-top: 0; }
}
@media (max-width: 760px) {
  .league-method-panel { padding: var(--sp-4) var(--panel-inset); }
  .league-lede { margin-bottom: var(--sp-4); font-size: var(--fs-md); }
  .league-spec { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3) var(--sp-2); }
  .league-spec > div { min-width: 0; padding: 0; border-left: 0; }
  .league-spec dd { font-size: var(--fs-sm); white-space: normal; }
}

/* --- 순위 제목 옆의 범례 — 무엇의 언제 값인가 ---------------------------- */
.league-head { flex-wrap: wrap; row-gap: var(--sp-2); }
.league-status { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-5); margin: 0 0 0 auto; }
.league-status > div { display: flex; align-items: baseline; gap: var(--sp-1h); }
.league-status dd {
  margin: 0; color: var(--ink); font: 600 var(--fs-sm)/1.2 var(--num);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
@media (max-width: 760px) {
  .league-status { width: 100%; margin-left: 0; gap: var(--sp-1) var(--sp-4); }
}

/* --- 표 공통 ---------------------------------------------------------- */
.league-page .league-table { width: 100%; font-size: var(--fs-sm); }
/* 첫 칸을 붙들지 않는다. 이 표들은 폭마다 칸을 접어 가로로 흐르지 않게 짰고, 붙들린
   칸은 제 바탕을 따로 칠해 줄에 손을 올리면 그 칸만 옛 색으로 남는다. */
.league-page .league-table :is(th, td):first-child { position: static; background: none; }
.league-page .league-table :is(th, td) { vertical-align: middle; }
/* 판 바닥에 닿는 표는 판의 둥근 아래 모서리를 따라 자른다(자 POKE: 안쪽 곡선 15 · 표 0).
   monitor.css가 위 모서리만 깎는 이유는 "그 아래를 푸터가 덮어서"인데, 매매 내역은 표가
   판의 마지막이다. 마지막 줄의 밑선은 판 테두리와 겹쳐 2px이 되므로 걷는다. */
.league-page .panel > .table-scroll:last-child {
  border-bottom-left-radius: calc(var(--r-md) - 1px);
  border-bottom-right-radius: calc(var(--r-md) - 1px);
}
.league-page .panel > .table-scroll:last-child tbody tr:last-child > * { border-bottom: 0; }
/* 머리글은 DESIGN.md의 범례(12px · 650 · +0.04em)다. 9px 대문자는 라벨 하한(12px)
   아래라 이 표에서는 쓰지 않는다. */
/* 머리 칸의 생김새(바탕·크기·굵기·자간)는 **표 한 벌 규칙**이 정한다(ocean.css의
   `One vocabulary` 블록). 여기서 다시 쓰면 (0,3,1)이라 그 규칙을 이겨서 리그의
   표 머리만 바탕 없이 자간 0.04em으로 섰다(실측 2026-09-17). 이 자리에 남는 것은
   이 표만의 값 하나 — 머리 칸이 아래로 붙는 것뿐이다. */
.league-page .league-table thead th { vertical-align: bottom; }
.league-page .league-table :is(.league-who, .league-trend, .league-make, .league-stock, .league-date) { text-align: left; }
/* 한글은 낱말 사이에서만 끊는다. world.css가 표의 글 칸에 `overflow-wrap: anywhere`를
   건다(폰에서 띄어쓰기 없는 약품명 하나가 열 폭을 정하던 것의 처방). 이 표의 글은 사람 ·
   모델 · 종목 이름이라 낱말이 짧은데, 그 규칙 아래서 "페르소/나" · "LG에너지솔루/션"처럼
   음절 사이가 끊겼다(360px 실측). `tr >`는 world.css의 (0,4,1)을 이기려는 특이도다. */
.world .league-page .league-table tr > :is(th, td):not(.num) { word-break: keep-all; overflow-wrap: break-word; }
/* 참가자 칸은 식별자다 — 머리글 문법을 물려주지 않는다. */
.league-page .league-table tbody th {
  color: var(--ink-2); font: 400 var(--fs-xs)/1.4 var(--sans); text-transform: none;
}
.league-page .league-name {
  display: block; color: var(--ink); font-size: var(--fs-sm); font-weight: 650; line-height: 1.35;
}
.league-page .league-table tbody th small {
  display: block; margin-top: 1px; color: var(--ink-3); font-size: var(--fs-xs);
}
.league-page .league-table td.num { color: var(--ink); font-family: var(--num); font-size: var(--fs-sm); }
.league-page .league-table td.league-ret { font-size: var(--fs-md); }
.league-page .league-table td.league-ret b { font-weight: 650; }
.league-page .league-table td.num.up { color: var(--up); }
.league-page .league-table td.num.down { color: var(--down); }
.league-page .league-table td.league-rank,
.league-slip .league-rank {
  color: var(--ink-3); font: 650 var(--fs-sm)/1 var(--num); font-variant-numeric: tabular-nums;
}
.league-page .league-table .league-rank { text-align: center; }
.league-page .league-table td.league-make { color: var(--ink-3); font-size: var(--fs-xs); }
/* 기준(지수) 줄은 참가자가 아니다 — 위에 짙은 선 하나로 갈린다. 선을 테두리로 주면
   `border-collapse`에서 윗줄의 밑선에 진다(같은 두께 · 같은 모양이면 위 칸이 이긴다). */
.league-page .league-index > * { box-shadow: inset 0 1px 0 var(--line-strong); }
.league-page .league-index .league-name { color: var(--ink-2); }
/* 값이 없는 칸 — 꺼진 셀. 대시가 아니라 이 세계의 서명이다. */
.league-off {
  display: inline-block; width: 4.5ch; height: .85em; vertical-align: -.08em;
  border-radius: 3px; background: var(--seg-ghost, var(--panel-3));
}
.league-off.is-track {
  display: block; width: 100%; min-width: 96px; height: 6px;
  border-radius: var(--r-pill); background: var(--seg-ghost-2, var(--panel-2));
}
/* 추이선 — 한 표의 모든 줄이 같은 눈금이고, 점선이 시작 금액이다(league_page._spark). */
.league-spark { display: block; width: 100%; min-width: 96px; height: 28px; overflow: visible; color: var(--ink-3); }
.league-spark .base { stroke: var(--line-strong); stroke-width: 1; stroke-dasharray: 3 3; vector-effect: non-scaling-stroke; }
.league-spark .line {
  fill: none; stroke: currentColor; stroke-width: 1.75;
  stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke;
}
.league-spark.up { color: var(--up); }
.league-spark.down { color: var(--down); }
/* 제공사 로고(§5.4 조건 2) — 작게, 이름 옆에. 파일은 받은 그대로라 모양 · 색을
   건드리지 않는다. 모서리만 둥글게 자른다(상자이지 그림이 아니다). */
.league-logo {
  display: inline-block; width: 14px; height: 14px; margin-right: var(--sp-1h);
  vertical-align: -2px; border-radius: 3px;
}
.league-sub { display: none; }

@media (min-width: 761px) {
  /* 칸은 내용만큼(`1%`), 남는 폭은 한 칸이 받는다 — 순위표는 추이, 매매 내역은 종목. */
  .league-page .league-table :is(th, td) { width: 1%; }
  .league-page .league-table :is(.league-trend, .league-stock) { width: auto; }
  /* world.css가 글 칸을 접히게 한다(폰에서 표가 네 배로 흐르던 것의 처방). 넓은 화면의
     이 표는 칸이 내용만큼 서야 위의 `1%`가 선다 — 접히면 이름 칸이 한 글자 폭으로
     무너진다. `tr >`는 특이도 (0,4,2)를 얻으려는 것이다: world.css의 (0,4,1)이 이
     파일보다 뒤에 실린다. */
  .world .league-page .league-table tr > :is(th, td):is(.league-who, .league-make, .league-stock) {
    white-space: nowrap;
  }
  .league-page .league-table .league-trend { padding-inline: var(--sp-5); }
}
@media (max-width: 1080px) {
  .league-page .league-table .league-xl { display: none; }
  .league-page .league-table .league-nav { padding-right: var(--panel-inset); }
}
@media (max-width: 760px) {
  .league-page .league-table .league-wide { display: none; }
  .league-page .league-sub {
    display: block; margin-top: 2px; color: var(--ink-3);
    font-size: var(--fs-xs); font-weight: 400; white-space: nowrap;
  }
  /* 접힌 칸이 끝에 있으면 `:last-child` 레일이 보이지 않는 칸에 걸린다 — 보이는 끝 칸에 준다. */
  .league-page .league-table .league-ret,
  .league-page .league-fills .league-amt { padding-right: var(--panel-inset); }
  .league-page .league-fills .league-who { padding-left: var(--panel-inset); }
  .league-page .league-table :is(.league-rank, .league-ret) { width: 1%; }
  .league-page .league-table td.league-rank { padding-right: 0; }
}

/* --- 판 바닥의 주석 — 시즌 경계 · 표본 · 읽는 법 · 안 잰 것 · 상표 ------------ */
.league-notes { padding: var(--sp-3) var(--panel-inset) var(--sp-4); }
.league-notes p { margin: 0; max-width: var(--measure); color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.6; }
.league-notes p + p { margin-top: var(--sp-1); }
.league-notes code { color: var(--ink-2); font-size: var(--fs-xs); }
.league-lead-note { padding: var(--sp-4) var(--panel-inset); border-bottom: 1px solid var(--line); }
.league-lead-note p { margin: 0; max-width: var(--measure); color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.6; }
.league-lead-note p + p { margin-top: var(--sp-2); }
.league-disclaimer { color: var(--ink); font-size: var(--fs-md); font-weight: 600; line-height: 1.6; }
.league-lead-note p.league-disclaimer { color: var(--ink); font-size: var(--fs-md); }

/* --- 지금 들고 있는 것 — 참가자마다 한 장, 머리카락 선으로 가른 격자 ------------ */
.league-holdings-panel, .league-rules-panel { overflow: hidden; }
/* 선은 칸의 **아래**와 왼쪽에 긋는다. 장 수가 칸 수로 안 나뉘면 마지막 줄이 비는데, 위에
   그으면 빈 칸 위의 장들이 밑이 열린 채 남는다(1440px · 13장 = 4 + 4 + 4 + 1 실측).
   판 가장자리에 닿는 선(첫 칸의 왼쪽 · 마지막 줄의 아래)은 판이 잘라 낸다. */
.league-slips {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  margin: 0 0 -1px -1px;
}
/* 한 장은 두 줄(머리 · 몸)을 격자와 나눠 쓴다 — 이름이 두 줄로 접힌 장이 있어도 같은 줄의
   목록이 같은 높이에서 시작한다(자 ALIGN 20.3px, 1440px). 몸(목록 + 근거)은 한 덩어리다:
   근거까지 줄을 맞췄더니 짧은 목록 아래에 200px 구멍이 나 근거가 제 목록에서 떨어져
   읽혔다 — 자는 100점이었고, 눈으로 보고 되돌렸다. 자식은 둘을 넘지 않는다(넘으면 암묵
   트랙이 아래 줄을 덮는다, 2026-09-08 함정). */
.league-slip {
  display: grid; grid-row: span 2; grid-template-rows: subgrid; row-gap: 0;
  min-width: 0; padding: var(--sp-4) var(--panel-inset);
  border-bottom: 1px solid var(--line); border-left: 1px solid var(--line);
}
.league-slip > header { display: flex; align-items: baseline; gap: var(--sp-2); min-width: 0; }
.league-slip .league-rank { flex: none; min-width: 1.2em; }
.league-slip h3 {
  flex: 1 1 auto; min-width: 0; margin: 0;
  color: var(--ink); font-size: var(--fs-md); font-weight: 650; line-height: 1.35; overflow-wrap: anywhere;
}
.league-meta {
  flex: none; color: var(--ink-3); font: 600 var(--fs-xs)/1.2 var(--num);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.league-holdings { margin: var(--sp-3) 0 0; padding: 0; list-style: none; }
/* 막대는 18%까지만 — 이름 칸이 「한화에어로스페이스 012450」을 자르지 않을 만큼(360px 실측). */
.league-holdings li {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(36px, 18%) 3.6em;
  column-gap: var(--sp-2); align-items: center; min-height: 26px; font-size: var(--fs-sm);
}
.league-hname { min-width: 0; overflow: hidden; color: var(--ink-2); text-overflow: ellipsis; white-space: nowrap; }
/* 종목 코드는 식별자지만 등폭이 아니라 숫자 면(--num)이다 — 사이트의 다른 화면과 같게
   (등폭은 `.kro-sym` · `code`에만, test_typography). */
.league-hname small {
  margin-left: var(--sp-1h); color: var(--ink-3);
  font: 400 var(--fs-xs)/1 var(--num); font-variant-numeric: tabular-nums;
}
/* 비중 막대 — 끝이 종목당 한도다. 중립색: 이 세계에서 색은 등락과 동작만 말한다. */
.league-bar {
  position: relative; display: block; height: 4px; overflow: hidden;
  border-radius: var(--r-pill); background: var(--seg-ghost-2, var(--panel-2));
}
.league-bar::after {
  content: ""; position: absolute; inset: 0 auto 0 0; width: var(--w, 0%);
  border-radius: var(--r-pill); background: var(--ink-3);
}
.league-hw { color: var(--ink); font: 600 var(--fs-sm)/1 var(--num); font-variant-numeric: tabular-nums; text-align: right; }
.league-empty { margin: var(--sp-2) 0 0; color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.55; }
.league-note { margin: var(--sp-3) 0 0; color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.6; overflow-wrap: anywhere; }
/* 칩은 DESIGN.md의 chip-source다 — panel-2 바탕 · md 모서리 · 2px 8px(impeccable detect:
   4px은 모서리 눈금 밖이었다). */
.league-chip {
  display: inline-block; margin-right: var(--sp-1h); padding: 1px 8px;
  border-radius: var(--r-md); background: var(--panel-2);
  color: var(--ink-2); font: 600 var(--fs-xs)/1.4 var(--num); font-variant-numeric: tabular-nums;
}
.league-empty-panel { margin: 0; padding: var(--sp-4) var(--panel-inset); color: var(--ink-2); font-size: var(--fs-md); line-height: 1.6; }
/* 판 머리의 한 줄 — 제 밑선이 격자와 가른다(격자의 장에는 윗선이 없다). */
.league-pending {
  margin: 0; padding: var(--sp-3) var(--panel-inset); border-bottom: 1px solid var(--line);
  color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.55;
}

/* --- 매매 내역 -------------------------------------------------------- */
.league-page .league-fills tbody th { color: var(--ink-2); font-size: var(--fs-sm); }
.league-page .league-fills td.league-stock { color: var(--ink); }
.league-page .league-fills td.league-date { color: var(--ink-3); font-size: var(--fs-xs); }
.league-side {
  display: inline-block; margin-right: var(--sp-1h); padding: 0 7px; border-radius: var(--r-md);
  background: var(--panel-2); color: var(--ink-2); font-size: var(--fs-xs); font-weight: 650; line-height: 1.6;
}
.league-side.is-buy { color: var(--ink); }
.league-code {
  margin-left: var(--sp-1h); color: var(--ink-3);
  font: 400 var(--fs-xs)/1 var(--num); font-variant-numeric: tabular-nums;
}

/* --- 규칙 참가자 — 원칙 한 문단 + 옮긴 것 · 정한 선 · 못 옮긴 것 · 출처 ---------- */
/* 묶음 머리 밑의 면책 — 사진이 서는 절마다 같이 선다(`_persona_note`). 부문 절의
   것보다 작게: 그 절은 이 문장이 요지이고, 여기서는 사진 옆에 붙는 단서다. */
.league-group-note {
  margin: 0 0 var(--sp-3); padding: 0 var(--panel-inset);
  max-width: calc(var(--measure) + 2 * var(--panel-inset));
  font-size: var(--fs-sm); font-weight: 600;
}
.league-rules-panel > .league-disclaimer { margin: 0; padding: var(--sp-4) var(--panel-inset); max-width: calc(var(--measure) + 2 * var(--panel-inset)); }
/* 칸 수는 폭으로 못 박는다(3 · 2 · 1). 마지막 줄이 비면 선이 거기서 끊겨 판이 덜 그려진
   것처럼 읽힌다 — 마지막 칸이 남은 칸을 채운다(다섯이면 3 + 2, 둘째 줄 끝이 두 칸). */
.league-rules { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin: 0 0 0 -1px; }
.league-rules > .league-rule:nth-child(3n + 1):last-child { grid-column: span 3; }
.league-rules > .league-rule:nth-child(3n + 2):last-child { grid-column: span 2; }
@media (max-width: 1180px) {
  .league-rules { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .league-rules > .league-rule:nth-child(n):last-child { grid-column: auto; }
  .league-rules > .league-rule:nth-child(2n + 1):last-child { grid-column: span 2; }
}
/* 이름 · 원칙 · 정의 목록 세 줄을 격자와 나눠 쓴다 — 원칙이 두 줄인 칸과 세 줄인 칸의
   목록이 같은 높이에서 시작한다(자 ALIGN 21.4px, 1440px). */
.league-rule {
  display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0;
  min-width: 0; padding: var(--sp-4) var(--panel-inset) var(--sp-5);
  border-top: 1px solid var(--line); border-left: 1px solid var(--line);
}
.league-rule h3 { margin: 0 0 var(--sp-2); color: var(--ink); font-size: var(--fs-lg); font-weight: 700; letter-spacing: -.01em; }
.league-rule > p { margin: 0 0 var(--sp-3); color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.65; }
/* 목록은 제 트랙에서 늘어나지 않는다 — 늘어나면 암묵 줄이 남는 높이를 나눠 가져, 항목이
   둘뿐인 존 보글 칸에서 두 줄 사이가 100px 벌어졌다(1440px 실측). */
.league-rule dl {
  display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--sp-2) var(--sp-3);
  align-self: start; margin: 0;
}
.league-rule dl > div { display: contents; }
.league-rule dt { color: var(--ink-3); font: 650 var(--fs-xs)/1.55 var(--sans); letter-spacing: .02em; white-space: nowrap; }
.league-rule dd { margin: 0; color: var(--ink-2); font-size: var(--fs-xs); line-height: 1.55; }
.league-excluded { padding: var(--sp-4) var(--panel-inset) var(--sp-5); border-top: 1px solid var(--line); }
.league-excluded h3 { margin: 0 0 var(--sp-2); color: var(--ink); font-size: var(--fs-md); font-weight: 650; }
.league-excluded ul { margin: 0; max-width: var(--measure); padding-left: 1.1em; color: var(--ink-2); font-size: var(--fs-sm); line-height: 1.6; }
.league-excluded li + li { margin-top: var(--sp-1h); }
.league-excluded strong { color: var(--ink); font-weight: 650; }
.league-excluded p { margin: var(--sp-3) 0 0; max-width: var(--measure); color: var(--ink-3); font-size: var(--fs-xs); line-height: 1.55; }
@media (max-width: 760px) {
  .league-rules { grid-template-columns: 1fr; }
  .league-rules > .league-rule:nth-child(n):last-child { grid-column: auto; }
  .league-rule dl { grid-template-columns: 1fr; gap: 2px; }
  .league-rule dl > div + div > dt { margin-top: var(--sp-2); }
}

/* --- 접힌 것(프롬프트) — 판 끝까지 선을 긋고 레일 안에 글을 둔다 -------------- */
.league-page .panel > .league-fold { margin: 0; padding: var(--sp-3) var(--panel-inset); border-top: 1px solid var(--line); }
.league-page .league-fold > summary { color: var(--ink-2); font-size: var(--fs-sm); font-weight: 600; cursor: pointer; }
.league-page .league-fold > summary:hover { color: var(--ink); }
.league-page .league-fold[open] > summary { margin-bottom: var(--sp-2); }
.league-page .league-fold h3 { margin: var(--sp-4) 0 0; color: var(--ink); font-size: var(--fs-sm); font-weight: 650; }
.league-page .league-fold > p { margin: var(--sp-2) 0 0; max-width: var(--measure); color: var(--ink-3); }
/* 프롬프트 전문은 거의 한글 글이라 본문 글꼴로 싣는다. 등폭 스택에는 한글이 없어 한 줄에
   두 글꼴이 선다(test_typography가 지키는 결정). "글자 그대로"는 줄바꿈 보존(pre-wrap)이
   지킨다. */
.league-page .league-fold .score-bench-prompt {
  max-width: 110ch; color: var(--ink-2); font-family: var(--sans);
  font-size: var(--fs-xs); line-height: 1.7;
}

/* --- 자주 묻는 것 ------------------------------------------------------ */
.league-qa { padding: var(--sp-4) var(--panel-inset) var(--sp-5); }
.league-qa h3 { margin: var(--sp-5) 0 var(--sp-2); color: var(--ink); font-size: var(--fs-md); font-weight: 650; }
.league-qa h3:first-child { margin-top: 0; }
.league-qa p { margin: 0; max-width: var(--measure); color: var(--ink-2); font-size: var(--fs-md); line-height: 1.7; }

.league-table tbody th small { display: block; color: var(--ink-3); font-weight: 400; }
/* 자리 이름은 낱말 경계에서만 끊는다. 표 칸은 world.css V5-3이 폰에서 `word-break:
   normal`로 음절 사이 끊기를 연다(띄어쓰기 없는 긴 낱말이 열을 넓히지 않게) — 그 규칙은
   칸(th)에 걸리므로 이름만 따로 감싸 되돌린다. 자리 이름이 '…의 원칙'(2026-09-11)이
   되며 길어져 '워런 버핏 / 의 원칙'처럼 조사가 떨어졌다(390px 실측). 긴 낱말의 비상
   끊기(`overflow-wrap: anywhere`)는 칸에서 물려받아 그대로다. */
.league-name { word-break: keep-all; }
.league-spark { display: block; margin-top: var(--sp-1h); color: var(--ink-3); }
/* 제공사 로고(§5.4 조건 2) — 작게, 이름 옆에. 파일은 받은 그대로라 모양 · 색을
   건드리지 않는다. 모서리만 둥글게 자른다(상자이지 그림이 아니다). */
.league-logo { display: inline-block; width: 14px; height: 14px; margin-right: var(--sp-1h);
  vertical-align: -2px; border-radius: 3px; }
/* 규칙 자리의 얼굴(운영자 요청 2026-09-11). 로고(14px 상자)보다 조금 크게, 둥글게 —
   얼굴은 14px에서 누구인지 안 읽힌다. 사진이 없는 사람은 같은 자리에 이니셜이 선다
   (13F 카드의 `.usm-portrait.is-initials`와 같은 결). 글자는 12px 바닥(--fs-xs)을 지킨다. */
.league-face { display: inline-block; width: 20px; height: 20px; margin-right: var(--sp-1h);
  vertical-align: -5px; border-radius: 50%; object-fit: cover; }
.league-face.is-initials { display: inline-flex; align-items: center; justify-content: center;
  box-sizing: border-box; background: var(--panel); border: 1px solid var(--line);
  color: var(--ink-3); font-family: var(--num); font-size: var(--fs-xs); font-weight: 650;
  line-height: 1; letter-spacing: -.04em;
  /* inline-flex의 기준선은 안쪽 글자다 — 사진(아래 모서리가 기준선)과 같은 -5px를 주면
     원이 이름보다 5px 내려앉는다(실측 2026-09-11). 글자 기준선에 그대로 둔다. */
  vertical-align: 0; }
.league-face.is-big { width: 36px; height: 36px; vertical-align: middle; margin-right: var(--sp-2); }
.league-face.is-big.is-initials { font-size: var(--fs-sm); }
/* 중계 제공사 한 줄 — 줄마다 붙던 'Nebius 중계'를 표 위에 모았다(운영자 요청 2026-09-11). */
.league-hosted { margin: 0 0 var(--sp-2); color: var(--ink-3); font-size: var(--fs-xs);
  line-height: 1.5; }
.league-hosted strong { color: var(--ink-2); font-weight: 650; }
