/* ===== 设计变量 =====
   主题由三部分组成：外观模式（data-theme: light/dark）· 界面色调（data-tint: neutral/warm/cool）· 主题色（accent）。
   运行时由 js/theme.js 写入 <html> 属性，并派生 --primary* 内联变量；
   下面的值只是默认（靛蓝 · 中性 · 浅色），保证不用 JS 时界面依旧完整。 */
:root {
  /* 主题色：--primary* 由 JS 按当前模式派生（悬停色、渐变副色、淡底色、按钮前景色） */
  --accent: #4F6BED;
  --primary: #4F6BED;
  --primary-hover: #3F59D8;
  --primary-2: #7C8CF8;
  --primary-soft: #EEF1FE;
  --on-primary: #FFFFFF;

  /* 语义色 */
  --success: #17A673;
  --warning: #E8A33D;
  --danger: #E5484D;

  /* 浅色 · 中性色调 */
  --bg: #F6F7F9;
  --card: #FFFFFF;
  --text: #1F2329;
  --text-sub: #4E5666;
  --muted: #8A9099;
  --border: #E9EBEF;
  --shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 8px 24px rgba(16, 24, 40, .06);

  --radius: 10px;
  --radius-sm: 8px;
  --sidebar-w: 224px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  --mono: "JetBrains Mono", "Cascadia Code", Consolas, "Courier New", monospace;
}

/* 浅色 · 暖调 / 冷调：只改底色与描边，文字对比度保持不变 */
[data-tint="warm"] { --bg: #FAF6F0; --card: #FFFCF8; --border: #EFE6D9; }
[data-tint="cool"] { --bg: #F2F5FA; --card: #FFFFFF; --border: #E3EAF4; }

/* 深色 · 中性色调 */
[data-theme="dark"] {
  --primary: #6B84F5;
  --primary-hover: #7F94F7;
  --primary-2: #8E9DF9;
  --primary-soft: #232842;
  --bg: #15171C;
  --card: #1D2027;
  --text: #E7E9EE;
  --text-sub: #B6BCC7;
  --muted: #868D99;
  --border: #2A2E37;
  --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 8px 24px rgba(0, 0, 0, .35);
}

/* 深色 · 暖调 / 冷调 */
[data-theme="dark"][data-tint="warm"] { --bg: #1A1614; --card: #221D1A; --border: #332B26; }
[data-theme="dark"][data-tint="cool"] { --bg: #121620; --card: #1A1F2B; --border: #27303F; }

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--primary); text-decoration: none; }
a:hover { color: var(--primary-hover); }
h1, h2, h3, h4 { margin: 0 0 12px; font-weight: 600; line-height: 1.35; }
p { margin: 0 0 10px; }
img { max-width: 100%; }

/* ===== 布局 ===== */
.app { display: flex; min-height: 100vh; }

.sidebar {
  position: fixed;
  top: 0; left: 0; bottom: 0;
  width: var(--sidebar-w);
  background: var(--card);
  border-right: 1px solid var(--border);
  padding: 18px 12px;
  display: flex;
  flex-direction: column;
  z-index: 30;
}

.brand {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 10px 18px;
  font-weight: 700; font-size: 16px; color: var(--text);
}
/* 品牌图标：由 logo.png 生成的多尺寸 PNG（原图是深紫底 + 图案，无透明通道）。
   用圆角 + overflow 裁切，尺寸沿用原设计（30px / 圆角 9px）。 */
.brand .logo {
  width: 30px; height: 30px; border-radius: 9px; overflow: hidden;
  display: grid; place-items: center; flex: none;
}
.brand .logo img { width: 100%; height: 100%; object-fit: cover; display: block; }

.nav { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.nav a {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: var(--radius-sm);
  color: var(--text-sub); font-weight: 500;
}
.nav a:hover { background: var(--primary-soft); color: var(--primary); }
.nav a.active { background: var(--primary-soft); color: var(--primary); font-weight: 600; }
.nav a .ico { width: 18px; text-align: center; }
.nav .section { padding: 14px 12px 6px; color: var(--muted); font-size: 12px; }

.sidebar-foot { border-top: 1px solid var(--border); padding-top: 12px; margin-top: 8px; }

.main { flex: 1; margin-left: var(--sidebar-w); min-width: 0; }

.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 14px;
  padding: 12px 24px;
  background: color-mix(in srgb, var(--card) 88%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}
.topbar .search { flex: 1; max-width: 460px; }
.content { padding: 22px 24px 48px; max-width: 1180px; }   /* 上限见下方 page-notes / wide / narrow 三条覆盖规则 */

/* 笔记详情：正文宽度完全跟随窗口（不再有 1180px 或 900px 上限）。
   阅读型页面的长行在超宽屏上会变长，如需限制可改成 max-width: min(1600px, 100%)。 */
.content.wide { max-width: none; }

/* ===== 滚动条 =====
   细一点、圆角、悬停变主题色。Chrome 用 ::-webkit-scrollbar（能画内缩与悬停态），
   Firefox 走标准属性，用 @supports 互斥，避免两套规则互相打架。
   注意：一旦在 Chrome 里设了 scrollbar-width/color，::-webkit-scrollbar 那套就失效了。 */
@supports not selector(::-webkit-scrollbar) {
  html { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--muted) 45%, transparent) transparent; }
}
/* 12px 的槽 + 3px 透明边框，视觉上是 6px 的圆角滑块（border 让滑块与内容留出气口） */
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background-color: color-mix(in srgb, var(--muted) 42%, transparent);
  background-clip: padding-box;
  border: 3px solid transparent;
  border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover {
  background-color: color-mix(in srgb, var(--primary) 72%, transparent);
  border-width: 2px;   /* 悬停时微微变粗 */
}
::-webkit-scrollbar-thumb:active { background-color: var(--primary); border-width: 2px; }
::-webkit-scrollbar-corner { background: transparent; }

/* ===== 我的笔记：「上中下」三段布局（筛选固定 / 内容滚动 / 分页固定）=====
   内容区分三段，只有中段滚动：
     上 = 标题 + 筛选栏   固定不动
     中 = 笔记卡片列表   flex:1 + overflow-y:auto ← 唯一的滚动容器
     下 = 分页           固定在底部
   整页（body）不滚动，侧边栏与顶栏完全静止。
   关键点：flex:1 的子项必须配 min-height:0，否则在固定高度父级里不会产生内部滚动、内容会把父级撑高。
   高度用 100vh + 100dvh 双层：移动端浏览器地址栏收展时 vh 会跳动。
   要在别的列表页复用：给 <body> 加 page-notes，把内容包成 .content-wrap > .content，
   中段套一个 .note-scroll 即可（当前使用者：我的笔记、文件库）。 */
body.page-notes { overflow: hidden; }
body.page-notes .app { height: 100vh; height: 100dvh; min-height: 0; }
body.page-notes .main {
  display: flex; flex-direction: column;
  height: 100vh; height: 100dvh;
}
/* 三段容器（自身不滚动，只负责分配高度） */
body.page-notes .content-wrap {
  flex: 1; min-height: 0; overflow: hidden;
  display: flex; flex-direction: column;
}
body.page-notes .content {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
  /* 上下内边距交给各段自己承担，避免出现固定段与滚动段之间的缝隙 */
  padding-top: 0; padding-bottom: 0;
  /* 兜底：视口太矮、上段+下段本身都放不下时（手机横屏、很小的窗口），
     允许 .content 整体滚动，否则页脚会被裁到视口外且无法触达。
     正常高度下 .content 不会溢出，滚动条只出现在中段。 */
  overflow-y: auto;
}
/* 列表与网格页（我的笔记 / 文件库 / 仪表盘 / 分类 / 外链）铺满可用宽度：
   其它页面仍保留 .content 的 1180px 上限（正文、编辑器要控制行宽）。 */
body.page-notes .content { max-width: none; }
/* 表单型页面（个人中心）：三段布局照旧，但内容列限宽居中，
   否则 2400px 屏上输入框会被拉成一条长带。
   必须同时给 width:100%：flex 子项一旦有交叉轴 auto margin，stretch 就失效，
   会退化成「按内容收缩」的窄列。 */
body.page-notes .content.narrow { width: 100%; max-width: 860px; margin-left: auto; margin-right: auto; }
body.page-notes .grid.cols-3 { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }

/* 上段：标题与筛选，固定 */
body.page-notes .page-head { flex: none; padding-top: 22px; }
/* 中段：唯一滚动区 */
body.page-notes .note-scroll {
  flex: 1; min-height: 0;
  overflow-y: auto; overflow-x: hidden;
  padding-top: 16px; padding-bottom: 4px;
  /* 预留滚动条宽度：筛选前后内容多少变化时卡片不会左右跳一下 */
  scrollbar-gutter: stable;
}
/* 下段：分页，固定在底部 */
/* 下段：页脚（无分页的页面它就是最底段） */
body.page-notes .site-footer { flex: none; }
body.page-notes .pager { flex: none; margin-top: 0; padding: 14px 0 20px; }
/* 上段的固定块统一 flex:none：我的笔记是筛选栏，文件库是「上传区 + 筛选栏」，
   不写的话矮视口里会被 flex 压缩变形。 */
body.page-notes .content > .card { flex: none; }

/* 文件库复用同一套三段布局（上 = 标题/上传/筛选，中 = 文件网格，下 = 分页 + 页脚）。
   窄屏下上段太占高度会把中段（真正要看的文件列表）挤到只剩 ~90px，所以：
     ① 上传区压成一行（图标与文案并排）、藏掉提示行；② 页头长描述隐藏（文件数量保留）。 */
.file-empty-hint { margin-top: 12px; font-size: 12px; color: var(--muted); }

@media (max-width: 767px) {
  /* 页头的长描述在手机上要换三四行，藏掉（文件数量保留） */
  .hide-sm { display: none; }
}

/* ===== 列表页固定工具条（我的笔记的搜索/筛选栏）=====
   贴在顶栏下方吸顶，卡片列表照常向下滚动；内容区不含任何独立滚动条。
   top 用 --topbar-h：顶栏高度由内容（按钮/天气组件）决定，写死像素容易错位，
   该变量在 app.js 里实测 .topbar 高度后写入；未测得时有兜底值。

   门槛取 768px（而不是更高）：该工具条在窄宽度下会折行变高（768~1050px 约 120px），
   再窄（手机 ~390px）会折成 6 行约 212px，连同顶栏会占掉 32%~43% 屏高，
   所以手机档保持普通滚动，只在 768px 以上吸顶。 */
/* 工具条内控件的宽度（原来写在行内样式里，行内样式无法被媒体查询覆盖，故移到这里） */
.sticky-toolbar .toolbar-kw { min-width: 200px; }
.sticky-toolbar select[name="categoryId"] { width: 150px; }
.sticky-toolbar select[name="tagId"] { width: 140px; }
.sticky-toolbar select[name="status"] { width: 120px; }
.sticky-toolbar select[name="sort"] { width: 130px; }

/* 中等宽度：整体收窄，尽量让固定条保持一行（120px 高的固定条会明显挤压内容） */
@media (max-width: 1150px) {
  .sticky-toolbar .toolbar-kw { min-width: 0; }
  .sticky-toolbar select[name="categoryId"] { width: 118px; }
  .sticky-toolbar select[name="tagId"] { width: 110px; }
  .sticky-toolbar select[name="status"] { width: 96px; }
  .sticky-toolbar select[name="sort"] { width: 104px; }
}

@media (min-width: 768px) {
  .sticky-toolbar {
    position: sticky;
    /* 整页滚动时偏移是顶栏高度；app-shell（我的笔记）下滚动容器是内容区，偏移为 0 */
    top: var(--topbar-h, 62px);
    z-index: 10;
    /* 吸顶后与下方滚动的卡片之间需要层次区分（未吸顶时看不出差别） */
    box-shadow: var(--shadow);
  }
  /* 我的笔记用的是「上中下」三段布局：筛选栏属于上段的普通固定块，不需要 sticky（见上方三段布局段） */
  /* 我的笔记：筛选栏是「上段」的普通固定块，不需要 sticky */
  body.page-notes .sticky-toolbar { position: static; }
}

/* ===== 页脚（备案号 / 联系邮箱 / 法律声明）=====
   数据来自 t_site_config，服务端渲染，见 fragments.html 的 siteFooter 片段。
   在普通页面它跟在内容后面（随页面滚动到底部可见）；在「我的笔记」三段布局里它是下段的一部分。 */
.site-footer {
  padding: 18px 0 6px;
  margin-top: 22px;
  border-top: 1px solid var(--border);
  font-size: 12px; color: var(--muted); line-height: 1.7;
  /* 备案号 / 联系邮箱 / 版权 / 法律声明整体居中 */
  text-align: center;
}
.site-footer .footer-line {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  justify-content: center;
}
.site-footer .footer-sep { color: var(--border); }
.site-footer a { color: var(--muted); }
.site-footer a:hover { color: var(--primary); }
/* 法律声明可能较长，收紧一点并且不要抢视觉焦点 */
.site-footer .footer-legal { margin-top: 4px; color: var(--muted); }
/* 暗色主题下 --muted 偏暗，小字号会发灰看不清，提亮一档到 --text-sub */
[data-theme="dark"] .site-footer { color: var(--text-sub); }
[data-theme="dark"] .site-footer a { color: var(--text-sub); }
[data-theme="dark"] .site-footer .footer-legal { color: var(--text-sub); }
/* 登录/注册这类居中页面：页脚固定在底部，不参与居中布局 */
.auth-wrap .site-footer {
  position: fixed; left: 0; right: 0; bottom: 0;
  margin: 0; padding: 12px 20px; text-align: center;
  border-top: none; background: transparent;
  justify-content: center;
  /* 必须高于 .auth-wrap::before 那张压暗遮罩（z-index:1）与卡片（z-index:2），
     否则页脚会被遮罩盖住——实测过：页脚在 DOM 里存在、命中测试也能点到，但视觉上被压暗遮罩吞掉 */
  z-index: 3;
}
.auth-wrap .site-footer .footer-line { justify-content: center; }
/* 登录页有背景视频/封面时遮罩是暗的，页脚文字要换成浅色才看得清；
   没有背景媒体时页面是浅底，保持默认的 muted 深灰。 */
.auth-wrap.bg-video .site-footer, .auth-wrap.bg-poster .site-footer {
  color: rgba(255, 255, 255, .75);
}
.auth-wrap.bg-video .site-footer a, .auth-wrap.bg-poster .site-footer a {
  color: rgba(255, 255, 255, .85);
}
.auth-wrap.bg-video .site-footer a:hover, .auth-wrap.bg-poster .site-footer a:hover {
  color: #fff;
}
.auth-wrap.bg-video .site-footer .footer-sep, .auth-wrap.bg-poster .site-footer .footer-sep {
  color: rgba(255, 255, 255, .35);
}
/* 分享页本身是浅色沉浸式布局，页脚居中即可 */
.share-wrap .site-footer { width: 100%; max-width: 860px; margin-top: 18px; text-align: center; }
.share-wrap .site-footer .footer-line { justify-content: center; }

.page-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 18px; flex-wrap: wrap; }
.page-head h2 { margin: 0; font-size: 20px; }
.muted { color: var(--muted); }
.sub { color: var(--text-sub); }

