/* AI Search Floating Ball & Drawer Styles */

/*
 * Floating Ball
 *
 * 定位（fixed / right / bottom / z-index）已经挪到外层 .ai-trigger-dock（css/ai-float-trigger.css）：
 * 球现在能拖，拖的是整个 dock（球 + 气泡）。这里只剩球自己的外观。
 */
.ai-search-trigger {
    width: 56px;
    height: 56px;
    border-radius: 28px;
    background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
    box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: grab;
    transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    color: white;
}

.ai-search-trigger:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    transform: scale(1.1) rotate(5deg);
    box-shadow: 0 6px 16px rgba(37, 99, 235, 0.4);
}

.ai-search-trigger i {
    font-size: 24px;
}

/* Chat Drawer */
.ai-drawer-overlay {
    position: fixed;
    inset: 0;
    /* 此前写的是不存在的 backdrop-blur 属性，等于一直没有模糊 */
    background: var(--kb-scrim-bg);
    backdrop-filter: blur(var(--kb-scrim-blur));
    -webkit-backdrop-filter: blur(var(--kb-scrim-blur));
    z-index: 2000;
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease;
}

.ai-drawer-overlay.active {
    opacity: 1;
    visibility: visible;
}

.ai-drawer {
    /*
     * 宽度只写一处：关闭态的 right 由它取负算出来。原来 width 和 right 各写死一个
     * 1000px，调宽度时漏改 right 抽屉就关不干净，会在右缘留一条。
     *
     * clamp 的下界 1000px 是老宽度——1024~1136px 的窄屏上 80vw 会比它还小，
     * 没有下界反而越改越窄；上界 1560px 免得大屏上抽屉宽到像整页跳转
     * （2560 宽的屏上仍露出约 1000px 的页面）。V3.61 从 1200px 放宽：AI 回答里的
     * 参数表、代码块在 1200px 里只有约 900px 可用，宽屏上右侧空着、表格却在横向滚。
     */
    --ai-drawer-width: clamp(1000px, 80vw, 1560px);
    /*
     * 会话列表宽度。样式表按断点给默认值（桌面 260 / 平板 220），用户拖过之后由
     * AiSearch._applySidebarWidth 写在元素上（行内变量压过这里），偏好存 localStorage。
     */
    --ai-sidebar-width: 260px;
    position: fixed;
    top: 0;
    right: calc(-1 * var(--ai-drawer-width));
    width: var(--ai-drawer-width);
    max-width: 100%;
    /* iOS Safari 的 100vh 是地址栏收起时的高度，按它撑满会把底部输入区顶出可视区，
       dvh 跟随实际可视高度；vh 留给不支持 dvh 的旧浏览器兜底 */
    height: 100vh;
    height: 100dvh;
    background: var(--bg-primary, #ffffff);
    box-shadow: -4px 0 20px rgba(0, 0, 0, 0.1);
    z-index: 2001;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transition: right 0.3s ease;
}

.ai-drawer.active {
    right: 0;
}

/* 拖图进来时的高亮。用 ::after 覆盖层而不是给 .ai-drawer 加边框：
   边框会占布局宽度，抽屉里的内容会在拖拽的瞬间整体位移一下。
   pointer-events:none 是必须的——覆盖层一旦吃掉指针事件，
   dragleave 会立刻触发，遮罩就变成疯狂闪烁 */
.ai-drawer::after {
    content: '松开即可上传图片';
    position: absolute;
    inset: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    font-weight: 600;
    color: var(--kb-accent, #2563eb);
    background: rgba(37, 99, 235, 0.08);
    border: 2px dashed var(--kb-accent, #2563eb);
    border-radius: 8px;
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.15s ease;
}

.ai-drawer.ai-drawer--dragover::after {
    opacity: 1;
    visibility: visible;
}

[data-theme="dark"] .ai-drawer::after {
    background: rgba(59, 130, 246, 0.14);
}

.ai-drawer-body {
    flex: 1;
    min-height: 0;
    display: flex;
    background: var(--bg-primary, #ffffff);
    /* 贴边的收起 / 展开键按它定位 */
    position: relative;
}

.ai-session-sidebar {
    width: var(--ai-sidebar-width);
    flex-shrink: 0;
    border-right: 1px solid var(--border-light, #f1f1f1);
    background: #f8fafc;
    display: flex;
    flex-direction: column;
    min-height: 0;
    transition: width 0.25s ease, border-color 0.25s ease;
}

/* 拖缝期间手在动、面板不能追着过渡 */
.ai-drawer.is-sidebar-resizing .ai-session-sidebar,
.ai-drawer.is-sidebar-resizing .ai-sidebar-toggle {
    transition: none;
}

/*
 * 桌面端（非覆盖式，> 720px）的收起态：宽度归零而不是 display:none，
 * 展开时才有从边缘滑出来的过渡；列表内容在归零过程中会被 overflow 裁掉。
 * 720px 以下的覆盖式抽屉有自己的 transform 规则，见文件末尾那段 @media。
 */
@media (min-width: 721px) {
    .ai-drawer.ai-sidebar-collapsed .ai-session-sidebar {
        width: 0;
        min-width: 0;
        overflow: hidden;
        border-right-color: transparent;
    }

    /* 拖拽调宽的缝：与目录面板的 .toc-resize-handle 同一副形态（1px、hover 才显色） */
    .ai-session-resize-handle {
        width: 1px;
        flex-shrink: 0;
        cursor: col-resize;
        background: transparent;
        transition: background 0.2s ease;
        position: relative;
        z-index: 11;
    }

    /* 1px 太难命中：用伪元素把可点区域向两侧各扩 3px，视觉上仍是一条细缝 */
    .ai-session-resize-handle::before {
        content: '';
        position: absolute;
        top: 0;
        bottom: 0;
        left: -3px;
        right: -3px;
    }

    .ai-session-resize-handle:hover,
    .ai-session-resize-handle.active {
        background: rgba(0, 0, 0, 0.1);
    }

    [data-theme="dark"] .ai-session-resize-handle:hover,
    [data-theme="dark"] .ai-session-resize-handle.active {
        background: rgba(255, 255, 255, 0.16);
    }

    .ai-drawer.ai-sidebar-collapsed .ai-session-resize-handle {
        display: none;
    }

    /*
     * 贴边收起 / 展开键：与目录面板的 .toc-edge-toggle 完全对称（16×44、圆角朝外）。
     * 主题版（.kb-paper-app .ai-sidebar-toggle）的配色早在 reading-theme.css 里等着了。
     * left 跟着列表宽度走，收起时贴到最左；拖缝期间关过渡（见上面 is-sidebar-resizing）
     */
    .ai-sidebar-toggle {
        position: absolute;
        left: var(--ai-sidebar-width);
        top: 50%;
        transform: translateY(-50%);
        z-index: 12;
        width: 16px;
        height: 44px;
        /*
         * min-* 要显式写：mobile.css 在 ≤1023px 给所有 button 兜了 min-width / min-height: 32px，
         * 而 min-width 不看特异度、直接压过 width——iPad mini 竖屏（744px）上这颗 16px 的贴边键
         * 就被撑成 32px 宽的一块。目录面板的 .toc-edge-toggle 同一处理。
         */
        min-width: 16px;
        min-height: 44px;
        padding: 0;
        border: none;
        border-radius: 0 6px 6px 0;
        background: var(--bg-secondary, #f3f4f6);
        color: rgb(100, 116, 139);
        cursor: pointer;
        font-size: 0.8rem;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: left 0.25s ease, background 0.2s, color 0.2s;
    }

    .ai-sidebar-toggle:hover:not(:where(html[data-kb-pointer="touch"] *)) {
        background: var(--bg-tertiary, rgb(229, 231, 235));
        color: rgb(30, 41, 59);
    }

    .ai-sidebar-toggle i {
        transition: transform 0.25s ease;
        line-height: 1;
    }

    .ai-drawer.ai-sidebar-collapsed .ai-sidebar-toggle {
        left: 0;
    }

    .ai-drawer.ai-sidebar-collapsed .ai-sidebar-toggle i {
        transform: rotate(180deg);
    }

    [data-theme="dark"] .ai-sidebar-toggle {
        background: rgb(38, 50, 66);
        color: rgb(148, 163, 184);
    }

    [data-theme="dark"] .ai-sidebar-toggle:hover:not(:where(html[data-kb-pointer="touch"] *)) {
        background: rgb(55, 65, 81);
        color: rgb(226, 232, 240);
    }
}

.ai-session-overlay {
    display: none;
}

[data-theme="dark"] .ai-session-sidebar {
    background: #111827;
    border-color: #374151;
}

.ai-session-sidebar-header {
    padding: 8px;
    display: flex;
    align-items: center;
    gap: 8px;
    border-bottom: 1px solid var(--border-light, #f1f1f1);
}

/*
 * 「聊天 / 工作·编码」分段控件。形状照 doc-converter 的 .source-tab（凹槽 + 浮起的选中项），
 * 配色直接取 --kb-* 令牌：凹槽底比侧栏低一档（--kb-segment-track-bg），选中项用 --kb-selected-*，
 * 深浅两套主题都定义过，不用再写 [data-theme="dark"] 分支。
 */
.ai-mode-tabs {
    display: flex;
    gap: 4px;
    margin: 8px 8px 0;
    padding: 3px;
    border-radius: 0.5rem;
    background: var(--kb-segment-track-bg, #f3f4f6);
    border: 1px solid var(--kb-paper-line, rgba(96, 84, 62, 0.15));
    box-sizing: border-box;
}

/*
 * 凹槽整体高度 = 3px 内边距 × 2 + 1px 边框 × 2 + 28px 的 tab = 36px，与下面
 * .ai-new-chat-btn 的 min-height 一致；两者左右都空 8px，宽度也对齐。
 */
.ai-mode-tab {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.3rem;
    min-height: 28px !important;
    padding: 0 8px;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--kb-ink-soft, #6b7280);
    background: transparent;
    /* 透明边框占位：选中时换成实色不会发生 1px 抖动 */
    border: 1px solid transparent;
    border-radius: 0.375rem;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.15s ease, color 0.15s ease;
}

.ai-mode-tab i {
    /* 与 .ai-step-icon 同一套：图标按行盒居中会比中文墨迹高一点，按字体族下压一档 */
    position: relative;
    top: var(--kb-icon-optical-shift, 0.06em);
    font-size: 0.95rem;
    line-height: 1;
}

.ai-mode-tab:not(.active):hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: var(--kb-active-bg, rgba(0, 0, 0, 0.04));
    color: var(--kb-ink, #374151);
}

.ai-mode-tab.active {
    background: var(--kb-selected-bg, #ffffff);
    color: var(--kb-selected-text, #1f2937);
    /* 选中项靠底色浮起就够了，不描边：凹槽本身已经有一圈边框，里面再描一圈是两层框 */
    border-color: transparent;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

/*
 * 会话列表的搜索框：直接挂知识库列表那套类（.search-container / .search-input-wrapper / .search-input，
 * 含主题覆盖），这里只把尺寸缩一档——侧栏比列表页窄得多。
 */
.ai-session-search {
    /* .search-container 在列表页头部是 flex:1 撑开的；侧栏是纵向 flex，这里必须不撑，否则它把列表挤到底部 */
    flex: 0 0 auto;
    max-width: none;
    /* 上下留白从分隔线起算、各 8px：上面就是这 8px；下面由列表的 4px 内边距 + 首条的 4px 外边距凑齐（见下一条） */
    padding: 8px 8px 0;
    box-sizing: border-box;
}

.ai-session-search + .ai-session-list {
    padding-top: 4px;
}

.ai-session-sidebar .ai-session-search .search-input-wrapper {
    height: 32px;
    padding: 0 10px;
    /* 与上面「新对话 / 新建项目」按钮同一个圆角 */
    border-radius: 6px;
    /* 侧栏底色本来就比页面低一档，再垫一层半透明的浅色就成了「多出来的一块背景」；聚焦只描边、不加内阴影 */
    background: transparent !important;
}

.ai-session-sidebar .ai-session-search .search-input-wrapper:focus-within {
    box-shadow: none !important;
}

.ai-session-sidebar .ai-session-search .search-icon {
    width: 14px;
    height: 14px;
    margin-right: 6px;
    font-size: 14px;
    line-height: 14px;
}

.ai-session-sidebar .ai-session-search .search-input {
    font-size: 0.8125rem;
}

.ai-session-sidebar .ai-session-search .search-clear {
    width: 20px;
    height: 20px;
    min-width: 0 !important;
    min-height: 0 !important;
    margin-left: 4px;
}

/* ── 「工作/编码」tab：项目行与它下面的会话行 ── */
.ai-project-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 2px 4px 2px 8px;
    font-size: 0.75rem;
    color: #9ca3af;
}

.ai-project-head .ai-session-action {
    /* 头部的「+」不是悬停浮层，常驻 */
    position: static;
    opacity: 1;
}

.ai-project-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    margin-top: 4px;
    border-radius: 6px;
    cursor: pointer;
    /* 只过渡悬停浮起等其它属性；背景高亮（hover/active）在整块重画后会立刻到位，
       不再从透明渐变到高亮——那一下渐变就是选中行「闪动」的来源。 */
    transition: background-color 0s;
    -webkit-tap-highlight-color: transparent;
}

@media (hover: hover) and (pointer: fine) {
    .ai-project-item:hover:not(:where(html[data-kb-pointer="touch"] *)) {
        background: rgba(0, 0, 0, 0.04);
    }

    [data-theme="dark"] .ai-project-item:hover:not(:where(html[data-kb-pointer="touch"] *)) {
        background: rgba(255, 255, 255, 0.06);
    }
}

/* 「更多」菜单开着：这一行保持悬停态，菜单才不像飘在空中 */
.ai-project-item--menu-open {
    background: rgba(0, 0, 0, 0.04);
}

[data-theme="dark"] .ai-project-item--menu-open {
    background: rgba(255, 255, 255, 0.06);
}

.ai-project-item--menu-open .ai-session-actions {
    opacity: 1 !important;
    pointer-events: auto !important;
}

.ai-project-item[draggable="true"] {
    -webkit-user-drag: element;
}

.ai-project-group--dragging {
    opacity: 0.45;
}

/* 拖动落点：目标行上沿 / 下沿一条 2px 的强调色插入线 */
.ai-project-group {
    position: relative;
}

.ai-project-group--drop-before::before,
.ai-project-group--drop-after::after {
    content: '';
    position: absolute;
    left: 8px;
    right: 8px;
    height: 2px;
    border-radius: 1px;
    background: var(--kb-accent, #6f674d);
    pointer-events: none;
    z-index: 1;
}

.ai-project-group--drop-before::before {
    top: 1px;
}

.ai-project-group--drop-after::after {
    bottom: -3px;
}

/* ── 项目行的「更多」菜单（挂在 body 上，fixed 定位；子菜单同一套样式） ── */
.ai-popover-menu {
    position: fixed;
    /* 抽屉本身在 2001，窄屏的会话侧栏在 2004：菜单要压在它们上面 */
    z-index: 2100;
    min-width: 176px;
    max-width: 280px;
    padding: 4px;
    border: 1px solid var(--kb-paper-line, rgba(96, 84, 62, 0.15));
    border-radius: 10px;
    background: var(--kb-paper-panel, #fffdf8);
    box-shadow: var(--kb-paper-shadow, 0 18px 42px rgba(67, 56, 38, 0.10));
    color: var(--kb-ink, #2f2b24);
    font-size: 0.8125rem;
    animation: ai-popover-in 0.12s ease-out;
}

@keyframes ai-popover-in {
    from { opacity: 0; transform: translateY(-2px); }
    to { opacity: 1; transform: none; }
}

.ai-popover-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 0 !important;
    padding: 6px 10px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.ai-popover-item > span {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ai-popover-item > i {
    flex-shrink: 0;
    font-size: 0.9375rem;
    color: var(--kb-ink-soft, #5e584e);
}

.ai-popover-item:focus-visible,
.ai-popover-item[aria-expanded="true"] {
    outline: none;
    background: var(--kb-active-bg, rgba(111, 103, 77, 0.10));
}

@media (any-hover: hover) {
    .ai-popover-item:hover:not(:where(html[data-kb-pointer="touch"] *)) {
        background: var(--kb-active-bg, rgba(111, 103, 77, 0.10));
    }
}

.ai-popover-item[aria-disabled="true"] {
    color: var(--kb-control-disabled-text, #9ca3af);
    cursor: default;
    background: transparent !important;
}

.ai-popover-item[aria-disabled="true"] > i {
    color: inherit;
}

.ai-popover-item--danger,
.ai-popover-item--danger > i {
    color: var(--color-error, #e74c3c);
}

.ai-popover-chevron {
    margin-left: auto;
}

.ai-popover-key {
    flex-shrink: 0;
    font-family: inherit;
    font-size: 0.75rem;
    color: var(--kb-ink-muted, #827a6d);
}

.ai-popover-sep {
    height: 1px;
    margin: 4px 6px;
    background: var(--kb-paper-line, rgba(96, 84, 62, 0.15));
}

.ai-popover-loading {
    padding: 6px 10px;
    color: var(--kb-ink-muted, #827a6d);
    white-space: nowrap;
}

/* 项目里有会话被选中：项目行也淡淡点亮，收起时用户仍知道当前对话在哪个项目下。
 * 用 inset box-shadow 而不是 background 出这层选中色——列表整块重画时新节点的
 * background 会从透明过渡到高亮（.ai-project-item 有 transition: background 0.15s），
 * 选中行因此闪一下；box-shadow 不参与这条过渡，重画后立刻就是稳定成色。
 * 选一个与原 5% 蓝色观感接近、但在纸张主题深色侧栏上也能看出来的暖色强调蒙层。
 */
.ai-project-item.active {
    background: var(--kb-active-bg, rgba(59, 130, 246, 0.05));
}

.kb-paper-app .ai-project-item.active {
    background: var(--kb-active-bg) !important;
    color: var(--kb-accent) !important;
}

.ai-project-icon {
    flex-shrink: 0;
    font-size: 1rem;
    color: #6b7280;
}

[data-theme="dark"] .ai-project-icon {
    color: #9ca3af;
}

.ai-project-badge {
    display: inline-block;
    margin-left: 6px;
    padding: 0 5px;
    font-size: 0.6875rem;
    font-weight: 400;
    line-height: 1.5;
    border-radius: 999px;
    vertical-align: 1px;
    background: rgba(0, 0, 0, 0.05);
    color: #6b7280;
}

.ai-project-badge--warn {
    background: rgba(245, 158, 11, 0.14);
    color: #b45309;
}

[data-theme="dark"] .ai-project-badge--warn {
    background: rgba(245, 158, 11, 0.18);
    color: #fbbf24;
}

/* 项目下的会话行缩进一档，左侧一条细线把归属画出来 */
.ai-project-sessions {
    margin-left: 14px;
    padding-left: 6px;
    border-left: 1px solid var(--border-light, #e5e7eb);
}

[data-theme="dark"] .ai-project-sessions {
    border-left-color: rgba(255, 255, 255, 0.1);
}

.ai-session-item--nested {
    padding-left: 6px;
}

.ai-project-no-sessions,
.ai-project-session-loading {
    padding: 6px 8px;
    font-size: 0.75rem;
    color: #9ca3af;
}

.ai-project-new-chat-link {
    min-height: 0 !important;
    padding: 0;
    border: none;
    background: transparent;
    color: #3b82f6;
    font-size: inherit;
    cursor: pointer;
}

.ai-project-empty p {
    margin: 0;
    line-height: 1.5;
}

.ai-project-empty-create {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: 0 !important;
    padding: 5px 10px;
    font-size: 0.75rem;
    color: #3b82f6;
    background: rgba(59, 130, 246, 0.08);
    border: 1px solid rgba(59, 130, 246, 0.2);
    border-radius: 6px;
    cursor: pointer;
}

/* ── 创建 / 编辑项目弹框：源文件夹列表 ── */
.ai-project-dialog {
    display: flex;
    flex-direction: column;
    gap: 18px;
    padding: 4px 0;
}

/* 文件夹区给足高度：一个空空的虚线框显得弹框「没内容」，用户不知道往哪儿点 */
.ai-project-folders {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-height: 88px;
}

.ai-project-folder {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 8px;
    border-radius: 6px;
    background: var(--kb-active-bg, rgba(0, 0, 0, 0.04));
    font-size: 0.8125rem;
    color: var(--kb-ink, #374151);
}

.ai-project-folder i {
    /* 与 .ai-step-icon 同一套：锁死盒高再居中，吸收字形在 em 盒里的位置差；再按字体族下压一档 */
    display: inline-flex;
    align-items: center;
    height: 1.5em;
    line-height: 1;
    flex-shrink: 0;
    position: relative;
    top: var(--kb-icon-optical-shift, 0.06em);
    color: var(--kb-ink-soft, #6b7280);
}

.ai-project-folder-path {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* 省略号打在开头、留住最后几级目录名：路径的区分度全在末尾。开头补了 &lrm; 让首个 / 不被
       双向算法甩到末尾 */
    direction: rtl;
    text-align: left;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.75rem;
}

.ai-project-folder .ai-session-action {
    position: static;
    opacity: 1;
}

.ai-project-folder-empty,
.ai-project-folder-hint {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    margin: 0;
    padding: 14px 16px;
    border: 1px dashed var(--kb-paper-line, rgba(96, 84, 62, 0.2));
    border-radius: 6px;
    font-size: 0.75rem;
    line-height: 1.5;
    color: var(--kb-ink-soft, #6b7280);
}

.ai-project-add-folder {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    align-self: center;
    min-height: 0 !important;
    padding: 6px 14px;
    font-size: 0.8125rem;
    color: var(--kb-ink, #374151);
    background: var(--kb-paper-panel, #fff);
    border: 1px solid var(--kb-paper-line, rgba(96, 84, 62, 0.15));
    border-radius: 999px;
    cursor: pointer;
}

.ai-project-add-folder:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    border-color: var(--kb-accent, #6f674d);
}

/* ── 输入框上方：一直挂着的插件 chip + 项目徽标 ── */
.ai-composer-context {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    /* 底栏自带 20px 上内边距：往上收 8px，与下方到输入框的 12px 对齐 */
    margin-top: -8px;
    padding: 0 2px 12px;
    font-size: 0.75rem;
}

/* 上方有图片预览时不往上收，否则会贴到预览图上 */
.ai-image-preview-list:not([style*="none"]) + .ai-composer-context {
    margin-top: 0;
}

.ai-composer-context[hidden] {
    display: none;
}

.ai-active-plugin,
.ai-workspace-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    box-sizing: border-box;
    height: 24px;
    min-height: 0 !important;
    /* 徽标是 <button>，不继承字号，比旁边的插件 chip 大一号 */
    font: inherit;
    padding: 0 6px 0 8px;
    border-radius: 999px;
    border: 1px solid var(--kb-paper-line, rgba(96, 84, 62, 0.15));
    background: var(--kb-active-bg, rgba(0, 0, 0, 0.04));
    color: var(--kb-ink, #374151);
    line-height: 1.6;
    white-space: nowrap;
}

.ai-workspace-badge {
    cursor: pointer;
    padding-right: 8px;
}

.ai-workspace-badge em {
    font-style: normal;
    opacity: 0.6;
}

.ai-workspace-badge--blocked {
    border-color: rgba(245, 158, 11, 0.4);
    background: rgba(245, 158, 11, 0.12);
    color: #b45309;
}

[data-theme="dark"] .ai-workspace-badge--blocked {
    color: #fbbf24;
}

.ai-active-plugin-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 0 !important;
    min-height: 0 !important;
    width: 16px;
    height: 16px;
    padding: 0;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: inherit;
    opacity: 0.55;
    cursor: pointer;
}

.ai-active-plugin-remove:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    opacity: 1;
    background: rgba(0, 0, 0, 0.08);
}

[data-theme="dark"] .ai-session-sidebar-header {
    border-color: #374151;
}

.ai-chat-panel {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    position: relative;
}

/*
 * 会话列表开关的尺寸、描边、底色、hover 与图标字号全部来自 .kb-header-icon-btn
 * （css/nav-controls.css）——它就是首页顶栏那颗菜单键，同一个图标不该有两种大小。
 *
 * 这里原来自带一整套：32px 方角、透明底、#6b7280 硬编码文字色、
 * `i { font-size: 1.25rem }` 以及 rgba(0,0,0,.06) 的 hover 底。
 * 那份 1.25rem 正是「AI 抽屉的菜单图标比首页大一圈」的来源。
 */

/* Dark Mode Support */
[data-theme="dark"] .ai-drawer {
    background: #1f2937;
    color: #f3f4f6;
}

/*
 * Drawer Header
 *
 * 几何（内边距、高度、分隔线、背景）全部来自 .editor-header —— 与「新增知识库」
 * 抽屉是同一套骨架，标题栏高度不该有肉眼可见的差别。这里**刻意不再写
 * padding / border-bottom / display**：ai-search.css 加载在 editor.css 之后，
 * 同权重下会压过骨架，那正是两个抽屉高度对不齐的原因。
 */
.ai-drawer-header {
    /* 骨架本身不带 gap，这里也不加——加了会把关闭按钮往里挤，与其它抽屉对不齐 */
}

/*
 * 标题 + 重建索引 + 清空 RAG 三者同属 .editor-header-content。
 * 两个动作按钮是一组，彼此贴紧（2px + 各自 4px 内边距）；与标题之间仍留 8px，
 * 靠标题自己的 margin-right 补足差额——gap 是均匀的，做不出「组内紧、组外松」。
 */
.ai-drawer-header .editor-header-content {
    /* 两个动作按钮现在是 36px 的圆形控件，2px 会让两颗圆贴在一起；
       与顶栏那组（.kb-nav-actions-left 的 0.25rem）取同一档间距 */
    gap: 0.25rem;
}

.ai-drawer-header .ai-drawer-title {
    margin-right: 6px;
}

@media (max-width: 1023px) {
    /*
     * .editor-header-content 在窄屏会被绝对居中（编辑器那边标题两侧是返回/关闭按钮）。
     * AI 抽屉的标题右侧还挂着重建索引和清空 RAG 两个按钮，一起绝对居中会挤成一团，
     * 所以这里退回正常流。
     */
    .ai-drawer-header .editor-header-content {
        position: static;
        transform: none;
        width: auto;
        justify-content: flex-start;
    }

    /*
     * 平板（含 iPad mini 竖屏 744px）会话列表常驻，不需要抽屉开关。
     *
     * 多带一层 .ai-drawer 把特异度提到 (0,3,0)：css/nav-controls.css 里
     * `.kb-header-icon-btn.mobile-only { display: inline-flex !important }` 同为 (0,2,0)
     * 且加载更晚，不加这一层，这个开关会在平板上冒出来。
     */
    .ai-drawer .ai-sidebar-open.mobile-only,
    .ai-drawer .ai-sidebar-toggle.mobile-only {
        display: none !important;
    }

    .ai-drawer {
        --ai-sidebar-width: 220px;
    }
}

@media (max-width: 720px) {
    /* 同上，特异度要与上面那条一致，否则手机上又回不来 */
    .ai-drawer .ai-sidebar-open.mobile-only,
    .ai-drawer .ai-sidebar-toggle.mobile-only {
        display: inline-flex !important;
    }

    /* 覆盖式抽屉：没有缝可拖，也没有贴边键，开合走标题栏的汉堡键 + 遮罩 */
    .ai-session-resize-handle,
    .ai-sidebar-toggle {
        display: none !important;
    }
}

/* 字号/字重/颜色由 .editor-title 提供；这里只负责让机器人图标与文字并排 */
.ai-drawer-title {
    display: flex;
    align-items: center;
    gap: 8px;
    /* .editor-title 的 flex:1 会把两个动作按钮顶到最右边，与原来「紧跟标题」的排布不同；
       收回 flex 让它按内容宽度收缩，省略号仍由 .editor-title 的 overflow 负责 */
    flex: 0 1 auto;
}

/*
 * AI 重索引按钮 - 紧跟在标题文字右侧。
 *
 * 这里**不能有 margin-left: auto**。它原本是死写法：旧结构里标题盒按内容收缩，
 * 左边没有可吃的剩余空间，auto 等于 0，按钮看着就贴着标题。改用
 * .editor-header-content（flex: 1）之后剩余空间跑到了这一层，auto 立刻生效，
 * 把两个按钮一路推到关闭按钮旁边。
 */
/* 尺寸/描边/底色/hover 全部来自 .kb-header-icon-btn（css/nav-controls.css）。
   曾经这里自带 4px 内边距与 4px 圆角，和抽屉里其它按钮完全不是一路货。 */

/*
 * 索引进行中：转的是**里面的图标**，不是那颗圆形按钮。
 * Tailwind 的 .animate-spin 挂在按钮上（JS 那边六处 addClass 都是这么写的），
 * 直接生效会让整颗带描边的圆一起转，看起来像界面坏了。
 */
.ai-reindex-btn.animate-spin {
    animation: none;
    cursor: default;
    color: var(--kb-accent);
}

.ai-reindex-btn.animate-spin > i {
    animation: spin 1s linear infinite;
}

/* 旋转态不可再次点击，去掉 hover 反馈 */
.ai-reindex-btn.animate-spin:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: var(--kb-nav-control-bg);
    border-color: var(--kb-paper-line);
    color: var(--kb-accent);
}

/* ===== 知识库索引选择弹框 ===== */
.reindex-dialog {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background: var(--kb-scrim-bg);
    backdrop-filter: blur(var(--kb-scrim-blur));
    -webkit-backdrop-filter: blur(var(--kb-scrim-blur));
    animation: reindexDialogFadeIn 0.18s ease-out;
}

.reindex-dialog-panel {
    width: 100%;
    max-width: 400px;
    padding: 24px;
    border-radius: 16px;
    border: 1px solid var(--border-color);
    background: var(--bg-primary);
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.18);
    animation: reindexDialogPop 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

@keyframes reindexDialogFadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes reindexDialogPop {
    from { opacity: 0; transform: translateY(8px) scale(0.98); }
    to { opacity: 1; transform: translateY(0) scale(1); }
}

.reindex-dialog-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 20px;
}

.reindex-dialog-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    border-radius: 12px;
    font-size: 1.25rem;
    color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 12%, transparent);
}

.reindex-dialog-heading {
    min-width: 0;
}

.reindex-dialog-title {
    margin: 0;
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.4;
    color: var(--text-primary);
}

.reindex-dialog-subtitle {
    margin: 2px 0 0;
    font-size: 0.8125rem;
    line-height: 1.4;
    color: var(--text-muted);
}

.reindex-dialog-options {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.reindex-option {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 14px;
    text-align: left;
    border-radius: 12px;
    border: 1px solid var(--border-color);
    background: var(--bg-secondary);
    cursor: pointer;
    transition: border-color 0.16s ease, background-color 0.16s ease;
}

.reindex-option:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    border-color: color-mix(in srgb, var(--color-primary) 46%, var(--border-color));
    background: color-mix(in srgb, var(--color-primary) 8%, var(--bg-secondary));
}

.reindex-option-group {
    overflow: hidden;
    border: 1px solid var(--border-color);
    border-radius: 12px;
    background: var(--bg-secondary);
    transition: border-color 0.16s ease, background-color 0.16s ease;
}

.reindex-option-group--danger:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    border-color: color-mix(in srgb, var(--color-accent) 46%, var(--border-color));
    background: color-mix(in srgb, var(--color-accent) 8%, var(--bg-secondary));
}

.reindex-option--embedded {
    border: 0;
    border-radius: 0;
    background: transparent;
}

.reindex-option--danger.reindex-option--embedded:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    border-color: transparent;
    background: transparent;
}

.reindex-option--danger:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    border-color: color-mix(in srgb, var(--color-accent) 46%, var(--border-color));
    background: color-mix(in srgb, var(--color-accent) 8%, var(--bg-secondary));
}

.reindex-option-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: 10px;
    font-size: 1.0625rem;
    color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 12%, transparent);
}

.reindex-option--danger .reindex-option-icon {
    color: var(--color-accent);
    background: color-mix(in srgb, var(--color-accent) 14%, transparent);
}

.reindex-option-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-width: 0;
}

.reindex-option-title {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--text-primary);
}

.reindex-option-tag {
    padding: 1px 6px;
    border-radius: 999px;
    font-size: 0.6875rem;
    font-weight: 400;
    line-height: 1.5;
    color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 14%, transparent);
}

.reindex-option-desc {
    font-size: 0.75rem;
    line-height: 1.5;
    color: var(--text-muted);
}

.reindex-option-arrow {
    flex-shrink: 0;
    font-size: 1.125rem;
    color: var(--text-muted);
    opacity: 0.6;
}

.reindex-vision-cache-option {
    margin-left: 58px;
    padding: 0 14px 14px 0;
}

.reindex-checkbox-label {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--text-primary);
    cursor: pointer;
}

.reindex-checkbox {
    width: 16px;
    height: 16px;
    margin: 0;
    flex-shrink: 0;
    accent-color: var(--color-accent);
    cursor: pointer;
}

.reindex-checkbox:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.reindex-checkbox-help {
    margin: 3px 0 0 24px;
    font-size: 0.6875rem;
    line-height: 1.55;
    color: var(--text-muted);
}

@media (max-width: 420px) {
    .reindex-dialog-panel {
        padding: 20px;
    }

    .reindex-vision-cache-option {
        margin-left: 58px;
    }
}

.reindex-dialog-cancel {
    width: 100%;
    margin-top: 16px;
    padding: 10px;
    border: none;
    border-radius: 10px;
    background: transparent;
    font-size: 0.875rem;
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.16s ease, background-color 0.16s ease;
}

.reindex-dialog-cancel:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: var(--text-primary);
    background: var(--bg-secondary);
}

/* AI 清空 RAG 数据库按钮 - 紧跟重建索引按钮右侧。
   外观（含 hover 转红）来自 .kb-header-icon-btn / --danger 变体，这里不再写。 */

/* 尺寸、配色与图标字号全部来自 .kb-header-icon-btn（css/nav-controls.css） */

/* 移动端没有返回按钮可依赖，关闭按钮必须一直在 */
.ai-drawer-close.editor-close-btn {
    display: flex !important;
}

/* Chat Messages */
.ai-chat-messages {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 20px;
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.ai-message-item {
    max-width: 85%;
    display: flex;
    flex-direction: column;
    position: relative;
}

.ai-message-item-user {
    align-self: flex-end;
    align-items: flex-end;
}

.ai-message-item-ai {
    align-self: flex-start;
    align-items: flex-start;
}

.message-bubble {
    max-width: 100%;
    padding: 12px 16px;
    border-radius: 12px;
    font-size: 0.9375rem;
    line-height: 1.5;
    position: relative;
}

.message-user {
    align-self: flex-end;
    background: #3b82f6;
    color: white;
    border-bottom-right-radius: 2px;
}

.message-ai {
    align-self: flex-start;
    background: #f3f4f6;
    color: #1f2937;
    border-bottom-left-radius: 2px;
}

[data-theme="dark"] .message-ai {
    background: #374151;
    color: #f3f4f6;
}

/* AI 回复异常（网络中断、服务端报错）的气泡样式 */
.message-ai-error {
    background: color-mix(in srgb, var(--color-error) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-error) 26%, transparent);
}

/* 澄清反问：AI 需要用户补充信息才能回答，视觉上与普通回答区分开 */
.message-bubble.ai-clarify {
    background: color-mix(in srgb, var(--primary-color) 6%, transparent);
    border-left: 3px solid color-mix(in srgb, var(--primary-color) 55%, transparent);
}

.ai-message-error {
    display: inline-flex;
    align-items: flex-start;
    gap: 6px;
    color: var(--color-error);
}

/* 正文正常输出、仅收尾出错时的轻量提示，挂在气泡末尾而不影响正文样式 */
.ai-message-error-notice {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid color-mix(in srgb, var(--color-error) 22%, transparent);
    font-size: 0.75rem;
    line-height: 1.5;
    color: var(--color-error);
}

.ai-message-error-notice i {
    flex-shrink: 0;
    font-size: 0.875rem;
}

/* 断流后正在等服务端把这一轮跑完：屏幕上此刻是半截内容，不给状态就像卡死了。
   用 muted 而不是 error 色——这不是失败，多数情况下几秒之后内容就补齐了 */
.ai-message-syncing-notice {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--border-light, #f1f1f1);
    font-size: 0.75rem;
    line-height: 1.5;
    color: var(--text-muted);
}

.ai-message-syncing-notice i {
    flex-shrink: 0;
    font-size: 0.875rem;
    animation: ai-message-syncing-spin 1s linear infinite;
}

@keyframes ai-message-syncing-spin {
    to { transform: rotate(360deg); }
}

.ai-message-error i {
    flex-shrink: 0;
    /* Remixicon 的 glyph 在 em 盒里偏下，直接给行高对不齐。
       这里让图标盒高度等于气泡一行的行高，再把 glyph 在盒内居中，即可与首行文字视觉居中对齐 */
    display: flex;
    align-items: center;
    height: 1.5em;
    line-height: 1;
}

.ai-message-actions {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    align-self: flex-end;
    gap: 6px;
    min-height: 24px;
    margin: 4px 4px -8px 0;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-1px);
    transition: opacity 0.16s ease, transform 0.16s ease;
    z-index: 1;
}

.ai-message-item:hover:not(:where(html[data-kb-pointer="touch"] *)) .ai-message-actions,
.ai-message-item:focus-within .ai-message-actions {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.ai-message-created-time {
    font-size: 11px;
    line-height: 1;
    color: #9ca3af;
    white-space: nowrap;
    user-select: none;
}

/* 两颗按钮同规格：右边复制，左边加入到知识库 */
.ai-message-copy-btn,
.ai-message-save-kb-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    min-height: 24px !important;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: #6b7280;
    cursor: pointer;
    transition: color 0.16s ease, background-color 0.16s ease, opacity 0.16s ease;
}

.ai-message-copy-btn:hover:not(:where(html[data-kb-pointer="touch"] *)),
.ai-message-save-kb-btn:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #2563eb;
    background: rgba(37, 99, 235, 0.1);
}

.ai-message-copy-btn--copied {
    color: #16a34a;
    background: rgba(22, 163, 74, 0.12);
}

/* 两颗按钮共用这个隐藏类：没有正文时一起藏，见 setMessageCopySource */
.ai-message-copy-btn--hidden {
    display: none;
}

[data-theme="dark"] .ai-message-copy-btn,
[data-theme="dark"] .ai-message-save-kb-btn {
    color: #d1d5db;
}

[data-theme="dark"] .ai-message-created-time {
    color: #9ca3af;
}

[data-theme="dark"] .ai-message-copy-btn:hover:not(:where(html[data-kb-pointer="touch"] *)),
[data-theme="dark"] .ai-message-save-kb-btn:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #93c5fd;
    background: rgba(147, 197, 253, 0.12);
}

/* 触摸设备上这排东西常驻显示。
   触发条件必须按「指针能力」判断，不能按 `max-width: 1023px` 判断：
   iPad 横屏是 1024px，落不进移动端断点，而上面的 hover 规则又被
   `data-kb-pointer="touch"` 排除，结果时间和两颗按钮永远不出现。
   `hover: none` 覆盖首次 pointerdown 之前的初始状态，属性选择器覆盖
   带触控板的 iPad 这类混合设备——手指操作时走常驻，鼠标操作时回到 hover。 */
@media (hover: none) {
    .ai-message-actions {
        min-height: 26px;
        margin: 6px 4px -2px 0;
        opacity: 1;
        pointer-events: auto;
        transform: none;
    }

    .ai-message-copy-btn,
    .ai-message-save-kb-btn {
        background: rgba(37, 99, 235, 0.1);
        color: #2563eb;
    }

    [data-theme="dark"] .ai-message-copy-btn,
    [data-theme="dark"] .ai-message-save-kb-btn {
        background: rgba(147, 197, 253, 0.14);
        color: #93c5fd;
    }
}

html[data-kb-pointer="touch"] .ai-message-actions {
    min-height: 26px;
    margin: 6px 4px -2px 0;
    opacity: 1;
    pointer-events: auto;
    transform: none;
}

html[data-kb-pointer="touch"] .ai-message-copy-btn,
html[data-kb-pointer="touch"] .ai-message-save-kb-btn {
    background: rgba(37, 99, 235, 0.1);
    color: #2563eb;
}

html[data-kb-pointer="touch"][data-theme="dark"] .ai-message-copy-btn,
html[data-kb-pointer="touch"][data-theme="dark"] .ai-message-save-kb-btn {
    background: rgba(147, 197, 253, 0.14);
    color: #93c5fd;
}

/* Markdown Content */
.ai-message-content p { margin-bottom: 8px; }
.ai-message-content p:last-child { margin-bottom: 0; }
.ai-message-content ul,
.ai-message-content ol {
    padding-left: 2.4em;
    margin: 8px 0;
}
.ai-message-content ul { list-style-type: disc; }
.ai-message-content ol { list-style-type: decimal; }
.ai-message-content ul ul { list-style-type: circle; }
.ai-message-content li {
    margin-bottom: 4px;
    line-height: 1.6;
}
.ai-message-content li > p { margin-bottom: 4px; }
.ai-message-content h1,
.ai-message-content h2,
.ai-message-content h3,
.ai-message-content h4 {
    font-weight: 600;
    margin: 12px 0 6px;
    line-height: 1.4;
}
.ai-message-content h1 { font-size: 1.25em; }
.ai-message-content h2 { font-size: 1.125em; }
.ai-message-content h3 { font-size: 1em; }
.ai-message-content h4 { font-size: 0.9375em; }
.ai-message-content blockquote {
    border-left: 3px solid #d1d5db;
    padding: 4px 12px;
    margin: 8px 0;
    color: #6b7280;
    background: rgba(0,0,0,0.03);
    border-radius: 0 4px 4px 0;
    line-height: 1.6;
    /* 知识正文的全局 blockquote 为保留 Quill 缩进使用了 pre-wrap。
       AI Markdown 的标签间换行只是排版源码，保留下来会在引用列表中生成大段空行。 */
    white-space: normal;
}
[data-theme="dark"] .ai-message-content blockquote {
    border-left-color: #4b5563;
    color: #9ca3af;
    background: rgba(255,255,255,0.03);
}
.ai-table-wrapper {
    overflow-x: auto;
    max-width: 100%;
    margin: 8px 0;
}
/* 表格左下角的「导出 Excel」键：样式复用 knowledge-content.css 的全局 .table-export-excel-btn，
   这里只收一下与表格的间距（容器自带 8px 下边距，再加按钮的 6px 上边距就离得太远） */
.ai-message-content .ai-table-wrapper + .table-export-excel-btn {
    margin: -2px 0 8px;
}
.ai-message-content table {
    border-collapse: collapse;
    font-size: 0.875em;
    width: max-content;
    min-width: 100%;
}
.ai-message-content th,
.ai-message-content td {
    border: 1px solid #e5e7eb;
    padding: 6px 10px;
    text-align: left;
}
.ai-message-content th {
    background: rgba(0,0,0,0.04);
    font-weight: 600;
}
[data-theme="dark"] .ai-message-content th,
[data-theme="dark"] .ai-message-content td {
    border-color: #4b5563;
}
[data-theme="dark"] .ai-message-content th {
    background: rgba(255,255,255,0.04);
}
.ai-message-content hr {
    border: none;
    border-top: 1px solid #e5e7eb;
    margin: 12px 0;
}
.ai-message-content strong { font-weight: 600; }
.ai-message-content em { font-style: italic; }
.ai-message-content pre {
    background: #1e293b;
    padding: 12px;
    border-radius: 8px;
    overflow-x: auto;
    margin: 8px 0;
    color: #e2e8f0;
    word-wrap: break-word;
    overflow-wrap: break-word;
    white-space: pre-wrap;
}
/*
 * 代码块右上角的「复制」键（V3.60）：与详情页同一套 DOM（SyntaxHighlighter.addCopyButton 包出的
 * .code-block-wrapper > .code-scroll-container > pre，按钮挂在外层），样式照 knowledge-content.css
 * 的 .code-copy-btn 抄，但那边全部限定在 .knowledge-content 下、气泡里够不着，这里单独给一份。
 * 外层接管原来 pre 的外边距与圆角，pre 自己归零，否则包一层后代码块会多出一圈缝。
 */
.ai-message-content .code-block-wrapper {
    position: relative;
    margin: 8px 0;
    border-radius: 8px;
    overflow: hidden;
}
.ai-message-content .code-block-wrapper .code-scroll-container {
    overflow-x: auto;
}
.ai-message-content .code-block-wrapper pre {
    margin: 0;
    border-radius: 0;
}
/* 悬浮在代码块右上角、不占正文空间：平时半透明，指到代码块上才亮起。
   偏移与 pre 的 12px 内边距对齐：贴着 8px 圆角的 0.5rem 会让按钮压在深色块的圆角边缘上 */
.ai-message-content .code-copy-btn {
    position: absolute;
    top: 18px;
    right: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    min-width: 28px;
    min-height: 28px;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 4px;
    background: rgba(30, 41, 59, 0.75);
    color: #e2e8f0;
    font-size: 0.75rem;
    cursor: pointer;
    opacity: 0.55;
    z-index: 15;
    transition: opacity 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}
.ai-message-content .code-block-wrapper:hover .code-copy-btn,
.ai-message-content .code-copy-btn:focus-visible {
    opacity: 1;
}
.ai-message-content .code-copy-btn:hover {
    background: rgba(255, 255, 255, 0.2);
    border-color: rgba(255, 255, 255, 0.3);
}
.ai-message-content .code-copy-btn.copied {
    background: rgba(34, 197, 94, 0.8);
    border-color: rgba(34, 197, 94, 1);
    color: #fff;
}
.ai-message-content .code-copy-btn i {
    font-size: 14px;
    line-height: 1;
}

/*
 * 没有空格的长串（密文、token、URL、长参数 JSON）不能把气泡撑破。
 * 此前只有移动端媒体查询里写了强制换行，桌面端一段 RSA 密文就直接越过了气泡右边界。
 * 用 anywhere 而不是 break-word：后者只在已经溢出时才断，不参与最小内容宽度计算，
 * 气泡在 flex 布局里仍会被撑宽；anywhere 让可断点计入最小宽度，从源头上不撑。
 * 与 reading-theme.css 里详情页正文（.knowledge-content）同一写法。
 */
.ai-message-content {
    overflow-wrap: anywhere;
}
.ai-message-content code {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    font-size: 0.875em;
}
.ai-message-content :not(pre) > code {
    background: rgba(0,0,0,0.06);
    padding: 1px 4px;
    border-radius: 3px;
    overflow-wrap: anywhere;
}
[data-theme="dark"] .ai-message-content :not(pre) > code {
    background: rgba(255,255,255,0.1);
}
.ai-message-content img {
    display: block;
    max-width: 100%;
    height: auto;
    border-radius: 8px;
    margin: 8px 0;
    box-shadow: 0 1px 4px rgba(0,0,0,0.1);
    cursor: pointer;
    transition: box-shadow 0.2s;
}
.ai-message-content img:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
/* 表格列宽由 max-content 决定，单元格内图片的 max-width:100% 解不出具体值，
   会按原始像素把表格撑到需要横向滚动，这里给个绝对上限，放大看走灯箱 */
.ai-message-content th img,
.ai-message-content td img {
    max-width: min(280px, 55vw);
    height: auto;
}

/* Input Area */
/* 流式期间用户往上翻看时出现的「回到底部」，浮在输入区正上方（bottom 由 JS 按输入区实际高度设）。
   外观在 styles/index.css 的 .kb-scroll-jump-btn（与详情页的顶 / 底跳转钮同一份），这里只写定位 */
.ai-scroll-bottom-btn {
    position: absolute;
    right: 20px;
    bottom: 96px;
    z-index: 5;
}

.ai-drawer-footer {
    padding: 20px;
    border-top: 1px solid var(--border-light, #f1f1f1);
    background: var(--bg-primary);
    flex-shrink: 0;
}

/* ============================================================
 * 写操作确认：盖在输入框上，而不是弹一个居中的系统对话框
 *
 * 确认属于**这一轮对话**，不属于整个应用。居中的模态框把用户从对话里拽出来，
 * 上下文（他刚说了什么、助手打算做什么）全被盖住；盖在输入框上时，
 * 上面的消息流一直看得见，而输入框被占住本身就说明「这一轮在等你」。
 *
 * 锚在 .ai-drawer-footer 的底部向上生长：内容多时会盖到消息区上，
 * 这是有意的——确认条比几条旧消息重要。
 * ============================================================ */

.ai-drawer-footer {
    position: relative;
}

/* 确认条在场时盖住消息区：全站唯一的一种遮罩（.kb-scrim），点击不响应——误触不该决定放行还是拒绝 */
.ai-confirm-backdrop {
    position: absolute;
    inset: 0;
    z-index: 29;
    animation: ai-confirm-fade 0.18s ease-out;
}

@keyframes ai-confirm-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

.ai-confirm-overlay {
    position: absolute;
    left: 12px;
    right: 12px;
    bottom: 12px;
    /* 顶不封死：内容少时贴着输入框，内容多时向上长，最多占到抽屉的六成高 */
    max-height: 60vh;
    z-index: 30;
    display: flex;
    align-items: flex-end;
    animation: ai-confirm-rise 0.18s ease-out;
}

@keyframes ai-confirm-rise {
    from { transform: translateY(8px); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}

.ai-confirm-card {
    width: 100%;
    max-height: 60vh;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 14px 16px 12px;
    border: 1px solid var(--kb-accent, #2563eb);
    border-radius: 12px;
    background: var(--bg-primary, #ffffff);
    /* 阴影要够重：它盖着的是可交互的输入框，必须一眼看出「上面这层才是现在要处理的」 */
    box-shadow: 0 -6px 28px rgba(15, 23, 42, 0.18), 0 2px 8px rgba(15, 23, 42, 0.08);
}

.ai-confirm-head {
    display: flex;
    align-items: flex-start;
    gap: 10px;
}

.ai-confirm-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: 9px;
    background: var(--kb-accent-soft, rgba(37, 99, 235, 0.12));
    color: var(--kb-accent, #2563eb);
    font-size: 1.0625rem;
}

.ai-confirm-title strong {
    display: block;
    font-size: 0.875rem;
    color: var(--text-primary, #111827);
}

.ai-confirm-title span {
    display: block;
    margin-top: 2px;
    font-size: 0.8125rem;
    line-height: 1.6;
    color: var(--text-secondary, #6b7280);
}

.ai-confirm-title code {
    padding: 1px 6px;
    border-radius: 4px;
    background: var(--bg-secondary, #f6f8fa);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.75rem;
}

/* 发起方给的人话说明。放在方法名与参数之间：先说清「这是在干什么」，
   再让用户去核对参数——反过来的话，用户要先读完一段 JSON 才知道自己在确认什么 */
.ai-confirm-hint {
    margin: 10px 0 0;
    padding: 8px 12px;
    border-left: 3px solid var(--kb-accent, #2563eb);
    border-radius: 0 6px 6px 0;
    background: var(--kb-accent-soft, rgba(37, 99, 235, 0.08));
    font-size: 0.8125rem;
    line-height: 1.6;
    color: var(--text-primary, #111827);
}

/* 参数原样摊开给用户核对——这是他为之负责的那次操作的全部内容，
   折叠或截断都会让「确认」退化成走过场 */
/* 打开网址（open-url）的确认条：只画那一个 URL，可换行、可整段选中复制去核对 */
.ai-confirm-url {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin: 10px 0 0;
    padding: 10px 12px;
    border-radius: 6px;
    background: var(--bg-secondary, #f6f8fa);
    font-size: 12px;
    line-height: 1.6;
}

.ai-confirm-url i {
    flex-shrink: 0;
    color: var(--kb-text-muted, #9ca3af);
    font-size: 14px;
    line-height: 1.4;
}

.ai-confirm-url code {
    min-width: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    word-break: break-all;
    user-select: all;
}

/* 下载确认（download-file）的地址清单：条数可能有八条，给它自己的滚动区，
   别把「保存到哪个目录」那一行挤出视野——那一行和地址一样是用户要判断的东西 */
.ai-confirm-url-list {
    margin: 0;
    padding: 0 0 0 4px;
    max-height: 132px;
    overflow: auto;
    overscroll-behavior: contain;
    list-style: none;
}

.ai-confirm-url-list li {
    padding: 3px 0;
}

.ai-confirm-url-list code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 11px;
    word-break: break-all;
    user-select: all;
}

/* 落盘目录：与来源地址同一种块，但图标不同，一眼分得清「从哪儿」和「到哪儿」 */
.ai-confirm-url--target {
    margin-top: 6px;
}

.ai-confirm-params {
    margin: 10px 0 0;
    padding: 10px 12px;
    max-height: 180px;
    overflow: auto;
    overscroll-behavior: contain;
    border-radius: 6px;
    background: var(--bg-secondary, #f6f8fa);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    line-height: 1.6;
    white-space: pre-wrap;
    word-break: break-all;
}

.ai-confirm-actions {
    display: flex;
    /* 三个键（取消 / 本轮对话始终允许 / 确认执行）在窄抽屉里放不下一行时换行，不挤成一团 */
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 12px;
}

.ai-confirm-btn {
    min-height: 34px;
    padding: 6px 16px;
    border: 1px solid var(--border-color, #e5e7eb);
    border-radius: 8px;
    background: transparent;
    color: var(--text-secondary, #4b5563);
    font-size: 0.8125rem;
    cursor: pointer;
    transition: background-color 0.2s ease;
}

.ai-confirm-btn:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: rgba(148, 163, 184, 0.14);
}

/* 文字色走 --text-inverse：深色主题下 --kb-accent 是浅奶油色，白字会糊掉。
   与 .kb-update-action--primary / .kb-download-action--primary 同一套语义 */
.ai-confirm-btn--primary {
    border-color: var(--kb-accent, #2563eb);
    background: var(--kb-accent, #2563eb);
    color: var(--text-inverse, #ffffff);
    font-weight: 500;
}

.ai-confirm-btn--primary:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: var(--kb-accent-strong, var(--kb-accent, #2563eb));
}

/* 删除确认：确认键是红的，用户一眼分得出这不是普通的「写文件」 */
.ai-confirm-btn--danger {
    border-color: #dc2626;
    background: #dc2626;
    color: #ffffff;
    font-weight: 500;
}

.ai-confirm-btn--danger:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: #b91c1c;
}

.ai-confirm-overlay--danger .ai-confirm-icon {
    color: #dc2626;
}

/* 删除确认里的路径清单：一条一行、等宽、限高滚动；超过 8 条折在 details 里 */
.ai-confirm-list {
    margin: 10px 0 0;
    padding: 8px 12px;
    max-height: 200px;
    overflow: auto;
    overscroll-behavior: contain;
    border-radius: 6px;
    background: var(--bg-secondary, #f6f8fa);
    font-size: 12px;
    line-height: 1.6;
}

.ai-confirm-list-count {
    margin-bottom: 4px;
    color: var(--text-secondary, #6b7280);
}

.ai-confirm-list ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

.ai-confirm-list li {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ai-confirm-list-more summary {
    cursor: pointer;
    color: var(--text-secondary, #6b7280);
}

[data-theme="dark"] .ai-confirm-card,
html.dark .ai-confirm-card {
    background: var(--bg-secondary, #1f2937);
    box-shadow: 0 -6px 28px rgba(0, 0, 0, 0.42), 0 2px 8px rgba(0, 0, 0, 0.24);
}

/* 图片预览区（输入框上方） */
.ai-image-preview {
    position: relative;
    display: inline-block;
    margin-bottom: 10px;
    padding: 6px 6px 0 0;
    /* 不设 overflow:hidden，让删除按钮可以超出 */
}

.ai-image-preview-list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
}

.ai-image-preview-item {
    position: relative;
    width: 64px;
    height: 64px;
    border-radius: 8px;
    overflow: visible;
}

.ai-image-preview-item img {
    width: 64px;
    height: 64px;
    display: block;
    object-fit: cover;
    border-radius: 8px;
    border: 1px solid #e5e7eb;
    background: #f3f4f6;
    cursor: zoom-in;
}

[data-theme="dark"] .ai-image-preview {
    /* 无需额外样式 */
}

.ai-image-preview img {
    max-width: 120px;
    max-height: 120px;
    display: block;
    object-fit: cover;
    border-radius: 8px;
    border: 1px solid #e5e7eb;
    background: #f3f4f6;
}

[data-theme="dark"] .ai-image-preview img {
    border-color: #374151;
    background: #1f2937;
}

.ai-image-remove {
    position: absolute;
    top: 0;
    right: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px !important;
    min-height: 20px !important;
    cursor: pointer;
    font-size: 16px;
    color: #ef4444;
    background: rgba(0, 0, 0, 0.22);
    border-radius: 50%;
    line-height: 1;
    z-index: 1;
    transition: color 0.15s, background-color 0.15s;
    box-shadow: none;
    border: none;
    padding: 0;
    backdrop-filter: blur(3px);
}

.ai-image-remove:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #dc2626;
    background: rgba(255, 255, 255, 0.9);
}

[data-theme="dark"] .ai-image-remove {
    background: rgba(17, 24, 39, 0.72);
    color: #f87171;
}

/* 上传按钮 - 与 textarea 首行文本顶部对齐 */
.ai-upload-btn,
.ai-web-search-btn,
.ai-think-mode-btn,
.ai-send-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    min-height: 32px !important;
    max-height: 32px;
    margin-top: 0;
    cursor: pointer;
    color: #9ca3af;
    background: transparent;
    border: none;
    border-radius: 8px;
    transition: all 0.2s;
    flex-shrink: 0;
    padding: 0;
    line-height: 1;
}

/*
 * 对话模型所属提供方不支持的能力，按钮整个藏起来（不是禁用）：上面这条 display:flex
 * 会压过 UA 的 [hidden]，所以用类 + !important；与 mobile.css 的 .mobile-only 无交集。
 */
.ai-upload-btn.is-capability-hidden,
.ai-web-search-btn.is-capability-hidden,
.ai-think-mode-btn.is-capability-hidden {
    display: none !important;
}

.ai-web-search-btn:hover:not(:where(html[data-kb-pointer="touch"] *)),
.ai-think-mode-btn:hover:not(:where(html[data-kb-pointer="touch"] *)),
.ai-upload-btn:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #3b82f6;
    background-color: rgba(59, 130, 246, 0.1);
}

.ai-web-search-btn.active {
    color: #2563eb;
    background-color: rgba(37, 99, 235, 0.14);
}

/* 思考模式用琥珀色，与联网搜索的蓝色区分开 */
.ai-think-mode-btn.active,
.ai-think-mode-btn.active:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #b45309;
    background-color: rgba(245, 158, 11, 0.14);
}

[data-theme="dark"] .ai-think-mode-btn.active,
[data-theme="dark"] .ai-think-mode-btn.active:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #fcd34d;
    background-color: rgba(245, 158, 11, 0.18);
}

.ai-web-search-btn i,
.ai-think-mode-btn i,
.ai-upload-btn i,
.ai-send-btn i {
    font-size: 20px;
}

/* 用户消息中的图片缩略图 */
.ai-msg-image-thumb {
    margin-bottom: 8px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* 文档附件 chip：输入区待发送态与用户气泡里的已发送态共用一套骨架 */
.ai-msg-attachments {
    margin-bottom: 8px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.ai-file-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 240px;
    padding: 6px 10px;
    border-radius: 8px;
    border: 1px solid var(--kb-paper-line);
    background: var(--kb-paper-soft);
    color: var(--kb-ink);
    font-size: 0.8125rem;
    line-height: 1.3;
    text-decoration: none;
}

.ai-file-chip--sent:hover {
    background: color-mix(in srgb, var(--kb-accent) 12%, var(--kb-paper-soft));
    text-decoration: none;
}

.ai-file-chip-icon {
    flex-shrink: 0;
    font-size: 1.125rem;
    color: var(--kb-accent);
}

.ai-file-chip-name {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ai-file-chip-size {
    flex-shrink: 0;
    color: var(--kb-ink-muted);
    font-size: 0.75rem;
}

/* 待发送态：与 64px 的图片缩略图并排，chip 自适应宽度、高度对齐 */
.ai-image-preview-item.ai-file-chip {
    width: auto;
    height: 64px;
    padding-right: 14px;
}

.ai-msg-image-thumb img {
    width: 68px;
    height: 68px;
    max-width: 68px;
    max-height: 68px;
    border-radius: 8px;
    object-fit: cover;
    cursor: pointer;
    transition: opacity 0.2s;
}

.ai-msg-image-thumb img:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    opacity: 0.85;
}

/*
 * 前三列是 auto 而不是 32px：工具键都是 32px 宽、auto 量出来一样；差别在按提供方能力藏掉某颗键之后，
 * 空出来的那一列会收成 0（32px 会留一个 32px 的洞），权限模式键（带文字、自动放置）就能紧挨着最后一颗工具键。
 */
.ai-input-container {
    display: grid;
    grid-template-columns: auto auto auto 1fr 32px;
    grid-template-rows: minmax(48px, auto) 32px;
    gap: 4px 4px;
    align-items: center;
    background: #f9fafb;
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    padding: 10px 12px 8px;
    transition: border-color 0.2s;
}

[data-theme="dark"] .ai-input-container {
    background: #111827;
    border-color: #374151;
}

.ai-input-container:focus-within {
    border-color: #3b82f6;
}

/*
 * 输入框是 contenteditable（不是 textarea），因为 @ 提及要渲染成整体 chip。
 * 随之而来的三个差异：高度靠 min/max-height 自然撑开、placeholder 靠 :empty::before
 * 模拟、禁用态靠 .is-disabled 类而不是 :disabled。改回 textarea 会让 chip 失效。
 */
#aiSearchInput {
    grid-column: 1 / -1;
    grid-row: 1;
    border: none;
    background: transparent;
    padding: 4px 0 2px;
    max-height: 180px;
    min-height: 48px;
    overflow-y: auto;
    line-height: 1.6;
    font-size: 0.9375rem;
    outline: none;
    color: inherit;
    white-space: pre-wrap;
    word-break: break-word;
}

/* :empty 只在真的一个节点都没有时命中，所以清空必须走 innerHTML = '' */
#aiSearchInput:empty::before {
    content: attr(data-placeholder);
    color: var(--kb-text-muted, #9ca3af);
    pointer-events: none;
}

#aiSearchInput.is-disabled {
    cursor: not-allowed;
    opacity: 0.5;
}

/*
 * 工具键只定行、不定列：按 DOM 顺序自动排进第二行的前三列。
 * 早先各自写死 grid-column 1 / 2 / 3，按提供方能力藏掉联网键（.is-capability-hidden）
 * 之后它那一列空着，附件键不会往左靠——「图标位置没有自适应」就是这个。
 * display:none 的元素不参与自动放置，剩下的键自然向左挤。
 */
#aiThinkModeBtn,
#aiWebSearchBtn,
#aiUploadBtn {
    grid-row: 2;
}

/*
 * 权限模式键（手动 / 自动 / 计划）：只有项目会话才画（[hidden] 由 ai-search.js 按会话切），
 * 与上面三颗一样只定行、按 DOM 顺序自动放置——排在最后一颗工具键的下一格，中间没有空列；
 * 落进 1fr 那列时贴左。图标 + 两个字，宽度按内容。点开的是 .ai-permission-menu 悬浮菜单。
 */
.ai-permission-mode-btn {
    grid-row: 2;
    justify-self: start;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 32px;
    min-height: 32px !important;
    max-height: 32px;
    padding: 0 10px 0 8px;
    border: 1px solid transparent;
    border-radius: 8px;
    background: transparent;
    color: #9ca3af;
    font-size: 12px;
    line-height: 1;
    cursor: pointer;
    transition: all 0.2s;
}

.ai-permission-mode-btn[hidden] {
    display: none;
}

.ai-permission-mode-btn i {
    font-size: 18px;
}

.ai-permission-mode-btn:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #3b82f6;
    background-color: rgba(59, 130, 246, 0.1);
}

/* 自动模式用与思考模式同一路琥珀色（「这条会话不会再逐次问你」值得一眼看出来）；计划模式用蓝 */
.ai-permission-mode-btn[data-mode="auto"],
.ai-permission-mode-btn[data-mode="auto"]:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #b45309;
    background-color: rgba(245, 158, 11, 0.14);
}

.ai-permission-mode-btn[data-mode="plan"],
.ai-permission-mode-btn[data-mode="plan"]:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #2563eb;
    background-color: rgba(37, 99, 235, 0.14);
}

[data-theme="dark"] .ai-permission-mode-btn[data-mode="auto"],
[data-theme="dark"] .ai-permission-mode-btn[data-mode="auto"]:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #fcd34d;
    background-color: rgba(245, 158, 11, 0.18);
}

[data-theme="dark"] .ai-permission-mode-btn[data-mode="plan"],
[data-theme="dark"] .ai-permission-mode-btn[data-mode="plan"]:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #93c5fd;
    background-color: rgba(59, 130, 246, 0.18);
}

#aiSearchInput:focus {
    box-shadow: none;
}

.ai-input-container:has(#aiSearchInput.is-disabled) {
    opacity: 0.6;
    background: var(--input-disabled-bg, #f3f4f6);
    cursor: not-allowed;
}

[data-theme="dark"] .ai-input-container:has(#aiSearchInput.is-disabled) {
    background: rgba(255, 255, 255, 0.04);
}

.ai-send-btn {
    grid-column: 5;
    grid-row: 2;
    margin-top: 0;
    color: #3b82f6;
    align-self: center;
    justify-self: end;
}

.ai-send-btn:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: rgba(59, 130, 246, 0.1);
}

/* 流式期间发送键变成停止键（见 AiSearchManager.setSendButtonMode）。主题下的配色在 reading-theme.css */
.ai-send-btn:disabled {
    cursor: default;
}

/* Streaming cursor animation */
.ai-streaming .ai-message-content::after {
    content: '▍';
    display: inline;
    animation: blink 0.8s infinite;
    color: #3b82f6;
    font-weight: bold;
}

@keyframes blink {
    0%, 100% { opacity: 1; }
    50% { opacity: 0; }
}

/* References section */
.ai-references {
    font-size: 0.8125rem;
    margin-top: 10px;
    padding-top: 8px;
    padding-bottom: 0;
}

.ai-references--collapsed {
    padding-top: 8px;
    padding-bottom: 0;
    margin-bottom: 0;
}

.ai-references-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 2px 0;
    margin: 0;
    min-height: 0;
    line-height: 1.25;
    font-size: 0.75rem;
    font-weight: 400;
    border: none;
    background: transparent;
    cursor: pointer;
    color: #6b7280;
    text-align: left;
    transition: color 0.2s;
}

.ai-references-toggle:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #111827;
}

[data-theme="dark"] .ai-references-toggle {
    color: #9ca3af;
}

[data-theme="dark"] .ai-references-toggle:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #f3f4f6;
}

.ai-references-toggle-label {
    display: inline-flex;
    align-items: center;
}

.ai-references-chevron {
    font-size: 0.875rem;
    line-height: 1;
    transition: transform 0.2s ease;
    flex-shrink: 0;
}

.ai-references-toggle-label i {
    font-size: 0.875rem;
    line-height: 1;
}

.ai-references:not(.ai-references--collapsed) .ai-references-chevron {
    transform: rotate(180deg);
}

.ai-references--collapsed .ai-references-body {
    display: none;
}

.ai-references-body {
    margin-top: 6px;
}

.ai-references:not(.ai-references--collapsed) {
    padding-bottom: 2px;
}

.ai-ref-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
}

.ai-ref-title {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    transition: color 0.2s;
    min-height: 1rem;;
}

.ai-ref-attachment {
    transition: color 0.2s;
    min-height: 1rem !important;
}

.ai-reasoning-panel {
    margin-bottom: 8px;
    padding: 8px 10px;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.6);
    color: #6b7280;
    font-size: 0.78rem;
}

[data-theme="dark"] .ai-reasoning-panel {
    border-color: #4b5563;
    background: rgba(17, 24, 39, 0.55);
    color: #cbd5e1;
}

.ai-reasoning-toggle {
    width: 100%;
    padding: 0;
    border: none;
    background: transparent;
    color: inherit;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 6px;
    cursor: pointer;
    font-weight: 600;
    text-align: left;
}

.ai-reasoning-chevron {
    transition: transform 0.2s ease;
}

.ai-reasoning--collapsed .ai-reasoning-chevron {
    transform: rotate(-90deg);
}

.ai-reasoning--collapsed .ai-reasoning-body {
    display: none;
}

.ai-reasoning-body {
    margin-top: 3px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    max-height: 190px;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-right: 2px;
}

.ai-reasoning-phase {
    color: #2563eb;
}

[data-theme="dark"] .ai-reasoning-phase {
    color: #93c5fd;
}

.ai-reasoning-search {
    display: flex;
    align-items: center;
    gap: 6px;
    color: #2563eb;
    flex-wrap: wrap;
}

.ai-reasoning-query {
    opacity: 0.8;
}

/* Agentic 多轮检索轨迹 */
.ai-reasoning-retrieval {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 4px;
}

.ai-reasoning-retrieval-item {
    display: flex;
    align-items: baseline;
    gap: 6px;
    flex-wrap: wrap;
}

.ai-reasoning-retrieval-round {
    flex-shrink: 0;
    font-weight: 600;
    opacity: 0.75;
}

.ai-reasoning-retrieval-query {
    word-break: break-word;
}

.ai-reasoning-retrieval-hits,
.ai-reasoning-retrieval-decision {
    flex-shrink: 0;
    opacity: 0.7;
}

.ai-reasoning-retrieval-decision::before {
    content: '→ ';
}

.ai-reasoning-text {
    line-height: 1.5;
    max-height: none;
    overflow: visible;
    word-break: break-word;
}

.ai-citations {
    margin-top: 10px;
    padding-top: 8px;
    font-size: 0.8125rem;
}

.ai-citations-title {
    color: #6b7280;
    margin-bottom: 6px;
}

.ai-citations-body {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.ai-citation-link {
    max-width: 100%;
    padding: 3px 8px;
    border-radius: 6px;
    background: rgba(59, 130, 246, 0.08);
    color: #2563eb;
    font-size: 0.75rem;
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ai-citation-link:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: rgba(59, 130, 246, 0.16);
}

/* Session Bar */
.ai-session-bar {
    padding: 8px 16px;
    border-bottom: 1px solid var(--border-light, #f1f1f1);
    background: var(--bg-primary, #ffffff);
    flex-shrink: 0;
}

[data-theme="dark"] .ai-session-bar {
    background: #1f2937;
    border-color: #374151;
}

.ai-session-bar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.ai-new-chat-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    width: 100%;
    min-height: 36px !important;
    padding: 6px 8px;
    font-size: 0.875rem;
    font-weight: 500;
    color: #3b82f6;
    background: rgba(59, 130, 246, 0.08);
    border: 1px solid rgba(59, 130, 246, 0.2);
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.2s;
    white-space: nowrap;
}

@media (any-hover: hover) {

.ai-new-chat-btn:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: rgba(59, 130, 246, 0.15);
    border-color: rgba(59, 130, 246, 0.4);
}
}

.ai-history-toggle {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 5px 10px;
    font-size: 0.75rem;
    color: #6b7280;
    cursor: pointer;
    border-radius: 6px;
    transition: all 0.2s;
}

.ai-history-toggle:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #374151;
    background: rgba(0,0,0,0.04);
}

[data-theme="dark"] .ai-history-toggle:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #d1d5db;
    background: rgba(255,255,255,0.06);
}

.ai-history-toggle i.rotated {
    transform: rotate(180deg);
}

.ai-session-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 8px;
    max-height: none;
    transition: none;
    /* 纵向 flex：空态 / 出错 / 加载中的那一块能 flex:1 撑满剩余高度并把内容居中；
       会话行与项目行都是块级、拉伸到整行，与原来的块级布局无差别 */
    display: flex;
    flex-direction: column;
}

.ai-session-list.expanded {
    max-height: none;
    overflow-y: auto;
    margin-top: 0;
}

.ai-session-item {
    /* 按钮组在有鼠标的设备上是绝对定位浮层，定位基准就是这里 */
    position: relative;
    display: flex;
    align-items: center;
    padding: 6px 8px;
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s;
    gap: 8px;
    margin-top: 4px;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
}

/* 悬浮态只给真正有鼠标的设备：触摸端首次点击若触发 hover 重绘，
   WebKit 会吞掉这次 click，表现为必须点两次才切换会话 */
@media (hover: hover) and (pointer: fine) {
    @media (any-hover: hover) {
    .ai-session-item:hover:not(:where(html[data-kb-pointer="touch"] *)) {
        background: rgba(0,0,0,0.04);
    }
    }

    @media (any-hover: hover) {

    [data-theme="dark"] .ai-session-item:hover:not(:where(html[data-kb-pointer="touch"] *)) {
        background: rgba(255,255,255,0.06);
    }
    }
}

@media (hover: none), (pointer: coarse) {
}

.ai-session-item.active {
    background: rgba(59, 130, 246, 0.08);
}

.ai-session-item-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.ai-session-item-title {
    font-size: 0.875rem;
    font-weight: 500;
    color: #374151;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

[data-theme="dark"] .ai-session-item-title {
    color: #e5e7eb;
}

/*
 * 后台任务标记（见 AiTaskTracker）：绿点带波纹 = 正在跑，灰点 = 跑完了还没看。
 * 它是 .ai-session-item 这一行的第一个 flex 项，不在标题里：标题是 overflow:hidden 的
 * 省略号单行，波纹放进去向左扩散那一半会被裁掉。行本身没有 overflow 限制，波纹能完整画出来。
 * 行的 gap 是 8px，这里不再加 margin。
 */
.ai-session-dot {
    position: relative;
    display: block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

.ai-session-dot--done {
    background: var(--kb-ink-muted, #9ca3af);
}

.ai-session-dot--running {
    background: #22c55e;
    box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.4);
}

/* 停在确认框上等用户：琥珀色、不带波纹——它不是在跑，是在等你 */
.ai-session-dot--awaiting {
    background: #f59e0b;
    box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.25);
}

.ai-session-dot--running::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: rgba(34, 197, 94, 0.55);
    animation: ai-dot-ripple 1.6s ease-out infinite;
}

@keyframes ai-dot-ripple {
    0% { transform: scale(1); opacity: 0.7; }
    100% { transform: scale(2.6); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .ai-session-dot--running::before {
        animation: none;
        display: none;
    }
}

.ai-session-item-date {
    font-size: 0.725rem;
    color: #9ca3af;
}

/*
 * 重命名/删除按钮组。
 *
 * 触摸设备上没有悬浮态、按钮常驻，只能老实占文档流的位置；有鼠标时则改成绝对定位的
 * 浮层——留在流里会永久吃掉约 60px 标题宽度，侧栏里几乎每条会话都被提前打上省略号，
 * 而这块位置一年里 99% 的时间是空的。悬浮时盖住标题尾巴是可接受的代价。
 */
.ai-session-actions {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: 2px;
}

.ai-session-action {
    min-width: 20px !important;
    min-height: 20px !important;
    flex-shrink: 0;
    padding: 4px;
    font-size: 0.75rem;
    color: #9ca3af;
    cursor: pointer;
    border-radius: 4px;
    border: none;
    background: transparent;
    transition: all 0.15s;
}

@media (hover: hover) and (pointer: fine) {
    .ai-session-actions {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        padding: 0 6px;
        border-radius: 0 6px 6px 0;
        /* 必须是不透明色，且要与「悬浮态条目」的最终成色一致，否则浮层会露出一块色差 */
        background: var(--ai-session-actions-bg, #eef0f2);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.15s;
    }

    /* 左缘渐隐，标题被硬边裁断会像渲染坏了 */
    .ai-session-actions::before {
        content: '';
        position: absolute;
        top: 0;
        right: 100%;
        bottom: 0;
        width: 20px;
        background: linear-gradient(to right, transparent, var(--ai-session-actions-bg, #eef0f2));
    }

    @media (any-hover: hover) {

    .ai-session-item:hover:not(:where(html[data-kb-pointer="touch"] *)) .ai-session-actions,
    .ai-project-item:hover:not(:where(html[data-kb-pointer="touch"] *)) .ai-session-actions {
        opacity: 1;
        pointer-events: auto;
    }
    }

    @media (any-hover: hover) {

    .ai-session-delete:hover:not(:where(html[data-kb-pointer="touch"] *)) {
        color: #ef4444;
        background: rgba(239, 68, 68, 0.1);
    }
    }

    @media (any-hover: hover) {

    .ai-session-rename:hover:not(:where(html[data-kb-pointer="touch"] *)) {
        color: #2563eb;
        background: rgba(37, 99, 235, 0.1);
    }
    }
}

/* 条目底色 = 侧栏底色叠悬浮/选中蒙层后的成色，浮层照抄一份 */
.ai-session-item.active {
    --ai-session-actions-bg: #e9f0fc;
}

[data-theme="dark"] .ai-session-item,
[data-theme="dark"] .ai-project-item {
    --ai-session-actions-bg: #1f2634;
}

[data-theme="dark"] .ai-session-item.active {
    --ai-session-actions-bg: #142038;
}

.ai-load-more-sessions {
    margin: 8px 12px 12px;
    padding: 8px;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    background: #fff;
    color: #6b7280;
    cursor: pointer;
    font-size: 0.75rem;
}

@media (any-hover: hover) {

.ai-load-more-sessions:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #2563eb;
    border-color: #bfdbfe;
}
}

.ai-rename-dialog {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.ai-rename-label {
    font-size: 0.8125rem;
    font-weight: 500;
    color: #4b5563;
}

.ai-rename-input {
    width: 100%;
    height: 40px;
    padding: 8px 10px;
    border: 1px solid #d1d5db;
    border-radius: 8px;
    background: #fff;
    color: #111827;
    font-size: 0.875rem;
    outline: none;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.ai-rename-input:focus {
    border-color: #3b82f6;
    box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.16);
}

[data-theme="dark"] .ai-rename-label {
    color: #d1d5db;
}

[data-theme="dark"] .ai-rename-input {
    border-color: #4b5563;
    background: #111827;
    color: #f9fafb;
}

.ai-session-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

/* 列表里顶层的「正在加载」与空态同样撑满居中（消息区里那份不受影响）；项目下会话的那一小行不撑 */
.ai-session-list > .ai-session-loading {
    flex: 1;
}

.ai-session-empty {
    /* 聊天与项目共用这一块：撑满列表剩余高度、内容垂直水平居中 */
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    text-align: center;
    padding: 12px;
    font-size: 0.75rem;
    color: #9ca3af;
}

/* 未选中会话时的聊天区占位 */
.ai-chat-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: auto;
    padding: 24px;
    text-align: center;
}

.ai-chat-empty-icon {
    font-size: 2rem;
    line-height: 1;
    margin-bottom: 4px;
    color: var(--text-muted);
    opacity: 0.5;
}

.ai-chat-empty-title {
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--text-secondary);
}

.ai-chat-empty-desc {
    max-width: 260px;
    font-size: 0.8125rem;
    line-height: 1.6;
    color: var(--text-muted);
}

/* Attachment links in AI response content */
.ai-message-content .ai-attachment-link {
    color: #3b82f6;
    text-decoration: none;
    cursor: pointer;
    border-bottom: 1px dashed #3b82f6;
    padding-bottom: 1px;
    transition: all 0.2s;
    white-space: nowrap;
}
.ai-message-content .ai-attachment-link:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #2563eb;
    border-bottom-style: solid;
}
.ai-message-content .ai-attachment-link i {
    margin-right: 2px;
    font-size: 0.85em;
}
[data-theme="dark"] .ai-message-content .ai-attachment-link,
.dark .ai-message-content .ai-attachment-link {
    color: #60a5fa;
    border-bottom-color: #60a5fa;
}
[data-theme="dark"] .ai-message-content .ai-attachment-link:hover:not(:where(html[data-kb-pointer="touch"] *)),
.dark .ai-message-content .ai-attachment-link:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #93bbfd;
}

/* 消息内容中的所有链接统一样式（含 marked.js 自动生成的 <a> 和自定义 .ai-auto-link） */
.ai-message-content a:not(.ai-ref-title):not(.ai-ref-attachment):not(.ai-attachment-link) {
    color: #3b82f6;
    text-decoration: none;
    word-break: break-all;
    border-bottom: 1px dashed rgba(59, 130, 246, 0.4);
    transition: all 0.2s ease;
}
.ai-message-content a:not(.ai-ref-title):not(.ai-ref-attachment):not(.ai-attachment-link):hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #2563eb;
    border-bottom-color: #2563eb;
    border-bottom-style: solid;
}
/* 用户消息中的链接 */
.message-user .ai-message-content a {
    color: #fff !important;
    border-bottom-color: rgba(255, 255, 255, 0.5) !important;
}
.message-user .ai-message-content a:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #fff !important;
    border-bottom-color: #fff !important;
    border-bottom-style: solid !important;
}
/*
 * 暗色下的正文链接。
 *
 * 必须同时写 [data-theme="dark"] 与 .dark：主题实际是由 theme.js 往 <html> 上写
 * data-theme 属性切换的，只写 .dark 的话这两条规则永远不会命中，暗色下链接会继续
 * 用亮色的 #3b82f6，落在深色气泡上对比度不足。（.dark 保留是为了兼容按 class
 * 切换的场景，ai-slash.css / ai-mention.css 也是这么成对写的。）
 */
[data-theme="dark"] .ai-message-content a:not(.ai-ref-title):not(.ai-ref-attachment):not(.ai-attachment-link),
.dark .ai-message-content a:not(.ai-ref-title):not(.ai-ref-attachment):not(.ai-attachment-link) {
    color: #60a5fa;
    border-bottom-color: rgba(96, 165, 250, 0.4);
}
[data-theme="dark"] .ai-message-content a:not(.ai-ref-title):not(.ai-ref-attachment):not(.ai-attachment-link):hover:not(:where(html[data-kb-pointer="touch"] *)),
.dark .ai-message-content a:not(.ai-ref-title):not(.ai-ref-attachment):not(.ai-attachment-link):hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #93bbfd;
    border-bottom-color: #93bbfd;
}

/* 正文中的知识标题链接（点击打开知识详情） */
.ai-message-content .ai-knowledge-link {
    color: #3b82f6;
    text-decoration: none;
    cursor: pointer;
    border-bottom: 1px dashed #3b82f6;
    padding-bottom: 1px;
    transition: all 0.2s;
}
.ai-message-content .ai-knowledge-link:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #2563eb;
    border-bottom-style: solid;
}
[data-theme="dark"] .ai-message-content .ai-knowledge-link,
.dark .ai-message-content .ai-knowledge-link {
    color: #60a5fa;
    border-bottom-color: #60a5fa;
}
[data-theme="dark"] .ai-message-content .ai-knowledge-link:hover:not(:where(html[data-kb-pointer="touch"] *)),
.dark .ai-message-content .ai-knowledge-link:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    color: #93bbfd;
    border-bottom-color: #93bbfd;
}

