/* ============================================================
   全站极简设计系统（白底黑字 · 灰阶层级 · 内容为王）
   ============================================================

   【色彩规则】（2026-09-11 二次更新：用户拍板「加点其他颜色」→ 科技蓝强调色 + 状态语义色）
   - 品牌强调色科技蓝 #2563eb：主按钮、正文链接、导航激活态、表单聚焦环、勾选框
   - 页面画布浅灰 #fafafa，卡片/面板纯白浮起——灰度层次做分区，彩色只做语义与强调
   - 状态语义色：计划=天蓝 / 进行中=靛蓝 / 完成=绿 / 取消=灰，见 --status-* 令牌
   - 阴影仅限灰黑 rgba(0,0,0,*)；动效克制：150-250ms，尊重 prefers-reduced-motion
   - 仍然禁止：渐变、大面积色块填充

   【字体层级】
   - 页面标题：text-2xl font-bold
   - 区块标题：text-base font-semibold
   - 正文：text-sm leading-relaxed
   - 辅助信息：text-xs

   【间距规则】
   - 页面容器：整宽由 base.html 的 main（max-w-7xl）给，两列页不再自套 max-w-* 居中壳
     （套两层会把左列挤窄）；只有刻意保持单列的表单/登录页自己限宽居中
   - 桌面端（md+）主内容流 + 辅助右列走通用列容器 .page-cols / .page-main / .page-rail
     （见下方【分端约定】同断点），移动端仍是单列
   - 阅读体（文章/报告正文）自己限宽（max-w-2xl），不跟着列宽跑
   - 区块间：py-6；组件间：space-y-4；元素间：gap-2
   - 用留白替代分隔线

   【边框原则】
   - 仅输入框、聊天浮窗面板、确认操作区保留 1px rgba(0,0,0,0.08) 边框
   - 普通信息展示无容器、无边框（.app-card/.card 已改为透明无界）
   - 需要边界的交互区域统一使用 .panel 类

   【状态映射】（唯一定义处 = 下方 --status-* 变量与四个工具类）
   - 进行中 = 最深（黑），计划 = 中灰，已完成 = 浅灰，已取消 = 最浅灰 + 删除线
   - 模板只写 `.status-bg--{{ status }}`（圆点/色条/日历块）、
     `.status-fg--{{ status }}`（图标描边）、`.badge-status--{{ status }}`（徽章）、
     `.status-fg-on--{{ status }}`（色块上的文字色），
     禁止再按状态写 bg-zinc-* / text-zinc-* 分支（曾有 4 套映射，done 与 cancelled 深浅互为颠倒）

   【分端约定】
   - 唯一分端断点：md:（768px），与导航层现状一致；640-768px 平板竖屏跟随桌面布局（预期行为）
   - 结构性显隐一律用成对块：桌面元素 `hidden md:flex` / `hidden md:block`，移动元素 `md:hidden`；
     禁止新增 sm: 结构性断点；sm:p-×、sm:text-×、sm:gap-× 等纯尺寸渐进类不属于结构，保留不动
   - 数据接口（返回 JSON 的端点）必须由原生 fetch() 消费，严禁在元素上挂 hx-* 属性
     （HTMX 仅用于返回 HTML 片段的端点；混用会导致 JSON 被当作文本插入 DOM）
   - 禁止手动调用 htmx.process()：htmx 内置 MutationObserver 会自动初始化新增节点，
     手动重复处理会造成双重绑定与旧节点引用残留（参见历史踩坑记录）
   ============================================================ */

:root {
    /* periwinkle 蓝紫强调色（2026-09-13 用户选定向医疗预约风截图，推翻 09-11 纯蓝）
       同时解禁大面积色块卡与宽松大卡节奏，圆角/胶囊全面放大 */
    --accent: #6478e8;
    --accent-hover: #5467d6;
    --accent-light: #eef0fe;    /* periwinkle 极浅底：hover/选中染色 */
    --accent-soft: #eef0fe;     /* 选中态/强调底色专用 */
    --bg: #e2e6fa;              /* 淡紫蓝画布（截图同源，比截图略浅保证内容可读） */
    --bg-card: #ffffff;
    --text: #18181b;
    --text-secondary: #52525b;
    --text-muted: #a1a1aa;
    --border: rgba(0, 0, 0, 0.08);
    --border-strong: rgba(0, 0, 0, 0.15);

    /* 阴影令牌：仅灰黑，全套唯一定义处（2026-09-11 用户解禁） */
    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04), 0 2px 6px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 14px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.05);
    --shadow-lg: 0 10px 30px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);
}

