/* yjinai UI 표준 v3 공용 토큰·컴포넌트 (2026-10-17). 정본: home 리포 public/ui/v3.css, 라이브 https://yjinai.com/ui/v3.css, 문서 https://yjinai.com/ui/
   각 서비스는 이 파일을 public/ui.css로 복사해 HTML <link>로 부른다. 동작이 필요한 컴포넌트(시트·탭·토스트·공유)는 ui.js 하나를 defer로 붙인다.
   v2 하위 호환: v2 클래스(.btn .btn-soft .fixed-bottom .seg .field .chips .card .num .skel .head .empty .sr)와 변수 이름은 그대로 동작한다.
   새 컴포넌트는 서비스 CSS와 이름이 겹치지 않게 ui- 접두사를 쓴다. v2.css는 이 파일의 복사본이다(고치면 cp v3.css v2.css). 다크 모드 없음. */

:root{
  /* 색: 브랜드 하나 + 회색 5단계 + 상태 3색. 글자 색은 모두 흰 바탕 대비 4.5:1 이상. */
  --brand:#1b64da;--brand-dark:#154fae;--brand-bg:#e8f0fd;
  --ink:#191f28;
  --g1:#f2f4f6;--g2:#e5e8eb;--g3:#b0b8c1;--g4:#6b7684;--g5:#4e5968; /* g3은 장식·비활성 테두리 전용(글자 금지) */
  --ok:#0b7a41;--ok-bg:#e6f4ec;
  --warn:#b25d00;--warn-strong:#8f4b00;--warn-bg:#fff4e5;
  --bad:#d92d20;--bad-strong:#b42318;--bad-bg:#fdecea;
  --focus:#1b64da;
  /* v2 이름(별칭) */
  --sub:var(--g5);--faint:var(--g4);--line:var(--g2);--bg-alt:var(--g1);

  /* 글자 크기: 12 보조 · 14 메타 · 16 본문 · 17 카드 제목 · 22 머리 문장 · 26 큰 숫자 */
  --fs-1:12px;--fs-2:14px;--fs-3:16px;--fs-4:17px;--fs-5:22px;--fs-6:26px;
  /* 간격: 4의 배수 */
  --sp-1:4px;--sp-2:8px;--sp-3:12px;--sp-4:16px;--sp-5:20px;--sp-6:24px;--sp-7:32px;--sp-8:40px;
  --gutter:20px;
  /* 둥글기 */
  --r-s:8px;--r-m:12px;--r-l:16px;--r-full:999px;
  --radius:var(--r-l);--radius-s:var(--r-m);
  /* 그림자: 떠 있는 것(토스트·시트)만. 그림자 애니메이션 금지. */
  --sh-1:0 1px 3px rgba(0,0,0,.08);--sh-2:0 8px 24px rgba(0,0,0,.14);
  /* 모션: 짧게. prefers-reduced-motion이면 꺼진다. */
  --dur-1:120ms;--dur-2:200ms;--ease:cubic-bezier(.2,.8,.2,1);
  /* 터치 최소 크기 */
  --touch:44px;
}

*{box-sizing:border-box}
html{font-size:16px;-webkit-text-size-adjust:100%}
body{margin:0;background:#fff;color:var(--ink);font-family:system-ui,sans-serif;font-size:var(--fs-3);line-height:1.5;word-break:keep-all;-webkit-font-smoothing:antialiased}
a{color:var(--brand)}
button,input,select,textarea{font-family:inherit;font-size:inherit}
:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* 페이지 틀: 머리글 · 본문 · 바닥글 */
.ui-top{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-3);min-height:56px;padding:0 var(--gutter);max-width:1440px;margin:0 auto}
.ui-top .logo{font-size:20px;font-weight:800;letter-spacing:-0.03em;color:var(--ink);text-decoration:none}
.ui-top a:not(.logo){display:inline-flex;align-items:center;min-height:var(--touch);font-size:var(--fs-2);color:var(--g5);text-decoration:none}
.ui-page{max-width:1440px;margin:0 auto;padding:0 var(--gutter) 120px}
.ui-foot{max-width:1440px;margin:0 auto;padding:var(--sp-6) var(--gutter) var(--sp-8);color:var(--g4);font-size:13px;line-height:1.6}
.ui-foot p{margin:0 0 var(--sp-2)}
.ui-foot a{color:var(--g5)}