/* KaTeX 数学公式样式 */
.ai-message-content .katex {
    font-size: 1em;
}
.ai-message-content .katex-display {
    margin: 0.75em 0;
    overflow-x: auto;
    overflow-y: hidden;
    padding: 0.25em 0;
}
.ai-message-content .katex-display > .katex {
    white-space: normal;
}
/* 公式渲染失败时的降级样式 */
.ai-message-content .math-fallback {
    font-family: 'KaTeX_Math', 'Times New Roman', serif;
    font-style: italic;
    background: rgba(0, 0, 0, 0.04);
    padding: 1px 4px;
    border-radius: 3px;
    font-size: 0.95em;
}
[data-theme="dark"] .ai-message-content .math-fallback,
.dark .ai-message-content .math-fallback {
    background: rgba(255, 255, 255, 0.08);
}

/* 表格中的数学符号优化 */
.ai-message-content table .katex {
    font-size: 0.95em;
}

/* Mobile Adjustments */
@media (max-width: 1023px) {
    .ai-drawer {
        --ai-drawer-width: 100%;
    }
    /* 悬浮球的窄屏位置见 css/ai-float-trigger.css 的 .ai-trigger-dock */

    /* 手机端彻底修复内容超出问题 */
    .ai-message-item {
        max-width: 95% !important;
    }

    /* 窄屏兜底，与上面按指针能力写的常驻规则同值：个别安卓 WebView 把
       `hover` 特性报错成 hover，只靠特性查询会漏掉真机。改数值要改两处 */
    .ai-message-actions {
        min-height: 26px;
        margin: 6px 4px -2px 0;
        opacity: 1;
        pointer-events: auto;
        transform: none;
    }

    .ai-message-copy-btn,
    .ai-message-save-kb-btn {
        background: rgba(37, 99, 235, 0.1);
        color: #2563eb;
    }

    [data-theme="dark"] .ai-message-copy-btn,
    [data-theme="dark"] .ai-message-save-kb-btn {
        background: rgba(147, 197, 253, 0.14);
        color: #93c5fd;
    }

    .message-bubble {
        max-width: 100% !important;
        word-wrap: break-word !important;
        overflow-wrap: break-word !important;
        word-break: break-word !important;
    }

    .ai-message-content {
        max-width: 100% !important;
        overflow-x: hidden !important;
        word-wrap: break-word !important;
        overflow-wrap: break-word !important;
    }

    .ai-message-content pre {
        overflow-x: auto !important;
        overflow-y: hidden !important;
        max-width: 100% !important;
        white-space: pre !important;
        word-wrap: normal !important;
        overflow-wrap: normal !important;
    }

    .ai-message-content code {
        word-wrap: break-word !important;
        overflow-wrap: break-word !important;
        word-break: break-all !important;
    }

    .ai-message-content p,
    .ai-message-content li {
        word-wrap: break-word !important;
        overflow-wrap: break-word !important;
        word-break: break-word !important;
    }

    /* 手机端参考来源紧凑间距 */
    .ai-references {
        margin-top: 8px;
        padding-top: 4px;
    }

    .ai-references-toggle {
        padding: 1px 0;
    }

    .ai-ref-item {
        margin-bottom: 2px !important;
        padding: 2px 0 !important;
        font-size: 0.75rem;
        line-height: 1.4 !important;
    }

    .ai-ref-item:last-child {
        margin-bottom: 0;
    }

    .ai-ref-title {
        padding: 1px 0 !important;
    }

    .ai-ref-attachment {
        padding: 1px 0 !important;
        min-height: 1rem !important;
    }

    /* 手机端禁用侧边栏 */
    body.ai-drawer-open #sidebar {
        display: none !important;
    }

    body.ai-drawer-open .main-container {
        margin-left: 0 !important;
    }
}

