/*!
 * seran-prose.css — 본문(산문) 지면 스타일시트 (모듈: prose-css)
 *
 * 소유 계약: assets/css/seran-prose.css · _wiring/prose-css.md
 *
 * 무엇을 위한 시트인가
 *   Brizy 를 걷어내며 scripts/migrate/07-pages.php 가 본문을 "정적화"했다.
 *   컨테이너(div/section/span/…)는 전면 평탄화됐고 클래스는 거의 남지 않았다 →
 *   지금 본문은 사실상 **p·h·img·ul·table 이 평평하게 나열된 문서**다.
 *   이 시트의 목표는 딱 하나: **시맨틱 HTML 만 있어도 읽을 만한 지면이 되게 한다.**
 *   콘텐츠 페이지(병원소개·의료진·진단서·비급여) · 증상가이드 · 공지/이벤트 본문이
 *   모두 `.seran-prose` 컨테이너 하나를 공유한다.
 *
 * 원칙 (CONTRACT-FRONT.md)
 *   §0-1  Brizy 클래스(brz-*)·토큰·엔드포인트를 되살리지 않는다. 구조만 읽고 새로 쓴다.
 *   §0-3  인라인 style 금지. 전부 클래스 기반.
 *   §0-4  색·반경·글꼴은 seran 디자인 토큰(assets/css/seran-tokens.css · static-pages 소유)만.
 *         **이 파일에는 hex 리터럴이 한 개도 없다.** 투명 틴트가 필요하면 color-mix() 로
 *         토큰에서 유도한다.
 *   모바일 우선 — 기본 규칙이 좁은 화면, 확장은 `@media (min-width:…)`.
 *   다크 모드 없음(라이트 전용). 토큰만 쓰므로 토큰이 바뀌면 자동으로 따라간다.
 *
 * 로드 순서 (중요 — _wiring/prose-css.md §5-1)
 *   clinic-skin-style(style.css) → seran-tokens → **seran-prose** → seran-{layout,guide,notice,…}
 *   `seran-tokens` 에 의존을 걸어 등록한다.
 *
 * 특정도 메모 (읽고 고칠 것)
 *   `seran-tokens.css` §4 가 이미 `.seran-prose p{…}` `.seran-prose table{…}` 같은
 *   **(0,1,1)** 규칙을 들고 있다. 그래서 이 시트에서 그 값을 갈아끼우려면
 *   (0,1,1) 이상이 필요하다. 흐름 여백처럼 `> *` 로 걸어야 하는 규칙은
 *   클래스를 두 번 적어(`.seran-prose.seran-prose > *` = (0,2,0)) 특정도를 올린다.
 *   반대로 **다른 모듈이 자기 클래스로 그린 표**(예: [clinician_schedule] 의
 *   `table.cs-matrix2`)는 건드리지 않도록, 표 규칙은 `table:not([class])` 와
 *   `table.seran-table` 에만 건다.
 *
 * 목차
 *   1. 컨테이너 · 지역 변수 · 폭
 *   2. 섹션 리듬(수직 여백)
 *   3. 타이포 — 제목 · 문단 · 리드 · 인용 · 강조
 *   4. 링크 · 버튼(.seran-btn)
 *   5. 리스트 — ul/ol/중첩 · 체크리스트 · 다단
 *   6. 강조 박스(.seran-callout — 정보/주의)
 *   7. 이미지 · figure · 아이콘 크기 이미지
 *   8. 아이콘 카드 그리드(.seran-cards)
 *   9. 정의형 행(.seran-deflist)
 *  10. 표 — 래퍼 스크롤 · 반응형 카드 변환 · 숫자 정렬
 *  11. 정적화 잔존 클래스 호환(비급여 수가표 등)
 *  12. 유틸리티 · 접근성 · prefers-reduced-motion
 */

/* =========================================================================
   1. 컨테이너 · 지역 변수 · 폭

   `.seran-prose` 자체(최대폭·글꼴·행간)는 seran-tokens §4 가 이미 선언한다.
   여기서는 그 위에 **지역 변수**를 얹고, 본문 측정폭(measure)과
   넓은 요소의 breakout 을 정의한다.
   전역 토큰을 새로 만들지 않는다 — 아래 --prose-* 는 `.seran-prose` 안에서만 산다.
   ========================================================================= */

.seran-prose {
	/* 본문 한 줄 길이. 한글 기준 68ch ≈ 37~40자/행. */
	--prose-measure: 68ch;

	/* 수직 리듬 */
	--prose-rhythm: 1.15em;      /* 형제 요소 사이 기본 간격 */
	--prose-rhythm-lg: 2.4em;    /* h2 앞(=섹션 경계) */
	--prose-rhythm-md: 1.8em;    /* h3 앞 */

	/* 넓은 요소(표·이미지·카드)가 본문 폭 밖으로 나가는 양.
	   (100vw - 여유 - 컨테이너 폭) / 2 를 0~150px 로 자른다.
	   화면이 좁으면 자동으로 0 이 되므로 가로 스크롤이 생기지 않는다.
	   여유 56px = 컨테이너 좌우 패딩(40px) + 세로 스크롤바 보정(100vw 는
	   스크롤바를 포함하므로 그만큼 넘칠 수 있다). */
	--prose-bleed: clamp(0px, (100vw - 56px - 100%) / 2, 150px);

	/* 컴포넌트 치수 */
	--prose-card-min: 200px;
	--prose-icon: 56px;
	--prose-anchor-offset: 96px;  /* 고정 헤더 아래로 앵커가 숨지 않게 */

	/* 토큰에서 유도한 틴트 — hex 를 새로 만들지 않기 위한 color-mix 레이어 */
	--prose-tint-orange: color-mix(in srgb, var(--seran-orange) 8%, transparent);
	--prose-tint-olive: color-mix(in srgb, var(--seran-olive) 10%, transparent);
	--prose-tint-error: color-mix(in srgb, var(--seran-error) 8%, transparent);
	--prose-hairline: color-mix(in srgb, var(--seran-line) 55%, transparent);
	--prose-row-hover: color-mix(in srgb, var(--seran-bg-warm) 60%, transparent);
}

