Files
FeedLite/assets/style.css
T
laoyang 974dd52367 去掉软件标签的描边;修「全部问题」列表分类标签渲染成空
两个问题:

一、两个标签中间那道「线」
  不是 CSS 分隔符 —— 是 .badge.sw(软件徽章)带 border:1px solid var(--swc-line),
  而 .badge.cat / .badge.st 都没有边框。并排显示时那道描边看起来
  就像凭空插了一条分隔线。去掉边框,三个标签统一为无边框胶囊。

二、反馈类型(Bug / 功能建议)在后台「全部问题」列表里不显示
  🔴 根因:fb_category_label() 参数是**数字 id**,内部会 (int) 化。
     而全部问题列表传的是 $t["category"](老 slug 字段,值为 bug),
     (int)bug === 0 → 函数返回空串 → 渲染出一个**空的** badge:
     标签框在、里面什么都没有,看起来就像「类型没了」。
  修法:
    - 新增 fb_category_label_by_slug($softwareId, $slug) 给老数据兜底
      (slug 在不同软件下可能重名,必须带 software_id)
    - 全部问题列表改用 category_id 优先、slug 兜底
    - 前台列表同样处理,并且**取不到名字就不渲染这个标签**,
      绝不再输出空胶囊
    - 在 fb_category_label() 的注释里写明「必须传数字 id」,
      避免下次再踩

验证:
  函数对照跑通:#4 category_id=6 → Bug;#5 category_id=7 → 功能建议;
  旧写法 fb_category_label("bug") → (空),确认这就是根因。
  浏览器实测详情页三个标签 border-top-width 全部 0px / style none,
  圆角都是 999px,描边已消除。
  前台列表两个条目分类标签分别渲染出 Bug / 功能建议,不再是空。
  7 个路由全 200。
2026-11-03 20:50:00 +08:00

