/* 터미널(xterm) 한글 전각 monospace — 기본 monospace 는 한글 글리프가 없어 시스템
 * 폴백이 한글을 반각으로 그려 셀 오른쪽 1칸이 비고 자간이 벌어진다. 한글·영문 폭
 * 비율이 일관된 코딩 폰트로 통일한다. */
@font-face {
  font-family: "Nanum Gothic Coding";
  src: url("/static/fonts/nanum-gothic-coding.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ===== AI Center 테마 — 토큰 + 시맨틱 클래스 =====
 * Surfaces: Win11 Fluent Dark(기본) · 밝은 화면은 아래 [data-scheme="light"] 가 토큰만 갈아 끼운다
 *
 * 단일 소스(SoT): 색 정의는 :root --bae-* 토큰 1곳 + 아래 시맨틱 클래스뿐이다.
 * 마크업/JS 는 라이트 Tailwind 색 유틸 대신 이 시맨틱 클래스를 직접 쓴다.
 */

:root {
    /* ── Accent — 테마색을 바꾸려면 이 블록만 고친다 ─────────────────
     * 아래 5줄이 앱 전체 accent 의 단일 ref 다. tint(배지·강조 배경)는
     * rgba(var(--bae-accent-rgb), α) 로 파생되므로 따로 손댈 곳이 없다.
     *
     * ⚠️ --bae-accent-rgb 는 --bae-accent 와 반드시 같은 색의 R,G,B 채널값.
     *    color-mix() 로 자동 파생하지 않는 이유는 --user-bubble-bg 주석 참조.
     * ⚠️ CSS 밖은 이 토큰이 닿지 않아 함께 갱신해야 한다:
     *    ① static/favicon.svg
     *    ② static/icon-*.png 4개 (temp/scratch/recolor_icons.py 의 DST_HEX 만 바꿔 재실행)
     *    ③ dashboard.html 의 var(--bae-accent, …) 폴백 hex
     *    ④ static/manifest.webmanifest 의 icons[].src 뒤 ?v=날짜
     *       — 안 올리면 설치된 PWA 가 옛 아이콘을 계속 쓴다(실제로 겪음).
     *    ⚠️ 아이콘은 색이 파일에 박혀 있어 아래 [data-theme] 전환을 따라가지 못한다 —
     *       기본(바이올렛) 한 벌만 둔다.
     */
    --bae-accent:        #C4B5FD;
    --bae-accent-rgb:    196, 181, 253;
    --bae-accent-hover:  #D3C2FF;
    --bae-accent-press:  #AC9BEF;
    --bae-accent-text:   #000000;

    /* 사용자 말풍선 배경 — accent 88% + #1a1a1a 12% 를 미리 계산한 정적 값.
       color-mix 는 브라우저 computed 가 color(srgb …) 로 직렬화돼 html2canvas 1.4.1
       (버그 리포트 화면 캡처)이 파싱 못 해 throw 한다. 그래서 파생이 아니라 상수다 —
       accent 를 바꾸면 이 값도 같은 비율로 다시 계산해 넣을 것. */
    --user-bubble-bg:   rgb(176, 162, 226);

    /* 글씨·테두리 자리의 accent — 어두운 화면에선 accent 그대로다. 밝은 화면에선 진한 색으로
       바뀐다(흰 배경 위에서 밝은 accent 는 대비 2 안팎이라 안 보인다). 칠하는 자리(버튼·점·tint)는
       계속 --bae-accent. [data-theme] 가 --bae-accent 를 바꾸면 여기도 따라온다(같은 요소에서 계산). */
    --bae-accent-fg:       var(--bae-accent);
    --bae-accent-fg-hover: var(--bae-accent-hover);

    /* 터미널(xterm) 배경 — 밝은 화면에서도 어둡다(터미널 프로그램 색이 어두운 배경을 전제로 한다). */
    --bae-term-bg:       #202020;

    /* Surfaces */
    --bae-bg:            #202020;
    --bae-bg-alt:        #1C1C1C;
    --bae-surface:       #2B2B2B;
    --bae-surface-alt:   #323232;
    --bae-surface-hover: #3A3A3A;
    --bae-surface-press: #272727;

    /* Borders */
    --bae-border:        #3A3A3A;
    --bae-border-hover:  #4A4A4A;
    --bae-divider:       #2D2D2D;

    /* Text */
    --bae-text-primary:  #FFFFFF;
    --bae-text-muted:    #C7C7C7;
    --bae-text-dim:      #9A9A9A;

    /* Status */
    --bae-danger:        #FF99A4;
    --bae-success:       #6CCB5F;
    --bae-warn:          #fde047;
}

/* ── TV 라임 테마 (선택) ───────────────────────────────────────────
 * 설정 → UI 설정 창의 "테마 색" 점이 <html data-theme="tv"> 를 붙이면 accent 만 라임으로
 * 바뀐다. 선택은 그 브라우저에만 남는다(localStorage `tv-cli-theme`) — 계정이 아니라
 * 기기 단위라, 회사 PC 만 라임으로 두고 나머지는 기본(바이올렛)으로 쓸 수 있다.
 * 위 :root accent 블록과 1:1 대응이며 서피스·텍스트 토큰은 공유한다.
 */
:root[data-theme="tv"] {
    --bae-accent:        #B5D332;
    --bae-accent-rgb:    181, 211, 50;
    --bae-accent-hover:  #C4E03F;
    --bae-accent-press:  #9DB924;
    --user-bubble-bg:    rgb(162, 189, 47);
}

/* ── 밝은 화면 (선택) ───────────────────────────────────────────
 * <html data-scheme="light"> — head 인라인 스크립트가 설정(UI 설정 → "화면 모드": 시스템·밝게·어둡게,
 * 이 브라우저 localStorage `tv-cli-scheme`, 기본 시스템)을 읽어 붙인다. 강조색(data-theme)과 독립이다.
 * 서피스·텍스트·상태 토큰만 갈아 끼우고, 강조색은 칠하는 자리엔 그대로·글씨와 테두리엔 --bae-accent-fg.
 */
:root[data-scheme="light"] {
    --bae-bg:            #F3F3F3;
    --bae-bg-alt:        #EBEBEB;
    --bae-surface:       #FFFFFF;
    --bae-surface-alt:   #F4F4F5;
    --bae-surface-hover: #E8E8EA;
    --bae-surface-press: #DCDCDF;

    --bae-border:        #D9D9DC;
    --bae-border-hover:  #BDBDC2;
    --bae-divider:       #E4E4E7;

    --bae-text-primary:  #1B1B1F;
    --bae-text-muted:    #45454D;
    --bae-text-dim:      #606067;

    --bae-danger:        #C62828;
    --bae-success:       #256B29;
    --bae-warn:          #8A5306;

    --bae-accent-fg:       #6D28D9;
    --bae-accent-fg-hover: #5B21B6;
}
:root[data-scheme="light"][data-theme="tv"] {
    --bae-accent-fg:       #3F6212;
    --bae-accent-fg-hover: #365314;
}
/* 사이드바는 본문보다 한 톤 어둡게 — 어두운 화면(본문보다 밝은 surface-alt)과 방향만 반대다. */
:root[data-scheme="light"] .app-bg-sidebar { background-color: var(--bae-bg-alt); }
:root[data-scheme="light"] .badge-warn     { background-color: rgba(234, 179, 8, 0.18); }
:root[data-scheme="light"] .badge-success  { background-color: rgba(34, 197, 94, 0.15); }
:root[data-scheme="light"] .badge-danger   { background-color: rgba(239, 68, 68, 0.10); }

/* ── 표면(배경) ───────────────────────────────────────────────── */
#terminal-view { background-color: var(--bae-term-bg); }
.app-bg        { background-color: var(--bae-bg); }
.app-bg-alt    { background-color: var(--bae-bg-alt); }
.app-bg-sidebar{ background-color: var(--bae-surface-alt); }
.surface       { background-color: var(--bae-surface); }
.surface-alt   { background-color: var(--bae-surface-alt); }
.surface-hover { background-color: var(--bae-surface-hover); }
.surface-hover-on-hover:hover { background-color: var(--bae-surface-hover); }
.surface-alt-on-hover:hover   { background-color: var(--bae-surface-alt); }

/* ── 텍스트 ────────────────────────────────────────────────────── */
.txt        { color: var(--bae-text-primary); }
/* 인라인 편집 입력(별칭) — 바꿔 끼우는 라벨(font-medium)과 같은 굵기 */
.txt-strong { color: var(--bae-text-primary); font-weight: 500; }
.txt-muted  { color: var(--bae-text-muted); }
.txt-dim    { color: var(--bae-text-dim); }
.txt-accent { color: var(--bae-accent-fg); }
.txt-accent-on-hover:hover { color: var(--bae-accent-fg); }
.txt-on-hover:hover        { color: var(--bae-text-primary); }
.txt-muted-on-hover:hover  { color: var(--bae-text-muted); }
.txt-success { color: var(--bae-success); }
.txt-danger  { color: var(--bae-danger); }
.txt-danger-on-hover:hover { color: var(--bae-danger); }
.txt-warn    { color: var(--bae-warn); }

/* ── 테두리·구분선 ─────────────────────────────────────────────── */
.bd          { border-color: var(--bae-border); }
.bd-strong   { border-color: var(--bae-border-hover); }
.bd-divider  { border-color: var(--bae-divider); }
.bd-accent   { border-color: var(--bae-accent-fg); }
.bd-danger   { border-color: var(--bae-danger); }
.bd-success  { border-color: var(--bae-success); }
/* 테두리도 hover 에서 색이 살도록 — 아이콘 버튼(만들기/제거)이 무엇을 하는 버튼인지
   손을 올렸을 때 색으로 드러난다(글자색 hover 클래스와 짝). */
.bd-accent-on-hover:hover { border-color: var(--bae-accent-fg); }
.bd-danger-on-hover:hover { border-color: var(--bae-danger); }

/* ── 주 액션 버튼 (accent) ─────────────────────────────────────── */
.btn-primary {
    background-color: var(--bae-accent);
    color: var(--bae-accent-text);
}
.btn-primary:hover  { background-color: var(--bae-accent-hover); }
.btn-primary:active { background-color: var(--bae-accent-press); }
.btn-primary:disabled { background-color: var(--bae-surface-hover); color: var(--bae-text-dim); }

/* ── 보조/위험 버튼 ────────────────────────────────────────────── */
.btn-ghost {
    border: 1px solid var(--bae-border-hover);
    color: var(--bae-text-muted);
}
.btn-ghost:hover { background-color: var(--bae-surface-hover); }
.btn-ghost:active { background-color: var(--bae-surface-press); }
.btn-ghost:disabled { background-color: transparent; color: var(--bae-text-dim); opacity: 0.5; }

.btn-danger {
    border: 1px solid var(--bae-danger);
    color: var(--bae-danger);
}
.btn-danger:hover { background-color: rgba(255, 153, 164, 0.15); }
.btn-danger:active { background-color: rgba(255, 153, 164, 0.25); }
.btn-danger:disabled { background-color: transparent; opacity: 0.5; }

/* ── 링크·accent 텍스트 ────────────────────────────────────────── */
.link { color: var(--bae-accent-fg); }
.link:hover { color: var(--bae-accent-fg-hover); }

/* ── 상태 배지 ─────────────────────────────────────────────────── */
/* 진한 tint(원본 *-100, 0.22) — status pill 등 */
.badge-success { background-color: rgba(108, 203, 95, 0.22); color: var(--bae-success); }
.badge-danger  { background-color: rgba(255, 153, 164, 0.22); color: var(--bae-danger); }
.badge-warn    { background-color: rgba(133, 77, 14, 0.40);   color: var(--bae-warn); }
.badge-info    { background-color: rgba(var(--bae-accent-rgb), 0.22); color: var(--bae-accent-fg); }
.badge-neutral { background-color: var(--bae-border-hover);     color: var(--bae-text-muted); }

/* ── backend 브랜드 아이콘 (사이드바 세션 카드) ─────────────────── */
/* 글자 배지 대신 마크로 어떤 CLI 인지 보여준다(이름은 hover tooltip).
   .backend-icon-terminal 은 마지막에 둔다 — kind=terminal 세션이 backend 색을 이기게. */
.backend-icon-claude   { color: #D97757; }                /* Claude(Anthropic) 브랜드색 */
.backend-icon-codex    { color: var(--bae-text-muted); }  /* OpenAI 마크는 단색 — 본문색에 맞춘다 */
.backend-icon-gemini   { color: #4285F4; }                /* Gemini 마크는 원본이 그라데이션 — 단색은 Google Blue */
.backend-icon-ollama   { color: #5FA46A; }                /* 로컬 모델 — 구독 백엔드와 구분되는 초록 */
.backend-icon-terminal { color: var(--bae-accent-fg); }      /* 터미널 세션은 앱 accent */

/* ── 사이드바 하위 카드(워커) ─────────────────────────── */
/* 한 단 들여쓰되 **폭을 그만큼 줄인다** — w-full 로 두면 들여쓴 만큼 넘쳐 사이드바에
   가로 스크롤이 생긴다. 워커 표식("↳")은 그 여백에 걸리므로 position 기준도 여기서. */
.session-nested {
    display: block;
    position: relative;
    margin-left: 1rem;
    width: calc(100% - 1rem);
}
/* 하위 카드의 표식 — 워커는 "↳".
   카드 밖(들여쓰기 여백)에 세로 가운데로 걸린다. 카드에 바짝 붙인다.
   들여쓴 카드 안에서만 보인다: 리더가 다른 그룹에 있어 들여쓰지 못한 고아 워커는
   카드가 relative 가 아니라 절대배치가 엉뚱한 조상에 걸린다.
   글자만 두면 hover 판정 영역이 글리프 크기(10x12)뿐이라 툴팁이 잘 안 걸린다 —
   박스를 키우고 그 안에서 가운데 정렬해, 보이는 위치는 그대로 두고 판정만 넓힌다. */
.session-nested-mark {
    display: none;
    position: absolute;
    left: -0.95rem;
    top: 50%;
    transform: translateY(-50%);
    align-items: center;
    justify-content: center;
    width: 1.1rem;
    height: 1.4rem;
    font-size: 0.75rem;
    line-height: 1;
    cursor: help;
}
.session-nested > .session-nested-mark {
    display: flex;
}
/* ⓘ — 제목 오른쪽의 정보 표식. 아이콘 svg 는 fill:none 이라 획 위에서만 hit-test 되므로
   (원 안쪽은 반응하지 않는다) 래퍼가 판정을 맡고 svg 는 포인터를 받지 않는다.
   카드가 draggable 이라 커서가 grab 으로 상속되는데, 여기는 잡는 곳이 아니라 읽는 곳이다. */
.session-info-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.25rem;
    margin: -0.25rem;      /* 판정만 넓히고 배치는 그대로 */
    border-radius: 9999px;
    cursor: help;
    /* 이웃(제목·오른쪽 아이콘 줄)이 확장된 판정 영역을 덮지 않게 위로 올린다. */
    position: relative;
    z-index: 1;
}
.session-info-mark:hover,
.session-info-mark:focus-visible { color: var(--bae-text-primary); }
.session-info-mark > svg { pointer-events: none; }

/* ── hover tooltip (dash_core attachTip) ───────────────────────── */
/* body 직속 fixed 노드 하나를 재사용한다 — 사이드바가 overflow-y-auto 라 카드 안에
   그리면 잘린다. 포인터를 받지 않게 해 툴팁 자신이 hover 를 가로채지 않는다. */
.tv-tip {
    position: fixed;
    inset: auto;                /* popover(top layer) UA 기본(inset:0·margin:auto·overflow)을 지운다 — 좌표는 JS */
    margin: 0;
    overflow: visible;
    max-width: min(22rem, calc(100vw - 16px));   /* 좁은 화면에서 좌우 8px 안에 */
    padding: 0.375rem 0.5rem;
    border-radius: 0.375rem;
    border: 1px solid var(--bae-border);
    background-color: var(--bae-surface-alt);
    color: var(--bae-text-muted);
    font-size: 0.75rem;
    line-height: 1.35;
    white-space: pre-line;      /* 여러 줄 tip 은 \n 으로 온다 */
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
    cursor: default;
}
.tv-tip-on {
    opacity: 1;
    visibility: visible;
}

/* ── toast (dash_core toast) ────────────────────────────────────── */
/* 잠깐 뜨는 알림. popover(top layer)라 열린 모달 위에도 보이고(dash_core raiseToasts), 흐름 밖이라
   아래 레이아웃을 밀지 않는다. 포인터를 받지 않아 뒤의 버튼을 가리지 않는다.
   화면 잠금 중엔 가려진다(custom.css screen-locked). */
/* 하단 중앙(2026-10-01 사용자 — 상단에서 옮김). 홈 바·제스처 영역 위로 띄운다. 채팅 입력창이 보이면
   dash_core.js toast() 가 bottom 을 입력창 위로 올린다(입력란을 덮지 않게). */
.tv-toasts {
    position: fixed;
    inset: auto;                /* popover(top layer) UA 기본(inset:0·margin:auto·테두리·배경·overflow)을 지운다 */
    margin: 0; padding: 0; border: 0; background: transparent; color: inherit; overflow: visible;
    bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    width: max-content;
    max-width: calc(100vw - 2rem);
    pointer-events: none;
}
.tv-toast {
    max-width: 28rem;
    padding: 0.5rem 0.875rem;
    border-radius: 0.5rem;
    border: 1px solid var(--bae-border);
    background-color: var(--bae-surface-alt);
    color: var(--bae-text-primary);
    font-size: 0.875rem;
    line-height: 1.35;
    text-align: center;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
    animation: tv-toast-in 0.15s ease-out;
    transition: opacity 0.2s;
}
.tv-toast-danger {
    border-color: var(--bae-danger);
    color: var(--bae-danger);
}
.tv-toast-out { opacity: 0; }
@keyframes tv-toast-in {
    from { opacity: 0; transform: translateY(6px); }
}

/* 옅은 tint(원본 *-50, 0.15) — 에러 박스·Edit diff 블록 등 */
.tint-success { background-color: rgba(108, 203, 95, 0.15); }
.tint-danger  { background-color: rgba(255, 153, 164, 0.15); }
.tint-info    { background-color: rgba(var(--bae-accent-rgb), 0.15); }

/* ── 사이드바 세션 카드 라이브 신호 ───────────────────────────── */
/* 진행 중(thinking/streaming/tool_running) — 노랑 펄스 도트와 통일. */
.session-busy {
    background-color: rgba(253, 224, 71, 0.10);
    box-shadow: inset 3px 0 0 #fde047;
}
/* 응답 완료 후 사용자가 그 세션을 아직 확인 안 함 — 녹색 도트와 통일. */
.session-unread {
    background-color: rgba(34, 197, 94, 0.12);
    box-shadow: inset 3px 0 0 #22c55e;
}
/* 자기는 안 도는데 **하위 세션(워커)이 응답 중** — 하늘. 자기 진행(노랑)과 갈라 보이게
   새 색을 쓴다(2026-09-22). 리더가 응답 완료(녹) 상태여도 이 색이 이긴다 — 아직 끝나지
   않은 일이 남았다는 뜻이 더 급하다. */
.session-worker {
    background-color: rgba(56, 189, 248, 0.12);
    box-shadow: inset 3px 0 0 #38bdf8;
}
/* AskUserQuestion 응답 대기 — 주황. 사용자가 직접 답해야 진행되므로 가장 강한 강조. */
.session-auq {
    background-color: rgba(251, 146, 60, 0.14);
    box-shadow: inset 3px 0 0 #fb923c;
}
/* 유휴 — 회색 도트와 통일(약한 톤, active 카드는 강조 유지를 위해 JS에서 제외). */
.session-idle {
    background-color: rgba(107, 114, 128, 0.06);
    box-shadow: inset 3px 0 0 rgba(107, 114, 128, 0.55);
}
/* 선택된 세션 — accent 색 outline 으로 강조(outline 은 카드 크기·시그널 box-shadow 와 충돌 없음). */
.session-active {
    outline: 1px solid var(--bae-accent-fg);
    outline-offset: -1px;
}
/* 선택 + 상태색: 원래는 좌측 상태 바(3px)와 accent outline 이 좌측 변에서 겹쳐 라인이 지저분.
   outline 을 box-shadow ring 으로 바꾸고 좌측 3px 상태 바를 그 위 레이어로 얹어 좌측의 accent
   선만 덮는다 → 좌측 겹침 제거. 상/우/하 accent 1px·상태색·fill 은 원래대로. busy/unread/auq. */
.session-active.session-busy {
    outline: none;
    box-shadow: inset 3px 0 0 #fde047, inset 0 0 0 1px var(--bae-accent-fg);
}
.session-active.session-unread {
    outline: none;
    box-shadow: inset 3px 0 0 #22c55e, inset 0 0 0 1px var(--bae-accent-fg);
}
.session-active.session-auq {
    outline: none;
    box-shadow: inset 3px 0 0 #fb923c, inset 0 0 0 1px var(--bae-accent-fg);
}
.session-active.session-worker {
    outline: none;
    box-shadow: inset 3px 0 0 #38bdf8, inset 0 0 0 1px var(--bae-accent-fg);
}

/* ── 사이드바 드래그 재정렬 ───────────────────────────── */
/* 그룹 헤더·세션 카드는 드래그로 순서 변경 가능. grab 커서로 가능함을 알리고,
   드래그 중인 요소는 반투명 처리. 클릭(세션 선택)은 그대로 동작. */
[data-tree] [draggable="true"] { cursor: grab; }
[data-tree] [draggable="true"]:active { cursor: grabbing; }
.sidebar-dragging { opacity: 0.45; }

/* 드롭될 자리를 가리키는 가로선. position:fixed 라 사이드바 스크롤 오프셋 계산이 필요
   없고(좌표는 dragover 마다 rect 로 새로 잡는다), pointer-events 가 없어 드래그를
   가로막지 않는다. 놓을 수 없는 자리에서는 선을 숨기고 커서가 금지 모양이 된다. */
.sidebar-drop-line {
  position: fixed;
  height: 2px;
  border-radius: 1px;
  background: var(--bae-accent);
  box-shadow: 0 0 4px rgba(var(--bae-accent-rgb), 0.7);
  pointer-events: none;
  z-index: 60;
}
/* 버튼·콤보 아래에 떠서 열리는 패널(하위 폴더 고르기·폴더 추가·PC 관리 작업 폴더/하네스/CLI).
   배경과 구분되도록 테두리를 accent 로 약하게 강조하고(2026-09-30 사용자), 안의 목록이 넘쳐도
   스크롤바는 그리지 않는다(휠·드래그 스크롤은 그대로 된다 — #event-stream 과 같은 방식). */
.float-panel { border-color: rgba(var(--bae-accent-rgb), 0.55); }
/* 받은 메시지 카드(user_inbox.js) — 떠 있는 패널은 아니지만 같은 accent 테두리 */
.user-msg-card { border-color: rgba(var(--bae-accent-rgb), 0.55); }
/* ── 떠 있는 화면 높이 — 채팅 위에 뜨는 화면(모달·패널·메뉴) 전부를 여기 한 곳에서 관리한다 ──────
 * 규칙(2026-10-02 사용자): **상한은 공통 --float-max(70vh), 그 안에서 화면마다 자기 크기를 --float-h 로 정한다.**
 * --float-h 를 안 주면 상한 크기다. 창마다 인라인 height/max-height 를 박지 않는다(상한을 우회한다) —
 * 크기를 정할 땐 style="--float-h: 40rem" 처럼 변수만 준다. 실제 높이 = min(--float-h, --float-max).
 *  · .float-modal     — 모달 창. 높이 고정(안에서 눌러도 창 크기가 안 변한다 — AGENTS.md ui-floating-fixed-size).
 *  · .float-modal-fit — 내용만큼 크는 작은 모달(확인 창 등). --float-h 는 최대치로 쓴다.
 *  · .float-panel     — 항목 아래에 뜨는 패널(테두리 강조 포함). 넘치면 안쪽 스크롤.
 *  · .float-menu      — 입력란·버튼 옆에 뜨는 메뉴(슬래시·첨부·설정). 넘치면 안쪽 스크롤.
 *  패널·메뉴가 자리(위·아래 남은 공간)에 맞춰 더 줄어야 하면 JS 가 --float-room 을 넣는다.
 *  overflow-hidden 인 것은 안쪽 요소가 스스로 스크롤한다.
 *  ⚠️ 사용자 정의 속성은 상속된다 — --float-h 를 준 창 안에 또 떠 있는 화면을 두면 그 화면도 자기 --float-h 를 다시 준다. */
:root { --float-max: 70vh; }
/* 예외(2026-10-08 사용자): 읽는 창인 파일 뷰어·'변경 사항'(diff) 만 상한 90vh. 안에 뜨는 화면도 상속받는다. */
.float-tall { --float-max: 90vh; }
.float-modal, .float-modal-fit, .float-panel, .float-menu {
  --float-size: min(var(--float-h, var(--float-max)), var(--float-max));
}
.float-modal { height: var(--float-size); max-height: var(--float-size); }
.float-modal-fit { max-height: var(--float-size); }
.float-panel, .float-menu { max-height: min(var(--float-size), var(--float-room, var(--float-size))); }
.float-panel:not(.overflow-hidden), .float-menu:not(.overflow-hidden) { overflow-y: auto; }
.float-panel, .float-panel .overflow-y-auto { scrollbar-width: none; }
.float-panel::-webkit-scrollbar, .float-panel .overflow-y-auto::-webkit-scrollbar { display: none; }

/* 탭 줄(코드 창 폴더·파일 탭, 콘솔 탭) 드래그 재정렬 표시선 — 위 선의 세로판. tab_reorder.js */
.tab-drop-line {
  position: fixed;
  width: 2px;
  border-radius: 1px;
  background: var(--bae-accent);
  box-shadow: 0 0 4px rgba(var(--bae-accent-rgb), 0.7);
  pointer-events: none;
  z-index: 60;
}

/* ── 사이드바 카드 라이브 점 — 응답대기(주황) > 생각중(노랑) > 미확인(녹) > 유휴(회).
   상시 pulse 애니메이션은 저CPU여도 GPU 컴포지터를 매 프레임 점유해 다른 탭 영상 재생을
   버벅이게 만든다. 움직임 없는 정적 halo(box-shadow — 1회 paint, 컴포지터 루프 없음)로
   대체: auq=강한 주황 glow, busy=옅은 노랑 glow. unread/idle 은 색만(정적). */
.session-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 9999px;
    flex-shrink: 0;
}
.session-dot-busy {
    background-color: #fde047;
    box-shadow: 0 0 4px rgba(253, 224, 71, 0.8);
}
/* 하위 세션이 응답 중 — 카드 tint(.session-worker)와 같은 하늘. 자기 진행(노랑 glow)과
   달리 glow 를 옅게 둬 "내 일은 아니다" 를 톤으로도 구분한다. */
.session-dot-worker {
    background-color: #38bdf8;
    box-shadow: 0 0 4px rgba(56, 189, 248, 0.6);
}
.session-dot-unread { background-color: #22c55e; }
.session-dot-idle   { background-color: #6b7280; opacity: 0.55; }
/* orphaned — agent WS 가 끊겨 재개 대기 중. 문자열 배지를 대신하는 빨간 도트. */
.session-dot-orphan { background-color: #ef4444; }
.session-dot-auq {
    background-color: #fb923c;
    box-shadow: 0 0 6px 1px rgba(251, 146, 60, 0.9);
}

/* ── 폼 필드 ───────────────────────────────────────────────────── */
.field {
    background-color: var(--bae-surface-alt);
    color: var(--bae-text-primary);
    border-color: var(--bae-border);
}
/* outline 은 지우지 않고 투명으로 — 고대비(forced-colors) 모드에서 포커스 표시가 남는다(Tailwind focus:outline-none 과 같은 값) */
.field:focus { border-color: var(--bae-accent-fg); outline: 2px solid transparent; outline-offset: 2px; }
.field:read-only,
.field[readonly] {
    background-color: var(--bae-surface);
    border-color: var(--bae-border);
}
.field:disabled { background-color: var(--bae-surface); color: var(--bae-text-dim); cursor: not-allowed; }
.field::placeholder { color: var(--bae-text-dim); }

/* ── 상태 점(2px dot) — solid 색 ──────────────────────────────── */
.dot-online  { background-color: var(--bae-success); }
.dot-offline { background-color: var(--bae-danger); }
.dot-neutral { background-color: var(--bae-text-dim); }

/* ── 포커스 링 ─────────────────────────────────────────────────── */
.focus-ring:focus { --tw-ring-color: var(--bae-accent-fg); }

/* ── AskUserQuestion 옵션 행 ───────────────────────────────────── */
.opt-recommended { border: 1px solid var(--bae-accent-fg); background-color: rgba(var(--bae-accent-rgb), 0.15); }
.opt-row { border: 1px solid transparent; }
.opt-row:hover { background-color: var(--bae-surface-alt); }
.opt-picked { background-color: rgba(108, 203, 95, 0.15); border-color: var(--bae-success); }

/* ── 막(딤 오버레이) — 모달이 아닌 덮개(모바일 사이드바·메모 옆 칸·파일 끌어놓기)용. 모달의 막은 아래 ::backdrop ── */
.overlay { background-color: rgba(0, 0, 0, 0.60); }
.overlay-strong { background-color: rgba(0, 0, 0, 0.70); }

/* ── 모달(<dialog>, ui_modal.js openModal) ─────────────────────────
 * dialog 는 화면 전체를 덮는 투명 층이고 창은 그 안의 상자다(가운데 정렬은 dialog 의 Tailwind 클래스).
 * 종전 div 막과 같은 자리라 상자의 배치·크기가 그대로다. 바깥 클릭 판정도 이 층(e.target === dialog).
 * UA 기본(테두리·여백·margin:auto·max-width·inset·overflow·배경·글자색)은 :where() 로 지운다 —
 * 명시도 0 이라 dialog 에 붙인 Tailwind(p-4 등)가 그대로 이긴다. 막 색은 ::backdrop(.60 / strong .70). */
@layer base {
    /* base 층 — 유틸리티(p-4 등)가 이긴다(층이 없는 Tailwind 3 형제에서도 브라우저 기본보다는 위). */
    :where(dialog.modal) {
        position: fixed; inset: 0;
        width: 100%; height: 100%; max-width: none; max-height: none;
        margin: 0; padding: 0; border: 0; overflow: visible;
        background: transparent; color: inherit;
    }
}
dialog.modal[open] { display: flex; }

/* ── popover(메뉴·떠 있는 패널·토스트·툴팁) — top layer ─────────────────
 * UA 기본(inset:0·margin:auto·padding·overflow:auto·글자색·배경)을 지운다. 명시도 0 이라 Tailwind 클래스가 이긴다.
 * 자리는 JS 가 fixed 좌표로 준다(ui_modal placePopover — top layer 엔 absolute 기준이 없다). 테두리는
 * Tailwind preflight(* { border: 0 solid })가 이미 UA 를 이긴다. */
@layer base {
    :where([popover]) {
        inset: auto; margin: 0; padding: 0; overflow: visible;
        color: inherit; background: transparent;
    }
}
dialog.modal:focus { outline: none; }
dialog.modal::backdrop { background-color: rgba(0, 0, 0, 0.60); }
dialog.modal-strong::backdrop { background-color: rgba(0, 0, 0, 0.70); }

/* ── 사용자 말풍선 (accent 강조 버블) ──────────────────────────── */
/* buildUserCard 전용. md 본문은 .assistant-md 경로를 그대로 쓰므로
   사용자 스코프에서 accent 위 가독 색으로 재정의. 하이재킹 규칙이 사라져
   더 이상 main .assistant-md * !important 와 경합하지 않으므로 !important 불요. */
.user-bubble {
    /* 배경은 :root --user-bubble-bg(accent 를 12% 톤다운한 상수). 페이드 ::after
       끝색도 같은 변수를 참조해 배경/페이드가 어긋나지 않는다. */
    background-color: var(--user-bubble-bg);
    color: #000000;
}
/* 잘림 하단 페이드 — max-h-28 + overflow-hidden 으로 콘텐츠가 잘렸을 때만
   (is-truncated 클래스) 그린다. 짧은 메시지는 원래 스타일 유지.
   톤다운 배경(--user-bubble-bg)으로 자연스럽게 사라지며, pointer-events: none 으로
   텍스트 선택·우상단 확대 버튼 hit-test 를 가리지 않는다. */
.user-bubble.is-truncated::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 1.5rem;
    background: linear-gradient(to bottom, transparent, var(--user-bubble-bg));
    pointer-events: none;
    border-bottom-left-radius: inherit;
    border-bottom-right-radius: inherit;
}
/* 우상단 확대 버튼이 첫 라인 텍스트와 겹치지 않도록 float 스페이서로 첫 라인만
   우측 공간 확보. assistant 측은 "ASSISTANT" 라벨이 우상단 영역을 비우지만
   user-bubble은 라벨이 없어 텍스트가 버튼 위로 흐른다 → is-truncated 일 때만 적용. */
.user-bubble.is-truncated::before {
    content: "";
    float: right;
    width: 3.5rem;
    height: 1.25rem;
}
/* 확대·복사 버튼: 글로벌 txt-dim/txt-muted-on-hover 가 다크 surface 기준이라
   accent 배경 위에서 잘 안 보임 → user-bubble 스코프에서 짙은 톤으로 재정의. */
.user-bubble .assistant-fullscreen-btn,
.user-bubble .assistant-copy-btn {
    color: rgba(0, 0, 0, 0.55);
}
.user-bubble .assistant-fullscreen-btn:hover,
.user-bubble .assistant-copy-btn:hover {
    color: #1a1a1a;
}
.user-bubble .assistant-md { color: #000000; }
/* accent(밝은) 배경의 검정 글씨는 어두운 배경의 흰 글씨(halation 으로 더 두껍게 지각)보다
   얇아 보인다 → 본문(p·li) 두께를 한 단계 올려 어시스턴트 말풍선과 지각 굵기를 맞춘다.
   strong/b 는 700 으로 보호(p·li 상속에 안 묻히게), heading·th 는 p·li 선택자 밖이라 영향 없음. */
.user-bubble .assistant-md p,
.user-bubble .assistant-md li { font-weight: 500; }
.user-bubble .assistant-md strong,
.user-bubble .assistant-md b { font-weight: 700; }
.user-bubble .assistant-md a {
    color: #0f2e00;
    text-decoration: underline;
}
.user-bubble .assistant-md a:hover { color: #1f4d00; }
.user-bubble .assistant-md code {
    background-color: rgba(0, 0, 0, 0.14);
    color: #14210a;
}
.user-bubble .assistant-md pre {
    background-color: #1f1f1f;
    color: #f3f4f6;
    max-width: 100%;
}
.user-bubble .assistant-md pre code {
    background: transparent;
    color: inherit;
}
.user-bubble .assistant-md blockquote {
    border-left-color: rgba(0, 0, 0, 0.45);
    color: #1f1f1f;
}
.user-bubble .assistant-md th,
.user-bubble .assistant-md td {
    border-color: rgba(0, 0, 0, 0.35);
}
.user-bubble .assistant-md th {
    background-color: rgba(0, 0, 0, 0.12);
    color: #14210a;
}
.user-bubble .assistant-md table { max-width: 100%; }
.user-bubble .assistant-md hr {
    border-top-color: rgba(0, 0, 0, 0.30);
}

/* ── assistant 마크다운 스코프 (다크 surface 톤 단일 정의) ─────── */
/* custom.css 의 라이트 hex 하드코딩 + dark.css 의 override 를 토큰 참조
   단일 정의로 통합 — 이중 페인트 제거. 색 외 레이아웃/타이포는 custom.css 유지. */
.assistant-md code {
    background-color: var(--bae-surface-alt);
    color: var(--bae-text-primary);
}
.assistant-md pre {
    background-color: var(--bae-bg-alt);
    color: var(--bae-text-primary);
}
.assistant-md blockquote {
    border-left-color: var(--bae-border-hover);
    color: var(--bae-text-muted);
}
.assistant-md th,
.assistant-md td {
    border-color: var(--bae-border);
}
.assistant-md th {
    background-color: var(--bae-surface-alt);
}
.assistant-md a {
    color: var(--bae-accent-fg);
}
.assistant-md a:hover {
    color: var(--bae-accent-fg-hover);
}
.assistant-md hr {
    border-top-color: var(--bae-border);
}