/* ===== 组件 ===== */
.card {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px;
}
/* 竖向堆叠时相邻卡片留白。网格内（.grid）由 gap 控制间距，
   否则 margin 会挤占行高，导致同一行卡片高低不齐。 */
.card + .card { margin-top: 16px; }
.grid > .card + .card { margin-top: 0; }
.card-title { font-size: 15px; font-weight: 600; margin-bottom: 12px; }

.grid { display: grid; gap: 16px; }
.grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid.auto { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }

.stat { display: flex; flex-direction: column; gap: 4px; }
.stat .num { font-size: 26px; font-weight: 700; letter-spacing: -.5px; }
.stat .label { color: var(--muted); font-size: 13px; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 36px; padding: 0 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--card); color: var(--text-sub);
  font-size: 14px; font-family: inherit; font-weight: 500;
  cursor: pointer; transition: all .15s ease; white-space: nowrap;
}
.btn:hover { border-color: var(--primary); color: var(--primary); }
.btn-primary { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); color: var(--on-primary); }
.btn-danger { color: var(--danger); }
.btn-danger:hover { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-sm { height: 30px; padding: 0 10px; font-size: 13px; }
/* 实心危险按钮：确认弹框的「删除」用它（原有 .btn-danger 只是描边款） */
.btn-danger-solid { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger-solid:hover { background: #C93A3F; border-color: #C93A3F; color: #fff; }
.btn-danger-solid:focus-visible { outline: 2px solid var(--danger); outline-offset: 2px; }
.btn-block { width: 100%; }
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn-ghost { background: transparent; border-color: transparent; }
.btn-ghost:hover { background: var(--primary-soft); }

.input, .select, .textarea {
  width: 100%; padding: 8px 12px; height: 36px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card); color: var(--text);
  font-family: inherit; font-size: 14px; outline: none; transition: border-color .15s ease, box-shadow .15s ease;
}
.textarea { height: auto; padding: 10px 12px; resize: vertical; line-height: 1.7; }
.input:focus, .select:focus, .textarea:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.field { margin-bottom: 14px; }
.field > label { display: block; margin-bottom: 6px; font-size: 13px; color: var(--text-sub); font-weight: 500; }
.form-tip { margin-top: 6px; font-size: 12px; color: var(--muted); }
.row { display: flex; gap: 10px; align-items: center; }
.row.wrap { flex-wrap: wrap; }
.row.between { justify-content: space-between; }
.row.end { justify-content: flex-end; }
.grow { flex: 1; min-width: 0; }

.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 8px; border-radius: 999px;
  background: var(--primary-soft); color: var(--primary);
  font-size: 12px; font-weight: 500;
}
.badge.gray { background: var(--bg); color: var(--muted); }
.badge.green { background: rgba(23, 166, 115, .12); color: var(--success); }
.badge.orange { background: rgba(232, 163, 61, .14); color: var(--warning); }

.tag {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 8px; border-radius: 6px;
  background: var(--bg); color: var(--text-sub); font-size: 12px;
}
.tag .x { cursor: pointer; color: var(--muted); font-style: normal; }
.tag .x:hover { color: var(--danger); }

/* 笔记卡片：同一行/不同行都保持等高，内部各区块高度固定，操作行贴底 */
.note-card {
  display: flex; flex-direction: column; gap: 8px;
  height: 100%;                 /* 撑满网格行高，保证等高 */
  min-width: 0;                 /* 防止长内容把列撑宽，保证等宽 */
  transition: transform .15s ease, box-shadow .15s ease;
}
.note-card:hover { transform: translateY(-2px); }
.note-card > .row { min-height: 22px; }   /* 置顶/草稿/时间行 */
.note-card h3 {
  margin: 0; font-size: 16px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-height: 44px;     /* 固定两行高度，标题长短不影响卡片高度 */
  overflow-wrap: anywhere;
}
.note-card h3 a { color: var(--text); }
.note-card h3 a:hover { color: var(--primary); }
.note-card .summary {
  color: var(--text-sub); font-size: 13px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-height: 44px;     /* 固定两行高度 */
  overflow-wrap: anywhere;
}
/* 分类/标签行固定一行，超出部分裁掉（详情页可见完整标签） */
.note-tags {
  display: flex; align-items: center; gap: 6px;
  height: 22px; min-height: 22px; overflow: hidden; flex-wrap: nowrap;
}
.note-tags .tag { flex: none; }
.note-card .meta {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  color: var(--muted); font-size: 12px;
  margin-top: auto;             /* 贴到卡片底部，使各卡片操作行对齐 */
  padding-top: 4px;
}
/* Note list master-detail (middle section) */
body.page-notes .note-master {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 4fr);
  gap: 16px;
  height: 100%;
  min-height: 0;
}
body.page-notes .note-index,
body.page-notes .note-detail {
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}
body.page-notes .note-index {
  display: flex;
  flex-direction: column;
  padding: 8px;
}
.note-index-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px 10px;
  font-size: 13px;
  color: var(--text-sub);
}
.note-index-head .muted { font-size: 12px; }
.note-index-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding-right: 2px;
}
.note-index-item {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  width: 100%;
  padding: 11px 10px;
  border: 0;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  background: transparent;
  color: var(--text);
  text-align: left;
  font-family: inherit;
  cursor: pointer;
}
.note-index-item:last-child { border-bottom: 0; }
.note-index-item:hover { background: var(--primary-soft); }
.note-index-item.active { background: var(--primary-soft); color: var(--primary); }
.note-index-title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 14px;
  line-height: 1.45;
  overflow-wrap: anywhere;
}
.note-index-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  color: var(--muted);
  font-size: 11px;
}
.note-index-meta > span:last-child {
  margin-left: auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.page-notes .note-detail {
  display: flex;
  flex-direction: column;
  padding: 22px;
}
.note-detail-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--border);
}
.note-detail-title-wrap { flex: 1; min-width: 0; }
.note-detail-title {
  margin: 0 0 10px;
  font-size: 20px;
  line-height: 1.4;
  overflow-wrap: anywhere;
}
.note-detail-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  color: var(--muted);
  font-size: 12px;
}
.note-detail-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.note-detail-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding-top: 16px;
}
.note-detail-loading,
.note-detail-error {
  padding: 20px 0;
  color: var(--muted);
}
.note-detail-error { color: var(--danger); }
body.page-notes .note-master.is-loading .note-detail-actions { opacity: .65; }

