@charset "UTF-8";
/* ==========================================================================
   Devin.KR Design System
   - AdminLTE / Bootstrap / jQuery 의존 없음. 이 파일 하나로 동작한다.
   - 다크모드: prefers-color-scheme 자동 + <html data-theme="dark|light"> 수동 우선
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. 토큰
   -------------------------------------------------------------------------- */
:root {
	/*
	   색 — 무채색 우선, 색은 아껴서

	   이전에는 accent 가 #2563eb(부트스트랩/테일윈드 기본 파랑)였고 버튼·페이지네이션이
	   전부 그 색이었다. 어느 사이트에서나 본 색이라 "기본값 그대로"로 읽힌다.
	   기준을 바꿨다 — **UI 의 강조는 검정이 하고, 파랑은 링크와 포커스에만 쓴다.**
	   Linear·Vercel·Stripe 계열이 이 방식이고, 색을 아낄수록 위계가 선명해진다.
	*/
	--bg:            #ffffff;
	--bg-subtle:     #fafafa;
	--surface:       #ffffff;
	--surface-alt:   #f4f4f5;
	--border:        #e7e7ea;   /* 헤어라인. 이전 #e2e5ea 보다 한 단계 옅다 */
	--border-strong: #d0d0d5;
	--text:          #131417;   /* 순검정을 피한 잉크색 */
	--text-muted:    #61636b;
	--text-faint:    #8e9098;

	/* UI 강조 = 잉크. 버튼·활성 상태가 이 색이다 */
	--ink:           #131417;
	--ink-hover:     #000000;
	--ink-fg:        #ffffff;

	/* 색 강조 = 링크·포커스 전용. 채도를 낮춰 기본 파랑 느낌을 지웠다 */
	--accent:        #2a4bd7;
	--accent-hover:  #1e3ab0;
	--accent-fg:     #ffffff;
	--accent-soft:   #eef1fd;

	--success:       #14713a;
	--success-soft:  #e8f4ec;
	--warn:          #8f5000;
	--warn-soft:     #fbf1e2;
	--danger:        #b02121;
	--danger-soft:   #fceded;

	--code-bg:       #f7f7f8;
	--code-text:     #131417;
	--mark-bg:       #fff2b0;

	/* 간격 (4px 배수) */
	--sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
	--sp-5: 24px; --sp-6: 32px; --sp-7: 40px; --sp-8: 48px;
	--sp-9: 64px; --sp-10: 88px;

	/*
	   타이포 — 크기 대비를 키웠다

	   이전 스케일은 12/13/15/18/22/28 로 위아래 차이가 작아서 제목과 본문이
	   비슷해 보였다. 그래서 굵기로만 위계를 주다 보니 "전부 굵은" 화면이 됐다.
	   이제 크기가 위계를 지고 굵기는 덜 쓴다.
	*/
	--fs-xs:   11px;
	--fs-sm:   13px;
	--fs-base: 15px;
	--fs-md:   16px;
	--fs-lg:   19px;
	--fs-xl:   24px;
	--fs-2xl:  32px;
	--fs-3xl:  42px;

	--lh-tight: 1.25;
	--lh-snug:  1.45;
	--lh-base:  1.75;   /* 한글 본문은 1.7 보다 조금 더 열어야 편하다 */

	/* 제목은 자간을 좁혀야 덩어리로 읽힌다. 한글도 마찬가지다 */
	--tr-tight:  -.022em;
	--tr-tighter: -.032em;
	/* 라벨·메타는 반대로 벌린다 */
	--tr-wide:   .06em;

	--font-sans: "Pretendard", "Pretendard Variable", -apple-system, BlinkMacSystemFont,
	             "Apple SD Gothic Neo", "Malgun Gothic", "맑은 고딕", system-ui, sans-serif;
	--font-mono: ui-monospace, SFMono-Regular, "SF Mono", "JetBrains Mono",
	             "D2Coding", Consolas, "Liberation Mono", monospace;

	/* 반경 — 크면 장난감처럼 보인다. 작게 */
	--r-sm: 3px; --r-md: 6px; --r-lg: 10px; --r-full: 999px;

	/* 그림자 — 거의 쓰지 않는다. 면 구분은 헤어라인이 한다 */
	--sh-1: 0 1px 2px rgba(19,20,23,.05);
	--sh-2: 0 8px 24px rgba(19,20,23,.08);

	/* 레이아웃 */
	--w-content: 720px;   /* 글 본문 — 한 줄 길이를 읽기 좋게 */
	--w-list:   1000px;   /* 목록 — 본문보다 넓어야 허전하지 않다 */
	--w-wide:   1240px;
	--h-header:   60px;
	--w-subnav:  200px;
	--w-aside:   280px;

	--dur: 140ms;
}