/* 状态语义色：全站唯一定义处（值名 = Activity.STATUS_CHOICES 的 key，
   日历与图表靠 `var(--status-<status>)` 引用，不再各存一份 hex）*/
:root {
    /* 状态语义色（2026-09-11 用户解禁彩色）：计划=天蓝 / 进行中=品牌蓝 / 完成=绿 / 取消=灰 */
    --status-planned: #0284c7;      /* sky-600：白字对比 4.6:1 */
    --status-in_progress: #6478e8;  /* periwinkle = 品牌色，进行中即「正在发生」 */
    --status-done: #16a34a;         /* green-600 */
    --status-cancelled: #a1a1aa;    /* 退出语义不加色相，维持灰 */
}

/* 背景用状态色：小圆点、顶部色条、日历色块 */
.status-bg--planned { background: var(--status-planned); }
.status-bg--in_progress { background: var(--status-in_progress); }
.status-bg--done { background: var(--status-done); }
.status-bg--cancelled { background: var(--status-cancelled); }

/* 线条色用状态色：Daily 卡左侧状态图标（svg 靠 currentColor）*/
.status-fg--planned { color: var(--status-planned); }
.status-fg--in_progress { color: var(--status-in_progress); }
.status-fg--done { color: var(--status-done); }
.status-fg--cancelled { color: var(--status-cancelled); }