/* 手机端：会话列表改为覆盖式抽屉。断点取 720px 而非 767px，
   iPad mini 6/7 竖屏视口是 744px，落在 767 以下会被误判成手机 */
@media (max-width: 720px) {
    .ai-session-overlay {
        position: fixed;
        inset: 0;
        z-index: 2003;
        display: block;
        background: var(--kb-scrim-bg);
        backdrop-filter: blur(var(--kb-scrim-blur));
        -webkit-backdrop-filter: blur(var(--kb-scrim-blur));
        opacity: 1;
        visibility: visible;
        transition: opacity 0.3s ease, visibility 0.3s ease;
    }

    .ai-drawer.ai-sidebar-collapsed .ai-session-overlay {
        opacity: 0;
        visibility: hidden;
        pointer-events: none;
    }

    .ai-session-sidebar {
        position: fixed;
        z-index: 2004;
        top: 0;
        left: 0;
        bottom: 0;
        /* 覆盖式抽屉不吃桌面端拖出来的宽度，!important 压过元素上的行内变量所参与的那条规则 */
        width: min(76vw, 320px) !important;
        height: 100dvh;
        border-right: 1px solid rgba(229, 231, 235, 0.9);
        box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
        transform: translateX(0);
        transition: transform 0.3s ease;
    }

    .ai-drawer.ai-sidebar-collapsed .ai-session-sidebar {
        transform: translateX(-105%);
    }
}