@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) {
		--bg:            #0e0f12;
		--bg-subtle:     #08090b;
		--surface:       #16181d;
		--surface-alt:   #1e2127;
		--border:        #26292f;
		--border-strong: #383c44;
		--text:          #e9eaec;
		--text-muted:    #9a9da5;
		--text-faint:    #71757d;

		/* 다크에서는 잉크 강조를 뒤집는다 — 흰 버튼이 검은 배경에서 가장 또렷하다 */
		--ink:           #f2f3f5;
		--ink-hover:     #ffffff;
		--ink-fg:        #0e0f12;

		--accent:        #8aa4ff;
		--accent-hover:  #a5b9ff;
		--accent-fg:     #0e0f12;
		--accent-soft:   #1a2033;

		--success:       #5cc47f;
		--success-soft:  #12291b;
		--warn:          #e2a548;
		--warn-soft:     #2b2113;
		--danger:        #f07a72;
		--danger-soft:   #2d1a19;

		--code-bg:       #0b0c0f;
		--code-text:     #e9eaec;
		--mark-bg:       #4a4021;

		--sh-1: 0 1px 2px rgba(0,0,0,.5);
		--sh-2: 0 8px 28px rgba(0,0,0,.6);
	}
}

:root[data-theme="dark"] {
	--bg:            #0e0f12;
	--bg-subtle:     #08090b;
	--surface:       #16181d;
	--surface-alt:   #1e2127;
	--border:        #26292f;
	--border-strong: #383c44;
	--text:          #e9eaec;
	--text-muted:    #9a9da5;
	--text-faint:    #71757d;

	/* 다크에서는 잉크 강조를 뒤집는다 — 흰 버튼이 검은 배경에서 가장 또렷하다 */
	--ink:           #f2f3f5;
	--ink-hover:     #ffffff;
	--ink-fg:        #0e0f12;

	--accent:        #8aa4ff;
	--accent-hover:  #a5b9ff;
	--accent-fg:     #0e0f12;
	--accent-soft:   #1a2033;

	--success:       #5cc47f;
	--success-soft:  #12291b;
	--warn:          #e2a548;
	--warn-soft:     #2b2113;
	--danger:        #f07a72;
	--danger-soft:   #2d1a19;

	--code-bg:       #0b0c0f;
	--code-text:     #e9eaec;
	--mark-bg:       #4a4021;

	--sh-1: 0 1px 2px rgba(0,0,0,.5);
	--sh-2: 0 8px 28px rgba(0,0,0,.6);
}


/* --------------------------------------------------------------------------
   2. 리셋 · 기본
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
	margin: 0;
	background: var(--bg);
	color: var(--text);
	font-family: var(--font-sans);
	font-size: var(--fs-base);
	line-height: var(--lh-base);
	word-break: keep-all;
	overflow-wrap: anywhere;
	-webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 { margin: 0 0 var(--sp-3); line-height: var(--lh-tight); font-weight: 700; }
h1 { font-size: var(--fs-2xl); letter-spacing: -.02em; }
h2 { font-size: var(--fs-xl); letter-spacing: -.01em; }
h3 { font-size: var(--fs-lg); }
h4, h5, h6 { font-size: var(--fs-base); }

p  { margin: 0 0 var(--sp-4); }
ul, ol { margin: 0 0 var(--sp-4); padding-left: var(--sp-5); }
li { margin-bottom: var(--sp-1); }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

hr { border: 0; border-top: 1px solid var(--border); margin: var(--sp-5) 0; }

img, svg, video { max-width: 100%; height: auto; }

small { font-size: var(--fs-sm); }
mark  { background: var(--mark-bg); color: inherit; padding: 0 2px; border-radius: 2px; }

code, kbd, samp, pre { font-family: var(--font-mono); font-size: .92em; }
code {
	background: var(--code-bg); color: var(--code-text);
	padding: .12em .38em; border-radius: var(--r-sm);
	border: 1px solid var(--border);
}
pre {
	background: var(--code-bg); color: var(--code-text);
	border: 1px solid var(--border); border-radius: var(--r-md);
	padding: var(--sp-4); overflow-x: auto; line-height: 1.6; margin: 0 0 var(--sp-4);
}
pre code { background: none; border: 0; padding: 0; }

kbd {
	background: var(--surface-alt); border: 1px solid var(--border-strong);
	border-bottom-width: 2px; border-radius: var(--r-sm);
	padding: .1em .4em; font-size: var(--fs-xs); color: var(--text);
}

blockquote {
	margin: 0 0 var(--sp-4); padding: var(--sp-2) var(--sp-4);
	border-left: 3px solid var(--border-strong); color: var(--text-muted);
}

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-sm); }

::selection { background: var(--accent-soft); color: var(--text); }

@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
}

/* 스크린리더 전용 / 건너뛰기 링크 */
.sr-only {
	position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
	overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.skip-link {
	position: absolute; left: var(--sp-3); top: -100px; z-index: 200;
	background: var(--accent); color: var(--accent-fg);
	padding: var(--sp-2) var(--sp-4); border-radius: var(--r-md);
}
.skip-link:focus { top: var(--sp-3); text-decoration: none; }

/* --------------------------------------------------------------------------
   3. 레이아웃
   -------------------------------------------------------------------------- */
.container { width: 100%; max-width: var(--w-wide); margin: 0 auto; padding: 0 var(--sp-5); }
.container--narrow { max-width: var(--w-content); }
/* 목록용. 글 본문보다 넓게 잡는다 — 좁은 목록이 넓은 화면에서 가장 허전해 보인다 */
.container--list { max-width: var(--w-list); }
.page { min-height: 100vh; display: flex; flex-direction: column; }
.page__main { flex: 1 0 auto; padding: var(--sp-5) 0 var(--sp-8); }

/* doc.html: 좌 서브내비 / 중 콘텐츠 / 우 사이드 */
.doc-grid {
	display: grid;
	grid-template-columns: var(--w-subnav) minmax(0, 1fr) var(--w-aside);
	gap: var(--sp-6);
	align-items: start;
}
.doc-grid > .doc-main { min-width: 0; }
/* 목록용 2단 — 우측 열 없이 서브내비 + 본문.
   3단(--w-aside 포함)은 인기글/광고가 실제로 생겼을 때 쓴다. */
.doc-grid--list { grid-template-columns: var(--w-subnav) minmax(0, 1fr); gap: var(--sp-8); }
@media (max-width: 760px) { .doc-grid--list { grid-template-columns: minmax(0, 1fr); } }

.doc-aside { position: sticky; top: calc(var(--h-header) + var(--sp-4)); }

@media (max-width: 1100px) {
	.doc-grid { grid-template-columns: var(--w-subnav) minmax(0, 1fr); }
	.doc-aside { display: none; }
}
@media (max-width: 760px) {
	.doc-grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); }
	.doc-subnav { display: none; }
	.doc-subnav.is-open { display: block; }
}

