/*
  oaran — 화면 시트. 이 시트는 **층 2·3**이다.

  층 1(골격 값: 반경·간격 6단·수직 4단·글자 6단·컨테이너 폭·거터·터치·중단점·버튼 뼈대)은
  공통 기본 골격 시트가 소유하고, 이 면들은 그것을 **이 시트보다 먼저** 싣는다.
  골격 값은 여기서 한 줄도 다시 적지 않는다 — 사본은 표류한다. 모자라면 덮지 않고 **추가**한다.

    층 2  이 파일 앞머리 — 브랜드 색 슬롯 재정의 + 사이트 접두사 토큰(--oa-*) + 역할 간격 별칭
    층 3  이 파일 본문   — 층 1·2의 var()만 소비한다. 스케일 밖 생 px 금지

  배치 규율(전면 정렬):
    · 정렬선은 둘뿐이다. A = 컨테이너 안쪽 모서리(거터), B = A + 한 단(--oa-pad, 거터와 같은 값).
      상자(카드·결과·오류)와 목록 들여쓰기는 B, 그 밖의 모든 글·행·요약·표의 첫 칸은 A에서 시작한다.
      **상자의 한 단은 테두리까지 합친 값이다**(--oa-box-pad = 한 단 − 테두리) — 그래야 상자 안 글줄과
      목록 들여쓰기가 같은 B에 선다. 종전에는 카드가 A+17, 목록이 A+16이라 B가 두 값이었다.
    · **칠하지 않은 컨테이너는 세로 안쪽 여백을 갖지 않는다.** 배경도 테두리도 없는 상자의 padding 은
      눈에 그냥 빈 띠이고 이웃의 간격과 합산된다 — 상자 사이가 아니라 **잉크 사이**가 사람이 보는 공백이다.
      안쪽 여백은 칠해진 상자(카드·결과·오류)와 누르는 것(버튼·행·요약)만 가진다.
    · 세로 간격은 역할로만 말한다: 행간 · 항목 간 · 블록 간 · 섹션 간 네 값뿐이다.
      **main 직계의 리듬은 섹션 간 한 값**이고 그 값은 `main > * + *`가 혼자 소유한다 — 인접 선택자를
      태그로 좁히면 사이에 낀 숨은 요소·비-section 블록이 리듬을 끊어 0px가 된다(실측 8면).
      역할 유틸리티(.space-top)는 문맥 규칙에 지지 않는다 — 문맥 쪽을 :where()로 낮춰 둔다.
    · 같은 역할은 같은 모양이다 — 버튼 위계는 주(채움)·보조(외곽선) 둘, 새 모양을 만들지 않는다.
      입력 묶음의 상자도 한 벌이다: **폼이 카드**이고 fieldset은 테두리 없는 묶음이다(UA 기본 테두리 제거).
      한 줄 안의 행동 버튼은 폭을 똑같이 나눠 가진다 — 같은 역할이 글자 수에 따라 다른 폭이 되지 않게.

  모바일 우선 · W3C 표준만 사용(접두사 단독 금지) · 라이트/다크 양쪽에 응답한다.
*/

/* ═══════════════════════════════════════════════════════════════════════════
   층 2 — 브랜드 색 슬롯 + 사이트 토큰
   ═══════════════════════════════════════════════════════════════════════════
   덮는 것은 색뿐이다. 글자·경계 색(--ink·--ink-2·--line)은 브랜드 바탕(--bg)과 **쌍으로**
   함께 옮겨 적은 것이며, 그 쌍이 대비를 지킨다. 그 밖의 골격 값은 여기 없다. */
:root {
  --bg:#F6F3EE; --surface:#FFFFFF; --ink:#20252B; --ink-2:#59636D;
  --line:#D9DEE3; --accent:#8B4964; --accent-ink:#FFFFFF; --accent-soft:#F3EAF0;
  --good:#59636D; --warn:#59636D; --bad:#A32942;
  color-scheme:light;

  /* 사이트 토큰 — 골격에 자리가 없는 것만. 값은 전부 골격 단계의 배수다. */
  --oa-font:-apple-system,BlinkMacSystemFont,"Apple SD Gothic Neo","Hiragino Kaku Gothic ProN","Segoe UI",sans-serif;
  --oa-hair:1px;                      /* 경계선 굵기 — 1종 */
  --oa-focus:calc(var(--s1) - 1px);   /* 포커스 링 굵기 — 1종 */
  --oa-header-h:calc(var(--s6) * 2);  /* 고정 머리 높이 */
  --oa-fab:calc(var(--s6) * 3);       /* 우하단에 겹쳐 뜨는 의견 위젯을 비켜 주는 본문 아래 높이 */
  --oa-pad:var(--gutter);             /* 상자 안쪽 여백 = 정렬선 B. 한 단은 거터 한 칸이다 */
  /* 머리 세 부품의 **폭 하한** — 로케일 최장 라벨을 담고도 남는 한 값이다(공통 표준 헤더 규약 1-4④).
     라벨 글자 수가 곧 폭이 되면 언어를 바꿀 때 로고·도구·언어 트리거의 x 가 밀린다(실측: 도구
     48.5~70.98 · 언어 59.75~75.92 · x 최대 28px). 폭을 못 박으면 네 로케일의 좌표가 ±0으로 모인다.
     값은 스케일 배수다(80 = --s2×10 · 96 = --s2×12). 라벨이 이 하한을 넘기면 상자가 커져 좌표가
     갈라지고, 배포 전 검사가 그 자리에서 막는다 — 그때 여기 한 값을 올린다. */
  --oa-menu-w:calc(var(--s2) * 10);   /* 도구·언어 트리거 공통 폭 하한 */
  --oa-brand-w:calc(var(--s2) * 12);  /* 로고(아이콘 + 이름) 폭 하한 */
  /* 테두리를 가진 상자의 안쪽 여백 — 테두리까지 합쳐 한 단이 되게 뺀다(정렬선 B는 한 값이다). */
  --oa-box-pad:calc(var(--oa-pad) - var(--oa-hair));

  /* 세로 간격 4단 — 층 1 --v-* 의 **별칭**이다(값은 층 1만 소유한다).
     line=본문 행간 · item=항목 간 · block=같은 섹션 안 덩어리 간 · section=주제 전환 */
  --gap-line:var(--v-line);
  --gap-item:var(--v-item);
  --gap-block:var(--v-block);
  --gap-section:var(--v-section);

  /* 앵커 착지 여유 — 머리가 고정이므로 골격이 정한 대로 「머리 높이 + 한 단」으로 올린다.
     착지 지점을 가진 요소(=id가 있는 요소)가 이 여유를 직접 진다. */
  --anchor-top:calc(var(--oa-header-h) + var(--s2));
}