/* ============================================
   图片灯箱预览
   ============================================ */
.ai-lightbox-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.85);
    z-index: 99999;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.2s ease;
    cursor: zoom-out;
    /* 放大后图片会溢出可视区，裁掉避免出现滚动条 */
    overflow: hidden;
    /* 自行处理捏合与平移手势，交给浏览器会变成页面缩放 */
    touch-action: none;
}

.ai-lightbox-overlay.ai-lightbox-visible {
    opacity: 1;
}

.ai-lightbox-overlay.ai-lightbox-fadeout {
    opacity: 0;
}

.ai-lightbox-close {
    position: absolute;
    top: 16px;
    right: 24px;
    color: white;
    font-size: 28px;
    cursor: pointer;
    opacity: 0.7;
    transition: opacity 0.2s;
    z-index: 1;
}

.ai-lightbox-close:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    opacity: 1;
}

.ai-lightbox-body {
    max-width: 90vw;
    max-height: 90vh;
    display: flex;
    align-items: center;
    justify-content: center;
}

.ai-lightbox-body img {
    max-width: 90vw;
    max-height: 90vh;
    object-fit: contain;
    border-radius: 6px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
    cursor: zoom-in;
    transform-origin: center center;
    will-change: transform;
    /* 图片自身不接管手势，滚轮与捏合统一由遮罩层处理 */
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;
    -webkit-user-drag: none;
}