/* 状态色块之上的文字色，与 .status-bg--* 成对使用（日历色块等）*/
.status-fg-on--planned, .status-fg-on--in_progress, .status-fg-on--done { color: #ffffff; }
.status-fg-on--cancelled { color: #71717a; }

/* 状态徽章（搭配 _status_badge.html 的通用形状类使用）*/
.badge-status--planned { background: #e0f2fe; color: #0369a1; }
.badge-status--in_progress { background: var(--status-in_progress); color: #ffffff; }
.badge-status--done { background: #dcfce7; color: #15803d; }
.badge-status--cancelled { color: var(--text-muted); text-decoration: line-through; }

/* 控件圆角：Things 3 式大而少的圆角（10px）。
   模板里带 rounded-full 的按钮也被这里压平 —— 胶囊满屏是「模板感」的主因之一；
   徽章/chip（.badge、span.rounded-full 非按钮）保持 pill 不受影响。 */
button, .btn, input[type="submit"],
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="search"], select, input[type="date"] {
    border-radius: 999px !important;   /* 全面胶囊化（截图风格 2026-09-13） */
}

/* 多行输入保持柔和大圆角，不胶囊（胶囊化会把多行框顶成怪形） */
textarea {
    border-radius: 1rem !important;
}

/* 卡片：白底浮在淡紫蓝画布上——超大圆角 + 极淡描边 + 柔和阴影（截图风） */
.app-card, .card {
    background: var(--bg-card);
    border: 1px solid rgba(100, 120, 232, 0.10);
    border-radius: 1.5rem;
    box-shadow: var(--shadow-sm);
}

/* 面板：浮层容器，阴影比卡片高一档 */
.panel {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 1.5rem;
    box-shadow: var(--shadow-md);
}

/* 主按钮（黑底白字）：微阴影 + hover 上浮，点按下收——按钮要有「物理感」 */
.btn-accent {
    background-color: var(--accent) !important;
    color: white !important;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

.btn-accent:hover {
    background-color: var(--accent-hover) !important;
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.22);
}

.btn-accent:active {
    transform: translateY(0) scale(0.97);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

/* 导航链接 */
.nav-link {
    color: var(--text-muted);
    font-size: 0.875rem;
}

.nav-link:hover {
    color: var(--text-secondary);
}

.nav-link-active {
    color: var(--accent);
    font-weight: 600;
}

/* 品牌色的轻量落点：聚焦环 + 勾选框（模板未写 focus: 类，此处是全局唯一 focus 处理） */
input:focus-visible, textarea:focus-visible, select:focus-visible {
    outline: 2px solid rgba(100, 120, 232, 0.40);
    outline-offset: 0;
}

input[type="checkbox"], input[type="radio"] {
    accent-color: var(--accent);
}

/* 徽章 pill 形（仅徽章/chip 保持全圆角，控件已收敛到 10px） */
.badge, span.rounded-full {
    border-radius: 9999px;
}

/* 输入框内边距：用 :where() 把特异性降到 0，避免压过模板里 Tailwind 的 pl-10 等内边距类（活动列表搜索框 pl-10 曾被这条规则压回 1rem，placeholder 顶进放大镜图标） */
:where(input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="search"], textarea) {
    padding-left: 1rem;
    padding-right: 1rem;
}

/* 链接悬停动效 */
a {
    transition: color 0.15s ease, opacity 0.15s ease;
}

/* ===== 微动效（2026-09-11 用户解禁）：克制、灰阶、可关闭 ===== */

/* 所有按钮：过渡 + 按下轻收（物理感的最小实现） */
button {
    transition: transform 0.12s ease, box-shadow 0.18s ease,
                background-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}
button:active {
    transform: scale(0.97);
}

/* 黑底主按钮（模板内联 bg-[var(--accent)] 写法）与 .btn-accent 同待遇：hover 上浮 */
button.bg-\[var\(--accent\)\],
a.bg-\[var\(--accent\)\],
button.btn-accent {
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
button.bg-\[var\(--accent\)\]:hover,
a.bg-\[var\(--accent\)\]:hover,
button.btn-accent:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.22);
}
button.bg-\[var\(--accent\)\]:active,
a.bg-\[var\(--accent\)\]:active {
    transform: translateY(0) scale(0.97);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

/* 卡片与列表行入场：轻微上移淡入；用户偏好减弱动效时不播 */
@media (prefers-reduced-motion: no-preference) {
    .app-card, .card, .daily-card {
        animation: fadeIn 0.25s ease-out both;
    }
}

/* 悬停时卡片阴影加深一档（仅桌面有 hover 的设备上有意义） */
@media (hover: hover) {
    .app-card:hover, .card:hover {
        box-shadow: var(--shadow-md);
    }
}

/* 淡入动画 */
@keyframes fadeIn {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

.fade-in {
    animation: fadeIn 0.3s ease-out;
}

/* ===== 原有样式保留 ===== */

/* Chat styles：**仅桌面端（md+）**的左右气泡分离。
   移动端（<768px）放弃左右分离 —— 390px 下 80% 上限只剩 260px 盒子、正文 237px，
   一条长回答要滚十几屏。全宽与角色竖条见文件末尾【聊天消息流移动端】段。
   为什么是「包一层媒体查询」而不是「在移动端写覆盖」：移动端根本不存在上限可覆盖，
   不必与本文件的声明做特异度/顺序竞争；而 margin 简写复位会连带清掉宿主 space-y
   给子元素的上外边距，块间距当场塌 —— 只有长手属性能安全复位。 */
@media (min-width: 768px) {
    .chat-message {
        max-width: 80%;
    }
    .chat-message.user {
        margin-left: auto;
    }
    .chat-message.assistant {
        margin-right: auto;
    }
}

/* Markdown content */
.markdown-content pre {
    background-color: #1f2937;
    color: #e5e7eb;
    padding: 1rem;
    border-radius: 0.75rem;
    overflow-x: auto;
}
.markdown-content code {
    background-color: var(--accent-light);
    padding: 0.125rem 0.375rem;
    border-radius: 0.375rem;
    font-size: 0.875rem;
}
.markdown-content pre code {
    background-color: transparent;
    padding: 0;
}

/* 全局搜索面板 */
.search-result-item {
    transition: background-color 0.15s ease;
}
.search-result-item:hover,
.search-result-item.bg-zinc-50 {
    background-color: var(--accent-light, #f4f4f5);
}

/* ===== 分端工具类（唯一断点 768px，见头部【分端约定】） ===== */

/* 移动端触控目标：≤767px 下保证最小 44×44px 点击区 */
@media (max-width: 767px) {
    .tap-target {
        min-width: 44px;
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}

/* 桌面端通用两列：主内容流 + 辅助右列。**全站唯一的一份列声明**，所有页面
   （活动详情、Daily、仪表盘、费用报告、知识库、备忘录……）都只挂 .page-cols，
   禁止再按页面各抄一份 grid —— 抄过一次就有 N 处会各自漂移。

   移动端（<768px）不定义任何规则 —— 列容器都是普通块级元素，
   纵向顺序完全由 DOM 决定（模板里 DOM 顺序即移动端预期顺序）。
   桌面端：左列自适应（minmax(0,1fr) 兜住长文本/宽表格不撑破列），
   右列固定 320px 且整列随滚动常驻。
   align-items:start 是 sticky 生效的前提：网格默认 stretch 会把右列拉到与左列
   等高，没有剩余空间可钉，滚动就完全不动。
   常驻的是整列而不是顶部单卡：卡片自己 sticky 时，同列的兄弟块会从它底下滚过去，
   而 .panel 没有背景色，滚到一半就会出现两块文字叠在一起。 */
@media (min-width: 768px) {
    .page-cols {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 320px;
        gap: 2rem;
        align-items: start;
    }

    /* 右列常驻；top = 导航 h-14(56px) + 16px 呼吸。
       max-height + overflow 兜住矮视口：列内容比可视区高时让列内自己滚，
       否则底部信息会被钉在屏幕外永远看不到。
       这里故意不加 overscroll-behavior: contain —— 列内滚到底后需要把滚动
       链回给页面，否则鼠标停在右列时整页就滚不动了。 */
    .page-rail {
        position: sticky;
        top: 4.5rem;
        max-height: calc(100vh - 5.5rem);
        overflow-y: auto;
        scrollbar-width: thin;
    }

    /* 需要「右列整块在 DOM 里排在主内容流之前」的页面（为了移动端阅读顺序与
       改造前逐块一致）挂这个修饰类，桌面端用 order 换回右侧。
       order 只在网格布局内参与计算，媒体查询外不定义就完全不影响移动端的块级流。 */
    .page-cols--rail-first .page-main {
        order: 1;
    }

    .page-cols--rail-first .page-rail {
        order: 2;
    }
}

/* 悬停操作区：桌面有 hover 时随 .group 悬停显示；触屏/移动端常驻可见 */
.hover-actions {
    opacity: 0;
    transition: opacity 0.15s ease;
}

@media (hover: hover) and (min-width: 768px) {
    .group:hover .hover-actions {
        opacity: 1;
    }
}

@media (hover: none), (max-width: 767px) {
    .hover-actions {
        opacity: 1;
    }
}

/* Daily 移动端 OnePage 翻页：第一页 = summary（问候/搜索/速览卡/本周消费），
   一次手势整页翻转到第二页活动流（手势接管 + 缓动过渡 + 页点指示器，JS 见 daily.html）。
   桌面端（md+）两列同屏，不分页，规则全部只落在本查询内。
   不用 CSS scroll-snap：吸附只能做到「靠近时停在页顶」，没有翻转感，
   且会在 JS 手势接管时打架 —— 翻页全部由 JS 接管，这里只管页面高度与特效。
   选择器用页面级 id 而非 .page-rail/.page-main：列容器声明全站唯一，
   被断点锁约束在 (min-width: 768px)，页面级规则不得混入。 */
@media (max-width: 767px) {
    /* 第一页兜底一屏：内容不足一屏时把提示胶囊推近视口下缘 */
    #daily-page1 {
        min-height: calc(100svh - 11rem);
    }

    /* 第二页兜底一屏：折叠态内容不足一屏时滚动上限不够会翻不到位（实测 2026-09-13），
       留白即呼吸感 */
    #daily-flow {
        min-height: calc(100svh - 5rem);
    }
}

/* 翻页入场特效：第二页活动卡片依次上浮淡入（delay 由 JS 按 index 设置，
   组类 .pa-page-enter 每次翻入时由 JS 挂上、播完移除）。
   特异性高于卡片自身的 fadeIn 入场，临时覆盖不冲突。 */
@keyframes paPageIn {
    from {
        opacity: 0;
        transform: translateY(14px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

.pa-page-enter .daily-card {
    animation: paPageIn 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* 对话多行输入框：Enter 只换行、不提交（只允许点「发送」按钮）。
   高度由 base.html 的 paFitTextarea 跟随内容增长，到顶后在框内滚动；
   resize:none 关掉手动拖拽，避免拖出破坏页面布局的大框 */
.chat-input {
    resize: none;
    overflow-y: auto;
    max-height: 160px;
    line-height: 1.5;
}

/* 【已下线】移动端两行 min-height 保底（2026-09-14 上、同日下）：
   当时为塞下两行 placeholder 加了 min-height:4.75rem，但输入框因此比
   全站其它输入框高出一截、视觉不统一。后改单行 placeholder
   「输入消息…（Enter 换行）」根治，本规则移除。
   教训保留：iOS Safari 不把 placeholder 算进 textarea scrollHeight，
   placeholder 文案必须保证单行，不要用高度 hack 兼容多行文案。 */

/* iOS Safari：聚焦 font-size < 16px 的输入控件会自动放大页面（viewport 缩放）。
   【全站规范】移动端统一把所有可输入控件字号提到 16px 规避；桌面 Safari 无此
   行为，维持设计系统的 text-sm 紧凑。新增输入控件无需单独处理。
   用 !important 是因为 Tailwind 为浏览器运行时构建，其 style 标签后置于本文件，
   元素选择器（0-0-1）对类选择器（.text-sm，0-1-0）靠源码顺序必输；
   限 ≤767px + 单属性，影响面可控。不建议用 transform:scale 补偿字号——
   会破坏 flex 容器宽度与 paFitTextarea 的 scrollHeight 高度拟合。 */
@media (max-width: 767px) {
    input,
    textarea,
    select {
        font-size: 16px !important;
    }

    /* iOS 的 <input type="date"> 按完整日期格式预留极大的固有宽度
       （min-width:0 也压不住 min-content，随字号 16px 更大），会把弹窗/表单
       撑出横向滚动（真机截图实证）。移动端统一 appearance:none 退化为普通
       文本框外观后即可正常收缩自适应；点击仍弹系统原生日期选择器，功能不变。
       桌面 ≥768px 不受影响，保留原生外观与日历图标。 */
    input[type="date"] {
        -webkit-appearance: none;
        appearance: none;
    }
}

/* iOS 弹窗内控件自适应宽度（手机端弹窗出现横向拖动条的修复）。
   iOS 的 date/select 等原生控件固有宽度大且默认 min-width:auto，字号提到
   16px 后更容易撑破弹窗滚动容器（overflow-y:auto 时 overflow-x 也变 auto，
   于是出现横向拖动条）。三件事：① 解除表单字段的最小宽度限制，允许收缩；
   ② 状态 select 撑满弹窗宽（原本无 w-full，宽度由选项内容决定）；
   ③ 弹窗滚动容器禁止横向滚动兜底——任何意外超宽都被裁剪而非拖动。 */
@media (max-width: 767px) {
    #create-activity-modal .w-full {
        min-width: 0;
    }

    #create-activity-modal select {
        width: 100%;
    }

    #create-activity-modal .overflow-y-auto {
        overflow-x: hidden;
    }
}

/* ===== AI 回复的 Markdown 排版（结构由 core/markdown_render.py 生成） =====
   本项目没装 Tailwind typography 插件，模板上的 prose 类其实不出任何样式，
   所以正文排版全部由这一份规则负责；行长仍由外层 max-w-* 控制。 */
.md-body {
    line-height: 1.7;
    overflow-wrap: anywhere;   /* 长 URL / 长 token 不撑破气泡（移动端实测会横向溢出） */
}

.md-body > *:first-child { margin-top: 0; }
.md-body > *:last-child { margin-bottom: 0; }

.md-p { margin: 0 0 0.6rem; }

.md-h {
    font-weight: 600;
    line-height: 1.4;
    margin: 1rem 0 0.4rem;
}

h2.md-h { font-size: 1.05rem; }
h3.md-h, h4.md-h, h5.md-h, h6.md-h { font-size: 0.95rem; }

.md-list { margin: 0 0 0.6rem; padding-left: 1.25rem; }
.md-list li { margin: 0.15rem 0; }
.md-list .md-list { margin-bottom: 0; }

/* 行内代码：配色沿用已有的 .markdown-content code（同一元素两条背景规则会互相覆盖，
   这里只管字号与字体，不再叠一套） */
.md-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85em;
}

/* 代码块：深色底沿用已有的 .markdown-content pre；这里补外边距与字号。
   overflow-x 也在那条规则里，缺了它一行长代码会把气泡撑出屏幕 */
.md-pre {
    margin: 0.5rem 0;
    font-size: 0.8rem;
    line-height: 1.55;
}

.md-pre code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

.md-table-wrap { overflow-x: auto; margin: 0.5rem 0; }

.md-table {
    border-collapse: collapse;
    width: 100%;
    font-size: 0.85rem;
}

.md-table th,
.md-table td {
    border: 1px solid var(--border);
    padding: 0.35rem 0.5rem;
    text-align: left;
    vertical-align: top;
}

.md-table th { background: var(--accent-light); font-weight: 600; white-space: nowrap; }

.md-link {
    color: var(--accent);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.md-quote {
    margin: 0.5rem 0;
    padding-left: 0.75rem;
    border-left: 2px solid var(--border-strong);
    color: var(--text-secondary);
}

.md-hr { border: 0; border-top: 1px solid var(--border); margin: 0.75rem 0; }

/* 裸链专用（渲染器给自动链接挂的类）：表头单元格里有 white-space:nowrap，
   光靠 .md-body 的 overflow-wrap 拦不住，不断开就会把 .md-table-wrap 撑宽到滑不到底 */
.md-break { word-break: break-all; }

/* 裸链专用（渲染器给自动链接挂的类）：表头单元格里有 white-space:nowrap，
   光靠 .md-body 的 overflow-wrap 拦不住，不断开就会把 .md-table-wrap 撑宽到滑不到底 */


/* ===== 聊天常驻快捷指令 ===== */
.chat-chip {
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.7rem;
    border: 1px solid var(--border-strong);
    border-radius: 9999px;
    background: var(--bg-card);
    color: var(--text-secondary);
    font-size: 0.75rem;
    white-space: nowrap;
    transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.chat-chip:hover,
.chat-chip:active {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-light);
}

/* 桌面才自己定高：移动端的高度由 .tap-target（44px）负责。写在基础规则里会和
   .tap-target 同特异度、靠顺序取胜（实测把 44px 压回 32px），分端工具类就白挂了 */
@media (min-width: 768px) {
    .chat-chip { min-height: 2rem; }
}

/* ===== @ 钉选（会话级上下文） ===== */
.pin-host { position: relative; }

.pin-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 1.25rem;
    flex-wrap: wrap;
}

.pin-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    max-width: 100%;
    padding: 0.1rem 0.25rem 0.1rem 0.55rem;
    border: 1px solid var(--accent);
    border-radius: 9999px;
    background: var(--accent-light);
    color: var(--text);
    font-size: 0.75rem;
}

.pin-chip-clear {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 9999px;
    color: var(--text-secondary);
    line-height: 1;
}

.pin-chip-clear:hover { color: var(--text); }

.pin-hint { font-size: 0.7rem; color: var(--text-muted); }

.pin-key { font-weight: 700; color: var(--text-secondary); }

/* 候选浮层向上开：宿主紧贴在输入框上方，向下开会盖住发送按钮 */
.pin-candidates {
    position: absolute;
    bottom: calc(100% + 4px);
    left: 0;
    z-index: 30;
    min-width: 13rem;
    max-width: 100%;
    max-height: 14rem;
    overflow-y: auto;
    padding: 0.25rem;
    border: 1px solid var(--border-strong);
    border-radius: 0.5rem;
    background: var(--bg-card);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}

.pin-item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    width: 100%;
    padding: 0.4rem 0.5rem;
    border-radius: 0.375rem;
    text-align: left;
}

.pin-item:hover { background: var(--accent-light); }

.pin-item-name {
    font-size: 0.8rem;
    color: var(--text);
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pin-item-meta { font-size: 0.7rem; color: var(--text-muted); }

.pin-empty { padding: 0.4rem 0.5rem; font-size: 0.75rem; color: var(--text-muted); }

/* ===== 可点追问（AI 回复末尾的「下一步」） =====
   chips 本体复用 .chat-chip，这里只管排版与分隔线 */
.follow-ups {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.65rem;
    padding-top: 0.5rem;
    border-top: 1px dashed var(--border);
}

.follow-ups-label { font-size: 0.7rem; color: var(--text-muted); }

/* 追问 chip 是 AI 生成的长句：.chat-chip 的 nowrap 会让整句撑出圆角按钮外
   （线上实测「把这套…存进知识库，标题《…》」溢出）。单类同特异度靠源码顺序取胜，
   必须写在 .chat-chip 之后；quick_chips 的短标签不受影响，仍享受 nowrap。 */
.follow-up {
    white-space: normal;
    text-align: left;
    overflow-wrap: anywhere;
}

/* ===== Chat 分栏布局（桌面端左右分栏 / 移动端 IM 式单栏） ===== */

/* 移动端默认：单栏，列表视图可见，聊天视图隐藏 */
/* 高度算术（勿随意改 9.5rem）：容器顶部距视口顶 = 顶栏 h-14(56px) + main pt-6(24px) = 80px；
   底部要让出 Tab 栏实高（py-2×2 + 图标 22 + 标签 ≈54px）+ 呼吸空隙 18px + iOS 安全区，
   即 100dvh - 80px(顶部) - 72px(底部) = 100dvh - 9.5rem - safe-area。
   改小会让发送框被 Tab 栏遮住（线上实测过）。 */
.chat-layout {
    display: flex;
    flex-direction: column;
    height: calc(100dvh - 9.5rem - env(safe-area-inset-bottom, 0px));
}

.chat-sidebar {
    flex: 1;
    overflow-y: auto;
    min-width: 0;
    /* 固定高度容器内的 flex 子项默认 min-height:auto，长对话列表会把
       .chat-layout 撑爆、内滚失效（同 .chat-main 的坑，实测踩过） */
    min-height: 0;
}

.chat-main {
    display: none;
    flex-direction: column;
    flex: 1;
    min-width: 0;
    /* 关键：不加这个，长对话内容会撑爆固定高度的 .chat-layout，
       #split-messages 内滚失效，发送框被推出视口、被底部 Tab 栏遮住
       （移动端 390×844 实测：短对话间隙 17px 正常，长对话重叠 55px） */
    min-height: 0;
}

/* 移动端：data-view="chat" 时切换到聊天视图 */
.chat-layout[data-view="chat"] .chat-sidebar { display: none; }
.chat-layout[data-view="chat"] .chat-main { display: flex; }

/* 对话项（左栏列表） */
.chat-conv-item {
    display: block;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border);
    cursor: pointer;
    transition: background 0.15s ease;
}
.chat-conv-item:hover { background: var(--accent-light); }
.chat-conv-item.active {
    background: var(--accent-light);
    border-left: 3px solid var(--accent);
}

/* 对话标题截断（约 10 个中文字符） */
.chat-conv-title {
    max-width: 10em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 桌面端（md+）：左右分栏 */
@media (min-width: 768px) {
    .chat-layout {
        flex-direction: row;
        height: calc(100dvh - 6rem);
    }

    .chat-sidebar {
        width: 300px;
        flex: none;
        border-right: 1px solid var(--border);
    }

    .chat-main {
        display: flex;
        flex: 1;
    }

    /* 桌面端始终显示两栏，data-view 不生效 */
    .chat-layout[data-view="chat"] .chat-sidebar { display: flex; }
}

/* ===== 聊天消息流移动端（<768px）：全宽 + 左侧角色竖条 =====
   移动端放弃左右气泡分离：窄屏上 80% 上限把正文压到 237px（约 17 个中文字），一条长回答
   要滚十几屏，宽表格与代码块基本没法看。满宽以后正文 302px（+27%）。
   去掉「左右位置」这层强编码后，角色改由三条不占横向的冗余表达：
   左竖条（黑 = 你 / 浅灰 = AI 助手）+ 模板里既有的底色差 + 元信息文字标签。
   手法沿用本文件既有的左侧色条，不引第二个断点、不引彩色（站点禁彩色/渐变/阴影）。

   写在文件末尾而不是紧贴上面的桌面段：有几个回归锁是按「某个类名在 CSS 里首次出现的位置
   + 往后 N 个字」取锚点的，而本段注释不可避免地要解释正文断行与表格的横向滚动行为，
   放在前面会把那三个锚点带偏（假失败）。

   两条硬约束：
   ① 覆盖气泡上那些工具类（内边距、圆角、边框、底色）必须写到两个类的特异度 —— Tailwind
      用的是浏览器构建，它生成的 style 标签在运行时才追加到 head 末尾，位置在本文件之后，
      单类选择器靠源码顺序赢不了。
   ② 只用长手属性。margin / padding 简写复位会连带清掉宿主 space-y 给子元素的上外边距与
      模板里的垂直内边距，间距当场塌。 */
@media (max-width: 767px) {
    /* 竖条压在气泡自己的左边框位置上，其余三边仍是模板里那 1px 细边。
       左上/左下不带圆角：竖条是一根「脊」，带圆角会断线。 */
    .chat-message.user .chat-bubble {
        border-left: 3px solid var(--accent);
        border-top-left-radius: 0;
        border-bottom-left-radius: 0;
    }

    .chat-message.assistant .chat-bubble {
        border-left: 3px solid var(--border-strong);
        border-top-left-radius: 0;
        border-bottom-left-radius: 0;
    }

    /* 满宽以后，长 token 的溢出从「撑破小盒子」升级成「整页横向滚动」，在气泡这一层兜一道
       断行（用户消息那一支没有正文断行规则，AI 回复那一支有）。只写这一个属性，别写 overflow
       简写 —— 那会把气泡变成滚动容器、裁掉里面卡片的圆角。 */
    .chat-message .chat-bubble {
        overflow-wrap: anywhere;
    }
}

/* ===== 备忘列表：移动块状卡片 / 桌面（md+）分隔线行式列表 ===== */
.note-list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.note-item {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 1rem;
    padding: 0.875rem 1rem;
}

/* 置顶卡片：边框加深一档，扫一眼能分出置顶组 */
.note-item--pinned {
    border-color: var(--border-strong);
}

/* 长备忘折叠：JS 检测到内容超高才加 .is-collapsed（无 JS 时全文展示，渐进增强） */
.note-fold.is-collapsed .note-fold-body {
    max-height: 9rem;   /* 约 6 行正文 */
    overflow: hidden;
}

@media (min-width: 768px) {
    /* 桌面端去卡片化：上下分隔线的行式列表 + 行悬停高亮，信息密度高于卡片堆 */
    .note-list {
        gap: 0;
    }

    .note-item {
        background: transparent;
        border: 0;
        border-radius: 0;
        border-bottom: 1px solid var(--border);
        padding: 1.25rem 0.5rem;
        transition: background-color 0.15s ease;
    }

    .note-list > .note-item:first-child {
        border-top: 1px solid var(--border);
    }

    .note-item:hover {
        background: var(--accent-light);
    }

    .note-item--pinned {
        border-color: var(--border);
    }
}

/* ===== 移动端触控与可读性铁律（2026-09 390×844 走查后建立） =====
   走查实测：全站 <44px 可点元素约 146 处、按钮高度 7 档同屏、10px meta 文字成片。
   本块统一三件事，全部限定 ≤767px，桌面端零改动：
   ① 行内小操作触区拉满 44×44（.row-action，挂给编辑/删除/归档这类裸文字小按钮）；
   ② 10px 的 meta/时间戳/标签文字抬到 12px（!important 原因同 16px 输入字号规则：
      Tailwind 运行时 style 标签在本文件之后，同特异度靠源码顺序必输）；
   ③ 主动作元素逐模板补 .tap-target（此处不全局兜底，避免误伤正文文字链）。 */
@media (max-width: 767px) {
    .row-action {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-height: 44px;
        min-width: 44px;
    }

    .text-\[10px\] {
        font-size: 12px !important;
    }
}

/* data-mobile-collapse 折叠区块（details/summary 原生开合）的箭头随开合旋转：
   默认 ▶（收起），open 时转 90° 变 ▼（展开）。不限断点——桌面端同样受益 */
details[data-mobile-collapse] summary span[aria-hidden] {
    transition: transform 0.15s ease;
}

details[data-mobile-collapse][open] summary span[aria-hidden] {
    transform: rotate(90deg);
}