/* 화면 **아래쪽**의 착지 여유 — 우하단 고정 위젯이 앉는 띠다(--oa-fab).
   위쪽 여유(--anchor-top)를 요소가 `scroll-margin-top` 으로 지는 것과 같은 축이고, 아래쪽은
   면마다 다를 이유가 없으므로 스크롤 상자(문서)가 한 번 진다. 표준 `scroll-padding-bottom` 은
   `scrollIntoView`·앵커 착지가 「보인다」고 보는 범위에서 이 띠를 **빼 준다** — 착지가 놓는 자리가
   위젯 밑이 되지 않는다. 착지 정책(assets/tool-result.js)도 이 선언을 **읽어서** 같은 값을 쓴다:
   값의 주인은 여전히 시트 하나이고, JS 는 px 를 다시 적지 않는다(원칙 5). */
html { scroll-padding-bottom:var(--oa-fab); }

/* 어두운 배색 — 같은 이름 재정의만(새 이름 0). 조건은 층 1과 같은 하나뿐이다. */
@media (prefers-color-scheme:dark) {
  :root {
    --bg:#20252B; --surface:#2A3038; --ink:#F6F3EE; --ink-2:#D9DEE3;
    --line:#79848E; --accent:#E7B8C8; --accent-ink:#20252B; --accent-soft:#3A424C;
    --good:#D9DEE3; --warn:#D9DEE3; --bad:#FDECEE;
    color-scheme:dark;
  }
}