@media (max-width: 860px) {
  body.page-notes .note-master {
    grid-template-columns: 1fr;
    height: auto;
  }
  body.page-notes .note-index-list { max-height: 260px; }
  body.page-notes .note-detail { min-height: 420px; }
}



/* ===== 外链收藏 =====
   卡片结构：logo + 名称/域名 → 介绍 → 账号密码 → 操作行。
   与笔记卡片同样的等高套路：h3/介绍固定高度、操作行 margin-top:auto 贴底。 */
.link-card {
  display: flex; flex-direction: column; gap: 10px;
  height: 100%; min-width: 0;
  transition: transform .15s ease, box-shadow .15s ease;
}
.link-card:hover { transform: translateY(-2px); }
.link-head { display: flex; align-items: center; gap: 10px; min-width: 0; }
/* logo 容器：首字母色块与图片叠在同一格（grid-area 重叠），图片加载失败时被 JS 隐藏就露出色块 */
.link-logo {
  flex: none; position: relative; width: 40px; height: 40px;
  display: grid; place-items: center; overflow: hidden;
  border-radius: 10px; background: var(--primary-soft); color: var(--primary);
  font-size: 17px; font-weight: 600;
}
.link-logo > * { grid-area: 1 / 1; }
.link-logo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.link-title { min-width: 0; }
.link-title h3 { margin: 0; font-size: 15px; line-height: 1.4;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.link-title h3 a { color: var(--text); }
.link-title h3 a:hover { color: var(--primary); }
.link-host { font-size: 12px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.link-desc { font-size: 13px; color: var(--text-sub); line-height: 1.6;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-height: 42px; overflow-wrap: anywhere; }
.link-cred { display: flex; flex-direction: column; gap: 6px;
  padding: 8px 10px; border-radius: var(--radius-sm); background: var(--bg); }
.link-cred-row { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 12px; }
.link-cred-row .k { flex: none; color: var(--muted); }
.link-cred-row .v { flex: 1; min-width: 0; color: var(--text-sub);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 密码用等宽字体：显示明文时不至于把字符看串（l/1、O/0） */
.link-cred-row .v.mono { font-family: var(--mono); letter-spacing: .06em; }
.link-cred-row .btn { flex: none; }
.link-actions { display: flex; align-items: center; gap: 6px; margin-top: auto; padding-top: 4px; }

/* 小号按钮：账号/密码行里的「复制」「显示」，比 btn-sm 再矮一点 */
.btn-xs { height: 24px; padding: 0 8px; font-size: 12px; border-radius: 6px; }

/* 添加/编辑外链的弹框：字段比通用弹框多，放宽一点 */
.link-modal { max-width: 520px; }
.link-modal .logo-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.link-modal .logo-preview {
  flex: none; width: 40px; height: 40px; display: grid; place-items: center;
  overflow: hidden; border-radius: 10px; background: var(--primary-soft);
  color: var(--primary); font-weight: 600;
}
.link-modal .logo-preview > * { grid-area: 1 / 1; }
.link-modal .logo-preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
.link-modal .modal-actions {
  display: flex; align-items: center; gap: 8px; justify-content: flex-end; margin-top: 18px;
}

.list-item { display: flex; gap: 12px; align-items: flex-start; padding: 12px 0; border-bottom: 1px dashed var(--border); }
.list-item:last-child { border-bottom: none; }

/* 仪表盘「分类分布」：分类名与篇数都是链接（跳到按该分类过滤的笔记列表），
   但保持原有观感 —— 名字用正文色、计数用 badge 的灰色，hover 才变主题色提示可点，不加下划线。 */
.dash-cat-name { color: var(--text); text-decoration: none; }
.dash-cat-name:hover { color: var(--primary); }
.dash-cat-count { text-decoration: none; }
.dash-cat-count:hover { color: var(--primary); }

table { width: 100%; border-collapse: collapse; }
th, td { padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--border); font-size: 13px; }
th { color: var(--muted); font-weight: 500; background: transparent; }
tbody tr:hover { background: var(--bg); }

.pager { display: flex; align-items: center; gap: 8px; justify-content: center; margin-top: 20px; }
.pager .page-info { color: var(--muted); font-size: 13px; }

.empty { padding: 48px 20px; text-align: center; color: var(--muted); }
.empty .big { font-size: 34px; margin-bottom: 8px; }

.avatar {
  width: 32px; height: 32px; border-radius: 50%;
  background: linear-gradient(135deg, var(--primary), var(--primary-2));
  color: var(--on-primary); display: grid; place-items: center; font-size: 13px; font-weight: 600;
  overflow: hidden; flex: none;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* 头像上传 */
.avatar-upload { display: flex; align-items: center; gap: 16px; }
.avatar-preview {
  position: relative; width: 84px; height: 84px; border-radius: 50%;
  overflow: hidden; cursor: pointer; flex: none;
  border: 2px solid var(--border); background: var(--bg);
}
.avatar-preview:hover { border-color: var(--primary); }
.avatar-preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar-preview .fallback {
  width: 100%; height: 100%; display: grid; place-items: center;
  background: linear-gradient(135deg, var(--primary), var(--primary-2));
  color: var(--on-primary); font-size: 30px; font-weight: 600;
}
.avatar-preview .mask {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(16, 24, 40, .5); color: #fff; font-size: 12px;
  opacity: 0; transition: opacity .15s ease;
}
.avatar-preview:hover .mask { opacity: 1; }

.dropdown { position: relative; }
.dropdown-menu {
  position: absolute; right: 0; top: calc(100% + 8px); min-width: 168px;
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 6px; display: none; z-index: 40;
}
.dropdown.open .dropdown-menu { display: block; }
.dropdown-menu a, .dropdown-menu button {
  display: block; width: 100%; text-align: left; padding: 8px 10px;
  border: none; background: none; border-radius: 6px; color: var(--text-sub);
  font-size: 13px; font-family: inherit; cursor: pointer;
}
.dropdown-menu a:hover, .dropdown-menu button:hover { background: var(--primary-soft); color: var(--primary); }

/* ===== 登录页 ===== */
.auth-wrap {
  position: relative;
  min-height: 100vh; display: grid; place-items: center; padding: 24px;
  overflow: hidden;
  /* 兜底背景：没有背景视频/封面时看到的就是它（与改动前完全一致） */
  background: radial-gradient(1200px 500px at 50% -10%, var(--primary-soft), transparent 70%), var(--bg);
}

/* ---- 背景视频（登录页专用，由 js/login-bg.js 填充源）---- */
.auth-bg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;              /* 铺满并裁切，避免变形 */
  z-index: 0; pointer-events: none;
  opacity: 0; transition: opacity 1s ease;   /* 播放后淡入，避免生硬切换 */
}
.auth-wrap.bg-video .auth-bg { opacity: 1; }

/* ---- 静态封面兜底 ----
   小屏 / 省流量 / 弱网 / 系统“减少动效” / 视频加载失败时使用，避免几 MB 的视频流量 */
.auth-wrap.bg-poster {
  background-image:
    var(--auth-poster, none),
    radial-gradient(1200px 500px at 50% -10%, var(--primary-soft), transparent 70%);
  background-size: cover, auto;
  background-position: center, center;
  background-repeat: no-repeat, no-repeat;
}

/* ---- 压暗遮罩：保证卡片在任何视频画面上都可读 ----
   没有背景媒体时自动隐藏（opacity 0），登录页保持原样式 */
.auth-wrap::before {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  opacity: 0; transition: opacity .8s ease;
  background:
    linear-gradient(180deg, rgba(8, 10, 16, .70) 0%, rgba(8, 10, 16, .38) 45%, rgba(8, 10, 16, .68) 100%),
    radial-gradient(130% 90% at 50% 45%, rgba(8, 10, 16, 0) 28%, rgba(8, 10, 16, .50) 100%);
}
.auth-wrap.bg-video::before, .auth-wrap.bg-poster::before { opacity: 1; }

.auth-card {
  position: relative; z-index: 2;      /* 压在视频与遮罩之上 */
  width: 100%; max-width: 380px;
}
/* 有背景媒体时卡片做成磨砂玻璃，视频从背后透出来 */
.auth-wrap.bg-video .auth-card,
.auth-wrap.bg-poster .auth-card {
  border-color: color-mix(in srgb, var(--card) 45%, transparent);
  box-shadow: 0 24px 64px rgba(6, 8, 14, .48);
}
/* 不支持 backdrop-filter 的浏览器保持不透明白底（上面 .card 的样式），保证可读性 */
@supports (backdrop-filter: blur(1px)) {
  /* 94% 而非更透：既保留玻璃质感，又不让卡片上的次要文字掉对比度 */
  .auth-wrap.bg-video .auth-card,
  .auth-wrap.bg-poster .auth-card {
    background: color-mix(in srgb, var(--card) 94%, transparent);
    backdrop-filter: blur(18px) saturate(1.2);
    -webkit-backdrop-filter: blur(18px) saturate(1.2);
  }
  /* 半透明卡片会整体压低文字对比度，这里把次要文字提升一档（muted → text-sub），
     保证「账号/密码」标签、占位提示、记住我、底部说明都清晰可读 */
  .auth-wrap.bg-video .auth-card .muted, .auth-wrap.bg-poster .auth-card .muted,
  .auth-wrap.bg-video .auth-card .form-tip, .auth-wrap.bg-poster .auth-card .form-tip,
  .auth-wrap.bg-video .auth-sub, .auth-wrap.bg-poster .auth-sub,
  .auth-wrap.bg-video .auth-foot, .auth-wrap.bg-poster .auth-foot {
    color: var(--text-sub);
  }
}

.auth-card .brand { justify-content: center; padding-bottom: 8px; }
.auth-title { text-align: center; font-size: 18px; margin-bottom: 4px; }
.auth-sub { text-align: center; color: var(--muted); font-size: 13px; margin-bottom: 22px; }
.auth-foot { margin-top: 16px; text-align: center; font-size: 13px; color: var(--muted); }

/* ===== 编辑器（Vditor 即时渲染，Typora 式单栏）===== */
#vditor { min-height: 520px; }
#vditor .vditor-reset { min-height: 460px; font-size: 15px; line-height: 1.8; }
#vditor .vditor-toolbar { border-bottom: 1px solid var(--border); }
#vditor .vditor-ir pre.vditor-reset { background: transparent; }
#vditor .vditor-panel { z-index: 25; }
.editor-status { display: flex; justify-content: space-between; gap: 12px; color: var(--muted); font-size: 12px; padding-top: 10px; }

/* 暗色主题下让编辑器与页面底色一致 */
[data-theme="dark"] #vditor .vditor-toolbar { background: var(--card); border-bottom-color: var(--border); }
[data-theme="dark"] #vditor .vditor-ir pre.vditor-reset { color: var(--text); }

/* ===== Markdown 正文 ===== */
.markdown { font-size: 15px; line-height: 1.85; color: var(--text); word-wrap: break-word; }
.markdown > *:first-child { margin-top: 0; }
.markdown h1 { font-size: 24px; margin-top: 28px; padding-bottom: 8px; border-bottom: 1px solid var(--border); }
.markdown h2 { font-size: 20px; margin-top: 26px; padding-bottom: 6px; border-bottom: 1px solid var(--border); }
.markdown h3 { font-size: 17px; margin-top: 22px; }
.markdown h4, .markdown h5, .markdown h6 { font-size: 15px; margin-top: 18px; }
.markdown code {
  font-family: var(--mono); font-size: 13px;
  background: var(--bg); border: 1px solid var(--border);
  padding: 1px 5px; border-radius: 5px;
}
.markdown pre {
  background: #1D2027; color: #E7E9EE; padding: 14px 16px; border-radius: var(--radius);
  overflow: auto; line-height: 1.7;
}
.markdown pre code { background: none; border: none; color: inherit; padding: 0; font-size: 13px; }
.markdown blockquote {
  margin: 14px 0; padding: 6px 14px; color: var(--text-sub);
  border-left: 3px solid var(--primary); background: var(--primary-soft); border-radius: 0 6px 6px 0;
}
.markdown table { margin: 16px 0; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.markdown table th { background: var(--bg); }
.markdown img { border-radius: var(--radius); }
.markdown hr { border: none; border-top: 1px solid var(--border); margin: 24px 0; }
/* 数学公式：块级公式居中，行内公式跟随文字 */
.markdown .math-block { margin: 16px 0; text-align: center; overflow-x: auto; }
.markdown .math-inline { display: inline; }
[data-theme="dark"] .markdown .katex { color: var(--text); }
.markdown ul, .markdown ol { padding-left: 22px; }
.markdown li { margin: 4px 0; }
.markdown input[type="checkbox"] { margin-right: 6px; }

/* ===== 上传 ===== */
.dropzone {
  /* 单行紧凑形态：原来是三行（图标/文案/提示）约 150px，现在约 45px（-70%）。
     约束信息（大小上限、支持的格式）挪到页头描述里，不再占上传区高度。 */
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 16px;
  border: 1.5px dashed var(--border); border-radius: var(--radius);
  text-align: center; color: var(--muted);
  transition: all .15s ease; cursor: pointer;
}
.dropzone .dz-icon { font-size: 17px; line-height: 1; }
.dropzone .dz-text { font-size: 13px; }
.dropzone:hover, .dropzone.dragover { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }

.progress { height: 6px; border-radius: 999px; background: var(--bg); overflow: hidden; margin-top: 8px; }
.progress > i { display: block; height: 100%; width: 0; background: var(--primary); transition: width .2s ease; }

.file-card { display: flex; flex-direction: column; gap: 8px; height: 100%; min-width: 0; }
/* 文件名固定两行高度：1 行与 2 行文件名不再造成卡片高矮不一 */
.file-card .file-name {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-height: 44px; overflow-wrap: anywhere;
}
.file-card .file-actions { margin-top: auto; }
.file-thumb {
  height: 132px; border-radius: var(--radius-sm); background: var(--bg);
  display: grid; place-items: center; overflow: hidden; color: var(--muted); font-size: 26px;
}
.file-thumb img { width: 100%; height: 100%; object-fit: cover; }
.file-name { font-size: 13px; font-weight: 500; word-break: break-all; }

/* ===== 迭代历史：时间轴 =====
   结构：.timeline（竖线画在 ::before）> .tl-item（每个节点）> .tl-node（圆点）+ .tl-card（卡片）。
   节点颜色按类型区分；最新一条（.latest）实心高亮并带一圈淡色光晕，一眼看到最新进展。 */
.timeline { position: relative; padding: 4px 0 4px 26px; }
.timeline::before {
  content: ""; position: absolute; left: 7px; top: 10px; bottom: 10px; width: 2px;
  background: var(--border); border-radius: 2px;
}
.tl-item { position: relative; }
.tl-item + .tl-item { margin-top: 14px; }
.tl-item .tl-node {
  position: absolute; left: -26px; top: 20px; width: 16px; height: 16px; border-radius: 50%;
  background: var(--card); border: 2px solid var(--muted); box-sizing: border-box; z-index: 1;
}
/* 类型配色：新增=主题色，修复=危险色，优化=成功色，其他=中性 */
.tl-node.feature { border-color: var(--primary); }
.tl-node.fix { border-color: var(--danger); }
.tl-node.optimize { border-color: var(--success); }
.tl-node.other { border-color: var(--muted); }
.tl-item.latest .tl-node { background: var(--primary); border-color: var(--primary); }
.tl-item.latest .tl-node.fix { background: var(--danger); border-color: var(--danger); }
.tl-item.latest .tl-node.optimize { background: var(--success); border-color: var(--success); }
.tl-item.latest .tl-node.other { background: var(--muted); border-color: var(--muted); }
.tl-item.latest .tl-node { box-shadow: 0 0 0 4px var(--primary-soft); }
.tl-card { padding: 14px 16px; }
.tl-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tl-title { margin: 0; font-size: 15px; font-weight: 600; }
.tl-type { font-size: 12px; font-weight: 600; padding: 1px 8px; border-radius: 999px;
  background: var(--primary-soft); color: var(--primary); }
.tl-type.fix { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); }
.tl-type.optimize { background: color-mix(in srgb, var(--success) 15%, transparent); color: var(--success); }
.tl-type.other { background: var(--bg); color: var(--muted); }
.tl-version { font-family: var(--mono); font-size: 12px; color: var(--text-sub);
  background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 1px 7px; }
.tl-date { margin-top: 6px; font-size: 12px; color: var(--muted); }
.tl-content { margin-top: 8px; font-size: 13px; color: var(--text-sub);
  white-space: pre-wrap; overflow-wrap: anywhere; }
.tl-actions { margin-top: 10px; gap: 6px; }
.changelog-modal { max-width: 560px; }


/* ===== 用户管理：筛选与操作列 =====
   操作列不换行、右对齐；窄屏时表格横向滚动（.table-wrap 由页面模板包住 table）。 */
.user-filter-kw { width: 180px; }
.user-filter-sel { width: 120px; }
.th-actions, .td-actions { text-align: right; }
.td-actions .row { justify-content: flex-end; flex-wrap: nowrap; }
.table-wrap { overflow-x: auto; }

/* ===== 优化建议 =====
   建议是长文本，所以卡片纵向堆叠（.card + .card 自带 16px 间距），
   管理员回复用左侧色条 + 淡底，与正文一眼区分开。 */
.fb-card { display: flex; flex-direction: column; gap: 10px; }
.fb-meta { gap: 8px; min-height: 22px; }
.fb-content { white-space: pre-wrap; overflow-wrap: anywhere; }
.fb-reply {
  border-left: 3px solid var(--primary); background: var(--primary-soft);
  border-radius: var(--radius-sm); padding: 10px 12px;
}
.fb-reply-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.fb-reply-who { font-size: 12px; font-weight: 600; color: var(--primary); }
.fb-reply-head .muted { font-size: 12px; }
.fb-reply-text { font-size: 13px; color: var(--text-sub); white-space: pre-wrap; overflow-wrap: anywhere; }
.fb-actions { gap: 6px; }
.fb-empty-hint { margin-top: 12px; font-size: 12px; color: var(--muted); }
.fb-filter-sel { width: 130px; }
.fb-modal { max-width: 520px; }
.fb-quote { border-left: 3px solid var(--border); padding: 2px 0 2px 10px; margin-bottom: 12px; }


/* ===== 随手记（备忘录）=====
   布局与「我的笔记」一致：上段 = 标题 + 工具条（快速记录 + 搜索），中段 = 卡片网格（唯一滚动区），
   下段 = 分页 + 页脚。工具条卡片里是两个并列的 form（写备忘 / 搜索），所以第二行加一条分隔线。
   正文用 pre-wrap 原样保留换行（随手记常是清单式多行内容）；置顶卡片左侧一条主题色竖条。 */
.memo-head-actions { gap: 8px; }
.memo-toolbar { display: flex; flex-direction: column; gap: 12px; }
.memo-toolbar > form + form { border-top: 1px solid var(--border); padding-top: 12px; }
.memo-input {
  width: 100%; min-height: 42px; max-height: 200px;
  resize: none; overflow-y: auto;   /* 高度由 JS 按内容自适应，超过 200px 才出现内部滚动条 */
}
.memo-compose-foot { gap: 10px; margin-top: 10px; }
.memo-counter { font-size: 12px; font-variant-numeric: tabular-nums; }
.memo-tip { font-size: 12px; }
/* 搜索框与「我的笔记」的筛选框同宽，用同一套响应式规则（toolbar-kw） */
.memo-search .memo-kw { min-width: 200px; max-width: 320px; }
.memo-card { display: flex; flex-direction: column; gap: 8px; height: 100%; min-width: 0; }
.memo-card.pinned { border-color: var(--primary); box-shadow: inset 3px 0 0 var(--primary); }
.memo-meta { min-height: 22px; }
.memo-meta .muted { font-size: 12px; }
.memo-content { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.7; }
/* 默认最多 6 行：备忘长短差别很大，不裁的话一张超长卡片会把整行撑得很高。
   真的被裁掉时由 JS 加上 has-more 显示「展开」，点开显示全文（expanded）。 */
.memo-card:not(.expanded) .memo-content {
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden;
}
.memo-more {
  display: none; align-self: flex-start; padding: 0; height: auto;
  background: none; border: 0; color: var(--primary); font-size: 12px; cursor: pointer;
}
.memo-more:hover { text-decoration: underline; }
.memo-card.has-more .memo-more { display: inline-flex; }
.memo-card .meta {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  color: var(--muted); font-size: 12px;
  margin-top: auto;             /* 操作行贴到卡片底部，同行卡片对齐 */
  padding-top: 4px;
}
.memo-empty-hint { margin-top: 12px; font-size: 12px; color: var(--muted); }
.memo-modal { max-width: 560px; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }


/* ===== 提示与弹窗 ===== */
/* ===== 回到顶部（笔记详情等长页面）=====
   需求是「黑色箭头」：箭头颜色固定近黑（#111），因此按钮底色也固定为浅色 ——
   深色主题下是一个白底黑箭头的悬浮按钮，对比度最高，也符合需求原文。
   bottom 取 84px 是为了让开右下角的 toast（.toast-box bottom: 24px），两者不重叠。
   z-index 70：低于自绘弹框(80)与提示(90)，被覆盖时自动让位。 */
.to-top {
  position: fixed; right: 24px; bottom: 84px; z-index: 70;
  width: 46px; height: 46px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 50%;
  background: #FFFFFF; color: #111111; cursor: pointer;
  box-shadow: 0 2px 6px rgba(16, 24, 40, .10), 0 10px 24px rgba(16, 24, 40, .12);
  opacity: 0; visibility: hidden; transform: translateY(8px) scale(.96);
  transition: opacity .2s ease, transform .2s ease, visibility .2s,
              box-shadow .2s ease, border-color .2s ease;
}
.to-top.show { opacity: 1; visibility: visible; transform: none; }
/* 悬停：外圈淡主色光环 + 箭头轻微上浮 + 阴影加深 */
.to-top::after {
  content: ""; position: absolute; inset: -4px; border-radius: 50%;
  border: 1px solid var(--primary); opacity: 0; transform: scale(.9);
  transition: opacity .2s ease, transform .2s ease;
}
.to-top:hover::after { opacity: .45; transform: scale(1); }
.to-top:hover {
  border-color: var(--primary);
  box-shadow: 0 4px 10px rgba(16, 24, 40, .14), 0 14px 30px rgba(16, 24, 40, .18);
}
.to-top svg { width: 20px; height: 20px; display: block; transition: transform .2s ease; }
.to-top:hover svg { transform: translateY(-2px); }
.to-top svg path { fill: none; stroke: #111111; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.to-top:active { transform: scale(.94); }
.to-top:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
[data-theme="dark"] .to-top { box-shadow: 0 2px 6px rgba(0, 0, 0, .45), 0 12px 28px rgba(0, 0, 0, .5); }
@media (prefers-reduced-motion: reduce) {
  .to-top, .to-top::after, .to-top svg { transition: none; }
}

.toast-box { position: fixed; right: 20px; bottom: 24px; z-index: 90; display: flex; flex-direction: column; gap: 10px; }
.toast {
  min-width: 200px; max-width: 340px; padding: 10px 14px;
  background: var(--card); border: 1px solid var(--border); border-left: 3px solid var(--primary);
  border-radius: var(--radius-sm); box-shadow: var(--shadow); font-size: 13px;
  animation: slide-in .18s ease;
}
.toast.success { border-left-color: var(--success); }
.toast.error { border-left-color: var(--danger); }
.toast.warn { border-left-color: var(--warning); }
@keyframes slide-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.modal-mask {
  position: fixed; inset: 0; background: rgba(16, 24, 40, .45);
  display: none; place-items: center; z-index: 80; padding: 20px;
}
.modal-mask.open { display: grid; }
.modal { width: 100%; max-width: 460px; max-height: 80vh; overflow: auto; }
/* .card.modal 自带 .card 的实底背景，这里只加强阴影做出浮层感 */
.card.modal { box-shadow: 0 24px 64px rgba(6, 8, 14, .42); }

/* ===== 通用确认弹框（替代原生 confirm）===== */
/* 结构：.modal-mask > .modal.confirm > .confirm-ico + .confirm-body(标题/说明) + .confirm-actions */
.modal.confirm {
  max-width: 420px;
  display: flex; gap: 14px; align-items: flex-start;
  padding: 20px 22px;
  animation: confirm-in .16s ease-out;
  /* 弹框必须有实底背景：确认弹框的 DOM 是 .modal.confirm（没有 .card 类），
     而 .modal 只负责宽度与最大高度 —— 少了这几行弹框就是透明的，底下内容会透出来。
     改动前实测 background-color = rgba(0, 0, 0, 0)，深色下几乎糊成一片。 */
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 24px 64px rgba(6, 8, 14, .42);
}
@keyframes confirm-in { from { opacity: 0; transform: translateY(-6px) scale(.98); } to { opacity: 1; transform: none; } }
.confirm-ico {
  flex: none; width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center; font-size: 19px;
  background: var(--primary-soft); color: var(--primary);
}
/* 危险操作用红底红字，和普通确认区分开 */
.modal.confirm.danger .confirm-ico { background: rgba(229, 72, 77, .12); color: var(--danger); }
.confirm-body { flex: 1; min-width: 0; }
.confirm-title { font-size: 15px; font-weight: 600; color: var(--text); margin-bottom: 6px; line-height: 1.4; }
.confirm-text { font-size: 13px; color: var(--text-sub); line-height: 1.6; overflow-wrap: anywhere; }
/* 被删除对象的名称可能很长（文件名/标题），单独一行并允许折断 */
.confirm-text strong { color: var(--text); font-weight: 600; }
.confirm-actions {
  grid-column: 1 / -1; display: flex; justify-content: flex-end; gap: 8px;
  margin-top: 18px;
}
/* 键盘可达性：弹框内的按钮有明显的焦点轮廓（原生 confirm 自带，自绘的要补上） */
.modal.confirm button:focus-visible {
  outline: 2px solid var(--primary); outline-offset: 2px;
}
/* 窄屏：图标与文字改为上下排布，按钮撑满一行更易点 */
@media (max-width: 480px) {
  .modal.confirm { flex-direction: column; gap: 10px; padding: 18px; }
  .confirm-actions { width: 100%; }
  .confirm-actions .btn { flex: 1; justify-content: center; }
}
/* ===== 响应式 ===== */
.menu-toggle { display: none; }
@media (max-width: 1080px) {
  .grid.cols-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 860px) {
  /* 小屏隐藏编辑器大纲面板，避免遮挡正文 */
  #vditor .vditor-outline { display: none !important; }
  /* 侧边栏让开顶栏（top 从 0 改为顶栏高度）：
     否则它会盖住顶栏最左侧的 ☰ 展开按钮 —— 侧边栏 z-index 30 高于顶栏 20，
     展开后按钮被压在下面，用户再点 ☰ 没反应、也没有别的地方可关，看起来就是「卡死」。 */
  .sidebar {
    top: var(--topbar-h, 61px);
    transform: translateX(-100%); transition: transform .2s ease; box-shadow: var(--shadow);
  }
  .sidebar.open { transform: none; }
  .main { margin-left: 0; }
  .menu-toggle { display: inline-flex; }
  .grid.cols-3, .grid.cols-2 { grid-template-columns: 1fr; }
  .content, .topbar { padding-left: 16px; padding-right: 16px; }
  /* 窄屏顶栏空间紧张：只留图标与温度，地区名进 title 提示 */
  .weather .w-city { display: none; }
  .topbar-clock [data-now="date"] { display: none; }
  .weather .weather-btn { padding: 0 9px; }
}

/* ===== 主题设置面板（顶栏调色按钮）===== */
.theme-panel { width: min(272px, calc(100vw - 24px)); padding: 14px; }
.theme-panel .tp-group + .tp-group { margin-top: 14px; }
.theme-panel .tp-title { font-size: 12px; color: var(--muted); margin-bottom: 8px; }

.theme-panel .segmented {
  display: flex; gap: 2px; padding: 3px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 9px;
}
.theme-panel .segmented button {
  display: block; flex: 1; width: auto; height: 28px; padding: 0 6px;
  border: none; background: none; border-radius: 6px; text-align: center;
  color: var(--text-sub); font-family: inherit; font-size: 12px; cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.theme-panel .segmented button:hover { background: transparent; color: var(--primary); }
.theme-panel .segmented button.active {
  background: var(--card); color: var(--primary); font-weight: 600;
  box-shadow: 0 1px 2px rgba(16, 24, 40, .08);
}

.theme-panel .swatches { display: grid; grid-template-columns: repeat(8, 1fr); gap: 6px; }
.theme-panel .swatch {
  position: relative; display: block; width: 100%; height: auto; aspect-ratio: 1 / 1;
  padding: 0; border: 1px solid rgba(0, 0, 0, .1); border-radius: 8px; cursor: pointer;
  transition: transform .12s ease, box-shadow .12s ease;
}
.theme-panel .swatch:hover { background: none; transform: translateY(-1px); box-shadow: 0 2px 8px rgba(16, 24, 40, .18); }
.theme-panel .swatch.active { box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--primary); }
.theme-panel .swatch .check {
  position: absolute; inset: 0; display: none; place-items: center;
  color: #fff; font-size: 12px; font-weight: 700; text-shadow: 0 1px 2px rgba(0, 0, 0, .35);
}
.theme-panel .swatch.active .check { display: grid; }

.theme-panel .tp-row {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 10px; font-size: 13px; color: var(--text-sub);
}
.theme-panel .tp-row input[type="color"] {
  width: 46px; height: 26px; padding: 2px;
  border: 1px solid var(--border); border-radius: 6px; background: var(--card); cursor: pointer;
}
.theme-panel .tp-row .hex { font-family: var(--mono); font-size: 12px; color: var(--muted); }
/* 自定义色调生效时高亮这一行（分段控件里没有对应按钮，靠它体现当前状态） */
.theme-panel .tp-row.active > span:first-child,
.theme-panel .tp-row.active .hex { color: var(--primary); font-weight: 600; }
.theme-panel .tp-foot { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border); }
.theme-panel .tp-foot .btn { display: inline-flex; justify-content: center; text-align: center; padding: 0 14px; }

/* Vditor 正文与详情页链接跟随主题色 */
#vditor .vditor-reset a, .markdown a { color: var(--primary); }

/* ===== 天气组件（顶栏右上角）===== */
.weather { flex: none; }
.topbar-clock {
  display: inline-flex; align-items: center; gap: 6px;
  flex: none; font-family: var(--mono); font-size: 12px;
  color: var(--text-sub); line-height: 1; white-space: nowrap;
}
.topbar-clock [data-now="date"] { color: var(--muted); }

.weather .weather-btn {
  display: inline-flex; align-items: center; gap: 7px;
  height: 36px; padding: 0 12px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--card); color: var(--text);
  font-family: inherit; font-size: 13px; cursor: pointer;
  transition: border-color .15s ease, color .15s ease, box-shadow .15s ease;
}
.weather .weather-btn:hover { border-color: var(--primary); color: var(--primary); }
.weather .w-ico { font-size: 16px; line-height: 1; }
.weather .w-text { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.15; }
.weather .w-temp { font-size: 13px; font-weight: 600; }
.weather .w-city {
  font-size: 11px; color: var(--muted); max-width: 108px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.weather.error .weather-btn { color: var(--muted); }
.weather.error .weather-btn:hover { color: var(--primary); border-color: var(--primary); }
.weather.loading .weather-btn { opacity: .6; }
.weather.stale .weather-btn { border-style: dashed; }
.weather.stale .w-city::after { content: ' · 偏旧'; color: var(--warning); }

/* ===== 地区选择器（个人中心）===== */
.area-picker { display: flex; flex-direction: column; gap: 8px; }
.area-picker .area-levels { display: flex; flex-direction: column; gap: 8px; }
.area-picker .area-level { display: flex; align-items: center; gap: 10px; }
.area-picker .area-level-label {
  flex: none; width: 52px; font-size: 12px; color: var(--muted); text-align: right;
}
.area-picker .area-search { gap: 8px; }
.area-picker .area-search .input { flex: 1; }
.area-picker .area-results {
  display: flex; flex-direction: column; gap: 2px;
  max-height: 232px; overflow: auto;
}
.area-picker .area-hit {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  width: 100%; padding: 7px 10px; text-align: left;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: var(--bg); color: var(--text);
  font-family: inherit; font-size: 13px; cursor: pointer;
}
.area-picker .area-hit:hover { border-color: var(--primary); color: var(--primary); }
.area-picker .area-hit-name { font-weight: 500; flex: none; }
.area-picker .area-hit-path {
  color: var(--muted); font-size: 12px; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.area-picker .area-empty { color: var(--muted); font-size: 13px; padding: 4px 0; }

/* ===== 笔记分享页（公开只读，不套后台框架）===== */
.share-wrap {
  min-height: 100vh; display: flex; flex-direction: column; align-items: center;
  padding: 40px 20px 24px; background: var(--bg);
  background-image: radial-gradient(900px 380px at 50% -8%, var(--primary-soft), transparent 70%);
}
.share-body { width: 100%; max-width: 860px; flex: 1; }
.share-head { margin-bottom: 18px; }
.share-head h1 {
  font-size: 26px; margin: 0 0 10px; line-height: 1.35; color: var(--text);
  overflow-wrap: anywhere;
}
.share-meta {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  font-size: 13px; color: var(--muted);
}
.share-card { padding: 28px 32px; }
.share-foot {
  margin-top: 28px; padding-top: 14px; width: 100%; max-width: 860px;
  border-top: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center; gap: 6px;
  font-size: 12px; color: var(--muted);
}
.share-foot .share-logo { border-radius: 5px; display: block; }

/* 链接失效提示 */
.share-invalid { padding: 56px 32px; text-align: center; }
.share-invalid-ico { font-size: 40px; line-height: 1; margin-bottom: 14px; }
.share-invalid h2 { font-size: 18px; margin: 0 0 10px; }
.share-invalid p { margin: 0 0 6px; }

/* 窄屏：正文卡片去掉过大的内边距，标题收一级 */
@media (max-width: 640px) {
  .share-wrap { padding: 24px 14px 18px; }
  .share-head h1 { font-size: 21px; }
  .share-card { padding: 18px 16px; }
  .share-invalid { padding: 40px 20px; }
}

/* ===== 音乐播放器（右下角常驻卡片 · 可拖动 · 半透明）=====
   版式参考《音乐播放器.png》：封面 + 曲名/歌手 + 进度 + 上一首/播放/下一首 + 播放顺序下拉 + 歌单按钮。
   几个要点：
   1. **半透明**：底色用主题的 --card 混成 76% 不透明度 + backdrop-filter 毛玻璃。
      因此深色主题下是深色半透明、浅色主题下是浅色半透明 —— 与截图观感一致，也不会跟环境脱节。
   2. **面板是普通子元素**（不是绝对定位）：组件盒子的大小就等于卡片大小，
      于是拖动时的夹取、位置持久化都按"看得见的卡片"来算，不会出现面板跑到屏幕外。
   3. 面板与悬浮球互斥：展开时藏起小球（.mp.open），收起时只剩小球。
   4. 层级 z-index 75：高于侧边栏(30)/顶栏(20)/回到顶部(70)，低于自绘弹框(80)与提示(90)。 */
.mp {
  position: fixed; right: 24px; bottom: 24px; z-index: 75;
  display: flex; flex-direction: column; align-items: flex-end;
}
.mp.dragging, .mp.dragging * { user-select: none; -webkit-user-select: none; }
.mp.open .mp-launch { display: none; }

/* 收起态：圆形悬浮球（内部是流动的光带 + 外圈呼吸光环） */
.mp-launch {
  position: relative; width: 48px; height: 48px; padding: 0;
  display: grid; place-items: center;
  overflow: hidden;                                   /* 把旋转的方形渐变裁成圆形 */
  border: 0; border-radius: 50%;
  background: linear-gradient(135deg, var(--primary), var(--primary-2));
  color: var(--on-primary); font-family: inherit; font-size: 20px; line-height: 1;
  cursor: grab; box-shadow: var(--shadow); touch-action: none;
  transition: transform .15s ease, box-shadow .2s ease;
}
/* 流动层：从一个比按钮大一圈的方盘旋转，保证任何角度都铺满圆内。
   光带只比底色亮一档：太亮会把图标糊掉（尤其深色主题下）。 */
.mp-launch::before {
  content: ""; position: absolute; inset: -60%;
  background: conic-gradient(from 0deg,
    var(--primary) 0deg, var(--primary-2) 62deg, color-mix(in srgb, var(--on-primary) 52%, transparent) 108deg,
    var(--primary-2) 150deg, var(--primary) 200deg, color-mix(in srgb, var(--on-primary) 26%, transparent) 250deg,
    var(--primary-2) 300deg, var(--primary) 360deg);
  animation: mp-swirl 7s linear infinite;
}
/* 柔光罩：压住流动层的对比度，也让图标始终看得清 */
.mp-launch::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(circle at 32% 26%, rgba(255, 255, 255, .30), transparent 62%),
              linear-gradient(160deg, transparent 42%, rgba(0, 0, 0, .16));
}
.mp-launch-ico {
  position: relative; z-index: 1;
  text-shadow: 0 1px 4px rgba(16, 24, 40, .5), 0 0 10px rgba(16, 24, 40, .22);
}
.mp-launch:hover { transform: translateY(-1px) scale(1.04); }
.mp-launch:active { transform: scale(.96); }
.mp-launch:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
.mp.dragging .mp-launch, .mp.dragging .mp-head { cursor: grabbing; }
/* 外圈呼吸光环：只做装饰，所以不吃鼠标事件。只在收起态（小球）显示 ——
   展开时容器就是整张卡片，光环会变成一圈套着卡片的椭圆，明显不对。 */
.mp:not(.open)::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%; pointer-events: none;
  animation: mp-halo 3.4s ease-out infinite;
}
.mp.playing .mp-launch-ico { animation: mp-beat 1.8s ease-in-out infinite; }
.mp.playing .mp-launch::before { animation-duration: 3.4s; }
.mp:not(.open).playing::before { animation-duration: 2.2s; }
.mp.uploading .mp-launch::before { animation-duration: 2.2s; }
.mp:not(.open).uploading::before { animation-duration: 1.8s; }
@keyframes mp-beat {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.18); }
}
@keyframes mp-swirl { to { transform: rotate(360deg); } }
@keyframes mp-halo {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 42%, transparent); opacity: .9; }
  70%, 100% { box-shadow: 0 0 0 12px transparent; opacity: 0; }
}