/* tool.html: 입력/출력 2분할 */
.tool-io {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: var(--sp-4);
}
@media (max-width: 860px) { .tool-io { grid-template-columns: minmax(0, 1fr); } }

.stack   > * + * { margin-top: var(--sp-4); }
.stack-sm > * + * { margin-top: var(--sp-2); }

.row { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; }
.row--between { justify-content: space-between; }
.row--end { justify-content: flex-end; }
.spacer { flex: 1 1 auto; }

/* --------------------------------------------------------------------------
   4. 헤더 · 내비
   -------------------------------------------------------------------------- */
.header {
	position: sticky; top: 0; z-index: 100;
	height: var(--h-header);
	background: color-mix(in srgb, var(--bg) 88%, transparent);
	backdrop-filter: saturate(180%) blur(8px);
	border-bottom: 1px solid var(--border);
}
.header__inner {
	height: 100%; display: flex; align-items: center; gap: var(--sp-4);
	max-width: var(--w-wide); margin: 0 auto; padding: 0 var(--sp-4);
}
.brand {
	display: inline-flex; align-items: center; gap: var(--sp-2);
	font-weight: 800; font-size: var(--fs-lg); color: var(--text);
	letter-spacing: -.02em; flex: 0 0 auto;
}
.brand:hover { text-decoration: none; }
.brand__logo { width: 26px; height: 26px; border-radius: var(--r-sm); }

.gnb { display: flex; gap: var(--sp-1); flex: 1 1 auto; }
.gnb__link {
	position: relative;
	display: inline-flex; align-items: center;
	height: var(--h-header); padding: 0 var(--sp-3);
	color: var(--text-muted); font-weight: 500; font-size: var(--fs-sm);
	letter-spacing: -.01em; white-space: nowrap;
}
.gnb__link:hover { color: var(--text); text-decoration: none; }
/* 활성 표시를 알약 배경에서 밑줄로 바꿨다.
   배경 알약은 메뉴가 버튼처럼 보여 헤더가 소란스러워진다. */
.gnb__link.is-active { color: var(--text); font-weight: 600; }
.gnb__link.is-active::after {
	content: ""; position: absolute; left: var(--sp-3); right: var(--sp-3); bottom: -1px;
	height: 2px; background: var(--ink);
}

.header__actions { display: flex; align-items: center; gap: var(--sp-2); flex: 0 0 auto; }

/* ⌘K 검색 트리거 */
.search-trigger {
	display: inline-flex; align-items: center; gap: var(--sp-2);
	min-width: 180px; height: 32px; padding: 0 var(--sp-3);
	background: transparent; border: 1px solid var(--border);
	border-radius: var(--r-sm); color: var(--text-faint);
	font-size: var(--fs-sm); cursor: pointer; font-family: inherit;
	transition: border-color var(--dur);
}
.search-trigger:hover { border-color: var(--border-strong); }
.search-trigger kbd { margin-left: auto; }

@media (max-width: 900px) {
	.gnb { display: none; }
	.gnb.is-open {
		display: flex; flex-direction: column; position: absolute;
		top: var(--h-header); left: 0; right: 0; padding: var(--sp-3);
		background: var(--bg); border-bottom: 1px solid var(--border); box-shadow: var(--sh-2);
	}
	.search-trigger { min-width: 0; }
	.search-trigger span { display: none; }
	.search-trigger kbd { display: none; }
}
/* 햄버거는 좁은 화면에서만 나온다.
   .nav-toggle 단독 선택자는 뒤에 오는 .btn 의 display:inline-flex 에 밀려(같은 특정도, 나중 규칙 승)
   데스크톱에서도 버튼이 보였다. .header 를 앞에 붙여 특정도를 올린다. */
