/* 컴포넌트
   치수는 한 세트로 움직인다 · 크기를 고르면 높이·반경·글자·패딩이 따라온다. */

/* ══ 버튼 ══════════════════════════════════════════════
   상태 규칙(docs/14): 상태가 바뀌어도 크기는 그대로다. 테두리는 안쪽 그림자로 그려 두께가 바뀌어도 밀리지 않는다.
   호버는 마우스가 있는 기기에서만 켠다(터치에서는 손을 뗀 뒤에도 호버가 남아 눌린 채로 보인다). */
.btn{
  --h:var(--c-md-h); --r:var(--c-md-r); --fs:var(--c-md-fs); --px:var(--c-md-px); --gap:var(--c-md-gap);
  position:relative;display:inline-flex;align-items:center;justify-content:center;gap:var(--gap);
  height:var(--h);padding-inline:var(--px);border-radius:var(--r);
  font-size:var(--fs);font-weight:600;line-height:1;letter-spacing:-.01em;
  white-space:nowrap;cursor:pointer;user-select:none;text-decoration:none;
  -webkit-tap-highlight-color:transparent;touch-action:manipulation;
  transition:background-color var(--d-1) var(--ease-inout),
             color var(--d-1) var(--ease-inout),
             box-shadow var(--d-1) var(--ease-inout),
             opacity var(--d-2) var(--ease-inout),
             transform var(--d-1) var(--ease-out);
}
.btn:active:not(:disabled,[aria-disabled="true"],[data-busy],[aria-busy="true"]){transform:scale(.97)}
/* 파일 선택도 입력 컴포넌트의 색과 글자 체계를 따른다. 문구는 기기 언어로 표시된다. */
.input[type="file"]{padding-block:var(--s-6);cursor:pointer}
.input[type="file"]::file-selector-button{font:inherit;font-size:var(--t-body-sm);font-weight:600;color:var(--ink-body);background:var(--tint);border:0;border-radius:var(--r-sm);
  height:var(--c-xs-h);padding:0 var(--s-12);margin-inline-end:var(--s-12);cursor:pointer;
  transition:background-color var(--d-1) var(--ease-inout)}
@media (hover:hover){.input[type="file"]:hover::file-selector-button{background:var(--tint-hover)}}
.input[type="file"]:disabled::file-selector-button{color:var(--ink-disabled);cursor:not-allowed}
/* 비활성: 모양은 그대로 두고 흐리게만. 대비 기준 면제 대상이지만 무엇이 있는지는 읽혀야 한다. */
.btn:disabled,.btn[aria-disabled="true"]{cursor:not-allowed;opacity:.42}
.btn svg{flex:none}
.btn__label{display:inline-flex;align-items:center;gap:inherit;min-width:0}

.btn--xs{--h:var(--c-xs-h);--r:var(--c-xs-r);--fs:var(--c-xs-fs);--px:var(--c-xs-px);--gap:var(--c-xs-gap)}
.btn--sm{--h:var(--c-sm-h);--r:var(--c-sm-r);--fs:var(--c-sm-fs);--px:var(--c-sm-px);--gap:var(--c-sm-gap)}
.btn--md{--h:var(--c-md-h);--r:var(--c-md-r);--fs:var(--c-md-fs);--px:var(--c-md-px);--gap:var(--c-md-gap)}
.btn--lg{--h:var(--c-lg-h);--r:var(--c-lg-r);--fs:var(--c-lg-fs);--px:var(--c-lg-px);--gap:var(--c-lg-gap)}
.btn--xl{--h:var(--c-xl-h);--r:var(--c-xl-r);--fs:var(--c-xl-fs);--px:var(--c-xl-px);--gap:var(--c-xl-gap)}
.btn--pill{--r:var(--r-full)}

/* 적중 영역 보장: 보이는 크기는 그대로 두고 누를 수 있는 범위만 44px로 넓힌다.
   손가락은 28px 버튼을 정확히 못 누른다. */
.btn--xs::before,.btn--sm::before,.btn--square.btn--md::before,
.quotes__nav::before,.totop::before{
  content:"";position:absolute;inset:50% auto auto 50%;translate:-50% -50%;
  width:max(100%,44px);height:max(100%,44px)}
.btn--xs,.btn--sm,.quotes__nav,.totop{position:relative}
.btn--block{display:flex;width:100%}
.btn--square{--px:0;width:var(--h)}

/* 주버튼: 화면당 하나. 두 개가 나란히 있으면 둘 다 약해진다. */
.btn--primary{background:var(--accent);color:var(--accent-ink)}
.btn--primary:active:not(:disabled){background:var(--accent-active)}

/* 보조: 단색 회색이 아니라 반투명 틴트. 어떤 배경에도 얹힌다. */
.btn--secondary{background:var(--tint);color:var(--ink-body)}
.btn--secondary:active:not(:disabled){background:var(--tint-active)}

.btn--soft{background:var(--accent-soft);color:var(--accent-text)}
.btn--soft:active:not(:disabled){background:var(--accent-soft-hover)}

.btn--outline{box-shadow:inset 0 0 0 1px var(--line-strong);color:var(--ink-body);background:transparent}
.btn--outline:active:not(:disabled){background:var(--tint-active)}

.btn--ghost{background:transparent;color:var(--ink-muted)}
.btn--ghost:active:not(:disabled){background:var(--tint-active);color:var(--ink-body)}

.btn--invert{background:var(--ink);color:var(--canvas)}
.btn--invert:active:not(:disabled){opacity:.78}

.btn--danger{background:var(--danger);color:var(--danger-ink)}
.btn--danger:active:not(:disabled){background:var(--danger-active)}

@media (hover:hover){
  .btn--primary:hover:not(:disabled,[aria-disabled="true"]){background:var(--accent-hover)}
  .btn--secondary:hover:not(:disabled,[aria-disabled="true"]){background:var(--tint-hover)}
  .btn--soft:hover:not(:disabled,[aria-disabled="true"]){background:var(--accent-soft-hover)}
  .btn--outline:hover:not(:disabled,[aria-disabled="true"]){background:var(--tint);box-shadow:inset 0 0 0 1px var(--ink-subtle)}
  .btn--ghost:hover:not(:disabled,[aria-disabled="true"]){background:var(--tint);color:var(--ink-body)}
  .btn--invert:hover:not(:disabled,[aria-disabled="true"]){opacity:.86}
  .btn--danger:hover:not(:disabled,[aria-disabled="true"]){background:var(--danger-hover)}
}
/* 포커스 링은 버튼 모서리를 따라간다(base.css 의 기본 링은 반경을 6px 로 두기 때문) */
.btn:focus-visible{border-radius:var(--r)}

/* 처리 중: data-busy 또는 aria-busy="true". 글자는 투명하게만 해서 폭이 그대로다(스피너가 뜰 때 버튼이 줄지 않는다).
   Turbo 가 제출 중인 폼(form[aria-busy])의 제출 버튼도 같은 모양이 된다. 이때 Turbo 가 버튼을 disabled 로 두므로 흐리게 하지 않는다. */
.btn[data-busy],.btn[aria-busy="true"],form[aria-busy="true"] .btn[type="submit"]{pointer-events:none;cursor:progress;-webkit-text-fill-color:transparent}
.btn[data-busy] > *,.btn[aria-busy="true"] > *,form[aria-busy="true"] .btn[type="submit"] > *{opacity:0}
form[aria-busy="true"] .btn[type="submit"]:disabled{opacity:1}
.btn[data-busy]::after,.btn[aria-busy="true"]::after,form[aria-busy="true"] .btn[type="submit"]::after{
  content:"";position:absolute;inset:0;margin:auto;width:1.15em;height:1.15em;
  border:2px solid currentColor;border-right-color:transparent;border-radius:50%;
  animation:spin .62s linear infinite}

/* ── 화살표 알약 ────────────────────────────────────────
   이 시스템의 대표 CTA. 연한 알약 안에 진한 원형 화살표가 들어간다.
   올리면 화살표가 오른쪽으로 조금 밀린다. */
.pill{
  position:relative;display:inline-flex;align-items:center;gap:12px;
  height:52px;padding:0 6px 0 22px;border-radius:var(--r-full);
  background:var(--tint);color:var(--ink);
  font-size:16px;font-weight:600;letter-spacing:-.01em;white-space:nowrap;cursor:pointer;
  -webkit-tap-highlight-color:transparent;
  transition:background-color var(--d-2) var(--ease-inout),transform var(--d-1) var(--ease-out)}
.pill:active{transform:scale(.975)}
.pill:focus-visible{border-radius:var(--r-full)}
.pill__dot{
  display:grid;place-items:center;width:40px;height:40px;border-radius:50%;
  background:var(--ink);color:var(--canvas);flex:none;
  transition:transform var(--d-3) var(--ease-out)}
.pill--accent{background:var(--accent);color:var(--accent-ink)}
.pill--accent .pill__dot{background:var(--accent-ink);color:var(--accent)}
.pill--lg{height:60px;padding-left:28px;font-size:17px}
.pill--lg .pill__dot{width:48px;height:48px}
.pill--sm{height:44px;padding-left:18px;font-size:15px;gap:10px}
.pill--sm .pill__dot{width:34px;height:34px}
@media (hover:hover){
  .pill:hover{background:var(--tint-hover)}
  .pill:hover .pill__dot{transform:translateX(3px)}
  .pill--accent:hover{background:var(--accent-hover)}
}
.pill[aria-disabled="true"],.pill:disabled{opacity:.42;pointer-events:none}

/* 글자 링크: 밑줄은 올렸을 때만 나타난다. 터치 기기는 누르는 동안만 밑줄. */
.link{color:var(--accent-text);font-weight:500;
  text-decoration:underline;text-decoration-color:transparent;text-underline-offset:3px;text-decoration-thickness:1px;
  transition:text-decoration-color var(--d-2) var(--ease-inout)}