/* 상태를 가진 면의 색 문맥 — 새 팔레트·새 단계가 아니라 같은 역할 이름의 재지정이다. */
.result-card { --surface:var(--accent-soft); }
.error-box,.control[aria-invalid="true"] { --surface:light-dark(#FDECEE,#4A2A30); --ink:var(--bad); --line:var(--bad); }

/* ═══════════════════════════════════════════════════════════════════════════
   층 3 — 바탕
   ═══════════════════════════════════════════════════════════════════════════ */
* { box-sizing:border-box; }
/* 면은 **화면 높이만큼은 찬다** — 내용이 짧아도 꼬리 밑에 빈 배경 띠가 남지 않게(실측 @390:
   /menu/en·/menu/es 289px · /404.html 397px. 같은 언어 창구를 네 번 돌면 착지면 절반만 그렇게
   끝나 화면이 면마다 다른 모양으로 닫혔다 — 원칙 6 공간 배분·제0원칙).
   고치는 자리는 셸 한 곳이다: 세로 축을 화면 높이로 잡고 본문이 남는 자리를 가져간다.
   `dvh` 는 주소 표시줄이 접히는 모바일에서 실제 보이는 높이다 — 그 값을 모르는 환경을 위해
   같은 뜻의 옛 단위를 먼저 적는다(뒤에 선언한 쪽이 이긴다 · 접두사 없는 표준 두 벌). */
body { margin:0; background:var(--bg); color:var(--ink); font:400 var(--t3)/var(--gap-line) var(--oa-font); display:flex; flex-direction:column; align-items:center; min-height:100vh; min-height:100dvh; }
h1,h2,h3,p,ul,ol,dl,dd,figure,fieldset,legend { margin:0; padding:0; }
/* 입력 묶음은 상자가 아니다 — 상자는 폼(카드) 한 벌이다. UA 기본 테두리(2px groove)를 지우지 않으면
   같은 '입력 그룹' 역할이 면마다 다른 모양이 되고, 사이트 테두리 굵기 종수가 하나 더 늘어난다. */
fieldset { border:0; min-inline-size:0; }
h1 { font-size:var(--t5); line-height:var(--t5-lh); font-weight:700; }
h2 { font-size:var(--t4); line-height:var(--t5-lh); font-weight:700; }
h3 { font-size:var(--t3); line-height:var(--gap-line); font-weight:700; }
/* 한국어 어절은 쪼개지 않는다. 일본어에는 어절 공백이 없어 같은 값이 제목을 통째로 화면 밖으로
   내보내므로(구두점 없는 제목) 표준 줄바꿈으로 되돌린다. 어느 쪽이든 마지막 방어는 break-word다. */
h1,h2,h3 { word-break:keep-all; overflow-wrap:break-word; }
html:lang(ja) :is(h1,h2,h3) { word-break:normal; }
p { font-size:var(--t3); color:var(--ink); }
a { color:var(--ink); text-underline-offset:var(--s1); }
button,input,select,textarea { font:inherit; margin:0; }
button,a,summary { touch-action:manipulation; }
button { cursor:pointer; }
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,summary:focus-visible {
  outline:var(--oa-focus) solid var(--ink); outline-offset:var(--s1);
}
small,.small { font-size:var(--t2); line-height:var(--gap-line); color:var(--ink-2); }
.eyebrow { display:block; color:var(--ink-2); font-size:var(--t2); font-weight:600; margin-bottom:var(--gap-item); }
/* 한 덩어리 코드 토큰·긴 주소는 글자 사이에 줄바꿈 기회가 없어 좁은 화면에서 문서를 넘긴다.
   🔴 2026-09-18 — **글꼴도 값이고, 이 사이트의 글꼴 값은 하나(--oa-font)다.** UA 기본값의
   monospace 는 그 한 값 밖의 두 번째 글꼴이었고(원칙 3·5), 그 글꼴의 세로 메트릭이 24px 줄 상자를
   밀어 올려 한 문단 안에 24·26px 두 줄 전진을 만들었다(실측 26px×54 /privacy/ko · ×6 en · ×5 es ·
   25px×10 ja). 실측으로 가려낸 원인이 **글꼴**이라는 것도 적어 둔다 — font-size·line-height 를
   문맥 값으로 못 박아도(둘 다 이미 15px/24px 였다) 26px 은 그대로였고, 글꼴을 문맥으로 되돌린
   경우에만 사라졌다. `<code>` 가 말하는 것은 모양이 아니라 **뜻**이고, 뜻은 태그가 지고 있다. */
code { overflow-wrap:anywhere; font-family:inherit; font-size:inherit; line-height:var(--gap-line); }
/* 감춘 것은 감춰진다 — 상자 규칙의 display가 UA 기본값을 이기지 못하게. */
[hidden] { display:none!important; }
/* 이름은 화면에 내지 않고 보조기술에만 주는 자리. */
.visually-hidden { position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
/* 착지 지점을 가진 요소가 고정 머리 아래로 내려앉을 여유를 직접 진다(값 한 벌). */
[id] { scroll-margin-top:var(--anchor-top); }

/* ═══════════════════════════════════════════════════════════════════════════
   층 3 — 머리·꼬리·본문 틀
   ═══════════════════════════════════════════════════════════════════════════ */
/* 머리의 문법은 한 벌이다: 좌 = 로고(아이콘 + 이름, 한 링크 = 그 언어의 홈) ·
   우 = 도구 메뉴와 언어 메뉴(언어는 사이트에서 유일한 창구라 항상 맨 오른쪽).
   세 부품의 **폭은 로케일과 무관하게 한 값**이다 — 글자가 바뀌어도 누를 자리는 움직이지 않는다. */
.site-header { width:100%; height:var(--oa-header-h); background:var(--bg); border-bottom:var(--oa-hair) solid var(--line); position:sticky; top:0; z-index:5; display:flex; justify-content:center; }
.header-inner { width:100%; max-width:var(--maxw); height:100%; padding-inline:var(--gutter); display:flex; align-items:center; justify-content:space-between; gap:var(--gap-item); }
.brand { display:inline-flex; align-items:center; gap:var(--gap-item); min-height:var(--touch); min-inline-size:var(--oa-brand-w); font-size:var(--t4); font-weight:700; text-decoration:none; white-space:nowrap; }
.brand img { display:block; width:var(--s5); height:var(--s5); }
.header-menus { display:flex; align-items:center; gap:var(--gap-item); }

/* 메뉴는 펼침 판을 **흐름 밖**에 둔다 — 항목 수를 따라 머리 높이가 흔들리면 면마다 틀이 달라진다. */
.menu { position:relative; }
/* 세로 패딩은 **0**이다 — 높이는 터치 하한 한 값이 정한다. 종전에는 일반 `summary` 규칙의
   세로 패딩(--s3 위아래)이 여기 그대로 남아 20.8+12+12+테두리 2 = **46.8px** 이 됐고,
   같은 「누르는 것」이 44(.btn·입력·행·로고)와 46.8 두 값으로 렌더됐다(전 27면 공통 셸). */
.menu > summary { display:inline-flex; align-items:center; justify-content:center; min-height:var(--touch); min-inline-size:var(--oa-menu-w); padding-block:0; padding-inline:var(--s3); border:var(--oa-hair) solid var(--line); border-radius:var(--r1); font-size:var(--t2); white-space:nowrap; list-style:none; }
.menu > summary::-webkit-details-marker { display:none; }
.menu[open] > summary { border-color:var(--accent); color:var(--accent); font-weight:700; }
.menu-list { position:absolute; right:0; top:calc(100% + var(--s2)); z-index:6; min-width:calc(var(--s6) * 6); max-width:calc(var(--s6) * 9); list-style:none; margin:0; padding:var(--s2); background:var(--surface); border:var(--oa-hair) solid var(--line); border-radius:var(--r1); box-shadow:var(--shadow-2); }
.menu-list a { display:flex; align-items:center; min-height:var(--touch); padding-inline:var(--s3); border-radius:var(--r1); font-size:var(--t2); text-decoration:none; }
.menu-list a[aria-current] { font-weight:700; background:var(--accent-soft); }

.site-footer { width:100%; max-width:var(--maxw); padding:var(--gap-section) var(--gutter) var(--oa-fab); border-top:var(--oa-hair) solid var(--line); }
.site-footer p { font-size:var(--t2); color:var(--ink-2); margin-top:var(--gap-item); }
/* 꼬리의 링크 열은 **칸을 똑같이 나눠 가진다** — 라벨 길이가 곧 좌표가 되면 언어를 바꿀 때 링크가 밀린다
   (실측 @390 두 번째 링크의 좌변 x: ko 80.56 · en 80.39 · ja 110.72 · es 182.98 — Δ 102.59px).
   머리 세 부품은 폭 하한으로 좌표를 못 박았고(--oa-menu-w·--oa-brand-w), 꼬리는 칸으로 못 박는다:
   칸 수가 같으면 네 로케일의 x 가 ±0으로 모이고, 글자만 바뀐다(원칙 1-1). */
.site-footer nav { display:grid; grid-auto-flow:column; grid-auto-columns:1fr; gap:var(--gap-item) var(--gap-block); margin-top:var(--gap-block); }
/* 칸 안에서 글자는 **정렬선에서 시작한다** — 가운데로 밀면 칸을 못 박은 보람이 없다(글자 길이가 다시 x가 된다). */
.site-footer a { min-height:var(--touch); min-inline-size:var(--touch); display:inline-flex; align-items:center; justify-content:start; font-size:var(--t2); }
.skip { position:absolute; left:var(--gutter); top:0; padding:var(--oa-pad); background:var(--surface); z-index:10; transform:translateY(-150%); }
.skip:focus { transform:none; }

main { width:100%; max-width:var(--maxw); padding:var(--gap-block) var(--gutter) var(--gap-section); flex:1 0 auto; }
/* main 직계의 세로 리듬은 **한 값**이다. 종전 `section + section`은 사이에 낀 숨은 요소(광고 자리·결과
   카드)나 비-section 블록에서 끊겨 같은 자리가 0px가 됐다 — 인접은 태그가 아니라 형제로 센다.
   숨은 형제는 상자를 만들지 않으므로 보이는 이웃 사이의 실간격은 그대로 한 값이 된다. */
main > * + * { margin-top:var(--gap-section); }

/* 위치 트레일 — 칸은 이름이다. 이름은 쪼개지 않고, 줄이 모자라면 칸째로 다음 줄에 내린다.
   자리는 머리 블록(.page-head) 안이다 — 위치·제목·한 줄 요약은 한 덩어리이고, main 직계 리듬을
   트레일 한 줄 때문에 두 값으로 가르지 않는다. */
.crumbs { display:flex; flex-wrap:wrap; align-items:center; gap:var(--gap-item); min-height:var(--touch); margin-bottom:var(--gap-block); font-size:var(--t2); }
.crumbs a { display:inline-flex; align-items:center; min-height:var(--touch); min-inline-size:var(--touch); }
.crumbs [aria-current] { color:var(--ink-2); }

/* 머리 블록 아래 간격은 main 리듬이 혼자 소유한다(값 하나에 주인 하나). */
:where(.page-head) p { margin-top:var(--gap-item); }
/* 절 머리 — 제목과 그 절의 행동 하나. 좁은 화면에서 **행동이 글자 단위로 접히지 않게** 한다:
   버튼은 제 폭을 지키고, 자리가 모자라면 행째로 다음 줄에 내려간다(실측: 접힌 버튼 높이 62px → 44px).
   같은 역할의 버튼이 면에 따라 다른 높이가 되면 그것이 곧 들쭉날쭉이다(원칙 9). */
.section-head { display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:var(--gap-block); margin-bottom:var(--gap-block); }
/* 절 머리에 붙는 버튼(현재 1건 — /mbti/ko 「고른 조합만 보기」)은 **행동 열의 칸이 아니다**:
   행(.actions)이 아니라 제목 줄에 붙는 토글이라 폭 격자(50%·상한)의 분모 밖이고, 라벨 길이가
   그대로 폭이 된다(실측 133px · 두 뷰포트 같은 값 · 눌러도 라벨이 바뀌지 않아 폭이 흔들리지 않는다).
   「행동 열 칸 폭 1종」은 `.actions` 안의 칸에 대한 약속이고, 이 자리는 그 약속의 예외가 아니라
   **다른 역할**이다 — 축을 넓힐 일이 생기면 여기 이 줄부터 고친다(2026-09-18 4회차 ㉡ 기각 근거). */
.section-head > .btn { white-space:nowrap; }

/* ═══════════════════════════════════════════════════════════════════════════
   층 3 — 상자와 목록
   ═══════════════════════════════════════════════════════════════════════════ */
/* 트랙은 **접지 않는다**(auto-fill). auto-fit은 빈 트랙을 접어 카드가 한 장뿐인 면에서 같은 역할의
   카드를 두 배 폭으로 만든다 — 언어만 바꿨는데 카드 폭이 356px↔728px로 갈렸다(실측 @1280). */
.grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,calc(var(--s6) * 10)),1fr)); gap:var(--gap-block); }
.card { display:block; background:var(--surface); color:var(--ink); border:var(--oa-hair) solid var(--line); border-radius:var(--r1); padding:var(--oa-box-pad); text-decoration:none; }
/* 답하지 않은 문항처럼 "아직 채워지지 않았다"는 상태는 모양이 말한다(안내 문장으로 때우지 않는다). */
.card.is-missing,.is-missing { border-color:var(--bad); }
a.card:hover { box-shadow:var(--shadow-1); }
.card-title { display:flex; justify-content:space-between; align-items:center; gap:var(--gap-item); }
.card-title strong { font-size:var(--t4); line-height:var(--t5-lh); }
/* 문맥이 정하는 기본 간격은 **역할 유틸리티에 지지 않는다** — :where()로 명시도를 0으로 낮춘다.
   종전에는 `.card p`(0-1-1)가 `.space-top`(0-1-0)을 이겨 같은 클래스가 8px과 16px 두 값으로 렌더됐다. */