/* ===== 卡片本体 ===== */
.mp-panel {
  width: min(432px, calc(100vw - 32px));
  display: flex; flex-direction: column;
  background: color-mix(in srgb, var(--card) 76%, transparent);
  -webkit-backdrop-filter: blur(16px) saturate(1.15);
  backdrop-filter: blur(16px) saturate(1.15);
  border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
  border-radius: 14px;
  box-shadow: var(--shadow);
  overflow: hidden;
}
.mp-panel[hidden] { display: none; }

/* 标题栏：也是拖动手柄 */
.mp-head {
  display: flex; align-items: center; gap: 4px;
  padding: 7px 8px 7px 12px;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
  cursor: grab; touch-action: none;
}
.mp-head .mp-grip { color: var(--muted); font-size: 11px; letter-spacing: -1px; }
.mp-head .mp-head-title { font-size: 13px; font-weight: 600; }
.mp-head .mp-count { margin-left: auto; margin-right: 2px; font-size: 12px; color: var(--muted); }

.mp-ico-btn {
  display: grid; place-items: center;
  min-width: 28px; height: 28px; padding: 0 4px;
  border: 0; border-radius: 8px; background: none;
  color: var(--text-sub); font-family: inherit; font-size: 14px; line-height: 1;
  cursor: pointer; transition: background .15s ease, color .15s ease;
}
.mp-ico-btn:hover { background: color-mix(in srgb, var(--primary-soft) 70%, transparent); color: var(--primary); }
.mp-ico-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.mp-ico-btn .mp-svg { width: 16px; height: 16px; display: block; fill: currentColor; }
.mp-play .mp-svg { width: 17px; height: 17px; }
.mp-upload-btn:hover { color: var(--primary); }
.mp-ico-btn[aria-expanded="true"] { color: var(--primary); background: color-mix(in srgb, var(--primary-soft) 70%, transparent); }