.link:active{text-decoration-color:currentColor}
.link-arrow{position:relative;display:inline-flex;align-items:center;gap:6px;
  min-height:44px;color:var(--accent-text);font-weight:600}
.link-arrow svg{transition:transform var(--d-3) var(--ease-out)}
@media (hover:hover){
  .link:hover{text-decoration-color:currentColor}
  .link-arrow:hover svg{transform:translateX(3px)}
}

/* ══ 배지 ══════════════════════════════════════════════
   점을 찍지 않는다. 면과 글자만으로 구분한다. */
.badge{display:inline-flex;align-items:center;gap:5px;
  height:26px;padding-inline:9px;border-radius:var(--r-sm);
  font-size:var(--t-micro);font-weight:600;line-height:1;letter-spacing:-.01em;white-space:nowrap}
.badge--lg{height:32px;padding-inline:12px;font-size:var(--t-caption);border-radius:var(--r-md)}
.badge--pill{border-radius:var(--r-full)}
.badge--neutral{background:var(--tint);color:var(--ink-muted-alt)}
.badge--accent{background:var(--accent-soft);color:var(--accent-text)}
.badge--green{background:var(--good-soft);color:var(--good-text)}
.badge--amber{background:var(--warn-soft);color:var(--warn-text)}
.badge--red{background:var(--bad-soft);color:var(--bad-text)}
.badge--violet{background:var(--note-soft);color:var(--note-text)}
.badge--solid{background:var(--ink);color:var(--canvas)}
.badge--outline{box-shadow:inset 0 0 0 1px var(--line-strong);color:var(--ink-muted)}

/* 상태 점: 배지와 따로. 정말 상태를 나타낼 때만 쓴다. */
.dot{display:inline-block;width:7px;height:7px;border-radius:50%;flex:none}
.dot--live{background:var(--good);box-shadow:0 0 0 3px var(--good-soft)}
.dot--idle{background:var(--ink-disabled)}
.dot--warn{background:var(--warn)}
.dot--down{background:var(--bad)}

/* ══ 카드 ══════════════════════════════════════════════
   테두리와 그림자를 동시에 주지 않는다. 면이 다르면 테두리가 필요없다. */
.card{background:var(--surface);border-radius:var(--r-xl);padding:24px;
  transition:transform var(--d-3) var(--ease-out),box-shadow var(--d-3) var(--ease-out)}
.card--line{position:relative}
/* 테두리는 자식 위에 덮는 층으로 그린다.
   안쪽 그림자로 그리면 배경이 있는 자식(키패드·목록 행·이미지)이 그 위를 칠해 테두리와 모서리가 사라진다. */
.card--line::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  box-shadow:inset 0 0 0 1px var(--line);z-index:3}
.card--flush{isolation:isolate}
.card--raise{box-shadow:var(--sh-sm)}
.card--float{box-shadow:var(--sh-lg)}
.card--lg{padding:32px;border-radius:var(--r-2xl)}
.card--sm{padding:16px;border-radius:var(--r-lg)}
.card--flush{padding:0;overflow:hidden}
.card--link{display:block;color:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent}
@media (hover:hover){
  .card--link:hover{transform:translateY(-3px);box-shadow:var(--sh-md)}
}
.card--link:active{transform:translateY(-1px) scale(.995);transition-duration:var(--d-1)}
/* 카드 모서리를 따라가는 포커스 링 */
.card--link:focus-visible{border-radius:var(--r-xl)}
.card--lg.card--link:focus-visible{border-radius:var(--r-2xl)}
.card--sm.card--link:focus-visible{border-radius:var(--r-lg)}
.card__media{aspect-ratio:16/10;background:var(--canvas-sunken);overflow:hidden}
.card__media img{width:100%;height:100%;object-fit:cover}
.card__body{padding:20px 24px 24px}

/* 특징 항목: 카드가 아니다. 아이콘·제목·설명만. */
.feature{display:flex;flex-direction:column;gap:10px}
.feature__icon{display:grid;place-items:center;width:44px;height:44px;border-radius:var(--r-md);
  background:var(--accent-soft);color:var(--accent-text);margin-bottom:6px}
.feature__title{font-size:var(--t-heading-sm);line-height:var(--t-heading-sm-lh);
  letter-spacing:var(--t-heading-sm-ls);font-weight:600;color:var(--ink)}
.feature__desc{color:var(--ink-muted);font-size:var(--t-body-sm);line-height:var(--t-body-sm-lh)}

/* 통계: 숫자가 주인공일 때만 */
.stat{display:flex;flex-direction:column;gap:4px}
.stat__value{font-size:var(--t-display-sm);line-height:1.1;font-weight:700;
  letter-spacing:var(--t-display-sm-ls);color:var(--ink);font-variant-numeric:tabular-nums}
.stat__label{font-size:var(--t-body-sm);color:var(--ink-muted)}

/* ══ 입력 ══════════════════════════════════════════════
   높이는 컨트롤 치수 표를 따른다(md 44 · sm 36 · lg 52). 테두리 1px 을 포함한 높이다.
   평소에는 옅은 면과 가는 테두리, 포커스하면 강조 테두리와 3px 링. 상태가 바뀌어도 테두리 두께는 1px 그대로다. */
.field{display:flex;flex-direction:column;gap:7px;min-width:0}
.field__label{font-size:var(--t-body-sm);line-height:var(--t-body-sm-lh);font-weight:600;color:var(--ink-body)}
/* 라벨 옆 '(선택)' 같은 덧말 */
.field__opt{margin-left:var(--s-4);font-weight:500;color:var(--ink-subtle)}
.field__help{font-size:var(--t-caption);line-height:var(--t-caption-lh);color:var(--ink-muted)}
/* 오류는 색·글자·아이콘 셋으로 알린다(색만으로 알리지 않는다). 입력에는 aria-invalid="true" 와 aria-describedby 로 이 문장을 잇는다. */
.field__error{display:flex;align-items:flex-start;gap:var(--s-4);font-size:var(--t-caption);line-height:var(--t-caption-lh);color:var(--bad-text);font-weight:500;
  word-break:keep-all;overflow-wrap:anywhere}
.field__error::before{content:"";flex:none;width:14px;height:14px;margin-top:3.5px;background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a7 7 0 1 1 0 14A7 7 0 0 1 8 1Zm0 3.2a.9.9 0 0 0-.9.9v3.4a.9.9 0 1 0 1.8 0V5.1a.9.9 0 0 0-.9-.9Zm0 6.1a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z'/%3E%3C/svg%3E") center/contain no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a7 7 0 1 1 0 14A7 7 0 0 1 8 1Zm0 3.2a.9.9 0 0 0-.9.9v3.4a.9.9 0 1 0 1.8 0V5.1a.9.9 0 0 0-.9-.9Zm0 6.1a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z'/%3E%3C/svg%3E") center/contain no-repeat}
.field__error:empty{display:none}

.input,.textarea,.select{
  width:100%;min-width:0;min-height:var(--c-md-h);padding:9px 14px;
  background:var(--canvas-alt);color:var(--ink);
  border:1px solid var(--line);border-radius:var(--c-md-r);
  font-size:var(--t-body-md);line-height:24px;
  caret-color:var(--accent);
  transition:background-color var(--d-2) var(--ease-inout),
             border-color var(--d-2) var(--ease-inout),
             box-shadow var(--d-2) var(--ease-inout);
  appearance:none}
/* 자리표시자는 읽혀야 하는 글이라 본문 대비(4.5:1)를 지킨다(KWCAG·WCAG 1.4.3). 적은 값(--ink)보다 한 단계 옅다 */
.input::placeholder,.textarea::placeholder{color:var(--ink-subtle);opacity:1}
@media (hover:hover){
  .input:hover:not(:focus,:disabled,[readonly],[aria-invalid="true"]),
  .textarea:hover:not(:focus,:disabled,[readonly],[aria-invalid="true"]),
  .select:hover:not(:focus,:disabled,[aria-invalid="true"]){
    background:var(--canvas-sunken);border-color:var(--line-strong)}
}
.input:focus,.textarea:focus,.select:focus{
  background:var(--surface);border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-soft);outline:none}
/* 오류: 빨간 테두리·연한 면. 포커스해도 링까지 오류 색으로 둔다(파란 링에 빨간 테두리가 섞이지 않게). */
.input[aria-invalid="true"],.textarea[aria-invalid="true"],.select[aria-invalid="true"]{
  border-color:var(--bad);background:var(--bad-soft)}
.input[aria-invalid="true"]:focus,.textarea[aria-invalid="true"]:focus,.select[aria-invalid="true"]:focus{
  border-color:var(--bad);box-shadow:0 0 0 3px var(--bad-soft)}
/* 비활성: 모양은 그대로, 글자만 흐리게. iOS 사파리는 비활성 글자를 따로 흐리게 칠해서 두 번 흐려지지 않게 맞춘다. */
.input:disabled,.textarea:disabled,.select:disabled{color:var(--ink-disabled);-webkit-text-fill-color:var(--ink-disabled);
  opacity:1;cursor:not-allowed;background:var(--canvas-alt);border-color:var(--line)}