/* 컨테이너 변형 --------------------------------------------------------- */

/* 넓은 지면 — 표·카드 위주 페이지(비급여 등). seran-tokens 가 선언한 별칭과 짝. */
.seran-prose.seran-prose--wide {
	max-width: var(--seran-content-width);
}

/* 좁은 지면 — 읽기 전용 안내문 */
.seran-prose.seran-prose--narrow {
	max-width: var(--prose-measure);
}

/* 이미 폭·패딩을 가진 부모 안에 들어갈 때(증상가이드 `.seran-guide__body`,
   공지 `.seran-notice-single__body` 처럼) 이중 여백을 없앤다.
   → the_content 래퍼 배선에서 페이지가 아닌 글에는 이 변형을 준다. */
.seran-prose.seran-prose--flush {
	max-width: none;
	margin-inline: 0;
	padding-inline: 0;
}

/* 본문 측정폭 — 글자 블록만 68ch 로 잡고 가운데 정렬한다.
   표·이미지·카드는 여기서 빠지므로 컨테이너 폭을 그대로 쓴다.
   (0,2,x) 로 걸어 seran-tokens §4 의 margin 선언을 이긴다. */
.seran-prose.seran-prose > :is(p, ul, ol, dl, blockquote, h1, h2, h3, h4, h5, h6),
.seran-prose.seran-prose > .seran-prose__lead,
.seran-prose.seran-prose > .seran-callout {
	max-width: var(--prose-measure);
	margin-inline: auto;
}

/* …단, 컴포넌트는 측정폭 밖이다. 카드 그리드·정의행·표는 <ul>/<dl>/<table> 이라
   위 규칙에 걸리므로 여기서 되돌린다((0,3,0) > (0,2,1)). */
.seran-prose.seran-prose > :is(.seran-cards, .seran-deflist, .seran-list--cols, .seran-prose__tablewrap, figure, table) {
	max-width: none;
	margin-inline: 0;
}

/* 넓은 요소 — 본문 폭 밖으로 대칭 확장. 화면이 좁으면 bleed 가 0 이라 무해하다.
   두 번째 셀렉터는 (0,3,0) — 위 측정폭 규칙(0,2,1)이 <p>·<h2> 에 걸어 둔
   `margin-inline:auto` 를 이기기 위한 것이다. */
.seran-prose .seran-prose__wide,
.seran-prose.seran-prose > .seran-prose__wide {
	max-width: none;
	margin-inline: calc(-1 * var(--prose-bleed));
}

/* =========================================================================
   2. 섹션 리듬 (수직 여백)

   07-pages.php 가 컨테이너를 전면 평탄화했으므로 본문은 대부분
   `.seran-prose` 의 **직계 자식**이다. 요소별 margin 을 한 번에 0 으로 내리고
   "형제 사이 간격" 하나로 리듬을 통일한다.
   `.seran-prose.seran-prose` 는 오타가 아니라 특정도 (0,2,0) 을 만들기 위한 것.
   ========================================================================= */

.seran-prose.seran-prose > * {
	margin-block: 0;
}

.seran-prose.seran-prose > * + * {
	margin-top: var(--prose-rhythm);
}

/* 제목 앞은 크게 벌린다 — h2 가 섹션 경계 역할을 한다. */
.seran-prose.seran-prose > * + h2 {
	margin-top: var(--prose-rhythm-lg);
}

.seran-prose.seran-prose > * + :is(h3, h4) {
	margin-top: var(--prose-rhythm-md);
}

/* 제목 바로 다음 요소는 붙인다(제목–본문은 한 덩어리). */
.seran-prose.seran-prose > :is(h1, h2, h3, h4, h5, h6) + * {
	margin-top: .7em;
}

/* 이미지·표·카드 앞뒤는 한 숨 더. */
.seran-prose.seran-prose > * + :is(figure, table, .seran-prose__tablewrap, .seran-cards, hr),
.seran-prose.seran-prose > :is(figure, table, .seran-prose__tablewrap, .seran-cards, hr) + * {
	margin-top: var(--prose-rhythm-md);
}

/* …제목 바로 뒤에 오는 표·카드는 예외 — 제목에 붙여 한 덩어리로 읽히게 한다.
   ((0,3,1) 로 바로 위 규칙(0,3,0)을 이긴다.) */
.seran-prose.seran-prose > :is(h1, h2, h3, h4, h5, h6) + :is(figure, table, .seran-prose__tablewrap, .seran-cards) {
	margin-top: .9em;
}

/* 첫/마지막 요소의 바깥 여백 제거 */
.seran-prose.seran-prose > :first-child {
	margin-top: 0;
}

.seran-prose.seran-prose > :last-child {
	margin-bottom: 0;
}

/* 중첩 블록(콜아웃·카드·표 셀·리스트 항목) 안의 리듬 */
.seran-prose :is(.seran-callout, .seran-cards__item, .seran-cards__body, .seran-deflist dd, td, li) > * {
	margin-block: 0;
}

.seran-prose :is(.seran-callout, .seran-cards__item, .seran-cards__body, .seran-deflist dd, td, li) > * + * {
	margin-top: .5em;
}

