/* FeedLite · 轻反馈 —— 简洁、克制的基础视觉基调 */ :root{ --fg:#1f2329; --muted:#6b7280; --line:#e5e7eb; --line-strong:#d7dbe0; --bg:#f5f6f8; --card:#ffffff; --brand:#0057B8; --brand-600:#004a9e; --brand-soft:#e8f0f9; /* 主题色的两档浅色,供下拉项 hover / 选中使用。 * 有软件时由 layout.php 按该软件主题色覆写;这里给默认蓝色的一套, * 保证后台、首页这类"无当前软件"的页面也有值可用。 * 为什么不用 CSS color-mix():实测它配 var(--brand) 在 Chrome 里 * 会解析成透明(oklab(0 0 0 / 0)),规则匹配上却不生效。 */ --brand-tint-1:#ecf3fa; /* hover:与白混 91% */ --brand-tint-2:#cfe0f1; /* 选中:与白混 80% */ --brand-tint-3:#b9d1ea; /* 选中+hover:与白混 72% */ /* 顶栏品牌图标:与官网首页同一枚应用图标(内联,离线预览也能显示) */ --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); /* ── 表单控件尺度(2026-11-04 统一)── * 用户:「输入框、下拉框高度太随意,一点设计感都没有。」 * 之前 padding 有 8px/9px/12px 三种,select 和 input 高度还不一样, * 并排放在一起参差不齐。现在只保留三档,全部按高度对齐: * --ctl-h-sm 32px 表格内 / 紧凑行 * --ctl-h 38px 常规表单(默认) * --ctl-h-lg 42px 主要操作区 * 高度用固定值 + line-height 居中的方式,而不是靠 padding 撑, * 这样 input / select / button 放同一行时基线必然一致。 */ --ctl-h-sm:32px; --ctl-h:38px; --ctl-h-lg:42px; --ctl-r:9px; /* 统一圆角 */ --ctl-px:12px; /* 统一左右内边距 */ --ctl-bd:1px solid var(--line-strong); --ctl-shadow:0 1px 2px rgba(16,24,40,.04); --ctl-shadow-focus:0 0 0 3px var(--brand-soft); } *{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} /* ---------- 按钮 ---------- */ /* 按钮高度与输入框严格一致(--ctl-h)。 * 🔴 原来靠 padding:8px + line-height:1.4 撑,算出来 38.3px, * 而输入框是固定 38px —— 并排时差 0.3px,放大看会有轻微的错位感。 * 改成固定 height + inline-flex 垂直居中,与控件完全同高。 */ .btn{ display:inline-flex; align-items:center; justify-content:center; height:var(--ctl-h); padding:0 16px; border:1px solid var(--line-strong); background:var(--card); color:var(--fg); border-radius:var(--ctl-r); font-size:14.5px; line-height:1; cursor:pointer; font-family:inherit; white-space:nowrap; box-shadow:var(--ctl-shadow); transition:border-color .12s, background .12s, color .12s; } .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; align-items:flex-start} /* ⚠️ 不要在这里给 input[type=file] 设任何样式 —— * 它已被 .file-btn 视觉隐藏(clip),设 max-width/font-size 之类 * 会把它从"视觉隐藏"变成"露出一个小方块",反而破坏新按钮外观。 */ /* 上传状态提示:选中文件后立刻告诉用户「选到了什么、合不合格」。 * 用户 2026-11-04:「上传的图标没有显示,也没有成功/失败提示。」 */ .icon-up-tip{ display:block; margin-top:7px; font-size:12.5px; line-height:1.6; color:var(--muted); word-break:break-all; } .icon-up-tip.is-ok{color:var(--ok, #16794a)} .icon-up-tip.is-err{color:var(--danger, #c0392b); font-weight:600} /* 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; position:relative} .color-input{ width:46px; height:34px; padding:2px; border:1px solid var(--line-strong); border-radius:9px; background:var(--card); cursor:pointer; flex:none; } /* ---------- 自绘色板 ---------- * 用户 2026-11-04:「需要一个完整的色板,右侧那些默认颜色就不要了。」 * * 🔴 色板必须 position:fixed —— 后台这个表单在
* 里面,而它有 overflow:hidden。用 absolute 会被裁掉下半部分, * 连带色相条一起看不见,用户就以为"只有蓝色"(只能看到当前色相)。 * fixed 直接相对视口定位,任何祖先的 overflow 都管不到它。 * 位置由 JS 按触发按钮的坐标算出来写进 style。 */ .color-trigger{ display:inline-flex; align-items:center; gap:9px; padding:5px 12px 5px 6px; height:34px; border:1px solid var(--line-strong); border-radius:9px; background:var(--card); cursor:pointer; flex:none; font-size:13px; font-family:ui-monospace,Menlo,Consolas,monospace; color:var(--fg); } .color-trigger:hover{border-color:var(--brand)} .color-trigger-chip{ width:22px; height:22px; border-radius:6px; flex:none; background:var(--cur, #0057B8); box-shadow:inset 0 0 0 1px rgba(0,0,0,.10); } .color-trigger-hex{font-weight:600; letter-spacing:.2px} .color-trigger-caret{font-size:10px; color:var(--muted); margin-left:1px} .cp{ position:fixed; z-index:9999; width:372px; padding:14px; background:var(--card); border:1px solid var(--line-strong); border-radius:14px; box-shadow:0 12px 36px rgba(16,24,40,.24); user-select:none; box-sizing:border-box; } .cp-hd{ font-size:12.5px; font-weight:700; color:var(--muted); letter-spacing:.3px; margin:0 0 10px; } /* 画布容器:相对定位,光标挂在这里面,坐标计算就不用管面板 padding */ .cp-sv-wrap{position:relative; border-radius:9px; overflow:hidden; line-height:0} .cp-sv{ display:block; width:100%; height:200px; border-radius:9px; cursor:crosshair; } .cp-cursor{ position:absolute; width:15px; height:15px; margin:-7.5px 0 0 -7.5px; border:2px solid #fff; border-radius:50%; pointer-events:none; box-shadow:0 0 0 1px rgba(0,0,0,.4), 0 1px 3px rgba(0,0,0,.3); } /* 两条滑条:色相 + 明度 * 🔴 色相条必须**看得出是光谱** —— 用户反馈「好像只有蓝色」, * 是因为之前色相条被 overflow 裁掉了,只看到上面那片蓝色的 HSV 板。 * 所以这里把色相条做高(18px)、加圆角描边,一眼就知道"能选所有颜色"。 */ .cp-slider{margin:12px 0 0} .cp-slider input[type=range]{ -webkit-appearance:none; appearance:none; width:100%; height:18px; border-radius:9px; outline:none; cursor:pointer; display:block; box-shadow:inset 0 0 0 1px rgba(0,0,0,.10); } .cp-hue input[type=range]{ background:linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%); } .cp-val input[type=range]{background:linear-gradient(to right, #000, #fff)} .cp-slider input[type=range]::-webkit-slider-thumb{ -webkit-appearance:none; width:20px; height:20px; border-radius:50%; background:#fff; border:2px solid #fff; box-shadow:0 0 0 1px rgba(0,0,0,.45), 0 1px 4px rgba(0,0,0,.3); cursor:pointer; } .cp-slider input[type=range]::-moz-range-thumb{ width:18px; height:18px; border-radius:50%; background:#fff; border:2px solid #fff; box-shadow:0 0 0 1px rgba(0,0,0,.45); cursor:pointer; } .cp-foot{display:flex; align-items:center; gap:8px; margin-top:13px} .cp-preview{ width:30px; height:30px; border-radius:8px; flex:none; box-shadow:inset 0 0 0 1px rgba(0,0,0,.12); } .cp-hex{ flex:1; min-width:0; height:30px; padding:0 9px; border:1px solid var(--line-strong); border-radius:8px; font-family:ui-monospace,Menlo,Consolas,monospace; font-size:13px; text-transform:uppercase; background:var(--card); color:var(--fg); } .cp-ok{flex:none; height:32px !important; padding:0 14px !important; font-size:13px !important} .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; /* 边框/高度/圆角统一在「统一表单控件」段里定义,这里只管宽度 */ } .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} /* 小号按钮:基类是固定 height,这里必须显式改 height 而不是改 padding, * 否则 padding 会被 height 吃掉、按钮还是 38px 高。 */ .btn.sm{height:var(--ctl-h-sm); padding:0 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:9px; align-items:center} /* 控件的具体样式统一在上面的「统一表单控件」段里定义(避免多处覆盖打架) */ /* ---------- 列表 ---------- */ .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} /* ---------- 表单 ---------- */ /* ══════════════════════════════════════════════════════════════ * 统一表单控件(2026-11-04 重做) * * 用户:「输入框、下拉框、选择图片那个按钮、排序输入框、前端筛选的 * 输入框下拉框,都特别丑,一点设计感都没有。高度太随意。」 * * 之前的问题: * ① 样式散落在 5-6 处(.field / .filter-row / .filters / .admin 各自一套) * ② padding 有 8px / 9px / 12px 三种,select 与 input 高度不等, * 并排放一起参差不齐 * ③ select 用浏览器默认箭头,各平台样式不一,还贴边 * ④ file input 完全是原始外观 * * 现在:一套基类 .ctl + 统一变量,所有控件高度/圆角/边框/聚焦环一致。 * 高度用「固定 height + line-height 居中」而不是 padding 撑, * 保证 input / select / button 同行时基线必然对齐。 * ══════════════════════════════════════════════════════════════ */ /* --- 基类:所有文本类控件 --- * 🔴 选择器要**宽松**。之前限定在 .field / .filters 里面, * 结果任何不在这些容器里的控件(后台零散布局里的 select、input) * 都退化成浏览器默认外观,高度只有 19~21px,跟旁边 38px 的按钮并排 * 参差不齐 —— 这正是用户说的"高度太随意"。 * 现在按 type 通吃,再用 :not() 排除掉不该套的(checkbox/radio/color/file/range)。 */ input[type=text]:not(.cp-hex), input[type=email], input[type=tel], input[type=password], input[type=url], input[type=number], input[type=search], select, textarea:not(.cp-hex){ height:var(--ctl-h); padding:0 var(--ctl-px); border:var(--ctl-bd); border-radius:var(--ctl-r); background:var(--card); color:var(--fg); font-family:inherit; font-size:14.5px; line-height:calc(var(--ctl-h) - 2px); /* 减掉上下边框,垂直居中 */ box-shadow:var(--ctl-shadow); transition:border-color .12s, box-shadow .12s; -webkit-appearance:none; appearance:none; } /* 文本域不能用固定高度 */ textarea{height:auto; min-height:110px; padding:9px var(--ctl-px); line-height:1.7; resize:vertical} /* 数字框保留原生上下箭头(用户要改排序,有箭头更直观) */ input[type=number]{-moz-appearance:auto; appearance:auto; -webkit-appearance:auto} /* --- 聚焦态:统一一圈柔和的 brand 光晕 --- */ input[type=text]:focus, input[type=email]:focus, input[type=tel]:focus, input[type=password]:focus, input[type=url]:focus, input[type=number]:focus, input[type=search]:focus, select:focus, textarea:focus{ outline:none; border-color:var(--brand); box-shadow:var(--ctl-shadow-focus); } /* --- 悬停:边框略深,给出可交互暗示 --- */ input[type=text]:hover:not(:focus), input[type=email]:hover:not(:focus), input[type=tel]:hover:not(:focus), input[type=password]:hover:not(:focus), input[type=url]:hover:not(:focus), input[type=number]:hover:not(:focus), input[type=search]:hover:not(:focus), select:hover:not(:focus), textarea:hover:not(:focus){ border-color:#c3c9d1; } /* --- 下拉框:自绘箭头 --- * 原生箭头各平台差异大且贴边。这里用内联 SVG 画一个 12px 的 V 形, * 右侧留 34px 空间,再给 padding-right 避开它。 * ⚠️ 背景必须同时写 background-color 和 background-image, * 否则 -webkit-appearance:none 后底色会丢失。 */ .field select, .filter-row select, .filters select, select{ padding-right:34px; background-color:var(--card); background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%236b7280' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:right 12px center; cursor:pointer; } select:hover{ background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%231f2329' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); } /* --- 搜索框:左侧放大镜图标 --- */ .filter-row input[type=search]{flex:1; min-width:170px; padding-left:36px; background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 15 15'%3E%3Ccircle cx='6.2' cy='6.2' r='4.6' fill='none' stroke='%236b7280' stroke-width='1.5'/%3E%3Cpath d='M9.8 9.8 13.4 13.4' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:12px center; } /* 去掉 Chrome 自带的搜索框清除按钮(和我们的图标风格不搭) */ .filter-row input[type=search]::-webkit-search-decoration, .filter-row input[type=search]::-webkit-search-cancel-button{ -webkit-appearance:none; appearance:none; } /* --- 文件选择按钮:把原生丑控件重做成一个真正的按钮 --- * 用户:「选择图片那个按钮太丑。」 * 做法:隐藏原生 input(但不能 display:none,否则不可点/不可聚焦), * 用