/* 放大后：可拖拽平移 */
.ai-lightbox-overlay.ai-lightbox-zoomed .ai-lightbox-body img {
    cursor: grab;
}

.ai-lightbox-overlay.ai-lightbox-zoomed .ai-lightbox-body img:active {
    cursor: grabbing;
}

/* ==========================================
   数据查询面板（Text-to-SQL 的图表 / 结果表）
   与 .ai-message-content 同级，位于正文之前——
   问「曲线图」时图本身就是答案，不该被文字压在下面。
   ========================================== */

.ai-data-panel {
    margin-bottom: 10px;
}

.ai-chart {
    position: relative;
    width: 100%;
    min-height: 220px;
    margin-bottom: 10px;
    border: 1px solid #e5e7eb;
    border-radius: 8px;
    background: rgba(0, 0, 0, 0.015);
    overflow: hidden;
}

[data-theme="dark"] .ai-chart {
    border-color: #4b5563;
    background: rgba(255, 255, 255, 0.02);
}

/* 横向滚动只发生在这一层：类目多时画布比视口宽，
   滚动条留在图表自己身上，不会让整个气泡或聊天区跟着横滚 */
.ai-chart-scroll {
    width: 100%;
    height: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
}

.ai-chart-canvas {
    height: 100%;
}