:where(.card) p { margin-top:var(--gap-item); }
.example { margin-top:var(--gap-block); font-size:var(--t2); color:var(--ink-2); }
.badge { display:inline-flex; align-items:center; padding:var(--s1) var(--s2); border:var(--oa-hair) solid var(--line); border-radius:var(--r2); font-size:var(--t1); font-weight:600; line-height:var(--gap-line); color:var(--ink-2); vertical-align:middle; }

/* 행 높이는 **한 값**이다 — 설명 줄이 한 줄 더 감긴 행만 79.2 → 100px 로 솟아, 같은 목록 안에서
   행이 두 높이로 렌더됐다(@390 실측 3면). 같은 결함을 `.field-grid` 에서 이미 판정·수리했고
   (`grid-auto-rows:1fr`), 처방도 같은 하나다 — 행 상자는 격자가 나눠 주고 링크가 그 칸을 다 쓴다. */
.row-list { display:grid; grid-auto-rows:1fr; list-style:none; border-top:var(--oa-hair) solid var(--line); }
.row-list > li { border-bottom:var(--oa-hair) solid var(--line); }
.row-list > li > .row-link { block-size:100%; }
/* 행 사이의 간격은 **머리카락 선**이 말한다 — 본문 목록의 항목 간격(8px)이 겹치면 격자가 나눠 준
   같은 높이의 칸 안에서 행만 8px 낮아진다(실측 @390 /menu/ja 88.2 · 80.2). 역할 목록이 문맥을 이긴다. */
ul.row-list > li + li { margin-top:0; }
.row-link { display:flex; align-items:center; justify-content:space-between; gap:var(--gap-block); padding:var(--s3) 0; text-decoration:none; min-height:var(--touch); }
.row-link strong { display:block; font-size:var(--t4); line-height:var(--t5-lh); font-weight:600; }
.row-link small { display:block; margin-top:var(--gap-item); }
.row-link:hover strong { text-decoration:underline; text-underline-offset:var(--s1); }
.row-link .arrow { flex:none; }
.inline-links { display:flex; flex-wrap:wrap; gap:var(--gap-item) var(--gap-block); }
/* 홀로 선 링크 줄 — 양축이 타깃이다(한두 글자짜리 등급 이름도 손가락으로 눌린다).
   **가운데 정렬은 하지 않는다**: 종전에는 짧은 라벨의 잉크가 44px 상자 한가운데로 밀려
   줄 첫 칸이 정렬선 A에서 +15px 떨어져 앉았다(실측 46건). 잉크는 상자 왼쪽 = 정렬선에서 시작한다. */
