/* ===== v3.css — aff 관리자 디자인 V3 (격리 트랙 · 단일 파일) =====
   정본: wiki/design/v3/v3-spec.md v3.0
   계약: 이 파일 하나가 tokens.css → kit/tokens.css → kit/admin-kit.css → aff.css
         4파일 스택을 **대체 로드**한다(lib/admin/layout.php의 V3 스위치).
         기존 파일은 수정하지 않는다 — 캐스케이드 간섭 0(격리).
   규율(상위 정본 유지):
   - 색: §2 팔레트 참조·알파 파생만. 신규 hex 0건.
   - 간격: §7 스케일 {4·8·12·16·20·24·28·32·40·56·64}.
   - 모션: §9-4(호버 배경 .2s) · §9-5(호버 텍스트색 .1s) · §9-17/18(드로어) ·
           admin-kit §7.5(구획 접힘)뿐. reduced-motion 전역 차단.
   - 이모지 0 · 아이콘 인라인 SVG(layout.php 출처) · 시맨틱색은 도트+틴트+g900 글자.
   V3 조형: 선(1px 헤어라인)이 구조, 그림자가 층을 만든다.
   그림자 3층(v3-spec §2-0-1): 콘텐츠 판 --v3-shadow-card / 크롬·보조 없음 /
   부양 --v3-shadow-float. 무차별 부여 금지 — 배정 없는 그림자는 반려다.
   라운드 2단: 컨트롤 8 · 판 12 · 알약은 상태 배지 전용(컨트롤 금지). */

/* ── 0. 토큰 ─────────────────────────────────────────────────────────── */
:root{
  /* §2 정본 팔레트 — tokens.css와 값 동일(token-audit 대조 대상) */
  --g50:#fbfaf9; --g100:#f4f3f1; --g200:#e8e6e3; --g300:#d6d3cf;
  --g400:#b4afaa; --g500:#918b85; --g600:#726c66; --g700:#56514c;
  --g800:#3a3632; --g900:#201d1a;
  --blue:#f0563a; --blue-hover:#d9401f; --blue-weak:#ffede7; --blue-deep:#cf4522;
  --ok:#5f9e3f; --warn:#e08c1a; --out:#c0334d;
  --ok-weak:#eff7e9; --warn-weak:#fdf3e3; --out-weak:#fbe9ee;
  --shadow-m:0 8px 16px 0 rgba(42,38,34,.10), 0 4px 8px 0 rgba(42,38,34,.06);
  --r-s:8px; --r-m:12px; --r-card:20px; --r-pill:999px;
  --ease:cubic-bezier(.25,1,.5,1);
  --maxw:1140px; --textw:720px;
  /* V3 역할 토큰 — KolDaat 테마(정본: wiki/design/v3/v3-spec.md §2-0 · 원천:
     /home/website/koldaat_com/cportal/admin/assets/kit/tokens.css). 값은 전부
     koldaat 토큰 인용이다(신규 발명 0). 오류색(--v3-out)만 aidure 정본 유지 —
     koldaat은 레드 금지 브랜드지만 aidure 폼 오류 상태는 기능 색이다. */
  --v3-canvas:#FAF9F8;                /* 페이지 지면 — koldaat --bg */
  --v3-rail:#F5F3F1;                  /* 사이드바 — koldaat --bg-faint */
  --v3-faint:#F5F3F1;                 /* 옅은 지면·th 밴드·행 호버 */
  --v3-soft:#EDEAE7;                  /* 가라앉은 지면·칩·호버 — koldaat --bg-soft */
  --v3-ink:#201D1A;                   /* 본문·제목 — koldaat --ink */
  --v3-ink2:#56514C;                  /* 보조 텍스트·라벨 — koldaat --ink-2 */
  --v3-ink3:#726C66;                  /* 메타·표 머리 — koldaat --ink-3 */
  --v3-mute:#B4AFAA;                  /* 플레이스홀더·비활성 — koldaat --line-hover */
  --v3-line:#E3E0DC;                  /* 헤어라인(카드·행) — koldaat --line-soft */
  --v3-line-soft:#EDEAE7;             /* 내부 소프트 헤어라인 */
  --v3-line-strong:#D6D3CF;           /* 입력·고스트 보더 — koldaat --line */
  --v3-accent:#F0563A;                /* 브랜드 액센트 — 마크·도트·현재 표시 */
  --v3-accent-ink:#CF4522;            /* 액센트 텍스트·링크·채움 버튼(흰 글자 6.7:1) */
  --v3-accent-ink2:#B23A1D;           /* 채움 버튼 호버 */
  --v3-tint:#FFDED4;                  /* 선택 면·블루 배지 — koldaat --accent-tint */
  --v3-hi:#FF9B80;                    /* 다크 면 위 액센트 텍스트·차트 밝은 파생 */
  --v3-dk2:#DED7CF; --v3-dk3:#A79E96; --v3-dk4:#968D85;  /* 다크 패널 보조 잉크 */
  --v3-ok:#3F7A2A; --v3-ok-tint:#EFF7E9;      /* koldaat 성공(틸 그린) */
  --v3-warn:#8A5A0E; --v3-warn-tint:#FDF3E3;  /* koldaat 경고(앰버) */
  --v3-out:#C0334D; --v3-out-tint:#FBE9EE;    /* aidure 오류 정본 유지 */
  /* [admin-v8] 모양 2단 복원(v3-spec v3.0 원칙 4) — 컨트롤 8 · 판 12.
     알약(--r-pill)은 상태 배지 전용이고 컨트롤에는 금지다. koldaat 필 언어(9/14/999)는
     폐기: 알약 버튼과 알약 정보칩이 같은 줄에서 구분되지 않았다(/stores 툴바 실측). */
  --v3-r-ctl:var(--r-s);              /* 컨트롤 라운드 8 */
  --v3-r-panel:var(--r-m);            /* 판 라운드 12 */
  --v3-ctl-h:44px;                    /* 컨트롤 표준 등고(§10 터치 44) */
  /* [admin-v8] 입력 폭 등급(v3-spec §3-4-1) — 컨트롤은 담는 값의 최대 길이만큼만 선다.
     §7 스케일의 통제 대상이 아니다(§7 머리말이 컴포넌트 내부 치수를 스스로 제외한다).
     등록부: design-system §12. 근거 실측: /stores/new 1440에서 maxlength=40 상호 칸 816px. */
  --v3-fw-xs:120px;                   /* 시각 HH:MM */
  --v3-fw-sm:168px;                   /* 날짜 · 수치 */
  --v3-fw-md:240px;                   /* 전화 · ≤20자 */
  --v3-fw-lg:360px;                   /* ≤60자 · 셀렉트 */
  --v3-fw-xl:480px;                   /* ≤120자 · 기본 상한 */
  --v3-formw:720px;                   /* 인증 계열 단일 목적 폼(form.aff-card = /password) 전용 상한 — QA r3 P2-3에서 범위 축소 */
  --v3-glow:rgba(240,86,58,.16);      /* 포커스 광륜 — koldaat --accent-glow */
  --v3-glow-out:rgba(192,51,77,.14);  /* 오류 링 — --v3-out 알파 파생 */
  /* 판 그림자는 **없다**(사용자 지시 2026-09-18: 대시보드 네모 박스 뒤 그림자 전체적으로 없애기). 판은 헤어라인(--v3-line)으로만 선다.
     부양(--v3-shadow-float: 드롭다운·서랍·툴팁)은 겹쳐 뜨는 것이라 남긴다. */
  --v3-shadow-card:none;
  --v3-shadow-float:0 4px 12px rgba(42,38,34,.05), 0 8px 32px rgba(42,38,34,.08);
  --v3-scrim:rgba(42,38,34,.4);
  --v3-scroll-hint:rgba(42,38,34,.28);
  /* [admin-v8] 폰트 1종 — Pretendard. Google Fonts를 부르지 않는다(admin-kit §2 ·
     v3-spec v3.0 §2-0). --v3-display 이름은 남긴다: 지우면 다음 사람이 새 이름을
     만든다(admin-kit §3 한계 3의 근거 그대로). 값이 --v3-sans와 같으므로 렌더는 하나다. */
  --v3-sans:'Pretendard Variable',Pretendard,-apple-system,BlinkMacSystemFont,'Apple SD Gothic Neo','Noto Sans KR',sans-serif;
  --v3-display:var(--v3-sans);
  /* 모노는 **정렬이 뜻을 갖는 자리**(diff·경로·원문 블록) 전용이다. 스택 끝은 반드시
     `monospace` 제네릭이어야 한다 — 그 앞에 비례 서체를 끼우면 앞 후보가 없는
     플랫폼에서 모노 전체가 비례로 해소된다(QA r2 P2-A). 한글을 품는 식별자는
     모노를 쓰지 않는다(.hash·.cell-code — 아래). */
  --v3-mono:ui-monospace,'SFMono-Regular',Menlo,Consolas,monospace;
}

/* ── 1. 리셋·베이스 ───────────────────────────────────────────────────── */
*{margin:0;padding:0;box-sizing:border-box}
[hidden]{display:none!important}
body{font-family:var(--v3-sans);
  font-size:15px;line-height:1.6;color:var(--v3-ink);background:var(--v3-canvas);
  -webkit-font-smoothing:antialiased;word-break:keep-all}
h1,h2,h3,h4{color:var(--v3-ink);font-weight:700;letter-spacing:-0.01em}
a{color:inherit;text-decoration:none}
.num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}
.nw{white-space:nowrap}
::selection{background:var(--v3-tint)}
:focus-visible{outline:2px solid var(--v3-accent);outline-offset:2px}
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}

/* [QA r4 P1-1] 클래스 없는 <code>는 UA 기본 monospace로 서서 한글과 맞붙는다.
   다만 **상대 크기(em)를 쓰면 안 된다** — 부모에 곱해져 13→11.96 · 12→11.04로
   램프 하한(12)을 뚫는다(v3-spec §6 "12px 미만 = P1"). 램프 값을 고정한다.
   그리고 :where()로 특이도를 0으로 낮춘다 — 그러지 않으면 (0,2,1)이
   `.wk-doc code`·`.gv-trunc code`(0,1,1~2)를 이겨 **모노 자리의 모노를 빼앗는다**. */
:where(.shell,.auth) code:not([class]){font-family:var(--v3-sans);
  font-variant-numeric:tabular-nums;font-size:12px;background:var(--v3-soft);
  border-radius:4px;padding:0 4px}

.skip{position:absolute;left:-9999px;top:0;z-index:200;background:#fff;color:var(--v3-accent-ink);
  font-size:13px;font-weight:600;padding:12px 16px;border-radius:var(--v3-r-ctl);
  border:1px solid var(--v3-line);box-shadow:var(--v3-shadow-float);
  display:inline-flex;align-items:center;min-height:44px}
.skip:focus{left:8px;top:8px}

/* ── 2. 콘솔 셸 ──────────────────────────────────────────────────────── */
.shell{display:flex;min-height:100vh}
.sidebar{flex:0 0 232px;width:232px;background:var(--v3-rail);
  border-right:1px solid var(--v3-line);
  position:sticky;top:0;height:100vh;display:flex;flex-direction:column;padding:16px 12px}
.sb-nav{flex:1 1 auto;min-height:0;overflow-y:auto}
.sb-logo{font-size:17px;font-weight:700;letter-spacing:-0.01em;color:var(--v3-ink);
  padding:4px 12px 20px;display:flex;align-items:center;gap:8px}
.sb-logo svg,.sb-logo img{display:block}
.sb-logo .wm{color:var(--v3-ink)}
.sb-logo .wm .pdot{color:var(--v3-accent)}

/* 구획 라벨(접기 버튼) — 12/700 g500 자간 .04em. 시각은 라벨, 타깃은 전폭 버튼 */
.sb-sec{display:flex;align-items:center;justify-content:space-between;gap:8px;
  width:100%;background:none;border:0;margin:12px 0 4px;padding:0 12px;min-height:36px;
  border-radius:var(--v3-r-ctl);font-family:inherit;
  font-size:12px;font-weight:700;letter-spacing:.04em;color:var(--v3-ink3);
  text-align:left;cursor:pointer;
  transition:background .2s ease,color .1s ease}   /* §9-4 · §9-5 */