.header .nav-toggle { display: none; }
@media (max-width: 900px) { .header .nav-toggle { display: inline-flex; } }

/* 섹션 서브내비 */
.subnav { position: sticky; top: calc(var(--h-header) + var(--sp-4)); font-size: var(--fs-sm); }
.subnav__group { margin-bottom: var(--sp-5); }
.subnav__title {
	font-family: var(--font-mono);
	font-size: var(--fs-xs); font-weight: 500; text-transform: uppercase;
	letter-spacing: var(--tr-wide); color: var(--text-faint);
	margin: 0 0 var(--sp-3); padding: 0 var(--sp-2);
}
.subnav__link {
	display: flex; align-items: center; gap: var(--sp-2);
	padding: var(--sp-2) var(--sp-2); border-radius: var(--r-sm);
	color: var(--text-muted);
}
.subnav__link:hover { background: var(--surface-alt); color: var(--text); text-decoration: none; }
.subnav__link.is-active { color: var(--text); background: var(--surface-alt); font-weight: 600; box-shadow: inset 2px 0 0 var(--ink); }

/* 푸터 */
.footer {
	flex: 0 0 auto; margin-top: var(--sp-10);
	border-top: 1px solid var(--border);
	background: var(--bg);
	padding: var(--sp-8) 0 var(--sp-6);
	font-size: var(--fs-sm); color: var(--text-muted);
}
.footer a { color: var(--text-muted); text-decoration: none; }
.footer a:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
/*
   이전에는 flex + space-between 이라 브랜드가 왼쪽 끝, 링크가 오른쪽 끝으로 밀려
   가운데가 통째로 비었다. 폭이 넓을수록 심해진다.
   브랜드에 넉넉한 열을 주고 링크 열은 고정폭으로 붙여 둔다.
*/
.footer__grid {
	display: grid;
	grid-template-columns: minmax(0, 2fr) repeat(2, minmax(140px, 1fr));
	gap: var(--sp-8) var(--sp-6);
}
.footer__brand { font-weight: 700; font-size: var(--fs-md); color: var(--text); letter-spacing: -.02em; }
.footer__head {
	font-family: var(--font-mono); font-size: var(--fs-xs);
	letter-spacing: var(--tr-wide); text-transform: uppercase; color: var(--text-faint);
	margin-bottom: var(--sp-3);
}
.footer__links { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-2); }
@media (max-width: 700px) {
	.footer__grid { grid-template-columns: 1fr 1fr; }
	.footer__grid > :first-child { grid-column: 1 / -1; }
}

/* 버튼 */
.btn {
	display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
	height: 34px; padding: 0 var(--sp-4);
	border: 1px solid var(--border-strong); border-radius: var(--r-sm);
	background: var(--surface); color: var(--text);
	font: inherit; font-size: var(--fs-sm); font-weight: 500; line-height: 1;
	letter-spacing: -.01em;
	cursor: pointer; text-decoration: none; white-space: nowrap;
	transition: background var(--dur), border-color var(--dur), color var(--dur);
}
.btn:hover { background: var(--surface-alt); border-color: var(--text-faint); text-decoration: none; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .45; cursor: default; }

/* 주 버튼은 잉크(검정)다. 파랑을 쓰면 어느 사이트에나 있는 화면이 된다 */
.btn--primary { background: var(--ink); border-color: var(--ink); color: var(--ink-fg); font-weight: 600; }
.btn--primary:hover { background: var(--ink-hover); border-color: var(--ink-hover); color: var(--ink-fg); }

.btn--ghost { background: transparent; border-color: transparent; color: var(--text-muted); }
.btn--ghost:hover { background: var(--surface-alt); border-color: transparent; color: var(--text); }
.btn--danger { border-color: var(--danger); color: var(--danger); background: transparent; }
.btn--danger:hover { background: var(--danger-soft); border-color: var(--danger); }
.btn--sm { height: 28px; padding: 0 var(--sp-3); font-size: var(--fs-xs); }
.btn--lg { height: 42px; padding: 0 var(--sp-5); font-size: var(--fs-md); }
.btn--icon { width: 34px; padding: 0; }
.btn--icon.btn--sm { width: 28px; }
.btn--block { width: 100%; }

.card {
	background: var(--surface); border: 1px solid var(--border);
	border-radius: var(--r-lg); box-shadow: var(--sh-1);
}
.card__header {
	padding: var(--sp-4); border-bottom: 1px solid var(--border);
	display: flex; align-items: center; gap: var(--sp-3);
}
.card__title { margin: 0; font-size: var(--fs-base); font-weight: 700; }
.card__body { padding: var(--sp-4); }
.card__footer { padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--border); background: var(--bg-subtle); border-radius: 0 0 var(--r-lg) var(--r-lg); }