.inline-links a { display:inline-flex; align-items:center; min-height:var(--touch); min-inline-size:var(--touch); }
/* 링크의 역할은 **둘**이다 — 이름이 하나였던 것이 결함의 뿌리였다(2026-09-18 재심사 ㉠).
   ① 문장 안 링크(.text-link) — 글의 일부다. 상자를 갖지 않는다.
   ② 홀로 선 링크(.tap-link · .inline-links a · .row-link · .menu-list a · .site-footer a · .crumbs a)
      — 줄·칸·문단이 통째로 그 링크 하나인 자리다. 손가락이 겨냥하는 것이 그것뿐이므로 터치 하한을 진다.

   종전에는 ①에도 `inline-flex + min-height/min-inline-size:44px + justify-content:center` 를 줬고,
   그 상자가 문장 안에서 세 가지를 동시에 부쉈다(실측):
     · 44px 상자가 24px 줄 상자를 밀어 **한 문단 안에 24·26·32·34·36·44px** 줄 전진이 났다(20면).
     · 44px 폭 하한이 짧은 라벨의 잉크를 가운데로 밀어 **정렬선을 이탈**시켰다(554건 중 46건, 최대 +16px —
       「凶」·「§4」 같은 한두 글자 링크. 목록 선두에서는 새 정렬선까지 만들었다).
     · 그 남는 폭이 **글자 사이의 죽은 칸**으로 보였다(좌우 각 12~16px).
   WCAG 2.5.8 은 문장 안 인라인 링크를 타깃 크기 예외로 둔다 — 인라인 상자는 줄바꿈이 되지 않아
   긴 링크가 줄을 넘기기 때문이다. 형제 사이트가 이미 같은 축으로 서 있고, 여기도 같다.
   배포 전 검사는 이 예외를 **세서 적어 둔다** — 숨기지 않는다.

   ①이 보장하는 것은 글자 크기가 문맥의 것이라는 점뿐이다(15px 문단 안은 15px, 13px 주석 안은 13px). */
.text-link { display:inline; font-size:inherit; }
/* ② 홀로 선 링크의 몸 — `.inline-links` 가 이미 갖고 있던 그 모양이고, 컨테이너가 없는 자리(표 칸·
   한 줄짜리 문단·목록 항목)에서는 링크 자신이 단다. 가운데 정렬은 하지 않는다 — 잉크는 제 정렬선에서 시작한다. */
.tap-link { display:inline-flex; align-items:center; min-height:var(--touch); min-inline-size:var(--touch); font-size:inherit; }

/* ═══════════════════════════════════════════════════════════════════════════
   층 3 — 버튼 위계 (주 = 채움 · 보조 = 외곽선)
   ═══════════════════════════════════════════════════════════════════════════
   골격이 `.btn`의 뼈대(글자·높이·안쪽 여백·반경·테두리 굵기)를 이미 정해 두었다.
   여기서는 **위계 색**만 얹는다. 화면마다 새 모양을 발명하지 않는다. */
.btn { display:inline-flex; justify-content:center; align-items:center; gap:var(--gap-item); text-decoration:none; line-height:var(--t5-lh); background:var(--accent); color:var(--accent-ink); border-color:var(--accent); }
/* 보조 버튼의 면색은 뿌리에서 한 번 굳혀 쓴다 — 상자가 --surface를 덮어도 같은 역할이 두 모양이 되지 않게. */
:root { --oa-btn-surface:var(--surface); }
.btn.secondary { background:var(--oa-btn-surface); color:var(--accent); border-color:var(--accent); }
.btn:hover { text-decoration:underline; }
.btn:active { outline:var(--oa-hair) solid var(--ink); outline-offset:calc(var(--oa-hair) * -1); }
.btn:disabled,.btn[aria-disabled="true"] { background:var(--bg); color:var(--ink-2); border-color:var(--line); cursor:default; }
/* 결과 뒤 행동 열은 스크롤 상자 바닥에서 위젯 여백만큼 떨어져 멈춘다(레이아웃은 그대로). */
.actions { display:flex; flex-wrap:wrap; gap:var(--gap-item); margin-top:var(--gap-block); scroll-margin-bottom:var(--oa-fab); }
/* 한 줄 안의 버튼은 폭을 똑같이 나눠 가진다 — 같은 역할이 글자 수에 따라 다른 폭이 되지 않게(실측 편차
   최대 88px · 주 버튼이 보조보다 좁은 줄 10건).
   🔴 2026-09-18 — 기준 폭(160px)만 주고 **열 수를 자리에 맡겼더니** 같은 행동 열이 면마다 2·3·4열이
   됐고, 좁아진 칸에서 라벨이 감겨 44px 행이 62px가 됐다(실측 10건: /seiza-aisho/ja 4열 176px ·
   /flames/en·/calculadora-del-amor/es 2열 175px). 행 높이는 **한 값**이어야 하므로 열 수를 선언한다 —
   좁은 화면 1열, 그 위 2열. 그러면 한 칸의 폭이 면과 무관해지고 라벨이 감길 자리가 없다. */
/* 🔴 2026-09-18(2) — 열 수를 선언했는데도 **폭이 다섯 종**이었다(@1280 실측 344·360·522.4·696·728).
   `flex:1 1 basis` 는 기준 폭만 말하고 남는 자리는 `grow` 가 가져간다 — 그래서 한 칸짜리 행에서는
   칸이 100%까지 늘고(696·728), `.btn` 이 아닌 형제(`.tap-link`)가 섞인 행에서는 또 다른 값이 됐다
   (522.4 · /ideal-type/ko 첫 화면). 한 면 안에서 같은 **보조** 버튼이 360과 728로 이웃했다.
   그래서 기준 폭과 **상한**을 같은 값으로 못 박는다: 한 칸짜리 행도 두 칸 폭을 넘지 않는다.
   대상은 `.btn` 만이 아니라 **행동 열의 칸 전부**다 — 역할이 섞인 행도 같은 격자를 탄다. */
.actions > :is(.btn,.tap-link) { flex:1 1 calc(50% - var(--gap-item)); max-inline-size:calc(50% - var(--gap-item)); }

/* ═══════════════════════════════════════════════════════════════════════════
   층 3 — 입력
   ═══════════════════════════════════════════════════════════════════════════ */
/* 행 높이는 **한 값**이다 — 칸의 글자 수가 행마다 다르면 같은 격자 안에서 행이 104px·80px 두 높이로
   갈린다(실측 /mbti/ko @390: 16칸 중 14칸 104 · INFJ·INTJ 줄만 80 — 그 줄만 눈에 띄게 낮았다).
   자동 행을 1fr 로 두면 가장 큰 행에 맞춰 전부 같아진다(칸은 이미 행 안에서 늘어난다). */