/* =========================================================================
   3. 타이포 — 제목 · 문단 · 리드 · 인용 · 강조

   글꼴(헤드라인=tvN 즐거운이야기 / 본문=Noto Sans KR)·기본 크기는 seran-tokens §4
   가 이미 잡았다. 여기서는 균형(자간·행간·색)과 변형만 더한다.
   ========================================================================= */

.seran-prose :is(h1, h2, h3, h4, h5, h6) {
	text-wrap: balance;
	scroll-margin-top: var(--prose-anchor-offset);
}

.seran-prose h2 {
	letter-spacing: -.02em;
}

.seran-prose h3 {
	letter-spacing: -.015em;
}

/* h4~h6 는 "라벨"에 가깝다 — 굵기로 위계를 만든다. */
.seran-prose :is(h4, h5) {
	font-weight: 700;
}

.seran-prose h6 {
	font-weight: 700;
	font-size: var(--seran-fs-base);
	color: var(--seran-ink-2);
}

/* 제목 장식 변형(선택) — 왼쪽 악센트 바 / 가운데 정렬 */
.seran-prose .seran-heading--bar {
	position: relative;
	padding-left: 14px;
}

.seran-prose .seran-heading--bar::before {
	content: "";
	position: absolute;
	inset-block: .18em .18em;
	left: 0;
	width: 4px;
	border-radius: 2px;
	background: var(--seran-grad-orange);
}

.seran-prose .seran-heading--center {
	text-align: center;
}

/* 눈썹 문구 — 제목 위 작은 라벨 */
.seran-prose .seran-prose__eyebrow {
	display: block;
	font-family: var(--seran-font);
	font-size: var(--seran-fs-xs);
	font-weight: 700;
	letter-spacing: .16em;
	text-transform: uppercase;
	color: var(--seran-orange);
	margin-bottom: .5em;
}

/* 리드 문단 — 제목 아래 도입부 */
.seran-prose .seran-prose__lead {
	font-size: var(--seran-fs-lg);
	line-height: 1.75;
	color: var(--seran-ink-2);
}

.seran-prose .seran-prose__lead--center {
	text-align: center;
}

/* 페이지 도입부 묶음(제목 + 리드 + 메타) */
.seran-prose .seran-prose__hero {
	text-align: center;
	padding-bottom: var(--seran-gap-lg);
	border-bottom: 1px solid var(--seran-line);
}

.seran-prose .seran-prose__meta {
	font-size: var(--seran-fs-sm);
	color: var(--seran-ink-3);
}

/* 보조 문구 */
.seran-prose .seran-prose__note {
	font-size: var(--seran-fs-sm);
	color: var(--seran-ink-3);
	line-height: 1.7;
}

.seran-prose .seran-prose__muted {
	color: var(--seran-ink-3);
}

/* 강조 */
.seran-prose :is(strong, b) {
	font-weight: 700;
}

.seran-prose mark {
	background: color-mix(in srgb, var(--seran-orange) 22%, transparent);
	color: var(--seran-ink);
	padding: 0 .18em;
	border-radius: 3px;
}

.seran-prose abbr[title] {
	text-decoration: underline dotted;
	text-underline-offset: .2em;
	cursor: help;
}

.seran-prose :is(sup, sub) {
	font-size: .72em;
	line-height: 0;
}

.seran-prose :is(code, kbd, samp) {
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: .92em;
	background: var(--seran-bg-soft);
	border: 1px solid var(--seran-line);
	border-radius: 4px;
	padding: .08em .38em;
}

/* 인용 */
.seran-prose blockquote {
	font-size: var(--seran-fs-base);
	line-height: 1.75;
}

.seran-prose blockquote cite {
	display: block;
	margin-top: .6em;
	font-size: var(--seran-fs-sm);
	font-style: normal;
	color: var(--seran-ink-3);
}

/* 구분선 */
.seran-prose hr {
	border-top-color: var(--prose-hairline);
}

.seran-prose hr.seran-prose__divider {
	width: 48px;
	margin-inline: auto;
	border-top: 3px solid var(--seran-orange);
	border-radius: 2px;
}

/* =========================================================================
   4. 링크 · 버튼
   ========================================================================= */

.seran-prose a:focus-visible,
.seran-prose :is(button, summary, [tabindex]):focus-visible {
	outline: 2px solid var(--seran-orange);
	outline-offset: 2px;
	border-radius: 3px;
}

/* 컴포넌트 링크(카드·버튼)는 밑줄을 지운다. */
.seran-prose a:is(.seran-btn, .seran-cards__item, .seran-cards__link) {
	text-decoration: none;
}

.seran-prose .seran-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	min-height: 44px;             /* 터치 타깃 */
	padding: 11px 26px;
	border: 1px solid transparent;
	border-radius: 999px;
	background: var(--seran-grad-orange);
	color: var(--brand-secondary);
	font-family: var(--seran-font);
	font-size: var(--seran-fs-base);
	font-weight: 700;
	line-height: 1.2;
	text-align: center;
	cursor: pointer;
	box-shadow: var(--seran-shadow);
	transition:
		transform var(--seran-dur) var(--seran-ease),
		box-shadow var(--seran-dur) var(--seran-ease),
		background-color var(--seran-dur) var(--seran-ease);
}

.seran-prose .seran-btn:hover,
.seran-prose .seran-btn:focus-visible {
	color: var(--brand-secondary);
	transform: translateY(-2px);
	box-shadow: var(--seran-shadow-lg);
}

.seran-prose .seran-btn--olive {
	background: var(--seran-grad-olive);
}

.seran-prose .seran-btn--ghost {
	background: transparent;
	color: var(--seran-cta);
	border-color: var(--seran-orange);
	box-shadow: none;
}