/* 버튼: 화면에 큰 버튼(.btn)은 하나. 보조는 .btn-soft, 글자만은 .btn-plain, 작은 크기는 .btn-sm */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--sp-2);width:100%;min-height:56px;padding:0 20px;border:0;border-radius:14px;background:var(--brand);color:#fff;font-size:17px;font-weight:700;cursor:pointer;text-decoration:none;transition:background-color var(--dur-1)}
.btn:active{background:var(--brand-dark)}
.btn[disabled],.btn[aria-disabled="true"]{opacity:.6;cursor:default;pointer-events:none}
.btn-soft{background:var(--g1);color:var(--ink)}
.btn-soft:active{background:var(--g2)}
.btn-plain{width:auto;min-height:var(--touch);padding:0 var(--sp-3);background:none;color:var(--brand);font-size:var(--fs-3);font-weight:600}
.btn-plain:active{background:var(--brand-bg)}
.btn-sm{width:auto;min-height:var(--touch);padding:0 var(--sp-4);border-radius:var(--r-m);font-size:15px}
.btn svg{width:20px;height:20px;flex:none}
@media (hover:hover){.btn:hover{background:var(--brand-dark)}.btn-soft:hover{background:var(--g2)}.btn-plain:hover{background:var(--brand-bg)}}