.field-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,calc(var(--s6) * 7)),1fr)); grid-auto-rows:1fr; gap:var(--gap-block); }
.pair-fields { grid-template-columns:repeat(2,minmax(0,1fr)); }
label { display:block; font-weight:600; }
/* 입력 글자는 16px 밑으로 내리지 않는다(작은 화면이 스스로 확대한다) — 골격 단계에서 그 위의 것을 쓴다. */
.control { display:block; width:100%; min-height:var(--touch); padding:var(--s2) var(--s3); margin-top:var(--gap-item); border:var(--oa-hair) solid var(--ink-2); border-radius:var(--r1); background:var(--surface); color:var(--ink); font-size:var(--t4); font-weight:400; line-height:var(--t5-lh); }
/* 높이는 **한 값**이다. select는 UA가 line-height를 무시해 같은 클래스가 46px·44.39px 두 상자가 됐다
   (같은 폼 안에서 위아래로 붙어 있어 눈에 보였다). 그래서 상자 높이를 골격 값으로 직접 못 박는다 —
   값은 터치 타깃 그 자체다(안쪽 42px에 22px 글자가 잘림 없이 든다 — scrollHeight == clientHeight 실측).
   여러 줄 입력(textarea)은 줄 수가 높이를 정하므로 이 축 밖이다. */
:is(input,select).control { block-size:var(--touch); }
textarea.control { block-size:auto; }
.control::placeholder { color:var(--ink-2); opacity:1; }
.control:disabled { color:var(--ink-2); }
.form-note { margin-top:var(--gap-item); font-size:var(--t2); color:var(--ink-2); }
.error-box { margin-top:var(--gap-item); padding:var(--oa-box-pad); background:var(--surface); color:var(--ink); border:var(--oa-hair) solid var(--line); border-radius:var(--r1); }
/* 보기 하나가 한 줄 설명을 데리고 있으면 제목과 설명을 줄로 가른다. 라디오 자체는 24px 정사각을 지킨다. */
.radio-row { display:flex; align-items:center; gap:var(--gap-item); min-height:var(--touch); border-bottom:var(--oa-hair) solid var(--line); }
.radio-row input { width:var(--s5); height:var(--s5); flex:none; accent-color:var(--accent); }
.radio-row strong,.btn strong { display:block; font-weight:600; }
.radio-row strong + small,.btn strong + small { display:block; margin-top:var(--gap-item); }
.state-row { display:flex; flex-wrap:wrap; gap:var(--gap-item); align-items:center; }
.progress-track { height:var(--s2); background:var(--line); border-radius:var(--r2); margin-top:var(--gap-item); }
.progress-fill { height:100%; width:50%; background:var(--accent); border-radius:var(--r2); }

/* ═══════════════════════════════════════════════════════════════════════════
   층 3 — 결과·펼침·표
   ═══════════════════════════════════════════════════════════════════════════ */
.result-card { border-top-width:var(--s1); }
/* 결과 카드는 절 안에 있기도 하고(블록 간) main 직계이기도 하다(섹션 간) — 어느 쪽이든 **자리가 정하게**
   :where()로 명시도를 0으로 낮춘다. 그러지 않으면 같은 결과 카드가 면에 따라 16px·32px 두 리듬을 탄다. */
:where(.result-card) { margin-top:var(--gap-block); }
/* 🔴 `.result-title` 은 **절 제목이 아니라 결과 값의 표시**다 — 역할이 다르므로 크기도 다르다.
   문서 개요를 위해 태그는 h2 를 쓰지만(결과 카드의 머리), 위계로는 「화면 최대 값」(--t6)이다.
   절 제목(h2)은 사이트 전체에서 한 값(--t4)이고, 두 역할이 섞이지 않게 여기서 갈라 적는다. */
.result-title { font-size:var(--t6); line-height:var(--t6-lh); margin-top:var(--gap-item); font-weight:700; overflow-wrap:break-word; }
.result-card h2 { color:var(--ink); }
.result-card .lead { font-size:var(--t4); line-height:var(--t5-lh); margin-top:var(--gap-item); }
.result-points { margin-top:var(--gap-block); display:grid; gap:var(--gap-item); }
.result-points dt { font-weight:600; font-size:var(--t2); }
.result-points dd { margin-top:var(--gap-item); }

/* 실선은 **본문 아코디언의 것**이다 — 머리의 도구·언어 트리거도 details 로 짓지만 그것은 메뉴이지
   아코디언이 아니다. 걸러 두지 않으면 한 줄에 선 같은 역할의 두 트리거가 다른 모양이 된다:
   도구는 위에만 실선이 걸려 y=7.59 h=47.80, 언어는 마지막 자식이라 아래까지 걸려 y=7.09 h=48.80 —
   높이 1px·세로 위치 0.5px가 어긋나고, 트리거 위아래에 쓸모없는 머리카락 선이 그려졌다(전 27면 공통 셸). */
details:not(.menu) { border-top:var(--oa-hair) solid var(--line); }
details:not(.menu):last-child { border-bottom:var(--oa-hair) solid var(--line); }
/* 요약의 글자는 **정렬선 A**에서 시작한다. UA 기본 ::marker(펼침 삼각형)는 글자만 15.89px 밀어
   제목이 제 본문(.detail-body)보다 안쪽으로 들어가는 모양을 만들었다(186곳). 마커를 걷고, 눌러
   보이게 하는 표시는 행 오른쪽 끝에 둔다 — 사이트가 이미 쓰는 글리프(›)를 돌려 쓴다(새 모양 0). */
/* 「누르는 것」의 높이는 **한 값**이다(--touch). 종전에는 본문 아코디언 트리거만 세로 패딩을 얹어
   48px 로 렌더돼, 버튼·입력·홀로 선 링크·머리 트리거가 모두 44 인 사이트에서 이것만 홀로 섰다.
   머리 트리거를 46.8 → 44 로 고친 것과 같은 축이다 — 높이는 터치 하한 한 값이 정하고,
   세로 패딩은 0이다(라벨이 감기는 좁은 화면에서는 줄 수만큼 자라고, 그 자람은 구조의 몫이다). */
summary { display:flex; align-items:center; justify-content:space-between; gap:var(--gap-block); min-height:var(--touch); padding-block:0; padding-inline:0; cursor:pointer; font-weight:600; font-size:var(--t3); list-style:none; }
summary::-webkit-details-marker { display:none; }
details:not(.menu) > summary::after { content:"\203A"; flex:none; color:var(--ink-2); transform:rotate(90deg); }
details:not(.menu)[open] > summary::after { transform:rotate(-90deg); }
/* 본문 블록은 **칠하지 않은 컨테이너**다 — 배경도 테두리도 없어서 그 세로 안쪽 여백은 눈에 그냥 빈
   띠로 보이고, 이웃이 말한 간격과 그대로 **합산**된다. 실측으로 네 가지 값이 여기서 나왔다:
   위 12(그 자체가 관계 간격) · `.stack`(16)+12=28 · 아래 16+`.form-note`(8)=24 · 아래 16+섹션 간(32)=48.
   선언은 전부 토큰인데 렌더가 토큰 밖이었다 — 칠하지 않은 컨테이너는 세로 여백을 갖지 않는다. */