/* 正在播放：封面 + 曲名 + 歌手 */
.mp-now { display: flex; align-items: center; gap: 12px; padding: 12px 14px 4px; }
.mp-cover {
  flex: none; width: 46px; height: 46px; border-radius: 10px;
  display: grid; place-items: center;
  background: linear-gradient(135deg, var(--primary), var(--primary-2));
  color: var(--on-primary); font-size: 22px; line-height: 1;
}
/* 播放中封面轻微起伏，收起面板后也能一眼看出在放歌 */
.mp.playing .mp-cover { animation: mp-beat 2.4s ease-in-out infinite; }
.mp-meta { min-width: 0; flex: 1; }
.mp-now-title {
  font-size: 14.5px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mp-artist {
  font-size: 12px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 进度 */
.mp-progress { padding: 8px 14px 0; }
.mp-times {
  display: flex; justify-content: space-between; margin-top: 3px;
  font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums;
}

/* 进度条与音量：原生 range 去掉默认外观，用 --p（百分比）画已播/已选部分 */
.mp-bar, .mp-range {
  -webkit-appearance: none; appearance: none;
  display: block; width: 100%; height: 4px; margin: 0;
  border-radius: 999px; cursor: pointer;
  background: linear-gradient(to right, var(--primary) var(--p, 0%),
              color-mix(in srgb, var(--border) 80%, transparent) var(--p, 0%));
}
.mp-bar::-webkit-slider-thumb, .mp-range::-webkit-slider-thumb {
  -webkit-appearance: none; width: 12px; height: 12px; border-radius: 50%;
  background: var(--card); border: 2px solid var(--primary);
  box-shadow: 0 1px 3px rgba(16, 24, 40, .3);
}
.mp-bar::-moz-range-thumb, .mp-range::-moz-range-thumb {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--card); border: 2px solid var(--primary);
}
.mp-bar::-moz-range-track, .mp-range::-moz-range-track {
  height: 4px; border-radius: 999px; background: color-mix(in srgb, var(--border) 80%, transparent);
}

/* 控制行：上一首 / 播放 / 下一首 —— 右侧是播放顺序与歌单（与截图一致） */
.mp-ctrl { display: flex; align-items: center; gap: 4px; padding: 6px 12px 12px; }
.mp-ctrl .mp-play {
  min-width: 38px; height: 38px; border-radius: 50%;
  background: var(--primary); color: var(--on-primary);
}
.mp-ctrl .mp-play:hover { background: var(--primary-hover); color: var(--on-primary); }
.mp-ctrl-right { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.mp-mode-select {
  height: 28px; max-width: 108px; padding: 0 4px;
  border: 1px solid color-mix(in srgb, var(--border) 80%, transparent); border-radius: 8px;
  background: color-mix(in srgb, var(--card) 55%, transparent);
  color: var(--text-sub); font-family: inherit; font-size: 12px; cursor: pointer;
}
.mp-mode-select:focus { outline: none; border-color: var(--primary); color: var(--primary); }

/* 歌单区（默认收起，点 ☰ 展开）：快速切歌 / 搜索 / 音量 / 上传进度 / 曲目列表 */
.mp-more {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px 12px 12px;
  border-top: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
}
.mp-more[hidden] { display: none; }
.mp-more .select, .mp-more .input { height: 32px; font-size: 13px; }
.mp-vol-row { display: flex; align-items: center; gap: 10px; }
.mp-vol-row .mp-range { flex: 1; height: 3px; }
.mp-vol-row .mp-range::-webkit-slider-thumb { width: 10px; height: 10px; }

.mp-list { max-height: min(38vh, 300px); overflow-y: auto; margin: 0 -4px; }
.mp-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 7px 8px; margin-bottom: 2px;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: none; color: var(--text); text-align: left;
  font-family: inherit; font-size: 13px; cursor: pointer;
}
.mp-item:hover { background: color-mix(in srgb, var(--primary-soft) 70%, transparent); color: var(--primary); }
.mp-item.active {
  background: color-mix(in srgb, var(--primary-soft) 85%, transparent); border-color: var(--primary);
  color: var(--primary); font-weight: 600;
}
.mp-item-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mp-item-size { flex: none; font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.mp-item.active .mp-item-size { color: var(--primary); }
.mp-hint { padding: 12px 8px; text-align: center; font-size: 12px; color: var(--muted); }
.mp-hint.error { color: var(--danger); cursor: pointer; }

/* 刚上传成功的曲目闪两下，便于在长列表里找到它 */
.mp-item.just-added { animation: mp-flash 1.1s ease-out 2; }
@keyframes mp-flash {
  0% { background: color-mix(in srgb, var(--primary-soft) 85%, transparent); border-color: var(--primary); }
  100% { background: transparent; border-color: transparent; }
}

/* ===== 收起后悬停悬浮球的快速切歌浮层 =====
   悬停在球上即出现，贴在球的左侧；球被拖到屏幕左边时（.qb-right）改贴右侧，
   屏幕上方放不下时（.qb-below）改为顶部对齐。 */
.mp-quickbar {
  position: absolute; right: calc(100% + 12px); bottom: 0;
  width: 268px; display: flex; flex-direction: column;
  background: color-mix(in srgb, var(--card) 86%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.1);
  backdrop-filter: blur(14px) saturate(1.1);
  color: var(--text);
  border: 1px solid color-mix(in srgb, var(--border) 72%, transparent); border-radius: var(--radius);
  box-shadow: var(--shadow); overflow: hidden;
  animation: mp-fade-in .12s ease;
}
.mp-quickbar[hidden] { display: none; }
.mp.qb-right .mp-quickbar { right: auto; left: calc(100% + 12px); }
.mp.qb-below .mp-quickbar { bottom: auto; top: 0; }
.mp-qb-head {
  display: flex; align-items: center; gap: 4px;
  padding: 7px 6px 7px 11px;
  background: color-mix(in srgb, var(--bg) 60%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
}
.mp-qb-now {
  flex: 1; min-width: 0; font-size: 12px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mp-qb-list { max-height: min(46vh, 320px); overflow-y: auto; padding: 5px; }
.mp-qb-item {
  display: block; width: 100%; padding: 6px 9px; margin-bottom: 1px;
  border: 1px solid transparent; border-radius: 6px;
  background: none; color: var(--text-sub); text-align: left;
  font-family: inherit; font-size: 12.5px; line-height: 1.5; cursor: pointer;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mp-qb-item:hover { background: color-mix(in srgb, var(--primary-soft) 70%, transparent); color: var(--primary); }
.mp-qb-item.active {
  background: color-mix(in srgb, var(--primary-soft) 85%, transparent);
  border-color: var(--primary); color: var(--primary); font-weight: 600;
}
.mp-quickbar .mp-hint { padding: 10px 6px; }
@keyframes mp-fade-in { from { opacity: 0; transform: translateX(6px); } to { opacity: 1; transform: none; } }
.mp.qb-right .mp-quickbar { animation-name: mp-fade-in-left; }
@keyframes mp-fade-in-left { from { opacity: 0; transform: translateX(-6px); } to { opacity: 1; transform: none; } }

/* ===== 上传进度区（仅管理员可见的上传入口配套）===== */
.mp-uploads {
  display: flex; flex-direction: column; gap: 7px;
  max-height: 132px; overflow-y: auto;
}
.mp-uploads[hidden] { display: none; }
.mp-up { font-size: 12px; }
.mp-up-head { display: flex; align-items: baseline; gap: 8px; }
.mp-up-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mp-up-size { flex: none; color: var(--muted); font-variant-numeric: tabular-nums; }
.mp-up-bar { height: 3px; margin: 5px 0 4px; border-radius: 999px; background: var(--border); overflow: hidden; }
.mp-up-bar > i {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--primary), var(--primary-2));
  transition: width .2s ease;
}
.mp-up-foot { display: flex; align-items: center; gap: 10px; color: var(--muted); }
.mp-up.failed .mp-up-bar > i { background: var(--danger); }
.mp-up.failed .mp-up-status { color: var(--danger); }
.mp-up-act {
  padding: 0; border: 0; background: none;
  color: var(--primary); font-family: inherit; font-size: 12px; cursor: pointer;
}
.mp-up-act:hover { text-decoration: underline; }

/* 窄屏：卡片几乎占满宽度，控件收窄 */
@media (max-width: 480px) {
  .mp { right: 14px; bottom: 14px; }
  .mp-panel { width: calc(100vw - 28px); }
  .mp-mode-select { max-width: 92px; font-size: 11px; }
  .mp-now { gap: 10px; padding: 10px 12px 2px; }
  .mp-cover { width: 40px; height: 40px; font-size: 19px; }
  .mp-ctrl { padding: 6px 10px 10px; }
  .mp-quickbar { width: min(264px, calc(100vw - 76px)); }
}
/* 矮视口：歌单区再矮一点，保证控制条始终可见 */
@media (max-height: 560px) {
  .mp-list { max-height: 30vh; }
}
@media (prefers-reduced-motion: reduce) {
  .mp-launch, .mp.playing .mp-launch-ico, .mp.playing .mp-cover { transition: none; animation: none; }
  /* 注意写全选择器：光环那条规则是 .mp:not(.open)::before，优先级比 .mp::before 高，
     只写后者是压不住它的（实测：开了"减少动效"光环还在转） */
  .mp-launch::before, .mp:not(.open)::before, .mp-item.just-added, .mp-quickbar { animation: none; }
}


/* ===== ?????????? ===== */
.writing-heat-card { overflow: hidden; }
.writing-heat-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.writing-heatmap {
  margin-top: 14px;
  display: flex; flex-direction: column; gap: 10px;
}
.wh-grid {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(7, 12px);
  grid-auto-columns: 12px;
  gap: 3px;
  overflow-x: auto;
  padding-bottom: 4px;
}
.wh-day {
  width: 12px; height: 12px; border-radius: 3px;
  background: var(--bg);
  transition: transform .12s ease;
}
.wh-day:hover { transform: scale(1.22); }
.wh-day[data-level="1"] { background: color-mix(in srgb, var(--primary) 24%, var(--card)); }
.wh-day[data-level="2"] { background: color-mix(in srgb, var(--primary) 48%, var(--card)); }
.wh-day[data-level="3"] { background: color-mix(in srgb, var(--primary) 72%, var(--card)); }
.wh-day[data-level="4"] { background: var(--primary); }
.wh-day.future { visibility: hidden; }
.wh-legend {
  display: flex; align-items: center; gap: 5px;
  color: var(--muted); font-size: 11px;
}
.wh-legend .wh-day { width: 10px; height: 10px; }

/* ===== ???????????? ===== */
.pomodoro {
  position: fixed; left: 24px; bottom: 24px; z-index: 74;
  display: flex; flex-direction: column; align-items: flex-start;
}
.pomodoro.open .pomo-launch { display: none; }
.pomo-launch {
  width: 48px; height: 48px; padding: 0;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: linear-gradient(135deg, var(--primary), var(--primary-2));
  color: var(--on-primary); font-size: 21px; line-height: 1;
  cursor: pointer; box-shadow: var(--shadow);
  transition: transform .15s ease, box-shadow .2s ease;
}
.pomo-launch:hover { transform: translateY(-1px) scale(1.04); }
.pomo-launch:active { transform: scale(.96); }
.pomo-launch:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; }
.pomodoro.running .pomo-launch-ico { display: inline-block; animation: pomo-pop 1.8s ease-in-out infinite; }
@keyframes pomo-pop {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.18); }
}