/* 읽기 전용: 고칠 수 없지만 읽고 복사할 수는 있다. 테두리 없는 틴트 면, 포커스는 중립 링. */
.input[readonly],.textarea[readonly]{background:var(--tint);border-color:transparent;color:var(--ink-body)}
.input[readonly]:focus,.textarea[readonly]:focus{background:var(--tint);border-color:var(--line-strong);box-shadow:0 0 0 3px var(--tint-hover)}
/* 자동 완성: 브라우저의 노란·파란 면 대신 연한 강조 면으로 둔다 */
.input:-webkit-autofill{-webkit-text-fill-color:var(--ink);-webkit-box-shadow:inset 0 0 0 100px var(--accent-soft);caret-color:var(--accent)}
.input:-webkit-autofill:focus{-webkit-box-shadow:inset 0 0 0 100px var(--accent-soft),0 0 0 3px var(--accent-soft)}
.input--sm{min-height:var(--c-sm-h);border-radius:var(--c-sm-r);padding:5px 12px}
.input--lg{min-height:var(--c-lg-h);border-radius:var(--c-lg-r);padding:13px 16px}
/* 숫자 칸의 위아래 화살표는 숨긴다(스크롤 휠에 값이 바뀌는 사고도 막는다). 숫자 자판은 inputmode="numeric" 으로 연다. */
/* 검색 칸의 기본 지우기(x)를 시스템 파란 x 대신 회색 원으로 */
.input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}
.input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none;width:18px;height:18px;margin-left:6px;cursor:pointer;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Ccircle cx='9' cy='9' r='9' fill='%23B5BBC4'/%3E%3Cpath d='M6 6l6 6M12 6l-6 6' stroke='white' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E") center/18px no-repeat}
/* 지우기 버튼(data-clearable)을 단 검색 칸은 브라우저 기본 지우기(x)를 숨긴다. 둘 다 보이면 x 가 두 개 나란히 뜬다. */
.input[type="search"][data-clearable]::-webkit-search-cancel-button{display:none}
.input[type="number"]{-moz-appearance:textfield}
.input[type="number"]::-webkit-inner-spin-button,.input[type="number"]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
/* 날짜·시간: iOS 는 값이 비면 높이가 줄고 가운데 정렬된다. 왼쪽 정렬과 한 줄 높이로 맞춘다. */
.input::-webkit-date-and-time-value{text-align:left;min-height:24px}
.input::-webkit-datetime-edit,.input::-webkit-datetime-edit-fields-wrapper{padding:0}
.input::-webkit-calendar-picker-indicator{opacity:.55;cursor:pointer;margin:0;padding:2px;height:20px}
/* 여러 줄 입력칸: 브라우저 크기 조절 손잡이를 쓰지 않고 글 길이만큼 늘어난다(field-sizing 지원 브라우저).
   지원하지 않는 브라우저는 최소 높이에 머물고 안에서 스크롤한다. 늘어나도 화면 절반을 넘지 않는다. */