/* 카드 그리드 (도구 허브) */
.grid { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.grid--wide { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }

/* 도구 카드 */
.toolcard {
	display: block; padding: var(--sp-4);
	background: var(--surface); border: 1px solid var(--border);
	border-radius: var(--r-lg); color: var(--text);
	transition: border-color var(--dur), box-shadow var(--dur), transform var(--dur);
}
.toolcard:hover { border-color: var(--accent); box-shadow: var(--sh-2); text-decoration: none; transform: translateY(-1px); }
.toolcard__name { font-weight: 700; margin-bottom: var(--sp-1); display: flex; align-items: center; gap: var(--sp-2); }
.toolcard__desc { font-size: var(--fs-sm); color: var(--text-muted); margin: 0; line-height: 1.55; }

/* 표 */
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.table th, .table td { padding: var(--sp-3); text-align: left; border-bottom: 1px solid var(--border); }
.table th { font-weight: 700; color: var(--text-muted); font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .04em; }
.table tbody tr:hover { background: var(--bg-subtle); }
.table--fixed { table-layout: fixed; }
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* 게시글 목록 */
.postlist { list-style: none; margin: 0; padding: 0; }
.postlist__item {
	padding: var(--sp-4) 0;
	border-bottom: 1px solid var(--border);
}
.postlist__item:last-child { border-bottom: 0; }
.postlist__item:first-child { padding-top: var(--sp-2); }
.postlist__title {
	display: block;
	font-size: var(--fs-lg); font-weight: 600; line-height: var(--lh-snug);
	letter-spacing: var(--tr-tight);
	color: var(--text); text-decoration: none;
	/* 밑줄은 hover 에서만, 글자에서 살짝 떨어뜨린다 */
	text-underline-offset: 3px;
}
.postlist__title:hover { color: var(--accent); text-decoration: underline; }
.postlist__meta {
	display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-3);
	margin-top: var(--sp-1);
	font-family: var(--font-mono);
	font-size: var(--fs-xs); letter-spacing: var(--tr-wide);
	color: var(--text-faint);
	/* 숫자 폭을 고정해 조회수가 세로로 정렬되게 한다 */
	font-variant-numeric: tabular-nums;
}
.postlist__meta a { color: inherit; }
.postlist__excerpt {
	margin: var(--sp-2) 0 0;
	font-size: var(--fs-sm); line-height: var(--lh-snug); color: var(--text-muted);
	display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

.field { display: block; margin-bottom: var(--sp-4); }
.label { display: block; font-size: var(--fs-sm); font-weight: 600; margin-bottom: var(--sp-2); }
.hint  { font-size: var(--fs-xs); color: var(--text-faint); margin-top: var(--sp-1); }
.error { font-size: var(--fs-xs); color: var(--danger); margin-top: var(--sp-1); }

.input, .textarea, .select {
	width: 100%; padding: var(--sp-2) var(--sp-3); min-height: 36px;
	background: var(--surface); color: var(--text);
	border: 1px solid var(--border-strong); border-radius: var(--r-md);
	font-family: inherit; font-size: var(--fs-sm); line-height: 1.5;
}
.input:focus, .textarea:focus, .select:focus {
	border-color: var(--accent); outline: 2px solid var(--accent-soft); outline-offset: 0;
}
.textarea { min-height: 180px; resize: vertical; font-family: var(--font-mono); line-height: 1.6; }
.textarea--code { min-height: 320px; white-space: pre; overflow-wrap: normal; overflow-x: auto; }
.select { appearance: none; padding-right: var(--sp-6); background-image: linear-gradient(45deg, transparent 50%, var(--text-muted) 50%), linear-gradient(135deg, var(--text-muted) 50%, transparent 50%); background-position: calc(100% - 16px) 15px, calc(100% - 11px) 15px; background-size: 5px 5px; background-repeat: no-repeat; }

.checkline { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); cursor: pointer; }

/* 뱃지 */
.badge {
	display: inline-flex; align-items: center; gap: 4px;
	padding: 2px var(--sp-2); border-radius: var(--r-full);
	font-size: var(--fs-xs); font-weight: 600; line-height: 1.6;
	background: var(--surface-alt); color: var(--text-muted); border: 1px solid var(--border);
}
.badge--accent  { background: var(--accent-soft);  color: var(--accent);  border-color: transparent; }
.badge--success { background: var(--success-soft); color: var(--success); border-color: transparent; }
.badge--warn    { background: var(--warn-soft);    color: var(--warn);    border-color: transparent; }
.badge--danger  { background: var(--danger-soft);  color: var(--danger);  border-color: transparent; }

/* 태그 */
.tag {
	display: inline-block; padding: 1px var(--sp-2); border-radius: var(--r-sm);
	background: var(--surface-alt); color: var(--text-muted);
	font-size: var(--fs-xs); font-weight: 500;
}
.tag:hover { background: var(--accent-soft); color: var(--accent); text-decoration: none; }

/* 알림 박스 */
.notice {
	padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
	border: 1px solid var(--border); background: var(--surface-alt);
	font-size: var(--fs-sm);
}
.notice--info    { background: var(--accent-soft);  border-color: transparent; }
.notice--success { background: var(--success-soft); border-color: transparent; }
.notice--warn    { background: var(--warn-soft);    border-color: transparent; }
.notice--danger  { background: var(--danger-soft);  border-color: transparent; }

