@charset "UTF-8";
/* ============================================================================
 * Aura AI — Glassmorphism 커스텀 유틸리티 / 컴포넌트 스타일
 * ----------------------------------------------------------------------------
 * 로드 순서 (index.html <head>):
 *   1) https://cdn.tailwindcss.com?plugins=forms,typography
 *   2) js/tailwind.config.js      ← 테마 토큰 주입
 *   3) css/glassmorphism.css      ← 이 파일
 *
 * ※ Tailwind CDN(JIT)은 "외부 CSS 파일 안의 @apply 를 처리하지 않는다."
 *    따라서 이 파일은 순수 CSS 로만 작성하며, 값은 js/tailwind.config.js 의
 *    토큰과 1:1로 동기화되어 있다. 값을 바꿀 때는 두 파일을 함께 수정할 것.
 *
 * 디자인 방향: 거의 흰색에 가까운 페일 블루 배경 + 뿌옇게 번진 소프트 Orb
 * ==========================================================================*/

/* ---------------------------------------------------------------------------
 * 1. FONT
 * ------------------------------------------------------------------------ */
/* 모든 페이지가 이 파일을 로드하므로 @font-face 도 여기에 둔다.
 * (chat.css 에 두면 chat.css 를 로드하지 않는 index.html 에서 폰트가 빠진다) */
@font-face {
  font-family: 'Pretendard Variable';
  font-weight: 45 920;      /* 가변 축 범위 */
  font-style: normal;
  font-display: swap;       /* FOIT 방지 — 시스템 폰트로 먼저 렌더 */
  src: url('../fonts/Pretendard/PretendardVariable.woff2') format('woff2-variations');
}

/* ---------------------------------------------------------------------------
 * 2. DESIGN TOKENS
 * ------------------------------------------------------------------------ */
:root {
  /* Ink — 텍스트 전용 */
  --ink-950: #0A1E3D;   /* 16.6:1 */
  --ink-900: #0F2A4F;   /* 14.3:1 */
  --ink-800: #134074;   /* 10.4:1 */
  --ink-600: #1D4ED8;   /*  6.7:1 */
  --ink-500: #2F79C8;   /*  4.5:1 미만 — 대형 텍스트·아이콘·보더 전용 */

  /* Body */
  --body-700: #334155;
  --body-600: #475569;   /* 글래스 위 본문/캡션 최소 색상 */

  /* Brand 액센트 (헤딩 강조어) — 시안 / 하늘 / 파랑
     배경 이미지(img_bg_mesh_a.png)에 분홍이 한 점도 없다. 트리오의 따뜻한 끝을
     분홍에서 시안으로 옮겨 세 색 모두 배경 구체에서 뽑아낸 색이 되게 했다.
     괄호 안은 흰 배경 대비율 — 셋 다 AA(4.5:1) 위. */
  --brand-cyan: #0E7490;   /* 5.4:1 */
  --brand-sky:  #0369A1;   /* 6.4:1 */
  --brand-blue: #1D4ED8;   /* 6.7:1 */

  /* 링크 밑줄 — 채팅의 앵커·링크가 '눌러서 더 볼 수 있다'고 말하는 한 가지 색.
     글자는 --ink-600 으로 읽고 이 색은 밑줄·테두리에만 얹는다(알파가 낮아 글자로는 흐리다).
     .md a · .vlink · .pcell__a · 삽입 화면 버튼이 모두 이 하나를 쓴다. */
  --link-line: rgba(56, 152, 208, .55);

  /* Pastel — 장식용 선명한 트리오 */
  --pastel-cyan: #31C5EA;
  --pastel-sky:  #4BA4F8;
  --pastel-blue: #1464F0;

  /* Glass 표면 */
  --glass-50:  rgba(255, 255, 255, .62);   /* 패널 표면 — .glass-card 와 같은 값 */
  --glass-100: rgba(255, 255, 255, .78);
  --glass-200: rgba(255, 255, 255, .88);
  --glass-300: rgba(255, 255, 255, .95);
  --glass-stroke: rgba(255, 255, 255, .85);

  /* Elevation — 회색이 아닌 옅은 블루 그림자 */
  --shadow-glass-sm: 0 1px 2px rgba(70, 95, 170, .04), 0 6px 18px -10px rgba(70, 95, 170, .20);
  --shadow-glass:    0 1px 3px rgba(70, 95, 170, .05), 0 14px 36px -18px rgba(70, 95, 170, .28);
  --shadow-glass-lg: 0 2px 6px rgba(70, 95, 170, .06), 0 32px 64px -28px rgba(70, 95, 170, .34);
  /* Orb — 넓은 60px bloom 은 구체 윤곽을 지운다. 접지 그림자를 좁게 잡고
     번짐은 절반으로 줄여 가장자리가 배경과 분리되게 한다. */
  --shadow-orb:      0 4px 10px -4px rgba(58, 96, 196, .22), 0 18px 32px -14px rgba(58, 96, 196, .45), 0 0 32px rgba(160, 195, 255, .30);

  /* Gradient — 시안 → 하늘 → 파랑
     배경 이미지의 구체가 시안에서 파랑으로 넘어가는 그 흐름을 그대로 쓴다.
     ※ 방향을 잡을 때 파랑 쪽 끝을 유지한 이유: 이 그라데이션 위에는 흰
       글자·아이콘이 올라간다. 밝은 시안을 끝에 두면 44px 버튼처럼 작은
       면적에서 밝은 구간만 샘플링돼 흰 글리프가 사라진다.
     흰 텍스트 대비는 2.4~3.9:1 로 WCAG AA(4.5:1) 아래다. 가독성을
     우선하려면 아래 --on-brand 를 #0A1E3D 로 바꾸면 전 구간 7:1 이상이 된다. */
  --grad-primary: linear-gradient(135deg, #0E7BBE 0%, #1C6FD6 48%, #0F4BD8 100%);
  /* 질문 말풍선 — 시안 → 하늘 → 파랑.
     좌상단에서 시안으로 시작해 우하단 파랑으로 가라앉는다. 방향을 뒤집으면
     안 된다: 이 위에는 흰 글자가 올라가는데, 흰 대비는 시안 쪽이 2.4:1,
     파랑 쪽이 4.9:1 이다. 밝은 끝을 말풍선 아래로 보내면 글줄 끝마다 글자가
     흐려진다. 시안을 더 밝게(#22C9E8 등) 올리면 2.1:1 밑으로 떨어진다. */
  --grad-bubble:  linear-gradient(135deg, #14B5D8 0%, #2E9BE8 48%, #1C6FD6 100%);
  --grad-soft:    linear-gradient(135deg, #31C5EA 0%, #4BA4F8 50%, #1464F0 100%);

  /* 상태 그라데이션 (정식 / 테스트)
     새 색을 들이지 않고 --grad-primary 의 트리오를 둘로 나눠 쓴다.
       정식   = 하늘 → 파랑   — 깊은 쪽. 검증된 도구
       테스트 = 시안 → 하늘   — 밝은 쪽. 실험 중인 도구
     분홍을 뺀 뒤로는 두 계열이 같은 파랑 안에 있어 색상만으로는 안 갈린다.
     대신 명도로 가른다 — 테스트 쪽을 두 단계 밝게(#16CFD8) 띄워야 나란히
     놓았을 때 "밝은 것 / 깊은 것" 두 무리로 읽힌다. 이 간격을 좁히면
     두 배지가 같은 색으로 보이니 밝기 차를 유지할 것.
     -v 는 세로용. 폭 3px 세로 바에 135deg 를 쓰면 거의 단색으로 보인다. */
  --grad-official:   linear-gradient(135deg, #3E8EF0 0%, #1C6FD6 100%);
  --grad-official-v: linear-gradient(180deg, #3E8EF0 0%, #1C6FD6 100%);
  --grad-test:       linear-gradient(135deg, #16CFD8 0%, #0E7BBE 100%);
  --grad-test-v:     linear-gradient(180deg, #16CFD8 0%, #0E7BBE 100%);
  /* 각 계열의 접지 그림자 — 타일 색과 다른 색의 그림자가 깔리면 떠 보인다 */
  --shadow-official: 0 4px 10px -4px rgba(70, 110, 215, .5);
  --shadow-test:     0 4px 10px -4px rgba(24, 165, 200, .45);

  /* 헤딩 강조어용 텍스트 그라데이션 — 흰 배경에서 전 구간 3:1 이상
     (대형 텍스트 기준. 20px 미만 본문에는 쓰지 않는다)
     ※ 시안 끝(#0895B4, 3.5:1)은 --pastel-cyan 보다 훨씬 어둡다. 장식용
       시안을 그대로 글자에 쓰면 2:1 밑으로 떨어져 읽히지 않는다. */
  --grad-text:    linear-gradient(100deg, #0895B4 0%, #2A7FE0 45%, #1C6FD6 100%);

  /* 그라데이션 위 전경색 — 한 곳에서 흰색/잉크 전환 */
  --on-brand: #FFFFFF;

  /* 입력창 포커스 글로우 — 경계선 없이 번짐만으로 만든다.
     blur 를 6 → 14 → 24 로 키우면서 alpha 는 .30 → .18 → .12 로 떨어뜨린다.
     세 겹이 겹쳐 하나의 매끄러운 falloff 로 읽히는 게 목적이라, 색은 같은
     파랑 계열로 묶고 단계 사이 간격을 일정하게 벌려두었다.
     번짐 폭을 조절할 땐 blur 만 비율로 줄이고 alpha 는 그대로 두는 게 낫다 —
     alpha 까지 같이 내리면 좁아지는 게 아니라 그냥 흐려진다. */
  --focus-near: rgba(28, 111, 214, .30);
  --focus-mid:  rgba(62, 142, 240, .18);
  --focus-far:  rgba(107, 178, 248, .12);

  --ease-glass: cubic-bezier(.16, 1, .3, 1);
}

/* ---------------------------------------------------------------------------
 * 3. BASE
 * ------------------------------------------------------------------------ */
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: 'Pretendard Variable', Pretendard, system-ui, -apple-system, 'Segoe UI', sans-serif;
  color: var(--ink-950);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  word-break: keep-all;          /* 한글 단어 단위 줄바꿈 */
}

/* ---------- 스크롤바 ----------------------------------------------------
 * 기본 회색 스크롤바는 페일 블루 배경 위에서 유독 탁해 보인다.
 * 트랙을 투명하게 두고, 썸만 반투명 글래스 알약으로 띄운다.
 * Firefox 는 scrollbar-* 표준 속성, Chromium/Safari 는 ::-webkit-* 사용. */
* {
  scrollbar-width: thin;
  scrollbar-color: rgba(120, 150, 220, .45) transparent;
}

::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  border-radius: 9999px;
  /* 트랙과의 여백은 투명 테두리로 만든다 (배경이 비쳐 보이도록) */
  border: 3px solid transparent;
  background-clip: content-box;
  background-color: rgba(120, 150, 220, .40);
}
::-webkit-scrollbar-thumb:hover {
  background-color: rgba(28, 111, 214, .60);   /* --grad-primary 의 파랑 */
}
::-webkit-scrollbar-thumb:active {
  background-color: rgba(28, 111, 214, .80);
}
::-webkit-scrollbar-corner {
  background: transparent;
}

/* 카드 내부처럼 좁은 영역은 더 얇게 */
.scroll-slim::-webkit-scrollbar { width: 6px; height: 6px; }
.scroll-slim::-webkit-scrollbar-thumb { border-width: 2px; }

/* 전역 포커스 링 — 여기 한 곳에서만 정의한다. 개별 요소에 붙일 필요 없음.
   box-shadow 가 아닌 outline 을 쓰는 이유: Tailwind 의 shadow-* 유틸리티가
   나중에 주입되어 포커스 링을 덮어쓰는 사고를 원천 차단하기 위함. */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--ink-600);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
 * 4. GLASS SURFACES
 * ------------------------------------------------------------------------ */
/* 글래스 강도 3단계 ─────────────────────────────────────────────────────────
 * 전부 똑같이 투명하면 텍스트가 지저분해지고, 전부 불투명하면 유리가 아니다.
 * 카드가 담는 내용의 "텍스트 밀도"에 따라 3단계로 나눈다.
 *
 *   .glass-card--sheer : 55%  텍스트 적고 여백 큰 카드 (Orb, 컴포저, 히어로)
 *   .glass-card        : 72%  표준
 *   .glass-card--solid : 90%  본문·리스트가 빽빽한 카드 (대화, 최근 목록)
 *
 * 뒤에 색이 없으면 blur 는 아무것도 못 만든다. 배경 블룸(pastel 단계)이
 * 카드 아래를 지나가도록 배치되어 있어야 이 단계 구분이 의미를 갖는다.
 * ------------------------------------------------------------------------ */
.glass-card,
.glass-group,
.nav-tile,
.rail-tile,
.avatar-plain {
  position: relative;
  border-radius: 1.75rem;                      /* 28px */
  background-color: rgba(255, 255, 255, .62);
  /* 대각선 스페큘러 — 유리 표면에 빛이 스치는 느낌.
     배경을 차분하게 유지한 채 "유리다움"을 만드는 주된 장치. */
  background-image: linear-gradient(125deg,
      rgba(255, 255, 255, .55) 0%,
      rgba(255, 255, 255, 0)   34%,
      rgba(255, 255, 255, 0)   62%,
      rgba(255, 255, 255, .30) 100%);
  border: 1px solid rgba(255, 255, 255, .9);
  box-shadow:
    0 1px 3px rgba(70, 95, 170, .06),
    0 20px 48px -22px rgba(70, 95, 170, .38),
    /* 유리 두께감: 좌상단 밝은 림 + 우하단 옅은 반사 + 안쪽 확산광 */
    inset 1px 1px 0 rgba(255, 255, 255, 1),
    inset -1px -1px 0 rgba(255, 255, 255, .55),
    inset 0 0 40px rgba(255, 255, 255, .22);
  /* saturate 를 크게 올리면 카드 "안쪽"만 색이 진해진다.
     배경은 차분한데 유리를 통과한 부분만 또렷해져 굴절처럼 읽힌다. */
  -webkit-backdrop-filter: blur(26px) saturate(215%) brightness(1.03);
  backdrop-filter: blur(26px) saturate(215%) brightness(1.03);
}

/* 굴절광 테두리 — 한쪽만 밝게 빛나는 1px 그라데이션 링.
   mask 로 테두리 영역만 남겨 배경색을 가리지 않는다. */
.glass-card::after,
.glass-group::after,
.nav-tile::after,
.rail-tile::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1.5px;
  pointer-events: none;
  background: linear-gradient(140deg,
              rgba(255, 255, 255, 1)   0%,
              rgba(255, 255, 255, .35) 26%,
              rgba(255, 255, 255, 0)   48%,
              rgba(255, 255, 255, .2)  72%,
              rgba(255, 255, 255, .85) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}

/* 투명도 높은 변형 — 뒤 색이 확실히 비친다
   (.glass-group 은 여기서 뺐다 — 아래 --crystal 로 내려갔다) */
.glass-card--sheer,
.nav-tile,
.rail-tile,
.avatar-plain {
  background-color: rgba(255, 255, 255, .46);
  -webkit-backdrop-filter: blur(30px) saturate(235%) brightness(1.04);
  backdrop-filter: blur(30px) saturate(235%) brightness(1.04);
}

/* aside 유리만의 예외 — 딱 두 가지 ─────────────────────────────────────────
 * 재질은 컴포저와 완전히 같다(위 두 규칙을 그대로 공유한다). 값을 따로 적어
 * 두면 한쪽만 고쳤을 때 조용히 어긋나므로, 여기서는 뺄 것만 뺀다.
 *   1) 테두리 — border 1px 과 inset 흰 림 1px 이 겹쳐 실질 2px 이었다
 *   2) 바깥 그림자 — #aside 가 overflow-hidden 이라 잘려 보인다
 * inset 확산광은 요소 안쪽이라 잘리지 않으니 남긴다. */
.rail-tile,
.avatar-plain {
  border-color: rgba(255, 255, 255, .5);
  box-shadow: inset 0 0 40px rgba(255, 255, 255, .22);
}

/* .nav-tile 은 예외에서 뺀다 — 런처 버튼 4개는 #chat_composer_box 와
   완전히 같은 유리여야 한다. 테두리(.9)도 바깥 그림자도 컴포저 그대로 받는다. */

/* 판유리 — 흰 판을 거의 지우고 굴절과 반사만 남긴 4단계.
 * --sheer(46%)가 "색이 비치는 흰 유리"라면 이쪽은 유리 그 자체다.
 *
 * 흰 판을 18% 까지 내리면 유리다움은 커지지만 두 가지가 무너진다.
 *   ① 뒤로 진한 파랑 구체가 지나갈 때 본문 대비가 떨어진다
 *      → blur 를 30 → 44px 로 키워 뒤 형체를 완전히 뭉갠다. 색은 남고
 *        형체만 사라지므로 대비는 지키면서 "비친다"는 인상은 유지된다.
 *        투명도를 더 내리고 싶다면 blur 를 먼저 올릴 것 — 순서가 반대면
 *        글자 뒤로 배경 무늬가 그대로 읽힌다.
 *   ② 흰 판이 사라지면 카드의 경계도 같이 사라진다
 *      → 경계를 배경색이 아니라 테두리 한 겹으로만 만든다. border 는
 *        투명으로 비우고 아래 ::after 그라데이션 링이 혼자 그 일을 한다.
 * ------------------------------------------------------------------------ */
.glass-card--crystal,
.glass-group {
  /* 면은 이 그라데이션 한 장이 전부다 — 위 흰색 30%, 아래 0.
     스페큘러 띠도, 상단 반사(.glass-sheen)도, 안쪽 확산광도 얹지 않는다.
     그런 장치는 저마다 흰색을 조금씩 더해서, 결과적으로 면이 30 → 0 이
     아니게 만든다. 흰색이 들어가는 자리는 아래 1px 림과 ::after 테두리 링,
     두 곳의 "가장자리"뿐이다.
     ※ 아래쪽 힌트 문구(Enter 전송…)는 흰 받침 없이 배경 위에 바로 놓인다.
       흐려 보이면 알파를 올리지 말고 문구 색을 slate-600 → ink-800 으로
       내릴 것. 알파를 올리면 아래가 다시 판이 된다. */
  background-color: transparent;
  background-image: linear-gradient(180deg,
      rgba(255, 255, 255, .30) 0%,
      rgba(255, 255, 255, 0)   100%);
  border-color: transparent;
  box-shadow:
    0 2px 6px -1px rgba(88, 92, 104, .10),
    0 12px 22px -10px rgba(88, 92, 104, .26),
    0 30px 60px -24px rgba(88, 92, 104, .44),
    /* 유리 두께 — 1px 짜리 위아래 림. 면이 아니라 가장자리다 */
    inset 0 1px 0 rgba(255, 255, 255, .95),
    inset 0 -1px 0 rgba(255, 255, 255, .40);
  /* 유리가 뒤에 하는 일을 최소로. 뒤 배경이 그대로 보이는 게 목적이다.
       blur 6px    — 뒤 형체를 알아볼 수 있는 정도. 44px 는 배경을 통째로
                     뭉개서 "투명한 유리"가 아니라 "젖빛 유리"가 된다.
       saturate 1  — 증폭도 탈색도 하지 않는다. 유리가 색에 아무 짓도 안 한다.
     ※ 여기서 보이는 파랑은 유리가 만든 색이 아니라 뒤 배경 그 자체다.
       유리를 탓해서 saturate 를 1 밑으로 내리면 배경이 회색으로 죽는다 —
       투명하게 만드는 것과 정반대다. 파랑을 줄이려면 유리가 아니라 뒤에
       있는 것(배경 이미지, --bg-scrim)을 손볼 것.
     ※ 두 줄을 반드시 함께 유지할 것. 접두사 없는 backdrop-filter 를 지우거나
       주석 처리하면, 그 속성을 쓰는 엔진에서 .glass-card 기본값인
       blur(26px) saturate(215%) 가 되살아난다. */
  -webkit-backdrop-filter: blur(6px) saturate(100%);
          backdrop-filter: blur(6px) saturate(100%);
}

/* 테두리 — 1px 흰 그라데이션 한 겹.
   .glass-card::after 의 1.5px 링을 얇게 줄인 것. 네 변이 고르게 빛나면
   안 된다 — 좌상단이 가장 밝고, 우하단에서 한 번 더 살아나고, 그 사이는
   거의 사라지는 게 이 링의 요점이다. 고르게 빛나면 테두리를 두른 상자로,
   끊기면 빛을 받는 유리 모서리로 읽힌다.
   ※ 배경과 마찬가지로 흰색만. 색을 넣으면 테두리를 칠한 것처럼 보인다. */
.glass-card--crystal::after,
.glass-group::after {
  padding: 1px;
  background: linear-gradient(140deg,
              rgba(255, 255, 255, 1)   0%,
              rgba(255, 255, 255, 1)   9%,    /* 좌상단 — 가장 센 반짝 */
              rgba(255, 255, 255, .45) 21%,
              rgba(255, 255, 255, .06) 34%,
              rgba(255, 255, 255, .85) 50%,   /* 중간 글린트 */
              rgba(255, 255, 255, .06) 63%,
              rgba(255, 255, 255, .60) 79%,
              rgba(255, 255, 255, 1)   100%); /* 우하단 — 다시 살아남 */
}

/* aside 유리(.glass-group)만의 예외 — 바깥 그림자를 뺀다.
   #aside 가 overflow: hidden 이라 바깥으로 나가는 3단 드롭섀도가 잘려서,
   부드러운 falloff 대신 딱 끊긴 계단으로 보인다. 위아래 1px 림만 남긴다.
   ※ 이 규칙은 반드시 --crystal 뒤에 와야 한다. 앞에 두면 crystal 의
     box-shadow 가 이걸 덮어써서 잘린 그림자가 그대로 돌아온다. */
.glass-group {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .95),
    inset 0 -1px 0 rgba(255, 255, 255, .40);
}

/* 상단 반사 없음 — .glass-sheen 이 붙어도 무시한다.
   이 카드의 면은 위 흰색 30% → 아래 0 그라데이션 한 장으로 끝이다. 여기에
   .glass-sheen 의 흰 물결이 겹치면 위쪽 알파가 30% 를 넘어서 그 한 장이
   더 이상 30 → 0 이 아니게 된다. 마크업에서 클래스를 빼도 되지만, 그러면
   다음에 누가 다시 붙였을 때 조용히 어긋난다 — 여기서 막아둔다. */
.glass-card--crystal.glass-sheen::before {
  content: none;
}

/* 텍스트가 빽빽한 카드 — 가독성 우선. 그래도 유리 티는 남긴다 */
.glass-card--solid {
  background-color: rgba(255, 255, 255, .86);
  -webkit-backdrop-filter: blur(18px) saturate(190%);
  backdrop-filter: blur(18px) saturate(190%);
}

/* 모달 패널 — 카드용 3단계와 별개로 취급한다.
 * --solid(86%) 는 "조용한 배경 위의 카드"를 전제로 한 값이라,
 * 임의의 페이지 내용 위에 뜨는 모달에서는 뒤 글자가 14% 비쳐 겹쳐 읽힌다.
 * 모달은 내용을 격리하는 게 우선이므로 96% 로 올리고, blur 를 키워
 * 남은 4% 마저 형체를 알아볼 수 없게 만든다. 유리 티(테두리·스페큘러·
 * 굴절광 링)는 .glass-card 가 그대로 유지하므로 톤은 어긋나지 않는다. */
/* .glass-modal 은 모달 골격과 함께 읽는 편이 나아 6b. MODAL 섹션에 있다 */

.glass-panel {
  background-color: var(--glass-50);
  border: 1px solid var(--glass-stroke);
  box-shadow:
    var(--shadow-glass-lg),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  /* brightness 가 빠져 있어 같은 배경 위에서도 .glass-card 보다 3~4% 어두웠다.
     유리 종류가 둘로 보이던 원인 — 카드와 같은 광학으로 맞춘다. */
  -webkit-backdrop-filter: blur(40px) saturate(200%) brightness(1.03);
  backdrop-filter: blur(40px) saturate(200%) brightness(1.03);
}

/* 카드 상단 유리 반사 — 순수 장식 */
.glass-sheen::before {
  content: '';
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 6rem;
  border-start-start-radius: inherit;
  border-start-end-radius: inherit;
  background: linear-gradient(180deg, rgba(255, 255, 255, .9) 0%, rgba(255, 255, 255, 0) 55%);
  opacity: .75;
  pointer-events: none;
}

.glass-lift {
  transition: transform .3s var(--ease-glass), box-shadow .3s var(--ease-glass);
}
.glass-lift:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-glass-lg);
}

/* ---------------------------------------------------------------------------
 * 5. COMPONENTS
 * ------------------------------------------------------------------------ */

/* 알약형 추천 칩 — 최소 44px 터치 타깃 */
.chip {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  min-height: 44px;
  padding: .625rem 1rem;
  border-radius: 9999px;
  border: 1px solid rgba(255, 255, 255, .9);
  background-color: rgba(255, 255, 255, .68);
  box-shadow:
    var(--shadow-glass-sm),
    inset 1px 1px 0 rgba(255, 255, 255, .9);
  -webkit-backdrop-filter: blur(20px) saturate(190%);
  backdrop-filter: blur(20px) saturate(190%);
  font-size: .875rem;
  font-weight: 500;
  color: var(--ink-900);
  transition: transform .3s var(--ease-glass), background-color .2s, box-shadow .3s var(--ease-glass);
}
.chip:hover {
  transform: translateY(-2px);
  background-color: #FFFFFF;
  box-shadow: var(--shadow-glass);
}

/* 아이콘 전용 버튼 — 44×44 보장 */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 9999px;
  color: var(--ink-800);
  transition: background-color .2s, transform .15s;
}
.icon-btn:hover { background-color: rgba(255, 255, 255, .85); }
.icon-btn:active { transform: scale(.95); }

/* 흰 글래스 원형 버튼 (Voice Interaction 카드의 보조 버튼) */
.circle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 9999px;
  border: 1px solid rgba(255, 255, 255, .9);
  background-color: rgba(255, 255, 255, .68);
  color: var(--ink-800);
  box-shadow:
    var(--shadow-glass-sm),
    inset 1px 1px 0 rgba(255, 255, 255, .9);
  -webkit-backdrop-filter: blur(18px) saturate(190%);
  backdrop-filter: blur(18px) saturate(190%);
  transition: transform .25s var(--ease-glass), background-color .2s;
}
.circle-btn:hover { transform: translateY(-2px); background-color: rgba(255, 255, 255, .92); }