.seran-prose .seran-btn--ghost:hover,
.seran-prose .seran-btn--ghost:focus-visible {
	background: var(--seran-bg-warm);
	color: var(--seran-cta);
}

.seran-prose .seran-btn--sm {
	min-height: 36px;
	padding: 7px 18px;
	font-size: var(--seran-fs-sm);
}

.seran-prose .seran-btn--block {
	display: flex;
	width: 100%;
}

/* 버튼 줄 */
.seran-prose .seran-btns {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	justify-content: center;
}

/* =========================================================================
   5. 리스트

   기본 마커 색을 브랜드로 바꾸고, 중첩 단계마다 마커 모양을 바꾼다.
   변형: 체크리스트(--check) · 마커 없음(--plain) · 다단(--cols) · 구분선(--divided)
   ========================================================================= */

.seran-prose :is(ul, ol) {
	padding-left: 1.35em;
}

.seran-prose li::marker {
	color: var(--seran-orange);
}

.seran-prose li + li {
	margin-top: .35em;
}

/* 중첩 — §2 의 중첩 리듬 규칙(0,2,1)을 이겨야 하므로 (0,2,2) 로 건다. */
.seran-prose.seran-prose li > :is(ul, ol) {
	margin-top: .35em;
	padding-left: 1.2em;
}

.seran-prose ul ul {
	list-style: circle;
}

.seran-prose ul ul ul {
	list-style: square;
}

.seran-prose ol ol {
	list-style: lower-alpha;
}

.seran-prose ol ol ol {
	list-style: lower-roman;
}

/* 마커 없는 리스트 */
.seran-prose .seran-list--plain {
	list-style: none;
	padding-left: 0;
}

/* 체크리스트 — li 앞 아이콘(순수 CSS, 이미지 없음) */
.seran-prose .seran-list--check {
	list-style: none;
	padding-left: 0;
}

.seran-prose .seran-list--check > li {
	position: relative;
	padding-left: 1.9em;
}

.seran-prose .seran-list--check > li::before {
	content: "";
	position: absolute;
	left: 0;
	top: calc(var(--seran-lh) * .5em - .62em);
	width: 1.24em;
	height: 1.24em;
	border-radius: 50%;
	background: var(--prose-tint-orange);
}

.seran-prose .seran-list--check > li::after {
	content: "";
	position: absolute;
	left: .42em;
	top: calc(var(--seran-lh) * .5em - .28em);
	width: .34em;
	height: .62em;
	border: solid var(--seran-orange);
	border-width: 0 2px 2px 0;
	transform: rotate(45deg);
}

/* 주의 목록 — 체크 대신 점(경고색) */
.seran-prose .seran-list--dot {
	list-style: none;
	padding-left: 0;
}

.seran-prose .seran-list--dot > li {
	position: relative;
	padding-left: 1.1em;
}

.seran-prose .seran-list--dot > li::before {
	content: "";
	position: absolute;
	left: .1em;
	top: calc(var(--seran-lh) * .5em - .2em);
	width: .4em;
	height: .4em;
	border-radius: 50%;
	background: var(--seran-olive);
}

/* 항목 사이 구분선 */
.seran-prose .seran-list--divided > li + li {
	margin-top: .6em;
	padding-top: .6em;
	border-top: 1px solid var(--prose-hairline);
}

/* 다단 — 의료진 학력/학회/경력처럼 짧은 항목이 길게 늘어질 때 */
.seran-prose .seran-list--cols {
	column-gap: var(--seran-gap-lg);
}

.seran-prose .seran-list--cols > li {
	break-inside: avoid;
}

/* 리스트 그룹 제목 */
.seran-prose .seran-list__label {
	display: block;
	font-weight: 700;
	color: var(--seran-ink);
	margin-bottom: .4em;
}

/* =========================================================================
   6. 강조 박스 — .seran-callout (정보 / 주의)
   ========================================================================= */

.seran-prose .seran-callout {
	padding: 16px 18px;
	border-radius: var(--seran-radius);
	border: 1px solid var(--seran-line);
	border-left: 3px solid var(--seran-ink-3);
	background: var(--seran-bg-soft);
	color: var(--seran-ink-2);
	font-size: var(--seran-fs-sm);
	line-height: 1.75;
}

.seran-prose .seran-callout__title {
	display: block;
	margin-bottom: .4em;
	font-family: var(--seran-font);
	font-size: var(--seran-fs-base);
	font-weight: 700;
	color: var(--seran-ink);
}

/* 정보 — 올리브 */
.seran-prose .seran-callout--info {
	border-color: color-mix(in srgb, var(--seran-olive) 35%, transparent);
	border-left-color: var(--seran-olive);
	background: var(--prose-tint-olive);
}

/* 주의 — 주황(브랜드 경고색) */
.seran-prose .seran-callout--warn {
	border-color: color-mix(in srgb, var(--seran-orange) 35%, transparent);
	border-left-color: var(--seran-orange);
	background: var(--seran-bg-warm);
}

.seran-prose .seran-callout--warn .seran-callout__title {
	color: var(--seran-cta);
}

/* 접기 상자 */
.seran-prose summary::marker {
	color: var(--seran-orange);
}

.seran-prose details[open] > summary {
	margin-bottom: .6em;
}

/* =========================================================================
   7. 이미지 · figure · 아이콘 크기 이미지

   기본(max-width:100% / height:auto / 가운데 / radius)은 seran-tokens §4 가 잡는다.
   여기서는 (a) 도판 그림자·테두리 (b) figure/figcaption
   (c) **아이콘이 확대되지 않게 막는 규칙** 을 더한다.

   왜 아이콘 규칙이 필요한가: 진단서 페이지의 8개 아이콘은 내부 width/height 가 없는
   SVG 라 브라우저 기본값(300×150)이나 컨테이너 폭까지 부풀어 오른다.
   ========================================================================= */