.textarea{min-height:104px;padding-block:11px;resize:none;line-height:1.6;field-sizing:content;max-height:min(320px,50dvh);overflow-y:auto}
/* 코드·JSON 편집칸(.mono)은 긴 내용을 다루므로 rows 높이와 손잡이를 그대로 둔다(콘솔) */
.textarea.mono{resize:vertical;field-sizing:fixed;max-height:none}
.select{padding-right:38px;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 6.5L8 10.5L12 6.5' stroke='%236E7680' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 14px center}

/* 앞뒤 칸이 붙는 입력
   앞: .input-group__icon (장식 아이콘)
   뒤: .input-group__end 안에 .input-group__btn(지우기·비밀번호 보기 같은 아이콘 버튼) · .input-group__addon(단위 글자 '원'·'분')
       또는 .input-group__icon--end (장식 아이콘)
   뒤 칸 폭만큼 입력 오른쪽 여백이 저절로 잡힌다(--end-w 로 직접 줄 수도 있다). */
.input-group{position:relative;display:flex;align-items:center;min-width:0}
.input-group__icon{position:absolute;left:14px;display:grid;place-items:center;color:var(--ink-subtle);pointer-events:none;
  transition:color var(--d-2) var(--ease-inout)}
.input-group__icon--end{left:auto;right:14px}
.input-group:focus-within .input-group__icon{color:var(--ink-muted)}
.input-group .input{padding-left:42px;padding-right:var(--end-w,14px)}
.input-group:not(:has(.input-group__icon:not(.input-group__icon--end))) .input{padding-left:14px}
.input-group:has(.input-group__icon--end){--end-w:42px}
.input-group:has(> .input-group__end){--end-w:48px}
.input-group:has(> .input-group__end > :nth-child(2)){--end-w:88px}
.input-group:has(> .input-group__end > .input-group__addon){--end-w:52px}
.input-group:has(> .input-group__end > .input-group__addon + *),.input-group:has(> .input-group__end > * + .input-group__addon){--end-w:92px}
.input-group__end{position:absolute;top:0;right:4px;bottom:0;display:flex;align-items:center}
.input-group__addon{padding-inline:6px 10px;font-size:var(--t-body-md);color:var(--ink-muted);white-space:nowrap;pointer-events:none}
/* 아이콘 버튼: 폭 40·높이 44(입력 높이 전체)를 적중 영역으로 쓰고, 보이는 원(28px)은 ::after 로 안에 그린다.
   이웃 버튼과 붙어 있어 가상 요소로 적중 영역을 넓히지 않는다(docs/04 '적중 영역을 넓힐 때 주의'). */
.input-group__btn{position:relative;display:grid;place-items:center;width:40px;height:44px;color:var(--ink-subtle);cursor:pointer;
  -webkit-tap-highlight-color:transparent;transition:color var(--d-1) var(--ease-inout)}
.input-group__btn::after{content:"";position:absolute;inset:0;margin:auto;width:30px;height:30px;border-radius:50%;background:transparent;
  transition:background-color var(--d-1) var(--ease-inout)}
.input-group__btn > *{position:relative;z-index:1}
.input-group__btn:active::after{background:var(--tint-active)}
@media (hover:hover){.input-group__btn:hover{color:var(--ink-body)}.input-group__btn:hover::after{background:var(--tint)}}
.input-group__btn:focus-visible{outline-offset:-4px;border-radius:var(--r-full)}
.input-group__btn[hidden]{display:none}
.input-group .input--lg ~ .input-group__end .input-group__btn,.input-group:has(.input--lg) .input-group__btn{height:52px}
.input-group .input--sm ~ .input-group__end .input-group__btn,.input-group:has(.input--sm) .input-group__btn{height:36px}

/* 선택 컨트롤: 체크·라디오를 직접 그린다(운영체제마다 다른 모양 대신 같은 모양). 적중 영역 44px.
   긴 라벨은 두 줄로 흐르고, 상자는 첫 줄에 맞춘다. */
.choice{display:inline-flex;align-items:flex-start;gap:10px;min-height:44px;padding-block:10px;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.choice input[type="checkbox"],.choice input[type="radio"]{
  appearance:none;-webkit-appearance:none;position:relative;flex:none;width:20px;height:20px;margin:2px 0 0;
  border-radius:6px;background:var(--surface) center/14px no-repeat;
  box-shadow:inset 0 0 0 1.5px var(--line-strong);cursor:pointer;
  transition:background-color var(--d-1) var(--ease-inout),box-shadow var(--d-2) var(--ease-out)}
.choice input[type="radio"]{border-radius:50%}
.choice input[type="checkbox"]:checked{background-color:var(--accent);box-shadow:none;
  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='M3.5 8.4l2.9 2.9L12.6 5' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
.choice input[type="checkbox"]:indeterminate{background-color:var(--accent);box-shadow:none;
  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 8h8' stroke='white' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E")}
/* 라디오: 굵은 강조 고리 + 가운데 흰 점. 두께를 안쪽 그림자로 그려 크기가 바뀌지 않는다. */
.choice input[type="radio"]:checked{box-shadow:inset 0 0 0 6px var(--accent)}
@media (hover:hover){.choice:hover input:not(:checked,:disabled,:indeterminate){box-shadow:inset 0 0 0 1.5px var(--ink-subtle)}}
.choice input:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.choice input[aria-invalid="true"]:not(:checked){box-shadow:inset 0 0 0 1.5px var(--bad);background-color:var(--bad-soft)}
.choice:has(input:disabled){cursor:not-allowed}
.choice input:disabled{cursor:not-allowed;background-color:var(--tint);box-shadow:inset 0 0 0 1.5px var(--line)}
.choice input:disabled:checked{opacity:.42;background-color:var(--accent);box-shadow:none}
.choice input[type="radio"]:disabled:checked{background-color:var(--surface);box-shadow:inset 0 0 0 6px var(--accent)}
.choice__text{min-width:0;font-size:var(--t-body-sm);line-height:var(--t-body-sm-lh);color:var(--ink-body);word-break:keep-all;overflow-wrap:anywhere}
.choice:has(input:disabled) .choice__text{color:var(--ink-disabled)}
/* 라벨 아래 한 줄 설명 */
.choice__sub{display:block;margin-top:2px;font-size:var(--t-caption);line-height:var(--t-caption-lh);color:var(--ink-muted)}

/* 스위치: 손잡이를 트랙 위에 흐름 안에서 겹친다(음수 여백). 글자가 앞에 와도 뒤에 와도 손잡이가 트랙 위에 있다.
   켜짐은 색과 손잡이 위치 두 가지로 알린다. 화면 읽기에는 input 에 role="switch" 를 준다. */
.switch{--sw-w:46px;--sw-h:28px;--sw-k:22px;--sw-gap:10px;
  position:relative;display:inline-flex;align-items:center;gap:var(--sw-gap);min-height:44px;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.switch input{position:absolute;opacity:0;width:0;height:0;margin:0}
.switch__track{width:var(--sw-w);height:var(--sw-h);border-radius:var(--r-full);background:var(--line-strong);
  transition:background-color var(--d-2) var(--ease-inout);flex:none}
.switch__knob{position:relative;flex:none;width:var(--sw-k);height:var(--sw-k);border-radius:50%;background:var(--knob);
  margin-left:calc(-1 * (var(--sw-w) + var(--sw-gap)) + 3px);
  margin-right:calc(var(--sw-w) - var(--sw-k) - 3px);
  box-shadow:0 1px 3px rgba(var(--shadow-color),.2),0 0 0 .5px rgba(var(--shadow-color),.06);
  transition:transform var(--d-3) var(--ease-spring)}
.switch input:checked ~ .switch__track{background:var(--accent)}
.switch input:checked ~ .switch__knob{transform:translateX(calc(var(--sw-w) - var(--sw-k) - 6px))}
.switch input:focus-visible ~ .switch__track{outline:2px solid var(--focus);outline-offset:2px}
.switch:has(input:disabled){cursor:not-allowed}
.switch input:disabled ~ .switch__track,.switch input:disabled ~ .switch__knob{opacity:.42}
.switch input:disabled ~ :not(.switch__track,.switch__knob){color:var(--ink-disabled)}
@media (hover:hover){.switch:hover input:not(:checked,:disabled) ~ .switch__track{background:color-mix(in srgb,var(--line-strong),var(--ink-subtle) 22%)}}

/* 분절 컨트롤: 배타 선택. 탭과 다르다. 고른 칸은 흰 면·그림자·진한 글자 셋이 함께 바뀐다(색만이 아니다). */
.segment{display:inline-flex;max-width:100%;padding:3px;gap:2px;background:var(--tint);border-radius:var(--r-md)}
.segment__item{position:relative;flex:0 1 auto;min-width:44px;height:38px;padding-inline:14px;border-radius:calc(var(--r-md) - 3px);
  font-size:var(--t-body-xs);font-weight:600;color:var(--ink-muted);cursor:pointer;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;-webkit-tap-highlight-color:transparent;
  transition:background-color var(--d-2) var(--ease-inout),color var(--d-2) var(--ease-inout),box-shadow var(--d-2) var(--ease-inout)}
@media (hover:hover){.segment__item:hover:not(:disabled,[aria-pressed="true"],[aria-selected="true"],[aria-current="page"]){color:var(--ink-body);background:var(--tint)}}
.segment__item:active:not(:disabled){background:var(--tint)}
.segment__item[aria-pressed="true"],.segment__item[aria-selected="true"],.segment__item[data-on],.segment__item[aria-current="page"]{
  background:var(--surface-raised);color:var(--ink);box-shadow:var(--sh-xs),0 0 0 .5px var(--line)}
.segment__item:focus-visible{border-radius:calc(var(--r-md) - 3px);outline-offset:0}
.segment__item:disabled,.segment__item[aria-disabled="true"]{color:var(--ink-disabled);cursor:not-allowed}
/* 링크 분절: 화면을 바꾸는 분절(지금 화면은 aria-current="page"). 버튼과 같은 모양 */
a.segment__item{display:inline-flex;align-items:center;justify-content:center;text-decoration:none}
/* 가로 전체를 같은 폭으로 나눈다(좁은 화면 설정 행) */
.segment--block{display:flex;width:100%}
.segment--block .segment__item{flex:1 1 0}
/* 작은 분절(sm 36px). 관리자 필터 줄 */
/* 보이는 높이 30px, 누르는 범위는 위아래로 넓혀 44px(옆 칸과는 붙어 있어 가로로는 넓히지 않고 칸 폭을 44px 로 둔다) */
.segment--sm .segment__item{height:30px;min-width:44px;padding-inline:var(--s-10);font-size:var(--t-caption);overflow:visible}
.segment--sm .segment__item::before{content:"";position:absolute;inset:-7px 0}

/* ══ 탭 ══════════════════════════════════════════════
   고른 탭은 진한 글자 + 밑줄 두 가지로 알린다. 넘치면 가로로 밀리고, 가장자리가 흐려져 더 있다는 걸 알린다(data-edge, ds.js). */
.tabs__list{position:relative;display:flex;gap:2px;overflow-x:auto;scrollbar-width:none;overscroll-behavior-x:contain;
  box-shadow:inset 0 -1px 0 var(--line);scroll-padding-inline:24px}
.tabs__list::-webkit-scrollbar{display:none}
.tabs__tab{position:relative;flex:none;display:inline-flex;align-items:center;gap:var(--s-6);height:48px;padding-inline:14px;
  font-size:var(--t-body-sm);font-weight:600;color:var(--ink-muted);cursor:pointer;white-space:nowrap;
  -webkit-tap-highlight-color:transparent;transition:color var(--d-2) var(--ease-inout)}
@media (hover:hover){.tabs__tab:hover:not(:disabled,[aria-selected="true"]){color:var(--ink-body)}}
.tabs__tab[aria-selected="true"]{color:var(--ink)}
/* 가로로 넘치는 목록 안이라 바깥 링은 잘린다. 안쪽에 그린다. */
.tabs__tab:focus-visible{outline-offset:-4px;border-radius:var(--r-sm)}
.tabs__tab:disabled,.tabs__tab[aria-disabled="true"]{color:var(--ink-disabled);cursor:not-allowed}
/* 탭 옆 개수 */
.tabs__count{min-width:20px;height:20px;padding-inline:6px;border-radius:var(--r-full);background:var(--tint);
  font-size:var(--t-nano);line-height:20px;font-weight:700;text-align:center;color:var(--ink-muted-alt);font-variant-numeric:tabular-nums}
.tabs__tab[aria-selected="true"] .tabs__count{background:var(--ink);color:var(--canvas)}
.tabs__ink{position:absolute;bottom:0;left:0;height:2px;background:var(--ink);border-radius:2px;pointer-events:none;
  transition:transform var(--d-4) var(--ease-out),width var(--d-4) var(--ease-out)}
.tabs__panel{padding-top:24px}
.tabs__panel:focus-visible{outline-offset:4px}

/* 가로로 넘치는 줄의 가장자리 흐림: ds.js 가 스크롤 위치에 따라 data-edge="start|end|both" 를 붙인다(탭·필터 칩·서브 내비) */
[data-edge="end"]{-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 40px),transparent);mask-image:linear-gradient(90deg,#000 calc(100% - 40px),transparent)}
[data-edge="start"]{-webkit-mask-image:linear-gradient(90deg,transparent,#000 40px);mask-image:linear-gradient(90deg,transparent,#000 40px)}
[data-edge="both"]{-webkit-mask-image:linear-gradient(90deg,transparent,#000 40px,#000 calc(100% - 40px),transparent);mask-image:linear-gradient(90deg,transparent,#000 40px,#000 calc(100% - 40px),transparent)}

/* ══ 아코디언 ══════════════════════════════════════════
   접힌 칸은 보이지 않을 뿐 아니라 Tab 으로도 들어가지 않는다(visibility, ds.js 가 data-open). */
.accordion__item{box-shadow:inset 0 -1px 0 var(--line)}
.accordion__trigger{display:flex;align-items:center;justify-content:space-between;gap:16px;
  width:100%;min-height:68px;padding:20px 4px;text-align:left;
  font-size:var(--t-body-lg);line-height:var(--t-body-lg-lh);font-weight:600;color:var(--ink);cursor:pointer;letter-spacing:-.01em;
  word-break:keep-all;overflow-wrap:anywhere;-webkit-tap-highlight-color:transparent}
.accordion__trigger:focus-visible{outline-offset:-2px;border-radius:var(--r-sm)}
.accordion__chev{flex:none;width:20px;height:20px;color:var(--ink-subtle);
  transition:transform var(--d-4) var(--ease-out),color var(--d-2) var(--ease-inout)}
@media (hover:hover){.accordion__trigger:hover .accordion__chev{color:var(--ink-body)}}
.accordion__trigger[aria-expanded="true"] .accordion__chev{transform:rotate(180deg)}
.accordion__panel{overflow:hidden;height:0;visibility:hidden;
  transition:height var(--d-4) var(--ease-inout),visibility 0s linear var(--d-4)}
.accordion__panel[data-open]{visibility:visible;transition:height var(--d-4) var(--ease-inout),visibility 0s}
.accordion__body{padding:0 4px 24px;color:var(--ink-muted);
  font-size:var(--t-body-md);line-height:var(--t-body-md-lh);max-width:52rem}

/* ══ 드롭다운 ══════════════════════════════════════════
   열림 pop(--d-2 ease-out), 닫힘 fade(--d-1 ease-in). 좁은 화면에서는 아래 시트(덮개 포함). */
.menu{position:fixed;z-index:var(--z-pop);min-width:200px;max-width:min(360px,calc(100vw - 24px));padding:6px;
  background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--sh-pop);
  max-height:min(62vh,440px);overflow-y:auto;overscroll-behavior:contain;
  transform-origin:top left}
.menu[data-side="top"]{transform-origin:bottom left}
.menu[data-align="end"]{transform-origin:top right}
.menu[data-side="top"][data-align="end"]{transform-origin:bottom right}
.menu__item{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;
  padding:10px 12px;border-radius:var(--r-sm);text-align:left;cursor:pointer;
  font-size:var(--t-body-sm);line-height:var(--t-body-sm-lh);color:var(--ink-body);
  word-break:keep-all;overflow-wrap:anywhere;-webkit-tap-highlight-color:transparent;
  transition:background-color var(--d-1) var(--ease-inout)}
@media (hover:hover){.menu__item:hover:not(:disabled,[aria-disabled="true"]){background:var(--tint)}}
.menu__item:active:not(:disabled,[aria-disabled="true"]){background:var(--tint-active)}
.menu__item:focus-visible{background:var(--tint-hover);outline:2px solid var(--focus);outline-offset:-2px}
/* 고른 항목: 연한 강조 면 + 굵은 강조 글자 + 오른쪽 체크(.menu__mark). 색만으로 알리지 않는다. */
.menu__item[aria-checked="true"]{color:var(--accent-text);font-weight:600;background:var(--accent-soft)}
/* 여러 개 고르는 체크 메뉴는 면을 칠하지 않는다(고른 항목이 이어지면 덩어리로 보인다). 체크 표시와 강조 글자로 알린다. */
.menu__item[role="menuitemcheckbox"][aria-checked="true"]{background:none}
.menu__mark{flex:none;margin-left:auto;width:16px;height:16px;opacity:0;transition:opacity var(--d-1) var(--ease-inout)}
.menu__item[aria-checked="true"] .menu__mark{opacity:1}
/* 앞 아이콘과 오른쪽 덧말(단축키·개수) */
.menu__icon{flex:none;width:20px;height:20px;color:var(--ink-muted)}
.menu__item[aria-checked="true"] .menu__icon{color:inherit}
.menu__meta{flex:none;margin-left:auto;padding-left:var(--s-12);font-size:var(--t-caption);font-weight:500;color:var(--ink-subtle);font-variant-numeric:tabular-nums}
.menu__meta + .menu__mark{margin-left:var(--s-8)}
/* 위험 항목(삭제·연결 끊기): 빨간 글자 + 빨간 아이콘. 목록 맨 아래, 구분선 뒤에 둔다. */
.menu__item--danger,.menu__item--danger .menu__icon{color:var(--bad-text)}
@media (hover:hover){.menu__item--danger:hover:not(:disabled){background:var(--bad-soft)}}
.menu__item--danger:active:not(:disabled){background:var(--bad-soft)}
.menu__item:disabled,.menu__item[aria-disabled="true"]{color:var(--ink-disabled);cursor:not-allowed}
.menu__item:disabled .menu__icon,.menu__item[aria-disabled="true"] .menu__icon{color:var(--ink-disabled)}
.menu__sep{height:1px;margin:6px 4px;background:var(--line)}
.menu__label{padding:8px 12px 4px;font-size:var(--t-nano);font-weight:600;
  letter-spacing:.05em;text-transform:uppercase;color:var(--ink-subtle)}
/* 시트 제목(data-menu-title 을 ds.js 가 넣는다): 좁은 화면 시트에서만 보인다 */
.menu__title,.menu__close{display:none}
/* 좁은 화면 시트 뒤 덮개(ds.js 가 붙인다). 넓은 화면에서는 보이지 않는 바깥 누름 막이다. */
.menu__scrim{position:fixed;inset:0;z-index:calc(var(--z-pop) - 1);background:transparent}

/* 좁은 화면에서는 아래에서 올라오는 시트로 바뀐다 */
@media (max-width:639px){
  .menu{left:0 !important;right:0 !important;top:auto !important;bottom:0 !important;
    width:auto;max-width:none;max-height:72dvh;
    border-radius:var(--r-3xl) var(--r-3xl) 0 0;
    padding:10px 10px calc(10px + var(--safe-b));
    box-shadow:var(--sh-xl);transform-origin:bottom center}
  .menu::before{content:"";display:block;width:36px;height:4px;border-radius:var(--r-full);
    background:var(--line-strong);margin:2px auto 10px}
  .menu__title{display:block;padding:4px 12px 10px;font-size:var(--t-body-sm);font-weight:600;color:var(--ink-muted);text-align:center}
  /* 닫기: 항목과 떨어진 맨 아래 한 줄(확인 시트의 '그대로 두기'처럼 가운데, 연한 면) */
  .menu__close{display:flex;justify-content:center;margin-top:var(--s-8);background:var(--canvas-alt);color:var(--ink-body);font-weight:600}
  @media (hover:hover){.menu__close:hover{background:var(--canvas-sunken)}}
  .menu__item{min-height:52px;font-size:var(--t-body-md);line-height:var(--t-body-md-lh)}
  .menu[data-state="open"]{animation:sheet-up var(--d-5) var(--ease-sheet) both}
  .menu[data-state="closing"]{animation:sheet-down var(--d-3) var(--ease-in) both}
  .menu__scrim{background:var(--scrim);animation:fade-in var(--d-4) var(--ease-inout) both}
  .menu__scrim[data-out]{animation:fade-out var(--d-3) var(--ease-inout) both}
}

/* ══ 오버레이: 시트·모달 ═══════════════════════════════
   ~767 아래 시트 · 768~ 가운데 창. 열림은 시트 곡선(--ease-sheet)·pop(ease-out), 닫힘은 ease-in 으로 더 짧게. */
.overlay{position:fixed;inset:0;z-index:var(--z-modal)}
.overlay[hidden]{display:none}
.overlay__scrim{position:absolute;inset:0;background:var(--scrim);
  backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px)}

.sheet{position:absolute;left:0;right:0;bottom:0;display:flex;flex-direction:column;
  max-height:min(88dvh,760px);background:var(--surface);
  border-radius:var(--r-3xl) var(--r-3xl) 0 0;box-shadow:var(--sh-xl);
  padding-bottom:var(--safe-b);overscroll-behavior:contain}
/* 열릴 때 초점은 패널 자체에 간다(ds.js). 패널은 누르는 곳이 아니라서 초점 테두리를 그리지 않는다. */
.sheet:focus-visible,.modal:focus-visible,.overlay:focus-visible{outline:none}
.sheet__grip{flex:none;display:grid;place-items:center;height:24px;cursor:grab;touch-action:none}
.sheet__grip::before{content:"";width:36px;height:4px;border-radius:var(--r-full);background:var(--line-strong);
  transition:background-color var(--d-1) var(--ease-inout)}
.sheet__grip:active{cursor:grabbing}
.sheet__grip:active::before{background:var(--ink-subtle)}
.sheet__grip:focus-visible{outline-offset:-4px;border-radius:var(--r-full)}
.sheet__head{flex:none;padding:8px 24px 16px}
.sheet__head :where(h2,h3){font-size:var(--t-heading-sm);line-height:var(--t-heading-sm-lh);letter-spacing:var(--t-heading-sm-ls);font-weight:700;color:var(--ink)}
.sheet__head :where(p){margin-top:var(--s-4);font-size:var(--t-body-sm);line-height:var(--t-body-sm-lh);color:var(--ink-muted)}
/* 닫기(X): 넓은 화면 창에는 손잡이가 없으므로 오른쪽 위에 둔다. 좁은 화면 시트에서도 써도 된다. */
.sheet__close{position:absolute;top:12px;right:12px;z-index:1}
.sheet:has(> .sheet__close) .sheet__head,.modal:has(> .sheet__close) > :first-child:not(.sheet__close){padding-right:64px}
.sheet__body{flex:1;min-height:0;overflow-y:auto;padding:0 24px 20px;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}
.sheet__foot{flex:none;display:flex;gap:8px;padding:16px 24px calc(20px + var(--safe-b));
  box-shadow:inset 0 1px 0 var(--line);background:var(--surface)}
.sheet__foot > *{flex:1;min-width:0}
/* 버튼 글자가 길어 한 줄에 둘이 안 들어갈 때: 위아래로 쌓는다(주버튼이 위) */
.sheet__foot--stack{flex-direction:column}
.sheet__foot--stack > *{width:100%;flex:none}
@media (min-width:768px){
  .sheet{left:50%;right:auto;bottom:auto;top:50%;translate:-50% -50%;
    width:min(520px,calc(100vw - 48px));border-radius:var(--r-2xl);padding-bottom:0}
  .sheet__grip{display:none}
  .sheet__head{padding-top:28px}
  .sheet__foot{justify-content:flex-end;padding-bottom:24px;border-radius:0 0 var(--r-2xl) var(--r-2xl)}
  .sheet__foot > *{flex:none}
  .sheet__foot--stack > *{width:100%}
}

.modal{position:relative;width:min(560px,calc(100vw - 32px));max-height:calc(100dvh - 80px);
  overflow:auto;overscroll-behavior:contain;background:var(--surface);border-radius:var(--r-2xl);padding:28px;
  box-shadow:var(--sh-xl);margin:auto}
.overlay--center{display:grid;place-items:center;padding:24px}
@media (max-width:640px){
  .overlay--center{align-items:flex-end;padding:0}
  /* margin:auto 가 격자 칸의 남는 높이를 먹으면 창이 가운데 뜬다. 위쪽만 auto 로 두어 바닥에 붙인다. */
  .modal{width:100%;margin:auto 0 0;border-radius:var(--r-3xl) var(--r-3xl) 0 0;max-height:90dvh;
    padding-bottom:calc(28px + var(--safe-b))}
}

/* ══ 토스트 ══════════════════════════════════════════
   어두운 떠 있는 면(--toast). 완료·오류는 면 색과 앞 아이콘(ds.js)을 함께 바꾼다. 긴 문장은 어절 단위로 줄을 바꾼다. */
.toasts{position:fixed;left:50%;translate:-50% 0;z-index:var(--z-toast);
  bottom:calc(var(--safe-b) + 24px);display:flex;flex-direction:column-reverse;gap:8px;
  align-items:center;pointer-events:none;width:calc(100% - 32px);max-width:440px}
/* 화면에 고정 탭바가 있으면 그 위로 띄운다 */
.tabbar--fixed ~ .toasts,:where(:has(> .tabbar--fixed)) ~ .toasts{bottom:calc(var(--safe-b) + var(--tabbar-h) + 16px)}
.toast{pointer-events:auto;display:flex;align-items:center;gap:12px;width:100%;
  min-height:52px;padding:12px 14px 12px 18px;
  background:var(--toast);color:var(--toast-ink);border-radius:var(--r-lg);
  box-shadow:var(--sh-xl),inset 0 0 0 1px var(--toast-line);font-size:var(--t-body-sm);line-height:1.5;font-weight:500}
.toast__icon{flex:none;width:20px;height:20px;margin-block:1px;align-self:flex-start;margin-top:2px}
.toast:has(.toast__icon){padding-left:14px}
.toast__text{flex:1;min-width:0;word-break:keep-all;overflow-wrap:anywhere;text-wrap-style:pretty}
.toast__action{flex:none;min-height:36px;padding-inline:10px;margin-block:-4px;border-radius:var(--r-sm);
  color:var(--toast-action);font-size:var(--t-body-sm);font-weight:600;cursor:pointer;white-space:nowrap;
  transition:background-color var(--d-1) var(--ease-inout)}
.toast__action:active{background:color-mix(in srgb,var(--toast-ink) 14%,transparent)}
@media (hover:hover){.toast__action:hover{background:color-mix(in srgb,var(--toast-ink) 10%,transparent)}}
.toast__action:focus-visible{outline-color:var(--toast-ink);outline-offset:0}
.toast--good{background:var(--toast-good)}
.toast--bad{background:var(--toast-bad)}
.toast--good .toast__action,.toast--bad .toast__action{color:var(--toast-ink);text-decoration:underline;text-underline-offset:3px}
/* 시트·창이 열려 있는 동안 뜬 토스트는 화면 위쪽에 띄운다. 아래에 두면 시트의 제목·본문·버튼을 가린다. */
html[data-overlay-open] .toasts{top:calc(var(--safe-t) + var(--s-12));bottom:auto;flex-direction:column}

/* ══ 툴팁 ══════════════════════════════════════════════
   동작(data-tip)은 extras.js. 모양·등장은 여기. 위쪽에 뜨면 data-side="top". */
.tip{position:absolute;z-index:var(--z-tip);max-width:min(260px,calc(100vw - 24px));padding:8px 11px;
  background:var(--toast);color:var(--toast-ink);border-radius:var(--r-sm);
  font-size:var(--t-micro);line-height:1.45;box-shadow:var(--sh-lg),inset 0 0 0 1px var(--toast-line);pointer-events:none;
  word-break:keep-all;overflow-wrap:anywhere;animation:tip-in var(--d-2) var(--ease-out) both}
/* 기본은 트리거 위에 떠서 위로 살짝 떠오른다. 아래에 뜨면(data-side="bottom") 아래로 살짝 내려온다. */
.tip[data-side="bottom"]{--tip-dy:-4px}
.tip[hidden]{display:none}

/* ══ 내비게이션 ════════════════════════════════════════ */
/* 흐린 유리 바탕은 ::before 에 깐다. 요소 자신에 backdrop-filter 를 걸면 그 안의 position:fixed(메뉴·툴팁·서랍)가
   화면이 아니라 이 바를 기준으로 놓여 엉뚱한 자리에 뜨거나 바 안에 갇힌다. */
.nav{position:sticky;top:0;z-index:var(--z-header);height:var(--nav-h);display:flex;align-items:center}
.nav::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;opacity:0;
  background:color-mix(in srgb,var(--canvas) 96%,transparent);
  backdrop-filter:saturate(180%) blur(14px);-webkit-backdrop-filter:saturate(180%) blur(14px);
  box-shadow:inset 0 -1px 0 var(--line);transition:opacity var(--d-3) var(--ease-inout)}
.nav[data-stuck]::before{opacity:1}
/* 브랜드 로고: 심볼(색이 박힌 그림 brand/symbol.svg) + 글자 로고(brand/wordmark.svg 를 마스크로 쓰고 역할 토큰 그라데이션 --brand-word-1·2 를 칠한다. 다크에서 밝게 뒤집힌다).
   크기는 --brand-h(심볼 높이) 하나로 정한다. 로고마다 다른 값(그림 비율·글자 높이·마스크 주소)은 brand.css(브랜드 슬롯)에 있다. 마크업은 shared/_brand. */
.brand{--brand-h:28px;display:inline-flex;align-items:center;gap:calc(var(--brand-h) * .22);color:var(--ink);line-height:0;flex:none}
.brand__symbol{flex:none;display:block;width:auto;height:var(--brand-h);aspect-ratio:1;transform-origin:50% 62%;
  transition:transform var(--d-4) var(--ease-spring)}
.brand__word{flex:none;display:block;height:calc(var(--brand-h) * .6);aspect-ratio:4 / 1;
  background:linear-gradient(178deg,var(--brand-word-1) 0%,var(--brand-word-2) 58%);
  -webkit-print-color-adjust:exact;print-color-adjust:exact;forced-color-adjust:none}
@media (hover:hover){a:hover .brand__symbol,.brand--live .brand__symbol{transform:rotate(-6deg) scale(1.05)}}
a:active .brand__symbol{transform:scale(.96)}
@media (forced-colors:active){.brand__word{background:CanvasText}}
@media (prefers-reduced-motion:reduce){.brand__symbol{transition:none}}

/* ── 불러오는 중(브랜드) .brand-loader ── Rails shared/_brand_loader. 화면이나 큰 영역을 처음 불러오는데 모양을 미리 모를 때 가운데에.
   300ms 규칙(docs/11): --loader-wait(기본 300ms) 뒤에 나타난다. 그 전에 내용이 와서 지우면 아무것도 보이지 않는다. 기다리는 동안은 읽기 도구에도 숨는다.
   --fill 은 감싼 칸을 채워 가운데, --now 는 기다리지 않고 바로. */
.brand-loader{--loader-wait:300ms;display:grid;justify-items:center;align-content:center;gap:var(--s-16);padding:var(--s-48) var(--s-24);text-align:center;
  animation:brand-loader-in var(--d-4) var(--ease-out) var(--loader-wait) both}
.brand-loader--fill{min-height:100%;flex:1 1 auto}
.brand-loader--page{min-height:calc(var(--fx-vh, 100dvh) * .6)}
.brand-loader--now{--loader-wait:0ms}
.brand-loader__text{margin:0;font-size:var(--t-body-md);line-height:var(--t-body-md-lh);font-weight:600;color:var(--ink-body)}
.brand-loader__sub{margin:calc(var(--s-12) * -1) 0 0;font-size:var(--t-body-sm);line-height:var(--t-body-sm-lh);color:var(--ink-muted)}
@keyframes brand-loader-in{from{opacity:0;visibility:hidden}to{opacity:1;visibility:visible}}
.nav__inner{display:flex;align-items:center;gap:8px;width:100%}
.nav__brand{display:flex;align-items:center;min-height:44px;gap:9px;font-size:var(--t-heading-sm);
  font-weight:700;letter-spacing:-.02em;color:var(--ink);flex:none}
.nav__links{display:none;align-items:center;gap:2px;margin-left:20px}
.nav__actions{display:flex;align-items:center;gap:var(--s-8);margin-left:auto}
/* 브랜드·가운데 메뉴·이용 버튼의 세 영역. 좌우 내용 길이와 무관하게 메뉴를 중앙에 둔다. */
@media (min-width:1024px){
  .nav--balanced .nav__inner{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:var(--s-16)}
  .nav--balanced .nav__brand{justify-self:start}
  .nav--balanced .nav__links{margin-left:0}
  .nav--balanced .nav__actions{justify-self:end;margin-left:0}
}
@media (max-width:560px){.nav__cta{display:none}}
@media (min-width:1024px){.nav__links{display:flex}}
.nav__link{display:inline-flex;align-items:center;height:44px;padding-inline:12px;
  border-radius:var(--r-sm);font-size:var(--t-body-sm);font-weight:500;color:var(--ink-muted);
  transition:background-color var(--d-2) var(--ease-inout),color var(--d-2) var(--ease-inout)}
@media (hover:hover){.nav__link:hover{background:var(--tint);color:var(--ink)}}
.nav__link:active{background:var(--tint-active)}
.nav__link[aria-current]{color:var(--ink);font-weight:600}

/* 모바일 서랍 */
.drawer{position:fixed;inset:0;z-index:var(--z-scrim);visibility:hidden}
.drawer[data-open]{visibility:visible}
/* 닫힌 서랍 안의 열린 아코디언 패널(visibility:visible)이 서랍의 hidden 을 이겨 Tab 순서에 들어가지 않게 */
.drawer:not([data-open]) .accordion__panel[data-open]{visibility:hidden}
.drawer__scrim{position:absolute;inset:0;background:var(--scrim);opacity:0;
  transition:opacity var(--d-4) var(--ease-inout)}
.drawer[data-open] .drawer__scrim{opacity:1}
.drawer__panel{position:absolute;top:0;right:0;bottom:0;width:min(84vw,340px);
  background:var(--surface);box-shadow:var(--sh-xl);overflow-y:auto;overscroll-behavior:contain;
  padding:calc(var(--safe-t) + 16px) 20px calc(var(--safe-b) + 24px);
  translate:100% 0;transition:translate var(--d-5) var(--ease-sheet)}
.drawer[data-open] .drawer__panel{translate:0 0}
.drawer__item{display:flex;align-items:center;min-height:54px;
  font-size:var(--t-body-lg);font-weight:600;color:var(--ink);
  box-shadow:inset 0 -1px 0 var(--line);-webkit-tap-highlight-color:transparent;
  transition:color var(--d-1) var(--ease-inout)}
.drawer__item:active{color:var(--accent-text)}
.drawer__item[aria-current]{color:var(--accent-text)}
.drawer__item:focus-visible{outline-offset:-2px}

/* ══ 푸터 ══════════════════════════════════════════════ */
.footer{padding-top:80px;padding-bottom:40px;position:relative;overflow:clip}
.footer__grid{display:grid;gap:40px 24px;grid-template-columns:repeat(2,minmax(0,1fr))}
@media (min-width:768px){.footer__grid{grid-template-columns:1.4fr repeat(3,minmax(0,1fr))}}
.footer__title{font-size:var(--t-caption);font-weight:700;color:var(--ink);margin-bottom:14px}
.footer__link{display:flex;align-items:center;min-height:var(--c-md-h);padding-block:var(--s-2);font-size:var(--t-body-sm);color:var(--ink-muted);
  transition:color var(--d-2) var(--ease-inout)}
@media (hover:hover){.footer__link:hover{color:var(--ink)}}
.footer__legal{margin-top:56px;padding-top:24px;box-shadow:inset 0 1px 0 var(--line);
  font-size:var(--t-micro);color:var(--ink-subtle);line-height:1.8}

/* ══ 스켈레톤 ══════════════════════════════════════════ */
/* 반투명 틴트로 칠해 흰 바탕·카드·다크 면 어디에 얹어도 보인다. 불러오는 구역에는 aria-busy="true" 를 준다. */
.skel{background:linear-gradient(90deg,var(--tint) 0%,var(--tint-hover) 42%,var(--tint) 80%);
  background-size:220% 100%;animation:shimmer 1.5s var(--ease-inout) infinite;border-radius:var(--r-sm)}
.skel--circle{border-radius:50%}
.skel--line{height:14px}
.skel--line + .skel--line{margin-top:10px}
.skel--title{height:22px;width:52%;border-radius:var(--r-md);margin-bottom:16px}
.skel--block{height:140px;border-radius:var(--r-lg)}

/* ══ 빈 상태 ══════════════════════════════════════════ */
.empty{display:flex;flex-direction:column;align-items:center;text-align:center;
  gap:8px;padding:56px 24px}
.empty__art{width:56px;height:56px;display:grid;place-items:center;border-radius:var(--r-lg);
  background:var(--canvas-alt);color:var(--ink-subtle);margin-bottom:10px}
/* 심볼 빈 상태(ui_empty brand: true): 서비스를 처음 열었을 때처럼 화면 전체가 빈 곳에서만. 목록 하나가 빈 곳은 아이콘을 쓴다 */
.empty__art--brand{width:auto;height:auto;background:none;border-radius:0;margin-bottom:var(--s-12)}
.empty__title{font-size:var(--t-heading-sm);font-weight:600;color:var(--ink)}
.empty__desc{color:var(--ink-muted);font-size:var(--t-body-sm);max-width:28rem}

/* ══ 표 ══════════════════════════════════════════════ */
.table-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}
.table{font-size:var(--t-body-sm)}
.table th{text-align:left;font-size:var(--t-micro);font-weight:600;color:var(--ink-subtle);
  letter-spacing:.04em;text-transform:uppercase;padding:0 16px 10px 0;white-space:nowrap;
  box-shadow:inset 0 -1px 0 var(--line)}
.table td{padding:13px 16px 13px 0;color:var(--ink-body);word-break:keep-all;overflow-wrap:anywhere;
  box-shadow:inset 0 -1px 0 var(--line);vertical-align:middle}
/* 첫·끝 칸 안쪽 여백: 줄에 올리면 칠해지는 면이 글자·체크·버튼에 붙지 않게(.table-dense 와 같은 12) */
.table :is(th,td):first-child{padding-left:var(--s-12)}
.table :is(th,td):last-child{padding-right:var(--s-12)}
.table tbody tr:last-child td{box-shadow:none}
.table tbody tr{transition:background-color var(--d-1) var(--ease-inout)}
@media (hover:hover){.table tbody tr:hover{background:var(--tint)}}
/* 숫자 칸은 오른쪽 정렬·숫자 폭 고정 */
.table :is(th,td).num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
/* 긴 칸: 두 줄까지 보이고 나머지는 말줄임. 전체 문장은 title 로 */
.table__clip{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;
  min-width:160px;max-width:28rem;word-break:keep-all;overflow-wrap:anywhere}
/* 정렬 머리: th 에 aria-sort, 안에 button.table__sort. 방향은 화살표 모양과 aria-sort 로 알린다. */
/* 버튼은 글자 줄 높이 그대로 두고(머리 글자들과 기준선이 같게) 여백은 음수 마진으로 상쇄한다. 누르는 범위는 ::before 로 위아래 44px. */
.table__sort{position:relative;display:inline-flex;align-items:center;gap:4px;margin:-6px -6px;padding:6px;
  border-radius:var(--r-sm);font:inherit;letter-spacing:inherit;text-transform:inherit;color:inherit;cursor:pointer;
  transition:color var(--d-1) var(--ease-inout),background-color var(--d-1) var(--ease-inout)}
.table__sort::before{content:"";position:absolute;inset:-9px 0}
@media (hover:hover){.table__sort:hover{color:var(--ink-body);background:var(--tint)}}
.table__sort::after{content:"";width:10px;height:10px;flex:none;background:currentColor;opacity:.45;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M5 1 8 4H2zM5 9 2 6h6z'/%3E%3C/svg%3E") center/contain no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M5 1 8 4H2zM5 9 2 6h6z'/%3E%3C/svg%3E") center/contain no-repeat}
.table th[aria-sort="ascending"],.table th[aria-sort="descending"]{color:var(--ink)}
.table th[aria-sort="ascending"] .table__sort::after{opacity:1;
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M5 2 8.5 6.5h-7z'/%3E%3C/svg%3E");
          mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M5 2 8.5 6.5h-7z'/%3E%3C/svg%3E")}
.table th[aria-sort="descending"] .table__sort::after{opacity:1;
  -webkit-mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M5 8 1.5 3.5h7z'/%3E%3C/svg%3E");
          mask-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E%3Cpath d='M5 8 1.5 3.5h7z'/%3E%3C/svg%3E")}
/* 빈 표: 머리는 두고 본문 한 칸에 안내 */
.table__empty td{padding:40px 16px;text-align:center;color:var(--ink-muted);box-shadow:none}
.table tbody tr.table__empty:hover{background:none}

/* ══ 애니메이션 ════════════════════════════════════════
   등장 ease-out(빠르게 나와 길게 멈춤), 퇴장 ease-in(천천히 시작해 빠르게 사라짐)·더 짧게. docs/02 모션 표. */
@keyframes spin{to{transform:rotate(1turn)}}
@keyframes shimmer{from{background-position:200% 0}to{background-position:-40% 0}}
@keyframes fade-in{from{opacity:0}to{opacity:1}}
@keyframes fade-out{from{opacity:1}to{opacity:0}}
@keyframes rise{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
@keyframes pop{0%{opacity:0;transform:scale(.94)}100%{opacity:1;transform:scale(1)}}
@keyframes pop-out{from{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.97)}}
/* 손잡이로 끌다 놓으면 끌린 자리(--sheet-from, ds.js)에서 내려간다. 맨 위로 튀었다가 내려가지 않게. */
@keyframes sheet-up{from{transform:translateY(100%)}to{transform:none}}
@keyframes sheet-down{from{transform:translateY(var(--sheet-from,0px))}to{transform:translateY(100%)}}
@keyframes toast-in{from{opacity:0;transform:translateY(16px) scale(.98)}to{opacity:1;transform:none}}
@keyframes toast-out{from{opacity:1;transform:none}to{opacity:0;transform:translateY(10px) scale(.98)}}
@keyframes toast-in-top{from{opacity:0;transform:translateY(-16px) scale(.98)}to{opacity:1;transform:none}}
@keyframes toast-out-top{from{opacity:1;transform:none}to{opacity:0;transform:translateY(-10px) scale(.98)}}
@keyframes tip-in{from{opacity:0;transform:translateY(var(--tip-dy,4px))}to{opacity:1;transform:none}}
@keyframes shake{0%,100%{transform:none}20%{transform:translateX(-6px)}40%{transform:translateX(5px)}60%{transform:translateX(-3px)}80%{transform:translateX(2px)}}

.overlay[data-state="open"] .overlay__scrim{animation:fade-in var(--d-4) var(--ease-inout) both}
.overlay[data-state="closing"] .overlay__scrim{animation:fade-out var(--d-3) var(--ease-inout) both}
.overlay[data-state="open"] .sheet{animation:sheet-up var(--d-5) var(--ease-sheet) both}
.overlay[data-state="closing"] .sheet{animation:sheet-down var(--d-3) var(--ease-in) both}
.overlay[data-state="open"] .modal{animation:pop var(--d-4) var(--ease-out) both}
.overlay[data-state="closing"] .modal{animation:pop-out var(--d-2) var(--ease-in) both}
/* 좁은 화면의 .modal 은 아래 시트 모양이므로 움직임도 시트처럼 */
@media (max-width:640px){
  .overlay[data-state="open"] .modal{animation:sheet-up var(--d-5) var(--ease-sheet) both}
  .overlay[data-state="closing"] .modal{animation:sheet-down var(--d-3) var(--ease-in) both}
}
.menu[data-state="open"]{animation:pop var(--d-2) var(--ease-out) both}
.menu[data-state="closing"]{animation:pop-out var(--d-1) var(--ease-in) both;pointer-events:none}
.toast{animation:toast-in var(--d-4) var(--ease-out) both}
.toast[data-out]{animation:toast-out var(--d-3) var(--ease-in) both}
html[data-overlay-open] .toast{animation-name:toast-in-top}
html[data-overlay-open] .toast[data-out]{animation-name:toast-out-top}
@media (min-width:768px){
  .overlay[data-state="open"] .sheet{animation:pop var(--d-4) var(--ease-out) both}
  .overlay[data-state="closing"] .sheet{animation:pop-out var(--d-2) var(--ease-in) both}
}
/* 모션 축소: 움직임은 거의 0 으로, 결과 상태는 그대로(끝 상태로 바로 간다) */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;
    transition-duration:.01ms !important;scroll-behavior:auto !important}
  .skel{animation:none}
}

/* ══ 선택기 ══════════════════════════════════════════
   네이티브 select 의 목록은 OS 가 그려서 디자인이 먹지 않는다.
   이 컴포넌트는 목록까지 우리가 그린다. 좁은 화면에서는 하단 시트가 된다.
   버튼은 입력칸과 같은 치수·상태(호버·포커스·열림·오류·비활성)를 가진다. */
.picker{position:relative;display:block;width:100%;min-width:0}
.picker__btn{display:flex;align-items:center;gap:10px;width:100%;
  min-height:var(--c-md-h);padding:9px 14px;
  background:var(--canvas-alt);color:var(--ink);
  border:1px solid var(--line);border-radius:var(--c-md-r);
  font-size:var(--t-body-md);line-height:24px;text-align:left;cursor:pointer;
  -webkit-tap-highlight-color:transparent;
  transition:background-color var(--d-2) var(--ease-inout),
             border-color var(--d-2) var(--ease-inout),
             box-shadow var(--d-2) var(--ease-inout)}
@media (hover:hover){.picker__btn:hover:not(:disabled,[aria-expanded="true"],[aria-invalid="true"]){background:var(--canvas-sunken);border-color:var(--line-strong)}}
.picker__btn:focus-visible{outline:none;background:var(--surface);border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.picker__btn[aria-expanded="true"]{background:var(--surface);border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-soft)}
.picker__btn:disabled{color:var(--ink-disabled);cursor:not-allowed;background:var(--canvas-alt);border-color:var(--line)}
.picker__btn:disabled .picker__caret{color:var(--ink-disabled)}
.picker__value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.picker__value[data-empty]{color:var(--ink-subtle)}
.picker__caret{flex:none;color:var(--ink-subtle);
  transition:transform var(--d-3) var(--ease-out)}
.picker__btn[aria-expanded="true"] .picker__caret{transform:rotate(180deg)}
.picker__btn[aria-invalid="true"]{border-color:var(--bad);background:var(--bad-soft)}
/* 오류 면(--bad-soft) 위 빈 값·자리표시자는 한 단계 진하게(보조 글자색은 이 면에서 4.5:1 에 조금 모자란다) */
.picker__btn[aria-invalid="true"] .picker__value[data-empty],.input[aria-invalid="true"]::placeholder,.textarea[aria-invalid="true"]::placeholder{color:var(--ink-muted)}
.picker__btn[aria-invalid="true"]:focus-visible,.picker__btn[aria-invalid="true"][aria-expanded="true"]{border-color:var(--bad);box-shadow:0 0 0 3px var(--bad-soft)}
.picker--lg .picker__btn{min-height:var(--c-lg-h);border-radius:var(--c-lg-r);padding:13px 16px}
.picker--sm .picker__btn{min-height:var(--c-sm-h);border-radius:var(--c-sm-r);padding:5px 12px;
  font-size:var(--t-body-sm)}

.picker__list{position:fixed;z-index:var(--z-pop);min-width:200px;max-width:min(420px,calc(100vw - 24px));padding:6px;
  background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--sh-pop);
  max-height:min(62vh,420px);overflow-y:auto;overscroll-behavior:contain;transform-origin:top left}
.picker__list[data-side="top"]{transform-origin:bottom left}
.picker__opt{display:flex;align-items:center;gap:10px;width:100%;min-height:44px;
  padding:10px 12px;border-radius:var(--r-sm);text-align:left;cursor:pointer;
  font-size:var(--t-body-sm);line-height:var(--t-body-sm-lh);color:var(--ink-body);
  word-break:keep-all;overflow-wrap:anywhere;-webkit-tap-highlight-color:transparent;
  transition:background-color var(--d-1) var(--ease-inout)}
@media (hover:hover){.picker__opt:hover:not(:disabled,[aria-disabled="true"]){background:var(--tint)}}
.picker__opt[data-active]{background:var(--tint)}
.picker__opt:focus-visible{background:var(--tint-hover);outline:2px solid var(--focus);outline-offset:-2px}
/* 고른 항목: 연한 강조 면 + 굵은 강조 글자 + 체크. */
.picker__opt[aria-selected="true"]{color:var(--accent-text);font-weight:600;background:var(--accent-soft)}
.picker__opt:disabled,.picker__opt[aria-disabled="true"]{color:var(--ink-disabled);cursor:not-allowed}
.picker__opt[hidden]{display:none}
.picker__opt-mark{margin-left:auto;flex:none;opacity:0}
.picker__opt[aria-selected="true"] .picker__opt-mark{opacity:1}
/* 항목 아래 한 줄 설명(.picker__opt 안에 .picker__opt-text > 글 + .picker__opt-sub) */
.picker__opt-text{flex:1;min-width:0;display:flex;flex-direction:column}
.picker__opt-sub{font-size:var(--t-caption);line-height:var(--t-caption-lh);font-weight:400;color:var(--ink-muted)}
.picker__group{padding:10px 12px 4px;font-size:var(--t-nano);font-weight:600;letter-spacing:.05em;color:var(--ink-subtle)}
/* 긴 목록 검색(data-picker-search, ds.js 가 목록 맨 위에 넣는다). 스크롤해도 위에 붙어 있다. */
.picker__search{position:sticky;top:-6px;z-index:1;margin:-6px -6px 6px;padding:6px;background:var(--surface)}
.picker__search .input{min-height:var(--c-sm-h);padding:5px 12px 5px 36px;border-radius:var(--c-sm-r);
  background:var(--canvas-alt) no-repeat 12px center / 16px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'%3E%3Ccircle cx='11' cy='11' r='6.5' stroke='%238C939D' stroke-width='1.8'/%3E%3Cpath d='M16 16l4 4' stroke='%238C939D' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E")}
.picker__empty{padding:20px 12px;text-align:center;font-size:var(--t-body-sm);color:var(--ink-muted)}
.picker__empty[hidden]{display:none}
.picker__list[data-state="open"]{animation:pop var(--d-2) var(--ease-out) both}
.picker__list[data-state="closing"]{animation:pop-out var(--d-1) var(--ease-in) both;pointer-events:none}
@media (max-width:639px){
  .picker__list{left:0 !important;right:0 !important;top:auto !important;bottom:0 !important;
    width:auto;max-width:none;max-height:72dvh;border-radius:var(--r-3xl) var(--r-3xl) 0 0;
    padding:10px 10px calc(10px + var(--safe-b));box-shadow:var(--sh-xl)}
  .picker__list::before{content:"";display:block;width:36px;height:4px;border-radius:var(--r-full);
    background:var(--line-strong);margin:2px auto 10px}
  .picker__opt{min-height:52px;font-size:var(--t-body-md);line-height:var(--t-body-md-lh)}
  .picker__search{top:-10px;margin:-10px -10px 6px;padding:10px}
  .picker__search .input{min-height:var(--c-md-h);padding-block:9px}
  .picker__list[data-state="open"]{animation:sheet-up var(--d-5) var(--ease-sheet) both}
  .picker__list[data-state="closing"]{animation:sheet-down var(--d-3) var(--ease-in) both}
}
.picker__scrim{position:fixed;inset:0;z-index:calc(var(--z-pop) - 1);background:transparent}
@media (max-width:639px){
  .picker__scrim{background:var(--scrim);animation:fade-in var(--d-4) var(--ease-inout) both}
  .picker__scrim[data-out]{animation:fade-out var(--d-3) var(--ease-inout) both}
}
/* 시트·창·서랍 안에서 연 목록은 그 위 층으로 올린다(ds.js 가 data-layer="top"). 덮개는 한 칸 아래. */
.menu[data-layer="top"],.picker__list[data-layer="top"]{z-index:calc(var(--z-toast) - 10)}
.menu__scrim[data-layer="top"],.picker__scrim[data-layer="top"]{z-index:calc(var(--z-toast) - 11)}
/* 폼 버튼(Rails button_to)이 메뉴 항목일 때 폼 상자가 줄을 차지하지 않게 */
.menu form.button_to,.menu > form{display:contents}

/* ══ 아이콘 ══════════════════════════════════════════
   assets/icons.svg 의 심볼을 쓴다. 색은 currentColor 를 따른다.
   <svg class="ico"><use href="/design-system/assets/icons.svg#ico-phone"/></svg> */
.ico{width:20px;height:20px;flex:none;display:inline-block;vertical-align:middle}
.ico--sm{width:16px;height:16px}
.ico--lg{width:24px;height:24px}
.ico--xl{width:32px;height:32px}

/* 외부 서비스 식별 마크. 원본 로고는 assets/providers와 출처 문서에서 관리한다. */
.provider-mark{display:inline-block;flex:none;width:var(--s-24);height:var(--s-24);object-fit:contain;vertical-align:middle}
.provider-mark--kakao{background:#FEE500;border-radius:var(--r-sm);padding:var(--s-4)}
/* 검은 선이 든 로고(Telegram·WhatsApp)는 다크 모드에서도 밝은 바탕(logo-plate)에 올린다. 카카오는 브랜드 노란 바탕. */
.provider-mark--telegram,.provider-mark--whatsapp{background:var(--logo-plate);border-radius:var(--r-sm);padding:var(--s-2)}

/* 음성 듣기: 한 번 누르면 재생, 기본 속도 1.2배. 두 줄로 둔다.
   위 줄은 재생 버튼·지금 위치/전체 길이(0:12 / 1:30)·속도, 아래 줄은 화면 폭을 다 쓰는 위치 막대(적중 높이 44px).
   360px 에서도 막대가 짧아지지 않게 버튼과 한 줄에 두지 않는다. */
.audio-player{display:flex;flex-direction:column;gap:var(--s-4);width:100%;padding:var(--s-8) var(--s-12);border-radius:var(--r-xl);background:var(--canvas-alt)}
.audio-player>audio{display:none}
.audio-player__bar{display:flex;align-items:center;gap:var(--s-8);min-width:0}
.audio-player .btn{flex:none;white-space:nowrap}
/* 속도 버튼은 글자만큼만(적중 폭 44px 유지). 카드 안 360px 에서도 '0:12 / 1:30' 이 잘리지 않게 시간 칸에 자리를 준다. */
.audio-player .audio-player__speed{--px:var(--s-8);min-width:var(--c-md-h)}
.audio-player__time{flex:1;min-width:0;font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.audio-player__seek{display:block;width:100%;min-width:0;margin:0;accent-color:var(--accent);height:var(--c-md-h);cursor:pointer}
.audio-player__seek:disabled{cursor:default}

/* 테마 잠금(<html data-theme-lock>): 테마 바꾸기 버튼을 숨긴다(docs/20_theme.md) */
[data-theme-lock] [data-theme-toggle]{display:none}