936 lines
43 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* FeedLite · 轻反馈 —— 简洁、克制的基础视觉基调 */
:root{
--fg:#1f2329; --muted:#6b7280; --line:#e5e7eb; --line-strong:#d7dbe0;
--bg:#f5f6f8; --card:#ffffff; --brand:#0057B8; --brand-600:#004a9e; --brand-soft:#e8f0f9;
/* 顶栏品牌图标:与官网首页同一枚应用图标(内联,离线预览也能显示) */
--icon-mark:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAADsOAAA7DgHMtqGDAAADj0lEQVR4nO1b205TQRTdGB/UB78B0BdfRNA3NUT/QPHMHIgaP0BeMPqoog8mJqDyCfoBImJnDuCFyEWhIGiUegONimkFodYEaqpj9qEEwZbS0zOXXlaykqZNO2uvM9M9Z8/ZABkhysBy9gLhl4Dwh0B5CAj7CZQLo4iaCJtwNRLWDITVZI4tY+CMAOGvtQfnnSGwnWNuLFmBBnYAZU8NCMAvDoLlVGwseCtwAAgLGyDaZ7IZsJ3D6wdP+CEg7Jd+sdIYBytQm+bKOxVAecQAkfJngsV3rolelBXYms/EgdV/jJRTA0SpJeF1K1c/v1OdRwPYxFL8dtc+7WJ00Q5U4/S/rF2INrKLkNzeiqIkYfcBCHujXYg+hgAoixkgRBNZDHL5gU22IxraxsXdkYiYnlsUid9/hGzgGDhWRzAi6tvGXQ05mQAev1jZ2CtGp6JCN0Ymo64WpQZUNvaKSDQuTEE4GhcVXk0AD9PehCu/FsH3UW/LAbL8Aq55U2HfGJNvQOdoRJiKO8GwfAO+zi0KU/Hl+6J8AxIKUp1XoDbpBqTCp9kFsftsf/aDe2TVuX7xeXYhpRYtBrR0TikLfpmt9z6YY8DQu3mx5XiXsuC3nuh2054xBiBwe9rzYkZ0P5dLHGO9P2JtBpiCkgG0NANEQaTBbSe7xdWOyfxYAi2S0uD2Uz35YcCQpDRoXRvLDwNkpMEnb+c9bbu1GWAKSgbQ0gwQUpdAIsW69JoGNzc4oq71mW+32Epuh6dT7MNzTYNY2fUDeIss3YCOYMTXNIjV3NhCwhcDbg8pKInVpymKekmDj17O+hY8gl5XUBTdZDu+TVk/MayqLA7JgxE8jDAFqKX8tKKDEfhn7aaryqi+8p5PhWgOBiwvBzyMwHo8lqRVHY7iWO3DYXfNazscBQ88cyuUMcCmmyFlekC1Acgr7env8fEz1XpA+YDJ88WP31bq+vga39OhBbQMmtwG72p67BJf69IB2gY2haBbgG4C5T+0i9BFwqNQlI/JrnpclrIHxf6gZLN2Ifp4Hg2oKd4ZwKuSzRI8VHzBs1crDRPYWqZbkGragSNrWmb4oHZRysj6/u8lpKy8aJqmsC8yTc9grdtapl2kNMaBsoMZeged/QXbOIl9kRuC5fYQDhRQ8H3uEs8OArvJ6tztovYAckh1lB2FnGEHqt0GI9w6uoaY2GXCYkvt86iRXwDL2bOR0P4Cy8Hrhv+SooQAAAAASUVORK5CYII=");
--ok:#0f9d58; --ok-soft:#e9f7ef; --warn:#b7791f; --warn-soft:#fff8e6;
--danger:#d93025; --danger-soft:#fdecea; --shadow:0 1px 3px rgba(16,24,40,.06);
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
margin:0; background:var(--bg); color:var(--fg);
font-family:-apple-system,BlinkMacSystemFont,"HarmonyOS Sans SC","HarmonyOS Sans","PingFang SC","Helvetica Neue","Microsoft YaHei",sans-serif;
font-size:15.5px; line-height:1.75; letter-spacing:.01em;
}
.wrap{max-width:880px; margin:0 auto; padding:0 16px}
a{color:var(--brand); text-decoration:none}
a:hover{text-decoration:underline}
h1{font-size:23px; margin:0 0 8px; font-weight:700}
h2{font-size:17px; margin:0 0 12px; font-weight:700}
p{margin:8px 0}
.muted{color:var(--muted)}
.small{font-size:13px}
.dot{color:var(--line-strong); padding:0 2px}
/* ---------- 顶栏(与官网首页同一套导航样式) / 页脚 ---------- */
.topbar{
position:sticky; top:0; z-index:20;
background:rgba(255,255,255,.82);
backdrop-filter:saturate(180%) blur(14px);
-webkit-backdrop-filter:saturate(180%) blur(14px);
border-bottom:1px solid var(--line);
/* 软件抽屉是 absolute + top:100%,需要它来做定位参照,否则会跑到页面最上面 */
}
.topbar .wrap{display:flex; align-items:center; gap:14px; min-height:66px; padding-top:9px; padding-bottom:9px; position:relative; box-sizing:border-box}
/* 顶栏品牌位:**左图标 + 右文字列**两栏
*
* [📅] 同步日历反馈系统 ← 文字列
* 优秀的鸿蒙CalDav同步客户端
*
* 🔴 用户 2026-11-03:「图标应该在标题和简介的正中间…
* 让标题和它下面的简介合起来和图标高度一样,两个对齐上下。」
* ⇒ 图标的垂直中线要与**两行文字整体**的中线重合,不是只对齐第一行。
*
* ⚠️ 关键在 align-items:center 作用在「图标 vs 文字列」这一层:
* 图标是 .brand-ic,文字列是 .brand-txt(内部再上下排 title/note)。
* 以前图标和标题被包在同一个 .sw-badge 里(单行结构),
* note 挂在它下面,图标天然只能对齐第一行 —— 那种结构做不到居中。
*/
.topbar .brand-mini{display:flex; flex-direction:row; align-items:center; gap:10px; font-weight:700; font-size:17px; color:var(--fg); min-width:0; line-height:1.25}
.topbar .brand-mini:hover{text-decoration:none; color:var(--fg)}
/* 图标:固定 30×30 的方框,自身内容居中,不参与文字行高计算 */
.topbar .brand-ic{
width:30px; height:30px; flex:none;
display:flex; align-items:center; justify-content:center;
border-radius:9px; overflow:hidden;
}
.topbar .brand-ic img{width:30px; height:30px; object-fit:contain; display:block; border-radius:9px}
.topbar .brand-ic-ch{
font-size:17px; line-height:1; color:var(--swc, var(--brand)); font-weight:700;
}
/* 文字列:上下两行,自己成一组 */
.topbar .brand-txt{display:flex; flex-direction:column; justify-content:center; gap:1px; min-width:0}
.topbar .brand-title{
font-size:17px; font-weight:700; letter-spacing:.2px; line-height:1.25;
color:var(--swc, var(--brand));
overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.topbar .brand-mini-note{
font-size:12.5px; font-weight:400; color:var(--muted);
line-height:1.3;
overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
max-width:520px;
}
/* 顶栏里的软件标识:17px 字 + 32px 图标 ——
* 比「选择软件」标签(13.5px)大两号,又不至于压过内容区标题。 */
.topbar .brand-mini .sw-badge{gap:9px}
.topbar .brand-mini .sw-badge-nm{font-size:17px; font-weight:700; letter-spacing:.2px}
@media (max-width:560px){
.topbar .wrap{min-height:60px; padding-top:8px; padding-bottom:8px}
.topbar .brand-mini{font-size:15.5px; gap:8px}
.topbar .brand-ic{width:26px; height:26px}
.topbar .brand-ic img{width:26px; height:26px}
.topbar .brand-ic-ch{font-size:15px}
.topbar .brand-title{font-size:15.5px}
.topbar .brand-mini-note{font-size:11.5px; max-width:60vw}
.topbar .brand-mini .sw-badge-nm{font-size:15.5px}
.topbar .brand-mini .sw-badge-img{width:26px !important; height:26px !important}
.topbar .brand-mini .sw-badge{gap:7px}
}
/* ---------- 右上角三横线按钮 + 下拉菜单 ---------- */
.sw-toggle{
flex:none; width:38px; height:38px; padding:0; margin-left:2px;
display:inline-flex; flex-direction:column; align-items:center; justify-content:center; gap:4px;
background:transparent; border:0; border-radius:9px;
cursor:pointer;
}
.sw-toggle span{
display:block; width:18px; height:2px; border-radius:2px;
background:var(--fg);
}
.sw-toggle:hover{background:var(--brand-soft)}
.sw-toggle[aria-expanded="true"]{background:var(--brand-soft)}
/* ---------- 软件下拉菜单(右上角三横线) ----------
* 参考家书 FamilyBook 顶栏那个 popup 的做法:**内容多高就多高的小浮窗**,
* 紧贴按钮下方、宽度由内容撑开,不是铺满整屏的面板,也不加遮罩。
* 用户 2026-11-03:「不用做那么复杂,就是点了之后拉下来一个很窄的框,
* 把所有的内容都铺在上面就可以了」。
*
* ⚠️ 用过两版都不对:
* ① 宽屏横排 / 窄屏竖排两套 —— 手机上和正文撞在一起
* ② 整幅 absolute 面板 + 遮罩 —— 太重了,像侧边栏而不是下拉菜单
* 现在只有这一种形态:小浮窗,贴按钮右侧对齐。 */
.sw-panel{
position:absolute; top:calc(100% - 4px); right:12px;
z-index:60;
min-width:172px; max-width:min(280px, calc(100vw - 24px));
padding:6px;
background:var(--card);
border:1px solid var(--line);
border-radius:12px;
box-shadow:0 10px 28px -8px rgba(20,30,50,.28), 0 2px 6px rgba(20,30,50,.08);
max-height:calc(100vh - 90px);
overflow:auto;
}
/* 菜单里不再需要「选择软件」这个标题 —— 按钮本身已经说明用途 */
.sw-panel-hd{display:none}
.sw-panel .wrap{padding:0; max-width:none}
/* 一条一行,竖排 */
.sw-panel-list{display:flex; flex-direction:column; gap:1px}
.sw-item{
display:flex; align-items:center; gap:8px;
padding:8px 10px; border-radius:8px; color:var(--fg);
font-size:14px; white-space:nowrap;
border:0;
}
.sw-item:hover{background:var(--brand-soft); text-decoration:none; color:var(--fg)}
.sw-item.on{background:var(--brand-soft)}
.sw-item.on .sw-badge-nm{font-weight:700}
.sw-item .sw-badge{gap:7px}
.sw-item .sw-badge-nm{font-size:14px; font-weight:500}
.sw-item .sw-badge-img{width:18px !important; height:18px !important}
/* 「当前」标记缩成一个小圆点,别在窄框里占地方 */
.sw-item-cur{
margin-left:auto;
width:6px; height:6px; flex:none; border-radius:50%;
background:var(--brand);
font-size:0; line-height:0; overflow:hidden; text-indent:-999px;
}
.topbar .brand-text{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.topbar .logo-mark{
width:30px; height:30px; flex:none; display:block; border-radius:8px;
background-image:var(--icon-mark); background-size:cover; background-position:center;
box-shadow:var(--shadow);
}
.topbar .spacer{flex:1}
.topbar .navlink{color:var(--muted); font-size:14.5px; padding:8px 10px; border-radius:8px; white-space:nowrap}
.topbar .navlink:hover{color:var(--brand); background:var(--brand-soft); text-decoration:none}
.topbar .btn-mini{
flex:none; font-size:14.5px; font-weight:600; color:#fff; background:var(--brand);
padding:9px 18px; border-radius:999px; white-space:nowrap;
box-shadow:0 4px 14px -4px rgba(0,87,184,.55);
}
.topbar .btn-mini:hover{background:var(--brand-600); color:#fff; text-decoration:none}
.hide-sm{display:inline-block}
@media (max-width:640px){
.hide-sm{display:none}
.topbar .wrap{gap:10px}
.topbar .brand-mini{font-size:15.5px; gap:9px}
.topbar .logo-mark{width:28px; height:28px}
}
main.wrap{padding-top:24px; padding-bottom:40px; min-height:60vh}
.foot{border-top:1px solid var(--line); background:var(--card); padding:22px 0 34px; margin-top:40px}
.foot p{margin:4px 0; text-align:center; font-size:13px; color:var(--muted)}
.foot a{color:var(--muted); text-decoration:underline}
/* 版权句 + 管理后台入口:同一行居中,窄屏自动换行 */
.foot-line{display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:0 6px}
.foot-line .dot{padding:0}
/* ---------- 按钮 ---------- */
.btn{
display:inline-block; border:1px solid var(--line-strong); background:var(--card);
color:var(--fg); border-radius:9px; padding:8px 16px; font-size:14.5px;
cursor:pointer; line-height:1.4; font-family:inherit;
}
.btn:hover{border-color:var(--brand); color:var(--brand); text-decoration:none}
.btn.primary{background:var(--brand); border-color:var(--brand); color:#fff; font-weight:600}
.btn.primary:hover{background:var(--brand-600); color:#fff}
/* ---------- 页头 ---------- */
.page-head{display:flex; align-items:flex-start; gap:16px; margin:6px 0 18px}
.page-head .btn{margin-left:auto; flex:none; margin-top:4px}
/* ---------- 首页:轻反馈介绍页 ----------
* 用户 2026-11-03:首页不列问题,只做介绍 + 指路。
* 因为访客总是从某个软件过来的,他要的是「怎么进自己那个软件的反馈」,
* 而不是看别人的问题列表。 */
.home{max-width:820px; margin:0 auto; padding:8px 0 40px}
.home-hero{text-align:center; padding:26px 0 30px}
.home-hero h1{
font-size:30px; line-height:1.3; margin:0 0 12px;
letter-spacing:-.4px;
}
.home-lead{
font-size:15.5px; line-height:1.75; color:var(--muted);
margin:0 auto; max-width:600px;
}
.home-feats{
display:grid; grid-template-columns:repeat(2, minmax(0,1fr));
gap:12px; margin:0 0 34px;
}
@media (max-width:600px){ .home-feats{grid-template-columns:1fr} }
.home-feat{
background:var(--card); border:1px solid var(--line);
border-radius:12px; padding:16px 18px;
}
.home-feat-ic{font-size:20px; line-height:1; margin-bottom:8px}
.home-feat h3{margin:0 0 6px; font-size:15px; font-weight:700}
.home-feat p{margin:0; font-size:13.5px; line-height:1.7; color:var(--muted)}
.home-enter{
background:var(--card); border:1px solid var(--line);
border-radius:14px; padding:22px 24px;
}
.home-enter h2{margin:0 0 10px; font-size:17px}
.home-enter-tip{
font-size:14px; color:var(--muted); line-height:1.8; margin:0 0 16px;
display:flex; align-items:center; flex-wrap:wrap; gap:6px;
}
.home-enter-tip b{color:var(--fg); font-weight:600}
/* 小号三横线示意,让「右上角那个设置按钮」有具体形象可对照 */
.home-menu-demo{
display:inline-flex; flex-direction:column; justify-content:center; gap:2.5px;
width:22px; height:22px; padding:4px; box-sizing:border-box;
border:1px solid var(--line-strong); border-radius:6px;
background:var(--bg, #f6f8fb);
}
.home-menu-demo i{display:block; width:100%; height:1.5px; background:var(--fg); border-radius:2px}
.home-sw-list{display:flex; flex-direction:column; gap:8px}
.home-sw{
display:flex; align-items:center; gap:12px;
padding:11px 14px; border-radius:11px;
border:1px solid var(--line); background:var(--card);
color:var(--fg);
}
.home-sw:hover{
text-decoration:none; color:var(--fg);
border-color:var(--swc); background:var(--bg, #f6f8fb);
}
.home-sw-ic{
width:36px; height:36px; flex:none; border-radius:9px;
display:flex; align-items:center; justify-content:center;
font-size:22px; line-height:1;
}
.home-sw-ic img{width:36px; height:36px; object-fit:contain; display:block}
.home-sw-nm{font-size:15px; font-weight:600; color:var(--swc)}
.home-sw-go{margin-left:auto; font-size:13px; color:var(--muted); flex:none}
.home-sw:hover .home-sw-go{color:var(--swc)}
.home-enter-alt{margin:12px 0 0}
.page-head h1{margin-bottom:4px}
.page-head .muted{font-size:14px; margin:0}
/* ---------- 后台处理按钮栏 ---------- */
.act-bar{
margin:0 0 18px; padding:14px 16px;
background:var(--card); border:1px solid var(--line); border-radius:12px;
}
.act-bar-title{
font-size:12.5px; font-weight:700; letter-spacing:.5px;
color:var(--muted); text-transform:uppercase; margin-bottom:10px;
}
.act-bar-body{display:flex; flex-wrap:wrap; gap:8px; align-items:center}
.act-inline{display:inline}
.act-btn{white-space:nowrap}
.act-btn.is-cur{
opacity:.55; cursor:default;
box-shadow:none;
}
.act-btn.ok{border-color:#b7dfc2; color:#1e7b3c}
.act-btn.ok:hover:not(:disabled){background:#f0f9f2}
.act-btn.warn{border-color:#f0dfae; color:#8a6a15}
.act-btn.warn:hover:not(:disabled){background:#fff9ec}
.act-state.on{
display:inline-block; padding:6px 12px; border-radius:99px;
font-size:12.5px; font-weight:600;
background:#f0f9f2; color:#1e7b3c; border:1px solid #b7dfc2;
}
.act-hint{
margin-left:auto; font-size:12.5px; color:var(--muted);
}
@media (max-width:560px){
.act-hint{margin-left:0; flex-basis:100%}
}
.act-note{
margin-top:14px; padding-top:14px; border-top:1px dashed var(--line);
}
/* ---------- 软件标识:图标 + 名字(多软件区分的主视觉) ----------
* 🔴 一律不要背景色:图标本身就是一张图/一个 emoji,再垫一个色块会糊在一起,
* 反而看不清。直接「图标 + 文字」并排是识别度最高的做法。
* 邮件模板里有等价的 table 写法,两边观感要对得上。 */
.sw-badge{display:inline-flex; align-items:center; gap:7px; min-width:0; vertical-align:middle}
.sw-badge-ic{
display:inline-flex; align-items:center; justify-content:center;
flex:none; line-height:1; letter-spacing:0;
background:none; border:0; box-shadow:none;
}
.sw-badge-nm{
font-weight:600; font-size:14px; color:var(--fg);
overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.sw-badge-sm .sw-badge-nm{font-size:14px}
.sw-badge-md .sw-badge-nm{font-size:16px; font-weight:600}
/* 内容区:只是软件标识,字号刻意小于顶栏标题(17px),
* 避免「上面的字比下面的小」这种主次颠倒。颜色同样跟随软件主题色。 */
.sw-badge-lg .sw-badge-nm{font-size:15px; font-weight:600; color:var(--swc, var(--fg))}
/* 顶栏主标题:比「选择软件」标签(13.5px)大两号 = 17px,且大于内容区的 15px。
* 颜色跟随软件主题色(--swc 由 PHP 内联写到 .brand-mini 上),
* 让「同步日历」「密码生成器」这些标题一眼可辨。 */
.sw-badge-brand .sw-badge-nm{font-size:17px; font-weight:700; letter-spacing:.2px; color:var(--swc, var(--fg))}
/* 页头副行:图标 + 软件名 */
/* (已删).page-sw-id —— 内容区那行软件标识已移除,
* 软件名与简介统一由顶栏承担,避免与顶栏标题重复。 */
/* 提交页顶部的软件上下文条:同样无背景色,只留一行轻分隔 */
.sw-context{
display:flex; align-items:center; gap:10px; flex-wrap:wrap;
margin:0 0 16px; padding:0 0 12px; border-bottom:1px solid var(--line);
}
.sw-context .sw-badge-nm{color:var(--fg)}
/* 后台软件编辑:图标快选 */
.icon-presets{display:flex; gap:4px; flex-wrap:wrap; margin-top:8px}
.icon-preset{
width:34px; height:34px; border:1px solid var(--line-strong); border-radius:9px;
background:var(--card); cursor:pointer; font-size:17px; line-height:1; padding:0;
display:inline-flex; align-items:center; justify-content:center;
}
.icon-preset:hover{border-color:var(--brand); background:var(--brand-soft)}
/* ---------- 软件图标(上传图片) ---------- */
/* 图标图片:外框与字符版完全一致,换图不会让布局跳动 */
/* 图标图片:不留背景、不加圆角底衬,直接贴图 */
.sw-badge-img{
display:inline-block; object-fit:contain; flex:none;
background:none; border:0; box-shadow:none;
}
.chip.on .sw-badge-img{box-shadow:0 0 0 1px rgba(255,255,255,.5)}
/* 后台图标上传行 */
.icon-up{display:flex; align-items:flex-start; gap:14px; flex-wrap:wrap; margin-top:6px}
.icon-prev{
width:56px; height:56px; flex:none; border-radius:12px; overflow:hidden;
border:1px solid var(--line); background:var(--card);
display:flex; align-items:center; justify-content:center;
}
.icon-prev img{width:100%; height:100%; object-fit:cover; display:block}
.icon-prev-ph{
width:100%; height:100%; display:flex; align-items:center; justify-content:center;
color:#fff; font-size:24px; font-weight:600;
}
.icon-up-main{flex:1; min-width:220px; display:flex; flex-direction:column}
.icon-up-main input[type=file]{font-size:13.5px; max-width:100%}
/* chip 里也不用白底反色了 —— 图标本来就没有底色 */
.chip.on .sw-badge-nm{color:#fff}
.chip .sw-badge-ic{background:none !important; color:inherit !important; box-shadow:none}
/* ---------- 主题色选择器 ---------- */
.sw-dot{
display:inline-block; width:10px; height:10px; border-radius:50%;
flex:none; margin-right:2px; vertical-align:middle;
box-shadow:0 0 0 1px rgba(0,0,0,.12);
}
.color-row{display:flex; align-items:center; gap:10px; flex-wrap:wrap}
.color-input{
width:46px; height:34px; padding:2px; border:1px solid var(--line-strong);
border-radius:9px; background:var(--card); cursor:pointer; flex:none;
}
.color-presets{display:flex; gap:6px; flex-wrap:wrap}
.color-preset{
width:26px; height:26px; border-radius:50%; border:2px solid transparent;
cursor:pointer; padding:0; flex:none; transition:transform .12s;
}
.color-preset:hover{transform:scale(1.12)}
.color-preset.on{border-color:var(--fg); box-shadow:0 0 0 2px var(--card) inset}
/* ---------- 邮件测试 ---------- */
.mail-test{
display:flex; flex-wrap:wrap; align-items:center; gap:10px;
padding:12px 14px; margin:6px 0 16px;
background:var(--card); border:1px dashed var(--line); border-radius:11px;
}
.mail-test input[type=email]{
flex:1 1 220px; min-width:180px;
border:1px solid var(--line-strong); border-radius:9px; padding:8px 10px;
font-size:14px; background:var(--card); color:var(--fg); font-family:inherit;
}
.mail-test-out{flex:1 1 100%; font-size:13px; line-height:1.6}
.mail-test-out.ok{color:var(--ok)}
.mail-test-out.err{color:#c9302c}
/* RAM 角色探测结果 */
.role-ok{
padding:8px 11px; border-radius:9px; font-size:13.5px;
background:var(--ok-soft, #eef8f0); border:1px solid #cfe8d5;
}
.role-warn{
padding:8px 11px; border-radius:9px; font-size:13.5px;
background:#fff8e6; border:1px solid #f0e0b0; color:#8a6d1f;
}
/* ---------- 表单就地校验的错误提示 ---------- */
.field.has-error > input,
.field.has-error > textarea,
.field.has-error > select,
.field.has-error .chips{
border-color:#d9534f !important;
box-shadow:0 0 0 3px rgba(217,83,79,.12) !important;
}
.field-error{
display:block; margin-top:6px; font-style:normal;
font-size:12.5px; color:#c9302c; line-height:1.5;
}
.field-error::before{content:"⚠ "; font-style:normal}
/* ---------- 后台:软件 / 分类 / 状态 ---------- */
.card-list{display:flex; flex-direction:column; gap:8px; margin-bottom:16px}
.tax-row{
display:flex; align-items:flex-start; gap:12px; flex-wrap:wrap;
padding:12px 14px; background:var(--card); border:1px solid var(--line);
border-radius:11px;
}
.tax-row.on{border-color:var(--brand); box-shadow:0 0 0 1px var(--brand) inset}
.tax-row.off{opacity:.62}
.tax-main{flex:1 1 320px; min-width:0}
.tax-name{font-weight:600; font-size:15.5px; text-decoration:none; color:var(--fg)}
.tax-name:hover{color:var(--brand)}
.tax-name.plain{font-weight:600}
.tax-slug{
display:inline-block; margin-left:8px; font-size:12px; color:var(--muted);
font-family:ui-monospace,Consolas,monospace;
}
.tax-meta{margin-left:10px; font-size:12.5px; color:var(--muted)}
.tax-note{margin-top:5px; font-size:13px; color:var(--muted); line-height:1.5}
.tax-acts{display:flex; flex-wrap:wrap; gap:6px; align-items:center}
.inline-form{display:inline}
.btn.sm{padding:5px 11px; font-size:13px; border-radius:8px}
.btn.danger{border-color:#e0b4b4; color:#b4242c}
.btn.danger:hover{background:#fdf2f2; border-color:#b4242c}
.tax-form-box{
margin:18px 0 8px; border:1px solid var(--line); border-radius:11px;
background:var(--card); overflow:hidden;
}
.tax-form-box>summary{
cursor:pointer; padding:12px 14px; font-weight:600; font-size:14.5px;
background:var(--bg-soft, #f7f8fa); user-select:none;
}
.tax-form-box>summary:hover{color:var(--brand)}
.tax-form-box[open]>summary{border-bottom:1px solid var(--line)}
.sm-form{padding:14px; margin:0}
.sm-form .field{margin-bottom:10px}
/* ---------- 软件切换(一级) ---------- */
.software-bar{
display:flex; flex-wrap:wrap; align-items:center; gap:8px;
margin-bottom:14px; padding-bottom:14px; border-bottom:1px solid var(--line);
}
.software-bar .sw-label{font-size:13.5px; color:var(--muted); font-weight:600}
.software-bar .chips{margin-bottom:0}
/* ---------- 筛选(二级:分类 / 状态) ---------- */
.filters{margin-bottom:16px}
.chips{display:flex; flex-wrap:wrap; gap:8px; margin-bottom:12px}
.chip{
padding:5px 13px; border-radius:999px; background:var(--card);
border:1px solid var(--line); font-size:13.5px; color:var(--fg);
}
.chip:hover{border-color:var(--brand); color:var(--brand); text-decoration:none}
.chip.on{background:var(--brand); border-color:var(--brand); color:#fff; font-weight:600}
.filter-row{display:flex; flex-wrap:wrap; gap:8px}
.filter-row select,.filter-row input[type=search]{
border:1px solid var(--line-strong); border-radius:9px; padding:8px 10px;
font-size:14px; background:var(--card); color:var(--fg); font-family:inherit;
}
.filter-row input[type=search]{flex:1; min-width:160px}
/* ---------- 列表 ---------- */
.list{display:flex; flex-direction:column; gap:12px}
.item{
display:block; background:var(--card); border:1px solid var(--line);
border-radius:13px; padding:15px 17px; box-shadow:var(--shadow); color:inherit;
}
.item:hover{border-color:var(--brand); text-decoration:none; box-shadow:0 3px 12px rgba(0,87,184,.10)}
/* 列表项:
* 行1 = 标题(顶头、单独一行)
* 行2 = 分类 / 状态 标签
* 行3 = 摘要、缩略图、作者信息
*
* 🔴 用户 2026-11-03:标签别放在标题前面。
* 以前 badges 和标题挤在同一个 flex 行里,标签占掉左边一大截,
* 标题被推到右边、长度不够就换行,很难看。
* 现在标题独占一行、从左边缘开始,标签另起一行。 */
/* ⚠️ .item-top 仍被 admin.php 的三处内部列表使用(后台待审核 / 详情头 / 操作日志)。
* 前台列表已改用 .item-head + .item-tags(标题独占一行),这里保留供后台用。 */
.item-top{display:flex; align-items:center; flex-wrap:wrap; gap:8px}
.item-head{display:flex; align-items:flex-start; gap:8px}
.item-title{font-weight:600; font-size:16px; flex:1; min-width:0; line-height:1.45; word-break:break-word}
.item-tags{display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:7px}
.item-ex{color:var(--muted); font-size:14px; margin:8px 0 8px; word-break:break-word}
.item-meta{display:flex; flex-wrap:wrap; align-items:center; gap:6px; font-size:13px; color:var(--muted)}
.item-meta .who{color:#3a424d; font-weight:600}
/* 带 token 回复时展示只读身份(昵称 + 邮箱) */
.reply-identity{
display:flex; align-items:center; flex-wrap:wrap; gap:8px;
padding:9px 12px; border-radius:9px;
background:var(--bg, #f6f8fb); border:1px solid var(--line);
font-size:14px;
}
.reply-identity-nm{font-weight:600; color:var(--fg)}
.reply-identity-mail{
color:var(--muted); font-size:13px;
padding:1px 8px; border-radius:99px; background:var(--card);
border:1px solid var(--line);
}
/* 提交人凭 token 看自己未公开反馈时的提示条 */
.owner-note{
display:flex; flex-direction:column; gap:4px;
margin:0 0 16px; padding:12px 14px;
background:var(--warn-soft, #fff8e6);
border:1px solid #f0d9a8; border-left:3px solid #d99b1f;
border-radius:10px; font-size:13.5px; line-height:1.65;
color:#6b5313;
}
.owner-note b{font-size:14px; color:#5a4610}
/* ---------- 后台「待审核」列表 ----------
* 列表式:一屏能看多条,右侧固定一个「通过并公开」。
* 详情/关闭说明留在管理页里填,列表页不塞表单。 */
.plist{display:flex; flex-direction:column; gap:10px}
.prow{
display:flex; align-items:flex-start; gap:16px;
background:var(--card); border:1px solid var(--line);
border-radius:12px; padding:13px 16px;
}
.prow:hover{border-color:var(--line-strong)}
.prow-main{flex:1; min-width:0}
/* 后台待审核条目:标题顶头独占一行 → 标签行 → 摘要 → 作者信息
* ⚠️ .prow-top 仍被「操作日志」那处复用(日志条目只有动作+编号,单行更合适),
* 所以这里保留它,另外新增 .prow-head / .prow-tags 给反馈条目用。 */
.prow-top{display:flex; align-items:center; flex-wrap:wrap; gap:8px}
.prow-head{display:flex; align-items:flex-start; gap:8px}
.prow-tags{display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:7px}
.prow-title{
font-weight:600; font-size:15.5px; color:var(--fg);
flex:1; min-width:0; word-break:break-word; line-height:1.45;
}
.prow-title:hover{color:var(--brand); text-decoration:underline}
.prow-ex{
color:var(--muted); font-size:13.5px; margin:6px 0;
word-break:break-word; display:-webkit-box; -webkit-line-clamp:2;
-webkit-box-orient:vertical; overflow:hidden;
}
.prow-meta{display:flex; flex-wrap:wrap; align-items:center; gap:6px; font-size:12.5px; color:var(--muted)}
.prow-meta .who{color:#3a424d; font-weight:600}
.prow-act{flex:none; padding-top:2px}
.prow-act .btn{white-space:nowrap}
@media (max-width:600px){
.prow{flex-direction:column; gap:10px}
.prow-act{align-self:flex-start}
}
/* 问题编号:便于按 id 逐条跟进与引用 */
.item-id{
flex:none; font-size:12.5px; font-weight:600; color:var(--muted);
font-variant-numeric:tabular-nums; letter-spacing:.02em;
border:1px solid var(--line); border-radius:6px; padding:0 7px; line-height:1.9;
}
/* ---------- 徽标 ---------- */
.badge{
display:inline-block; font-size:12px; line-height:1.6; padding:1px 9px;
border-radius:999px; background:var(--brand-soft); color:var(--brand);
font-weight:600; white-space:nowrap;
}
.badge.st{background:#f1f3f5; color:#5b636e}
.badge.st-open{background:var(--warn-soft); color:var(--warn)}
/* 「未公开」= 还没审过,用中性灰,不要和「已关闭」混淆 */
.badge.st-hidden{background:#eef0f3; color:#6b7684}
.badge.st-doing{background:var(--brand-soft); color:var(--brand)}
.badge.st-resolved{background:var(--ok-soft); color:var(--ok)}
.badge.st-closed{background:#f1f3f5; color:#8a929c}
.badge.official{background:var(--brand); color:#fff}
/* 软件徽章:比分类更"重",一眼看出属于哪个软件 */
/* 软件徽标:每个软件用自己的主题色 + 图标,方便一眼区分是哪个软件。
* 颜色由 PHP 内联写入(--swc / --swc-soft),这里只管形态。 */
.badge.sw{
display:inline-flex; align-items:center; gap:5px;
background:var(--swc-soft, #eef2f8); color:var(--swc, #2b4a74);
/* ⚠️ 不要加 border —— 用户 2026-11-03 指出「两个标签中间加个线干嘛」。
* 分类/状态标签都没有边框,只有软件标签有,并排显示时那道描边
* 看起来就像凭空插了一条分隔线。统一成无边框的胶囊。 */
font-weight:600;
padding:1px 9px 1px 6px;
}
.badge.sw .badge-sw-ic{
display:inline-flex; align-items:center; justify-content:center;
width:15px; height:15px; flex:none; line-height:1;
}
.badge.sw .badge-sw-ic img{width:15px; height:15px; display:block; object-fit:contain}
.badge.sw .badge-sw-nm{white-space:nowrap}
.badge.st-wontfix{background:#f6eef0; color:#a13c53}
/* ---------- 分页 ---------- */
.pager{display:flex; align-items:center; gap:12px; margin:22px 0 0; justify-content:center}
.pager-info{font-size:13.5px; color:var(--muted)}
/* ---------- 空态 ---------- */
.empty{
background:var(--card); border:1px dashed var(--line-strong); border-radius:13px;
padding:34px 20px; text-align:center; color:var(--muted);
}
.empty.small{padding:20px}
/* ---------- 面包屑 ---------- */
.crumbs{margin:4px 0 14px; font-size:14px}
/* ---------- 主题 / 回复 ---------- */
.subject{background:var(--card); border:1px solid var(--line); border-radius:14px; padding:20px 22px; box-shadow:var(--shadow)}
/* 详情页三段:标题(顶头独占一行)→ 标签行 → 作者信息行。
* 🔴 用户 2026-11-03:软件名/分类/状态这三个标签原来在标题前面,
* 把标题挤到右边去了。现在标题在最上面顶头,标签另起一行放下面。 */
.subject-head{display:flex; align-items:flex-start; gap:10px}
.subject-title{font-size:21px; margin:0; flex:1; min-width:0; line-height:1.4; word-break:break-word}
.subject-tags{display:flex; flex-wrap:wrap; align-items:center; gap:7px; margin:10px 0 0}
.subject-body{margin-top:14px; white-space:normal; word-break:break-word; line-height:1.85}
.subject-body br{content:""}
.replies{margin-top:22px}
.reply{
background:var(--card); border:1px solid var(--line); border-left:3px solid var(--line-strong);
border-radius:11px; padding:13px 16px; margin-bottom:11px;
}
.reply.admin{border-left-color:var(--brand); background:linear-gradient(180deg,var(--brand-soft),var(--card) 42%)}
.reply-head{display:flex; align-items:center; gap:8px; font-size:13px; color:var(--muted); margin-bottom:6px}
.reply-head .who{font-weight:600; color:#3a424d; font-size:14px}
.reply-body{word-break:break-word; line-height:1.8}
/* ---------- 表单 ---------- */
/* 提交页容器。
* 🔴 原来只有 max-width:640px,**没有居中** —— 在 880px 的内容区里,
* 表单贴左边、右侧空出 240px 白,看起来像"页面缺了一块"。
* 用户 2026-11-03 指出这一点。现在:加 margin 居中,宽度放到 720px,
* 既不至于像正文那么宽(长行难读),也不会显得抠掉一块。 */
.narrow{max-width:720px; margin-left:auto; margin-right:auto}
/* ---------- 提交成功页 ----------
* 用户 2026-11-03:提交完不要跳走,要给回执 + 凭据 + 后续去处。 */
.submitted{
background:var(--card); border:1px solid var(--line);
border-radius:16px; padding:30px 32px 26px; margin-top:14px;
box-shadow:var(--shadow);
text-align:center;
}
.submitted-ok{
width:52px; height:52px; margin:0 auto 14px; border-radius:50%;
background:var(--ok-soft, #e8f6ee); color:var(--ok, #16794a);
font-size:26px; line-height:52px; font-weight:700;
}
.submitted h1{font-size:22px; margin:0 0 10px}
.submitted-lead{
font-size:14px; line-height:1.75; color:var(--muted);
margin:0 auto 20px; max-width:520px;
}
.submitted-lead b{color:var(--fg)}
/* 凭据框:要显眼但不能吓人 —— 用中性浅底 + 等宽字,看起来像"码" */
.token-box{
text-align:left; margin:0 0 22px; padding:15px 16px;
background:var(--bg, #f6f8fb); border:1px solid var(--line);
border-radius:11px;
}
.token-box-hd{
font-size:12.5px; font-weight:700; color:var(--muted);
letter-spacing:.3px; margin-bottom:8px;
}
.token-code{
font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size:14px; font-weight:600; color:var(--fg);
padding:10px 12px; background:var(--card);
border:1px dashed var(--line-strong); border-radius:8px;
word-break:break-all; user-select:all; line-height:1.5;
}
.token-box-tip{
font-size:12.5px; line-height:1.7; color:var(--muted); margin:10px 0 0;
}
.token-box-warn{
font-size:12.5px; line-height:1.7; color:#8a5a10; margin:8px 0 0;
padding:7px 10px; background:#fff8e6; border-radius:6px;
}
.submitted-next{
font-size:13px; color:var(--muted); margin:0 0 10px; text-align:left;
}
.submitted-actions{
display:flex; flex-wrap:wrap; gap:8px; justify-content:flex-start;
margin:0 0 22px;
}
/* (已删)submitted-others / submitted-sw ——
* 成功页不再列其他软件的入口,跨软件只有顶栏三横线菜单一个入口。 */
.submitted-credit{
margin:18px 0 0; padding-top:16px; border-top:1px solid var(--line);
font-size:12.5px; color:var(--muted); text-align:left;
word-break:break-all;
}
@media (max-width:600px){
.submitted{padding:24px 18px 20px}
.submitted-actions .btn{flex:1 1 auto; text-align:center}
}
.card-form{background:var(--card); border:1px solid var(--line); border-radius:14px; padding:20px 22px; box-shadow:var(--shadow); margin-top:14px}
.field{display:block; margin-bottom:16px}
.field > span{display:block; font-size:14px; font-weight:600; margin-bottom:6px}
.field .req{color:var(--danger)}
.field .hint{font-style:normal; font-weight:400; font-size:12.5px; color:var(--muted); margin-left:6px}
.field input[type=text],.field input[type=email],.field input[type=tel],
.field input[type=password],.field textarea,.field select{
width:100%; border:1px solid var(--line-strong); border-radius:9px;
padding:9px 12px; font-size:15px; font-family:inherit; background:var(--card);
color:var(--fg); line-height:1.6;
}
.field textarea{resize:vertical; min-height:110px}
.field input:focus,.field textarea:focus,.field select:focus{
outline:none; border-color:var(--brand); box-shadow:0 0 0 3px var(--brand-soft);
}
.row2{display:grid; grid-template-columns:1fr 1fr; gap:14px}
@media (max-width:560px){ .row2{grid-template-columns:1fr} }
.captcha{margin:18px 0 0; padding:14px 16px; background:#fafbfc; border:1px solid var(--line); border-radius:11px}
.captcha .field{margin-bottom:0}
.captcha-line{display:flex; align-items:center; gap:10px; flex-wrap:wrap}
.captcha-line .c-q{
flex:1; min-width:200px; font-weight:600; color:var(--brand);
background:var(--brand-soft); border-radius:8px; padding:8px 12px;
}
.captcha-line input{flex:none; width:110px}
.captcha-line .reload{font-size:13.5px; white-space:nowrap}
.form-actions{margin-top:20px}
.form-actions .btn{padding:10px 26px; font-size:15px}
.admin-status{margin-bottom:16px}
/* 蜜罐字段:对用户不可见,但保留在 DOM 中诱捕机器人 */
.hp-field{position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden}
/* ---------- 提示条 ---------- */
.flash{border-radius:10px; padding:11px 15px; font-size:14px; margin:0 0 16px}
.flash.error{background:var(--danger-soft); border:1px solid #f6c6c1; color:#9c2b21}
.flash.ok{background:var(--ok-soft); border:1px solid #bfe5cd; color:#0b6b3d}
/* ---------- 附件上传(浏览器直传 OSS) ---------- */
.uploader-box{
margin:18px 0 0; padding:14px 16px; background:#fafbfc;
border:1px solid var(--line); border-radius:11px;
}
.uploader{border-radius:10px; transition:background .15s, box-shadow .15s}
.uploader + .uploader{margin-top:14px; padding-top:14px; border-top:1px dashed var(--line)}
.uploader.dragging{background:var(--brand-soft); box-shadow:0 0 0 2px var(--brand) inset}
.up-head{display:flex; align-items:center; gap:10px; flex-wrap:wrap}
.up-title{font-size:14px; font-weight:600}
.up-head .btn{margin-left:auto; padding:6px 14px; font-size:13.5px; flex:none}
.up-file{display:none}
.up-list{display:flex; flex-wrap:wrap; gap:9px; margin-top:10px}
.up-list:empty{display:none}
.up-item{
position:relative; display:flex; gap:10px; align-items:center; width:100%;
padding:8px 10px; border:1px solid var(--line); border-radius:10px; background:var(--card);
}
.up-thumb{
width:52px; height:52px; flex:none; border-radius:8px; overflow:hidden; background:#eef1f4;
display:flex; align-items:center; justify-content:center;
}
.up-thumb img{width:100%; height:100%; object-fit:cover; display:block}
.up-thumb-video{font-size:10px; font-weight:700; color:var(--muted); letter-spacing:.08em}
.up-info{flex:1; min-width:0}
.up-name{font-size:13.5px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.up-state{font-size:12.5px; color:var(--muted); word-break:break-word}
.up-bar{height:4px; border-radius:2px; background:#e6eaee; overflow:hidden; margin-top:5px}
.up-bar i{display:block; height:100%; width:0; background:var(--brand); transition:width .2s}
.up-item.done .up-bar{display:none}
.up-item.fail{border-color:#f6c6c1; background:var(--danger-soft)}
.up-item.fail .up-state{color:var(--danger)}
.up-del{
flex:none; border:1px solid var(--line-strong); background:var(--card); color:var(--muted);
border-radius:7px; padding:5px 10px; font-size:12.5px; cursor:pointer; font-family:inherit;
}
.up-del:hover{border-color:var(--danger); color:var(--danger)}
.up-del:disabled{opacity:.45; cursor:default}
/* ---------- 附件展示 ---------- */
/* align-items:flex-start —— 否则同行里有视频(多了标题栏)时,图片盒子会被拉伸,底部留白 */
.atts{display:flex; flex-wrap:wrap; align-items:flex-start; gap:10px; margin-top:14px}
.atts .att{
margin:0; max-width:100%; border:1px solid var(--line); border-radius:11px;
overflow:hidden; background:var(--card);
}
.atts .att-image img{display:block; width:220px; height:auto; max-height:200px; object-fit:cover}
.atts.compact .att-image img{width:150px; max-height:140px}
.atts .att-video{flex:1 1 320px; max-width:440px}
.atts .att-video video{display:block; width:100%; max-height:330px; background:#000}
.att-video-ph{
width:360px; max-width:100%; height:200px; background:#11161c; color:#8b97a5;
display:flex; align-items:center; justify-content:center; font-size:13px;
}
.atts figcaption{
display:flex; gap:8px; align-items:center; padding:6px 9px; font-size:12px; color:var(--muted);
}
.atts .att-name{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.atts .att-size{margin-left:auto; flex:none}
.thumbs{display:flex; gap:8px; margin:0 0 8px}
.thumbs img{
width:78px; height:78px; object-fit:cover; display:block;
border-radius:9px; border:1px solid var(--line);
}
.att-tag{color:var(--brand); font-weight:600}
/* ---------- 附件灯箱(点击放大 + 左右切换) ---------- */
.atts .att-image .att-lb{display:block; line-height:0; cursor:zoom-in}
.atts .att-image .att-lb:focus-visible{outline:2px solid var(--brand); outline-offset:2px}
.att-zoom{
flex:none; border:1px solid var(--line-strong); background:var(--card); color:var(--muted);
border-radius:6px; padding:2px 9px; font-size:12px; line-height:1.6; cursor:pointer; font-family:inherit;
}
.att-zoom:hover{border-color:var(--brand); color:var(--brand)}
html.lb-open,body.lb-open{overflow:hidden}
.lb{
position:fixed; inset:0; z-index:1000; background:rgba(12,14,17,.94);
display:flex; flex-direction:column; animation:lb-in .16s ease-out;
}
.lb[hidden]{display:none}
@keyframes lb-in{from{opacity:0} to{opacity:1}}
.lb-stage{flex:1; min-height:0; position:relative}
.lb-media{
position:absolute; inset:0; z-index:1; padding:48px 62px;
display:flex; align-items:center; justify-content:center;
}
.lb-media img,.lb-media video{
display:block; max-width:100%; max-height:100%; border-radius:6px;
box-shadow:0 10px 44px rgba(0,0,0,.55);
}
.lb-media video{background:#000; width:auto}
.lb-media.loading::after{
content:''; position:absolute; width:26px; height:26px; border-radius:50%;
border:3px solid rgba(255,255,255,.26); border-top-color:#fff;
animation:lb-spin .8s linear infinite;
}
@keyframes lb-spin{to{transform:rotate(360deg)}}
.lb-nav{
position:absolute; top:50%; transform:translateY(-50%); z-index:2;
width:46px; height:46px; padding:0 0 3px; border:0; border-radius:50%; cursor:pointer;
background:rgba(255,255,255,.14); color:#fff; font-size:26px; line-height:1;
display:flex; align-items:center; justify-content:center; font-family:inherit;
}
.lb-nav:hover{background:rgba(255,255,255,.32)}
.lb-nav[hidden]{display:none}
.lb-prev{left:14px}
.lb-next{right:14px}
.lb-x{
position:absolute; top:14px; right:14px; z-index:3;
width:40px; height:40px; border:0; border-radius:50%; cursor:pointer;
background:rgba(255,255,255,.14); color:#fff; font-size:17px; font-family:inherit;
}
.lb-x:hover{background:rgba(255,255,255,.32)}
.lb-bar{
flex:none; display:flex; align-items:center; gap:10px; flex-wrap:wrap;
padding:10px 18px 16px; color:#e9edf2; font-size:13.5px;
}
.lb-name{font-weight:600; max-width:58vw; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.lb-meta{color:#9aa4b0; white-space:nowrap}
.lb-orig{margin-left:auto; color:#9ec5ff; white-space:nowrap}
.lb-orig[hidden]{display:none}
@media (max-width:560px){
.lb-media{padding:40px 10px}
.lb-nav{width:38px; height:38px; font-size:22px}
.lb-prev{left:6px} .lb-next{right:6px}
.lb-name{max-width:44vw}
}
/* ---------- 深色模式 ---------- */
@media (prefers-color-scheme: dark){
:root{
--fg:#e6e8eb; --muted:#9aa2ad; --line:#2c3138; --line-strong:#3a4149;
--bg:#15181c; --card:#1c2024; --brand:#5aa2ff; --brand-soft:#1e2a3d;
--ok:#4ec98a; --ok-soft:#16301f; --warn:#e2b559; --warn-soft:#2a2517;
--danger:#ff8a80; --danger-soft:#33191a; --shadow:0 1px 3px rgba(0,0,0,.35);
}
.item-meta .who,.reply-head .who{color:#cfd4da}
.field > span{color:#e6e8eb}
.captcha{background:#21262b}
.uploader-box{background:#21262b}
.up-thumb{background:#2c3138}
.up-bar{background:#2c3138}
.up-item.fail{border-color:#5a2a2a}
.badge.st{background:#242a30; color:#a8b0ba}
.badge.st-closed{background:#242a30; color:#8a929c}
.topbar{background:rgba(21,24,28,.82)}
.topbar .navlink:hover{background:var(--brand-soft)}
.btn:hover{border-color:var(--brand)}
.reply.admin{background:linear-gradient(180deg,var(--brand-soft),var(--card) 42%)}
.flash.error{background:var(--danger-soft); border-color:#5a2a2a; color:#ffb4ab}
.flash.ok{background:var(--ok-soft); border-color:#26503a; color:#9fe3bd}
}
/* ---- 管理后台 ---- */
.tabs{display:flex; flex-wrap:wrap; gap:8px; margin:16px 0 4px; border-bottom:1px solid var(--line); padding-bottom:10px}
.tab{padding:7px 14px; border-radius:999px; font-size:14px; color:var(--muted); background:var(--card); border:1px solid var(--line)}
.tab:hover{color:var(--brand); border-color:var(--brand)}
.tab.on{background:var(--brand); border-color:var(--brand); color:#fff}
.grid2{display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:12px 16px; margin:12px 0}
.grid2 .field{margin:0}
.check{display:flex; align-items:center; gap:8px; font-size:14px; color:var(--muted); margin:8px 0}
.check input{width:16px; height:16px}
.btn.danger{border-color:#e08b84; color:#c0392b}
.btn.danger:hover{background:#fdecea}
.filters{display:flex; flex-wrap:wrap; gap:8px; margin:18px 0 4px}
.filters input[type=text]{flex:1 1 220px; min-width:180px}
.filters select{max-width:160px}
@media (max-width:640px){
.grid2{grid-template-columns:1fr}
.filters input[type=text],.filters select{width:100%; max-width:none}
}