.detail-body { padding:0; }
/* 아코디언 밖에 선 본문 블록(22곳)은 제 위 간격을 **블록 간 한 값**으로 갖는다. 격자·스택이 이미
   간격을 말하는 자리에서는 아래 §「간격은 한 번만 말한다」가 이 margin 을 0으로 내린다 — 주인은 하나다. */
:where(:not(details)) > .detail-body { margin-top:var(--gap-block); }
/* 펼친 아코디언의 아래 여백은 **제 상자 안**이다 — 실선이 그 상자를 열고 닫으므로 요약 행의 안쪽
   여백과 같은 한 단을 쓴다(바깥 공백이 아니라 상자의 몫이라, 다음 형제의 간격과 합산되지 않는다). */
details:not(.menu)[open] { padding-bottom:var(--s3); }
.detail-body p + p { margin-top:var(--gap-block); }
/* ── 본문 목록의 정렬 정책 **한 벌**(2026-09-18 4회차 ㉡) ──────────────────────────
   재는 것은 상자가 아니라 **잉크**다. 그래서 규칙도 잉크로 적는다:
     ① 목록의 **글자**는 제 문맥의 본문 정렬선에서 시작한다 — 카드 안이면 B, 카드 밖이면 A+한 단.
     ② **글머리는 그 글자 왼쪽 한 단(16px) 띠 안**에 그린다. 그 띠를 넘어 테두리나 정렬선 A를
        침범하지 않는다.
   종전에는 두 처방이 서로를 밀어냈다. 카드 **밖**은 `::marker` 가 글자보다 한 단 왼쪽에 그려지는데
   그 간격이 상자 안쪽 여백보다 넓어 **글머리 잉크가 A보다 1.5px 왼쪽**으로 나갔고(실측 x=15.0 · A=16),
   카드 **안**은 그것을 `list-style-position:inside` 로 막았더니 이번엔 **글자**가 B+21에 서서
   한 면 안에서 목록 글자가 32와 53 두 줄에 섰다(그 면의 문단 잉크는 32.25).
   `::marker` 의 자리는 시트가 정할 수 없다 — 그래서 **글머리를 우리가 그린다**: 목록은 마커를 끄고,
   항목이 제 왼쪽 띠에 기호(또는 번호)를 얹는다. 띠 폭·글자 자리가 전부 토큰 배수이고 두 문맥의
   차이는 들여쓰기 한 줄뿐이다. 명시도를 :where() 로 낮춘 것은 역할 목록(.source-list)이
   문맥 규칙에 지지 않게 하려는 것이다 — `!important` 같은 사문(死文) 없이 역할이 이긴다. */
:where(.detail-body) :is(ul,ol) { list-style:none; padding-left:var(--oa-pad); counter-reset:oa-li; }
/* 역할 목록(.source-list·.row-list·.inline-links…)은 제 모양을 이미 가진다 — 본문 목록 정책 밖이다.
   :where() 안의 :not() 은 명시도를 올리지 않으므로 역할 규칙이 계속 이긴다. */
:where(.detail-body) :is(.source-list,.row-list,.menu-list) { padding-left:0; counter-reset:none; }
:where(.detail-body) :is(.source-list,.row-list,.menu-list) > li::before { content:none; }
/* 카드 **안**은 상자의 안쪽 여백이 곧 글머리 띠다 — 글자는 B(=상자 안쪽 모서리)에서 시작한다. */
:where(.card) :where(.detail-body) :is(ul,ol) { padding-left:0; }
:where(.detail-body) :is(ul,ol) > li { position:relative; counter-increment:oa-li; }
:where(.detail-body) :is(ul,ol) > li::before {
  position:absolute; inset-inline-start:calc(var(--oa-pad) * -1); inline-size:var(--oa-pad);
  text-align:center; color:var(--ink-2);
}
:where(.detail-body) ul > li::before { content:"\2022"; }
:where(.detail-body) ol > li::before { content:counter(oa-li) "."; font-size:var(--t2); }
.detail-body li + li { margin-top:var(--gap-item); }
.source-list { list-style:none; padding-left:0; }
.source-list li { padding:var(--s3) 0; border-bottom:var(--oa-hair) solid var(--line); }
.source-list strong { display:block; font-size:var(--t2); }
.source-list a { display:flex; align-items:center; min-height:var(--touch); font-size:var(--t2); overflow-wrap:anywhere; }

table { border-collapse:collapse; width:100%; font-size:var(--t2); font-variant-numeric:tabular-nums; }
caption { text-align:left; font-size:var(--t4); line-height:var(--t5-lh); font-weight:600; padding:var(--gap-block) 0 var(--s2); }
th,td { padding:var(--s3) var(--oa-pad); text-align:left; border-bottom:var(--oa-hair) solid var(--line); vertical-align:top; }
/* 표의 첫 칸 글자는 본문과 같은 세로선(A)에서 시작하고, 마지막 칸은 컨테이너 모서리에서 끝난다.
   안쪽 여백은 칸과 칸 **사이**에만 쓴다 — 표 하나 때문에 정렬선이 하나 더 생기지 않게. */
th:first-child,td:first-child { padding-left:0; }
th:last-child,td:last-child { padding-right:0; }
/* 찾은 칸은 모양으로 말한다 — 조회 결과가 색과 굵기로 그 자리에서 보인다. */
th.hit,td.hit { background:var(--accent-soft); color:var(--ink); font-weight:700; outline:var(--oa-focus) solid var(--accent); outline-offset:calc(var(--oa-hair) * -2); }
/* 머리글은 이름이다 — 자동 배치가 짧은 칸을 한 글자까지 짜부라뜨리지 않게 하한을 준다. */
th { min-inline-size:calc(var(--s6) * 4); }
.num { font-variant-numeric:tabular-nums; }
th.num,td.num { text-align:right; }
/* 표 상자의 **위 간격은 표가 갖는다** — 감싸는 것이 `.stack`(gap 16)이냐 `<section>` 직계냐에 따라
   같은 「제목/설명 → 표」 경계가 16px·0px 두 값으로 갈렸다(실측 28자리 중 0px 23자리·11면. 촬영으로
   /shindan-type-fcpe/ja 의 제목이 표 머리행에 붙어 있었다). 간격의 주인을 상자 자신으로 옮기면
   컨테이너가 무엇이든 한 값이다 — 격자가 이미 말하는 자리에서는 아래 §「간격은 한 번만 말한다」가
   이 margin 을 0으로 내리고 gap 이 같은 값을 준다(주인은 언제나 하나). */