/* 그라데이션 원형 버튼 (메인 마이크 / 전송) */
.circle-btn-brand {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 9999px;
  background-image: var(--grad-bubble);
  color: var(--on-brand);
  box-shadow: var(--shadow-orb);
  transition: transform .25s var(--ease-glass), filter .2s;
}
.circle-btn-brand:hover { transform: translateY(-2px); filter: brightness(1.1); }
.circle-btn-brand:active { transform: scale(.96); }

/* 프라이머리 CTA — 블루 → 바이올렛 그라데이션 */
/* 브랜드 CTA 표면 — 알약 버튼(.btn-primary)과 원형 아이콘 버튼(.btn-brand)이
 * 공유한다. 색만 같고 입체감이 다르면 같은 버튼으로 안 읽히기 때문에, 색·광택·
 * 그림자를 한 규칙에 묶어 둔다. 크기와 모양은 각자 알아서.
 *
 * 평평한 그라데이션 하나로는 "칠한 원"으로 보인다. .bubble-user 와 같은
 * 네 겹으로 부풀린다:
 *   ① 상단 돔 하이라이트 — 위에서 빛을 받는 볼록한 면
 *   ② 하단 반사광        — 아래 면에서 되비치는 빛. 이게 있어야 구가 된다
 *   ③ inset 림           — 위 밝은 선 / 아래 어두운 선. 1px 짜리 두께
 *   ④ 3단 드롭섀도       — 접지 / 들림 / 확산
 * ------------------------------------------------------------------------ */
.btn-primary,
.btn-brand {
  background-image:
    /* ① 윗면 광택 띠 — 위 절반에서 뚝 끊긴다. 이 "끊김"이 부푼 면의 능선이다.
          부드럽게 이어지면 그냥 밝은 그라데이션이고, 끊겨야 면이 꺾여 보인다. */
    linear-gradient(180deg,
        rgba(255, 255, 255, .40) 0%,
        rgba(255, 255, 255, .14) 44%,
        rgba(255, 255, 255, 0)   52%,
        rgba(255, 255, 255, 0)   100%),
    /* ② 상단 돔 하이라이트 — 위에서 빛을 받는 볼록한 면 */
    radial-gradient(140% 92% at 50% -34%,
        rgba(255, 255, 255, .52) 0%,
        rgba(255, 255, 255, .13) 46%,
        rgba(255, 255, 255, 0)   72%),
    /* ③ 하단 반사광 — 아래 면에서 되비치는 빛. 이게 있어야 구가 된다 */
    radial-gradient(120% 82% at 50% 132%,
        rgba(255, 255, 255, .26) 0%,
        rgba(255, 255, 255, 0)   56%),
    var(--grad-bubble);
  color: var(--on-brand);
  box-shadow:
    /* 접지 두 겹 — 1px 짜리 단단한 선 + 그 바로 아래 짧은 번짐.
       이 둘이 붙어 있어야 버튼이 바닥에 "닿아" 보인다 */
    0 1px 1px rgba(40, 70, 160, .26),
    0 2px 4px rgba(40, 70, 160, .18),
    /* 들림 + 확산 */
    0 10px 18px -8px rgba(70, 110, 215, .50),
    0 22px 40px -18px rgba(70, 110, 215, .46),
    /* 두께 — 위 밝은 림 / 아래 어두운 림 */
    inset 0 1px 0 rgba(255, 255, 255, .78),
    inset 0 -2px 0 rgba(20, 40, 120, .22),
    /* 아래 안쪽으로 들어가는 그늘. 아랫면이 뒤로 물러나 보여 두께가 생긴다 */
    inset 0 -7px 11px -7px rgba(20, 40, 120, .34);
  transition: transform .3s var(--ease-glass), filter .2s, box-shadow .3s var(--ease-glass);
}

.btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 44px;
  padding: .75rem 1.5rem;
  border-radius: 9999px;
  font-size: .875rem;
  font-weight: 600;
}

/* 원형 아이콘 버튼 — 크기(w-10, h-11 …)와 배치는 마크업의 유틸리티가 정한다.
   ※ 이 클래스를 쓰는 버튼에 shadow-* 유틸리티를 함께 붙이지 말 것.
     Tailwind CDN 이 <style> 을 나중에 주입해서 위 층진 box-shadow 를
     통째로 덮어쓴다 — 입체감이 사라지고 평평한 원이 된다. */
.btn-brand { border-radius: 9999px; }

/* 눌리는 감각 — 뜰 때는 그림자가 길어지고, 눌릴 때는 짧아지며 가라앉는다 */
/* 뜰 때 — 그림자만 길어지는 게 아니라 접지선이 함께 옅어져야 실제로 떠 보인다 */
.btn-primary:hover,
.btn-brand:hover {
  transform: translateY(-2px);
  filter: brightness(1.06);
  box-shadow:
    0 1px 1px rgba(40, 70, 160, .18),
    0 3px 6px rgba(40, 70, 160, .14),
    0 14px 24px -8px rgba(70, 110, 215, .52),
    0 30px 50px -18px rgba(70, 110, 215, .48),
    inset 0 1px 0 rgba(255, 255, 255, .86),
    inset 0 -2px 0 rgba(20, 40, 120, .22),
    inset 0 -8px 12px -7px rgba(20, 40, 120, .34);
}

/* 눌릴 때 — 바닥에 닿으므로 바깥 그림자는 거의 사라지고,
   위쪽 광택이 죽고 안쪽 그늘이 위에서 들어온다(빛을 등지는 면이 뒤집힌다) */
.btn-primary:active,
.btn-brand:active {
  transform: translateY(1px);
  filter: brightness(.98);
  box-shadow:
    0 1px 1px rgba(40, 70, 160, .28),
    0 2px 5px -2px rgba(70, 110, 215, .34),
    inset 0 -1px 0 rgba(255, 255, 255, .30),
    inset 0 1px 0 rgba(20, 40, 120, .26),
    inset 0 6px 12px -5px rgba(20, 40, 120, .38);
}

/* 비활성 CTA — 회색 덩어리 대신 "빛이 꺼진 유리" 로 */
.btn-primary:disabled,
.btn-primary[disabled] {
  background-image: none;
  background-color: rgba(148, 170, 215, .32);
  color: rgba(30, 27, 75, .45);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5);
  cursor: not-allowed;
  transform: none;
  filter: none;
}

/* ---------------------------------------------------------------------------
 * 지우기 버튼이 달린 검색 인풋
 * ---------------------------------------------------------------------------
 * 입력이 있을 때만 우측에 X 가 뜬다. 표시 여부는 .has-value 클래스로 제어하며
 * chat.js 의 위임 핸들러가 input 이벤트에서 토글한다.
 *
 * ※ z-index 필수 — .field 의 backdrop-filter 가 스택 컨텍스트를 만들어
 *   input 이 위치 지정 요소처럼 승격되므로, 버튼이 뒤에 깔려 사라진다.
 * ------------------------------------------------------------------------ */
.search-field {
  position: relative;
  display: block;
}
.search-field input.field {
  padding-right: 2.75rem;
}
.search-field__clear {
  position: absolute;
  z-index: 1;
  right: .4375rem;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.875rem;
  height: 1.875rem;
  border-radius: 9999px;
  color: var(--body-600);
  font-size: .8125rem;
  opacity: 0;
  visibility: hidden;
  transition: opacity .15s, visibility .15s, background-color .2s, color .2s;
}
.search-field.has-value .search-field__clear {
  opacity: 1;
  visibility: visible;
}
.search-field__clear:hover {
  background-color: rgba(255, 255, 255, .95);
  color: var(--ink-900);
  box-shadow: var(--shadow-glass-sm);
}
.search-field__clear:active { transform: translateY(-50%) scale(.92); }

/* 아이콘이 왼쪽에 있는 .search 안에서도 동일하게 동작하도록 */
.search .search-field__clear { right: .4375rem; }

/* ---------------------------------------------------------------------------
 * 검색 결과 행
 * 사이드바 세션 행과 같은 언어(유리 표면 + 아이콘 타일 + hover 리프트).
 * 화살표는 평소 흐리게 두고 hover 에 또렷해지며 살짝 오른쪽으로 밀린다.
 * ------------------------------------------------------------------------ */
.search-result {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .5rem .75rem;
  border-radius: 1.125rem;
  border: 1px solid transparent;
  cursor: pointer;
  transition:
    background-color .2s,
    border-color .2s,
    box-shadow .3s var(--ease-glass),
    transform .25s var(--ease-glass);
}
.search-result:hover {
  transform: translateY(-1px);
  background-color: rgba(255, 255, 255, .9);
  border-color: rgba(255, 255, 255, .95);
  box-shadow: var(--shadow-glass-sm);
}
.search-result:active { transform: translateY(0) scale(.995); }

.search-result__title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: .875rem;
  font-weight: 500;
  color: var(--ink-900);
}

.search-result__go {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 1.625rem;
  height: 1.625rem;
  border-radius: 9999px;
  color: var(--brand-blue);
  font-size: .6875rem;
  opacity: .35;
  transition: opacity .2s, background-color .2s, transform .25s var(--ease-glass);
}
.search-result:hover .search-result__go {
  opacity: 1;
  background-color: rgba(107, 178, 248, .22);
  transform: translateX(2px);
}

/* 검색 결과 없음 / 로딩 — 빈 화면도 컴포넌트로 */
.search-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .75rem;
  color: var(--body-600);
  font-size: .875rem;
}
.search-empty__icon {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 9999px;
  border: 1px solid rgba(255, 255, 255, .9);
  background-color: rgba(255, 255, 255, .7);
  box-shadow: var(--shadow-glass-sm);
  color: var(--ink-500);
  font-size: 1.0625rem;
}

/* ---------------------------------------------------------------------------
 * 검색어 형광펜
 * ---------------------------------------------------------------------------
 * <mark> 의 브라우저 기본값은 노랑 배경 + 검정 글자다. 이 페이지에서 유일하게
 * 채도가 튀는 면이 되므로 배경·글자색을 둘 다 덮어써야 한다.
 *
 * 면을 통째로 칠하면 결과가 많을 때 목록이 알록달록한 블록 나열로 보인다.
 * 실제 형광펜처럼 글자 아래쪽 절반만 지나가게 해서, 원래 텍스트 색을 유지한
 * 채 "그어진" 느낌만 남긴다. 색은 페이지 트리오의 하늘→파랑 구간.
 * (글자색은 inherit — slate-600 본문이 그대로 유지되어 §5.1 을 지킨다)
 * ------------------------------------------------------------------------ */