.seran-prose img {
	border-radius: var(--seran-radius);
}

.seran-prose figure {
	margin-inline: 0;
}

.seran-prose figure > img {
	margin-block: 0;
}

.seran-prose figcaption {
	line-height: 1.6;
}

/* 사진 도판 강조(선택) */
.seran-prose .seran-figure--framed > img {
	border: 1px solid var(--seran-line-warm);
	box-shadow: var(--seran-shadow);
}

/* --- 아이콘 크기 이미지 -------------------------------------------------
   대상: `.seran-icon` 을 붙인 이미지 · 카드 아이콘 슬롯의 이미지 ·
        확장자가 .svg 인 이미지 · width 속성이 작은 이미지.
   `max-width` 만으로는 SVG 가 컨테이너를 채우는 것을 못 막으므로
   `width:auto` + `max-height` 를 함께 건다.
   ---------------------------------------------------------------------- */
.seran-prose :is(
	img.seran-icon,
	.seran-cards__icon img,
	img[src$=".svg"],
	img[src*=".svg?"],
	img[width="16"], img[width="20"], img[width="24"], img[width="28"],
	img[width="32"], img[width="36"], img[width="40"], img[width="48"]
) {
	width: auto;
	height: auto;
	max-width: min(100%, var(--prose-icon));
	max-height: var(--prose-icon);
	margin-inline: 0;
	border-radius: 0;
}

/* 탈출구 — 큰 SVG 도판(다이어그램)은 `.seran-media` 를 붙이거나 <figure> 안에 넣는다.
   `img.seran-media`·`.seran-prose__wide > img` 는 위 규칙과 같은 (0,2,1) 이지만
   **뒤에 선언**되므로 이기고, figure 쪽은 `:not(.seran-icon)` 로 (0,2,2) 를 만든다. */
.seran-prose img.seran-media,
.seran-prose figure > img:not(.seran-icon),
.seran-prose .seran-prose__wide > img {
	width: auto;
	max-width: 100%;
	max-height: none;
	margin-inline: auto;
	border-radius: var(--seran-radius);
}

/* =========================================================================
   8. 아이콘 카드 그리드 — .seran-cards

   진단서 및 특수검사 페이지가 이 형태다(아이콘 + 라벨, 3열).
   기본 레이아웃은 **가로형**(아이콘 왼쪽 · 텍스트 오른쪽) — 구 지면과 같다.
   `--stack` 은 세로형(아이콘 위 · 가운데 정렬), `--photo` 는 인물 카드.

   마크업 계약(_wiring/prose-css.md §3):
     <ul class="seran-cards seran-cards--3">
       <li class="seran-cards__item">
         <a class="seran-cards__link" href="…">
           <span class="seran-cards__icon"><img src="…" alt=""></span>
           <span class="seran-cards__body">
             <span class="seran-cards__label">영문진단서</span>
             <span class="seran-cards__desc">발급 안내</span>
           </span>
         </a>
       </li>
     </ul>
   링크가 없으면 `<a>` 없이 `__icon` + `__body` 를 바로 넣어도 된다.
   ========================================================================= */

.seran-prose .seran-cards {
	display: grid;
	gap: var(--seran-gap);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--prose-card-min)), 1fr));
	list-style: none;
	margin-inline: 0;
	padding: 0;
}

/* 열 수 고정 변형 — auto-fit 이 어색할 때만 쓴다(모바일에서는 항상 1열). */
.seran-prose .seran-cards--2 { --prose-card-min: 260px; }
.seran-prose .seran-cards--3 { --prose-card-min: 200px; }
.seran-prose .seran-cards--4 { --prose-card-min: 160px; }

.seran-prose .seran-cards__item {
	display: flex;
	align-items: center;
	gap: 14px;
	min-height: 84px;
	padding: 16px 18px;
	margin: 0;
	border: 1px solid var(--seran-line-warm);
	border-radius: var(--seran-radius);
	background: var(--seran-bg-warm);
	color: var(--seran-ink);
	text-align: left;
	transition:
		transform var(--seran-dur) var(--seran-ease),
		box-shadow var(--seran-dur) var(--seran-ease),
		border-color var(--seran-dur) var(--seran-ease);
}

/* 카드 전체가 링크인 경우 */
.seran-prose a.seran-cards__item,
.seran-prose .seran-cards__link {
	color: var(--seran-ink);
}

.seran-prose .seran-cards__link {
	display: flex;
	align-items: center;
	gap: 14px;
	width: 100%;
	color: inherit;
}

/* 호버 상승 */
.seran-prose :is(a.seran-cards__item, .seran-cards__item:has(.seran-cards__link)):hover,
.seran-prose :is(a.seran-cards__item, .seran-cards__item:has(.seran-cards__link)):focus-within {
	transform: translateY(-3px);
	border-color: var(--seran-orange-soft);
	box-shadow: var(--seran-shadow-lg);
}

/* 아이콘 슬롯 */
.seran-prose .seran-cards__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: var(--prose-icon);
	height: var(--prose-icon);
	border-radius: 50%;
	background: var(--brand-secondary);
	box-shadow: var(--seran-shadow);
}

.seran-prose .seran-cards__icon img {
	max-width: 60%;
	max-height: 60%;
	margin: 0;
}