.ai-chart-scroll::-webkit-scrollbar {
    height: 8px;
}

.ai-chart-scroll::-webkit-scrollbar-track {
    background: transparent;
}

.ai-chart-scroll::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, 0.18);
    border-radius: 4px;
}

.ai-chart-scroll::-webkit-scrollbar-thumb:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: rgba(0, 0, 0, 0.3);
}

[data-theme="dark"] .ai-chart-scroll::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.22);
}

[data-theme="dark"] .ai-chart-scroll::-webkit-scrollbar-thumb:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: rgba(255, 255, 255, 0.35);
}

/* 可横滚时给个提示：右侧渐隐，暗示内容还没到头 */
.ai-chart-scrollable::after {
    content: '';
    position: absolute;
    top: 1px;
    right: 0;
    bottom: 9px;
    width: 24px;
    pointer-events: none;
    background: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.85));
}

[data-theme="dark"] .ai-chart-scrollable::after {
    background: linear-gradient(to right, rgba(17, 24, 39, 0), rgba(17, 24, 39, 0.85));
}

.ai-chart-actions {
    position: absolute;
    top: 6px;
    right: 6px;
    z-index: 2;
    display: flex;
    gap: 4px;
    opacity: 0;
    transition: opacity 0.15s ease;
}

.ai-chart:hover:not(:where(html[data-kb-pointer="touch"] *)) .ai-chart-actions,
.ai-chart-actions:focus-within {
    opacity: 1;
}