mark.hl {
  background-color: transparent;
  background-image: linear-gradient(180deg,
      transparent 46%,
      rgba(125, 211, 252, .55) 46%,
      rgba(107, 178, 248, .48) 100%);
  color: inherit;
  font-weight: 600;
  border-radius: .125rem;
  /* 좌우 패딩 없음 — 한 글자 검색어가 연속으로 걸리면(예: 'a' → AAA) 인접한
     mark 끼리 패딩이 겹쳐 글자 간격이 벌어진다. 형광펜은 글자 뒤에 깔리므로
     패딩이 없어도 성립하고, 이러면 레이아웃이 전혀 흔들리지 않는다. */
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* ---------------------------------------------------------------------------
 * 필터 칩 (마켓플레이스 / 내 도구)
 * ---------------------------------------------------------------------------
 * 기존에는 JS 가 런타임에 Tailwind 유틸리티 문자열을 통째로 갈아끼웠는데,
 * 그 방식은 (1) 모양이 CSS 어디에도 남지 않아 추적이 어렵고
 * (2) 빌드형 Tailwind 로 옮기는 순간 JS 안의 클래스는 스캔되지 않아 사라진다.
 * → 모양은 여기서 정의하고, JS 는 .is-active 만 토글한다.
 * ------------------------------------------------------------------------ */
/* 세그먼트 트랙 — 알약 3개가 따로 떠 있으면 "버튼 몇 개"로 읽힌다.
 * 하나의 오목한 유리 레일에 넣어 한 덩어리(단일 선택 컨트롤)로 보이게 한다.
 * inline-flex 라 내용만큼만 차지하고, 검색창 아래에서 왼쪽으로 붙는다. */
/* 세그먼트 트랙 — 실제로 홈을 판다.
   전에는 border-radius 만 있고 면이 없어서, 알약 3개가 각자 떠 있는 "버튼 세 개"로
   읽혔다. 안쪽으로 눌린 옅은 홈을 만들어 그 위에 선택 알약이 얹히게 하면,
   비로소 하나의 단일 선택 컨트롤이 된다. */
.tool-filters {
  display: inline-flex;
  align-items: center;
  gap: .125rem;
  padding: .1875rem;
  border-radius: 9999px;
  border: 1px solid rgba(99, 130, 220, .10);
  background-color: rgba(99, 130, 220, .07);
  box-shadow: inset 0 1px 2px rgba(70, 95, 170, .07);
}

.tool-filter {
  display: inline-flex;
  align-items: center;
  gap: .3125rem;
  padding: .3125rem .625rem;
  border: 0;
  border-radius: 9999px;
  background-color: transparent;
  font-size: .75rem;
  font-weight: 500;
  line-height: 1.4;
  color: var(--body-600);
  white-space: nowrap;
  cursor: pointer;
  /* 크기 변화(scale) 없이 색·그림자만 — 필터 행이 눈에 튀면 안 된다 */
  transition: background-color .2s, color .2s, box-shadow .3s var(--ease-glass);
}

/* 개수 — 알약 안의 또 다른 알약이었다. 12px 라벨 하나에 도형이 둘이라
   필터 3개가 도형 6개로 읽혔다. 배경을 걷고 숫자만 흐리게 붙인다. */
.tool-filter__count {
  font-size: .6875rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;   /* 자릿수 바뀔 때 폭이 안 튀게 */
  color: var(--ink-500);
  opacity: .7;
  transition: color .2s, opacity .2s;
}

.tool-filter:hover {
  background-color: rgba(255, 255, 255, .6);
  color: var(--ink-900);
}

/* 선택 — 홈 위로 떠오른 흰 알약.
   그라데이션을 뺀 이유: --grad-primary 는 이 시스템에서 "지금 눌러야 할
   단 하나"(전송·새 대화·분석 시작)의 표식이다. 12px 짜리 필터까지 같은 옷을
   입으면 화면에서 진짜 CTA 와 경쟁하고, 60px 폭에 하늘·파랑·분홍 세 색이
   압축돼 들어가 그라데이션이 아니라 얼룩으로 보인다.
   → 면은 흰색으로 띄우고, 브랜드는 글자색으로만 남긴다. */
.tool-filter.is-active {
  background-color: #FFFFFF;
  color: var(--brand-blue);
  font-weight: 600;
  box-shadow:
    0 1px 2px rgba(70, 95, 170, .10),
    0 3px 8px -3px rgba(70, 95, 170, .20),
    inset 0 1px 0 rgba(255, 255, 255, 1);
}
.tool-filter.is-active .tool-filter__count { color: var(--brand-blue); opacity: .6; }

/* 결과 0건인 필터는 눌러도 빈 화면이라는 걸 미리 알린다 */
.tool-filter.is-zero:not(.is-active) { color: #94A3B8; }
.tool-filter.is-zero:not(.is-active) .tool-filter__count { opacity: .45; }

/* --- 모바일: 필터 줄이 '툴 등록'과 폭을 나눠 쓴다 --------------------------
 * 이 줄에는 알약 4개(전체·정식·실험실·심사 + 개수 배지)와 CTA 가 함께 선다.
 * 360px 화면에서 모달 폭은 90vw - 여백 = 약 290px 인데 기본값으로는 315px 라
 * 넘친다. 넘친 만큼 flex 가 CTA 를 눌러 "툴 / 등록" 으로 접혔던 것이다.
 *
 * 세 가지를 함께 건다.
 *   ① 알약의 좌우 여백과 간격을 줄인다 — 글자 크기(12px)는 건드리지 않는다.
 *      좁다고 타입부터 줄이면 읽는 난이도가 올라가는데, 여기서 남는 건
 *      대부분 여백이라 여백만 걷어도 60px 가 빠진다.
 *   ② 트랙이 줄어들 수 있게 하고, 그래도 모자라면 가로로 스크롤시킨다.
 *      스크롤바는 숨긴다 — 몇 칸 안 되는 세그먼트 컨트롤에 스크롤바가 뜨면
 *      "더 있나?" 하고 헤매게 된다(끝 알약이 잘려 보이는 것으로 충분하다).
 *   ③ CTA 는 줄지도 접히지도 않게 못박는다.
 * ------------------------------------------------------------------------ */
@media (max-width: 639px) {
  .tool-filter {
    gap: .25rem;
    padding: .3125rem .4375rem;
  }

  /* ② 트랙 — inline-flex 라 기본이 flex: 0 1 auto. min-width 만 풀어주면
     내용보다 작게 줄어들 수 있고, 그 지점부터 스크롤이 넘겨받는다.
     홈(padding·inset 그림자)은 그대로 둔다 — 스크롤될 때도 알약이 레일
     안에서 움직이는 것으로 읽혀야 한다. */
  .tool-filters {
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .tool-filters::-webkit-scrollbar { display: none; }
}

/* ---------------------------------------------------------------------------
 * 담은 도구 스트립 (#mk_owned) — 마켓 목록 맨 위 한 줄
 * ---------------------------------------------------------------------------
 * 마켓을 훑는 동안 "내가 이미 담은 것"을 계속 보여 준다. 아래 카드 목록과
 * 같은 어휘(카드·설명·CTA)로 그리면 목록이 두 벌이 되어 어느 쪽을 보는지
 * 흐려지므로, 여기는 이름표만 남긴 가장 가벼운 형태로 둔다.
 *   · 이름 + 상태 점.  설명도 담기 버튼도 없다(그건 아래 카드의 일이다)
 *   · 줄바꿈 없음.     몇 개가 되든 높이가 고정이라 목록 자리를 잠식하지 않는다
 *   · 넘치면 가로 스크롤. 오른쪽 끝을 페이드로 잘라 "더 있다"를 알린다
 * ------------------------------------------------------------------------ */
.mk-owned {
  display: flex;
  align-items: center;
  gap: .625rem;
  min-width: 0;
  padding: .125rem 0 .75rem;
}

.mk-owned__label {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  flex-shrink: 0;
  font-size: .75rem;
  font-weight: 600;
  color: var(--body-600);
}
.mk-owned__label > i { font-size: 11px; color: var(--brand-blue); }
.mk-owned__count {
  min-width: 1.125rem;
  padding: .0625rem .3125rem;
  border-radius: 9999px;
  background-color: rgba(99, 130, 220, .12);
  color: var(--brand-blue);
  font-size: 10px;
  font-style: normal;
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* 트랙 — 스크롤바는 감춘다(.tool-filters 와 같은 규칙). 대신 오른쪽 끝
   12px 을 마스크로 흘려 잘린 이름표가 "짤린 것"이 아니라 "이어지는 것"으로
   보이게 한다. 왼쪽은 라벨이 경계를 만들어 주므로 건드리지 않는다.
   마스크는 뒤에 더 있을 때만(.has-more) — 끝까지 밀었는데 마지막 이름표가
   흐리면 아직 남은 줄 알고 계속 민다. */
.mk-owned__track {
  display: flex;
  align-items: center;
  gap: .375rem;
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  padding: .125rem .75rem .125rem .125rem;   /* 포커스 링이 잘리지 않을 만큼 */
  scrollbar-width: none;
  overscroll-behavior-x: contain;   /* 끝까지 밀어도 모달 뒤가 따라 움직이지 않게 */
}
.mk-owned__track.has-more {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 1.5rem), transparent 100%);
  mask-image: linear-gradient(90deg, #000 calc(100% - 1.5rem), transparent 100%);
}
.mk-owned__track::-webkit-scrollbar { display: none; }

/* 좌우 이동 버튼 — 넘칠 때만 선다(.is-shown). 끝에 닿은 쪽은 지우지 않고
   흐리게만 둔다: 사라지면 남은 버튼이 자리를 옮겨 다음 클릭이 빗나간다. */
.mk-owned__nav {
  display: none;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 1.375rem;
  height: 1.375rem;
  border: 1px solid rgba(255, 255, 255, .9);
  border-radius: 9999px;
  background-color: rgba(255, 255, 255, .72);
  box-shadow: var(--shadow-glass-sm);
  color: var(--body-600);
  font-size: 9px;
  cursor: pointer;
  transition: background-color .2s, color .2s, opacity .2s;
}
.mk-owned__nav.is-shown { display: inline-flex; }
.mk-owned__nav:hover:not(:disabled) { background-color: #FFFFFF; color: var(--brand-blue); }
.mk-owned__nav:disabled { opacity: .3; cursor: default; }

/* 이름표 — 유리 알약. 눌러서 상세로 갈 수 있으므로 hover 를 준다. */
button.mk-owned__item {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  flex-shrink: 0;              /* 좁아져도 글자가 뭉개지지 않게 — 대신 스크롤한다 */
  max-width: 11rem;
  padding: .25rem .625rem .25rem .5rem;
  border: 1px solid rgba(255, 255, 255, .9);
  border-radius: 9999px;
  background-color: rgba(255, 255, 255, .72);
  box-shadow: var(--shadow-glass-sm);
  color: var(--ink-900);
  font-size: .75rem;
  font-weight: 500;
  line-height: 1.5;
  cursor: pointer;
  transition: background-color .2s, border-color .2s, transform .15s;
}
button.mk-owned__item:hover {
  background-color: #FFFFFF;
  border-color: rgba(99, 130, 220, .35);
}
button.mk-owned__item:active { transform: scale(.97); }

/* 상태 점 — 배지(정식/테스트) 대신 점 하나. 이름표 폭을 두 배로 만들지 않으면서
   마켓 카드의 아이콘 타일과 같은 그라데이션을 쓴다. */
.mk-owned__dot {
  flex-shrink: 0;
  width: .4375rem;
  height: .4375rem;
  border-radius: 9999px;
  background-image: var(--grad-official-v);
}
.mk-owned__dot[data-status="test"] { background-image: var(--grad-test-v); }

.mk-owned__name {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* 모바일 — 라벨을 아이콘+개수로만 줄여 트랙에 폭을 넘긴다.
   좁은 화면에서 '담은 도구' 네 글자가 트랙의 절반을 먹는다. */
@media (max-width: 480px) {
  .mk-owned { gap: .5rem; }
  .mk-owned__label { font-size: 0; gap: .25rem; }   /* 글자만 지운다 */
  .mk-owned__label > i { font-size: 12px; }
  .mk-owned__count { font-size: 10px; }
}

/* ---------------------------------------------------------------------------
 * 마켓 카드 (#mk_list)
 * ---------------------------------------------------------------------------
 * 마켓은 '고르는' 화면이라 카드마다 끝에 결단(담기)이 붙는다. 그 결단이
 * 본문과 같은 무게로 떠 있으면 카드가 그냥 글상자로 읽힌다.
 *   · 담기  = 유일한 채색 CTA. 브랜드 그라데이션 알약 + 플러스
 *   · 담김  = 끝난 일. 채도를 빼고 체크로 바꿔 "더 누를 것 없음"을 만든다
 * 아이콘 타일과 상태 색은 내 도구 행(.mn-row)과 같은 토큰을 쓴다 —
 * 두 모달을 오갈 때 같은 도구가 같은 색으로 보여야 한다.
 * ------------------------------------------------------------------------ */
.tool-card {
  display: flex;
  flex-direction: column;
  gap: .625rem;
  padding: .875rem;
  border-radius: 1.25rem;
  border: 1px solid var(--glass-stroke);
  background-color: rgba(255, 255, 255, .62);
  box-shadow: var(--shadow-glass-sm);
  transition:
    background-color .2s,
    border-color .2s,
    box-shadow .3s var(--ease-glass),
    transform .25s var(--ease-glass);
}
.tool-card:hover {
  transform: translateY(-2px);
  background-color: rgba(255, 255, 255, .92);
  border-color: rgba(255, 255, 255, .95);
  box-shadow: var(--shadow-glass);
}

/* 제목줄 + 설명은 통째로 상세 열기 영역 */
.tool-card__open { cursor: pointer; }
.tool-card__head {
  display: flex;
  align-items: center;
  gap: .625rem;
  min-width: 0;
}
/* 상태 타일 — 색 정의는 .mn-row__icon 과 같은 토큰(--grad-official/--grad-test) */
.tool-card__icon {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: .75rem;
  font-size: .8125rem;
  color: var(--on-brand);
  background-image: var(--grad-official);
  box-shadow: var(--shadow-official), inset 0 1px 0 rgba(255, 255, 255, .45);
}
.tool-card--test .tool-card__icon {
  background-image: var(--grad-test);
  box-shadow: var(--shadow-test), inset 0 1px 0 rgba(255, 255, 255, .45);
}
/* 심사 중·반려 — 아직 쓸 수 없는 도구다. 아이콘 색으로 '대기(호박)·중단(빨강)'을 구분한다.
   정식·테스트가 쓰는 브랜드 그라데이션을 주면 승인된 도구처럼 읽힌다. */
.tool-card--pending .tool-card__icon {
  background-image: linear-gradient(160deg, #FBBF24 0%, #D97706 100%);
  box-shadow: 0 2px 8px -2px rgba(217, 119, 6, .45), inset 0 1px 0 rgba(255, 255, 255, .45);
}
.tool-card--rejected .tool-card__icon {
  background-image: linear-gradient(160deg, #F87171 0%, #DC2626 100%);
  box-shadow: 0 2px 8px -2px rgba(220, 38, 38, .45), inset 0 1px 0 rgba(255, 255, 255, .45);
}
/* 반려 사유 표시 — 등록자가 무엇을 고쳐야 하는지가 카드에서 바로 읽혀야 한다.
   설명(.tool-card__desc)과 달리 줄을 자르지 않는다. 잘린 사유는 사유 구실을 못 한다. */
.tool-card__reject {
  margin-top: .5rem;
  padding: .5rem .625rem;
  border: 1px solid rgba(248, 113, 113, .35);
  border-radius: .5rem;
  background-color: rgba(254, 226, 226, .45);
  font-size: .75rem;
  line-height: 1.55;
  color: #B91C1C;
  word-break: break-word;
}
.tool-card__reject > b { display: block; margin-bottom: .125rem; font-weight: 700; }
.tool-card__title {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: .9375rem;
  font-weight: 600;
  color: var(--ink-900);
}
/* 두 줄 고정 — 그리드에서 카드마다 설명 길이가 다르면 CTA 줄이 계단처럼 어긋난다 */
.tool-card__desc {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: .5rem;
  min-height: 2.6em;
  font-size: .8125rem;
  line-height: 1.6;
  color: var(--body-600);
  word-break: break-word;
}

/* 카드 바닥 — 얇은 선으로 '고르는 정보'와 '누르는 것'을 나눈다 */
.tool-card__foot {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-top: auto;
  padding-top: .625rem;
  border-top: 1px solid rgba(148, 170, 215, .20);
}
.tool-card__note {
  display: inline-flex;
  align-items: center;
  gap: .3125rem;
  margin-right: auto;
  font-size: .6875rem;
  color: var(--body-600);
}
.tool-card__note > i { color: var(--ink-500); font-size: .625rem; }

/* --- 담기 / 담김 ----------------------------------------------------------
 * 같은 자리에서 상태만 바뀌므로 크기(높이·좌우 여백)는 두 상태가 똑같아야 한다.
 * 다른 건 색과 아이콘뿐 — 담을 때 버튼이 커졌다 작아지면 목록이 출렁인다. */
/* 담기 / 담김 — 아이콘 하나로만 말한다.
 * 이전에는 라벨 달린 그라데이션 알약(84×32)이었다. 카드 하나에 담긴 정보는
 * 이름·배지·설명 정도인데 그 아래 CTA 가 카드 폭의 절반을 쓰며 그라데이션까지
 * 두르니, 목록을 훑을 때 도구가 아니라 버튼 줄이 먼저 보였다.
 * → 면과 그림자를 전부 걷고 글리프만 크게 남긴다. 상태는 모양과 색이 말한다.
 *     ＋(브랜드 블루) 담을 수 있음 / ✓(초록) 이미 담김
 * 텍스트가 없으니 aria-label·title 은 마크업에서 반드시 채운다. */
.tool-add {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  margin-left: auto;          /* 안내 문구가 없는 카드(미담김)에서도 오른쪽 끝 */
  width: 2.125rem;
  height: 2.125rem;
  border: 0;
  border-radius: 9999px;
  /* 평소에는 면이 없다 — 카드마다 원이 하나씩 박혀 있으면 목록을 훑을 때
     도구가 아니라 버튼 줄이 먼저 보인다. 면은 hover 에서만 깔린다. */
  background-color: transparent;
  background-image: none;
  box-shadow: none;
  color: var(--brand-blue);   /* background-clip 미지원 브라우저의 단색 폴백 */
  cursor: pointer;
  transition: background-color .2s, transform .2s var(--ease-glass);
}
/* 글리프는 크게 — 34px 원 안의 16px. 아이콘만 남은 버튼에서 12px 글리프는
   눌러야 할 것이 아니라 장식으로 읽힌다. */
.tool-add > i { font-size: 1rem; line-height: 1; }

/* 면을 걷어낸 대신 브랜드는 글리프가 입는다 — 아이콘 폰트도 결국 텍스트라
   background-clip: text 가 그대로 먹는다(.dropzone__icon 과 같은 기법). */
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  .tool-add > i {
    background-image: var(--grad-bubble);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
  }
}

.tool-add:hover {
  background-color: rgba(226, 233, 253, .75);
  transform: translateY(-1px);
}
.tool-add:active { transform: translateY(0) scale(.92); }

/* 담김 — 끝난 상태다. 초록 체크는 이 팔레트에 없는 색이라 카드 위에서 혼자
   튀고, "방금 성공했다"는 알림처럼 읽혀 계속 시선을 끈다. 조작할 게 없는
   표식이니 그라데이션도 풀고 블루틴트 그레이로 가라앉힌다(꺼진 행 아이콘과
   같은 값). 이 규칙은 위 @supports 블록보다 뒤에 와야 이긴다 — 특정도가
   (0,1,1) 로 같아서 순서가 승부를 가른다. */
.tool-add--added { color: #8FA3C4; cursor: default; }
.tool-add--added > i {
  background-image: none;
  color: #8FA3C4;
  -webkit-text-fill-color: currentColor;
}
/* 누를 수 없는 버튼이라 뜨지는 않는다. 면만 아주 옅게 — 커서가 어디 있는지만 */
.tool-add--added:hover {
  background-color: rgba(148, 170, 215, .16);
  transform: none;
}

/* ---------------------------------------------------------------------------
 * 내 도구 행 (#mn_list)
 * ---------------------------------------------------------------------------
 * 이전에는 1px 선으로 칸을 나눈 divide-y 목록이었다. 유리 위에서 실선 격자는
 * 표(table)처럼 읽혀 뒤에 번지는 배경과 따로 놀았고, 켜짐/꺼짐을 행 전체
 * opacity 로만 구분해 꺼진 행은 글씨까지 흐려졌다(대비 3:1 미만).
 *
 * → 행 하나를 얕은 유리 카드로 세우고 8px 씩 띄운다. 상태는 세 곳이 말한다.
 *     ① 왼쪽 그라데이션 바 — 켜진 행에만. 목록을 훑을 때 제일 먼저 보인다
 *     ② 아이콘 타일의 채도 — 켜짐(브랜드 그라데이션) / 꺼짐(무채색)
 *     ③ 스위치             — 유일한 조작점
 *   꺼진 행은 "표면"만 가라앉히고 글자 대비는 유지한다. 정보를 흐리게 만드는
 *   대신 유리 두께(그림자·불투명도)를 걷어내는 쪽이 상태 표현으로 정확하다.
 * ------------------------------------------------------------------------ */
/* 컨테이너 — 스크롤 박스 자체는 테두리 없이 두고, 행에만 표면을 준다.
   좌우 2px 패딩은 hover 리프트의 그림자가 스크롤 경계에서 잘리지 않게 하는 여유. */
.mn-list {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .125rem;
}

/* ── parameters 입력: 폼 / JSON 탭 ─────────────────────────────────────
   같은 값을 두 방식으로 쓴다. 탭은 '지금 어느 쪽으로 쓰는 중인가'라 활성 칸을 칠한다
   (일괄 on/off 세그먼트와 반대다 — 그쪽은 누르는 즉시 실행이라 칠하지 않는다). */
.tool-ptabs {
  display: inline-flex;
  padding: .125rem;
  border-radius: 9999px;
  background-color: rgba(28, 111, 214, .08);
}
.tool-ptab {
  padding: .25rem .625rem;
  border-radius: 9999px;
  font-size: .6875rem;
  font-weight: 600;
  color: var(--ink-500);
  transition: background-color .12s, color .12s;
}
.tool-ptab:hover { color: var(--brand-blue); }
.tool-ptab.is-active {
  background-color: #FFFFFF;
  color: var(--brand-blue);
  box-shadow: 0 1px 2px rgba(70, 95, 170, .12);
}

/* ── 파라미터 에디터 ───────────────────────────────────────────────────
 * 여기서 적는 것은 폼 필드가 아니라 모델이 읽을 호출의 인자다. 그래서 폼이 아니라
 * API 레퍼런스의 어휘로 짠다 — 식별자와 타입은 고정폭, 나머지는 본문 서체.
 *
 * 칸을 flex 로 흘리지 않고 grid 로 세운 이유: 한 칸만 줄바꿈돼도 열 정렬이 무너져
 * 무엇을 적는 자리인지 알 수 없게 된다. 열이 고정돼야 머리글 한 줄이 전체를 설명한다.
 * -------------------------------------------------------------------- */
.param-editor { display: flex; flex-direction: column; gap: .625rem; }

/* ── 툴 등록 폼 ────────────────────────────────────────────────────────
 * 칸을 '읽는 주체'로 가른다. 이름·설명·입력값은 모델이 읽어 호출 여부를 정하고,
 * 메서드·URL·헤더는 서버만 쓴다. 한 줄기로 쌓으면 설명이 헤더와 같은 무게로 보인다.
 * -------------------------------------------------------------------- */
/* 표면 언어를 하나로 모은다.
   앱 공통 .field 는 유리 알약(반경 9999px · blur · 최소 46px)이라 검색창처럼 짧은 입력
   하나가 떠 있을 때 맞는 물건이다. 여기는 식별자·주소·스키마를 채우는 조밀한 구조 입력이고,
   알약 여섯 개 옆에 사각 격자가 서면 두 언어가 한 화면에서 부딪힌다.
   그래서 이 폼 안에서만 .field 를 판으로 되돌리고, 격자·요청 라인과 같은 값을 쓰게 한다. */
.tool-form {
  --tf-line: rgba(186, 222, 242, .9);        /* 바깥 경계 */
  --tf-line-soft: rgba(186, 222, 242, .5);   /* 안쪽 구분선 */
  --tf-surface: rgba(255, 255, 255, .7);     /* 입력 면 */
  --tf-surface-head: rgba(232, 245, 252, .8);/* 머리글·보조 면 */
  --tf-radius: .5rem;
  --tf-focus: rgba(28, 111, 214, .55);
  --tf-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  display: flex;
  flex-direction: column;
  /* 묶음 사이는 묶음 안쪽(.75rem)보다 확실히 넓게 — 간격만으로도 경계가 읽히게 */
  gap: 1.75rem;
}

/* (0,2,1) — input.field (0,1,1) 를 !important 없이 넘어선다 */
.tool-form input.field,
.tool-form textarea.field,
.tool-form select.field {
  min-height: 0;
  padding: .5rem .75rem;
  border-radius: var(--tf-radius);
  border-color: var(--tf-line);
  background-color: var(--tf-surface);
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  font-size: .8125rem;
  color: var(--ink-900);
}
.tool-form input.field:hover,
.tool-form textarea.field:hover,
.tool-form select.field:hover { background-color: rgba(255, 255, 255, .85); }
.tool-form input.field:focus,
.tool-form textarea.field:focus,
.tool-form select.field:focus {
  border-color: var(--tf-focus);
  background-color: #FFFFFF;
  box-shadow: none;
}
/* 이름은 모델이 함수명으로 읽는 식별자다 — 입력값 이름·URL 과 같은 고정폭으로 */
.tool-form input.font-mono,
.tool-form textarea.font-mono { font-family: var(--tf-mono); }


/* 묶음 — 이름 옆 한 줄이 '왜 이 묶음인지'를 말한다. 괘선은 이름 뒤로만 이어 표제처럼 읽히게. */
/* 묶음 표제 아래로 괘선이 끝까지 이어진다 — '여기부터 다음 줄까지가 한 묶음'이 눈으로 잡혀야
   사람용 칸과 AI용 칸을 헷갈리지 않는다. 이름 뒤에만 짧게 긋던 장식은 뺐다(같은 일을 두 번 한다). */
.tool-group { display: flex; flex-direction: column; gap: .75rem; }
.tool-group__legend {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  flex-wrap: wrap;
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--tf-line);
}
.tool-group__name {
  flex-shrink: 0;
  font-size: .8125rem;
  font-weight: 700;
  color: var(--ink-900);
}
.tool-group__hint {
  flex: 1 1 auto;
  min-width: 0;
  font-size: .6875rem;
  color: var(--body-600);
}

.tool-field { display: flex; flex-direction: column; gap: .3125rem; }
.tool-field__label { font-size: .75rem; font-weight: 600; color: var(--ink-800); }
.tool-field__req { color: #DC2626; font-weight: 700; }
.tool-field__opt {
  margin-left: .25rem;
  font-size: .625rem;
  font-weight: 500;
  color: var(--body-600);
}
.tool-field__hint { font-size: .6875rem; line-height: 1.6; color: var(--body-600); }

/* 요청 라인 — 메서드와 주소를 한 칸처럼 붙인다. 둘이 합쳐진 것이 곧 보내는 요청이다. */
.tool-reqline {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--tf-line);
  border-radius: var(--tf-radius);
  background-color: var(--tf-surface);
  overflow: hidden;
  transition: border-color .12s;
}
.tool-reqline:focus-within { border-color: var(--tf-focus); }
.tool-reqline__method {
  flex-shrink: 0;
  padding: .5rem .5rem .5rem .75rem;
  border: 0;
  border-right: 1px solid var(--tf-line);
  background-color: var(--tf-surface-head);
  font-family: var(--tf-mono);
  font-size: .8125rem;
  font-weight: 600;
  color: var(--brand-sky);
}
.tool-reqline__url {
  flex: 1 1 auto;
  min-width: 0;
  padding: .5rem .75rem;
  border: 0;
  background-color: transparent;
  font-family: var(--tf-mono);
  font-size: .8125rem;
  color: var(--ink-900);
}
.tool-reqline__method:focus-visible,
.tool-reqline__url:focus-visible { outline: 2px solid var(--ink-600); outline-offset: -2px; }

/* 격자 — 필수 / 이름 / 타입 / 설명 / 삭제. 머리글과 행이 같은 정의를 공유한다. */
.param-grid {
  /* 필수 · 이름 · 타입 · 허용값 · 설명 · 삭제.
     허용값 입력을 본 행에 올리고 설명은 남는 폭을 가져간다 — 설명은 길어도 한 줄에 다 안 보이므로
     고정폭을 크게 잡아 봐야 이득이 없고, 허용값처럼 짧고 반복 입력하는 칸이 손에 가까워야 한다. */
  --param-cols: 2.25rem 9rem 8rem 8.5rem minmax(7rem, 1fr) 2rem;
  border: 1px solid var(--tf-line);
  border-radius: var(--tf-radius);
  background-color: var(--tf-surface);
  overflow: hidden;
}
.param-head,
.param-row {
  display: grid;
  grid-template-columns: var(--param-cols);
  align-items: center;
  gap: .375rem;
  padding: .375rem .5rem;
}
.param-head {
  background-color: var(--tf-surface-head);
  border-bottom: 1px solid var(--tf-line);
  font-size: .625rem;
  font-weight: 600;
  color: var(--brand-sky);
}
.param-head > span:first-child { text-align: center; }
.param-row + .param-row { border-top: 1px solid var(--tf-line-soft); }
.param-row:hover { background-color: rgba(240, 249, 254, .6); }

/* 칸들 — 테두리 없는 셀. 격자가 이미 경계를 그으므로 칸마다 상자를 또 두르면 선이 두 겹이 된다.
   포커스일 때만 밑줄이 서서 지금 어디를 쓰는지 알린다. */
.param-row input,
.param-row select {
  width: 100%;
  min-width: 0;
  padding: .25rem .375rem;
  border: 1px solid transparent;
  border-radius: calc(var(--tf-radius) - .125rem);
  background-color: transparent;
  font-size: .75rem;
  color: var(--body-700);
  transition: background-color .12s, border-color .12s;
}
.param-row input:hover,
.param-row select:hover { background-color: rgba(226, 244, 252, .6); }
.param-row input:focus,
.param-row select:focus {
  border-color: rgba(28, 111, 214, .45);
  background-color: #FFFFFF;
}
/* 키보드로 들어온 포커스는 테두리 색만으로 부족하다 — 링을 남긴다(마우스 클릭엔 안 뜬다). */
.param-row input:focus-visible,
.param-row select:focus-visible,
.param-row .pr-del:focus-visible,
.param-add:focus-visible {
  outline: 2px solid var(--ink-600);
  outline-offset: 1px;
}
/* 이름과 타입은 식별자다 — 고정폭으로 세우고, 이름은 한 단 진하게 */
.param-row .pr-name {
  font-family: var(--tf-mono);
  font-weight: 600;
  color: var(--ink-900);
}
.param-row .pr-type,
.param-row .pr-items {
  font-family: var(--tf-mono);
  color: var(--brand-sky);
}
.pr-typewrap { display: flex; gap: .25rem; min-width: 0; }
.pr-typewrap .pr-items { flex: 0 1 5rem; }
.pr-reqbox { display: grid; place-items: center; }
.pr-reqbox .pr-req { width: .875rem; height: .875rem; accent-color: var(--brand-blue); cursor: pointer; }
/* 삭제는 늘 보인다 — hover 로 나타나게 하면 터치 기기에서 영영 흐린 채로 남는다 */
.param-row .pr-del {
  justify-self: center;
  padding: .1875rem .3125rem;
  border-radius: calc(var(--tf-radius) - .125rem);
  color: var(--ink-500);
  transition: color .12s, background-color .12s;
}
.param-row .pr-del:hover { color: #DC2626; background-color: rgba(220, 38, 38, .08); }

/* 등록된 허용값 — 입력칸 바로 아래로 이어붙여 그 칸의 결과임이 위치로 읽히게 한다 */
.pr-enumcell { min-width: 0; }
.pr-enum-wrap {
  grid-column: 4 / -1;
  display: flex;
  align-items: center;
  gap: .375rem;
  flex-wrap: wrap;
  padding: .125rem .375rem .25rem;
}
.pr-enum-label { flex-shrink: 0; font-size: .6875rem; color: var(--ink-500); }
.pr-enum-chips { display: flex; align-items: center; gap: .25rem; flex-wrap: wrap; }
/* 칩은 본문 서체로 둔다 — 값이 한글일 때가 많은데 고정폭에서 CJK 는 자간이 들쭉날쭉해진다.
   이름·타입(식별자)과 달리 허용값은 사람이 읽는 값이다. */
.pr-enum-chip {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .0625rem .375rem .0625rem .5rem;
  border: 1px solid rgba(28, 111, 214, .20);
  border-radius: 9999px;
  background-color: rgba(232, 240, 254, .7);
  font-size: .625rem;
  color: var(--ink-800);
}
.pr-enum-x { color: var(--ink-500); line-height: 1; }
.pr-enum-x:hover { color: #DC2626; }

/* 빈 상태 — 비워 두는 것도 정답인 화면이라 재촉하지 않고 사실을 알린다 */
.param-empty {
  padding: 1.25rem .75rem;
  text-align: center;
  font-size: .75rem;
  color: var(--body-600);
}

.param-foot { display: flex; align-items: center; gap: .625rem; flex-wrap: wrap; }
.param-add {
  display: inline-flex;
  align-items: center;
  gap: .3125rem;
  padding: .3125rem .625rem;
  border: 1px dashed rgba(28, 111, 214, .35);
  border-radius: var(--tf-radius);
  font-size: .6875rem;
  font-weight: 600;
  color: var(--brand-blue);
  transition: background-color .12s, border-color .12s;
}
.param-add:hover { background-color: rgba(28, 111, 214, .08); border-color: rgba(28, 111, 214, .55); }
.param-add > i { font-size: .5625rem; }

/* 좁은 화면 — 열을 세울 자리가 없으면 머리글을 걷고 이름/타입, 설명을 두 줄로 접는다.
   접힌 뒤에도 필수 체크와 삭제는 이름 줄에 붙어 있어 어느 행의 것인지 잃지 않는다. */
@media (max-width: 640px) {
  .param-head { display: none; }
  .param-grid { --param-cols: 2rem minmax(6rem, 1fr) 7.5rem 1.75rem; }
  .param-row { grid-template-columns: var(--param-cols); row-gap: .25rem; }
  .pr-enumcell,
  .param-row .pr-desc,
  .pr-enum-wrap { grid-column: 2 / -1; }
}

/* 일괄 on/off — 두 칸을 하나의 덩어리로. 조회 필터(.tool-filters)와 같은 알약 모양이라
   툴바에서 두 컨트롤이 형제로 읽힌다. 다만 필터는 '고른 상태'가 남고 이쪽은
   누르는 즉시 실행이라, 활성 칸을 칠하지 않고 눌린 느낌만 준다. */
.mn-bulk__seg {
  display: inline-flex;
  align-items: stretch;
  overflow: hidden;
  border: 1px solid rgba(28, 111, 214, .20);
  border-radius: 9999px;
  background-color: rgba(255, 255, 255, .55);
}
.mn-bulk__opt {
  display: inline-flex;
  align-items: center;
  gap: .3125rem;
  padding: .4375rem .75rem;
  font-size: .6875rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--brand-blue);
  white-space: nowrap;
  transition: background-color .12s, color .12s;
}
.mn-bulk__opt + .mn-bulk__opt { border-left: 1px solid rgba(28, 111, 214, .20); }
.mn-bulk__opt:hover:not([disabled]) { background-color: rgba(28, 111, 214, .10); }
.mn-bulk__opt:active:not([disabled]) { background-color: rgba(28, 111, 214, .18); }
/* 이미 전부 그 상태 = 할 일이 없다. 눌러도 아무 일 없는 칸은 고장으로 읽히므로 죽여 둔다. */
.mn-bulk__opt[disabled] { color: var(--ink-500); opacity: .5; cursor: not-allowed; }


.mn-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: .75rem;
  /* 왼쪽 1rem — 켜짐 바(3px) 자리를 비켜준 값. 켜짐/꺼짐이 같은 패딩이라
     스위치를 눌러도 이름이 좌우로 밀리지 않는다. */
  padding: .625rem .75rem .625rem 1rem;
  border-radius: 1rem;
  border: 1px solid var(--glass-stroke);
  background-color: rgba(255, 255, 255, .62);
  box-shadow: var(--shadow-glass-sm);
  transition:
    background-color .2s,
    border-color .2s,
    box-shadow .3s var(--ease-glass),
    transform .25s var(--ease-glass);
}
.mn-row:hover {
  transform: translateY(-1px);
  background-color: rgba(255, 255, 255, .92);
  border-color: rgba(255, 255, 255, .95);
  box-shadow: var(--shadow-glass);
}

/* 켜짐 바 ──────────────────────────────────────────────────────────────────
 * 목표는 "왼쪽에 세운 막대"가 아니라 "두꺼운 border-left" 다. 진짜 보더는
 * 바깥쪽 모서리만이 아니라 안쪽 모서리도 곡선이고, 모서리로 갈수록 얇아진다.
 * 세로 직선으로 자르는 mask(90deg)로는 오른쪽 변이 직선이라 그 느낌이 안 난다.
 *
 * → .glass-card::after 와 같은 padding-box mask 기법을 쓴다. padding-left 만
 *   준 채 border-box 와 content-box 를 xor 하면 남는 영역이 정확히 "왼쪽 보더"다.
 *   content-box 의 안쪽 반지름이 가로만 줄어(세로는 유지) 타원 곡선이 되므로,
 *   오른쪽 변에도 굴곡이 생기고 위아래 끝에서 자연스럽게 가늘어진다.
 *
 * ※ clip-path 가 필요한 이유: 이 기법은 padding 을 준 왼쪽만 영역이 남고
 *   위·아래·오른쪽 변에서는 두 박스의 윤곽이 완전히 겹친다. 이론상 xor 결과가
 *   0 이어야 하지만, 두 마스크의 안티에일리어싱이 정확히 상쇄되지 않아
 *   1px 이 안 되는 실같은 찌꺼기가 남는다(특히 오른쪽 둥근 모서리).
 *
 * ※ border-left + border-image 로는 못 한다 — border-image 는 border-radius 를
 *   무시한다. overflow: hidden 도 안 쓴다 — 안쪽 컨트롤의 포커스 링이 잘린다.
 * ------------------------------------------------------------------------ */
.mn-row.is-on::before {
  content: '';
  position: absolute;
  /* -1px — 절대 배치의 기준은 padding box 라 inset: 0 이면 1px 테두리 안쪽에
     들어앉는다. 바깥으로 1px 물려 border box 와 정확히 겹쳐야 흰 테두리를 덮고
     모서리 곡률도 어긋나지 않는다. */
  inset: -1px;
  border-radius: inherit;
  padding-left: 3px;
  pointer-events: none;
  background-image: var(--grad-official-v);   /* 기본값 — 상태 클래스가 덮어쓴다 */
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  clip-path: inset(0 calc(100% - 16px) 0 0);
}

/* 정식 / 테스트 — 바와 아이콘 타일이 같은 계열을 쓴다.
   배지(글자)는 작아서 색만으로는 멀리서 안 읽힌다. 행의 왼쪽 끝(바)과
   아이콘까지 같은 계열로 물들여야 목록을 훑을 때 두 무리로 갈라진다. */
.mn-row--official.is-on::before { background-image: var(--grad-official-v); }
.mn-row--test.is-on::before     { background-image: var(--grad-test-v); }

/* 꺼진 행 — 유리를 얇게. 글자색은 아래에서 한 단계만 낮춘다 */
.mn-row.is-off {
  background-color: rgba(255, 255, 255, .34);
  border-color: rgba(255, 255, 255, .62);
  box-shadow: none;
}
.mn-row.is-off:hover {
  background-color: rgba(255, 255, 255, .78);
  box-shadow: var(--shadow-glass-sm);
}

/* 아이콘 타일 — 켜진 행에서만 브랜드 그라데이션을 켠다 */
.mn-row__icon {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: .75rem;
  font-size: .8125rem;
  color: var(--on-brand);
  background-image: var(--grad-official);
  box-shadow: var(--shadow-official), inset 0 1px 0 rgba(255, 255, 255, .45);
  transition: background-color .25s, box-shadow .3s var(--ease-glass), color .25s;
}
.mn-row--official .mn-row__icon {
  background-image: var(--grad-official);
  box-shadow: var(--shadow-official), inset 0 1px 0 rgba(255, 255, 255, .45);
}
.mn-row--test .mn-row__icon {
  background-image: var(--grad-test);
  box-shadow: var(--shadow-test), inset 0 1px 0 rgba(255, 255, 255, .45);
}
.mn-row.is-off .mn-row__icon {
  background-image: none;
  background-color: rgba(148, 170, 215, .20);
  color: #8FA3C4;
  box-shadow: inset 0 1px 2px rgba(70, 95, 170, .12);
}

/* 텍스트 묶음 — 행에서 유일하게 늘어나는 칸이라 min-width: 0 이 필수다
   (안 주면 긴 설명이 truncate 되지 않고 스위치를 밀어낸다) */
.mn-row__body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .0625rem;
  cursor: pointer;
}
.mn-row__head {
  display: flex;
  align-items: center;
  gap: .375rem;
  min-width: 0;
}
.mn-row__name {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: .875rem;
  font-weight: 600;
  color: var(--ink-900);
}
.mn-row.is-off .mn-row__name { color: var(--body-700); }
.mn-row__desc {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: .75rem;
  line-height: 1.45;
  color: var(--body-600);
}

/* '내가 등록' 표식 — 옆의 상태 배지(정식/테스트)가 이미 파랑·주황이라
   여기까지 색을 쓰면 이름줄이 알록달록해진다. 테두리만 있는 무채색 칩. */
.mn-row__mine {
  flex-shrink: 0;
  padding: 0 .375rem;
  border-radius: 9999px;
  border: 1px solid rgba(148, 170, 215, .45);
  font-size: .625rem;
  font-weight: 600;
  line-height: 1.0625rem;
  color: var(--body-600);
  white-space: nowrap;
}

/* '항상 켜짐' — official 자리에 스위치 대신 서는 표식. 누를 수 없는 것이라
   스위치와 같은 폭을 차지하지 않고, 색은 켜진 상태(초록)를 그대로 빌린다. */
.mn-row__always {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  flex-shrink: 0;
  padding: .1875rem .5rem;
  border-radius: 9999px;
  font-size: .625rem;
  font-weight: 600;
  line-height: 1.0625rem;
  color: #047857;
  background-color: #D1FAE5;
  white-space: nowrap;
}
.mn-row__always i { font-size: 8px; }

/* 조작부 — 아이콘 버튼은 평소 .55 로 물러나 있다가 행에 들어오면 또렷해진다.
   완전히 숨기지 않는 이유: 터치 기기에는 hover 가 없어 영영 안 보인다. */
.mn-row__actions {
  display: flex;
  align-items: center;
  gap: .125rem;
  flex-shrink: 0;
}
.mn-row__act {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.875rem;
  height: 1.875rem;
  border-radius: 9999px;
  border: 0;
  background-color: transparent;
  color: var(--body-600);
  font-size: .8125rem;
  opacity: .55;
  cursor: pointer;
  transition: opacity .2s, background-color .2s, color .2s, box-shadow .3s var(--ease-glass), transform .15s;
}
.mn-row:hover .mn-row__act,
.mn-row__act:focus-visible { opacity: 1; }
.mn-row__act:hover {
  background-color: rgba(255, 255, 255, .95);
  color: var(--ink-900);
  box-shadow: var(--shadow-glass-sm);
}
.mn-row__act:active { transform: scale(.92); }
/* 삭제만 위험색 — hover 전까지는 다른 아이콘과 같은 무게로 둔다 */
.mn-row__act--danger:hover {
  background-color: rgba(255, 228, 232, .95);
  color: #BE123C;                        /* state.danger — .btn-danger 와 같은 값 */
}

/* 스위치는 조작의 끝점이라 얇은 선으로 조작부와 분리한다.
   <label> 이라 이 영역 아무 데나 눌러도 토글된다 — 위아래 패딩을 행 패딩만큼
   주고 같은 크기의 음수 마진으로 상쇄해, 보이는 위치는 그대로 두고 터치
   표적만 행 높이까지 넓힌다(구분선도 덕분에 행 전체 높이로 선다). */
.mn-row__switch {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  padding: .625rem 0 .625rem .625rem;
  margin: -.625rem 0 -.625rem .125rem;
  border-left: 1px solid rgba(148, 170, 215, .28);
  cursor: pointer;
}

/* --- 좁은 화면 ------------------------------------------------------------
 * 360px 에서 아이콘 타일(36) + 조작 2개(60) + 스위치(40) 가 이름 칸을 잡아먹는다.
 * 설명 한 줄은 살리고 타일과 여백만 줄인다 — 스위치는 터치 표적이라 그대로. */
@media (max-width: 639px) {
  .mn-row {
    gap: .5rem;
    padding: .5rem .5rem .5rem .875rem;
  }
  .mn-row__icon {
    width: 2rem;
    height: 2rem;
    border-radius: .625rem;
  }
  /* 행 패딩이 .5rem 으로 줄었으니 상쇄 마진도 같이 맞춘다 */
  .mn-row__switch {
    padding: .5rem 0 .5rem .375rem;
    margin: -.5rem 0 -.5rem .125rem;
  }
}

/* ---------------------------------------------------------------------------
 * 도구 상세 (#mk_detail_view · #mn_detail_view 공용, .tdv-*)
 * ---------------------------------------------------------------------------
 * 이전에는 배지 하나와 설명 한 줄이 전부였다. 목록에서 상세로 들어왔는데
 * 목록의 행 한 줄보다 정보가 적으니, 75vh 짜리 모달이 통째로 비어 보였다.
 * (행에는 아이콘·이름·배지·설명·스위치·삭제가 다 있었다)
 *
 * → 상세를 "그 행이 가진 것을 펼쳐 놓은 화면"으로 만든다. 세 덩어리다.
 *     .tdv-hero     정체    — 아이콘 타일 + 이름 + 배지 + 요약 (행의 확대판)
 *     .tdv-card     내용    — 설명 전문 / 속성 표
 *     .tdv-actions  조작    — 목록에서 하던 일을 여기서도 (스위치·담기·삭제)
 *
 * 표면 어휘는 .mn-row 를 그대로 따른다. 같은 도구를 다루는 화면이 목록에서는
 * 유리 카드, 상세에서는 다른 재질이면 같은 대상으로 안 읽힌다.
 * ------------------------------------------------------------------------ */
.tdv {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  padding: .125rem .125rem .25rem;   /* hover 그림자가 스크롤 경계에서 안 잘리게 */
}

/* 뒤로 — 제목을 겸하던 h4 를 없애고(이름은 히어로가 갖는다) 이동 수단만 남긴다.
   아이콘만 있는 원형 버튼은 "무엇으로" 돌아가는지 안 알려준다. */
.tdv-back {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .3125rem .6875rem .3125rem .5rem;
  border-radius: 9999px;
  color: var(--body-600);
  font-size: .75rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color .2s, color .2s, box-shadow .3s var(--ease-glass), transform .15s;
}
.tdv-back i { font-size: 10px; transition: transform .25s var(--ease-glass); }
.tdv-back:hover {
  background-color: rgba(255, 255, 255, .9);
  color: var(--ink-900);
  box-shadow: var(--shadow-glass-sm);
}
.tdv-back:hover i { transform: translateX(-2px); }
.tdv-back:active { transform: scale(.97); }

/* --- 히어로 -------------------------------------------------------------- */
.tdv-hero {
  display: flex;
  align-items: flex-start;
  gap: .875rem;
  padding: 1rem;
  border-radius: 1.25rem;
  border: 1px solid var(--glass-stroke);
  background-color: rgba(255, 255, 255, .62);
  box-shadow: var(--shadow-glass-sm);
}

/* 아이콘 타일 — 목록 행(36px)의 확대판(52px). 계열색도 행과 같은 것을 쓴다 */
.tdv-hero__icon {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 1rem;
  font-size: 1.125rem;
  color: var(--on-brand);
  background-image: var(--grad-official);
  box-shadow: var(--shadow-official), inset 0 1px 0 rgba(255, 255, 255, .45);
}
.tdv-hero--test .tdv-hero__icon {
  background-image: var(--grad-test);
  box-shadow: var(--shadow-test), inset 0 1px 0 rgba(255, 255, 255, .45);
}
/* 꺼진 도구 — 행과 같은 규칙. 표면만 가라앉히고 글자 대비는 유지한다 */
.tdv-hero.is-off .tdv-hero__icon {
  background-image: none;
  background-color: rgba(148, 170, 215, .20);
  color: #8FA3C4;
  box-shadow: inset 0 1px 2px rgba(70, 95, 170, .12);
}

.tdv-hero__body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .375rem; }
.tdv-hero__name {
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -.01em;
  color: var(--ink-950);
  word-break: break-word;
}
/* 표시 이름을 따로 지은 툴은 기계 이름도 같이 보여준다 — 로그와 force_tool 이 쓰는 식별자라
   사용자가 알아야 할 때가 있다. 표시 이름이 없으면(= 제목이 곧 기계 이름) 이 줄은 안 나온다. */
.tdv-hero__id {
  margin-top: .125rem;
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: .6875rem;
  color: var(--body-600);
  word-break: break-all;
}
.tdv-hero__badges { display: flex; align-items: center; gap: .375rem; flex-wrap: wrap; }
.tdv-hero__desc {
  font-size: .8125rem;
  line-height: 1.7;
  color: var(--body-600);
}

/* 상태 칩 — 정식/테스트 배지(status_badge)와 나란히 서므로 같은 크기·라운드 */
.tdv-chip {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  flex-shrink: 0;
  padding: .0625rem .375rem;
  border-radius: .375rem;
  font-size: .625rem;
  font-weight: 600;
  line-height: 1.0625rem;
  white-space: nowrap;
}
.tdv-chip i { font-size: 8px; }
.tdv-chip--on { color: #047857; background-color: #D1FAE5; }
.tdv-chip--off { color: var(--body-600); background-color: rgba(148, 170, 215, .22); }
/* '내가 등록' — 옆의 배지들이 이미 색을 쓰므로 테두리만 있는 무채색 칩
   (.mn-row__mine 과 같은 판단) */
.tdv-chip--mine {
  padding: 0 .375rem;
  border-radius: 9999px;
  border: 1px solid rgba(148, 170, 215, .45);
  color: var(--body-600);
}

/* --- 카드 (설명 · 속성) --------------------------------------------------- */
.tdv-card {
  padding: .875rem 1rem 1rem;
  border-radius: 1.125rem;
  border: 1px solid var(--glass-stroke);
  background-color: rgba(255, 255, 255, .5);
  box-shadow: var(--shadow-glass-sm);
}
.tdv-card__title {
  display: flex;
  align-items: center;
  gap: .4375rem;
  margin-bottom: .625rem;
  font-size: .8125rem;
  font-weight: 700;
  color: var(--ink-900);
}
.tdv-card__title i { font-size: 11px; color: var(--brand-blue); }

.tdv-desc {
  font-size: .8125rem;
  line-height: 1.8;
  color: var(--body-700);
  white-space: pre-line;
  word-break: break-word;
}
.tdv-desc--empty { color: var(--body-600); font-style: italic; }

/* 속성 — 격자선을 다 그으면 값보다 선이 먼저 보인다. 가로 구분선만 남긴다 */
.tdv-facts { display: flex; flex-direction: column; }
.tdv-fact {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .4375rem 0;
  border-top: 1px solid rgba(99, 130, 220, .10);
}
.tdv-fact:first-child { border-top: 0; padding-top: 0; }
.tdv-fact__k { flex-shrink: 0; font-size: .75rem; color: var(--body-600); }
.tdv-fact__v {
  min-width: 0;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--ink-900);
  text-align: right;
  word-break: break-word;
}
/* 호출 이름은 코드다 — 본문 폰트로 두면 사람이 읽는 라벨처럼 보인다 */
.tdv-fact__v--code {
  padding: .0625rem .375rem;
  border-radius: .375rem;
  background-color: rgba(99, 130, 220, .09);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .75rem;
  color: var(--ink-800);
}
.tdv-fact__v--muted { color: var(--body-600); font-weight: 500; }

/* --- 조작 --------------------------------------------------------------- */
.tdv-actions {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  padding: .75rem 1rem;
  border-radius: 1.125rem;
  border: 1px solid var(--glass-stroke);
  background-color: rgba(255, 255, 255, .5);
  box-shadow: var(--shadow-glass-sm);
}
/* 스위치는 이 화면의 주된 조작이라 왼쪽 끝에 두고, 버튼들을 오른쪽으로 민다 */
.tdv-actions__switch {
  display: flex;
  align-items: center;
  gap: .625rem;
  margin-right: auto;
  cursor: pointer;
}
.tdv-actions__label { display: flex; flex-direction: column; gap: .0625rem; }
.tdv-actions__label b { font-size: .8125rem; font-weight: 600; color: var(--ink-900); }
.tdv-actions__label span { font-size: .6875rem; color: var(--body-600); }

/* 목록에서 빼기 — 평소엔 다른 버튼과 같은 무게, hover 에서만 위험색 */
.tdv-btn-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .375rem;
  min-height: 2.125rem;
  padding: .375rem .875rem;
  border-radius: 9999px;
  border: 1px solid rgba(148, 170, 215, .38);
  background-color: rgba(255, 255, 255, .7);
  color: var(--body-600);
  font-size: .75rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color .2s, border-color .2s, color .2s, box-shadow .3s var(--ease-glass);
}
.tdv-btn-danger i { font-size: 11px; }
.tdv-btn-danger:hover {
  border-color: rgba(190, 18, 60, .35);
  background-color: rgba(255, 228, 232, .95);
  color: #BE123C;
  box-shadow: var(--shadow-glass-sm);
}

@media (max-width: 639px) {
  .tdv-hero { padding: .875rem; gap: .75rem; }
  .tdv-hero__icon { width: 2.75rem; height: 2.75rem; border-radius: .875rem; font-size: 1rem; }
  .tdv-hero__name { font-size: .9375rem; }
  .tdv-card { padding: .75rem .875rem .875rem; }
  .tdv-actions { padding: .625rem .75rem; }
}

/* ---------------------------------------------------------------------------
 * 빈 목록 (마켓 · 내 도구 공용)
 * 글자 한 줄만 가운데 놓으면 "로딩이 덜 됐나?" 로 읽힌다. 아이콘 타일을 세워
 * 의도된 상태임을 알리고, 안내 문구를 한 줄 덧붙일 자리를 만든다.
 * ------------------------------------------------------------------------ */
.tool-empty {
  grid-column: 1 / -1;          /* 마켓은 그리드라 한 줄을 통째로 차지해야 한다 */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .75rem;
  padding: 2.5rem 1rem;
  margin: auto 0;               /* flex 컬럼(내 도구)에서 세로 가운데 */
  text-align: center;
}
.tool-empty__icon {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: 9999px;
  border: 1px solid rgba(255, 255, 255, .9);
  background-color: rgba(255, 255, 255, .7);
  box-shadow: var(--shadow-glass-sm);
  color: var(--ink-500);
  font-size: 1.0625rem;
}
.tool-empty__msg {
  font-size: .875rem;
  font-weight: 500;
  color: var(--body-700);
}
.tool-empty__hint {
  font-size: .75rem;
  color: var(--body-600);
}

/* ---------------------------------------------------------------------------
 * 파일 드롭존
 * 회색 점선 + 회색 배경은 이 시스템에서 유일하게 탁한 면이 된다.
 * 유리 표면 + 브랜드 점선으로 바꾸고, 드래그 중에는 브랜드색으로 물들인다.
 * ------------------------------------------------------------------------ */
.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .625rem;
  width: 100%;
  padding: 2rem 1rem;
  border-radius: 1.25rem;
  border: 1.5px dashed rgba(120, 150, 220, .45);
  background-color: rgba(255, 255, 255, .55);
  background-image: linear-gradient(150deg,
      rgba(255, 255, 255, .6) 0%,
      rgba(255, 255, 255, 0)  55%);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  backdrop-filter: blur(16px) saturate(180%);
  text-align: center;
  cursor: pointer;
  transition:
    border-color .2s,
    background-color .2s,
    box-shadow .3s var(--ease-glass),
    transform .25s var(--ease-glass);
}
.dropzone:hover {
  border-color: var(--brand-blue);
  background-color: rgba(255, 255, 255, .8);
  box-shadow: var(--shadow-glass-sm);
}

/* 두 상태를 같은 자리에 겹쳐 둔다 — 안내문 / 첨부된 파일 */
.dropzone__prompt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .625rem;
}
.dropzone__file {
  display: flex;
  align-items: center;
  gap: .625rem;
  width: 100%;
  text-align: left;
}
.dropzone__file.hidden { display: none; }

/* 파일이 담긴 뒤 — 점선은 "여기에 놓으세요"라는 뜻이라 실선으로 바꾸고,
   빈 영역을 기다릴 이유가 없으니 높이를 줄여 카드 한 줄로 앉힌다. */
.dropzone.has-file {
  padding: .875rem 1rem;
  border-style: solid;
  border-color: rgba(29, 78, 216, .30);
  background-color: rgba(255, 255, 255, .8);
}
.dropzone.has-file .dropzone__prompt { display: none; }
/* 드래그 중 — 파일을 놓을 수 있다는 신호를 확실히 */
.dropzone.is-dragover {
  border-color: var(--brand-blue);
  border-style: solid;
  background-color: rgba(107, 178, 248, .18);
  box-shadow:
    0 8px 22px -10px rgba(70, 110, 215, .5),
    inset 0 0 0 1px rgba(29, 78, 216, .25);
  transform: scale(1.01);
}
/* 드롭존 안 아이콘 — 브랜드 그라데이션 원형 */
/* 드롭존 아이콘 — 배지(원형 그라데이션)가 아니라 아이콘 그 자체.
   업로드 드롭존의 관용 표현은 "구름 + 위 화살표"이고, 이건 실루엣이 곧 의미라
   원 안에 가두면 오히려 정체가 흐려진다. 크게 놓고 색만 브랜드로 준다. */
.dropzone__icon {
  display: block;
  font-size: 2.5rem;
  line-height: 1;
  /* background-clip 미지원 브라우저에서 남을 단색 */
  color: var(--brand-blue);
  opacity: .9;
  transition: transform .25s var(--ease-glass), opacity .2s;
}
/* 아이콘 글리프를 그라데이션으로 — .text-grad 와 같은 기법.
   아이콘 폰트도 결국 텍스트라 background-clip: text 가 그대로 먹는다. */
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  .dropzone__icon {
    background-image: var(--grad-bubble);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
  }
}
.dropzone:hover .dropzone__icon { opacity: 1; }
/* 드래그 중에는 아이콘이 살짝 떠올라 "여기 놓으면 된다"를 강화한다 */
.dropzone.is-dragover .dropzone__icon {
  transform: translateY(-3px);
  opacity: 1;
}