/* 번호 배지(01·02·03 형태의 특징 목록) */
.seran-prose .seran-cards__num {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 38px;
	height: 38px;
	border-radius: 50%;
	background: var(--seran-grad-orange);
	color: var(--brand-secondary);
	font-family: var(--seran-font);
	font-size: var(--seran-fs-sm);
	font-weight: 700;
	line-height: 1;
}

.seran-prose .seran-cards__body {
	display: flex;
	flex-direction: column;
	gap: 3px;
	min-width: 0;
}

.seran-prose .seran-cards__eyebrow {
	font-size: var(--seran-fs-xs);
	font-weight: 700;
	letter-spacing: .04em;
	color: var(--seran-olive-dark);
}

.seran-prose .seran-cards__label {
	font-family: var(--seran-font-display);
	font-size: var(--seran-fs-lg);
	font-weight: 500;
	line-height: var(--seran-lh-tight);
	color: var(--seran-ink);
	word-break: keep-all;
}

.seran-prose .seran-cards__desc {
	font-size: var(--seran-fs-sm);
	line-height: 1.65;
	color: var(--seran-ink-2);
}

.seran-prose .seran-cards__meta {
	font-size: var(--seran-fs-xs);
	color: var(--seran-ink-3);
}

/* 세로형 — 아이콘 위, 가운데 정렬 */
.seran-prose .seran-cards--stack .seran-cards__item,
.seran-prose .seran-cards--stack .seran-cards__link {
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: 10px;
}

.seran-prose .seran-cards--stack .seran-cards__body {
	align-items: center;
}

/* 흰 카드 변형(따뜻한 배경 위에 얹을 때) */
.seran-prose .seran-cards--plain .seran-cards__item {
	background: var(--brand-secondary);
	border-color: var(--seran-line);
}

/* 인물 카드 — 사진 위, 이름·직함 아래 (병원소개·의료진소개) */
.seran-prose .seran-cards--photo {
	--prose-card-min: 220px;
}

.seran-prose .seran-cards--photo .seran-cards__item {
	flex-direction: column;
	align-items: stretch;
	gap: 0;
	padding: 0;
	overflow: hidden;
	background: var(--brand-secondary);
	border-color: var(--seran-line);
	text-align: center;
}

.seran-prose .seran-cards--photo .seran-cards__link {
	flex-direction: column;
	align-items: stretch;
	gap: 0;
}

.seran-prose .seran-cards--photo .seran-cards__media {
	display: block;
	margin: 0;
	background: var(--seran-bg-warm);
}

.seran-prose .seran-cards--photo .seran-cards__media img {
	display: block;
	width: 100%;
	max-width: 100%;
	max-height: none;
	height: auto;
	margin: 0;
	border-radius: 0;
	object-fit: cover;
}

.seran-prose .seran-cards--photo .seran-cards__body {
	align-items: center;
	gap: 4px;
	padding: 16px 16px 20px;
}

/* =========================================================================
   9. 정의형 행 — .seran-deflist ("항목 — 설명" 쌍)

   검사 항목표·안내 문답처럼 표까지는 필요 없는 2열 데이터에 쓴다.
   마크업 두 가지를 모두 받는다:
     (a) <dl class="seran-deflist"><dt>…</dt><dd>…</dd>…</dl>
     (b) <dl class="seran-deflist"><div class="seran-deflist__row"><dt>…</dt><dd>…</dd></div>…</dl>
   (b) 의 행 래퍼는 `display:contents` 로 접히므로 두 형태의 격자가 같아진다.
   ========================================================================= */

.seran-prose .seran-deflist {
	display: grid;
	gap: 0;
	margin-inline: 0;
	padding: 0;
	border-top: 1px solid var(--seran-line);
}

.seran-prose .seran-deflist__row {
	display: contents;
}

.seran-prose .seran-deflist > dt,
.seran-prose .seran-deflist__row > dt {
	margin: 0;
	padding: 12px 0 0;
	font-weight: 700;
	color: var(--seran-ink);
	word-break: keep-all;
}

.seran-prose .seran-deflist > dd,
.seran-prose .seran-deflist__row > dd {
	margin: 0;
	padding: 2px 0 12px;
	border-bottom: 1px solid var(--prose-hairline);
	color: var(--seran-ink-2);
	font-size: var(--seran-fs-sm);
	line-height: 1.75;
}

/* 조밀형 */
.seran-prose .seran-deflist--compact > dt,
.seran-prose .seran-deflist--compact .seran-deflist__row > dt { padding-top: 8px; }

.seran-prose .seran-deflist--compact > dd,
.seran-prose .seran-deflist--compact .seran-deflist__row > dd { padding-bottom: 8px; }

/* =========================================================================
   10. 표

   방침(모듈 사양): `table{display:block;overflow-x:auto}` 로 표 자체를 스크롤시키지
   않는다 — display:block 은 표 레이아웃(열 폭 계산·colspan)을 통째로 버리기 때문이다.
   대신 **부모 래퍼 스크롤**(.seran-prose__tablewrap)을 기본으로 하고,
   행이 짧고 열이 많은 표에는 **반응형 카드 변환**(.seran-table--cards)을 옵션으로 준다.

   대상 한정: `table:not([class])`(정적화된 본문의 표) 와 `table.seran-table`(신규 마크업).
   → 다른 모듈이 자기 CSS 로 그리는 표(예: [clinician_schedule] 의 `table.cs-matrix2`)는
     이 시트가 손대지 않는다.
   ========================================================================= */

/* --- 스크롤 래퍼 ------------------------------------------------------- */
.seran-prose .seran-prose__tablewrap {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	border-radius: var(--seran-radius);
	border: 1px solid var(--seran-line);
	background: var(--brand-secondary);
}