/* 토스트 */
.toast-host {
	position: fixed; right: var(--sp-4); bottom: var(--sp-4); z-index: 300;
	display: flex; flex-direction: column; gap: var(--sp-2); pointer-events: none;
}
.toast {
	background: var(--text); color: var(--bg);
	padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
	box-shadow: var(--sh-2); font-size: var(--fs-sm); font-weight: 600;
	animation: toast-in var(--dur) ease-out;
}
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* 페이지네이션 */
.pagination {
	display: flex; align-items: center; justify-content: center; gap: var(--sp-1);
	margin: var(--sp-8) 0 var(--sp-6);
}
.pagination a, .pagination span {
	display: inline-flex; align-items: center; justify-content: center;
	min-width: 32px; height: 32px; padding: 0 var(--sp-2);
	border: 0; border-radius: var(--r-sm);
	font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
	color: var(--text-muted); text-decoration: none;
	transition: background var(--dur), color var(--dur);
}
.pagination a:hover { background: var(--surface-alt); color: var(--text); text-decoration: none; }
/* 현재 페이지도 잉크. 파란 알약보다 조용하고 또렷하다 */
.pagination .is-current { background: var(--ink); color: var(--ink-fg); font-weight: 600; }
.pagination .is-disabled { opacity: .3; cursor: default; }

.pagehead {
	display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-5);
	flex-wrap: wrap;
	margin: var(--sp-8) 0 var(--sp-6);
	padding-bottom: var(--sp-4);
	border-bottom: 1px solid var(--border);
}
.pagehead__title {
	margin: 0;
	font-size: var(--fs-2xl); font-weight: 700; line-height: var(--lh-tight);
	letter-spacing: var(--tr-tighter);
}
.pagehead__desc { margin: var(--sp-2) 0 0; color: var(--text-muted); font-size: var(--fs-sm); }
/* 제목 위에 얹는 분류 라벨. 모노+자간으로 "손으로 짠 화면" 느낌을 준다 */
.pagehead__eyebrow {
	display: block; margin-bottom: var(--sp-2);
	font-family: var(--font-mono); font-size: var(--fs-xs);
	letter-spacing: var(--tr-wide); text-transform: uppercase;
	color: var(--text-faint);
}
.pagehead__actions { display: flex; align-items: center; gap: var(--sp-2); }

.toolhead {
	display: flex; align-items: flex-start; gap: var(--sp-4);
	padding-bottom: var(--sp-4); margin-bottom: var(--sp-5);
	border-bottom: 1px solid var(--border); flex-wrap: wrap;
}
.toolhead__meta { flex: 1 1 260px; min-width: 0; }
.toolhead__actions { display: flex; gap: var(--sp-2); flex: 0 0 auto; }

/* 로컬 처리 배지 — 도구 신뢰 표시 */
.localbadge {
	display: inline-flex; align-items: center; gap: 6px;
	padding: 2px var(--sp-2); border-radius: var(--r-full);
	background: var(--success-soft); color: var(--success);
	font-size: var(--fs-xs); font-weight: 600;
}

/* 빈 상태 */
.empty { text-align: center; padding: var(--sp-8) var(--sp-4); color: var(--text-faint); }

/* 아이콘 */
.icon { width: 1em; height: 1em; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex: 0 0 auto; vertical-align: -.125em; }
.icon--lg { width: 20px; height: 20px; }

/* 통계 타일 */
.stats { display: flex; gap: var(--sp-4); flex-wrap: wrap; }
.stat { flex: 1 1 100px; }
.stat__label { font-size: var(--fs-xs); color: var(--text-faint); text-transform: uppercase; letter-spacing: .05em; }
.stat__value { font-size: var(--fs-xl); font-weight: 700; font-variant-numeric: tabular-nums; }

/* --------------------------------------------------------------------------
   6. 광고 슬롯
   ad.js가 컨테이너 폭을 재고 광고 단위를 주입한다. 여기서는 자리만 예약한다.
   -------------------------------------------------------------------------- */
.ad-slot {
	display: block; margin: var(--sp-5) 0; text-align: center;
	/* CLS 방지: 최소 높이 예약. ad.js가 폭 판정 후 실제 높이로 조정 */
	min-height: 100px;
}
.ad-slot::before {
	content: "광고"; display: block;
	font-size: 10px; color: var(--text-faint); letter-spacing: .1em;
	margin-bottom: var(--sp-1); text-align: left;
}
.ad-slot--empty { display: none !important; }
/* 도구 페이지: 입력/버튼과 충분히 떨어뜨려 오클릭 방지 */
.ad-slot--tool { margin-top: var(--sp-8); }
.ad-slot--sidebar { min-height: 250px; margin: 0; position: sticky; top: calc(var(--h-header) + var(--sp-4)); }

/* --------------------------------------------------------------------------
   6-2. 명령 팔레트 (⌘K)
   -------------------------------------------------------------------------- */