/* 전폭 CTA — 사이드바의 "새 대화" 처럼 가로로 긴 버튼용.
 * 입체 장치(하이라이트·림·드롭섀도·hover 리프트)를 전부 걷어낸 평면 알약이다.
 * 135deg 그라데이션은 폭이 넓어지면 하늘·파랑·분홍이 전부 드러나 산만해지므로
 * 각도만 눕혀 파랑을 중심으로 읽히게 한다. 상태 변화는 밝기로만 표현한다. */
.btn-primary--block {
  width: 100%;
  min-height: 42px;
  padding: .625rem 1rem;
  border-radius: 9999px;
  background-image: linear-gradient(102deg, #58e1ff 0%, #3E8EF0 44%, #1C6FD6 72%, #0F4BD8 100%);
  font-size: .875rem;
  /* 모달 푸터의 CTA 는 600 이지만 사이드바는 세로로 좁고 요소가 촘촘해서
     같은 굵기가 훨씬 무겁게 읽힌다. 사이드바 안에서만 한 단 내린다. */
  font-weight: 500;
  letter-spacing: -.01em;
  box-shadow: none;
  transition: filter .2s;
}
/* ※ box-shadow: none 을 hover/active 에도 다시 써야 한다. 위의 base 규칙만으로는
     .btn-primary:hover(0,2,0) 가 base(0,1,0) 를 이겨서, 마우스를 올리는 순간
     걷어냈던 7겹 입체 그림자가 되살아난다. 접힘 레일의 같은 버튼
     (.rail-btn--brand:hover) 과 규칙을 맞춘다. */
.btn-primary--block:hover {
  transform: none;
  filter: brightness(1.06);
  box-shadow: none;
}
.btn-primary--block:active {
  transform: none;
  filter: brightness(.96);
  box-shadow: none;
}

/* 완만한 CTA — --block 처럼 전부 걷어내지는 않고, 입체 장치의 강도만 낮춘다.
 * 대화 안에 놓이는 버튼용이다(계약서 결과 카드의 "분석 결과 열기" 등). 본문
 * 흐름에 끼어드는 자리라, 모달 푸터의 CTA 와 같은 세기로 부풀면 카드보다
 * 버튼이 먼저 읽힌다.
 *
 * 기본형에서 덜어낸 것:
 *   · 하단 반사광(radial ③) — 구(球)로 읽히게 만드는 층. 통째로 뺀다.
 *   · 상단 돔(②)과 광택 띠(①) — 알파를 절반 아래로.
 *   · 드롭섀도 4겹 → 2겹, 아래 어두운 림(inset 0 -2px 0)은 제거.
 * 남긴 것: 그라데이션 면, 위쪽 밝은 림, 얕은 접지. 여전히 눌리는 버튼으로
 * 읽히되 "부푼 알약"은 아니다. */
.btn-primary--soft {
  background-image:
    linear-gradient(180deg,
        rgba(255, 255, 255, .26) 0%,
        rgba(255, 255, 255, .08) 46%,
        rgba(255, 255, 255, 0)   56%,
        rgba(255, 255, 255, 0)   100%),
    radial-gradient(140% 92% at 50% -34%,
        rgba(255, 255, 255, .28) 0%,
        rgba(255, 255, 255, .06) 46%,
        rgba(255, 255, 255, 0)   72%),
    var(--grad-bubble);
  box-shadow:
    0 1px 2px rgba(40, 70, 160, .16),
    0 8px 16px -8px rgba(70, 110, 215, .34),
    inset 0 1px 0 rgba(255, 255, 255, .55),
    inset 0 -3px 8px -6px rgba(20, 40, 120, .18);
}
/* 뜨는 높이도 2px → 1px. 그림자만 줄이고 리프트를 그대로 두면, 낮아진 그림자
   위에서 버튼만 성큼 올라와 오히려 더 눈에 띈다. */
.btn-primary--soft:hover {
  transform: translateY(-1px);
  filter: brightness(1.04);
  box-shadow:
    0 1px 2px rgba(40, 70, 160, .12),
    0 12px 22px -8px rgba(70, 110, 215, .38),
    inset 0 1px 0 rgba(255, 255, 255, .60),
    inset 0 -3px 8px -6px rgba(20, 40, 120, .18);
}
.btn-primary--soft:active {
  transform: translateY(0);
  filter: brightness(.98);
  box-shadow:
    0 1px 2px rgba(40, 70, 160, .20),
    inset 0 1px 0 rgba(20, 40, 120, .14);
}

/* 어두운 그라데이션 위에서는 흰 아웃라인이 더 잘 보인다 */
.btn-primary:focus-visible,
.circle-btn-brand:focus-visible {
  outline-color: #FFFFFF;
  box-shadow: 0 0 0 4px var(--ink-600);
}

/* 세컨더리 (글래스) */
.btn-secondary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 44px;
  padding: .75rem 1.5rem;
  border-radius: 9999px;
  border: 1px solid rgba(255, 255, 255, .9);
  background-color: rgba(255, 255, 255, .85);
  color: var(--ink-900);
  font-size: .875rem;
  font-weight: 600;
  box-shadow: var(--shadow-glass-sm);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
  backdrop-filter: blur(20px) saturate(150%);
  transition: transform .3s var(--ease-glass), background-color .2s;
}
.btn-secondary:hover { transform: translateY(-2px); background-color: #FFFFFF; }

/* 블록 세컨더리 — 사이드바에서 New Chat 바로 아래 짝으로 놓인다.
   높이·라운드·글자 크기를 --block 프라이머리와 1:1 로 맞추고, hover 리프트도
   똑같이 죽인다. 좁은 사이드바에서 버튼만 떠오르면 목록이 흔들려 보인다.

   ※ 반드시 .btn-secondary "뒤"에 와야 한다. 앞에 두면 특정도가 같아(0,1,0)
     기본값(min-height 44 / padding 12px / font-weight 600)이 이겨서
     New Chat 보다 5px 높아진다 — 실제로 그 상태였다. */
.btn-secondary--block {
  width: 100%;
  min-height: 42px;
  padding: .625rem 1rem;
  font-size: .875rem;
  font-weight: 500;        /* --block 프라이머리와 같은 굵기 */
  letter-spacing: -.01em;
  /* 사이드바에서는 이 알약도 옆의 타일·묶음과 같은 유리여야 한다.
     기본 .btn-secondary(흰 85% / blur 20)는 이 화면에서 혼자 불투명해 보인다. */
  background-color: rgba(255, 255, 255, .46);
  background-image: linear-gradient(125deg,
      rgba(255, 255, 255, .5) 0%,
      rgba(255, 255, 255, 0)  38%,
      rgba(255, 255, 255, .26) 100%);
  box-shadow:
    0 1px 3px rgba(70, 95, 170, .06),
    0 16px 34px -18px rgba(70, 95, 170, .40),
    inset 1px 1px 0 rgba(255, 255, 255, 1),
    inset -1px -1px 0 rgba(255, 255, 255, .55);
  -webkit-backdrop-filter: blur(30px) saturate(235%) brightness(1.03);
          backdrop-filter: blur(30px) saturate(235%) brightness(1.03);
  transition: background-color .2s, box-shadow .3s var(--ease-glass);
}
.btn-secondary--block:hover {
  transform: none;
  background-color: rgba(255, 255, 255, .62);
  box-shadow:
    0 1px 3px rgba(70, 95, 170, .07),
    0 22px 44px -18px rgba(70, 95, 170, .48),
    inset 1px 1px 0 rgba(255, 255, 255, 1),
    inset -1px -1px 0 rgba(255, 255, 255, .6);
}
.btn-secondary--block:active { transform: none; }
/* 프라이머리 아이콘은 흰색(그라데이션 위)이라 색 지정이 필요 없지만,
   유리 표면 위에서는 아이콘이 라벨과 같은 무게로 묻힌다 → 브랜드색으로 분리 */
.btn-secondary--block > i { color: var(--brand-blue); }

/* 사이드바 액션 알약 (New Chat · Search) ───────────────────────────────────
 * macOS 제어 센터(레퍼런스 1764078101-image7.jpg)의 알약을 옮겨왔다. 그 화면의
 * 요소들은 전부 같은 문법으로 되어 있다:
 *
 *   [ ● 아이콘 ]  라벨          ← 원형 배지 + 왼쪽 정렬 라벨, 알약 컨테이너
 *
 * 핵심은 "아이콘과 라벨이 나란한 한 줄"이 아니라 **아이콘이 자기 원을 갖는다**
 * 는 점이다. Wi-Fi 는 유리 알약 안에 파란 원, 블루투스는 흰 원 안에 파란 글리프.
 * 배지가 있으면 컨테이너 표면을 아무리 옅게 깔아도 요소가 흐물거리지 않는다 —
 * 대비를 배지가 혼자 감당하므로 면은 계속 투명할 수 있다. 유리 UI 가 아이콘을
 * 다루는 방식이 이거다.
 *
 * 예전 .btn-primary--block / .btn-secondary--block(가운데 정렬 · 맨몸 글리프)
 * 을 여기서만 갈아탄다. 두 --block 클래스는 계약서 패널·모달에서도 쓰이므로
 * 건드리지 않는다.
 *
 * ※ 폭 계산 — 사이드바는 xl:w-72(288px)다. 2열로 놓으면 좌우 여백과 gap 을
 *   빼고 한 칸이 약 125px 밖에 안 된다. 배지 34 + 간격 8 + "New Chat"
 *   (13px/600 ≈ 62px) + 좌 5 / 우 10 = 119px 로 겨우 들어간다. 라벨을 더
 *   길게 쓰거나 배지를 키우면 넘치므로 .aside-action__label 에 truncate 를
 *   걸어 뒀다 — 넘쳐도 레이아웃이 깨지는 대신 말줄임으로 끝난다.
 * ------------------------------------------------------------------------ */
.aside-action {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  min-height: 44px;
  /* 왼쪽 패딩이 5px 뿐인 건 배지가 그 자리를 채우기 때문이다. 배지와 알약의
     곡률이 동심원이 되려면 (알약 높이 - 배지 지름) / 2 = 5px 여야 한다. */
  padding: .3125rem .625rem .3125rem .3125rem;
  border-radius: 9999px;
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: -.01em;
  text-align: left;
  transition:
    background-color .2s,
    box-shadow .3s var(--ease-glass),
    filter .2s;
}

/* 원형 배지 — 34px. 44px 알약 안에서 위아래 5px 씩 남는 크기다.
   더 키우면 알약을 꽉 채워 "원 안의 원"이 아니라 잘린 도넛으로 보인다. */
.aside-action__badge {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 2.125rem;
  height: 2.125rem;
  border-radius: 9999px;
  font-size: 12.5px;
}

/* 라벨이 배지를 밀어내지 않도록. min-width:0 이 없으면 flex 자식은 자기
   콘텐츠보다 작아지지 않아 truncate 가 동작하지 않는다. */
.aside-action__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 프라이머리(New Chat) — 레퍼런스의 Display/Sound 행처럼 면 자체가 브랜드색인
   "켜진" 요소다. 배지는 반대로 흰 원 + 파란 글리프(블루투스 켜짐과 같은 처리).
   이 페이지의 유일한 그라데이션이라는 위치는 그대로 유지된다. */
/* 알파를 넣은 이유 — 레퍼런스의 Display/Sound 막대는 "파란 판"이 아니라
 * 파란 유리다. 뒤 배경이 비쳐야 그 재질이 나온다.
 *
 * ※ 그냥 투명하게만 하면 흰 글자가 무너진다. 원래 값(#1C6FD6 불투명)에서
 *   흰 글자 대비가 4.56:1 로 이미 AA(4.5) 턱걸이였다. 여기에 알파만 먹이면
 *   밝은 배경이 섞여 3.7:1 까지 내려간다.
 *   → 스톱을 그만큼 더 깊게 내려서 상쇄했다. 라벨이 놓이는 40~100% 구간을
 *     밝은 사이드바 배경 위에서 합성하면 약 4.9:1 로, 오히려 전보다 여유가
 *     생긴다. 스톱을 밝게 되돌리거나 알파를 더 낮추면 이 여유가 사라진다.
 * ※ 0% 스톱만 밝은 시안인 건 그 자리를 흰 배지가 덮기 때문이다 — 글자가
 *   지나가지 않는 구간이라 채도를 살려도 대비에 영향이 없다. */
.aside-action--primary {
  background-image: linear-gradient(102deg,
      rgba(28, 150, 205, .86)   0%,
      rgba(24,  96, 190, .89)  40%,
      rgba(20,  80, 182, .90)  72%,
      rgba(14,  62, 174, .92) 100%);
  color: var(--on-brand);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .3);
  /* 반투명해진 만큼 뒤가 그대로 비치면 지저분하다. 배경의 블롭을 뭉개서
     "유리 너머"로 만든다 — 사이드바는 xl 이상에서 투명이라 이 뒤에 있는 건
     실제 페이지 배경이다(세션 행과 달리 블러할 무늬가 있다). */
  -webkit-backdrop-filter: blur(24px) saturate(180%);
          backdrop-filter: blur(24px) saturate(180%);
}
.aside-action--primary .aside-action__badge {
  background-color: rgba(255, 255, 255, .96);
  color: var(--brand-blue);
}
.aside-action--primary:hover { filter: brightness(1.06); }
.aside-action--primary:active { filter: brightness(.96); }
/* 어두운 그라데이션 위에서는 흰 아웃라인이 더 잘 보인다(.btn-primary 와 동일) */
.aside-action--primary:focus-visible {
  outline-color: #FFFFFF;
  box-shadow: 0 0 0 4px var(--ink-600);
}

