用户提的两个核心问题:
一、首页不该列全部问题
场景:这套系统是给某个软件配反馈入口、把地址贴进那软件的「意见反馈」里。
访客总是从某个软件过来的,看别的软件的问题对他没意义。
⇒ / 不带 sw 时渲染介绍页(特点介绍 + 「点右上角设置按钮选软件」+ 软件卡片)
带 sw 才是该软件的问题列表,检索/筛选/分类全在本软件范围内
二、提交后未审核,用户点不进去(真实缺陷)
邮件里给了「点击查看您刚才提交的反馈」,但 thread.php 只在 visible=1 时
才给看,未审核的一律 404 / 只看到「等待审核」静态页 —— 链接等于白给。
⇒ threads 加 track_token(32位hex = 128位熵),提交时生成:
- 邮件里所有链接一律带 ?t=<token>(不再是裸 id)
- 带对 token:可看完整详情、可回复,哪怕未公开/已关闭
- 没 token 或 token 错:对外一律 404,不泄露存在性
- 公开列表仍用 id 链接(公开内容谁都能看,用于避免重复提交)
实现细节:
- threads.track_token + 唯一索引;幂等迁移,存量数据自动回填
- fb_track_new_token / fb_track_token_ok(hash_equals 防时序探测)
/ fb_thread_viewable / fb_thread_link(thread, personal)
- thread.php 权限从 fb_thread_public 改为 fb_thread_viewable
- 带 token 看自己未公开的反馈时,顶部给「私人跟踪链接」提示条
- 回复表单与回复后跳转都保留 token,否则回复完就失去访问权
- 提交完成后直接带 token 跳详情页,不再只给静态等待页
- close 类邮件补上「查看这条反馈」按钮(原来完全没链接)
- 顶栏「全部问题」改为「问题列表」且只在选中软件后显示
- 详情/提交页「返回问题列表」按所属软件返回,不再回介绍页
- new.php 无 sw 时不再默认落到第一个软件,改为让用户先选
(默默替选会让反馈进错软件、通知发错人)
验证:首页 0 条问题卡片且未泄露任何标题、三个软件入口齐全;
未公开#4 无 token 404 / 错 token 404 / 正确 token 200 且显示完整详情
(不再卡在「等待审核」)、提示条与表单 token 都在;
已公开#2 无 token 可看;5 类邮件(回执/通过/回复/状态/关闭)链接全带 token;
两套回归各 30+ 项断言全过。
782 lines
36 KiB
CSS
782 lines
36 KiB
CSS
/* 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; height:66px; position:relative}
|
||
.topbar .brand-mini{display:flex; align-items:center; gap:10px; font-weight:700; font-size:17px; color:var(--fg); min-width:0}
|
||
.topbar .brand-mini:hover{text-decoration:none; color:var(--fg)}
|
||
/* 顶栏里的软件标识: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{height:60px}
|
||
.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{margin:0; display:flex; align-items:center}
|
||
/* 提交页顶部的软件上下文条:同样无背景色,只留一行轻分隔 */
|
||
.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)}
|
||
.item-top{display:flex; align-items:center; flex-wrap:wrap; gap:8px}
|
||
.item-title{font-weight:600; font-size:16px; flex:1; min-width:160px}
|
||
.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 看自己未公开反馈时的提示条 */
|
||
.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{display:flex; align-items:center; flex-wrap:wrap; gap:8px}
|
||
.prow-title{
|
||
font-weight:600; font-size:15.5px; color:var(--fg);
|
||
flex:1; min-width:160px; word-break:break-word;
|
||
}
|
||
.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:1px solid var(--swc-line, #cfdcee); 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)}
|
||
.subject-title{font-size:21px; margin:0; flex:1; min-width:200px}
|
||
.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}
|
||
|
||
/* ---------- 表单 ---------- */
|
||
.narrow{max-width:640px}
|
||
.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-pw{margin-top:6px}
|
||
.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}
|
||
}
|