.palette {
	position: fixed; inset: 0; z-index: 400;
	background: rgba(10, 13, 17, .45);
	backdrop-filter: blur(2px);
	display: flex; align-items: flex-start; justify-content: center;
	padding: 12vh var(--sp-4) var(--sp-4);
}
.palette[hidden] { display: none; }
.palette__box {
	width: 100%; max-width: 560px;
	background: var(--surface); border: 1px solid var(--border);
	border-radius: var(--r-lg); box-shadow: var(--sh-2);
	overflow: hidden;
	animation: palette-in 120ms ease-out;
}
@keyframes palette-in { from { opacity: 0; transform: translateY(-6px) scale(.98); } to { opacity: 1; transform: none; } }
.palette__input {
	width: 100%; padding: var(--sp-4);
	border: 0; border-bottom: 1px solid var(--border);
	background: transparent; color: var(--text);
	font-family: inherit; font-size: var(--fs-lg);
}
.palette__input:focus { outline: none; }
.palette__list { list-style: none; margin: 0; padding: var(--sp-2); max-height: 50vh; overflow-y: auto; }
.palette__item {
	display: flex; align-items: center; gap: var(--sp-3);
	padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md);
	cursor: pointer; margin: 0;
}
.palette__item.is-active { background: var(--accent-soft); }
.palette__name { font-weight: 600; font-size: var(--fs-sm); }
.palette__group { margin-left: auto; font-size: var(--fs-xs); color: var(--text-faint); }
.palette__empty { padding: var(--sp-5); text-align: center; color: var(--text-faint); font-size: var(--fs-sm); }

/* --------------------------------------------------------------------------
   6-3. 히어로 / 섹션 헤더 (홈)
   -------------------------------------------------------------------------- */
.hero {
	padding: var(--sp-8) 0 var(--sp-7);
	border-bottom: 1px solid var(--border);
	background:
		radial-gradient(60rem 22rem at 15% -20%, var(--accent-soft), transparent 60%),
		var(--bg);
}
.hero__title {
	font-size: clamp(26px, 4.4vw, 40px);
	letter-spacing: -.03em; margin-bottom: var(--sp-3);
}
.hero__lead { font-size: var(--fs-lg); color: var(--text-muted); max-width: 46ch; margin-bottom: var(--sp-5); }
.hero__actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; }

.section { margin-top: var(--sp-8); }
.section__head { display: flex; align-items: baseline; gap: var(--sp-3); margin-bottom: var(--sp-4); }
.section__title { margin: 0; font-size: var(--fs-xl); letter-spacing: -.01em; }
.section__more { margin-left: auto; font-size: var(--fs-sm); font-weight: 600; }

/* --------------------------------------------------------------------------
   7. 유틸리티 (최소한만)
   -------------------------------------------------------------------------- */
.muted   { color: var(--text-muted); }
.faint   { color: var(--text-faint); }
.small   { font-size: var(--fs-sm); }
.xsmall  { font-size: var(--fs-xs); }
.bold    { font-weight: 700; }
.mono    { font-family: var(--font-mono); }
.nowrap  { white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.text-center { text-align: center; }
.text-right  { text-align: right; }
.mt-0 { margin-top: 0; }    .mb-0 { margin-bottom: 0; }
.mt-4 { margin-top: var(--sp-4); }  .mb-4 { margin-bottom: var(--sp-4); }
.mt-6 { margin-top: var(--sp-6); }  .mb-6 { margin-bottom: var(--sp-6); }
.hide { display: none !important; }
@media (max-width: 760px) { .hide-sm { display: none !important; } }
@media (min-width: 761px) { .show-sm { display: none !important; } }

/* 본문 렌더링 영역 (마크다운 산출물) */
.prose { max-width: var(--w-content); }
.prose > :first-child { margin-top: 0; }
.prose h2 { margin-top: var(--sp-7); padding-top: var(--sp-2); }
.prose h3 { margin-top: var(--sp-6); }
.prose img { border-radius: var(--r-md); border: 1px solid var(--border); }
.prose table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); margin-bottom: var(--sp-4); }
.prose th, .prose td { padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border); text-align: left; }
.prose th { background: var(--surface-alt); font-weight: 700; }

/* --------------------------------------------------------------------------
   글 본문 (.dv-content) — 사용자가 작성한 HTML 이 그대로 들어온다

   .prose 와 달리 여기 들어오는 마크업을 우리가 통제할 수 없다.
   기존 글에는 <table width="900">, 원본 크기 <img>, 인라인 style 이 섞여 있고
   그대로 두면 본문이 레이아웃 밖으로 밀고 나간다. 그래서 규칙이 두 겹이다.
     1) .prose 와 같은 읽기 스타일을 준다
     2) 어떤 마크업이 와도 가로 폭을 넘지 못하게 막는다
   -------------------------------------------------------------------------- */
.dv-content {
	/* .prose 는 max-width 로 줄 길이를 제한하지만, 본문에는 코드·표가 많아
	   폭을 좁히면 오히려 읽기 나빠진다. 대신 컨테이너 폭에 맞춘다. */
	max-width: 100%;
	line-height: var(--lh-base);
	/* 줄바꿈 없는 긴 URL·해시값이 폭을 밀어내는 것을 막는다 */
	overflow-wrap: anywhere;
}
.dv-content > :first-child { margin-top: 0; }
.dv-content h2 { margin-top: var(--sp-7); padding-top: var(--sp-2); }
.dv-content h3 { margin-top: var(--sp-6); }