/* 세컨더리(Search) — 유리 알약. 표면은 .btn-secondary--block 에서 그대로
   가져왔다(같은 사이드바, 같은 재질이어야 한다). 배지만 새로 얹는다. */
.aside-action--glass {
  /* .btn-secondary--block 은 .46 이었다. 뒤가 비치게 .28 까지 내린다 —
     글자가 --ink-900(14.3:1)이라 면이 옅어져도 대비는 문제되지 않는다.
     대신 면이 얇아진 만큼 가장자리 스페큘러(inset)로 형태를 잡아 준다. */
  background-color: rgba(255, 255, 255, .28);
  background-image: linear-gradient(125deg,
      rgba(255, 255, 255, .42) 0%,
      rgba(255, 255, 255, 0)   38%,
      rgba(255, 255, 255, .2) 100%);
  color: var(--ink-900);
  box-shadow:
    0 1px 3px rgba(70, 95, 170, .05),
    0 16px 34px -18px rgba(70, 95, 170, .32),
    inset 1px 1px 0 rgba(255, 255, 255, .95),
    inset -1px -1px 0 rgba(255, 255, 255, .5);
  -webkit-backdrop-filter: blur(30px) saturate(235%) brightness(1.03);
          backdrop-filter: blur(30px) saturate(235%) brightness(1.03);
}
/* 유리 위의 유리라 배지는 흰 원 하나로 충분하다 — 여기에 그림자까지 주면
   반투명한 면 위에 불투명한 알약이 얹힌 것처럼 층이 하나 더 생긴다. */
.aside-action--glass .aside-action__badge {
  background-color: rgba(255, 255, 255, .78);
  color: var(--brand-blue);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .9);
}
.aside-action--glass:hover {
  background-color: rgba(255, 255, 255, .62);
  box-shadow:
    0 1px 3px rgba(70, 95, 170, .07),
    0 22px 44px -18px rgba(70, 95, 170, .48),
    inset 1px 1px 0 rgba(255, 255, 255, 1),
    inset -1px -1px 0 rgba(255, 255, 255, .6);
}
.aside-action--glass:hover .aside-action__badge {
  background-color: rgba(255, 255, 255, .95);
}

/* 바로가기 4개(기술 트렌드 · 계약서 · 마켓 · 툴 설정) ────────────────────────
 * 넷이 .glass-group--slide 유리판 하나에 담긴다(세션 목록·프로필과 같은 판).
 * 그래서 행은 자기 면을 갖지 않는다 — 판 위에 반투명 알약을 넷 얹으면 흰색이
 * 두 겹이 되어 판의 경계가 흐려지고, 묶음이 아니라 "떠 있는 조각 넷"이 된다.
 * 평소에는 배지의 색과 라벨만 보이고, 표면은 hover 에서만 나타난다.
 * #aside_scroll 안의 .session-row 와 정확히 같은 규칙이다.
 *
 * ※ backdrop-filter 도 없다. 행 뒤에 있는 건 이제 균일한 유리판 한 장이라
 *   블러해도 굴절될 무늬가 없다 — .session-row 에서 뺐던 것과 같은 이유다.
 *   (New Chat/Search 는 판 밖에 맨몸으로 떠 있어서 뒤가 실제 페이지 배경이다.
 *    거기서는 backdrop-filter 가 제 일을 한다.)
 *
 * 예전에는 이 자리에 .glass-card--crystal + .glass-sheen + Tailwind 그라데
 * 이션이 겹쳐 있었고 hover 마다 2px 씩 떠올랐다. 표면을 세 겹 쌓은 만큼
 * 레퍼런스의 납작한 알약과는 반대 방향이었다. 리프트를 뺀 이유도 같다 —
 * 제어 센터의 요소들은 눌려도 뜨지 않는다.
 * ------------------------------------------------------------------------ */
.aside-action--tile {
  background-color: transparent;
  color: var(--ink-900);
  font-weight: 500;   /* New Chat/Search(600)보다 한 단 아래 — 목록이지 CTA 가 아니다 */
}
.aside-action--tile:hover {
  background-color: rgba(255, 255, 255, .58);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .8);
}
.aside-action--tile:active { background-color: rgba(255, 255, 255, .7); }
/* 채색 배지 위 글리프는 흰색이다(.icon-tile--gN 과 같은 규칙). 배지 색 자체는
   .aside-action__badge--gN 이 얹는다 — 정의는 .icon-tile--gN 과 한 줄에 있다. */
.aside-action--tile .aside-action__badge { color: #FFFFFF; }

/* 리스트형 글래스 아이템 */
.glass-item {
  display: block;
  border-radius: 1.125rem;
  border: 1px solid rgba(255, 255, 255, .8);
  background-color: rgba(255, 255, 255, .72);
  padding: .875rem;
  transition: background-color .2s, box-shadow .3s var(--ease-glass);
}
.glass-item:hover {
  background-color: #FFFFFF;
  box-shadow: var(--shadow-glass-sm);
}

/* 헤딩 강조어 — 텍스트 그라데이션 (레퍼런스의 "through AI", "Blank PLUS")
   ※ 20px 이상 헤딩에만. 작은 글씨에 쓰면 색이 뭉개져 오히려 안 읽힌다.
   ※ 지원하지 않는 브라우저에서는 --brand-blue 단색으로 남는다. */
.text-grad {
  color: var(--brand-blue);
  /* 디센더(g, y, ㅜ)가 잘리는 것을 막는 여유 */
  padding-bottom: .06em;
  margin-bottom: -.06em;
}
@supports ((background-clip: text) or (-webkit-background-clip: text)) {
  .text-grad {
    background-image: var(--grad-text);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
  }
}

/* 글자 뒤 흰 확산광 — 배경 구체·그라데이션 위에 얹힌 글자의 대비를 세운다.
   ※ text-shadow 가 아니라 filter: drop-shadow 다. .text-grad 는 배경을 글자
      모양으로 오려 쓰므로(background-clip: text) text-shadow 를 주면 그림자가
      그라데이션 위를 덮어 색을 뭉갠다. drop-shadow 는 이미 그려진 결과의
      바깥으로만 번지므로 그라데이션이 그대로 남는다.
   ※ 좁게 한 겹, 넓게 한 겹. 좁은 쪽이 글자 획을 배경에서 떼어내고 넓은 쪽이
      그 경계를 감춘다. 다만 흰빛이 보이기 시작하면 글자가 떠 보이므로, 배경이
      비쳐 보일 만큼만 옅게 — 있는지 모를 정도가 이 장치의 적정선이다. */
.text-halo {
  filter:
    drop-shadow(0 0 4px rgba(255, 255, 255, .25))
    drop-shadow(0 0 12px rgba(255, 255, 255, .25));
}

/* 아이콘 타일 */
.icon-tile {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: .75rem;
  color: var(--ink-800);
  font-size: .875rem;
  border: 1px solid rgba(255, 255, 255, .5);
  background-color: rgba(255, 255, 255, .34);
  background-image: linear-gradient(125deg,
      rgba(255, 255, 255, .60) 0%,
      rgba(255, 255, 255, 0)   52%,
      rgba(255, 255, 255, .26) 100%);
}

/* ---------------------------------------------------------------------------
 * 5a. SIDEBAR — chat.html 의 aside 전용
 * ---------------------------------------------------------------------------
 * index.html 의 어휘(icon-btn · glass-item · icon-tile · btn-primary)를 그대로
 * 쓰되, 사이드바 밀도에 맞춰 크기만 줄인 변형이다. 색/그림자/이징은 위 컴포넌트와
 * 동일한 토큰을 참조하므로 토큰을 바꾸면 사이드바도 함께 따라온다.
 *
 * ※ display 를 지정하는 클래스들은 Tailwind 의 hidden / flex 유틸리티와 함께
 *   쓰인다. CDN 은 이 파일보다 나중에 <style> 을 주입하므로 유틸리티가 이긴다
 *   (index.html 의 `icon-btn hidden sm:inline-flex` 와 같은 전제).
 * ------------------------------------------------------------------------ */

/* --- 사이드바 껍데기 --------------------------------------------------------
 * 데스크톱(xl+)에서는 면이 없다. 예전에는 사이드바 전체가 한 장의 .glass-panel
 * 이었고 그 안을 헤어라인으로 나눴는데, 배경이 이미지가 되면서 그 큰 유리판이
 * 화면 왼쪽을 통째로 덮어 배경이 오른쪽에만 남았다.
 * → 껍데기는 투명하게 비우고, 안의 묶음(New Chat · Search · 타일 · 세션 ·
 *   프로필)이 각자 유리로 떠 있게 한다. 배경이 묶음 사이로 그대로 지나간다.
 *
 * xl 미만은 사정이 다르다. 여기서 aside 는 화면을 덮는 드로어라, 투명하면
 * 뒤의 대화가 그대로 비쳐 목록을 읽을 수 없다. → 그때만 유리 면을 갖는다.
 * ------------------------------------------------------------------------ */
.aside-shell {
  background-color: var(--glass-50);
  box-shadow: var(--shadow-glass-lg);
  /* .glass-panel 과 같은 광학 — brightness 누락으로 카드보다 어두웠다 */
  -webkit-backdrop-filter: blur(40px) saturate(200%) brightness(1.03);
          backdrop-filter: blur(40px) saturate(200%) brightness(1.03);
}

/* --- 모바일 드로어의 어두운 스크림 (xl 미만) --------------------------------
 * 껍데기를 흰 유리(--glass-50 = 흰색 .62)로 두면 안의 묶음들도 전부 흰 유리라
 * 판과 껍데기가 같은 톤이 된다. 경계가 사라져 "환한데 아무것도 안 보이는"
 * 화면이 되는데, 대비를 만들 색이 화면에 하나도 없기 때문이다.
 * → 껍데기만 어둡게 뒤집는다. 그러면 흰 판들이 어두운 바탕 위에 뜬 조각으로
 *   읽히고, 판 안의 잉크색 글자는 그대로 쓸 수 있다. 안쪽을 다크 테마로
 *   바꾸는 것보다 손대는 곳이 훨씬 적다.
 *
 * blur 는 40 → 20px 로 내렸다. 40px 는 뒤를 완전히 뭉개서 "닫힌 판"이 되는데,
 * 드로어는 대화 위에 임시로 덮이는 것이라 뒤가 어렴풋이 보이는 편이 낫다.
 * brightness(1.03)도 뺐다 — 어두운 스크림을 다시 들어올려 탁해진다.
 * ------------------------------------------------------------------------ */
@media (max-width: 1279px) {
  .aside-shell {
    background-color: rgba(9, 20, 38, .55);
    -webkit-backdrop-filter: blur(20px) saturate(130%);
            backdrop-filter: blur(20px) saturate(130%);
  }

  /* 판을 두르지 않고 껍데기 위에 바로 놓이는 것들 ─ 상단 바의 로고와 닫기 버튼.
     둘 다 어두운 잉크색이라 스크림 위에서 그대로 묻힌다.
     로고는 색이 두 가지(#0058A6 / #334156) 구워진 SVG 라 color 가 안 먹는다.
     brightness(0) 로 전부 검게 만든 뒤 invert(1) 로 뒤집으면 알파는 유지한 채
     흰 로고가 된다 — .icon-tile--gN img 가 쓰는 것과 같은 수법이다. */
  .aside-logo {
    filter: brightness(0) invert(1);
    opacity: .92;
  }
  /* ※ 반드시 .aside-topbar 로 스코프를 잡을 것. 그냥 .aside-shell .rail-btn 으로
       두면 프로필 묶음의 로그아웃 버튼(같은 .rail-btn)까지 흰 글리프가 되는데,
       그건 흰 유리판 위에 있어서 그대로 사라진다. */
  .aside-topbar .rail-btn {
    color: rgba(255, 255, 255, .92);
  }
  /* hover 에 흰 면(.85)을 깔면 흰 글리프가 그 위에서 사라진다. 면은 살짝만
     밝히고 글리프는 흰색으로 유지한다. */
  .aside-topbar .rail-btn:hover {
    background-color: rgba(255, 255, 255, .18);
    color: #FFFFFF;
  }

  /* Search 알약 — 흰색 .28 은 밝은 배경 위에서 나온 값이다. 어두운 스크림
     위에서는 중간 회색이 되어 --ink-900 글자가 안 읽힌다. 아래 유리판들과
     같은 밝기까지 올려 "어두운 바탕 위의 흰 조각" 하나로 통일한다. */
  .aside-action--glass {
    background-color: rgba(255, 255, 255, .82);
  }
  .aside-action--glass:hover {
    background-color: rgba(255, 255, 255, .92);
  }

  /* 유리판 3종(바로가기 · 세션 목록 · 프로필). 흰색 .72 → .50 은 흰 배경
     기준이라, 어두운 스크림 위에서는 가운데(.50)가 중간 회색까지 내려간다.
     판 전체를 한 단 올려 잉크색 글자의 대비를 지킨다. */
  .glass-group--slide {
    background-image: linear-gradient(150deg,
        rgba(255, 255, 255, .88) 0%,
        rgba(255, 255, 255, .74) 60%,
        rgba(255, 255, 255, .82) 100%);
  }
}

@media (min-width: 1280px) {
  .aside-shell {
    background-color: transparent;
    box-shadow: none;
    /* 껍데기는 아무것도 하지 않는다 ───────────────────────────────────────
     * 면도, 필터도 없다. 사이드바 여백과 본문 여백이 "같은 배경 이미지를
     * 같은 밝기로" 보여주는 게 목적이라, 한쪽에만 걸리는 보정은 그 자체가
     * 어긋남을 만든다. saturate/brightness 로 톤을 맞춰본 적이 있는데,
     * 배경이 밝은 구간과 어두운 구간에서 보정량이 달라야 해서(흰 오버레이는
     * 어두운 쪽을 더 들어올리고 brightness 는 비율로 곱한다) 어디를 맞추면
     * 어디가 틀어졌다. 양쪽 다 원본으로 두는 게 유일하게 정확하다.
     * ------------------------------------------------------------------ */
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
  }
}

/* --- 묶음(그룹) 유리판 ------------------------------------------------------
 * 사이드바 안에서 "한 덩어리로 읽혀야 하는 것"을 담는 면 — 세션 목록, 계정,
 * 접힘 레일.
 *
 * 표면 값은 컴포저(#chat_composer_box = .glass-card--sheer)와 같은 규격이다:
 * 흰 46% / blur 30px / saturate 235%. 사이드바만 더 불투명하면 같은 화면에서
 * 유리가 두 종류로 보인다. 채도를 크게 올리는 게 핵심 — 판 "안쪽"만 배경색이
 * 진해져서, 흰 면을 얹은 게 아니라 유리를 통과해 보이는 것으로 읽힌다.
 *
 * 그림자도 컴포저와 같은 3단(접지 1px + 깊은 확산 + 안쪽 림)이라 판이 배경에서
 * 확실히 떠오른다. 라운드는 .nav-tile(24px)과 맞춘다 — 같은 층에 나란히 떠 있는
 * 면들이라 반지름이 다르면 하나만 다른 부품처럼 보인다.
 * ------------------------------------------------------------------------ */
.glass-group {
  border-radius: 1.5rem;
}

/* --- 덱 슬라이드 표면 ------------------------------------------------------
 * 레퍼런스(레퍼런스/테크GPT_v2_실무회의_통합.html 의 .slide)의 유리판을 그대로
 * 옮긴 것. 값은 원본에서 손대지 않았다 — 150deg 흰 그라데이션 한 장 + 1px 흰
 * 실선 + blur(30px) saturate(1.5).
 *
 * 쓰는 곳은 두 종류다. 사이드바의 묶음 판(.glass-group--slide: 바로가기 ·
 * 세션 목록 · 프로필)과 컴포저(.glass-card--slide: #chat_composer_box).
 * 면은 완전히 같고 바깥 그림자만 다르다 — 아래 각주 참고.
 *
 * 기본형(=--crystal 계열)과 다른 점은 두 가지다.
 *   · 면이 "위 30% → 아래 0" 세로 그라데이션이 아니라 150deg 대각선이고,
 *     아래쪽이 다시 밝아진다(.50 → .60). 판이 아래에서 한 번 더 빛을 받는다.
 *   · 테두리가 투명이 아니라 흰 실선이다. 그래서 굴절광 링(::after)을 끈다 —
 *     안 끄면 실선 위에 그라데이션 링이 겹쳐 가장자리만 두꺼워진다.
 *
 * ※ .slide.on 의 fade 애니메이션은 옮기지 않았다. 덱에서 슬라이드를 넘길 때
 *   쓰는 장치라, 사이드바에 붙이면 페이지를 열 때마다 목록 판이 한 번 떠오른다.
 * ------------------------------------------------------------------------ */
.glass-group--slide,
.glass-card--slide {
  background-color: transparent;
  background-image: linear-gradient(150deg,
      rgba(255, 255, 255, .72) 0%,
      rgba(255, 255, 255, .50) 60%,
      rgba(255, 255, 255, .60) 100%);
  border-color: rgba(255, 255, 255, .72);
  border-radius: 22px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .85);
  -webkit-backdrop-filter: blur(30px) saturate(150%);
          backdrop-filter: blur(30px) saturate(150%);
}
.glass-group--slide::after,
.glass-card--slide::after { display: none; }
/* 상단 반사도 끈다. --crystal 이 이미 막고 있지만(.glass-card--crystal.glass-sheen),
   그건 마크업에 --crystal 이 함께 있을 때만이다. 여기서 한 번 더 막아두면
   나중에 --crystal 을 떼도 6rem 짜리 흰 물결이 조용히 되살아나지 않는다. */