/* 하단 고정 바(모바일). 본문(.ui-page)에 padding-bottom 120px. 720px 이상에서는 제자리에 놓인다. 블러 없음(폰 레이아웃 비용). */
.fixed-bottom{position:fixed;left:0;right:0;bottom:0;z-index:20;padding:10px var(--gutter) calc(10px + env(safe-area-inset-bottom));background:#fff;border-top:1px solid var(--line)}

/* 세그먼트(둘~넷 중 하나, 라디오) */
.seg{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;background:var(--g1);border-radius:14px;padding:4px;border:0;margin:0;min-width:0}
.seg legend{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.seg label{display:flex;align-items:center;justify-content:center;min-height:var(--touch);border-radius:11px;font-size:16px;font-weight:600;color:var(--sub);cursor:pointer;position:relative}
.seg label:has(input:checked){background:#fff;color:var(--ink);box-shadow:var(--sh-1)}
.seg label:has(input:focus-visible){outline:3px solid var(--focus);outline-offset:1px}
.seg input{position:absolute;opacity:0;width:1px;height:1px}

/* 입력·선택(.field 라벨 안에 input/select/textarea), 체크(.ui-check) */
.field{display:flex;flex-direction:column;gap:4px;font-size:13px;font-weight:600;color:var(--faint)}
.field input,.field select,.field textarea{min-height:52px;font-size:17px;font-weight:600;padding:0 14px;border:1.5px solid var(--line);border-radius:12px;color:var(--ink);background:#fff;width:100%}
.field textarea{padding:12px 14px;min-height:104px;font-weight:400;line-height:1.5;resize:vertical}
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--brand);outline:0;box-shadow:0 0 0 3px var(--brand-bg)}
.field [aria-invalid="true"]{border-color:var(--bad)}
.field .hint{font-weight:400;color:var(--g4)}
.field .msg{font-weight:600;color:var(--bad-strong)}
.ui-check{display:flex;align-items:center;gap:10px;min-height:var(--touch);font-size:var(--fs-3);color:var(--ink);cursor:pointer}
.ui-check input{width:22px;height:22px;margin:0;flex:none;accent-color:var(--brand)}

/* 칩 줄: 한 줄 가로 스크롤, 두 줄로 접지 않는다. button(aria-pressed) 또는 a(aria-current) */
.chips{display:flex;gap:8px;overflow-x:auto;padding:4px var(--gutter) 12px;margin:0 calc(-1 * var(--gutter));scrollbar-width:none}
.chips::-webkit-scrollbar{display:none}
.chips button,.chips a{flex:0 0 auto;display:inline-flex;align-items:center;min-height:var(--touch);padding:0 14px;border:1px solid var(--line);border-radius:20px;background:#fff;font-size:14px;font-weight:600;color:var(--sub);cursor:pointer;text-decoration:none;white-space:nowrap}
.chips button[aria-pressed="true"],.chips a[aria-current]{border-color:var(--ink);background:var(--ink);color:#fff}

/* 카드: 카드 전체가 링크, 오른쪽 .num 큰 숫자, 왼쪽 아이콘은 .card-ico + .ico 하나(24~40px, 장식 그라데이션 금지). 여러 장은 .ui-grid로 감싼다 */
.ui-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:10px}
.card{position:relative;display:grid;grid-template-columns:1fr auto;gap:4px 12px;align-items:center;padding:16px;border-radius:var(--radius);background:#fff;border:1px solid var(--line);text-decoration:none;color:inherit}
.card:active{background:var(--g1)}
@media (hover:hover){a.card:hover{border-color:var(--g3)}}
.card h2,.card h3{margin:0;font-size:17px;font-weight:700;grid-column:1}
.card .meta{margin:0;color:var(--sub);font-size:14px;grid-column:1}
.card .num{margin:0;grid-column:2;grid-row:1/span 3;text-align:right;font-weight:800;font-variant-numeric:tabular-nums}
.card .num strong{display:block;font-size:26px;line-height:1.1}
.card-ico{padding-left:72px}
.card-ico>.ico{position:absolute;left:16px;top:50%;margin-top:-20px}
.ico{display:inline-flex;align-items:center;justify-content:center;flex:none;width:40px;height:40px;border-radius:var(--r-m);background:var(--brand-bg);color:var(--brand);font-size:22px;line-height:1}
.ico svg{width:22px;height:22px}

/* 목록 행: 한 줄에 하나, 행 전체가 눌린다. 끝 값은 .end */
.ui-list{list-style:none;margin:0;padding:0}
.ui-list>li>a,.ui-list>li>.item{display:flex;align-items:center;gap:var(--sp-3);min-height:56px;padding:var(--sp-2) 0;border-bottom:1px solid var(--line);color:var(--ink);text-decoration:none;font-size:var(--fs-3)}
.ui-list>li>a:active{background:var(--g1)}
.ui-list .end{margin-left:auto;font-weight:700;font-variant-numeric:tabular-nums;white-space:nowrap}
.ui-list .sub{display:block;font-size:13px;color:var(--g4)}

/* 탭: role=tablist 안의 button[role=tab](ui.js가 패널 전환) 또는 a[aria-current=page](페이지 이동) */
.ui-tabs{display:flex;gap:var(--sp-1);overflow-x:auto;border-bottom:1px solid var(--line);scrollbar-width:none}
.ui-tabs::-webkit-scrollbar{display:none}
.ui-tabs>button,.ui-tabs>a{flex:0 0 auto;min-height:48px;padding:0 var(--sp-3);border:0;border-bottom:2px solid transparent;margin-bottom:-1px;background:none;color:var(--g4);font-size:var(--fs-3);font-weight:700;cursor:pointer;text-decoration:none;display:inline-flex;align-items:center}
.ui-tabs>[aria-selected="true"],.ui-tabs>[aria-current="page"]{color:var(--ink);border-bottom-color:var(--ink)}

/* 배지: 카드·행 안의 짧은 상태 한 단어 */
.ui-badge{display:inline-flex;align-items:center;height:22px;padding:0 6px;border-radius:6px;background:var(--g1);color:var(--g5);font-size:var(--fs-1);font-weight:700;vertical-align:middle;white-space:nowrap}
.ui-badge.brand{background:var(--brand-bg);color:var(--brand)}
.ui-badge.ok{background:var(--ok-bg);color:var(--ok)}
.ui-badge.warn{background:var(--warn-bg);color:var(--warn-strong)}
.ui-badge.bad{background:var(--bad-bg);color:var(--bad-strong)}

/* 결과 머리 문장 */
.head{margin:16px 0 4px;font-size:22px;font-weight:800;letter-spacing:-0.02em;line-height:1.3}
.head b{color:var(--brand)}

/* 스켈레톤: 스피너 대신 자리 모양. HTML에 정적으로 넣는다 */
.skel .card{pointer-events:none;border-color:transparent;background:var(--g1)}
.skel .card *{visibility:hidden}
.skel-line{display:block;height:14px;margin:6px 0;border-radius:6px;background:var(--g1)}
.skel .card,.skel-line{animation:ui-pulse 1.4s ease-in-out infinite}
@keyframes ui-pulse{50%{opacity:.55}}

/* 빈 상태·오류 상태: 제목 한 줄 + 이유 한 줄 + 버튼 하나 */
.empty,.ui-error{padding:40px 16px;text-align:center;color:var(--sub);font-size:16px}
.empty b,.ui-error b{display:block;color:var(--ink);font-size:18px;margin-bottom:6px}
.ui-error b{color:var(--bad-strong)}
.empty .btn,.ui-error .btn{margin-top:var(--sp-4)}

/* 출처 줄: 결과 아래 한 줄 */
.ui-src{margin:var(--sp-5) 0 0;font-size:13px;color:var(--g4)}
.ui-src a{color:var(--g5)}

/* 광고 자리: 화면마다 정해 둔 자리(결과 아래)에서만 쓴다. 광고 코드가 없으면 숨김(:empty, 태그 안에 공백 없이). 있으면 높이 고정(--ad-h)으로 레이아웃이 흔들리지 않고, 미채움이면 광고만 숨겨 자리는 유지 */
.ui-ad{position:relative;height:var(--ad-h,100px);margin:var(--sp-5) 0;overflow:hidden;text-align:center}
.ui-ad:empty{display:none}
.ui-ad::before{content:"광고";position:absolute;top:0;left:0;font-size:11px;color:var(--g4)}
.ui-ad ins[data-ad-status="unfilled"]{display:none!important}

/* 토스트: ui.toast("문구") 또는 data-toast="문구". 하단 고정 바 위에 뜬다 */
.ui-toast{position:fixed;left:50%;bottom:calc(96px + env(safe-area-inset-bottom));z-index:40;max-width:calc(100% - 2 * var(--gutter));padding:12px 18px;border-radius:var(--r-m);background:var(--ink);color:#fff;font-size:15px;font-weight:600;box-shadow:var(--sh-2);transform:translate(-50%,8px);opacity:0;pointer-events:none;transition:opacity var(--dur-2) var(--ease),transform var(--dur-2) var(--ease)}
.ui-toast.show{opacity:1;transform:translate(-50%,0)}

/* 바텀 시트: 기본 <dialog class="ui-sheet">. 열기 data-sheet="id"(진입 직후 자동으로 열지 않는다), 보조 버튼 문구는 "닫기"(form method="dialog"), Esc, 바깥 누르기 */
.ui-sheet{width:100%;max-width:100%;max-height:85vh;margin:auto 0 0;padding:0;border:0;border-radius:20px 20px 0 0;background:#fff;color:var(--ink);box-shadow:var(--sh-2)}
.ui-sheet::backdrop{background:rgba(0,0,0,.4)}
.ui-sheet[open]{animation:ui-up var(--dur-2) var(--ease)}
.ui-sheet .body{padding:var(--sp-2) var(--gutter) calc(var(--sp-5) + env(safe-area-inset-bottom))}
.ui-sheet .body::before{content:"";display:block;width:40px;height:4px;margin:0 auto var(--sp-3);border-radius:2px;background:var(--g2)}
.ui-sheet h2{margin:0 0 var(--sp-3);font-size:20px;font-weight:800}
@keyframes ui-up{from{transform:translateY(24px);opacity:.6}}

@media (min-width:720px){
  :root{--gutter:32px}
  .btn{width:auto;min-width:240px}
  .btn-plain,.btn-sm{min-width:0}
  .fixed-bottom{position:static;padding:20px 0 0;background:none;border:0}
  .ui-page{padding-bottom:40px}
  .ui-toast{bottom:32px}
  .ui-sheet{max-width:480px;margin:auto;border-radius:20px}
}
@media (prefers-reduced-motion:reduce){*,::before,::after{animation:none!important;transition:none!important}}