.sb-sec:hover{background:var(--v3-soft);color:var(--v3-ink2)}
.sb-sec-i{flex:none;fill:none;stroke:var(--v3-ink3);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.sb-sec[aria-expanded="false"] .sb-sec-i{transform:rotate(-90deg)}

.sb-nav a{display:flex;align-items:center;gap:8px;min-height:44px;padding:0 12px;
  border-radius:var(--v3-r-ctl);color:var(--v3-ink2);font-size:15px;font-weight:600;
  letter-spacing:-0.005em;margin-bottom:1px;
  transition:background .2s ease,color .1s ease}   /* §9-4 · §9-5 */
.sb-nav a svg{width:16px;height:16px;flex:0 0 16px;color:var(--v3-ink3)}
.sb-nav a:hover{color:var(--v3-ink);background:var(--v3-soft)}
.sb-nav a.on{color:var(--v3-ink);font-weight:700;background:var(--v3-tint)}
.sb-nav a.on svg{color:var(--v3-accent-ink)}

@media (min-width:901px){
  .sb-secbody{max-height:520px;opacity:1;overflow:hidden}
  .sb-secbody[data-collapsed]{max-height:0;opacity:0;pointer-events:none}
  .sb-secbody[data-sec-anim]{transition:max-height .2s ease,opacity .2s ease}  /* admin-kit §7.5 */
}

.sb-foot{margin-top:auto;flex:none;border-top:1px solid var(--v3-line);padding:12px 12px 0;font-size:13px}
.sb-user{font-weight:700;color:var(--v3-ink);display:inline}
.sb-role{color:var(--v3-ink3);font-size:12px;display:inline;margin-left:8px}
.sb-acts{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:12px}
.sb-acts>form{display:contents}
.sb-acts .btn{flex:1 1 auto;min-width:0;width:auto;padding:0 12px}
.sb-ver{margin-top:12px;font-size:12px;color:var(--v3-mute);font-variant-numeric:tabular-nums;line-height:1.5}
/* [QA V3-1차 P3] 릴리스 식별자 상시 노출 축소(스펙 §3-1 · D5) — 정본 자리는
   /settings 「시스템 정보」다. 사이드바 버전 줄은 화면 계약 버전 한 줄만 남는다. */
.sb-ver .sb-rel{display:none}

.main{flex:1;min-width:0;background:var(--v3-canvas);min-height:100vh}

/* ── 3. 본문 컬럼·수직 리듬 ──────────────────────────────────────────── */
/* [admin-v8] 콘솔은 마케팅 컬럼이 아니다(v3-spec §4). --maxw(1140)는 design-system §2가
   정한 홈·손님 공용 컨테이너다 — 1440에서 68px를 죽이면서 정작 1100에서는 표 열이
   잘렸다(/visits 「플래그」 열 실측). 콘솔의 틀은 사이드바(232)와 좌우 패딩이 만든다.
   measure는 페이지가 아니라 산문이 갖는다(.sub·.fn·.card-note·KV 값 = --textw). */
.aff-main{max-width:none;margin:0;padding:24px 32px 64px}
.aff-main>*+*{margin-top:24px}
.aff-main>.grp{margin-top:40px}
/* [admin-v8] 각주는 블록 리듬(24)에서 한 단 내려선다 — 증거(표)와 해설의 무게를
   가르는 마지막 한 수다(v3-spec 원칙 5 · 문안은 V3.1 카피 회차 소관). */
.aff-main>.card-note,.aff-main>.fn{margin-top:16px}
.aff-main>.fn+.fn{margin-top:8px}
.aff-main>.dr-mask,.aff-main>.drawer{margin-top:0}   /* 오버레이는 리듬 밖 */

/* ── 4. 마스트헤드(page-head) — V3 동형 머리 ─────────────────────────── */
.page-head{position:relative;padding-bottom:16px;border-bottom:1px solid var(--v3-line-soft);
  margin-bottom:24px}
.page-head h1{font-size:22px;font-weight:700;color:var(--v3-ink);letter-spacing:-0.01em;line-height:1.3}
.page-head .sub{margin-top:8px;color:var(--v3-ink2);font-size:13px;line-height:1.6;max-width:var(--textw)}
.page-head .ph-act{position:absolute;top:0;right:0;min-height:28px;display:flex;align-items:center;
  font-size:13px;color:var(--v3-ink3);font-variant-numeric:tabular-nums}
.page-head:has(> .tbl-bar) .ph-act{min-height:44px}
/* [QA V3-1차 P3] 기준시각은 평문 메타다(스펙 §3-2 13/g500) — 알약은 상태 배지 전용. */
.page-head .ph-act .badge{background:transparent;border:0;padding:0;height:auto;
  font-size:13px;font-weight:400;color:var(--v3-ink3);font-variant-numeric:tabular-nums}

/* [V3 후속 — Joseph 지시 /kpc 회차] 섹션 간 간격 28 → 40 — 섹션은 §7 리듬의
   "그룹"이다(블록 24 · 그룹 40). 28은 블록과 그룹 사이 어중간한 단이라 대형 화면
   (kpc·dashboard)에서 표 섹션들이 한 덩어리로 붙어 읽혔다. */
.section{margin-top:40px}
.section h2{font-size:17px;font-weight:700;color:var(--v3-ink);letter-spacing:-0.01em;line-height:1.4;margin-bottom:12px}
.section h2 small{font-weight:400;font-size:12px;color:var(--v3-ink3);margin-left:8px;letter-spacing:0}
.h2-row{display:flex;align-items:center;justify-content:space-between;gap:8px 12px;margin-bottom:12px;flex-wrap:wrap}
.h2-row h2{margin-bottom:0}
.h2-act{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.h2-act .btn{flex:none;width:auto}
.section>*+.card-note{margin-top:12px}

/* 화면 머리 보조(구판 어휘 잔존 대비) */
.aff-sec{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
.aff-sec .t{font-size:22px;font-weight:700;color:var(--v3-ink);letter-spacing:-0.01em}
.aff-sec .acts{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.aff-ts{font-size:13px;color:var(--v3-ink3);font-variant-numeric:tabular-nums;white-space:nowrap}

/* 캡션·각주 */
/* [QA r3 P2-1] 표 캡션도 캡션 띠다(§2-2-1) — 공용 헬퍼 aff_tsec_open() 출력이라
   30곳에 퍼져 있는데 13px·measure 없음으로 남아 각주(.fn 12/720)와 갈렸다. */
.aff-cap{font-size:12px;line-height:1.6;color:var(--v3-ink3);margin-top:8px;
  max-width:var(--textw);text-wrap:balance}
.fn{font-size:12px;line-height:1.6;color:var(--v3-ink3);max-width:var(--textw)}
.fn+.fn{margin-top:8px}
.muted{color:var(--v3-ink2)}

/* ── 5. 버튼 — 3변형 2크기 ───────────────────────────────────────────
   색·모양은 **두레 랜딩 페이지의 CTA와 한 벌**이다(사용자 지시 2026-09-18: 「CTA 색+스타일 두레 페이지랑 통일」).
   채움 = 브랜드 주황(--blue #f0563a, 호버 --blue-hover) 알약, 보조(.b2) = 랜딩 .btn-2(옅은 회색 면, 테두리 없음).
   전에는 어두운 주황(--v3-accent-ink) 8px 모서리 + 흰 면 테두리 보조였다 — 랜딩에서 넘어오면 다른 제품처럼 보였다.
   v3-spec의 「컨트롤 알약 금지」는 이 지시로 CTA 버튼에 한해 접는다(칩·배지는 그대로). 높이(44)는 컨트롤 등고를 지킨다. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  width:auto;height:var(--v3-ctl-h);padding:0 24px;border:1px solid transparent;
  border-radius:var(--r-pill);font-family:inherit;font-size:15px;font-weight:600;cursor:pointer;
  background:var(--blue);color:#fff;white-space:nowrap;
  transition:background .2s ease}   /* §9-4 */
/* 호버는 **마우스가 있는 화면에서만**. 터치에서는 누른 뒤에도 배경이 남아 「로그아웃 눌렀더니 뒤에 배경이 생긴다」로 보였다(사용자 지적) */
@media(hover:hover){.btn:hover{background:var(--blue-hover)}}
.btn:disabled{background:var(--v3-soft);border-color:transparent;color:var(--v3-mute);cursor:default}
.btn.b2{background:var(--g100);border-color:transparent;color:var(--g800)}
@media(hover:hover){.btn.b2:hover{background:var(--g200)}}
.btn.b2:disabled{background:var(--v3-faint);color:var(--v3-mute)}
.btn.ghost{background:#fff;border-color:var(--v3-line);color:var(--v3-ink2)}
@media(hover:hover){.btn.ghost:hover{background:var(--v3-faint);color:var(--v3-ink)}}
.btn.ghost:disabled{background:var(--v3-faint);color:var(--v3-mute)}
.btn.sm{height:36px;padding:0 16px;font-size:13px}
.btn.accent{background:var(--blue);border-color:transparent;color:#fff}
@media(hover:hover){.btn.accent:hover{background:var(--blue-hover)}}

/* ── 6. 입력·폼 ──────────────────────────────────────────────────────── */
.field label,.shell label.fl,.auth label.fl{display:block;font-size:13px;font-weight:600;
  color:var(--v3-ink2);margin:0 0 8px}
.aff-input,
.shell :is(input[type="text"],input[type="password"],input[type="email"],input[type="number"],
          input[type="date"],input[type="search"],select,textarea):not(.aff-input),
.auth  :is(input[type="text"],input[type="password"],input[type="email"],input[type="number"],
          input[type="date"],input[type="search"],select,textarea):not(.aff-input){
  width:100%;height:var(--v3-ctl-h);border:1px solid var(--v3-line-strong);
  border-radius:var(--v3-r-ctl);background:#fff;padding:0 16px;
  font-family:inherit;font-size:15px;font-weight:500;color:var(--v3-ink)}
.aff-input::placeholder,
.shell input:not(.aff-input)::placeholder,.auth input:not(.aff-input)::placeholder{color:var(--v3-mute);font-weight:500}
.aff-input:focus,
.shell :is(input,select,textarea):not(.aff-input):focus,
.auth  :is(input,select,textarea):not(.aff-input):focus{
  outline:none;border-color:var(--v3-accent);box-shadow:0 0 0 3px var(--v3-glow)}
.aff-input:focus-visible{outline:none}
.aff-input:disabled{background:var(--v3-faint);color:var(--v3-mute)}
.aff-input.err{border-color:var(--v3-out);box-shadow:0 0 0 3px var(--v3-glow-out)}
.aff-input.num,input.aff-input[inputmode="numeric"],
.shell input[type="date"],.auth input[type="date"]{font-variant-numeric:tabular-nums}
textarea.aff-input,.shell textarea:not(.aff-input),.auth textarea:not(.aff-input){
  height:auto;min-height:88px;padding:12px 16px;line-height:1.6;resize:vertical}
/* 드롭다운 — 브라우저 기본 화살표를 끄고 셰브론을 우리 자로 그린다(디자인 규칙: 네이티브 금지).
   화살표 자리만큼 오른쪽 여백(40)을 두고, 글자 색 잉크(--v3-ink3)로 옅게. 열린 목록은 OS 몫이다. */
select.aff-input,.shell select:not(.aff-input),.auth select:not(.aff-input){
  appearance:none;-webkit-appearance:none;padding-right:40px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M4 6l4 4 4-4' stroke='%23918b85' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;background-size:16px 16px}
select.aff-input:disabled,.shell select:not(.aff-input):disabled{background-color:var(--v3-faint)}

.aff-err{font-size:13px;font-weight:600;color:var(--v3-out);margin-top:8px}
.aff-hint{font-size:12px;line-height:1.6;color:var(--v3-ink3);margin-top:8px}
.field .msg-err{font-size:13px;font-weight:600;color:var(--v3-out);margin-top:8px}

/* [admin-v8] 라벨 거터는 160 하나다 — .form-row(160)·.kv·.aff-kv와 같은 값.
   180과 160이 공존해 같은 뜻의 행이 화면마다 다른 축으로 섰다(craft §6 일관). */
.aff-row{display:grid;grid-template-columns:160px 1fr;gap:16px;align-items:start}
.aff-row+.aff-row{margin-top:20px}
.aff-row>label{margin-bottom:0;padding-top:12px;font-size:13px;font-weight:600;color:var(--v3-ink2)}
.form-row{display:grid;grid-template-columns:160px 1fr;gap:12px;align-items:start}
.form-row+.form-row{margin-top:16px}
.aff-fgrp+.aff-fgrp{margin-top:40px}
.aff-fgrp>.t{font-size:15px;font-weight:700;color:var(--v3-ink);margin-bottom:16px}
.aff-acts{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:24px}
.aff-acts>.btn{flex:none;width:auto}
/* 판 아래 CTA 줄의 보조 단추는 **외곽선을 두지 않는다**(사용자 지시) — 채운 주황 옆에
   가는 선 하나만 두면 짝이 안 맞아 보였다. 선 대신 옅은 면으로 세운다.
   다른 자리의 `.ghost`(툴바·폼)는 그대로다 — 거기서는 선이 경계 노릇을 한다. */
.aff-acts>.btn.ghost{background:var(--v3-soft);border-color:transparent;color:var(--v3-ink2)}
@media(hover:hover){.aff-acts>.btn.ghost:hover{background:var(--g200);color:var(--v3-ink)}}
.form-intro{font-size:12px;color:var(--v3-ink3);margin-bottom:16px}

/* [QA r3 P2-3] 폼 판에 전역 상한을 걸지 않는다. 폼 마크업이 세 형태(form이 판 /
   판이 form을 감쌈 / form이 판 여럿을 감쌈)라 어떤 훅도 **한 form 안의 형제 판**이나
   상세 화면의 이웃 판과 폭을 가른다 — 「같은 등록 폼이 화면마다 두 폭」이 그 증상이었다.
   판은 전부 콘솔 폭으로 통일하고, 폼의 절제는 컨트롤 폭(§3-4-1)이 진다.
   예외는 **인증 계열 단일 목적 폼**(`.aff-card` — /password 하나)이다: 그 화면은 판이
   화면의 전부라 폭을 채우면 컨트롤 셋이 빈 면에 떠 있게 된다. */
/* [QA r4 P2-1] 폼 화면은 **본문 컬럼**이 폼 measure로 접힌다 — 훅이 화면에 있으므로
   폼 마크업 형태(form이 판 / 판이 form / form이 판 여럿)와 무관하고, 한 화면 안의
   모든 판이 같은 폭으로 선다. 판에 거는 방식은 형제 판을 갈랐고(QA r3), 안 거는
   방식은 빈 면을 남겼다(QA r4). 세 번째 자리가 옳은 자리다.
   `.is-form`은 layout.php `aff_head($t,$nav,['form'=>true])`가 붙인다. */
.main.is-form .aff-main{max-width:var(--v3-formw)}
.main.is-form .aff-main .aff-row{grid-template-columns:160px minmax(0,1fr)}

/* [QA r4 P2-3] 쓰기 폼이 조회 스트립 스킨을 입지 않게 한다. `.filter-bar`는
   **method=get 조회 폼 전용**이고(§2-0-1 크롬 층), 레코드를 만드는 폼은 판이다.
   `.aff-formbar`는 판이되 필터 바와 같은 격자를 쓰는 한 줄 입력 폼이다. */
/* [QA r5 P3-5] 자유 텍스트 칸(할 일·설명)이 auto-fit 1fr 트랙에 145px로 접혔다 —
   폭이 데이터를 말해야 한다(§1 원칙 6). 텍스트 입력은 두 트랙을 차지한다. */
.aff-formbar{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  gap:12px;align-items:end}
@media (min-width:601px){
  .aff-formbar>div:has(input[type="text"]:not([maxlength="20"])),
  .aff-formbar>div:has(textarea){grid-column:span 2}
}
.aff-formbar>.btn{justify-self:start}

/* 필터 바 — 헤어라인 카드 */
/* [admin-v8] 필터 바는 판이 아니라 **조회 스트립**이다(v3-spec §2-0-1 크롬 층).
   흰 카드 + r14 + 그림자로 서면 표와 같은 층으로 떠서 "조회하는 곳"과 "읽는 곳"이
   구분되지 않는다(craft §1-4 어포던스). 가라앉은 면 + 헤어라인 + 컨트롤 라운드로 내린다.
   필드 최소폭 200 → 160: 1100에서 필터가 한 칸 더 들어간다(밀도 우선 — §12 aff 행). */
.filter-bar{background:var(--v3-soft);border:1px solid var(--v3-line-soft);
  border-radius:var(--v3-r-ctl);
  padding:12px 16px;display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));
  gap:12px;align-items:end}
.aff-panel .filter-bar,.card .filter-bar{background:var(--v3-faint);border-color:var(--v3-line-soft)}
.filter-bar .btn{flex:none;width:auto}
.filter-bar>.btn{justify-self:start}
/* [QA V3-1차 P2] 채움 파랑 = 화면의 주 행동 1개(스펙 §1-3). 필터·입력 바 안의 제출은
   조회·재출력이지 화면의 주 행동이 아니다 — 바 안에서는 채움을 벗고 보더로 선다.
   화면의 채움 1개는 툴바 생성(.tb-act .btn)·폼 제출(.aff-acts .btn)이 가진다. */
.filter-bar .btn:not(.b2):not(.ghost){background:#fff;border-color:var(--v3-line-strong);color:var(--v3-ink)}
.filter-bar .btn:not(.b2):not(.ghost):hover{background:var(--v3-faint)}
.filter-bar .fl{margin-top:0}
.filter-bar+*{margin-top:24px}
.aff-panel .filter-bar+*{margin-top:16px}
.aff-filter-acts{display:flex;align-items:center;gap:12px}
.aff-filter-acts .btn{flex:none;width:auto}
.fb-grow{flex:1;min-width:200px}

/* ── 6-3. 입력 폭 등급 (v3-spec §3-4-1) ─────────────────────────────────
   훅은 마크업이 이미 든 속성이다(type · maxlength · inputmode) — **새 클래스 0 ·
   마크업 변경 0 · aff.css 계약표 개정 0**. 뷰는 이미 데이터 폭을 선언하고 있고
   (45개 입력이 maxlength 보유) CSS가 그것을 읽으면 된다. 매칭이 없으면 기본 상한(xl)으로
   안전 강등한다. .auth(로그인 380 컬럼)는 전폭이 판형이므로 .shell 안으로 한정한다. */
/* 기본 상한은 :where()로 특이도를 0으로 낮춘다 — 그러지 않으면 (0,3,0)이
   등급 규칙 (0,2,1)을 이겨서 maxlength=40 칸이 lg(360)가 아니라 xl(480)로 선다.
   등급이 기본을 이겨야지 그 반대가 되면 안 된다. */
:where(.shell) .aff-input{max-width:var(--v3-fw-xl)}

.shell input[type="time"]{max-width:var(--v3-fw-xs)}
.shell input[type="date"],
.shell input[type="number"],
.shell input[inputmode="numeric"]{max-width:var(--v3-fw-sm)}
.shell input[type="tel"],
.shell input[inputmode="tel"],
.shell :is(input,select)[maxlength="10"],
.shell :is(input,select)[maxlength="12"],
.shell :is(input,select)[maxlength="20"]{max-width:var(--v3-fw-md)}
.shell :is(input,select)[maxlength="40"],
.shell :is(input,select)[maxlength="60"],
.shell select:not([multiple]):not([size]){max-width:var(--v3-fw-lg)}
.shell :is(input,select)[maxlength="80"],
.shell :is(input,select)[maxlength="100"],
.shell :is(input,select)[maxlength="120"]{max-width:var(--v3-fw-xl)}

/* 상한 없음 — 긴 값은 접히면 읽을 수 없다. [QA admin-v8 P2-1] 면제는 **긴 값을 실제로
   담는 종류**에만 준다. maxlength만 보고 풀면 실값이 12~40자인 비밀번호 칸(maxlength 200은
   안전 상한일 뿐이다)이 1070px로 선다 — 원칙 6 위반이다. */
/* [QA r2 P2-C] 「없음」은 textarea에만 준다. url·search는 한 줄 컨트롤이라 접혀도
   좌우 스크롤로 읽히고, 상한이 없으면 같은 폼의 주소(480)보다 1.9배 넓게 선다. */
.shell textarea,
.shell textarea[maxlength]{max-width:none}
.shell input[type="url"],
.shell input[type="search"]{max-width:var(--v3-fw-xl)}
.shell input[type="password"]{max-width:var(--v3-fw-md)}

/* [QA admin-v8 P3-1] 날짜+시각 입력 — 등급표에 없어 기본 상한(480)으로 강등돼 있었다.
   실 점유 약 185px인 값이 480으로 서고 옆 칸(168)과 어긋났다. */
.shell input[type="datetime-local"]{max-width:var(--v3-fw-md)}

/* 폼 안 표(영업시간) — 컨트롤 폭이 곧 열 폭이다. 열이 잔여 폭을 나눠 가지면
   「휴무」 체크박스가 「월」 라벨에서 890px 떨어져 선다(1440 /stores/new 실측). */
.shell .tbl-wrap>.tbl:has(input.aff-input){width:auto}

/* 체크박스 */
.check{display:inline-flex;align-items:center;gap:8px;min-height:44px;min-width:44px;
  font-size:13px;color:var(--v3-ink);cursor:pointer;letter-spacing:-0.005em}
.check input{appearance:none;-webkit-appearance:none;margin:0;cursor:pointer;
  width:16px;height:16px;flex:0 0 16px;border:1px solid var(--v3-line-strong);
  border-radius:4px;background:#fff;display:inline-grid;place-content:center}
.check input:hover{border-color:var(--v3-mute)}
.check input:checked{background:var(--v3-accent-ink);border-color:var(--v3-accent-ink)}
.check input:checked::before{content:'';width:12px;height:12px;background:#fff;
  clip-path:polygon(37% 80%,9% 52%,20% 41%,37% 58%,79% 16%,90% 27%)}
.check input[disabled]{opacity:.45;cursor:not-allowed}
.check:has(input[disabled]){cursor:not-allowed;color:var(--v3-ink3)}
.check input:focus-visible{outline:2px solid var(--v3-accent);outline-offset:2px;box-shadow:none}
.field-invalid input,.field-invalid select,.field-invalid textarea{border-color:var(--v3-out)}
.field-invalid .fl{color:var(--v3-out)}
.field-msg{display:block;font-size:12px;color:var(--v3-out);margin-top:4px;line-height:1.5}

/* ── 7. 데이터 표 ────────────────────────────────────────────────────── */
/* 표는 콘텐츠 판이다 — 흰 카드 + 헤어라인 + 카드 그림자(v3-spec §2-0-1). */
.tbl-wrap{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;
  background:#fff;border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);
  box-shadow:var(--v3-shadow-card)}
.tbl-wrap>.tbl th:first-child,.tbl-wrap>.tbl td:first-child{padding-left:16px}
.tbl-wrap>.tbl th:last-child,.tbl-wrap>.tbl td:last-child{padding-right:16px}
/* [QA r3 P2-4] 이중 판형은 해제하되 **가로 스크롤 힌트는 남긴다** — background를
   통째로 transparent로 덮으면 4겹 힌트 배경까지 지워져, 390 /stores/new에서
   영업시간 표의 「휴무」 열 7개가 넘침 표시 없이 화면 밖에 숨었다(83px 넘침 실측).
   커버 색만 판 지면(#fff)으로 맞추고 힌트 레이어는 유지한다. */
.aff-panel .tbl-wrap,.card .tbl-wrap{border:0;border-radius:0;box-shadow:none}
.aff-panel .tbl-wrap>.tbl th:first-child,.aff-panel .tbl-wrap>.tbl td:first-child,
.card .tbl-wrap>.tbl th:first-child,.card .tbl-wrap>.tbl td:first-child{padding-left:0}
.aff-panel .tbl-wrap>.tbl th:last-child,.aff-panel .tbl-wrap>.tbl td:last-child,
.card .tbl-wrap>.tbl th:last-child,.card .tbl-wrap>.tbl td:last-child{padding-right:0}

/* ── 표 텍스트 계약 — **여기가 유일한 정의 자리다** ─────────────────────
   [Joseph 지적 2026-08-20] "테이블 텍스트들 크기가 다르다. 공용 컴포넌트기 때문에
   일괄적으로 해야 된다 — 그게 플랫폼이고 템플릿화·컴포넌트화의 목적이다."
   변형(.tbl · .dash-tbl · .lb · gv 표)이 저마다 크기를 다시 선언하면 한 곳을 고쳐도
   전부 반영되지 않는다. 그 순간 「공용 컴포넌트」는 이름만 남는다.
   그래서 크기는 **표 컨테이너가 한 번** 정하고 셀은 상속만 받는다.
   값을 바꿀 일이 있으면 이 블록만 고친다.

   **등록된 예외는 둘뿐이다**(예외는 여기 적혀야 예외다 — 안 적히면 드리프트다):
   ① 표 머리 `th` 12/600 — 한 단 아래로 내려 본문과 구분한다.
   ② 리더보드 순위·점수 `.lb-row .rk/.sc` 17/700 — 그 줄의 제품인 수치다
      (v3-spec §1 원칙 5 「수치가 주인공」). 이름·메타는 계약대로 13이다.
   그 밖의 자리에서 표 셀 크기를 다시 선언하면 craft §6 일관 결함으로 센다. */
.tbl,.dash-tbl,.lb,.gv-files{font-size:13px;line-height:1.6}
.tbl th,.tbl td,.dash-tbl th,.dash-tbl td{font-size:inherit}

.tbl{width:100%;border-collapse:collapse}
.tbl th,.tbl td{text-align:left;padding:0 12px}
.tbl th:first-child,.tbl td:first-child{padding-left:0}
.tbl th:last-child,.tbl td:last-child{padding-right:0}
.tbl th{height:40px;font-size:12px;font-weight:600;letter-spacing:.02em;color:var(--v3-ink3);   /* 머리만 한 단 아래 */
  background:var(--v3-faint);white-space:nowrap;border-bottom:1px solid var(--v3-line)}
/* 이미 카드인 판 안에서는 밴드를 벗는다(이중 판형 금지 — §3-5). */
.aff-panel .tbl-wrap .tbl th,.card .tbl-wrap .tbl th{background:transparent}
.aff-tblbox .dash-tbl th{background:#fff}
.tbl td{padding-top:12px;padding-bottom:12px;vertical-align:middle;white-space:nowrap;
  color:var(--v3-ink);border-bottom:1px solid var(--v3-line-soft)}
/* [admin-v8 · Joseph 지적 「테이블 텍스트 크기도 크다」] 표 본문 15 → 13.
   §6의 15px 하한은 그 조항이 스스로 밝힌 대로 **qr 손님 화면**(50~70대·모바일)의 값이고,
   관리자는 데스크톱에서 수십 행을 훑는 밀도 화면이다(design-system §12 aff 행 v4.3).
   행 등고 46.8 = 13 + 13 + 13×1.6 — **줄어드는 것은 글자이지 터치 타깃이 아니다**. */
.tbl td.aff-wrap{white-space:normal;min-width:200px}
.tbl tr:last-child td{border-bottom:0}
.tbl tfoot td{border-top:1px solid var(--v3-line-strong);border-bottom:0}
.tbl .rowh{font-weight:600;color:var(--v3-ink)}   /* 위계는 크기가 아니라 무게 */
.tbl .num,.tbl th.num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.tbl th.num,.tbl th.nw,.tbl th.fit{width:1%}
.tbl .hi{background:var(--v3-tint)}
.tbl th.hi{color:var(--v3-accent-ink);border-bottom-color:var(--v3-accent)}
.tbl td.muted,.tbl .muted{color:var(--v3-ink2)}
tr.int-off td,tr.err-done td{color:var(--v3-ink3)}

/* 셀 링크 — 잉크/무밑줄, 호버에서만 파랑(D4 교정) */
.tbl a{color:var(--v3-ink);font-weight:600;text-decoration:none;
  transition:color .1s ease}   /* §9-5 */
.tbl a:hover{color:var(--v3-accent-ink)}
.tbl a.btn{color:#fff}
.tbl a.btn.b2{color:var(--v3-ink)}
.tbl a.btn.ghost{color:var(--v3-ink2)}
.tbl a.hash{color:var(--v3-ink2);font-weight:500}

.tbl tr.rowlink{cursor:pointer;transition:background .2s ease}   /* §9-4 */
.tbl tr.rowlink:hover{background:var(--v3-faint)}
.tbl tr.rowlink:focus-visible{outline:2px solid var(--v3-accent);outline-offset:-2px;background:var(--v3-faint)}
.tbl.tbl-rich td{white-space:normal;vertical-align:top}
.tbl.tbl-rich td.nw,.tbl.tbl-rich td.num{white-space:nowrap}
/* [QA KolDaat 회차 P2] 다중행 표의 본문(랩 허용) 열 최소 폭 — 협폭에서 nw 열들이
   자연폭을 다 가져가면 본문 열이 min-content(한 어절 폭)로 붕괴해 8줄 랩이 났다
   (390 /settlements 조건표 실측). 최소 220을 깔면 표가 래퍼 폭을 넘고, 넘친 폭은
   `.tbl-wrap` 가로 스크롤 + 힌트가 받는다(§3-5 계약 — 페이지는 밀리지 않는다). */
.tbl.tbl-rich td:not(.nw):not(.num){min-width:220px}

/* 정렬 머리(aff.js 생성 버튼) */
.aff-sort{display:flex;align-items:center;gap:4px;width:100%;min-width:44px;height:40px;
  border:0;background:none;padding:0;cursor:pointer;
  font-family:inherit;font-size:inherit;font-weight:inherit;color:inherit}
.aff-sort:hover{color:var(--v3-ink2)}
.tbl th.num .aff-sort{justify-content:flex-end}
.aff-sort-i{flex:none;display:inline-block;vertical-align:middle;margin-left:4px;
  fill:none;stroke:var(--v3-line-strong);stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.aff-sort .aff-sort-i{display:block;margin-left:0}
.tbl th[data-sort]{cursor:pointer;user-select:none}
.tbl th[data-sort]:hover{color:var(--v3-ink2)}
.tbl th[data-sort]:focus-visible{outline:2px solid var(--v3-accent);outline-offset:-2px}
.tbl th[aria-sort] .aff-sort-i,
.tbl th[aria-sort="ascending"] .aff-sort-i,.tbl th[aria-sort="descending"] .aff-sort-i{stroke:var(--v3-ink2)}
.tbl th[aria-sort="ascending"],.tbl th[aria-sort="descending"]{color:var(--v3-ink)}

/* 표 위 툴바 */
.tbl-bar{display:flex;align-items:center;justify-content:space-between;
  gap:8px 16px;flex-wrap:wrap;margin-bottom:16px}
.tbl-bar .tb-act,.tbl-bar .tb-info{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}
.tbl-bar .tb-act{gap:12px}
.tbl-bar .tb-info{color:var(--v3-ink3);font-size:13px;line-height:1.6}
.tbl-bar .btn{flex:none;width:auto}

/* 셀 안 전환 폼(/dev) */
.tbl td .h2-act{flex-wrap:nowrap}
.tbl td .h2-act .aff-input{height:36px}

/* 가로 스크롤 힌트 — 4겹 배경(JS 0줄) */
.tbl-wrap,.aff-tblbox{
  --hint-face:#fff;
  background-color:var(--hint-face);
  background-image:
    linear-gradient(90deg,var(--hint-face) 40%,transparent),
    linear-gradient(270deg,var(--hint-face) 40%,transparent),
    radial-gradient(farthest-side at 0 50%,var(--v3-scroll-hint),transparent),
    radial-gradient(farthest-side at 100% 50%,var(--v3-scroll-hint),transparent);
  background-position:left center,right center,left center,right center;
  background-size:40px 100%,40px 100%,12px 100%,12px 100%;
  background-repeat:no-repeat;
  background-attachment:local,local,scroll,scroll}

/* 페이지네이션 */
.pager{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:16px}
.pager a,.pager span{display:inline-flex;align-items:center;justify-content:center;
  min-width:40px;height:40px;padding:0 12px;border-radius:var(--v3-r-ctl);
  font-size:13px;font-weight:600;color:var(--v3-ink2);font-variant-numeric:tabular-nums;
  transition:background .2s ease}   /* §9-4 */
.pager a:hover{background:var(--v3-soft)}
.pager .on,.pager .on:hover{background:var(--v3-tint);color:var(--v3-ink);font-weight:700}
.pager .off,.pager [disabled]{color:var(--v3-mute);pointer-events:none}
.pager .pg-gap{min-width:0;padding:0 4px;color:var(--v3-mute)}
.pager .pg-info{min-width:0;height:auto;margin-left:auto;padding:0;
  font-size:13px;font-weight:400;color:var(--v3-ink3)}

/* ── 8. 판 — 카드·패널·그리드·타일 ───────────────────────────────────── */
/* 판은 **살짝 비친다**(사용자 지시: 약간 투명한 글래스모피즘). 꽉 찬 흰 면 대신 흰빛을 .66만 두고
   뒤를 흐려(blur) 지면의 색이 배어 나오게 한다 — 채도를 조금 올려야 뿌옇게 죽지 않는다.
   헤어라인은 그대로다. 유리는 같은 층의 글까지 빨아들이므로 안쪽 칸이 뜰 자리는 따로 올린다. */
.card{background:rgba(255,255,255,.66);backdrop-filter:blur(14px) saturate(130%);
  -webkit-backdrop-filter:blur(14px) saturate(130%);
  border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);
  box-shadow:var(--v3-shadow-card);padding:20px 24px}
.aff-panel{background:rgba(255,255,255,.66);backdrop-filter:blur(14px) saturate(130%);
  -webkit-backdrop-filter:blur(14px) saturate(130%);
  border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);
  box-shadow:var(--v3-shadow-card);padding:24px}
.aff-panel-hd{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.aff-panel-hd .t{font-size:17px;font-weight:700;color:var(--v3-ink);letter-spacing:-0.01em}
.aff-panel-hd .r{display:flex;align-items:center;gap:8px}
.aff-panel-hd+*{margin-top:16px}
.aff-panel>*+*{margin-top:16px}
.aff-panel>.aff-kv+.aff-kv{margin-top:0}
.aff-card{background:#fff;border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);
  box-shadow:var(--v3-shadow-card);padding:28px}
.aff-card>*+*{margin-top:20px}
.aff-card .t{font-size:17px;font-weight:700;color:var(--v3-ink)}

.grid{display:grid;gap:12px}
.grid.c4{grid-template-columns:repeat(4,minmax(0,1fr))}
.grid.c3{grid-template-columns:repeat(3,minmax(0,1fr))}
.grid.c2{grid-template-columns:repeat(2,minmax(0,1fr))}
.col{display:flex;flex-direction:column;min-width:0}
.col>.tbl-wrap,.col>.card{flex:1}
.col>.card{display:flex;flex-direction:column}
.col>.card>.empty{margin:auto 0}
.grid.c2 .tbl-wrap .empty{padding:64px 20px}
.col>.card>form{width:100%}
/* [V3 등고 — Joseph 지시] 페어 판 등고: 같은 grid 행의 판은 **같은 높이**로 선다
   (grid stretch 기본값 복원). v2의 align-self:start(패널 확장 방지 — 상세 화면의 빈
   흰 판 회피)는 폐기 — 총괄 판정: 좌우 섹션 높이가 갈라지면 정렬이 무너져 신뢰를
   깎는다. 판을 flex 기둥으로 세워 빈 상태·짧은 콘텐츠는 판 안에서 세로 중앙을 잡고,
   데이터가 없어도 판이 주저앉지 않게 빈 상태에 최소 높이를 깐다(등고의 하한). */
.aff-main .section.grid>.aff-panel,.aff-main .section.grid>.card{display:flex;flex-direction:column}
.aff-panel>.empty,.card>.empty{margin-top:auto;margin-bottom:auto}
.aff-panel .empty,.card .empty,.tbl-wrap .empty{min-height:160px;
  display:flex;flex-direction:column;justify-content:center}

/* 지표 타일 */
.tile{background:#fff;border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);
  box-shadow:var(--v3-shadow-card);padding:20px;display:flex;flex-direction:column}
.tile .k{font-size:13px;font-weight:600;color:var(--v3-ink2);letter-spacing:0}
.tile .v{font-size:28px;font-weight:700;color:var(--v3-ink);letter-spacing:-0.01em;
  margin-top:8px;line-height:1.2;font-variant-numeric:tabular-nums}
.tile .v small{font-size:15px;font-weight:600;color:var(--v3-ink2);letter-spacing:0}
.tile .v.v-mono{font-family:var(--v3-mono);font-size:15px;letter-spacing:0;line-height:1.5}
.tile .d{font-size:12px;color:var(--v3-ink3);margin-top:8px}
.tile .t-act{margin-top:auto;padding-top:12px}
.tile .aff-cap{margin-top:8px}

/* 구판 대시보드 셀 어휘(잔존 대비 동형) */
.dash{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}
.dash-cell{background:#fff;border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);
  box-shadow:var(--v3-shadow-card);padding:20px}
.dash-cell .k{font-size:13px;font-weight:600;color:var(--v3-ink2)}
.dash-cell .v{font-size:28px;font-weight:700;color:var(--v3-ink);letter-spacing:-0.01em;
  font-variant-numeric:tabular-nums;margin-top:8px}
.dash-cell .v small{font-size:15px;font-weight:600;color:var(--v3-ink2)}
.dash-cell .sub{font-size:12px;color:var(--v3-ink3);margin-top:8px}
.dash-cell .aff-cap{margin-top:8px}
.aff-krow{display:flex;align-items:center;justify-content:space-between;gap:8px}

/* 미니 표 */
.dash-tbl{width:100%;border-collapse:collapse}
.dash-tbl th,.dash-tbl td{text-align:left;padding:12px 12px;border-bottom:1px solid var(--v3-line-soft)}
/* [QA r5 P3-4] 셀 글자를 13으로 내리며 패딩을 보정하지 않아 행 등고가 41 → 37.8로
   떨어졌다(.tbl 46.8과 9px 갈림). 등고 하한 46은 표 계열 공통이다 — 13+13+13×1.6. */
.dash-tbl th:first-child,.dash-tbl td:first-child{padding-left:0}
.dash-tbl th:last-child,.dash-tbl td:last-child{padding-right:0}
.dash-tbl th{font-size:12px;font-weight:600;color:var(--v3-ink3);white-space:nowrap}   /* 머리만 한 단 아래 */
.dash-tbl td{color:var(--v3-ink)}
.dash-tbl tr:last-child td{border-bottom:0}
.dash-tbl .rowh{font-weight:600;color:var(--v3-ink)}
.dash-tbl .num,.dash-tbl th.num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.aff-tblbox{max-height:560px;overflow:auto}
.aff-tblbox .dash-tbl th{position:sticky;top:0;z-index:1;background:#fff;box-shadow:0 1px 0 0 var(--v3-line-soft)}

/* 키·값 */
.kv{container-type:inline-size}
/* [admin-v8] KV는 라벨과 값이 다른 띠에 선다(v3-spec §3-6). 둘 다 15/600이면
   라벨 열을 훑을 수 없다 — 상세 화면에서 가장 큰 "관리자답지 않음"이었다.
   값에 measure를 주는 이유: /kpc 산출 기준의 200~300자 정의문이 830px로 흘렀다. */
.kv div{display:grid;grid-template-columns:minmax(0,160px) minmax(min-content,1fr);
  gap:16px;padding:12px 0;border-bottom:1px solid var(--v3-line-soft)}
.kv div:last-child{border-bottom:0}
@container (max-width:368px){.kv div{grid-template-columns:minmax(0,1fr);gap:4px}}
.kv span{font-size:13px;color:var(--v3-ink2);font-weight:600;min-width:0}
.kv strong{font-size:15px;line-height:1.6;font-weight:600;color:var(--v3-ink);text-align:left;
  min-width:0;max-width:var(--textw);font-variant-numeric:tabular-nums}
/* [QA r2 P2-D] 값 자리에 식별자 칩이 오면 칩 규격이 이겨야 한다 — 그러지 않으면
   그리드 stretch로 전폭 회색 밴드가 되고, 같은 값이 화면마다 두 모양으로 선다. */
.kv strong.hash,.aff-kv .v.hash{justify-self:start;width:max-content;max-width:100%}
/* [QA r4 P2-4] 식별자 칩은 어느 문맥에 놓여도 12/500이다(§3-7). 문맥 규칙
   (`.kv span` 13/600 · `.aff-copy .tx` 15)이 칩을 밟아 **한 값이 네 크기**로 섰고,
   /stores/1에서는 15px 전폭 회색 밴드가 됐다. 칩 규격이 문맥을 이기게 못박는다. */

.aff-kv{display:grid;grid-template-columns:minmax(0,160px) minmax(min-content,1fr);gap:16px;
  padding:12px 0;border-bottom:1px solid var(--v3-line-soft)}
.aff-kv:first-child{padding-top:0}
.aff-kv:last-child{padding-bottom:0;border-bottom:0}
.aff-kv .k{font-size:13px;font-weight:600;color:var(--v3-ink2)}
.aff-kv .v{font-size:15px;line-height:1.6;font-weight:600;color:var(--v3-ink);
  max-width:var(--textw);font-variant-numeric:tabular-nums}

/* ── 9. 배지·칩·상태 ─────────────────────────────────────────────────── */
.badge{display:inline-flex;align-items:center;font-size:12px;font-weight:600;letter-spacing:0;
  height:24px;line-height:1;padding:0 12px;border-radius:var(--r-pill);
  background:var(--v3-soft);color:var(--v3-ink2);border:0;white-space:nowrap}
.badge.blue{background:var(--v3-tint);color:var(--v3-accent-ink)}
.badge.ok{background:var(--v3-ok-tint);color:var(--v3-ok)}
.badge.warn{background:var(--v3-warn-tint);color:var(--v3-warn)}
.badge.off{background:var(--v3-soft);color:var(--v3-ink3)}
.badge.grade{font-variant-numeric:tabular-nums}   /* [QA r3 P3-1] 모노는 열 정렬이 뜻인 자리만(§3-7) */
.tag{display:inline-flex;align-items:center;font-size:12px;line-height:1;font-weight:600;
  height:24px;padding:0 12px;background:var(--v3-tint);color:var(--v3-accent-ink);border-radius:var(--r-pill)}
.tag.ok{background:var(--v3-ok-tint);color:var(--v3-ok)}
.tag.mute{background:var(--v3-soft);color:var(--v3-ink2)}
.tag.aff-warn{background:var(--v3-warn-tint);color:var(--v3-warn)}
/* [QA r2 P2-A] 식별자 칩은 한글을 품는다(HS-미영-001) — 모노를 씌우면 라틴만 모노로
   서고 한글은 폴백돼 한 토큰 안에서 서체가 갈린다. sans + tnum으로 세운다(자릿수
   정렬은 tabular-nums가 받는다). 모노는 diff·경로처럼 열 정렬이 뜻인 자리에만 남긴다. */
.hash{display:inline-block;font-family:var(--v3-sans);font-variant-numeric:tabular-nums;
  font-size:12px;font-weight:500;letter-spacing:0;
  padding:4px 8px;border-radius:8px;background:var(--v3-soft);color:var(--v3-ink2);white-space:nowrap}
a.hash:hover{color:var(--v3-accent-ink)}
.pill{display:inline-flex;align-items:center;gap:8px;height:28px;
  background:var(--v3-soft);color:var(--v3-ink2);font-size:12px;line-height:1;font-weight:600;
  padding:0 12px;border-radius:var(--r-pill);white-space:nowrap;cursor:default}
.aff-panel .pill,.card .pill{background:var(--v3-faint)}
.pill .pk{color:var(--v3-ink3);font-weight:600}
.pill .pv{color:var(--v3-ink);font-weight:700;font-variant-numeric:tabular-nums}
.pill .dot{width:8px;height:8px;border-radius:50%}
.chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.chip{display:inline-flex;align-items:center;gap:8px;font-size:12px;font-weight:600;
  background:var(--v3-tint);color:var(--v3-accent-ink);border-radius:var(--r-pill);padding:4px 8px 4px 12px}
.chip button{border:0;background:transparent;color:var(--v3-accent-ink);cursor:pointer;
  font-size:13px;line-height:1;padding:0 4px}
.rcpt-tools{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:8px}

.aff-st{display:inline-flex;align-items:center;gap:8px;font-size:13px;font-weight:600;color:var(--v3-ink)}
.aff-st .dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--v3-mute)}
.aff-st.ok .dot{background:var(--v3-ok)}
.aff-st.warn .dot{background:var(--v3-warn)}
.aff-st.out .dot{background:var(--v3-out)}

/* ── 10. 노티스·안내·빈 상태 ─────────────────────────────────────────── */
.notice{background:#fff;border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);padding:20px 24px}
.aff-panel .notice,.card .notice{background:var(--v3-faint);border-color:var(--v3-line-soft)}
.notice .tt{font-size:13px;font-weight:700;color:var(--v3-accent-ink)}
.notice .bd{font-size:15px;line-height:1.65;color:var(--v3-ink2);margin-top:8px}
.notice .acts{margin-top:16px}
.notice.aff-flash .tt{display:flex;align-items:center;gap:8px;font-size:15px;color:var(--v3-ink)}
.notice.aff-flash .tt .dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--v3-ok)}
.notice.aff-flash.err .tt .dot{background:var(--v3-out)}

.aff-msg{background:var(--v3-faint);border-radius:var(--v3-r-panel);padding:32px 24px;text-align:center}
.af-box .aff-msg,.main>.aff-main>.aff-msg{background:#fff;border:1px solid var(--v3-line)}
.main>.aff-main>.aff-msg{max-width:var(--textw);margin-inline:auto}
.aff-msg .tt{font-size:17px;font-weight:700;color:var(--v3-ink)}
.aff-msg .bd{font-size:15px;line-height:1.65;color:var(--v3-ink2);margin-top:8px}
.aff-msg .acts{margin-top:24px}

/* [QA r3 P2-2] 띠 뒤집기는 폐기한다. `aff_tsec_empty()`가 <strong>제목</strong> + 맨
   텍스트를 내므로 판을 제목 띠로 만들면 **보조문까지 굵어져** 위계가 사라졌다(판형이
   2종에서 3종이 됐다). 판은 캡션 띠로 되돌리고 제목만 올린다 — 대신 헬퍼가 보조문을
   <p>로 감싸고(layout.php), 한 줄짜리 빈 상태도 <strong>로 감싼다(뷰 5곳).
   **골격은 마크업이 지고 CSS는 띠만 준다.** */
.empty{text-align:center;color:var(--v3-ink3);padding:48px 20px;font-size:12px;line-height:1.6}
.empty strong{display:block;color:var(--v3-ink2);font-size:15px;font-weight:600;margin-bottom:8px}
.empty p{font-size:12px;font-weight:400;color:var(--v3-ink3);line-height:1.6;margin:0}
.aff-empty{padding:48px 24px;text-align:center}
.aff-empty .t{font-size:15px;font-weight:600;color:var(--v3-ink2)}
.aff-empty .s{font-size:12px;color:var(--v3-ink3);margin-top:8px}
/* [admin-v8] 각주는 캡션 띠다 — 12/ink3 + measure(v3-spec §2-2-1·§4).
   문안은 손대지 않는다(V3.1 카피 회차 소관) — 시각적 감량만 타이포가 진다. */
.card-note{font-size:12px;color:var(--v3-ink3);line-height:1.6;text-align:left;max-width:var(--textw)}
.card-note strong{color:var(--v3-ink);font-weight:600}
.card-note p{margin:0 0 8px}
.card-note p:last-child{margin-bottom:0}
.card-note ul,.card-note ol{margin:0 0 8px;padding-left:16px}
.card-note ul:last-child,.card-note ol:last-child{margin-bottom:0}
.card-note li{margin-bottom:4px}
.state-card{display:flex;flex-direction:column;align-items:flex-start;gap:12px}
.state-card .ic{width:44px;height:44px;border-radius:var(--v3-r-panel);background:var(--v3-tint);
  display:flex;align-items:center;justify-content:center;color:var(--v3-accent-ink)}
.state-card .ic svg{width:24px;height:24px}
.state-card h3{font-size:15px;font-weight:600}
.state-card p{font-size:12px;color:var(--v3-ink3);line-height:1.6}
.state-card ul{list-style:none;width:100%;margin-top:4px}
.state-card li{font-size:12px;color:var(--v3-ink3);padding:8px 0;border-top:1px solid var(--v3-line-soft);
  display:flex;gap:8px;align-items:center}
.state-card li::before{content:"";width:8px;height:8px;border-radius:var(--r-pill);background:var(--v3-accent);flex:0 0 auto}

/* ── 11. 특수 컴포넌트 ───────────────────────────────────────────────── */
/* 이상 플래그 행 */
.aff-flag{display:grid;grid-template-columns:1fr auto;gap:16px;align-items:center;
  padding:16px 0;border-bottom:1px solid var(--v3-line-soft)}
.aff-flag:last-child{border-bottom:0}
.aff-flag:first-child{padding-top:0}
.aff-flag .d{font-size:13px;line-height:1.6;color:var(--v3-ink2);margin-top:4px}
.aff-flag .d .ts{color:var(--v3-ink3);font-variant-numeric:tabular-nums}
.aff-flag .btn{flex:none}

/* 리더보드(인플루언서 상위) */
.lb{background:#fff;border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);
  box-shadow:var(--v3-shadow-card);overflow:hidden}
.lb-row{display:grid;grid-template-columns:48px 1fr auto;align-items:center;gap:12px;
  padding:16px 20px;border-bottom:1px solid var(--v3-line-soft)}
.lb-row:last-child{border-bottom:0}
.lb-row .rk{font-size:17px;font-weight:700;color:var(--v3-ink3);text-align:center;font-variant-numeric:tabular-nums}
.lb-row .nm{font-weight:600;color:var(--v3-ink)}   /* 표 계약 상속 */
.lb-row .sc{font-size:17px;font-weight:700;color:var(--v3-ink);font-variant-numeric:tabular-nums}
.lb-row .sc small{font-size:13px;font-weight:400;color:var(--v3-ink3)}
.lb-row.r1 .rk,.lb-row.r2 .rk,.lb-row.r3 .rk{color:var(--v3-accent-ink)}
.lb-row.r1{background:var(--v3-tint)}
.aff-top .lb-row.r1:has(~ .lb-row.r1),
.aff-top .lb-row.r1 ~ .lb-row.r1{background:transparent}
.aff-top .lb-row .nm{display:flex;flex-direction:column;justify-content:center;gap:4px;min-width:0}
.aff-top .lb-row .nm .n{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.aff-top .lb-row .ts{font-size:13px;font-weight:600;color:var(--v3-ink2);font-variant-numeric:tabular-nums}

/* 복사 블록 */
.aff-copy{background:var(--v3-faint);border-radius:var(--v3-r-ctl);padding:16px 20px;
  display:flex;flex-wrap:wrap;align-items:center;gap:12px 16px}
.aff-copy .tx{font-family:inherit;font-size:15px;line-height:1.7;color:var(--v3-ink);
  white-space:pre-wrap;word-break:break-all;flex:1 1 260px;min-width:0}
.aff-copy .acts{margin-top:0;flex:none}

/* 위험 동작 확인 */
.aff-danger{background:#fff;border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);padding:24px}
.aff-panel .aff-danger{background:var(--v3-faint);border-color:var(--v3-line-soft)}
.aff-danger>*+*{margin-top:16px}
.aff-danger .bd{font-size:15px;line-height:1.65;color:var(--v3-ink2)}
.aff-danger .aff-input{max-width:var(--v3-fw-xl)}

/* 보조 링크 */
.aff-link{display:inline-flex;align-items:center;min-height:44px;
  font-size:13px;font-weight:600;color:var(--v3-accent-ink)}
.aff-panel-hd .aff-link{margin:-12px 0}
.aff-main a:not([class]){padding-block:16px}
.aff-main .pager a:not([class]){padding-block:0}

/* 표 셀 메모·코드 */
.int-note{font-size:12px;color:var(--v3-ink3);max-width:220px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;display:block}
.cell-code{display:block;font-family:var(--v3-mono);font-size:12px;letter-spacing:0;   /* [QA r3 P3-3] 경로는 모노 — .gv-file-p와 같은 뜻·같은 서체 */
  line-height:1.6;color:var(--v3-ink2);overflow-wrap:anywhere;word-break:break-all}

/* 사이트맵 타일 */
.sm-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
.sm-tile{display:flex;flex-direction:column;gap:8px;min-width:0;
  background:#fff;border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);
  box-shadow:var(--v3-shadow-card);
  padding:20px;text-decoration:none;color:var(--v3-ink);
  transition:background .2s ease}   /* §9-4 */
.sm-tile:hover{background:var(--v3-faint)}
.sm-tile:focus-visible{outline:2px solid var(--v3-accent);outline-offset:2px}
.sm-hd{display:flex;align-items:center;gap:12px;min-width:0}
.sm-ic{flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;border-radius:var(--v3-r-ctl);background:var(--v3-soft);color:var(--v3-ink2);
  transition:background .2s ease,color .1s ease}   /* §9-4 · §9-5 */
.sm-ic svg{width:16px;height:16px}
.sm-tile:hover .sm-ic{background:var(--v3-tint);color:var(--v3-accent-ink)}
.sm-t{font-size:17px;font-weight:700;color:var(--v3-ink);line-height:1.3;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sm-d{font-size:12px;line-height:1.6;color:var(--v3-ink3)}
.sm-meta{display:flex;align-items:center;justify-content:space-between;
  gap:8px;flex-wrap:wrap;margin-top:auto;padding-top:8px}
.sm-views{font-size:13px;color:var(--v3-ink3);font-variant-numeric:tabular-nums;white-space:nowrap}

/* 스켈레톤(정적) */
.skl{background:var(--v3-soft);border-radius:var(--v3-r-ctl)}
.aff-skl-v{display:block;width:60%;height:28px;margin-top:8px}
.aff-skl-l{display:block;width:100%;height:20px}

/* 차트 소품·툴팁(관리자 /dev·/kpc 잔존 어휘) */
.legend{display:flex;gap:16px;font-size:12px;color:var(--v3-ink2);margin:8px 0 12px}
.legend .sw{display:inline-block;width:16px;height:4px;border-radius:2px;background:var(--v3-accent);vertical-align:3px;margin-right:8px}
.legend .sw.hi{background:var(--v3-accent)}
.legend .sw.band{height:12px;background:var(--v3-glow);vertical-align:-1px}
svg.chart text{font-family:inherit}
.sim-note{font-size:12px;color:var(--v3-ink3);margin-top:12px;line-height:1.6}
.go-flag{font-size:17px;font-weight:700;color:var(--v3-ink);display:inline-flex;align-items:center;gap:8px}
.go-flag::before{content:'';flex:none;width:8px;height:8px;border-radius:var(--r-pill);background:var(--v3-line-strong)}
.go-flag.go::before{background:var(--v3-ok)}
.go-flag.no::before{background:var(--v3-out)}
.tip{position:fixed;z-index:50;pointer-events:none;display:none;
  background:var(--v3-ink);color:#fff;font-size:12px;padding:8px 12px;
  border-radius:var(--v3-r-ctl);line-height:1.5;white-space:nowrap;box-shadow:var(--v3-shadow-float)}
.hbar-row{display:grid;grid-template-columns:128px 1fr 84px;gap:12px;align-items:center;padding:8px 0}
.hbar-name{font-size:13px;color:var(--v3-ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hbar-track{height:20px;position:relative}
.hbar-fill{position:absolute;left:0;top:4px;height:12px;border-radius:0 8px 8px 0;
  background:var(--v3-accent);min-width:4px;width:var(--w,0%)}
.hbar-val{font-size:12px;color:var(--v3-ink2);text-align:right;font-variant-numeric:tabular-nums}
.sim-layout{display:grid;grid-template-columns:320px 1fr;gap:12px}
.sim-out{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-bottom:12px}
.ms-list{margin-top:4px}
.ms-row{display:grid;grid-template-columns:96px 1fr 104px;gap:12px;align-items:start;
  padding:12px 0;border-bottom:1px solid var(--v3-line-soft)}
.ms-row:first-child{padding-top:4px}
.ms-row:last-child{border-bottom:0;padding-bottom:4px}
.ms-title{font-size:13px;color:var(--v3-ink)}
.ms-detail{font-size:12px;color:var(--v3-ink3);margin-top:4px;max-width:560px;line-height:1.55}
.ms-due{font-size:12px;color:var(--v3-ink3);text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.ms-row.doing .ms-title{font-weight:600}
.ms-row.done .ms-title,.ms-row.done .ms-detail,.ms-row.done .ms-due{color:var(--v3-ink3)}

/* ── 12. 드로어 ──────────────────────────────────────────────────────── */
.dr-mask{position:fixed;inset:0;background:var(--v3-scrim);opacity:0;pointer-events:none;
  transition:opacity .18s ease;z-index:200}   /* §9-18 */
.dr-mask.on{opacity:1;pointer-events:auto}
.drawer{position:fixed;top:0;right:0;height:100vh;width:640px;max-width:92vw;
  background:#fff;border-left:1px solid var(--v3-line);z-index:201;box-shadow:var(--v3-shadow-float);
  transform:translateX(100%);visibility:hidden;
  transition:transform .2s ease,visibility 0s .2s;   /* §9-17 */
  display:flex;flex-direction:column}
.drawer.on{transform:translateX(0);visibility:visible;transition:transform .2s ease}
.dr-head{position:relative;padding:16px 24px;border-bottom:1px solid var(--v3-line)}
.dr-title{font-size:17px;font-weight:700;line-height:1.45;word-break:keep-all;padding-right:56px;letter-spacing:-0.01em}
.dr-meta{font-size:12px;color:var(--v3-ink3);margin-top:8px}
.dr-tools{display:flex;gap:8px;align-items:center;margin-top:12px;flex-wrap:wrap}
.dr-tools button[disabled]{opacity:.4;cursor:default}
.dr-acts{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.dr-tools .dr-nav{margin-left:auto;display:flex;gap:4px}
.dr-hint{margin:0;font-size:12px;color:var(--v3-ink3)}
.dr-hint.warn{color:var(--v3-ink);font-weight:600}
.dr-close{position:absolute;top:12px;right:16px}
.dr-body{flex:1;overflow:auto;padding:0;background:#fff}
.dr-body pre.txt{font-family:inherit;font-size:13px;line-height:1.75;white-space:pre-wrap;
  word-break:keep-all;overflow-wrap:break-word;margin:0;padding:24px}
.dr-body iframe{width:100%;min-height:320px;border:0;display:block;background:#fff}
.dr-text{font-size:12px;color:var(--v3-ink3);line-height:1.6}
.dr-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;padding:16px 24px;
  border-bottom:1px solid var(--v3-line)}
.dr-stat{border:1px solid var(--v3-line-soft);border-radius:var(--v3-r-ctl);padding:12px 12px;min-width:0;
  background:var(--v3-faint)}
.dr-stat span{display:block;font-size:12px;color:var(--v3-ink3);margin-bottom:4px;white-space:nowrap}
.dr-stat b{display:block;font-size:15px;font-weight:600;letter-spacing:-0.01em;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;font-variant-numeric:tabular-nums}
.dr-sec{padding:16px 24px;border-bottom:1px solid var(--v3-line-soft)}
.dr-sec:last-child,.dr-sec.nb{border-bottom:0}
.dr-sec-label{font-size:12px;font-weight:600;letter-spacing:.05em;color:var(--v3-ink3);margin-bottom:8px}
.dr-sec .kv div{font-size:15px}
.dr-sec .tbl th,.dr-sec .tbl td{padding:8px 8px}
.dr-foot-meta{padding:12px 24px 20px;font-size:12px;color:var(--v3-ink3);line-height:1.7}
.dr-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.drawer.sec .dr-body{background:var(--v3-faint);padding:12px 16px 16px;display:flex;flex-direction:column;gap:12px}
.drawer.sec .dr-sec,.drawer.sec .dr-stats{background:#fff;border:1px solid var(--v3-line);
  border-radius:var(--v3-r-panel)}
.drawer.sec .dr-sec{padding:16px 16px}
.drawer.sec .dr-stats{padding:16px 16px}
.drawer.sec .dr-foot-meta{padding:0 4px 4px}

/* ── 13. 인증 화면 ───────────────────────────────────────────────────── */
.auth{display:flex;min-height:100vh}
.auth-brand{flex:0 0 44%;background:var(--v3-ink);color:#fff;
  display:flex;flex-direction:column;padding:48px}
.ab-logo{font-size:17px;font-weight:600;letter-spacing:-0.01em;display:flex;align-items:center;gap:12px}
.ab-logo svg,.ab-logo img{display:block}
.ab-logo .wm{color:#fff}
.ab-logo .wm .pdot{color:var(--v3-hi)}
.ab-mid{margin:auto 0;padding:40px 0}
/* [admin-v8] 톤다운(v3-spec §3-9) — 34px 슬로건 + 블루 강조어는 홈 히어로 문법이다.
   여기는 기관 담당자가 업무를 시작하러 들어오는 콘솔 진입 화면이다.
   판형·문안·다크 대비 실측값은 불변이고 무게만 낮춘다. */
.ab-title{font-size:24px;font-weight:700;color:#fff;letter-spacing:-0.02em;line-height:1.35}
/* 강조어는 흰 글자로 통일한다 — 다크 판 위 블루 강조어는 마케팅 히어로 문법이다
   (v3-spec §3-9 톤다운). 문안의 <em> 마크업은 그대로 두고 시각만 거둔다. */
.ab-title em{font-style:normal;color:inherit}
.ab-sub{margin-top:16px;font-size:13px;color:var(--v3-dk3);line-height:1.7;max-width:380px}
.ab-points{margin-top:28px;display:grid;gap:12px;font-size:13px;color:var(--v3-dk2)}
.ab-points div::before{content:'';display:inline-block;width:8px;height:8px;border-radius:4px;
  background:var(--v3-accent);margin-right:12px;vertical-align:2px}
.ab-foot{font-size:12px;color:var(--v3-dk4)}
.auth-form{flex:1;display:flex;align-items:center;justify-content:center;
  background:var(--v3-canvas);padding:48px 24px}
.af-box{width:380px;max-width:100%}
.af-box>*+*{margin-top:20px}
.af-box .fn{margin-top:24px}
.af-box h1,.af-box h2{font-size:22px;font-weight:700;letter-spacing:-0.01em;color:var(--v3-ink)}
.af-box .sub{color:var(--v3-ink2);font-size:13px;margin:8px 0 0;line-height:1.6}
.af-box h1+.sub,.af-box h2+.sub{margin-top:8px}
.af-box .field+.field,.af-box .field{margin-top:20px}
.af-box .btn:not(.sm){width:100%;height:48px;margin-top:24px}
.af-box .btn.sm{margin-top:16px}
.af-box :is(input[type="text"],input[type="password"]):not(.aff-input),
.af-box .aff-input{height:48px}
.af-note{margin-top:28px;padding-top:16px;border-top:1px solid var(--v3-line);
  font-size:13px;color:var(--v3-ink3);line-height:1.65}
.login-err{background:var(--v3-warn-tint);color:var(--v3-warn);font-size:13px;font-weight:600;
  border-radius:var(--v3-r-ctl);padding:12px 16px;margin:16px 0 0;line-height:1.6}

/* ── 14. 유틸리티 ────────────────────────────────────────────────────── */
.mb16{margin-bottom:16px}
/* [admin-v8] 폭 유틸 32종 중 29종을 지웠다 — 소스 전수 grep + 15화면 실렌더 DOM 대조
   이중 확인에서 사용처 0(admin-v6이 밟은 절차와 같다. admin-kit §8: 도달 경로 없는
   스타일은 남기지 않는다 — 남겨 두면 다음 사람이 그것을 근거로 사다리를 늘린다).
   살아남은 것은 /dev 다음 스텝 표의 w120 하나다. */
.w120{width:120px}

/* ── 15. 반응형 ──────────────────────────────────────────────────────── */
@media (min-width:901px) and (max-width:1100px){
  .aff-main .grid.c4{grid-template-columns:repeat(4,minmax(0,1fr))}
  /* [admin-v8] c3는 2열 상태를 갖지 않는다 — 3타일이 2+1로 꺾이면 우하 사분면이
     빈 판이 된다(design-system §3 `.stats`[v4.1] 선례 · /visits 실측). */
  .aff-main .grid.c3{grid-template-columns:repeat(3,minmax(0,1fr))}
}
@media (max-width:1100px){
  /* [QA V3-1차 P2] 사이드바는 232 고정(스펙 §3-1) — 킷 계보의 208 축폭이 푸터
     버튼 2개를 세로로 꺾었다(1100 실측). 좁아지는 것은 본문 패딩이 진다. */
  .aff-main{padding:24px 24px 56px}
  .tbl-rich th:first-child,.tbl-rich td:first-child{min-width:110px}
  .grid.c4{grid-template-columns:repeat(2,minmax(0,1fr))}
  .sm-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .sim-layout{grid-template-columns:288px 1fr}
  .dash{grid-template-columns:repeat(4,1fr)}
  .auth-brand{flex-basis:40%;padding:40px 36px}
}
@media (max-width:900px){
  .hide-900{display:none}
  .shell{flex-direction:column}
  .sidebar{position:sticky;top:0;z-index:100;width:auto;height:auto;flex:none;
    flex-direction:row;align-items:center;gap:4px;padding:8px 16px;flex-wrap:wrap;
    border-right:0;border-bottom:1px solid var(--v3-line)}
  .sb-logo{padding:0 12px 0 0;white-space:nowrap;min-height:44px}
  .sb-sec{display:none}
  .sb-secbody{display:contents}
  .sb-nav{display:flex;gap:4px;flex:1 1 100%;min-width:0;overflow-x:auto;overflow-y:visible;
    padding:4px 0;-webkit-overflow-scrolling:touch;
    background-color:var(--v3-rail);
    background-image:
      linear-gradient(90deg,var(--v3-rail) 40%,transparent),
      linear-gradient(270deg,var(--v3-rail) 40%,transparent),
      radial-gradient(farthest-side at 0 50%,var(--v3-scroll-hint),transparent),
      radial-gradient(farthest-side at 100% 50%,var(--v3-scroll-hint),transparent);
    background-position:left center,right center,left center,right center;
    background-size:32px 100%,32px 100%,10px 100%,10px 100%;
    background-repeat:no-repeat;
    background-attachment:local,local,scroll,scroll}
  .sb-nav a{white-space:nowrap;flex:none;min-height:44px;padding:0 16px;margin:0}
  .sb-foot{margin:0 0 0 auto;border:0;padding:0;white-space:nowrap;flex-shrink:1;min-width:0;
    display:flex;align-items:center;gap:8px;flex-wrap:wrap}
  .sb-user,.sb-role{display:inline;font-size:13px}
  .sb-acts{margin-top:0}
  .sb-acts .btn{flex:none}
  .sb-ver{margin-top:0;white-space:normal}
  .aff-main{padding:20px 20px 40px}
  .page-head .ph-act{position:static;margin-top:8px;min-height:0}
  .grid.c4,.grid.c2{grid-template-columns:repeat(2,minmax(0,1fr))}
  .aff-main .grid.c3{grid-template-columns:repeat(3,minmax(0,1fr))}
  .dash{grid-template-columns:1fr 1fr}
  .sim-layout{grid-template-columns:1fr}
  .sim-out{grid-template-columns:1fr 1fr}
  .form-row{grid-template-columns:1fr;gap:4px}
  .hbar-row{grid-template-columns:104px 1fr 76px}
  .ms-row{grid-template-columns:88px 1fr}
  .ms-due{grid-column:2;text-align:left;margin-top:4px}
  .aff-row{grid-template-columns:1fr;gap:8px}
  .aff-row>label{padding-top:0}
  .aff-tblbox{max-height:none}
  .aff-tblbox .dash-tbl th{position:static;box-shadow:none}
  .drawer{width:100%;max-width:100%;top:auto;bottom:0;height:92vh;
    border-left:0;border-top:1px solid var(--v3-line);
    border-radius:var(--v3-r-panel) var(--v3-r-panel) 0 0;transform:translateY(100%)}
  .drawer.on{transform:translateY(0)}
  .dr-stats{grid-template-columns:repeat(2,1fr)}
  .auth{flex-direction:column}
  .auth-brand{flex:none;padding:28px 24px}
  .ab-mid{margin:0;padding:20px 0 4px}
  .ab-points,.ab-foot{display:none}
  .auth-form{align-items:flex-start;padding:36px 24px}
}
@media (max-width:600px){
  .aff-main{padding:16px 16px 40px}
  /* [QA admin-v8 P1-1] c3의 3열 유지 규칙(≤900 · 특이도 0,2,1)을 이기려면
     여기도 같은 특이도여야 한다 — 미디어 쿼리는 특이도를 더하지 않는다.
     390에서 3열로 남아 스탯 값이 두 줄로 쪼개졌다(판형 파손). */
  .grid.c4,.grid.c2{grid-template-columns:minmax(0,1fr)}
  .aff-main .grid.c3{grid-template-columns:minmax(0,1fr)}
  .sm-grid{grid-template-columns:minmax(0,1fr)}
  .sim-out{grid-template-columns:1fr}
  .grid.c2 .tbl-wrap .empty{padding:48px 20px}
  .page-head .ph-act,.page-head:has(> .tbl-bar) .ph-act{position:static;display:inline-flex;margin-top:8px;min-height:0}
  .dr-tools,.dr-acts{flex-wrap:wrap}
  .hbar-row{grid-template-columns:88px 1fr 64px}
  .aff-kv{grid-template-columns:1fr;gap:4px}
  .aff-card{padding:24px}
  .auth-brand{padding:20px}
  .ab-mid{padding:16px 0 4px}
  .ab-title{font-size:22px}
  .auth-form{padding:24px 20px}
  .af-box{width:100%;max-width:380px}
  .aff-sec .t,.page-head h1{font-size:20px}
}
@media (max-width:599px){
  .dash{grid-template-columns:1fr}
  .sidebar{padding-left:16px;padding-right:16px}
}

/* ── 16. Git 관측(gv-*) — admin-v7 · 정본: v3-spec §3-10 ─────────────────
   /git 전용 신규 컴포넌트: 저장소 상태 카드(TAP au-mgmt 대응) · 2행 시각 ·
   파일 증감 목록 · diff 다크 코드블록. 색은 팔레트 참조·color-mix 파생만
   (신규 hex 0 — v3-spec §2-1 diff 행 등재). 상태는 V3 문법(도트 + g900 글자)로
   그린다 — TAP의 색 숫자(ok-fg 수치)는 V3 §2-1 상태 규율로 치환했다. */

/* 저장소 상태 카드 — 판 r12 헤어라인 + 메트릭 4칸(헤어라인 분할) + 경고 배너 */
.gv-status{background:#fff;border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);
  box-shadow:var(--v3-shadow-card);padding:20px 24px}
.gv-status-hd{display:flex;align-items:center;justify-content:space-between;gap:8px 12px;flex-wrap:wrap}
.gv-status-t{font-size:17px;font-weight:700;color:var(--v3-ink);letter-spacing:-0.01em;
  display:flex;align-items:center;gap:8px}
.gv-status-meta{font-size:13px;color:var(--v3-ink3);font-variant-numeric:tabular-nums}
.gv-metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin-top:16px}
.gv-mc{min-width:0;padding:4px 20px;border-left:1px solid var(--v3-line-soft);
  display:flex;flex-direction:column}
.gv-mc:first-child{border-left:0;padding-left:0}
.gv-mc-l{font-size:13px;font-weight:600;color:var(--v3-ink2)}
.gv-mc-v{display:flex;align-items:center;gap:8px;margin-top:8px;
  font-size:22px;font-weight:700;color:var(--v3-ink);letter-spacing:-0.01em;line-height:1.3;
  font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gv-mc-v small{font-size:15px;font-weight:600;color:var(--v3-ink2);letter-spacing:0}
.gv-mc-v .dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--v3-mute)}
.gv-mc-v.ok .dot{background:var(--v3-ok)}
.gv-mc-v.warn .dot{background:var(--v3-warn)}
.gv-mc-v.off{color:var(--v3-ink3);font-size:17px}
.gv-mc-v.mono{font-size:15px}
.gv-mc-v.mono .hash{padding:4px 8px}   /* 크기는 칩 계약이 진다 */
.gv-mc-s{font-size:13px;color:var(--v3-ink3);margin-top:8px;font-variant-numeric:tabular-nums;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gv-alert{margin-top:16px;padding:12px 16px;border-radius:var(--v3-r-ctl);
  font-size:13px;line-height:1.6;color:var(--v3-ink)}
.gv-alert.warn{background:var(--v3-warn-tint)}
.gv-alert.out{background:var(--v3-out-tint)}
.gv-alert+.gv-alert{margin-top:8px}

/* limit 셀렉트 GET 폼 — 툴바(h2-act) 안 한 줄. 등고 36 = .btn.sm */
.gv-limit-form{display:flex;align-items:center;gap:8px}
.gv-limit-form .aff-input{width:auto;height:36px;font-size:13px}
.gv-limit-form .btn{flex:none;width:auto}

/* 배포 대기 패널 소품 — main → 라이브 흐름 표기 · 상태 한 줄 */
.gv-flow{display:inline-flex;align-items:center;gap:8px;margin-left:12px;vertical-align:1px}
.gv-arrow{color:var(--v3-mute);font-size:13px;font-weight:400}
.gv-deploy-line{font-size:13px;line-height:1.6;color:var(--v3-ink2)}   /* 표 계약 값(컨테이너 없음 — 직접 선언) */
.gv-deploy-line strong{color:var(--v3-ink);font-weight:600;font-variant-numeric:tabular-nums}

/* 커밋 히스토리 — 상대+절대 2행 시각(TAP 동형) */
.gv-time{line-height:1.45}
.gv-t-rel{display:block;color:var(--v3-ink);font-variant-numeric:tabular-nums}   /* 표 계약 상속 */
.gv-t-abs{display:block;font-size:12px;color:var(--v3-ink3);margin-top:4px;font-variant-numeric:tabular-nums}
.gv-cell-msg{min-width:260px}

/* 드로어 — 커밋 본문·파일 증감 목록 */
.gv-body{margin:12px 0 0;padding:12px 16px;background:var(--v3-faint);border-radius:var(--v3-r-ctl);
  font-family:inherit;font-size:13px;line-height:1.7;color:var(--v3-ink2);
  white-space:pre-wrap;word-break:keep-all;overflow-wrap:break-word}
.gv-files{list-style:none;margin:0;padding:0}
.gv-file{display:flex;align-items:baseline;gap:12px;padding:8px 0;
  border-bottom:1px solid var(--v3-line-soft)}
.gv-file:last-child{border-bottom:0}
.gv-file-p{flex:1;min-width:0;font-family:var(--v3-mono);font-size:12px;color:var(--v3-ink);
  overflow-wrap:anywhere;word-break:break-all}
.gv-file-n{flex:none;font-size:12px;font-variant-numeric:tabular-nums;white-space:nowrap}
.gv-file-n .a{color:var(--v3-ink);font-weight:600}
.gv-file-n .d{color:var(--v3-ink2);font-weight:600}

/* diff 다크 코드블록 — TAP 조형의 토큰 재현. 다크 면 = g900, 글자색은 팔레트
   color-mix 파생(미지원 브라우저는 앞선 팔레트 원색 선언으로 강등 — 판독 유지). */
.gv-diff{background:var(--v3-ink);border-radius:var(--v3-r-panel);padding:16px;margin:0;
  overflow-x:auto;font-family:var(--v3-mono);font-size:12px;line-height:1.6;
  -webkit-font-smoothing:auto}
.gv-diff:focus-visible{outline:2px solid var(--v3-accent);outline-offset:2px}
.gv-dl{display:block;white-space:pre;color:var(--v3-line-strong)}
.gv-dl.add{color:var(--v3-ok);color:color-mix(in srgb,var(--v3-ok) 55%,#fff)}
.gv-dl.del{color:var(--v3-out);color:color-mix(in srgb,var(--v3-out) 60%,#fff)}
.gv-dl.hunk{color:var(--v3-accent);color:color-mix(in srgb,var(--v3-accent) 55%,#fff)}
.gv-dl.meta{color:var(--v3-mute);font-weight:600}
.gv-trunc{margin-top:12px;padding:12px 16px;border-radius:var(--v3-r-ctl);
  background:var(--v3-warn-tint);color:var(--v3-ink);font-size:13px;line-height:1.6}
.gv-trunc code{font-family:var(--v3-mono);font-size:12px}

@media (max-width:900px){
  .gv-metrics{grid-template-columns:repeat(2,minmax(0,1fr));row-gap:16px}
  .gv-mc{padding:0 16px}
  .gv-mc:nth-child(odd){border-left:0;padding-left:0}
}
@media (max-width:600px){
  .gv-metrics{grid-template-columns:minmax(0,1fr)}
  .gv-mc{border-left:0;padding:0}
  .gv-cell-msg{min-width:200px}
}

/* ── 18. 위키 관리(/wiki) — wk-* (wiki-manage.md 3절) ─────────────────────
   TAP Wiki Manage의 2페인 탐색기·문서 드로어 판형을 V3 어휘로 그린다.
   색·라운드·그림자·서체는 전부 --v3-* 역할 토큰 — 신규 발명 0.
   [admin-v8] 이 절만 자기 사다리(9.5·11·11.5·12.5·13.5·14 — 램프 밖 17선언)와
   radius 리터럴(5·7)을 갖고 있어 관리자 안에서 이 화면만 다른 시스템으로 섰다.
   v3-spec §2-2 정수 8단 램프와 --v3-r-* 로 전건 흡수했다(소수 font-size 금지). */
.wk-explorer{display:grid;grid-template-columns:224px minmax(0,1fr);background:#fff;
  border:1px solid var(--v3-line);border-radius:var(--v3-r-panel);
  box-shadow:var(--v3-shadow-card);overflow:hidden;min-height:420px}
.wk-cats{border-right:1px solid var(--v3-line-soft);background:var(--v3-rail);padding:12px 8px}
.wk-cats-title{margin:0;padding:8px 12px 8px;font-size:12px;font-weight:700;
  letter-spacing:.06em;color:var(--v3-ink3)}
.wk-cat{display:flex;align-items:center;justify-content:space-between;gap:8px;
  padding:8px 12px;border-radius:var(--v3-r-ctl);color:var(--v3-ink2);font-size:13px;
  text-decoration:none;transition:background .2s ease}   /* §9-4 */
.wk-cat:hover{background:#fff}
.wk-cat.on{background:#fff;color:var(--v3-ink);font-weight:700}
.wk-cat-n{font-size:12px;font-weight:700;color:var(--v3-ink3);background:var(--v3-soft);
  border-radius:var(--r-pill);padding:1px 8px;font-variant-numeric:tabular-nums}
.wk-cat.on .wk-cat-n{background:var(--v3-tint);color:var(--v3-accent-ink)}
.wk-main{display:flex;flex-direction:column;min-width:0}
.wk-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:12px 16px;border-bottom:1px solid var(--v3-line-soft);flex-wrap:wrap}
.wk-crumb{margin:0;font-size:13px;font-weight:700;color:var(--v3-ink)}
.wk-crumb-n{margin-left:8px;font-size:12px;font-weight:600;color:var(--v3-ink3);
  background:var(--v3-soft);border-radius:var(--r-pill);padding:4px 8px}
.wk-search{display:flex;align-items:center;gap:8px}
.wk-search input{height:36px;border:1px solid var(--v3-line-strong);border-radius:var(--v3-r-ctl);
  background:#fff;padding:0 12px;font-family:inherit;font-size:13px;color:var(--v3-ink);min-width:250px}
.wk-search input::placeholder{color:var(--v3-mute)}
.wk-search input:focus{outline:none;border-color:var(--v3-accent);box-shadow:0 0 0 3px var(--v3-glow)}
.wk-search .btn.sm{width:auto}
.wk-files{flex:1;padding:8px 8px 16px;overflow:auto;max-height:560px}
.wk-hint{margin:4px 8px 8px;font-size:12px;color:var(--v3-ink3)}
.wk-frow{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:12px 12px;border-radius:var(--v3-r-ctl);text-decoration:none;
  transition:background .2s ease}   /* §9-4 */
.wk-frow:hover{background:var(--v3-faint)}
.wk-fname{min-width:0;font-size:13px;font-weight:600;color:var(--v3-ink)}
.wk-fpath{display:block;font-size:12px;font-weight:400;color:var(--v3-ink3);
  font-family:var(--v3-mono);margin-top:1px}
.wk-snip{display:block;font-size:12px;font-weight:400;color:var(--v3-ink2);
  line-height:1.5;margin-top:4px}
.wk-fmeta{flex:none;font-size:12px;color:var(--v3-ink3);text-align:right;
  font-variant-numeric:tabular-nums;line-height:1.45}

/* 문서 드로어 — 킷 .drawer.sec 위에 폭·본문 전용만 더한다 */
.wk-drawer{width:760px}
.wk-dpath{display:block;font-size:12px;font-weight:400;color:var(--v3-ink3);
  font-family:var(--v3-mono);margin-top:4px}
.wk-dtools{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.wk-dact{display:inline-flex;gap:8px;margin-left:auto}
.wk-dtools .btn.ghost.sm{width:auto}
.wk-seg{display:inline-flex;background:var(--v3-soft);border-radius:var(--v3-r-ctl);padding:4px}
.wk-seg a{padding:4px 16px;border-radius:var(--v3-r-ctl);font-size:12px;font-weight:600;
  color:var(--v3-ink2);text-decoration:none}
.wk-seg a.on{background:#fff;color:var(--v3-ink)}
.wk-rawsrc{position:absolute;left:-9999px;top:0;height:1px;width:1px;opacity:0}
.wk-refs-lbl{margin:12px 0 8px;font-size:12px;font-weight:700;letter-spacing:.05em;color:var(--v3-ink3)}
.wk-refs-lbl:first-child{margin-top:0}
.wk-chips{margin:0;line-height:1.9}
.wk-chip{display:inline-flex;align-items:center;gap:4px;border:1px solid var(--v3-line);
  background:#fff;border-radius:var(--v3-r-ctl);padding:4px 8px;margin:0 4px 4px 0;
  font-size:12px;color:var(--v3-ink2);text-decoration:none;max-width:100%}
a.wk-chip:hover{color:var(--v3-accent-ink);border-color:var(--v3-accent)}
.wk-chip.bad{background:var(--v3-warn-tint);border-color:var(--v3-warn-tint)}
.wk-chip.ent small{font-size:12px;font-weight:700;letter-spacing:.04em;color:var(--v3-mute);text-transform:uppercase}
.wk-rawpre{white-space:pre-wrap;word-break:break-word;font-family:var(--v3-mono);
  font-size:12px;line-height:1.6;color:var(--v3-ink);margin:0}

/* 렌더된 마크다운 본문 — 관리자 안 미리보기 전용 타이포 */
.wk-doc{font-size:15px;line-height:1.7;color:var(--v3-ink)}
.wk-doc h1,.wk-doc h2,.wk-doc h3,.wk-doc h4{color:var(--v3-ink);line-height:1.3;margin:1.4em 0 .5em}
.wk-doc h1{font-size:20px;border-bottom:2px solid var(--v3-line-soft);padding-bottom:.3em}
.wk-doc h2{font-size:17px;border-bottom:1px solid var(--v3-line-soft);padding-bottom:.25em}
.wk-doc h3{font-size:15px}.wk-doc h4{font-size:13px}
.wk-doc p{margin:.7em 0}
.wk-doc ul,.wk-doc ol{margin:.6em 0;padding-left:1.5em}
.wk-doc li{margin:.25em 0}
.wk-doc a{color:var(--v3-accent-ink);text-decoration:none}
.wk-doc a:hover{text-decoration:underline}
.wk-doc code{background:var(--v3-soft);color:var(--v3-accent-ink);padding:1.5px 6px;
  border-radius:var(--v3-r-ctl);font-size:12px;font-family:var(--v3-mono)}
.wk-doc pre{background:var(--v3-ink);color:var(--v3-dk2);border-radius:var(--v3-r-ctl);
  padding:16px 16px;overflow:auto;margin:.8em 0}
.wk-doc pre code{background:transparent;color:inherit;padding:0;font-size:12px;line-height:1.6}
.wk-doc blockquote{margin:.8em 0;padding:.4em 1em;border-left:3px solid var(--v3-line-strong);
  color:var(--v3-ink2);background:var(--v3-faint);border-radius:0 var(--v3-r-ctl) var(--v3-r-ctl) 0}
.wk-doc hr{border:0;border-top:1px solid var(--v3-line-soft);margin:1.4em 0}
.wk-tblwrap{overflow-x:auto;margin:.9em 0}
.wk-doc table.wk-table{border-collapse:collapse;width:100%;font-size:13px}   /* 표 계약 */
.wk-doc table.wk-table th:first-child,.wk-doc table.wk-table td:first-child{white-space:nowrap}
.wk-doc table.wk-table th,.wk-doc table.wk-table td{border:1px solid var(--v3-line-soft);
  padding:8px 12px;text-align:left;vertical-align:top}
.wk-doc table.wk-table th{background:var(--v3-faint);font-weight:700;color:var(--v3-ink2)}

@media (max-width:900px){
  .wk-explorer{grid-template-columns:minmax(0,1fr)}
  .wk-cats{border-right:0;border-bottom:1px solid var(--v3-line-soft);
    display:flex;flex-wrap:wrap;gap:4px}
  .wk-cats-title{width:100%}
  .wk-search input{min-width:0;flex:1}
  .wk-bar{align-items:stretch;flex-direction:column}
  .wk-search{width:100%}
}

/* ── 19. 식별자 칩 계약 — 파일 맨 끝 ────────────────────────────────────
   [QA r5 P2-③] `.hash`는 어느 문맥에 놓여도 12/500이다(v3-spec §3-7).
   그런데 문맥 규칙과 **특이도가 같으면 순서가 이긴다** — `.aff-copy .tx`(0,2,0)가
   뒤에 있어 `/stores/{id}` 승인번호 칩이 15px 전폭 밴드로 섰다. 같은 화면 아래쪽
   `HS-호수식당-R1`은 정상 칩이라 **한 화면에서 같은 클래스가 두 모양**이었다.
   특이도로 이기려 하면 다음 문맥 규칙이 또 이긴다 — **자리로** 이긴다. */
.kv .hash,.aff-kv .hash,.aff-copy .hash,.aff-copy .tx.hash,.gv-mc-v .hash,
.tbl .hash,.dash-tbl .hash,.wk-doc .hash{font-size:12px;font-weight:500;line-height:1.5;
  width:max-content;max-width:100%}

/* ═══ 로그인(.login) — 포털의 문 ═══
   포털 안은 도구 화면(v3)이지만 문은 랜딩에서 들어오는 자리다. 그래서 랜딩 문법으로 선다:
   가운데 카드 하나, 위에 표식·제목, 카드 위쪽에 토글(전화번호|이메일), 아래 박스에 입력 하나.
   패널 둘을 위아래로 쌓던 것은 "둘 중 하나만 하면 된다"는 말을 화면이 못 하고 있었다. */
.login{min-height:calc(100vh - 64px);display:grid;place-items:center;padding:88px 0 48px}
.login-in{width:min(440px,100%);text-align:center}
.login-bar{position:fixed;inset:0 0 auto 0;height:64px;z-index:20;display:flex;align-items:center;padding:0 24px;
  background:rgba(250,249,248,.85);backdrop-filter:blur(12px)}
.login-wm{font-size:20px;font-weight:700;letter-spacing:-.015em;color:var(--g900);text-decoration:none}
.login-wm span{color:var(--blue)}
.login-eb{margin:0 0 16px;font-size:13px;font-weight:600;letter-spacing:.115em;color:var(--blue)}
.login-h{margin:0;font-size:clamp(26px,3.2vw,32px);font-weight:600;letter-spacing:-.035em;line-height:1.2;color:var(--g900)}
.login-cap{margin:12px 0 28px;font-size:15px;line-height:1.6;color:var(--g600)}
.login-card{text-align:left;background:rgba(255,255,255,.72);border-radius:var(--r-card);padding:24px;
  backdrop-filter:blur(16px) saturate(130%);-webkit-backdrop-filter:blur(16px) saturate(130%);
  box-shadow:0 0 4px rgba(42,38,34,.05),0 4px 16px rgba(42,38,34,.06),inset 0 0 0 1px var(--g200)}
/* 토글 — 둘 중 하나. 라디오처럼 한 칸만 켜지고, 켜진 칸이 흰 판으로 떠오른다(g100 홈 위) */
.login-toggle{display:grid;grid-template-columns:1fr 1fr;gap:4px;padding:4px;border-radius:var(--r-m);background:var(--g100);margin:0 0 20px}
.login-toggle button{height:40px;border:0;border-radius:calc(var(--r-m) - 4px);background:transparent;
  font-family:inherit;font-size:14.5px;font-weight:600;color:var(--g500);cursor:pointer;transition:background .18s,color .18s,box-shadow .18s}
.login-toggle button[aria-selected="true"]{background:#fff;color:var(--g900);box-shadow:0 1px 3px rgba(42,38,34,.08)}
.login-card .field{margin:0}
.shell .login-card label.fl,.login-card .fl{display:flex;align-items:center;gap:8px;margin:0 0 8px;font-size:13.5px;font-weight:600;
  line-height:20px;color:var(--g700)}
.req{color:var(--blue);font-size:14px;font-weight:700;font-style:normal;line-height:1;position:relative;top:1px}
.login-card .field{display:block;width:100%}
.login-card .field input.aff-input,.login-card input.aff-input{width:100%;max-width:none;min-width:0;height:56px;padding:0 16px;border:0;border-radius:var(--r-m);background:var(--g50);
  box-shadow:inset 0 0 0 1.5px var(--g200);font-family:inherit;font-size:16px;font-weight:500;color:var(--g900);box-sizing:border-box}
.login-card .aff-input:focus{outline:0;background:#fff;box-shadow:inset 0 0 0 2px var(--blue)}
.login-card .aff-input::placeholder{color:var(--g400);font-weight:400}
.login-card .aff-acts{margin-top:16px}
.login-card .aff-acts .btn{width:100%;height:52px;border-radius:var(--r-pill);font-size:16px;font-weight:600;
  background:var(--blue)}
.login-card .aff-acts /* 호버는 **마우스가 있는 화면에서만**. 터치에서는 누른 뒤에도 배경이 남아 「로그아웃 눌렀더니 뒤에 배경이 생긴다」로 보였다(사용자 지적) */
@media(hover:hover){.btn:hover{background:var(--blue-hover)}}
.login-card .aff-panel{border:0;padding:0;box-shadow:none;background:transparent}
.login-card .aff-panel-hd{margin-bottom:12px}
.login-card .aff-hint{margin:12px 0 0;font-size:13px;color:var(--g500)}
.login-foot{margin:20px 0 0;font-size:13px;color:var(--g500)}
.login-foot a{color:var(--g700);font-weight:600;text-decoration:none}
.login-foot a:hover{color:var(--g900)}
.login .aff-flash{text-align:left;margin:0 0 16px}
/* 가입 — 로그인과 같은 카드 안에 선다. 고르는 칸(참여 유형)은 위 토글과 같은 조형을 쓴다. */
.login-step{margin:0 0 16px;font-size:14.5px;line-height:1.5;color:var(--g600)}
.login-card .field + .field{margin-top:20px}
.login-seg{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.login-seg label{display:flex;align-items:center;justify-content:center;height:48px;border-radius:var(--r-m);background:#fff;
  box-shadow:inset 0 0 0 1.5px var(--g200);font-size:15px;font-weight:600;color:var(--g500);cursor:pointer;
  transition:box-shadow .18s,color .18s,background .18s}
.login-seg label:hover{box-shadow:inset 0 0 0 1.5px var(--g300);color:var(--g700)}
.login-seg input{position:absolute;opacity:0;width:0;height:0}
.login-seg label:has(input:checked){background:var(--blue-weak);color:var(--blue-deep);box-shadow:inset 0 0 0 2px var(--blue)}
.login-seg label:has(input:focus-visible){box-shadow:inset 0 0 0 2px var(--blue),0 0 0 3px var(--blue-weak)}
.login-agree{display:grid;gap:12px}
.login-agree label{display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:12px;align-items:center;cursor:pointer}
.login-agree .doc{flex:none;font-size:12.5px;font-weight:600;color:var(--g500);text-decoration:underline;
  text-underline-offset:2px;white-space:nowrap}
.login-agree .doc:hover{color:var(--g900)}
/* 동의 체크 — 기본 모양은 `appearance:none`만 강제하고(포털 시트가 네이티브 체크를 되살린다),
   **색과 테두리는 강제하지 않는다.** 둘 다 `!important`면 기본과 선택 상태가 서로를 못 이겨
   눌러도 흰 칸으로 남았다(실측). 강제는 선택 상태 한 곳에만 둔다. */
.login-agree input[type="checkbox"]{
  appearance:none !important;-webkit-appearance:none !important;
  width:20px;height:20px;margin:0;flex:0 0 auto;border:0;border-radius:8px;
  background-color:#fff;background-image:none;
  box-shadow:inset 0 0 0 1.5px var(--g300);
  cursor:pointer;position:relative;transition:background-color .18s,box-shadow .18s}
.login-agree input[type="checkbox"]:checked{
  background-color:var(--blue) !important;box-shadow:none !important;
  /* 체크 표시는 끝이 둥근 획 하나 — 각진 기본 체크가 딱딱했다(사용자). 상자는 네모 그대로 둔다 */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none'%3E%3Cpath d='M5.5 10.5l3 3 6-6.5' stroke='white' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") !important;
  background-size:20px 20px;background-repeat:no-repeat;background-position:center}
.login-agree input[type="checkbox"]:focus-visible{
  outline:0;box-shadow:inset 0 0 0 2px var(--blue),0 0 0 3px var(--blue-weak) !important}
.login-agree span{font-size:14px;line-height:1.45;color:var(--g700)}

.login-agree .req{margin-left:4px}
/* 하단 — 회원가입 · 운영 로그인. 「회원가입」은 다른 페이지가 아니라 위 전화번호 칸을 가리킨다 */
.as-link{border:0;background:none;padding:0;font-family:inherit;font-size:13px;font-weight:600;color:var(--g700);cursor:pointer}
.as-link:hover{color:var(--g900)}
.login-back{margin:0 0 16px}
.login-back button{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;
  margin-left:-8px;border:0;border-radius:50%;background:none;color:var(--g500);cursor:pointer;transition:background .18s,color .18s}
.login-back button:hover{background:var(--g100);color:var(--g900)}
.login-back svg{width:20px;height:20px}
.login-foot{display:flex;align-items:center;justify-content:center;gap:12px}
.login-foot .bar{width:1px;height:12px;background:var(--g300)}
.login-foot a.as-link{text-decoration:none}
/* 표시 이름 도움말 — 물어본 사람에게만. 늘 떠 있으면 폼이 길어지고, 없으면 무엇을 적는지 모른다 */
.fl-help{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;
  position:relative;top:-1px;flex:none;
  border:1px solid var(--g400);border-radius:50%;background:none;color:var(--g500);
  font-family:inherit;font-size:9.5px;font-weight:700;line-height:1;cursor:pointer;transition:border-color .18s,color .18s}
.fl-help:hover{border-color:var(--g600);color:var(--g900)}
.fl-tip{margin:0 0 8px;padding:12px 12px;border-radius:var(--r-s);background:var(--g100);
  font-size:13px;line-height:1.5;color:var(--g700)}
/* 「다시 추천」 — 라벨 줄 오른쪽 끝. 상자를 두르지 않는다(입력 옆에 두면 값처럼 보인다) */
.fl-sug{margin-left:auto;display:inline-flex;align-items:center;gap:4px;padding:0;border:0;background:none;
  font-family:inherit;font-size:13px;font-weight:700;color:var(--g600);cursor:pointer;transition:color .18s}
.fl-sug svg{width:16px;height:16px}
.fl-sug:hover{color:var(--g900)}
/* 폼 오류 — 말풍선도 문구도 두지 않는다(사용자 지시). **빈 칸을 강조**하는 것으로 끝낸다 */
.login-card .invalid .aff-input,.login-card .aff-input.invalid{box-shadow:inset 0 0 0 2px var(--blue) !important}
.login-agree label.invalid input[type="checkbox"]{box-shadow:inset 0 0 0 2px var(--blue) !important}
.login-seg.invalid label{box-shadow:inset 0 0 0 1.5px var(--blue) !important}

/* ═══ 사이트맵 푸터(.sf) — `SiteFooter.svelte`가 쓰는 규칙. site.css와 같은 판이다 ═══
   공용 컴포넌트라 **쓰는 시트마다** 있어야 한다. 한쪽에만 두면 다른 쪽에서 껍데기만 그려진다. */
.sf{background:var(--g900);color:#fff}
.sf-in{max-width:1176px;margin:0 auto;padding:56px 24px 40px}
.sf-grid{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:32px}
.sf-col{display:flex;flex-direction:column;align-items:flex-start;gap:10px;min-width:0}
.sf-h{margin:0 0 4px;font-size:14px;font-weight:700;letter-spacing:-.01em;color:#fff}
.sf-col a{font-size:14px;font-weight:400;line-height:20px;color:rgba(255,255,255,.62);text-decoration:none}
/* 누를 수 없는 줄 — 손님 쿠폰 화면은 매장 QR로만 열린다. 링크와 같은 자리에 서되 색과 커서로 「여기는 길이 아니다」를 말한다 */
.sf-off{display:block;font-size:14px;font-weight:400;line-height:20px;color:rgba(255,255,255,.34);cursor:default}
.sf-col a:hover{color:#fff}
.sf-n{margin:2px 0 0;font-size:12px;line-height:18px;color:rgba(255,255,255,.38)}
.sf-bot{max-width:1176px;margin:0 auto;padding:20px 24px 40px;
  font-size:12.5px;line-height:1.7;color:rgba(255,255,255,.45);
  display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:8px 20px}
/* 법적 고지 — 사이트맵 칸이 아니라 바닥 줄에 둔다(어느 페이지에서나 같은 자리) */
.sf-legal{display:flex;gap:18px}
.sf-legal a{color:rgba(255,255,255,.62);text-decoration:none;transition:color .15s ease}
.sf-legal a:hover{color:#fff}
@media(max-width:1000px){.sf-grid{grid-template-columns:repeat(3,minmax(0,1fr));gap:28px 24px}}
@media(max-width:620px){.sf-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .sf-in{padding:40px 20px 28px}.sf-bot{padding:16px 20px 32px}}

/* 모바일 상자 자(≤599) — 랜딩·캠페인과 같은 값(카드 20/18 · 라운드 14). 로그인 카드가 대상이다. */
@media(max-width:599px){.login-card{padding:20px 18px;border-radius:14px}.card,.aff-panel,.notice{padding:20px 18px;border-radius:14px}}