.glass-card--slide.glass-sheen::before { content: none; }

/* 바깥 드롭섀도 — 원본(.slide)의 90px 번짐은 잘리지 않는 자리에서만 쓸 수 있다.
 *
 * 컴포저는 #chat_box 위에 떠 있고 자르는 조상이 없다 → 항상 켠다.
 * 사이드바 판은 #aside 가 overflow:hidden 인 구간(1280px 미만)에서 판 경계에
 * 딱 잘려 계단으로 보인다 — "aside 유리만의 예외" 주석이 그림자를 뺀 이유가
 * 그것이다. chat.css 가 1280px 부터 overflow:visible 로 풀어주므로 거기서만
 * 살린다. */
.glass-card--slide {
  box-shadow:
    0 34px 90px -28px rgba(22, 44, 80, .36),
    inset 0 1px 0 rgba(255, 255, 255, .85);
}
@media (min-width: 1280px) {
  .glass-group--slide {
    box-shadow:
      0 34px 90px -28px rgba(22, 44, 80, .36),
      inset 0 1px 0 rgba(255, 255, 255, .85);
  }
}

/* 사이드바 상단 바 / 접힘 레일의 아이콘 버튼 — icon-btn(44px)은 h-14 바에 과하다 */
.rail-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 9999px;
  color: var(--ink-800);
  transition: background-color .2s, box-shadow .3s var(--ease-glass), transform .15s;
}
.rail-btn:hover {
  background-color: rgba(255, 255, 255, .85);
}
.rail-btn:active { transform: scale(.94); }

/* --- 접힘 레일 ------------------------------------------------------------
 * 접힌 사이드바가 투박해지는 건 "아이콘만 남아서"가 아니라, 남은 아이콘들이
 * 서로 관계 없이 세로로 늘어서기 때문이다. 셋으로 나눠 리듬을 만든다.
 *   ① 브랜드(Orb)  ② 액션(New Chat·검색)  ③ 바로가기 타일 4개
 * 구간 사이는 .rail-sep 한 줄로만 끊는다.
 * ----------------------------------------------------------------------- */

/* 브랜드 겸 펼치기 버튼 — 평소엔 Orb(로고 자리), 올리면 펼치기 화살표.
   컨트롤을 하나로 합쳐 접힘 상태 최상단이 "떠 있는 토글"로 보이지 않게 한다. */
.rail-brand {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 9999px;
  transition: transform .2s var(--ease-glass);
}
.rail-brand:active { transform: scale(.94); }

/* 둘을 같은 그리드 칸에 겹쳐 놓는다. absolute 로 띄우면 inset 을 따로 잡아야
   하고, 부모의 place-items:center 도 못 쓴다. */
.rail-brand__logo,
.rail-brand__chev { grid-area: 1 / 1; }

/* 미니 로고(99×38, 약 2.6:1). 정사각 박스에 넣으면 찌그러지므로 가로를
   버튼 폭(2.25rem)에 가깝게 두고 object-fit: contain 으로 비율을 지킨다.
   높이는 접힘 레일의 다른 버튼과 같은 리듬을 유지하도록 1.75rem 로 잡되,
   contain 이라 실제로는 그 안에서 세로 중앙에 얇게 놓인다. */
.rail-brand__logo {
  width: 2rem;
  height: 1.75rem;
  object-fit: contain;
  transition: opacity .2s, transform .3s var(--ease-glass);
}
.rail-brand__chev {
  font-size: .75rem;
  color: var(--ink-800);
  opacity: 0;
  transition: opacity .2s;
}
.rail-brand:hover .rail-brand__logo,
.rail-brand:focus-visible .rail-brand__logo { opacity: .22; transform: scale(.92); }
.rail-brand:hover .rail-brand__chev,
.rail-brand:focus-visible .rail-brand__chev { opacity: 1; }

/* 레일의 바로가기 — 펼침 상태 2×2 타일의 축약. 라운드와 tint 를 그대로 물려
   받아, 접었다 폈을 때 같은 것이 모양만 바뀐 것으로 읽히게 한다. */
.rail-tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: .875rem;
  color: var(--ink-800);
  font-size: .8125rem;
  /* 표면(배경·테두리·blur·saturate)은 여기서 쓰지 않는다 — 위쪽
     .glass-card / .glass-card--sheer 규칙을 공유해 컴포저와 같은 값을
     그대로 받는다. 값을 여기 또 적으면 한쪽만 고쳤을 때 어긋난다. */
  transition: transform .2s var(--ease-glass), box-shadow .3s var(--ease-glass);
}
.rail-tile:hover {
  transform: translateY(-1px);
}
.rail-tile:active { transform: translateY(0) scale(.96); }

/* 구간 구분선 — 흰 헤어라인은 유리 위에서 사라지므로 옅은 블루로 */
.rail-sep {
  width: 1.5rem;
  height: 1px;
  margin: .25rem 0;
  border-radius: 9999px;
  background-color: rgba(99, 130, 220, .18);
}

/* 그라데이션 레일 버튼 — 접힘 상태의 New Chat.
   펼침 상태의 btn-primary--block 과 같은 버튼이므로 평면 처리도 똑같이 맞춘다. */
.rail-btn--brand {
  background-image: var(--grad-bubble);
  color: var(--on-brand);
  box-shadow: none;
}
.rail-btn--brand:hover {
  background-color: transparent;
  filter: brightness(1.06);
  box-shadow: none;
}

/* 런처 / 메뉴 항목 — glass-item 을 한 줄 높이로 줄인 것.
   평소엔 투명하고 hover 에서만 유리판이 떠오른다(목록이 길어도 시끄럽지 않게). */
.nav-item {
  display: flex;
  align-items: center;
  gap: .625rem;
  width: 100%;
  padding: .4375rem .625rem;
  border-radius: 1rem;
  border: 1px solid transparent;
  font-size: .875rem;
  font-weight: 500;
  color: var(--body-700);
  text-align: left;
  transition: background-color .2s, border-color .2s, box-shadow .3s var(--ease-glass), color .2s;
}

/* 바로가기 타일 — 리스트 행이 아니라 "눌리는 버튼"으로 읽히게.
   표면(유리) + 테두리 + 그림자로 떠 있고, hover 에 뜨고 active 에 눌린다. */
.nav-tile {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .5rem;
  padding: .75rem;
  border-radius: 1.5rem;
  font-size: .8125rem;
  font-weight: 500;        /* 사이드바 버튼 공통 굵기 */
  line-height: 1.35;
  color: var(--ink-900);
  text-align: left;
  word-break: keep-all;
  cursor: pointer;
  transition:
    transform .25s var(--ease-glass),
    box-shadow .25s var(--ease-glass),
    background-color .2s;
}
/* hover 는 "불투명해지는" 게 아니라 "더 떠오르는" 것으로만 표현한다.
   .88 까지 채우면 손이 닿을 때마다 유리가 흰 판으로 바뀌어 버린다. */
.nav-tile:hover {
  transform: translateY(-2px);
  background-color: rgba(255, 255, 255, .62);
  box-shadow:
    inset 1px 1px 0 rgba(255, 255, 255, 1),
    inset -1px -1px 0 rgba(255, 255, 255, .6),
    inset 0 0 32px rgba(255, 255, 255, .22);
}
/* 눌리는 느낌 — 살짝 내려앉고 그림자가 줄어든다 */
.nav-tile:active {
  transform: translateY(0) scale(.98);
  box-shadow:
    inset 0 1px 3px rgba(70, 95, 170, .16);
}
.nav-item:hover {
  background-color: rgba(255, 255, 255, .8);
  border-color: rgba(255, 255, 255, .9);
  box-shadow: var(--shadow-glass-sm);
  color: var(--ink-900);
}

/* icon-tile 의 사이드바 버전 (36px → 28px) */
.icon-tile--sm {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: .625rem;
  font-size: .75rem;
}

/* --- 런처 타일의 파스텔 그라데이션 ------------------------------------------
 * 사이드바의 유리판은 전부 흰색 하나로 통일했다. 그래서 자리를 구분하는
 * 색은 아이콘 타일 하나만 갖는다 — 판이 무채색일 때 작은 채색면이 오히려
 * 또렷하게 읽힌다.
 *
 * 파스텔로 묶은 이유: 타일이 28px 밖에 안 된다. 진한 색을 쓰면 이 크기에서
 * 색점 네 개가 튀어 목록이 아니라 신호등처럼 보인다. 명도를 높게 잡아
 * 아이콘(ink-800)이 그 위에서 그대로 읽히게 했다 — 흰 글리프로 뒤집을
 * 필요가 없어 사이드바 전체가 같은 잉크 색을 유지한다.
 *
 * 네 색은 민트→시안→스카이→페리윙클로 한 방향으로 흐른다. 무작위로 고르면
 * 네 개가 서로 안 맞고, 한 색의 명도만 바꾸면 구분이 안 된다.
 * 괄호 안은 아이콘(ink-800 #134074) 대비 — 진한 스톱 기준. */
/* 사이드바 바로가기가 .aside-action 문법으로 바뀌면서 같은 네 색을 원형 배지
   에서도 쓴다. 값이 두 벌이 되면 반드시 한쪽만 고쳐지므로 선택자를 나란히 둔다. */