.seran-prose .seran-prose__tablewrap:focus-visible {
	outline: 2px solid var(--seran-orange);
	outline-offset: 2px;
}

/* 래퍼 안에서는 표가 **표로** 남는다. seran-tokens §4 의 모바일
   `display:block` 규칙과 같은 (0,1,1) 이지만 뒤에 실려 이긴다. */
.seran-prose__tablewrap > table {
	display: table;
	width: 100%;
	margin: 0;
	border: 0;
}

/* 열이 많아 눌리는 표는 최소 폭을 줘서 래퍼가 스크롤되게 한다(선택). */
.seran-prose__tablewrap > table.seran-table--wide {
	min-width: 40em;
}

/* --- 기본 표 모양 ------------------------------------------------------ */
.seran-prose :is(table:not([class]), table.seran-table) {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--seran-fs-sm);
	line-height: 1.6;
	background: var(--brand-secondary);
}

.seran-prose :is(table:not([class]), table.seran-table) caption {
	caption-side: top;
	padding-bottom: .6em;
	font-size: var(--seran-fs-sm);
	font-weight: 700;
	color: var(--seran-ink-2);
	text-align: left;
}

.seran-prose :is(table:not([class]), table.seran-table) > :is(thead, tbody, tfoot) > tr > :is(th, td) {
	padding: 12px 14px;
	border-bottom: 1px solid var(--prose-hairline);
	vertical-align: top;
	text-align: left;
	word-break: keep-all;
}

.seran-prose :is(table:not([class]), table.seran-table) > thead > tr > th {
	background: var(--seran-bg-mega);
	border-bottom: 1px solid var(--seran-line);
	color: var(--seran-ink-2);
	font-weight: 700;
	white-space: nowrap;
}

/* 행 머리(th scope=row) */
.seran-prose :is(table:not([class]), table.seran-table) > tbody > tr > th {
	background: var(--seran-bg-soft);
	font-weight: 700;
	color: var(--seran-ink);
	white-space: nowrap;
}

.seran-prose :is(table:not([class]), table.seran-table) > tbody > tr:last-child > :is(th, td) {
	border-bottom: 0;
}

.seran-prose :is(table:not([class]), table.seran-table) > tbody > tr:hover {
	background: var(--prose-row-hover);
}

.seran-prose :is(table:not([class]), table.seran-table) > tfoot > tr > :is(th, td) {
	background: var(--seran-bg-soft);
	font-size: var(--seran-fs-xs);
	color: var(--seran-ink-3);
}

/* 숫자 열 — 우측 정렬 · 고정폭 숫자 */
.seran-prose :is(table:not([class]), table.seran-table) :is(th, td):is(.price, .price-col, .is-num, [data-num]) {
	text-align: right;
	white-space: nowrap;
	font-variant-numeric: tabular-nums;
	font-feature-settings: "tnum" 1;
}

.seran-prose :is(table:not([class]), table.seran-table) td:is(.price, .is-num) {
	font-weight: 700;
	color: var(--seran-ink);
}

.seran-prose :is(table:not([class]), table.seran-table) td .unit {
	margin-left: 2px;
	font-size: var(--seran-fs-xs);
	font-weight: 400;
	color: var(--seran-ink-3);
}

/* 셀 안 보조 설명 */
.seran-prose :is(table:not([class]), table.seran-table) td .desc {
	display: block;
	margin-top: 3px;
	font-size: var(--seran-fs-xs);
	color: var(--seran-ink-3);
}

/* 값이 아니라 문구가 들어간 금액 칸("별도 문의" 등) */
.seran-prose :is(table:not([class]), table.seran-table) td.price.special {
	font-weight: 400;
	color: var(--seran-ink-3);
}

/* 조밀형 */
.seran-prose table.seran-table--compact > :is(thead, tbody, tfoot) > tr > :is(th, td) {
	padding: 8px 10px;
}

/* --- 반응형 카드 변환(옵션) --------------------------------------------
   `<table class="seran-table seran-table--cards">` 에 각 `td[data-label]` 을 주면
   좁은 화면에서 행 하나가 카드 하나가 된다. 열이 3개 이상인 표에 권장.
   ---------------------------------------------------------------------- */
@media (max-width: 599px) {
	.seran-prose table.seran-table--cards,
	.seran-prose table.seran-table--cards > tbody,
	.seran-prose table.seran-table--cards > tbody > tr,
	.seran-prose table.seran-table--cards > tbody > tr > :is(th, td) {
		display: block;
		width: auto;
	}

	.seran-prose table.seran-table--cards > thead {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}

	.seran-prose table.seran-table--cards > tbody > tr {
		margin-bottom: 10px;
		border: 1px solid var(--seran-line);
		border-radius: var(--seran-radius);
		background: var(--brand-secondary);
		overflow: hidden;
	}

	.seran-prose table.seran-table--cards > tbody > tr:hover {
		background: var(--brand-secondary);
	}

	.seran-prose table.seran-table--cards > tbody > tr > th {
		background: var(--seran-bg-warm);
		white-space: normal;
	}

	.seran-prose table.seran-table--cards > tbody > tr > td[data-label] {
		display: flex;
		justify-content: space-between;
		gap: 12px;
		text-align: right;
	}

	.seran-prose table.seran-table--cards > tbody > tr > td[data-label]::before {
		content: attr(data-label);
		flex: 0 0 auto;
		font-weight: 700;
		color: var(--seran-ink-3);
		text-align: left;
	}

	.seran-prose table.seran-table--cards > tbody > tr > :is(th, td):last-child {
		border-bottom: 0;
	}
}