.pomo-panel {
  width: min(292px, calc(100vw - 28px));
  display: flex; flex-direction: column; gap: 12px;
  padding: 14px;
  background: color-mix(in srgb, var(--card) 82%, transparent);
  -webkit-backdrop-filter: blur(16px) saturate(1.12);
  backdrop-filter: blur(16px) saturate(1.12);
  border: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
  border-radius: 14px;
  box-shadow: var(--shadow);
}
.pomo-panel[hidden] { display: none; }
.pomo-head { display: flex; align-items: center; justify-content: space-between; }
.pomo-title { font-size: 14px; font-weight: 600; }
.pomo-icon-btn {
  width: 28px; height: 28px; padding: 0; border: 0; border-radius: 8px;
  display: grid; place-items: center; background: none;
  color: var(--text-sub); font-family: inherit; font-size: 14px; cursor: pointer;
}
.pomo-icon-btn:hover { background: var(--primary-soft); color: var(--primary); }
.pomo-modes {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 3px;
  padding: 3px; border: 1px solid var(--border); border-radius: 9px;
  background: var(--bg);
}
.pomo-modes button {
  height: 28px; padding: 0 5px; border: 0; border-radius: 6px;
  background: none; color: var(--text-sub); font-family: inherit; font-size: 12px;
  cursor: pointer;
}
.pomo-modes button:hover { color: var(--primary); }
.pomo-modes button.active { background: var(--card); color: var(--primary); font-weight: 600; }
.pomo-ring {
  position: relative; width: 132px; height: 132px; margin: 0 auto;
  display: grid; place-items: center; border-radius: 50%;
  background: conic-gradient(var(--primary) var(--p, 0%),
              color-mix(in srgb, var(--border) 70%, transparent) var(--p, 0%));
}
.pomo-ring::before {
  content: ""; position: absolute; inset: 7px; border-radius: 50%;
  background: var(--card);
}
.pomo-ring > div { position: relative; z-index: 1; text-align: center; }
.pomo-time { font-family: var(--mono); font-size: 25px; font-weight: 700; line-height: 1; }
.pomo-phase { margin-top: 5px; font-size: 12px; color: var(--muted); }
.pomo-actions { display: flex; align-items: center; justify-content: center; gap: 8px; }
.pomo-actions .btn { min-width: 52px; }
.pomo-settings {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px;
}
.pomo-settings label {
  display: flex; flex-direction: column; gap: 4px;
  color: var(--muted); font-size: 11px;
}
.pomo-settings input {
  width: 100%; height: 30px; padding: 0 6px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg); color: var(--text); font-family: inherit; font-size: 12px;
  outline: none;
}
.pomo-settings input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }

@media (max-width: 480px) {
  .pomodoro { left: 14px; bottom: 14px; }
  .pomo-panel { width: calc(100vw - 28px); }
  .pomo-ring { width: 118px; height: 118px; }
  .pomo-time { font-size: 22px; }
}
@media (prefers-reduced-motion: reduce) {
  .pomodoro.running .pomo-launch-ico { animation: none; }
  .wh-day, .pomo-launch, .pomo-ring { transition: none; }
}