.table-wrap { overflow-x:auto; margin-top:var(--gap-block); }
/* 열이 셋 이상인 표는 본문 폭 아래로 쥐어짜지 않고 컨테이너 안에서 옆으로 민다. */
.table-wrap > table:has(tr > :nth-child(3)) { min-width:calc(var(--maxw) - var(--gutter) * 2); }

.stack { display:grid; gap:var(--gap-block); }
.space-top { margin-top:var(--gap-block); }
/* 절 안에서 **주제가 바뀌는 자리**는 제목이 말한다 — 그 앞은 블록 간 한 값이다. 앞 내용과 다음 제목이
   0px로 맞붙으면 주제 전환이 모양으로 보이지 않는다(실측 2자리: /flames/en #meaning · /omikuji/ja).
   첫 자식 제목에는 붙지 않는다(절·상자가 이미 제 위 간격을 말했다). main 직계는 이 축 밖이다 —
   그 리듬은 `main > * + *`(섹션 간) 혼자 소유한다. */
:where(section,article,.detail-body) > * + :is(h2,h3) { margin-top:var(--gap-block); }

/* ═══════════════════════════════════════════════════════════════════════════
   층 3 — 간격은 한 번만 말한다
   ═══════════════════════════════════════════════════════════════════════════
   ① **격자가 말하는 자리에서는 자식이 말하지 않는다.** 컨테이너의 `gap` 과 자식의 세로 `margin`
      이 합산되면 같은 관계가 한 면 안에서 두 값이 된다 — 실측: `.stack`(16) 안의 `.form-note`(8)가
      24를 만들어 16과 24가 갈렸다(8면 24건). 선언은 토큰인데 **렌더가 갈라지던** 자리라
      정적 검사로는 보이지 않았다. 간격의 주인을 컨테이너 하나로 못 박는다.
   ② **내용이 없으면 자리도 없다**(원칙 8의 세로판). 빈 문단·빈 슬롯이 격자 한 칸을 차지하면
      그 칸과 gap 만큼 화면이 벌어진다 — 실측 48px 구멍 1건(빈 상태 문단이 격자 자식이었다).
      모양을 위한 상자(진행 막대 같은 것)는 내용이 없는 것이 정상이라 이 규칙의 대상이 아니다. */
:is(.grid,.field-grid,.stack,.result-points,.actions,.inline-links,.state-row) > * { margin-block:0; }
/* ③ **상자의 첫 자식은 위 간격을 갖지 않는다.** 안쪽 한 단 위에 항목 간격이 한 번 더 얹히면 같은 상자의
   위/아래가 24/16 으로 갈린다(실측 22곳 — `:where(.card) p` 가 첫 자식에도 걸렸다). 상자 안쪽 여백은
   상자가 소유한 한 값이다. 자리는 이 절이다 — 역할 유틸리티(.space-top)보다 **뒤에** 서야 이긴다. */
:where(.card) > :first-child { margin-top:0; }
:is(p,ul,ol,dl,.grid,.field-grid,.row-list,.source-list,.actions,.inline-links,.detail-body,.result-points,.stack,.space-top):empty { display:none; }

/* ═══════════════════════════════════════════════════════════════════════════
   층 3 — 좁은 화면
   ═══════════════════════════════════════════════════════════════════════════
   골격의 중단점은 두 개뿐이고, `@media`는 var()를 읽지 못하므로 그 값을 그대로 적는다.
   좁은 화면에서는 ⓐ 행동 버튼이 폭을 나눠 가지며 ⓑ 오른쪽 끝의 화살표를 접는다(그 자리는 고정
   위젯이 앉는 세로 띠와 같아서, 겨냥하게 만드는 표시를 두지 않는다).
   위치 트레일은 접지 않는다 — 칸이 줄을 넘으면 칸째로 내려가고, 구분 기호가 남아 이름이 이어져
   보이지 않는다(종전에는 앞 칸과 기호를 함께 숨겨 이름 두 개가 붙어 보였다). */
@media (max-width:560px) {
  .row-link .arrow,.card-title > [aria-hidden="true"] { display:none; }
  /* 좁은 화면의 행동 열은 **1열**이다 — 2열(175px)에서는 긴 라벨이 두 줄로 감겨 행이 62px가 됐다.
     상한도 같이 푼다(상한만 남으면 1열 선언이 반 칸에서 멈춘다 — 폭의 주인은 언제나 한 쌍이다). */
  .actions > :is(.btn,.tap-link) { flex-basis:100%; max-inline-size:100%; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   층 3 — 움직임을 줄이라고 말한 사람 (원칙 13 · W3C prefers-reduced-motion)
   ═══════════════════════════════════════════════════════════════════════════
   시트에 이 질의 블록이 **한 곳도 없었다**(base-tokens·v2 전수). 그동안 움직임의 주인은 JS 쪽
   `behavior:'smooth'` 세 모듈뿐이었고, 그 호출은 사람의 설정을 묻지 않았다 — reduce 문맥에서도
   같은 ~500ms 애니메이션이 그대로 돌았다(실측: /shindan-aisho/ja 제출 뒤 scrollY 40ms×14 표본).
   JS 쪽은 착지 정책 한 벌(assets/tool-result.js)이 matchMedia 로 묻게 고쳤고, 여기서는 **선언으로**
   같은 말을 한 번 더 한다: 앞으로 시트에 들어올 어떤 움직임도 이 질의 아래에서 멈춘다.
   `!important` 는 쓰지 않는다 — 이 시트에 이 값들의 다른 주인이 없으므로 필요가 없다. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior:auto; }
  *,*::before,*::after { animation-duration:1ms; animation-iteration-count:1; transition-duration:1ms; }
}

/* ── 사이트 슬롯 — 빌드 스탬프 ─────────────────────────────────────────────
   캐시를 비우지 않은 평소 브라우저에서 "이 화면이 어느 배포인가"를 읽는 자리다.
   원본은 항상 "dev"이고, 배포 빌더가 배포 트리에서 커밋 해시로 치환한다.
   읽는 법: getComputedStyle(document.documentElement).getPropertyValue('--build') */
:root { --build:"efb3cf5947c55d86c98b9d1199636b65131d8667"; }