/* =========================================================================
   11. 정적화 잔존 클래스 호환

   07-pages.php 는 컨테이너를 평탄화했지만 **평탄화 대상이 아닌 태그**(h*·p·th·td·li)
   에 붙어 있던 클래스는 그대로 남겼다. 비급여 안내(31101)처럼 고객이 임베드로
   붙였던 문서가 여기에 해당한다. 그 클래스들을 세란 토큰으로 다시 입혀
   **본문을 고치지 않고** 지면을 되살린다.
   (Brizy 클래스가 아니라 고객 원고의 클래스이므로 §0-1 위반이 아니다.)
   ========================================================================= */

.seran-prose :is(h1, h2, h3).section-title {
	font-size: var(--seran-fs-h3);
	padding-bottom: .35em;
	border-bottom: 2px solid var(--seran-orange);
}

.seran-prose .section-num {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 30px;
	height: 30px;
	margin-right: 8px;
	border-radius: 50%;
	background: var(--seran-grad-orange);
	color: var(--brand-secondary);
	font-size: var(--seran-fs-xs);
	font-weight: 700;
	vertical-align: middle;
}

.seran-prose p.subtitle {
	font-size: var(--seran-fs-lg);
	color: var(--seran-ink-2);
	text-align: center;
}

.seran-prose p.meta {
	font-size: var(--seran-fs-sm);
	color: var(--seran-ink-3);
	text-align: center;
}

.seran-prose :is(p, div, ul).notes,
.seran-prose .seran-prose__notes {
	padding: 16px 18px;
	border-radius: var(--seran-radius);
	border-left: 3px solid var(--seran-olive);
	background: var(--prose-tint-olive);
	font-size: var(--seran-fs-sm);
	color: var(--seran-ink-2);
	line-height: 1.8;
}

.seran-prose p.footer {
	padding-top: 1.2em;
	border-top: 1px solid var(--seran-line);
	font-size: var(--seran-fs-xs);
	color: var(--seran-ink-3);
	text-align: center;
}

/* 임베드가 들고 있던 폭 컨테이너가 남아 있으면 폭 계산을 넘기지 않게 한다. */
.seran-prose .container {
	max-width: 100%;
	margin-inline: auto;
	padding: 0;
}

/* 모듈이 자기 마크업을 그대로 넣는 자리 — 산문 리듬에서 뺀다. */
.seran-prose.seran-prose > .seran-prose__raw {
	margin-block: var(--prose-rhythm-md);
	max-width: none;
}

/* =========================================================================
   12. 유틸리티 · 접근성 · 모션
   ========================================================================= */

.seran-prose .seran-prose__center { text-align: center; }
.seran-prose .seran-prose__left { text-align: left; }
.seran-prose .seran-prose__right { text-align: right; }

/* 스크린리더 전용 */
.seran-prose .seran-prose__sr {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* 표·카드가 뷰포트를 밀지 않도록 격자 자식의 최소 폭을 푼다. */
.seran-prose :is(.seran-cards, .seran-deflist) > * {
	min-width: 0;
}

/* 임의의 임베드가 뷰포트를 넘기지 않게 하는 최후 방어선 */
.seran-prose :is(iframe, video, canvas, svg:not(.seran-icon)) {
	max-width: 100%;
}

.seran-prose iframe {
	border: 0;
	border-radius: var(--seran-radius);
}

/* =========================================================================
   반응형 — 모바일 우선. 위 규칙이 좁은 화면 기준이고 아래에서 확장한다.
   ========================================================================= */

@media (min-width: 600px) {
	.seran-prose {
		--prose-rhythm: 1.25em;
		--prose-rhythm-md: 2em;
		--prose-rhythm-lg: 2.8em;
	}

	/* 정의형 행 — 2열 격자 */
	.seran-prose .seran-deflist {
		grid-template-columns: minmax(8em, 14em) 1fr;
		column-gap: var(--seran-gap-lg);
	}

	.seran-prose .seran-deflist > dt,
	.seran-prose .seran-deflist__row > dt {
		padding: 14px 0;
		border-bottom: 1px solid var(--prose-hairline);
	}

	.seran-prose .seran-deflist > dd,
	.seran-prose .seran-deflist__row > dd {
		padding: 14px 0;
	}

	/* 다단 리스트 */
	.seran-prose .seran-list--cols {
		columns: 2;
	}

	.seran-prose .seran-callout {
		padding: 20px 22px;
	}

	.seran-prose :is(table:not([class]), table.seran-table) > :is(thead, tbody, tfoot) > tr > :is(th, td) {
		padding: 14px 18px;
	}
}

@media (min-width: 783px) {
	.seran-prose {
		--prose-icon: 60px;
	}

	.seran-prose .seran-prose__lead {
		font-size: 1.25rem;
	}

	.seran-prose .seran-cards {
		gap: 18px;
	}

	.seran-prose .seran-cards__item {
		padding: 18px 20px;
	}

	.seran-prose :is(table:not([class]), table.seran-table) {
		font-size: var(--seran-fs-base);
	}
}

@media (min-width: 1024px) {
	.seran-prose .seran-list--cols--3 {
		columns: 3;
	}
}

/* 모션 최소화 — 상승·전환을 끈다(토큰의 --seran-dur 도 함께 줄어든다). */
@media (prefers-reduced-motion: reduce) {
	.seran-prose .seran-btn,
	.seran-prose .seran-cards__item {
		transition: none;
	}

	.seran-prose .seran-btn:hover,
	.seran-prose .seran-btn:focus-visible,
	.seran-prose :is(a.seran-cards__item, .seran-cards__item:has(.seran-cards__link)):hover,
	.seran-prose :is(a.seran-cards__item, .seran-cards__item:has(.seran-cards__link)):focus-within {
		transform: none;
	}
}