/* 触屏没有 hover，按钮必须常驻，否则等于没有入口 */
@media (hover: none) {
    .ai-chart-actions {
        opacity: 1;
    }
}

.ai-chart-fullscreen-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    min-height: 28px !important;
    padding: 0;
    border: 1px solid var(--kb-paper-line, #e5e7eb);
    border-radius: 6px;
    background: var(--kb-paper-panel, #ffffff);
    color: var(--kb-ink-soft, #6b7280);
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.ai-chart-fullscreen-btn:hover:not(:where(html[data-kb-pointer="touch"] *)),
.ai-chart-fullscreen-btn:focus-visible {
    color: var(--kb-ink, #111827);
    border-color: var(--kb-ink-soft, #6b7280);
}

.ai-chart-fullscreen-btn i {
    font-size: 15px;
    line-height: 1;
}

.ai-chart.ai-chart-error {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 0;
    padding: 12px;
    font-size: 0.8125rem;
    color: #92400e;
    background: rgba(251, 191, 36, 0.12);
    border-color: rgba(251, 191, 36, 0.4);
}

[data-theme="dark"] .ai-chart.ai-chart-error {
    color: #fcd34d;
}

/* ==========================================
   图表全屏预览
   缩放走 echarts 原生 dataZoom（数据级），不是 CSS transform，
   所以这里只负责布局，不做任何 scale。
   ========================================== */

body.ai-chart-fullscreen-open {
    overflow: hidden;
}

.ai-chart-fullscreen {
    /* 顶栏要为 macOS 交通灯让出的高度。默认 0，桌面端由 desktop.css 按平台与窗口全屏
       状态统一改写（流程图全屏预览用的是同一个变量）。舞台是 flex:1、canvas 撑满，
       顶栏变高后剩余高度自动收窄，不像流程图那边还要另算一个 max-height */
    --kb-fullscreen-titlebar: 0px;
    position: fixed;
    inset: 0;
    z-index: 10050;
    display: flex;
    flex-direction: column;
    background: var(--kb-paper-panel, #ffffff);
    color: var(--kb-ink, #111827);
}

.ai-chart-fullscreen-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    /* 全局 box-sizing 是 border-box，让位高度必须同时加进 min-height，
       只加 padding 的话顶栏总高不变、内容被往下挤出去 */
    min-height: calc(60px + var(--kb-fullscreen-titlebar));
    padding: calc(0.75rem + var(--kb-fullscreen-titlebar)) 1.25rem 0.75rem;
    border-bottom: 1px solid var(--kb-paper-line, #e5e7eb);
    flex: 0 0 auto;
}

.ai-chart-fullscreen-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ai-chart-fullscreen-header-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 0 0 auto;
}

.ai-chart-zoom-controls {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--kb-paper-line, #e5e7eb);
    border-radius: 8px;
}

.ai-chart-zoom-btn,
.ai-chart-fullscreen-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--kb-ink-soft, #6b7280);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.ai-chart-zoom-btn:hover:not(:where(html[data-kb-pointer="touch"] *)):not(:disabled),
.ai-chart-fullscreen-close:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: rgba(0, 0, 0, 0.06);
    color: var(--kb-ink, #111827);
}

[data-theme="dark"] .ai-chart-zoom-btn:hover:not(:where(html[data-kb-pointer="touch"] *)):not(:disabled),
[data-theme="dark"] .ai-chart-fullscreen-close:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: rgba(255, 255, 255, 0.1);
}

.ai-chart-zoom-btn:disabled {
    cursor: not-allowed;
}

/* 图表按钮只保留组件布局，禁用配色统一消费阅读主题语义变量。 */
.kb-paper-app .ai-chart-zoom-btn:disabled,
.ai-chart-zoom-btn:disabled {
    opacity: 1;
    border-color: var(--kb-control-disabled-border, rgba(107, 114, 128, 0.2)) !important;
    background: var(--kb-control-disabled-bg, #f3f4f6) !important;
    color: var(--kb-control-disabled-text, #6b7280) !important;
    box-shadow: none !important;
}

.ai-chart-zoom-btn i,
.ai-chart-fullscreen-close i {
    font-size: 17px;
    line-height: 1;
}

.ai-chart-zoom-level {
    min-width: 52px;
    height: 32px;
    padding: 0 6px;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--kb-ink-soft, #6b7280);
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
}

.ai-chart-zoom-level:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: rgba(0, 0, 0, 0.06);
    color: var(--kb-ink, #111827);
}

[data-theme="dark"] .ai-chart-zoom-level:hover:not(:where(html[data-kb-pointer="touch"] *)) {
    background: rgba(255, 255, 255, 0.1);
}

.ai-chart-fullscreen-stage {
    flex: 1 1 auto;
    min-height: 0;
    padding: 12px 16px;
}

.ai-chart-fullscreen-canvas {
    width: 100%;
    height: 100%;
}

.ai-chart-fullscreen-hint {
    flex: 0 0 auto;
    padding: 6px 16px 10px;
    text-align: center;
    font-size: 0.6875rem;
    color: var(--kb-ink-soft, #9ca3af);
}

@media (max-width: 640px) {
    .ai-chart-fullscreen-title {
        font-size: 0.875rem;
    }

    .ai-chart-fullscreen-stage {
        padding: 8px;
    }
}

.ai-result-table {
    margin-bottom: 10px;
}

/* 结果表不走 .ai-message-content 的选择器，样式要自己写一份 */
.ai-result-table table {
    border-collapse: collapse;
    font-size: 0.8125rem;
    width: max-content;
    min-width: 100%;
}

.ai-result-table td {
    border: 1px solid #e5e7eb;
    padding: 5px 10px;
    text-align: left;
    white-space: nowrap;
}

.ai-result-table .ai-result-th {
    background: rgba(0, 0, 0, 0.04);
    font-weight: 600;
}

[data-theme="dark"] .ai-result-table td {
    border-color: #4b5563;
}

[data-theme="dark"] .ai-result-table .ai-result-th {
    background: rgba(255, 255, 255, 0.05);
}

/* 0 行结果的空态。表头行的 white-space: nowrap 会让这行也不换行，居中即可 */
.ai-result-table .ai-result-empty {
    text-align: center;
    color: #9ca3af;
    font-size: 0.8125rem;
    padding: 12px 10px;
}

.ai-result-meta {
    margin-top: 4px;
    font-size: 0.6875rem;
    color: #9ca3af;
}

/*
 * 计划模式的回复底部：「开发计划」徽标 + 「执行此计划」。
 * 与产物清单一样是 .message-bubble 下 .ai-message-content 的兄弟节点（ai-search.js renderPlanActions）。
 * 只有会话最后一条上的可点；更早的计划打上 --stale，只剩徽标，按钮走全站禁用态变量。
 */
.ai-plan-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px dashed var(--kb-paper-line, #e5e7eb);
}

.ai-plan-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 12px;
    color: var(--kb-ink-soft, #6b7280);
}

.ai-plan-badge i {
    font-size: 14px;
}

/* 与确认条的主键（.ai-confirm-btn--primary）同一套：底色走主题强调色、字色走 --text-inverse——
   夜间主题的强调色是浅金，写死白字就看不清 */
.ai-plan-run-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-width: 0 !important;
    min-height: 0 !important;
    padding: 5px 12px;
    border: 1px solid var(--kb-accent, #2563eb);
    border-radius: 8px;
    background: var(--kb-accent, #2563eb);
    color: var(--text-inverse, #ffffff);
    font-size: 13px;
    line-height: 1.4;
    cursor: pointer;
    transition: background-color 0.2s;
}

.ai-plan-run-btn i {
    font-size: 15px;
}

.ai-plan-run-btn:hover:not(:disabled):not(:where(html[data-kb-pointer="touch"] *)) {
    border-color: var(--kb-accent-strong, var(--kb-accent, #2563eb));
    background: var(--kb-accent-strong, var(--kb-accent, #2563eb));
}

.ai-plan-run-btn:disabled {
    background: var(--kb-control-disabled-bg);
    border-color: var(--kb-control-disabled-border);
    color: var(--kb-control-disabled-text);
    cursor: default;
}

.ai-plan-actions--stale .ai-plan-run-btn {
    display: none;
}

/* ── 权限模式的悬浮菜单（复用 .ai-popover-menu；输入区贴底，菜单向上长） ── */
.ai-permission-menu {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 280px;
    max-width: 340px;
}

.ai-popover-title {
    padding: 4px 10px 6px;
    font-size: 0.75rem;
    color: var(--kb-ink-muted, #827a6d);
}

.ai-permission-menu-item {
    align-items: flex-start;
    padding: 8px 10px;
}

.ai-permission-menu-item > i:first-child {
    margin-top: 2px;
}

/* 特异性要压过通用的 .ai-popover-item > span（nowrap + ellipsis），否则说明文字被截成一行 */
.ai-permission-menu-item > .ai-permission-menu-text {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    overflow: visible;
    text-overflow: clip;
    white-space: normal;
}

.ai-permission-menu-text b {
    font-weight: 500;
    color: var(--kb-ink, #2f2b24);
}

.ai-permission-menu-text small {
    font-size: 0.75rem;
    line-height: 1.45;
    white-space: normal;
    color: var(--kb-ink-muted, #827a6d);
}

.ai-permission-menu-check {
    margin-top: 2px;
    color: var(--kb-accent, #2563eb) !important;
}

.ai-permission-menu-item.is-current {
    background: var(--kb-accent-soft, rgba(37, 99, 235, 0.08));
}

.ai-permission-menu-item .ai-popover-key {
    margin-top: 2px;
}