/* 표 — 새 콘텐츠는 3열 정도지만, 옛 글에는 width 속성이 박힌 표가 있다.
   width 속성은 CSS 로 덮어써야 무력화된다. */
.dv-content table {
	width: 100% !important;
	max-width: 100%;
	border-collapse: collapse;
	font-size: var(--fs-sm);
	margin-bottom: var(--sp-4);
	display: block;        /* 열이 많아 넘칠 때 표 자체가 가로 스크롤된다 */
	overflow-x: auto;
}
.dv-content th, .dv-content td {
	padding: var(--sp-2) var(--sp-3);
	border: 1px solid var(--border);
	text-align: left;
	vertical-align: top;
}
.dv-content th { background: var(--surface-alt); font-weight: 700; }

/* 이미지·미디어 — 원본 크기로 들어와도 컨테이너를 넘지 않는다 */
.dv-content img,
.dv-content video,
.dv-content iframe,
.dv-content embed {
	max-width: 100%;
	height: auto;
}
.dv-content img {
	border-radius: var(--r-md);
	border: 1px solid var(--border);
}

/* 코드 — pre 는 전역에서 이미 overflow-x:auto 다. 옛 글이 pre 없이
   긴 줄을 넣은 경우를 대비해 인라인 code 도 넘치지 않게 둔다. */
.dv-content code { overflow-wrap: anywhere; }
.dv-content pre { max-width: 100%; }

/* 옛 글의 인라인 고정 폭 무력화. width 속성과 style="width:900px" 둘 다 잡는다. */
.dv-content [width],
.dv-content [style*="width"] { max-width: 100% !important; }

.dv-content blockquote {
	border-left: 3px solid var(--border-strong);
	margin: 0 0 var(--sp-4);
	padding: var(--sp-1) var(--sp-4);
	color: var(--text-muted);
}
.dv-content ul, .dv-content ol { padding-left: var(--sp-5); }
.dv-content li + li { margin-top: var(--sp-1); }
.dv-content a { overflow-wrap: anywhere; }

/* --------------------------------------------------------------------------
   레거시 붙여넣기 정리

   기존 글 상당수가 ChatGPT · StackOverflow 화면에서 그대로 복사돼 있다.
   본문 안에 인라인 style 이 수백 줄씩 들어 있고, 거기에 그 사이트의
   글자색·배경색·폰트가 박혀 있다. 실제로 확인된 것들:
     · style="width: 628px"                → 좁은 화면에서 레이아웃을 밀어낸다
     · style="color: rgb(12,13,14)"        → 다크모드에서 검은 글자가 검은 배경에 얹힌다
     · font-family: Söhne / var(--ff-mono) → 우리 쪽에 없는 폰트·변수라 폴백이 제각각이다
     · background-color: var(--highlight-bg) → 정의되지 않은 변수라 투명하게 떨어진다

   인라인 style 은 !important 로만 덮을 수 있다. 코드 하이라이팅 색이 같이
   죽지만, 다크모드에서 글이 안 보이는 것보다는 낫다.
   근본 해결은 저장 시점에 본문을 정제하는 것이고, 이건 그때까지의 방어막이다.
   -------------------------------------------------------------------------- */

/* 폰트는 항상 우리 것으로. 없는 폰트를 참조하면 글꼴이 페이지마다 달라진다. */
.dv-content [style*="font-family"] { font-family: inherit !important; }
.dv-content [style*="font-family"] code,
.dv-content [style*="font-family"] pre { font-family: var(--font-mono) !important; }

/* 고정 폭 무력화 (위 [style*="width"] 규칙을 인라인보다 확실히 이기게 한다) */
.dv-content [style*="width"] { width: auto !important; max-width: 100% !important; }

/* 다크모드에서만 색을 되돌린다. 라이트모드에서는 원본 색이 대체로 읽히므로 두 번 손대지 않는다. */
@media (prefers-color-scheme: dark) {
	:root:not([data-theme="light"]) .dv-content [style*="color"] { color: var(--text) !important; }
	:root:not([data-theme="light"]) .dv-content [style*="background"] { background: transparent !important; }
	:root:not([data-theme="light"]) .dv-content pre,
	:root:not([data-theme="light"]) .dv-content code { background: var(--code-bg) !important; color: var(--code-text) !important; }
}
:root[data-theme="dark"] .dv-content [style*="color"] { color: var(--text) !important; }
:root[data-theme="dark"] .dv-content [style*="background"] { background: transparent !important; }
:root[data-theme="dark"] .dv-content pre,
:root[data-theme="dark"] .dv-content code { background: var(--code-bg) !important; color: var(--code-text) !important; }

/* 인쇄 */
@media print {
	.header, .footer, .subnav, .doc-aside, .ad-slot, .toolhead__actions { display: none !important; }
	body { background: #fff; color: #000; }
	.doc-grid { display: block; }
}