.icon-tile--g1, .aside-action__badge--g1 { background-image: linear-gradient(135deg, #80EDE3 0%, #20B6AB 100%); }  /* 민트-틸   */
.icon-tile--g2, .aside-action__badge--g2 { background-image: linear-gradient(135deg, #FDC3C3 0%, #F36F6F 100%); }  /* 코랄      */
.icon-tile--g3, .aside-action__badge--g3 { background-image: linear-gradient(135deg, #AFD4FE 0%, #3B82F6 100%); }  /* 스카이블루 */
.icon-tile--g4, .aside-action__badge--g4 { background-image: linear-gradient(135deg, #D8C4FB 0%, #9061F0 100%); }  /* 라벤더    */

/* 채색 타일은 유리가 아니다 — 반투명 흰 배경/스페큘러를 끄지 않으면
   그라데이션 위에 흰 베일이 덮여 색이 탁해진다. 글리프는 흰색으로 통일한다.
   괄호 안 대비는 각 그라데이션의 "밝은 쪽 스톱" 기준(그래픽 최소 3:1). */
.icon-tile--g1, .icon-tile--g2, .icon-tile--g3, .icon-tile--g4 {
  background-color: transparent;
  border-color: rgba(255, 255, 255, .38);
  color: #FFFFFF;
}

/* icon_trend.png 은 파란색이 구워진 이미지라 color 가 안 먹는다. 채색 타일
   위에서는 파란 아이콘이 배경과 부딪히므로 흰색으로 강제한다.
   brightness(0) 로 전부 검게 만든 뒤 invert(1) 로 뒤집으면 알파는 그대로
   둔 채 흰 실루엣만 남는다. */
.icon-tile--g1 img,
.icon-tile--g2 img,
.icon-tile--g3 img,
.icon-tile--g4 img { filter: brightness(0) invert(1); }

/* 섹션 라벨 (오늘 / 어제 / 최근 7일 …) — 목록을 끊어주는 구분자일 뿐이다.
   --brand-blue 로 두면 정작 주인공인 세션 제목보다 라벨이 먼저 눈에 들어오고,
   활성 행이 쓰는 파랑과도 경쟁한다. → 채도 없는 --body-600 으로 물러나게 한다.

   아이콘과 헤어라인은 걷어냈다. 11px 라벨 하나에 글리프·자간·그라데이션 선까지
   붙으면 "구분자"가 아니라 또 하나의 요소가 된다. 그룹 경계는 라벨 위쪽 여백
   (margin-top)이 이미 충분히 만들어 준다 — 형태가 아니라 공간이 맡는 쪽이
   유리 패널 위에서 훨씬 조용하다.

   좌측 패딩은 .session-row 와 같은 12px — 라벨과 제목의 세로선이 맞아야
   목록이 하나의 열로 읽힌다. 한쪽을 바꾸면 다른 쪽도 같이 바꿀 것. */
.aside-label {
  display: flex;
  align-items: center;
  padding: .25rem .5rem .375rem .75rem;
  font-size: .6875rem;
  /* 색을 더 내리고 싶지만 11px 라벨은 소형 텍스트라 대비가 더 중요하다.
     --body-600 은 글래스 위 AA 하한(§1.2)이라 여기서 한 단 더 내리면
     slate-500 = 4.08:1 로 미달이 된다. 그래서 색 대신 굵기를 내린다. */
  font-weight: 500;
  letter-spacing: .04em;
  color: var(--body-600);
  white-space: nowrap;
}

/* 세션 항목 ────────────────────────────────────────────────────────────────
 * 이전 디자인은 행 하나가 "떠 있는 알약"이었다 — 16px 라운드 + 1px 테두리 +
 * hover 시 드롭섀도. 높이 34px 짜리에 그 장식이 다 들어가니 행이 버튼처럼
 * 커 보였고, 그 결과 행 사이 2px 간격이 실제보다 훨씬 넓어 보였다.
 *
 * → 목록은 "버튼 더미"가 아니라 "글줄"이다. 테두리·그림자를 걷어내고 행끼리
 *   맞붙인다(간격 0). 표면은 hover/active 에서만 나타나므로, 평소에는 제목
 *   텍스트만 보이는 조용한 열이 된다.
 *
 *   다만 라운드는 반대로 끝까지 밀었다(10px → 999px). 행이 버튼처럼 보였던
 *   원인은 곡률이 아니라 테두리·그림자였고, 그것들이 사라진 지금은 완전한
 *   알약 쪽이 오히려 더 가볍다 — 유리 패널의 둥근 모서리와도 형태가 맞는다.
 * ------------------------------------------------------------------------ */
.session-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: .125rem;
  /* 999px — 행 높이(약 32px)의 절반을 넘는 값이라 완전한 알약이 된다.
     10px 라운드는 "모서리를 조금 깎은 사각형"이라 유리 패널 위에서 각져 보였다.
     알약은 그 자체로 형태가 완결돼 테두리·바 같은 장식이 필요 없다. */
  border-radius: 999px;
  /* 좌우 패딩이 라운드 반경(16px)에 가까워야 글자가 곡면에 끼지 않는다.
     좌측 12px 은 .aside-label 과 맞춘 값 — 한쪽을 바꾸면 같이 바꿀 것. */
  padding: .375rem .5rem .375rem .75rem;
  transition:
    background-color .18s var(--ease-glass),
    box-shadow .25s var(--ease-glass);
}

/* hover — 반투명 흰 면 + 위쪽 1px 정반사, 그게 전부다.
   한 번은 .chip / .circle-btn 의 유리 공식을 그대로 줄여 써 봤다(흰 테두리
   한 바퀴 + backdrop-filter blur/saturate). 활성 행과 같은 이유로 과했다 —
   backdrop-filter 는 뒤에 균일한 유리판 한 장뿐이라 굴절될 무늬가 없고
   채도만 올려 이 행의 배경만 떠 보이게 했고, 흰 테두리 한 바퀴는 스치기만
   해도 행이 카드처럼 도드라져 목록의 흐름을 끊었다.

   hover 는 "여기 있다"는 신호일 뿐 상태가 아니다. 활성 행보다 반드시 약해야
   한다 — 지금은 색 없는 흰 면이라 시안이 도는 활성 행과 성격부터 갈린다.
   유리 느낌은 면의 투명도와 위쪽 하이라이트만으로 충분히 난다. */
.session-row:hover {
  background-color: rgba(255, 255, 255, .58);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .8);
}

/* 활성 세션 ────────────────────────────────────────────────────────────────
 * 이전에는 무채색 면 + 왼쪽 그라데이션 바였다. 바는 padding-box mask + xor +
 * clip-path 까지 동원해야 겨우 "두꺼운 border-left" 로 보였고, 그 노력에 비해
 * 5px 폭이라 눈에 잘 띄지도 않았다.
 *
 * → Search 알약(.aside-action--glass)과 같은 유리 표면 하나로 끝낸다. 사이드바
 *   에서 "선택됨"을 나타내는 표면이 두 종류일 이유가 없다. 배지는 없다 —
 *   세션 행에는 원형 아이콘 자리가 없고, 라벨과 더보기 버튼뿐이다.
 *
 * ※ 색면(cyan→sky)이 아니라 흰 유리인 이유. 목록에서 색을 갖는 건 활성 행
 *   하나뿐인데, 그 하나가 채도까지 가지면 사이드바에서 가장 센 요소가 된다.
 *   판(.glass-group--slide)보다 행이 세지는 순간 위계가 뒤집힌다. 선택은
 *   "더 진한 색"이 아니라 "표면이 하나 더 있는 것"으로 나타낸다.
 *
 * ※ 한 번은 여기에 네온을 세게 넣어 봤다(시안 링 .55 + 바깥 글로우 두 겹 +
 *   backdrop-filter saturate 200%/brightness). 결과는 튀기만 했다. 이유는
 *   두 가지다.
 *   1) 이 화면은 밝은 배경 위의 라이트 글래스다. 네온은 어두운 면에서
 *      "빛나는" 것이지, 흰 판 위에서는 그냥 진한 색 테두리로 보인다.
 *   2) 32px 행은 목록에서 가장 작은 단위다. 여기에 사이드바 전체에서 제일
 *      강한 그림자가 붙으면 위계가 뒤집힌다 — 세션 하나가 패널보다 세진다.
 *   → 빛은 "번지는 양"이 아니라 "가장자리의 선명함"으로 낸다. 알파를 절반
 *     아래로 내리고 바깥 글로우는 아주 얕게 한 겹만 남겼다.
 *
 * ※ backdrop-filter 는 뺐다. 행 뒤에 있는 건 거의 균일한 .glass-group 한 장
 *   뿐이라 블러해도 굴절될 무늬가 없다. saturate/brightness 만 남아 이 행의
 *   배경만 주변보다 붕 떠 보였다 — "어색함"의 큰 몫이 여기였다.
 *
 * ※ 링을 box-shadow(0 0 0 1px)로 만든 이유 — 진짜 border 를 주면 활성 행만
 *   1px 커져 제목이 밀린다. 다른 행에도 투명 보더를 깔아 맞추는 방법도 있지만,
 *   그러면 목록 전체의 패딩 계산이 보더 유무에 묶인다. 그림자 링은 레이아웃
 *   밖에서 그려지므로 활성/비활성이 완전히 같은 상자를 쓴다.
 * ------------------------------------------------------------------------ */
.session-row.is-active,
.session-row.is-active:hover {
  z-index: 2;   /* hover(1) 보다 위 — 옆 행에 마우스를 얹어도 가장자리가 안 잘린다 */
}
/* 표면은 .aside-action--glass 에서 가져왔다. 다만 두 값은 이 자리에 맞게 바꿨다.
 *
 * ① 흰 면을 .28 → .62 로 올렸다. 원본의 .28 은 Search 알약이 페이지 배경 위에
 *    맨몸으로 떠 있어서 나온 값이다. 이 행은 이미 흰 유리판(.glass-group--slide)
 *    위에 있어서, .28 을 그대로 쓰면 판에 묻혀 선택이 안 보인다. 같은 판 위의
 *    .aside-action--tile:hover 가 .58 인 것과 같은 이유다 — 그 위 반 단.
 *
 * ② 바깥 드롭섀도(0 16px 34px -18px)는 뺐다. #aside_scroll 이 overflow-y:auto
 *    라 스크롤 상자 밖으로 나가는 그림자가 잘린다. 부드러운 falloff 대신 딱
 *    끊긴 계단이 되므로, 안 쓰느니만 못하다(css/chat.css 의 같은 취지 주석 참고).
 *    형태는 원본의 스페큘러 그라데이션과 안쪽 림 두 겹이 대신 잡는다.
 *
 * ③ backdrop-filter 도 없다 — 행 뒤는 균일한 유리판 한 장이라 블러해도 굴절될
 *    무늬가 없고, saturate/brightness 만 남아 이 행의 배경만 붕 뜬다. */
.session-row.is-active {
  background-color: rgba(255, 255, 255, .62);
  background-image: linear-gradient(125deg,
      rgba(255, 255, 255, .42) 0%,
      rgba(255, 255, 255, 0)   38%,
      rgba(255, 255, 255, .2) 100%);
  color: var(--ink-900);
  /* 좌상단 밝은 림 + 우하단 옅은 반사 — 원본 알약의 두께감이 여기서 나온다.
     hover(inset 0 1px 0 한 겹)와 구분되는 지점도 이 두 겹이다. */
  box-shadow:
    inset 1px 1px 0 rgba(255, 255, 255, .95),
    inset -1px -1px 0 rgba(255, 255, 255, .5);
}
/* 이미 선택된 행에도 hover 반응은 남긴다 — 같은 면을 반 단만 세게.
   차이를 크게 두면 마우스가 스칠 때마다 목록이 깜빡이는 것처럼 보인다. */
.session-row.is-active:hover {
  background-color: rgba(255, 255, 255, .74);
  box-shadow:
    inset 1px 1px 0 rgba(255, 255, 255, 1),
    inset -1px -1px 0 rgba(255, 255, 255, .6);
}

/* 활성 행의 "더보기" 버튼은 hover 없이도 항상 보인다 */
.session-row.is-active .session_more {
  opacity: 1;
}
/* Tailwind 유틸리티(text-slate-700 = 0,1,0)보다 높은 특정도로 활성 행의 글자만
   덮어쓴다. 자식이 자기 color 를 들고 있어서, 행에 준 color 는 여기서 다시
   지정하지 않으면 제목까지 내려오지 않는다.
   --ink-900 은 이 흰 유리 면 위에서 12:1 이 넘는다 — 13px 세미볼드가 요구하는
   4.5:1 에 여유가 크다. 굵기 600 이 선택을 알리는 두 번째 신호다. */
.session-row.is-active .session_title {
  color: var(--ink-900);
  font-weight: 600;
}
/* 더보기 아이콘은 제목보다 한 단 물러난다 — 같은 먹으로 두면 점 세 개가
   제목만큼 진해져 시선을 뺏는다. ink-800 도 이 면 위에서 7:1 이 넘는다. */
.session-row.is-active .session_more { color: var(--ink-800); }

/* 하단 계정 행 */
.account-row {
  display: flex;
  align-items: center;
  gap: .625rem;
  border-radius: 1rem;
  padding: .375rem .5rem;
  cursor: pointer;
  text-align: left;   /* button 은 UA 기본이 center 라 이름이 가운데로 몰린다 */
  transition: background-color .2s, box-shadow .3s var(--ease-glass);
}
.account-row:hover {
  background-color: rgba(255, 255, 255, .85);
}

/* 계정 아바타 ──────────────────────────────────────────────────────────────
 * 32px 원까지 유리 구체(.orb)로 만들 필요는 없다 — 정반사·굴절 레이어는 뺀다.
 * 다만 --grad-soft(135deg 선형 띠)를 그대로 쓰면 레퍼런스와 인상이 다르다.
 * 레퍼런스의 아바타는 "대각선 띠"가 아니라 색이 뭉쳐 있는 원형 블롭이라서,
 * 바닥 띠 위에 radial 두 개를 겹쳐 같은 인상을 낸다. blur 레이어가 없으니 납작하고
 * ::before/::after 도 안 써서 hover 시 계정 행 유리판과 겹치지 않는다.
 *
 * 흰 글리프가 파스텔 위에서 묻히지 않도록 .orb--sky/blue/cyan 과 같은
 * 중채도 트리오를 쓴다(--pastel-* 원본보다 한 단계 진하다). */
.avatar-plain {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  border-radius: 9999px;
  font-size: .8125rem;

  /* 면 — 시안 → 스카이 → 블루. 바닥에 140deg 띠를 깔고 그 위에 radial 두 개를
     얹어 색이 뭉치게 한다(대각선 띠 하나만 쓰면 레퍼런스의 "블롭"이 안 나온다).
     시안은 좌상단 구석으로 밀어두었다 — 글리프가 놓이는 한가운데까지 올라오면
     흰 아이콘이 밝은 하늘색 위에서 묻힌다. 가운데는 #3E8EF0 언저리로 남는다. */
  background-color: transparent;
  background-image:
    radial-gradient(72% 72% at 20% 16%,
        rgba(88, 225, 255, .95) 0%, rgba(88, 225, 255, 0) 62%),
    radial-gradient(88% 88% at 84% 106%,
        rgba(20, 100, 240, .92) 0%, rgba(20, 100, 240, 0) 68%),
    linear-gradient(140deg, #58E1FF 0%, #3E8EF0 46%, #1464F0 100%);
  color: #FFFFFF;

  /* 유리 장치를 끈다. 위 .glass-card 계열에서 물려받은 흰 판(.46)과 안쪽
     확산광(inset 40px)을 남기면 그라데이션 위에 흰 베일이 덮여 색이 탁해진다.
     — .icon-tile--g1~g4 가 채색 타일에서 같은 이유로 하는 처리와 같다.
     남기는 건 가장자리뿐: 흰 테두리 1px + 위쪽 림. */
  border-color: rgba(255, 255, 255, .55);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .45);
  /* 면이 불투명해져 뒤가 안 비치므로 blur 는 하는 일 없이 합성 레이어만 만든다.
     ※ 두 줄을 함께 유지할 것 — 접두사 없는 쪽만 지우면 그 속성을 쓰는
       엔진에서 .glass-card 기본값 blur(26px) saturate(215%) 가 되살아난다. */
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
}

/* ---------------------------------------------------------------------------
 * 5b. FORM CONTROLS
 * ---------------------------------------------------------------------------
 * ※ 선택자에 element 를 함께 쓰는 이유:
 *   @tailwindcss/forms 플러그인이 [type='checkbox'] 같은 속성 선택자로
 *   기본 스타일을 넣는데, CDN 은 이 CSS 파일보다 "나중에" 주입된다.
 *   .check (0,1,0) 만으로는 밀리므로 input[type].check (0,2,1) 로 올린다.
 * ------------------------------------------------------------------------ */

/* 텍스트 인풋 / 검색창 공통 */
input.field,
textarea.field,
select.field {
  width: 100%;
  min-height: 46px;
  padding: .625rem 1rem;
  border-radius: 9999px;
  border: 1px solid rgba(255, 255, 255, .9);
  background-color: rgba(255, 255, 255, .7);
  box-shadow:
    var(--shadow-glass-sm),
    inset 1px 1px 0 rgba(255, 255, 255, .9);
  -webkit-backdrop-filter: blur(18px) saturate(185%);
  backdrop-filter: blur(18px) saturate(185%);
  font-size: .9375rem;
  color: var(--ink-950);
  /* 글로우가 켜질 때 튀지 않도록 border-color 도 같이 전이시킨다 */
  transition: background-color .2s, border-color .2s, box-shadow .3s var(--ease-glass);
}
input.field::placeholder,
textarea.field::placeholder { color: var(--body-600); }

input.field:hover,
select.field:hover { background-color: rgba(255, 255, 255, .85); }

input.field:focus,
textarea.field:focus,
select.field:focus {
  background-color: rgba(255, 255, 255, .95);
  border-color: rgba(255, 255, 255, 1);
}

/* --- 입력창 포커스 글로우 ------------------------------------------------
 * 전역 규칙(:where(...):focus-visible)의 2px outline 대신, 테두리 바깥으로
 * 빛이 번지는 box-shadow 를 쓴다. 전역 규칙은 :where() 라 특정도가 0 이므로
 * 아래 선택자(0,1,1)가 !important 없이 그냥 이긴다.
 *
 * 경계선을 만들지 않는 게 핵심이다 — blur 0 인 그림자(0 0 0 3px …)는 퍼지는
 * 빛이 아니라 딱 떨어지는 테두리로 보인다. 그래서 모든 겹에 blur 를 주고,
 * blur 를 키우는 만큼 alpha 를 낮춰 바깥으로 갈수록 자연스럽게 사라지게 한다.
 * spread 는 blur 의 1/4 수준으로만 둔다(크게 주면 다시 윤곽이 생긴다).
 *
 * ※ outline: 2px solid transparent 는 지우지 말 것.
 *   Windows 고대비(forced-colors) 모드는 box-shadow 를 전부 무시하므로,
 *   투명 outline 을 남겨둬야 그 모드에서 시스템 색으로 칠해져 포커스가 보인다.
 *   여기서 outline: none 을 쓰면 고대비 사용자는 포커스를 완전히 잃는다.
 *   (평소에는 투명이라 파란 테두리로 보이지 않는다)
 *
 * ※ .field 기본 box-shadow(글래스 그림자 + 안쪽 흰 림)를 여기서 다시 적어야
 *   한다. box-shadow 는 누적이 아니라 교체라, 빼먹으면 포커스 순간 카드가
 *   납작해진다.
 * ---------------------------------------------------------------------- */
input.field:focus-visible,
textarea.field:focus-visible,
select.field:focus-visible {
  outline: 2px solid transparent;   /* forced-colors 대비 — 평소엔 안 보인다 */
  outline-offset: 2px;
  border-color: #FFFFFF;
  background-color: rgba(255, 255, 255, .97);
  box-shadow:
    inset 1px 1px 0 rgba(255, 255, 255, .9),     /* 유리 안쪽 림 (기본값 유지) */
    0 0 6px  0px var(--focus-near),              /* 가장자리에 붙는 옅은 빛 */
    0 0 14px 2px var(--focus-mid),               /* 중간 번짐 */
    0 0 24px 5px var(--focus-far),               /* 가장 바깥 — 거의 사라짐 */
    0 6px 18px -10px rgba(70, 110, 215, .30);    /* 아래로 떨어지는 빛 */
}

/* 사각형 인풋 (textarea, 여러 줄) */
textarea.field { border-radius: 1.125rem; }

/* --- 검색창 ------------------------------------------------------------- */
.search {
  position: relative;
  display: block;
}
.search input.field {
  padding-left: 3rem;        /* 아이콘 자리 */
  padding-right: 2.875rem;   /* 지우기 버튼 자리 */
}

/* ※ z-index 필수:
   .field 의 backdrop-filter 가 스택 컨텍스트를 만들어 input 이 위치 지정
   요소처럼 승격된다. 아이콘이 DOM 상 input 보다 앞이라 z-index 가 없으면
   input 배경에 그대로 덮여 사라진다. */
.search__icon {
  position: absolute;
  z-index: 1;
  left: 1.125rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--brand-blue);
  pointer-events: none;
  font-size: 1rem;
}
.search__clear {
  position: absolute;
  z-index: 1;
  right: .375rem;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 9999px;
  color: var(--body-600);
  font-size: .8125rem;
  transition: background-color .2s, color .2s;
}
.search__clear:hover {
  background-color: rgba(255, 255, 255, .9);
  color: var(--ink-900);
}

/* --- 컴팩트 검색창 (모달 안 목록용) --------------------------------------
 * 마켓 / 내 도구 검색창은 바로 아래 필터 알약 줄과 한 덩어리로 읽혀야 하는데,
 * 기본 46px 알약은 그 옆에서 혼자 크다. 필터 트랙 높이에 맞춘다.
 *
 *   .tool-filters = 1px 테두리 + 4px 패딩 + 27px 알약 + 4px + 1px ≈ 37px
 *   → 검색창 38px. 1px 차이는 눈에 잡히지 않는다.
 *
 * 입력창만 줄이면 돋보기와 지우기 버튼이 그대로 남아 안쪽이 답답해지므로
 * 래퍼(.search--compact)에 걸어 아이콘·버튼·좌우 여백을 함께 줄인다.
 * 화면 폭과 무관하게 늘 같은 크기다(필터 줄이 어느 폭에서나 같으므로).
 *
 * ※ 특정도가 .search input.field 와 같은 (0,2,1) 이라 순서로 이긴다.
 *   이 블록을 .search 정의보다 위로 옮기면 padding 이 되돌아간다.
 * ---------------------------------------------------------------------- */
.search--compact input.field {
  min-height: 38px;
  padding-top: .375rem;
  padding-bottom: .375rem;
  padding-left: 2.25rem;     /* 아이콘 자리 (기본 3rem) */
  padding-right: 2.25rem;    /* 지우기 버튼 자리 (기본 2.875rem) */
  font-size: .8125rem;
}
.search--compact .search__icon {
  left: .8125rem;
  font-size: .8125rem;
}
.search--compact .search-field__clear {
  right: .3125rem;
  width: 1.625rem;
  height: 1.625rem;
  font-size: .6875rem;
}

/* --- 셀렉트 ------------------------------------------------------------- */
select.field {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 2.5rem;
  cursor: pointer;
  /* 쉐브론 — 브랜드 블루 SVG */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%232563EB' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  background-size: 1rem;
}
/* 드롭다운 목록은 OS 렌더링이라 배경만 맞춰준다 */
select.field option {
  background-color: #FFFFFF;
  color: var(--ink-950);
}

/* --- 체크박스 ----------------------------------------------------------- */
input[type="checkbox"].check,
input[type="radio"].check {
  appearance: none;
  -webkit-appearance: none;
  flex-shrink: 0;
  width: 1.375rem;
  height: 1.375rem;
  margin: 0;
  border-radius: .5rem;
  border: 1.5px solid rgba(120, 150, 220, .45);
  background-color: rgba(255, 255, 255, .75);
  box-shadow: inset 1px 1px 0 rgba(255, 255, 255, .9);
  -webkit-backdrop-filter: blur(12px) saturate(180%);
  backdrop-filter: blur(12px) saturate(180%);
  cursor: pointer;
  transition: background-color .2s, border-color .2s, transform .15s;
}
input[type="radio"].check { border-radius: 9999px; }

input[type="checkbox"].check:hover,
input[type="radio"].check:hover { border-color: var(--brand-blue); }

input[type="checkbox"].check:checked {
  border-color: transparent;
  /* 체크 표시가 위, 그라데이션이 아래 */
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m3.5 8.5 3 3 6-6.5'/%3E%3C/svg%3E"),
    var(--grad-bubble);
  background-repeat: no-repeat;
  background-position: center;
  background-size: .875rem, cover;
  box-shadow: 0 6px 14px -6px rgba(70, 110, 215, .7);
}

input[type="radio"].check:checked {
  border-color: transparent;
  background-image:
    radial-gradient(circle at 50% 50%, #FFFFFF 0 28%, transparent 30%),
    var(--grad-bubble);
  box-shadow: 0 6px 14px -6px rgba(70, 110, 215, .7);
}

input[type="checkbox"].check:active,
input[type="radio"].check:active { transform: scale(.92); }

input[type="checkbox"].check:disabled,
input[type="radio"].check:disabled {
  opacity: .45;
  cursor: not-allowed;
}

/* 체크박스 + 라벨 한 줄 */
.check-row {
  display: flex;
  align-items: center;
  gap: .625rem;
  min-height: 44px;
  font-size: .9375rem;
  color: var(--body-700);
  cursor: pointer;
}
.check-row:hover { color: var(--ink-900); }

/* --- 토글 스위치 ---------------------------------------------------------
 * ON 색을 :checked 에서 background-image 로 갈아끼우면 그라데이션은 보간되지
 * 않아 색이 툭 튄다. 그래서 트랙은 OFF 색으로 두고, 그라데이션은 ::before 로
 * 한 겹 덮어 opacity 만 0↔1 로 넘긴다. 노브(::after)는 뒤에 선언돼 위에 깔린다.
 * ------------------------------------------------------------------------ */
input[type="checkbox"].switch {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  flex-shrink: 0;
  width: 2.5rem;             /* 40 × 22 — iOS 스위치보다 살짝 작고 단정하게 */
  height: 1.375rem;
  margin: 0;
  border-radius: 9999px;
  border: 0;
  /* OFF: 옅은 블루그레이 — 빈 유리로 보이지 않도록 톤을 준다 */
  background-color: rgba(148, 170, 215, .38);
  box-shadow: inset 0 1px 2px rgba(70, 95, 170, .18);
  cursor: pointer;
  transition: box-shadow .25s var(--ease-glass);
}
/* ON 색 레이어 */
input[type="checkbox"].switch::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-image: var(--grad-bubble);
  opacity: 0;
  transition: opacity .22s var(--ease-glass);
}
input[type="checkbox"].switch::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 1.125rem;           /* 18px 노브 — 상하 2px 여백 */
  height: 1.125rem;
  border-radius: 9999px;
  background-color: #FFFFFF;
  box-shadow:
    0 1px 3px rgba(70, 95, 170, .35),
    0 0 0 .5px rgba(70, 95, 170, .06);
  /* 이동은 살짝 되튀는 곡선(--ease-glass), 눌린 폭은 짧고 곧게 되돌아온다 */
  transition: transform .28s var(--ease-glass), width .16s ease-out;
}
input[type="checkbox"].switch:checked {
  box-shadow: 0 2px 8px -2px rgba(70, 110, 215, .55);
}
input[type="checkbox"].switch:checked::before { opacity: 1; }
/* left 대신 transform — 리플로우 없이 부드럽게 */
input[type="checkbox"].switch:checked::after {
  transform: translateX(1.125rem);
}

/* 누르는 동안 노브가 진행 방향으로 늘어난다(스쿼시).
   실제 스위치의 "밀린다"는 감각을 만드는 건 이 한 프레임이다.
   ON 상태에서는 늘어난 만큼(4px) 왼쪽으로 당겨 오른쪽 끝을 고정한다. */
input[type="checkbox"].switch:active::after { width: 1.375rem; }
input[type="checkbox"].switch:checked:active::after {
  width: 1.375rem;
  transform: translateX(.875rem);
}
/* 트랙도 아주 살짝 눌린다 — 노브만 움직이면 버튼이 아니라 슬라이더로 읽힌다 */
input[type="checkbox"].switch:active { transform: scale(.96); }

input[type="checkbox"].switch:disabled {
  opacity: .45;
  cursor: not-allowed;
}
input[type="checkbox"].switch:disabled:active { transform: none; }
input[type="checkbox"].switch:disabled:active::after { width: 1.125rem; }

/* 조밀한 목록용 작은 변형 — 34 × 19, 노브 15px.
   행 높이(약 60px)에서 40px 스위치는 이름보다 먼저 눈에 들어온다.
   작아진 만큼 터치 표적은 감싸는 <label>(.mn-row__switch)이 책임진다 —
   그쪽 패딩까지 포함하면 약 44 × 60px 이라 오히려 넓어진다. */
input[type="checkbox"].switch--sm {
  width: 2.125rem;
  height: 1.1875rem;
}
input[type="checkbox"].switch--sm::after {
  width: .9375rem;
  height: .9375rem;
}
input[type="checkbox"].switch--sm:checked::after { transform: translateX(.9375rem); }
input[type="checkbox"].switch--sm:active::after { width: 1.1875rem; }
input[type="checkbox"].switch--sm:checked:active::after {
  width: 1.1875rem;
  transform: translateX(.6875rem);
}

/* 말풍선 — 유저(그라데이션) / AI(흰색) */
/* 유저 말풍선 — 살짝 볼록한 정도까지만.
     1) 상단 돔 하이라이트 : 위에서 빛을 받는 면. 표면이 부푼 "정도"만 알려준다
     2) 하단 반사광        : 아주 옅게 — 두께감의 힌트
     3) inset 림           : 위 밝은 선 / 아래 어두운 선 (1px 모서리)
     4) 2단 드롭섀도       : 접지 + 짧은 확산
   그림자를 넓게 번지게 하면(24px+ 블룸) 말풍선만 화면에서 떠올라 대화 흐름과
   따로 논다. 확산을 18px 안쪽으로 묶어 표면에 붙어 있게 유지한다. */
.bubble-user {
  position: relative;
  background-image:
    /* 1) 상단 돔 하이라이트 */
    radial-gradient(140% 90% at 50% -30%,
        rgba(255, 255, 255, .32) 0%,
        rgba(255, 255, 255, .10) 42%,
        rgba(255, 255, 255, 0)   66%),
    /* 2) 하단 반사광 */
    radial-gradient(120% 80% at 50% 130%,
        rgba(255, 255, 255, .15) 0%,
        rgba(255, 255, 255, 0)   58%),
    var(--grad-bubble);
  color: var(--on-brand);
  border-radius: 1.125rem 1.125rem .25rem 1.125rem;
  padding: .625rem .875rem;
  box-shadow:
    /* 접지 — 좁고 옅게. 이게 없으면 인쇄된 것처럼 납작해진다 */
    0 1px 2px rgba(40, 70, 160, .16),
    /* 짧은 확산 */
    0 8px 18px -10px rgba(70, 110, 215, .38),
    /* 유리 두께: 위 밝은 림 · 아래 어두운 림 */
    inset 0 1px 0 rgba(255, 255, 255, .55),
    inset 0 -1px 0 rgba(20, 40, 120, .14);
}

/* AI 답변 — 유리판. 얇고 밝은 림 + 넓고 옅은 그림자로 떠 보이게.
 * 이 판은 한두 줄짜리 말풍선이 아니라 표·목록·인용이 들어가는 리포트를
 * 담는다. 그래서 말풍선 기준(.625rem)이 아니라 카드 기준으로 여백을 잡는다.
 *
 * 불투명도 66% 는 이 페이지의 유리 중에서는 높은 편이다. 컴포저(18%)나
 * 옛 대화 시트(24%)처럼 내리지 않는 이유는 담는 내용이 다르기 때문이다 —
 * 표의 헤어라인과 12~13px 셀 글자는 뒤 무늬가 조금만 비쳐도 뭉개진다.
 * 여백 큰 면은 얇게, 글이 빽빽한 면은 두껍게. 더 투명하게 가야 한다면
 * 배경색보다 blur 를 먼저 올릴 것.
 * ------------------------------------------------------------------------ */
.bubble-ai {
  position: relative;
  background-color: rgba(255, 255, 255, .66);
  background-image: linear-gradient(160deg,
      rgba(255, 255, 255, .5) 0%,
      rgba(255, 255, 255, 0)  42%);
  color: var(--body-700);
  border: 1px solid rgba(255, 255, 255, .9);
  /* 왼쪽 아래 한 곳만 각져서 "왼쪽에서 나온 답변"이라는 방향이 남는다 */
  border-radius: 1.25rem 1.25rem 1.25rem .375rem;
  padding: 1rem 1.25rem;
  box-shadow:
    0 1px 2px rgba(70, 95, 170, .06),
    0 12px 28px -14px rgba(70, 95, 170, .35),
    inset 1px 1px 0 rgba(255, 255, 255, 1),
    inset -1px -1px 0 rgba(255, 255, 255, .5);
  /* saturate 는 뒤 색을 증폭하는 값이다. 뒤로 시안~파랑 구체가 지나가는
     배경 이미지가 있어서 200% 를 걸면 유리가 파랗게 착색된 것처럼 보인다.
     106% 면 뒤 색을 거의 그대로 통과시켜 유리는 무색으로 남는다. */
  -webkit-backdrop-filter: blur(26px) saturate(106%) brightness(1.04);
  backdrop-filter: blur(26px) saturate(106%) brightness(1.04);
}

@media (min-width: 768px) {
  .bubble-ai { padding: 1.25rem 1.5rem; }
}

/* backdrop-filter 미지원 브라우저 — 뒤를 흐릴 수 없으니 면만으로 대비를
   확보한다. 66% 그대로 두면 배경 이미지의 진한 파랑이 표 위로 그대로 올라온다. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .bubble-ai { background-color: rgba(255, 255, 255, .90); }
}

/* ---------------------------------------------------------------------------
 * 6. GLASS ORB — 색 구름을 가둔 유리 구체
 *    ::before = 안에 갇힌 색 구름, ::after = 유리 껍질(정반사·굴절·림).
 *    색은 --c1~--c3, 흐림 정도는 --orb-blur 변수로만 바꾼다.
 *
 *    ※ 두 가지를 지키면 "파스텔 원"이 아니라 "유리"로 읽힌다.
 *      1) 색을 덮는 흰 레이어를 최소화하고 blur 를 낮춰 색 경계를 남긴다.
 *      2) 하이라이트를 하나가 아니라 넷으로 쪼갠다 — 작고 단단한 정반사점,
 *         넓은 상단 광택, 바닥에서 되비치는 초승달, 가장자리 굴절 띠.
 *
 *    ※ 그라데이션 위치·크기는 % 라 지름에 따라 같이 늘어나지만 blur 와 림
 *      두께는 px 고정이다. 그래서 24~36px 짜리 작은 Orb 에는 .orb--sm 을,
 *      96px 이상 히어로 Orb 에는 .orb--lg 를 함께 준다.
 * ------------------------------------------------------------------------ */
.orb {
  --c1: var(--pastel-sky);    /* 하늘 */
  --c2: var(--pastel-blue);   /* 파랑 */
  --c3: var(--pastel-cyan);   /* 시안 */
  --orb-blur: 6px;
  position: relative;
  border-radius: 9999px;
  overflow: hidden;
  isolation: isolate;
  /* 유리 자체의 옅은 뿌옇음. 이 값을 올릴수록 색이 죽는다. */
  background-color: rgba(255, 255, 255, .16);
  box-shadow: var(--shadow-orb);
}

/* 내부 색 구름 — 채도를 올리고 blur 를 낮춰 세 색이 각각 보이게 한다 */
.orb::before {
  content: '';
  position: absolute;
  inset: -24%;
  background:
    radial-gradient(34% 34% at 30% 28%, var(--c1) 0%, transparent 66%),
    radial-gradient(36% 36% at 68% 36%, var(--c2) 0%, transparent 66%),
    radial-gradient(38% 38% at 46% 74%, var(--c3) 0%, transparent 66%);
  filter: blur(var(--orb-blur)) saturate(1.3);
}

/* 유리 껍질 — 정반사점 · 상단 광택 · 하단 반사광 · 가장자리 굴절
   inset box-shadow 는 자식보다 아래에 그려지므로, 안쪽 음영은 .orb 가 아니라
   반드시 이 레이어(::after)에 둬야 색 구름 위로 올라온다. */
.orb::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background:
    /* 1) 작고 단단한 정반사점 — 유리로 읽히게 하는 핵심 */
    radial-gradient(15% 11% at 31% 19%, rgba(255, 255, 255, .98) 0%, rgba(255, 255, 255, 0) 100%),
    /* 2) 넓은 상단 광택 */
    radial-gradient(44% 33% at 34% 24%, rgba(255, 255, 255, .60) 0%, rgba(255, 255, 255, 0) 72%),
    /* 3) 바닥에서 되비치는 초승달 반사광 */
    radial-gradient(62% 38% at 52% 101%, rgba(255, 255, 255, .70) 0%, rgba(255, 255, 255, 0) 62%),
    /* 4) 가장자리 굴절 띠 — 구체의 두께감 */
    radial-gradient(closest-side,
      rgba(58, 96, 196, 0) 66%,
      rgba(58, 96, 196, .22) 93%,
      rgba(58, 96, 196, .05) 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .78),   /* 흰 림 */
    inset 0 1px 1px rgba(255, 255, 255, .95),   /* 윗면 광택 엣지 */
    inset 0 -9px 14px -11px rgba(58, 96, 196, .55);  /* 아랫면 굴절 그늘 */
}

/* 지름별 흐림 보정 */
.orb--sm { --orb-blur: 2.5px; }   /* 24~36px 아바타·로고 */
.orb--lg { --orb-blur: 9px; }     /* 96px 이상 히어로 */

/* 색상 변형 — 같은 트리오 안에서 지배색만 바꾼다 */
.orb--sky  { --c1: #4BA4F8; --c2: #A9D2FD; --c3: #58e1ff; }
.orb--blue { --c1: #2F7BF5; --c2: #9CC3FD; --c3: #1464F0; }
.orb--cyan { --c1: #58e1ff; --c2: #9BEAF7; --c3: #4BA4F8; }

/* 하단 확산광 */
.orb-glow {
  position: absolute;
  left: 50%;
  bottom: -10%;
  width: 72%;
  height: 28%;
  transform: translateX(-50%);
  background: radial-gradient(50% 50% at 50% 50%,
              rgba(120, 160, 240, .52) 0%, rgba(120, 160, 240, 0) 70%);
  filter: blur(11px);
  z-index: -1;
}

/* 장식용 소프트 그라데이션 타일 (이미지 생성 결과 자리 등) */
.tile-soft {
  background-image: var(--grad-soft);
  border-radius: .75rem;
  box-shadow: var(--shadow-glass-sm);
}
.tile-soft--sky  { background-image: linear-gradient(135deg, #4BA4F8 0%, #1464F0 100%); }
.tile-soft--blue { background-image: linear-gradient(135deg, #1464F0 0%, #31C5EA 100%); }
.tile-soft--cyan { background-image: linear-gradient(135deg, #31C5EA 0%, #4BA4F8 100%); }

/* ---------------------------------------------------------------------------
 * 6b. MODAL — 모든 모달의 공통 골격
 * ---------------------------------------------------------------------------
 * 구조는 항상 세 덩어리다.
 *
 *   .modal-hero    오로라 배너 + 장식 Orb + 아이콘 + 제목/설명 + 닫기
 *   .modal-body    흰 시트. 내용이 길면 여기만 스크롤한다
 *   .modal-footer  오른쪽 정렬 액션. 취소=btn-secondary / 확정=btn-primary
 *
 * 히어로만 색을 갖고 본문은 흰 시트로 두는 이유: 모달은 텍스트·폼 밀도가 높아
 * 전면에 색을 깔면 읽기 어려워진다. 색은 상단에 몰아 "이 모달이 무엇인지"를
 * 알리는 데만 쓰고, 아래는 비워 둔다.
 *
 * ※ 이 섹션은 .orb 정의 "뒤"에 와야 한다. .modal-hero__deco 가 .orb 의
 *   position: relative 를 absolute 로 덮어써야 하기 때문.
 * ------------------------------------------------------------------------ */

/* 모달 패널 — glass-card 위에 얹어 쓴다. 뒤 배경이 비치면 글자가 지저분해지므로
   유리감은 남기되 불투명도를 .96 까지 올린다. */
.glass-modal {
  background-color: rgba(255, 255, 255, .96);
  box-shadow:
    0 2px 6px rgba(70, 95, 170, .08),
    0 40px 80px -30px rgba(40, 60, 130, .45),
    inset 1px 1px 0 rgba(255, 255, 255, 1),
    inset -1px -1px 0 rgba(255, 255, 255, .6);
  -webkit-backdrop-filter: blur(30px) saturate(180%);
  backdrop-filter: blur(30px) saturate(180%);
}

/* --- 열림 상태: 패널을 원래 크기로 ---------------------------------------
 * 마크업의 scale-95 는 "닫혀 있을 때 살짝 작다 → 열리면서 커진다" 는 등장
 * 애니메이션의 시작값인데, 이걸 되돌리는 규칙이 어디에도 없었다. 즉 모든
 * 모달이 열린 뒤에도 계속 95% 로 축소된 채였다.
 *
 * 이게 단순히 "조금 작다" 로 끝나지 않는 이유: 패널은 backdrop-filter 때문에
 * 이미 별도 합성 레이어다. 거기에 0.95 배 변환이 걸리면 브라우저는 레이어를
 * 한 번 래스터화한 뒤 리샘플링하므로 글자·1px 선이 픽셀 격자에서 어긋나
 * 전체가 흐릿해진다. 모바일에서 유독 심한 건 GPU 래스터 배율 상한이 낮아
 * 다시 그려주지 않기 때문이다.
 *
 * 열림 신호는 handlePopup 이 래퍼에 붙이는 .opacity-100 하나뿐이라 그걸 쓴다.
 * (0,3,0) 이므로 나중에 주입되는 Tailwind 의 .scale-95 (0,1,0) 를 이긴다. */
.modal.opacity-100 > .scale-95 { transform: scale(1); }

/* --- 모바일: 패널에서 유리 blur 를 뺀다 -----------------------------------
 * 위 변환을 바로잡아도 backdrop-filter 레이어 자체가 모바일에서 축소 래스터화
 * 되는 브라우저가 있다(안드로이드 크로미움 계열). 패널은 이미 불투명도 .96
 * 이라 blur 30px 이 만드는 차이는 사실상 보이지 않는 반면, 글자 선명도는
 * 눈에 띄게 잃는다 — 데스크톱에서만 유리를 쓰고 모바일에서는 흰 면으로 둔다.
 * 유리 티(테두리·스페큘러·굴절광 링)는 .glass-card 가 그대로 유지한다.
 *
 * 배경 오버레이의 blur 도 같이 끈다. 전면 backdrop-filter 는 비용이 크고,
 * 어둡게 덮는 bg-ink-950/45 만으로도 뒤 화면과의 분리는 충분하다. */
@media (hover: none) and (pointer: coarse) {
  .glass-card.glass-modal {
    background-color: #FFFFFF;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .modal.fixed {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/* --- 히어로 헤더 ---------------------------------------------------------- */
.modal-hero {
  position: relative;
  overflow: hidden;                      /* 장식 Orb 를 배너 안에 가둔다 */
  padding: 1.25rem 1.375rem;
  /* 패널의 라운드를 그대로 물려받아 배너가 모서리 밖으로 새지 않게 */
  border-start-start-radius: inherit;
  border-start-end-radius: inherit;
  /* 배너 높이는 90px 남짓이다. 이 폭에 130% 짜리 블롭을 하늘·보라·분홍으로
     세 개 겹치면 각 블롭이 그라데이션이 아니라 '색 판'으로 깔려, 오로라가
     아니라 세 색이 섞인 탁한 띠로 읽힌다(특히 가운데 보라). 그래서
       ① 색 계열을 하늘→파랑 하나로 모으고,
       ② 분홍은 제목에서 먼 우하단 모서리에 한 겹만 스치게 남기고,
       ③ 상단에 흰 스페큘러를 얹어 빛의 방향을 만들고,
       ④ 바닥은 흰색으로 열어 modal-body 와 이어지게 한다.
     블롭의 소실점은 같은 색의 alpha 0 으로 둔다 — 배너처럼 좁은 면에서는
     서로 다른 색끼리 겹치는 구간이 곧바로 얼룩으로 보인다. */
  background-image:
    /* ① 상단 스페큘러 — glass-card 의 대각선 반사와 같은 각도 */
    linear-gradient(168deg, rgba(255, 255, 255, .85) 0%, rgba(255, 255, 255, 0) 46%),
    /* ② 좌상단 하늘 */
    radial-gradient(78% 165% at -2% -25%, rgba(163, 214, 247, .52) 0%, rgba(163, 214, 247, 0) 66%),
    /* ③ 우상단 파랑 */
    radial-gradient(66% 150% at 101% -18%, rgba(170, 192, 250, .44) 0%, rgba(170, 192, 250, 0) 62%),
    /* ④ 베이스 — 패널이 비치도록 반투명 유지.
       (분홍 한 겹은 제거했다. 좁은 배너에서는 그라데이션이 아니라 하단에
        분홍 얼룩으로 읽힌다. 배너는 하늘→파랑 한 계열로만 간다.) */
    linear-gradient(180deg, rgba(238, 246, 255, .85) 0%, rgba(255, 255, 255, .35) 50%, rgba(255, 255, 255, .88) 100%);
}

/* 구분선 — 배너가 흰색으로 끝나므로 1px 직선을 끝까지 그으면 그 줄만
   또렷하게 잘려 보인다. 양끝을 흘려보내 가운데만 남긴다. */
.modal-hero::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg,
      rgba(99, 130, 220, 0)   0%,
      rgba(99, 130, 220, .18) 18%,
      rgba(99, 130, 220, .18) 82%,
      rgba(99, 130, 220, 0)   100%);
}

/* (우측 장식 Orb `.modal-hero__deco` 는 제거했다 — 모달마다 같은 구체가 반복되니
   장식이 아니라 잡음으로 읽혔다. 헤더는 아이콘 타일과 제목만으로 충분하다.) */

.modal-hero__inner {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: .875rem;
}

/* 아이콘 타일 — 오로라 배너 위에서는 흰 타일 + 브랜드 블루가 가장 또렷하다 */
.modal-hero__icon {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: .875rem;
  border: 1px solid rgba(255, 255, 255, .95);
  background-color: rgba(255, 255, 255, .82);
  box-shadow: var(--shadow-glass-sm);
  color: var(--brand-blue);
  font-size: .9375rem;
}
/* 파괴적 동작(삭제·로그아웃)만 색으로 구분한다 */
.modal-hero__icon--danger { color: #BE123C; }

/* 제목은 17px — text-grad 는 20px 미만에서 색이 뭉개지므로 쓰지 않는다.
   컨셉은 배너와 Orb 가 이미 전달하고 있다. */
.modal-hero__title {
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -.01em;
  color: var(--ink-950);
}
.modal-hero__desc {
  margin-top: .1875rem;
  font-size: .8125rem;
  line-height: 1.45;
  color: var(--body-600);
}

/* 닫기 — 배너 위에 뜨는 반투명 유리 버튼 */
.modal-hero__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  margin-left: auto;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 9999px;
  color: var(--body-600);
  transition: background-color .2s, color .2s, transform .15s;
}
.modal-hero__close:hover {
  background-color: rgba(255, 255, 255, .9);
  color: var(--ink-900);
}
.modal-hero__close:active { transform: scale(.94); }

/* --- 모바일 헤더 ---------------------------------------------------------
 * 배치는 데스크톱과 같은 한 줄(아이콘 · 제목/설명 · 닫기)을 유지한다.
 * 좁은 폭에서 줄이 늘어나는 만큼 여백과 헤더 안 CTA 크기만 줄여 상쇄한다.
 * ------------------------------------------------------------------------ */
/* 마켓플레이스 '툴 등록' — 이 화면의 주인공은 도구 목록이고 등록은 가끔 쓰는
   동작이다. 헤더에서 기본 .btn-sm(40px)로 서면 제목보다 먼저 눈에 들어온다.
   .mk_register_btn 으로 스코프를 잡아 다른 .btn-sm 18곳은 건드리지 않는다. */
.mk_register_btn.btn-primary {
  min-height: 2rem;
  padding: .3125rem .8125rem;
  font-size: .75rem;
  gap: .375rem;
}
.mk_register_btn.btn-primary > i { font-size: 10px; }

@media (max-width: 639px) {
  .modal-hero { padding: .875rem 1rem 1rem; }

  /* 제목·설명 — 좁은 폭에서 한 단씩 내린다. 제목 17→15px, 설명 13→12px 로
     둘 사이 간격(4px)은 유지해야 위계가 흐려지지 않는다. 설명을 더 줄이지
     않는 건 11px 이 본문 최소선 아래이기 때문. */
  .modal-hero__title { font-size: .9375rem; }

  .modal-hero__desc {
    margin-top: .125rem;
    font-size: .75rem;
    line-height: 1.4;
  }

  /* 마켓플레이스 '툴 등록' — 모바일에서 한 단 더 줄인다.
     이 화면의 주인공은 도구 목록이고 등록은 가끔 쓰는 동작이다. 검색창 위에서
     기본 크기(40px)로 서면 목록보다 먼저 눈에 들어온다.
     헤더 버전(sm 이상에서만 보임)도 같은 값을 공유해 두 자리의 크기가
     어긋나지 않게 한다 — 다른 .btn-sm 은 건드리지 않는다. */
  .mk_register_btn.btn-primary {
    min-height: 1.875rem;
    padding: .25rem .6875rem;
    font-size: .75rem;
    gap: .375rem;
    /* 필터 알약과 한 줄을 나눠 쓰므로, 폭이 모자라면 flex 가 이 버튼부터
       눌러 '툴 / 등록' 으로 접는다. 라벨이 두 줄이 된 알약은 버튼으로 안 읽힌다.
       → 줄이지도 접지도 못하게 못박고, 부족한 폭은 필터 트랙이 스크롤로 흡수한다. */
    flex-shrink: 0;
    white-space: nowrap;
  }
  .mk_register_btn.btn-primary > i { font-size: 10px; }
}

/* --- 본문 / 푸터 ---------------------------------------------------------- */
.modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 1.25rem 1.375rem;
}

.modal-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .5rem;
  flex-shrink: 0;
  padding: .875rem 1.375rem 1.125rem;
  border-top: 1px solid rgba(99, 130, 220, .12);
}
/* 본문과 붙여 쓰는 푸터(스크롤이 없는 짧은 모달) — 구분선을 뺀다.
 *
 * 구분선을 빼면 .modal-body 의 아래 패딩(1.25rem)과 푸터의 위 패딩(.875rem)이
 * 그대로 이어붙어 34px 짜리 빈 띠가 된다. 선이 있을 때는 두 영역이 나뉘어
 * 보이므로 문제가 없지만, 선이 없으면 그냥 "간격이 뜬 것"으로 읽힌다.
 * → 위 패딩을 본문 쪽에 넘기고 여기서는 0 으로 둔다. 본문 아래 20px,
 *   버튼 아래 18px 로 균형이 맞는다.
 *
 * ※ 본문이 스크롤되는 모달에는 --plain 을 쓰지 말 것. 스크롤 도중에는
 *   내용이 버튼에 그대로 붙어 버린다(그때는 구분선이 필요하다). */
.modal-footer--plain {
  border-top: 0;
  padding-top: 0;
}

/* 모달 안의 버튼은 한 단계 작게. btn-primary/secondary 뒤에 와야 이긴다 */
.btn-sm {
  min-height: 40px;
  padding: .5rem 1.25rem;
  font-size: .8125rem;
}

/* 파괴적 확정 버튼 — 그라데이션 CTA 와 나란히 서므로 평면 단색으로 구분한다 */
.btn-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 40px;
  padding: .5rem 1.25rem;
  border-radius: 9999px;
  background-color: #BE123C;
  color: #FFFFFF;
  font-size: .8125rem;
  font-weight: 600;
  transition: background-color .2s;
}
.btn-danger:hover { background-color: #9F1239; }

/* ---------------------------------------------------------------------------
 * 7. 음성 파형 (장식)
 * ------------------------------------------------------------------------ */
.wave { display: flex; align-items: center; gap: .25rem; height: 1.5rem; }
.wave span {
  display: block;
  width: 3px;
  border-radius: 9999px;
  background-color: currentColor;
  animation: wave 1.1s ease-in-out infinite;
}
@keyframes wave {
  0%, 100% { height: 8px; }
  50%      { height: 22px; }
}

/* ---------------------------------------------------------------------------
 * 8. 폴백
 * ------------------------------------------------------------------------ */

/* backdrop-filter 미지원 → 불투명 배경으로 대체.
   이게 없으면 구형 브라우저에서 카드가 흐린 반투명 판이 되어 글자가 안 읽힌다. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass-card,
  .glass-card--sheer,
  .glass-card--solid,
  .glass-panel,
  .chip,
  .circle-btn,
  .btn-secondary {
    background-color: rgba(255, 255, 255, .95);
  }
}

/* 모션 감소 선호 — 오로라 드리프트 / Orb 부유는 무한 루프라 멀미 유발 가능 */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------------------------------------
 * 떠 있는 메뉴 (#context_menu) — 같은 유리, 불투명도만 다르다
 * ---------------------------------------------------------------------------
 * --crystal 을 그대로 쓰면 안 된다. crystal 은 "뒤가 보이는 것"이 목적이라
 * 면이 사실상 없는데, 이 메뉴는 대화 본문 위에 떠서 글자를 얹는다. 뒤가
 * 비치면 글자 위에 글자가 겹쳐 읽을 수 없다.
 *
 * 그래서 재질은 같게 두고(중성 회색 3단 그림자 + 1px 흰 그라데이션 링 +
 * 위아래 림) 면만 88% 로 올린다. 같은 계열로 읽히면서 내용은 격리된다.
 * blur 도 6px → 20px 로 키운다 — 남은 12% 로 비치는 형체를 못 알아보게.
 *
 * ※ .glass-card 와 함께 쓴다. ::after 링의 mask 장치를 .glass-card::after
 *   에서 물려받고, 여기서는 두께와 그라데이션만 갈아 끼운다.
 * ------------------------------------------------------------------------ */
.glass-card--menu {
  border-radius: 1rem;                 /* 16px — 작은 면이라 타일(24px)보다 작게 */
  background-color: rgba(255, 255, 255, .88);
  background-image: linear-gradient(180deg,
      rgba(255, 255, 255, .35) 0%,
      rgba(255, 255, 255, 0)   100%);
  border-color: transparent;           /* 경계는 아래 ::after 링이 혼자 만든다 */
  box-shadow:
    0 2px 6px -1px rgba(88, 92, 104, .10),
    0 12px 22px -10px rgba(88, 92, 104, .26),
    0 30px 60px -24px rgba(88, 92, 104, .44),
    inset 0 1px 0 rgba(255, 255, 255, .95),
    inset 0 -1px 0 rgba(255, 255, 255, .40);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
          backdrop-filter: blur(20px) saturate(140%);
}

/* 링은 crystal 과 같은 1px 흰 그라데이션 — 좌상단이 가장 밝고 중간에서
   한 번 끊겼다가 우하단에서 다시 살아난다. */
.glass-card--menu::after {
  padding: 1px;
  background: linear-gradient(140deg,
              rgba(255, 255, 255, 1)   0%,
              rgba(255, 255, 255, 1)   9%,
              rgba(255, 255, 255, .45) 21%,
              rgba(255, 255, 255, .06) 34%,
              rgba(255, 255, 255, .85) 50%,
              rgba(255, 255, 255, .06) 63%,
              rgba(255, 255, 255, .60) 79%,
              rgba(255, 255, 255, 1)   100%);
}

/* 메뉴 항목 — hover 에 흰 판을 깔지 않는다. 88% 면 위에 흰색을 더 얹으면
   차이가 거의 안 보이는데다, 예전처럼 그림자까지 주면 항목 하나가 카드처럼
   떠올라 메뉴가 아니라 목록으로 읽힌다. 잉크와 옅은 회색 틴트만 쓴다. */
.menu-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  padding: .5rem .75rem;
  border-radius: .625rem;
  text-align: left;
  white-space: nowrap;
  color: var(--body-700);
  transition: background-color .15s, color .15s;
}
.menu-item > i { width: 1rem; text-align: center; color: var(--ink-800); }
.menu-item:hover  { background-color: rgba(88, 92, 104, .08); color: var(--ink-900); }
.menu-item:active { background-color: rgba(88, 92, 104, .14); }

/* 삭제 — 되돌릴 수 없는 동작이라 잉크와 hover 틴트 모두 붉은 계열로.
   아이콘은 상속을 따로 끊어야 위 .menu-item > i 의 ink-800 이 안 먹는다. */
.menu-item--danger,
.menu-item--danger > i { color: #BE123C; }
.menu-item--danger:hover { background-color: rgba(190, 18, 60, .09); color: #9F1239; }
.menu-item--danger:hover > i { color: #9F1239; }


/* --- 언어 (사이드바 상단 지구본 + 목록) -----------------------------------
 * 트리거는 .rail-btn 을 그대로 입는다 — 상단 바의 접기/닫기와 같은 크기·같은 hover 여야
 * 머리에 낯선 컨트롤이 하나 더 붙은 걸로 안 읽힌다. 여기서 더하는 건 잉크와 움직임뿐이다.
 *
 * 움직임은 한 군데만 쓴다 — 자오선이 스르륵 접혔다 펴지는 0.5초. 바깥 원과 적도는
 * 제자리에 둔다. 원까지 같이 돌리면 그냥 빙글대는 아이콘이 되고, 지구가 축을 돌아
 * 반대편을 내민다는 뜻이 사라진다. 언어가 실제로 바뀔 때만 돈다(메뉴를 열 때가 아니라).
 * ------------------------------------------------------------------------- */
.lang-globe { color: var(--brand-sky); }
.lang-globe > svg { width: 1.0625rem; height: 1.0625rem; }

.globe-mer { transform-origin: 12px 12px; }

@keyframes lang-globe-turn {
  0%   { transform: scaleX(1); }
  50%  { transform: scaleX(.06); }
  100% { transform: scaleX(1); }
}
.lang-globe.is-turning .globe-mer {
  animation: lang-globe-turn .5s cubic-bezier(.55, 0, .45, 1);
}

/* 목록 — 세션 ⋯ 메뉴(.menu-item)와 같은 문법. 언어 이름은 그 언어의 글자로 적는다.
   지금 언어에만 체크가 서고, 나머지 자리는 비워 두지 않고 폭만 잡아 둔다
   (opacity 로 감춘다 — display 로 지우면 고를 때마다 이름이 좌우로 흔들린다). */
#lang_menu { min-width: 9.5rem; }

.lang-item__check { opacity: 0; }
.lang-item.is-active > .lang-item__check { opacity: 1; color: var(--brand-blue); }
.lang-item.is-active .lang-item__name { color: var(--ink-900); font-weight: 600; }

/* 라틴 대문자는 자간을 벌린다 — 한글 이름과 나란히 섰을 때 글자 자체가 언어를 말한다 */
.lang-item[data-lang="en"] .lang-item__name { font-size: 11.5px; letter-spacing: .07em; }

@media (prefers-reduced-motion: reduce) {
  .lang-globe.is-turning .globe-mer { animation: none; }
}
