Files
op-packages/luci-app-isp-split/htdocs/luci-static/resources/isp-split/isp-split.css
T

1301 lines
25 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.
/*
* openwrt-isp-split — LuCI 页面样式(原生 CSS,无框架、无外链)
*
* 配色原则:
* · 背景/边框/文字全部走 LuCI 主题变量(--background-color-*、--border-color-*、
* --text-color-*、--primary-color-*),深浅色主题自动跟随;
* · 只有"运营商身份色"(电信蓝/联通红/移动绿/教育网紫)是固定色相,
* 统一收敛成 --isp-accent-* 变量,主题作者可以在 theme 里覆盖;
* · 阴影只用中性黑(透明度很低),两种主题下都不会突兀。
*/
.isp-app {
--isp-card-bg: var(--background-color-high, rgba(128, 128, 128, 0.07));
--isp-card-bg-2: var(--background-color-medium, rgba(128, 128, 128, 0.12));
--isp-border: var(--border-color-low, rgba(128, 128, 128, 0.28));
--isp-border-strong: var(--border-color-medium, rgba(128, 128, 128, 0.45));
/* 次要文字用 --text-color-medium:原来的 --text-color-low 是主题里的边框/禁用色
(浅色 #bfbfbf、深色 #404040),深色主题下正文对比度只有 1.5:1,几乎看不见。 */
--isp-muted: var(--text-color-medium, rgba(128, 128, 128, 0.95));
--isp-text: var(--text-color-high, inherit);
--isp-primary: var(--primary-color-high, currentColor);
--isp-ok: var(--success-color-high, currentColor);
--isp-warn: var(--warn-color-high, currentColor);
--isp-bad: var(--error-color-high, currentColor);
--isp-accent-tel: #2f6fd0;
--isp-accent-uni: #d0362f;
--isp-accent-cmcc: #2e9e5b;
--isp-accent-cernet: #8a5cd6;
--isp-accent-other: #8a8a8a;
--isp-radius: 14px;
--isp-shadow: 0 1px 2px rgba(0, 0, 0, 0.10), 0 4px 12px rgba(0, 0, 0, 0.06);
}
.isp-app * {
box-sizing: border-box;
}
/* ---------------------------------------------------------------- 首装提示条(BUG-25) */
.isp-banner-wrap {
display: block;
}
.isp-banner {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: space-between;
gap: 12px 18px;
margin: 0 0 16px 0;
padding: 14px 16px;
border: 1px solid var(--isp-border-strong);
border-left: 5px solid var(--isp-warn);
border-radius: var(--isp-radius);
background: var(--background-color-high, rgba(128, 128, 128, 0.08));
box-shadow: var(--isp-shadow);
}
.isp-banner.is-warn {
border-left-color: var(--warn-color-high, #d9822b);
background: var(--background-color-high, rgba(128, 128, 128, 0.08));
}
.isp-banner-msg {
flex: 1 1 360px;
min-width: 240px;
color: var(--isp-text);
font-size: 0.92rem;
line-height: 1.5;
}
.isp-banner-msg strong {
display: block;
margin-bottom: 4px;
font-size: 1rem;
color: var(--warn-color-high, #b35c00);
}
.isp-banner-hint {
margin-top: 6px;
color: var(--isp-muted);
font-size: 0.84rem;
}
.isp-banner-hint code {
padding: 1px 5px;
border-radius: 4px;
background: var(--isp-card-bg-2);
font-size: 0.84rem;
}
.isp-banner-btn {
flex: 0 0 auto;
align-self: center;
white-space: nowrap;
}
.isp-banner-err {
margin-top: 6px;
color: var(--isp-bad);
font-size: 0.84rem;
line-height: 1.45;
}
.isp-banner-err:empty {
display: none;
}
@media (max-width: 600px) {
.isp-banner-btn {
width: 100%;
}
}
/* ---------------------------------------------------------------- 头部 */
.isp-hero {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
margin: 0 0 14px 0;
}
.isp-hero h2 {
margin: 0;
font-size: 1.35rem;
font-weight: 600;
color: var(--isp-text);
}
.isp-hero .isp-sub {
flex: 1 1 260px;
min-width: 200px;
color: var(--isp-muted);
font-size: 0.86rem;
line-height: 1.45;
}
.isp-toolbar {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
}
.isp-pill {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
border-radius: 999px;
background: var(--isp-card-bg-2);
border: 1px solid var(--isp-border);
font-size: 0.78rem;
color: var(--isp-muted);
white-space: nowrap;
}
.isp-pill .isp-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--isp-ok);
}
.isp-pill.is-paused .isp-dot {
background: var(--isp-warn);
}
/* 刷新中:徽标转中文「刷新中…」并让图标转圈,替代主题自带的英文 Refreshing 提示 */
.isp-pill.is-busy {
color: var(--isp-text);
border-color: var(--isp-border-strong);
}
.isp-pill .isp-ico {
display: inline-flex;
align-items: center;
}
.isp-spin {
display: inline-flex;
animation: isp-rotate 0.9s linear infinite;
transform-origin: 50% 50%;
}
@keyframes isp-rotate {
to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
.isp-spin {
animation: none;
}
}
/* ---------------------------------------------------------------- 卡片网格 */
.isp-cards {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 12px;
margin-bottom: 12px;
}
.isp-grid-2 {
display: grid;
grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
gap: 12px;
margin-bottom: 12px;
}
.isp-grid-3 {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
margin-bottom: 12px;
}
.isp-card {
position: relative;
background: var(--isp-card-bg);
border: 1px solid var(--isp-border);
border-radius: var(--isp-radius);
box-shadow: var(--isp-shadow);
padding: 14px 16px;
min-width: 0;
overflow: hidden;
}
.isp-card > h3 {
margin: 0 0 10px 0;
font-size: 0.92rem;
font-weight: 600;
color: var(--isp-muted);
display: flex;
align-items: center;
gap: 8px;
}
/* 运营商卡片:顶部身份色条 */
.isp-card-op {
padding-top: 18px;
}
.isp-card-op::before {
content: "";
position: absolute;
inset: 0 0 auto 0;
height: 4px;
background: var(--isp-accent, var(--isp-accent-other));
}
/* 卡头(方案 B,0.3.1):44px 图标左置 + 名称右排。
0.3.0 是「名称左、20px 图标右」,运营商多起来时右角的小图标很难认,
且各家 SVG 的视觉重心不一致;改成左置大图后,卡片读起来像一张名片:
先认标志,再看名字,最后看数字。 */
.isp-card-head {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 10px;
margin-bottom: 10px;
}
.isp-op-name {
font-size: 1rem;
font-weight: 600;
color: var(--isp-text);
letter-spacing: 0.02em;
/* 四列布局下内容宽 ~218px:44px 图标 + 10px 间距后,
长运营商名(ISP_TABLE 自定义标签)不要顶破卡片 */
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* 图标位:logo 与「无 logo 的 glyph 占位」共用 44×44 的盒子,
两者视觉同构——卡片并排时卡头高度、名称基线完全对齐。 */
.isp-op-ico {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 44px;
width: 44px;
height: 44px;
color: var(--isp-accent, var(--isp-accent-other));
opacity: 0.95;
}
/* 品牌 PNG(192×192 透明底):按盒子缩放,不拉伸、不裁切 */
.isp-brand-logo {
display: block;
width: 100%;
height: 100%;
object-fit: contain;
}
/* 深色主题的 logo 提亮(实测,不是"看着差不多"):
电信官方蓝 #004080 的 luminance 太低,直接贴到深色卡面 (#222) 上对比度只有
1.55:1——44px 下像蒙了一层灰。只提亮不改色相(brightness/saturate):
电信 1.55:1 → 3.31:1 联通 2.47:1 → 3.84:1 移动 2.46:1 → 5.31:1
(前一列按 PNG 原色对 #222 算,后一列从深色截图里采 logo 像素实测。)
浅色主题不动:白底上三家分别是 10.27 / 6.44 / 6.48:1,提亮反而失真。
LuCI 的 bootstrap 主题用 :root[data-darkmode="true"] 切整套变量,这里跟随
同一个属性——用户点顶栏开关或跟系统深色,都会命中。 */
[data-darkmode="true"] .isp-brand-logo {
filter: brightness(1.55) saturate(1.05);
}
/* 兜底卡:与运营商卡同构(顶部色条 + 44px 卡头 + 大数字)。
它是「未归属任何运营商」的那一格,所以身份色用中性灰而不是某家的品牌色。 */
.isp-card-fb {
--isp-accent: var(--isp-accent-other);
}
/* 网格里只有一条「没有启用的运营商」提示时,让它横跨整行,
否则会被 repeat(4) 挤成 1/4 宽的一条细缝 */
.isp-cards > .isp-empty {
grid-column: 1 / -1;
}
.isp-big {
display: inline-block;
font-size: 1.9rem;
line-height: 1.15;
font-weight: 600;
font-variant-numeric: tabular-nums;
color: var(--isp-text);
}
.isp-unit {
margin-left: 6px;
font-size: 0.76rem;
color: var(--isp-muted);
}
.isp-op-sub {
margin-top: 4px;
font-size: 0.8rem;
color: var(--isp-muted);
font-variant-numeric: tabular-nums;
}
.isp-route {
display: flex;
align-items: center;
gap: 6px;
margin-top: 10px;
font-size: 0.8rem;
color: var(--isp-muted);
}
.isp-route .isp-arrows {
display: inline-flex;
align-items: center;
gap: 2px;
font-size: 1rem;
line-height: 1;
color: var(--isp-accent, var(--isp-accent-other));
}
.isp-meter {
margin-top: 10px;
height: 6px;
border-radius: 999px;
background: var(--isp-card-bg-2);
overflow: hidden;
}
.isp-meter > i {
display: block;
height: 100%;
border-radius: 999px;
background: var(--isp-accent, var(--isp-accent-other));
opacity: 0.85;
transition: width 0.4s ease;
}
/* 零流量卡片:不画进度条(否则 0% 只剩一个孤点),改成一行占位「—」 */
.isp-meter-empty {
margin-top: 10px;
height: 6px;
display: flex;
align-items: center;
font-size: 0.8rem;
line-height: 1;
color: var(--isp-muted);
font-variant-numeric: tabular-nums;
}
/* ---------------------------------------------------------------- 列表 / 表格 */
.isp-list {
display: flex;
flex-direction: column;
gap: 8px;
margin: 0;
padding: 0;
list-style: none;
}
.isp-line {
display: grid;
grid-template-columns: 10px minmax(64px, auto) 1fr auto;
gap: 10px;
align-items: center;
padding: 8px 10px;
border-radius: 10px;
background: var(--isp-card-bg-2);
border: 1px solid transparent;
min-width: 0;
}
.isp-line .isp-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--isp-muted);
}
.isp-line.is-online .isp-dot {
background: var(--isp-ok);
box-shadow: 0 0 0 3px rgba(46, 158, 91, 0.18);
}
.isp-line.is-offline .isp-dot {
background: var(--isp-bad);
}
.isp-line .isp-line-name {
font-weight: 600;
color: var(--isp-text);
font-size: 0.88rem;
white-space: nowrap;
}
.isp-line .isp-line-track {
font-size: 0.78rem;
color: var(--isp-muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.isp-line .isp-line-pct {
font-size: 0.78rem;
color: var(--isp-muted);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.isp-table {
width: 100%;
border-collapse: collapse;
font-size: 0.82rem;
}
.isp-table th {
text-align: left;
font-weight: 500;
color: var(--isp-muted);
padding: 4px 8px 6px 0;
border-bottom: 1px solid var(--isp-border);
white-space: nowrap;
}
.isp-table td {
padding: 6px 8px 6px 0;
border-bottom: 1px solid var(--isp-border);
color: var(--isp-text);
vertical-align: middle;
}
.isp-table tr:last-child td {
border-bottom: none;
}
.isp-table .num {
text-align: right;
font-variant-numeric: tabular-nums;
}
.isp-tag {
display: inline-block;
padding: 1px 8px;
border-radius: 999px;
font-size: 0.72rem;
background: var(--isp-card-bg-2);
color: var(--isp-muted);
white-space: nowrap;
}
/* 长的说明性标签(如出线方式解释)允许换行,避免窄屏把页面撑宽。
圆角从 999px 收敛成 8px:胶囊形的半圆端在换行后会把首尾字符压在弧线上,
看起来像被截断;直角一点的说明条才容得下两行完整文字。 */
.isp-btn-row .isp-tag {
white-space: normal;
word-break: break-word;
max-width: 100%;
padding: 4px 10px;
border-radius: 8px;
line-height: 1.5;
}
.isp-tag.is-ok {
color: var(--isp-ok);
}
.isp-tag.is-warn {
color: var(--isp-warn);
}
.isp-tag.is-bad {
color: var(--isp-bad);
}
.isp-empty {
color: var(--isp-muted);
font-size: 0.84rem;
padding: 8px 0;
}
.isp-time {
display: flex;
flex-wrap: wrap;
gap: 6px 18px;
font-size: 0.82rem;
color: var(--isp-muted);
}
.isp-time .isp-tag {
margin-left: 6px;
}
.isp-time b {
color: var(--isp-text);
font-weight: 500;
font-variant-numeric: tabular-nums;
}
/* ---------------------------------------------------------------- 操作区 */
.isp-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 4px 0 10px 0;
}
.isp-actions .cbi-button {
display: inline-flex;
align-items: center;
gap: 6px;
}
.isp-ico {
display: inline-flex;
align-items: center;
justify-content: center;
}
.isp-out {
max-height: 22em;
overflow: auto;
white-space: pre-wrap;
word-break: break-all;
font-family: var(--font-mono, monospace);
font-size: 12px;
line-height: 1.5;
padding: 10px 12px;
border-radius: 10px;
border: 1px solid var(--isp-border);
background: var(--isp-card-bg);
color: var(--isp-text);
margin: 0;
}
/* 没有输出时不留空盒子:hidden 属性必须真的生效(主题里有 pre{display:block},
单靠 hidden 会被作者样式盖掉,只剩一个 22px 高的空边框)。 */
.isp-out[hidden],
.isp-out.is-empty {
display: none !important;
}
/* ---------------------------------------------------------------- 表单(配置页) */
.isp-section {
background: var(--isp-card-bg);
border: 1px solid var(--isp-border);
border-radius: var(--isp-radius);
box-shadow: var(--isp-shadow);
padding: 14px 16px 16px;
margin-bottom: 12px;
}
.isp-section > h3 {
display: flex;
align-items: center;
gap: 8px;
margin: 0 0 4px 0;
font-size: 1rem;
font-weight: 600;
color: var(--isp-text);
}
.isp-section > .isp-desc {
margin: 0 0 12px 0;
font-size: 0.82rem;
line-height: 1.5;
color: var(--isp-muted);
}
.isp-form-table {
width: 100%;
border-collapse: collapse;
font-size: 0.84rem;
}
.isp-form-table th {
text-align: left;
font-weight: 500;
color: var(--isp-muted);
padding: 0 8px 6px 0;
border-bottom: 1px solid var(--isp-border);
white-space: nowrap;
}
.isp-form-table td {
padding: 6px 8px 6px 0;
border-bottom: 1px solid var(--isp-border);
vertical-align: top;
}
.isp-form-table tr:last-child td {
border-bottom: none;
}
.isp-form-table input[type="text"],
.isp-form-table select {
width: 100%;
min-width: 90px;
}
.isp-err {
display: none;
margin-top: 3px;
font-size: 0.76rem;
line-height: 1.35;
color: var(--isp-bad);
}
.isp-err.is-on {
display: block;
}
.isp-row-actions {
display: inline-flex;
gap: 4px;
align-items: center;
white-space: nowrap;
}
.isp-icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
padding: 0;
border-radius: 8px;
border: 1px solid var(--isp-border);
background: var(--isp-card-bg-2);
color: var(--isp-text);
cursor: pointer;
}
.isp-icon-btn:hover:not(:disabled) {
border-color: var(--isp-border-strong);
}
.isp-icon-btn:disabled {
opacity: 0.4;
cursor: default;
}
.isp-icon-btn.is-danger {
color: var(--isp-bad);
}
.isp-switch {
position: relative;
display: inline-block;
width: 40px;
height: 22px;
vertical-align: middle;
}
.isp-switch input {
position: absolute;
opacity: 0;
width: 100%;
height: 100%;
margin: 0;
cursor: pointer;
}
.isp-switch span {
position: absolute;
inset: 0;
border-radius: 999px;
background: var(--isp-card-bg-2);
border: 1px solid var(--isp-border);
transition: background 0.2s ease;
pointer-events: none;
}
.isp-switch span::after {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--isp-muted);
transition: transform 0.2s ease, background 0.2s ease;
}
.isp-switch input:checked + span {
background: var(--isp-primary);
border-color: transparent;
}
.isp-switch input:checked + span::after {
transform: translateX(18px);
background: var(--background-color-high, #fff);
}
.isp-btn-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
margin-top: 10px;
}
/* 表单下方的整段说明(如「出线方式」的解释):允许换行,不加胶囊边框 */
.isp-note {
margin-top: 8px;
font-size: 0.78rem;
line-height: 1.55;
color: var(--isp-muted);
overflow-wrap: anywhere;
}
.isp-test-result {
font-size: 0.78rem;
line-height: 1.35;
color: var(--isp-muted);
min-height: 1em;
}
.isp-test-result.is-ok {
color: var(--isp-ok);
}
.isp-test-result.is-bad {
color: var(--isp-bad);
}
.isp-footer-actions {
/* 曾经是 position:sticky; bottom:0 —— 会浮在视口底部盖住 DNS 表最后两行。
保存按钮放在正常文档流里即可,页脚用一条上边框跟内容分开。 */
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 4px 0 8px 0;
padding: 12px 0 0 0;
border-top: 1px solid var(--isp-border);
background: transparent;
}
/* ---------------------------------------------------------------- 响应式 */
@media (max-width: 1100px) {
.isp-cards {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.isp-grid-3 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 820px) {
.isp-grid-2,
.isp-grid-3 {
grid-template-columns: minmax(0, 1fr);
}
}
@media (max-width: 620px) {
.isp-cards {
grid-template-columns: minmax(0, 1fr);
}
.isp-big {
font-size: 1.7rem;
}
.isp-line {
grid-template-columns: 10px 1fr;
row-gap: 2px;
}
.isp-line .isp-line-pct {
grid-column: 2;
}
/* 表单表格在窄屏改成两块:上半行是标签,下半行是输入 */
.isp-form-table thead {
display: none;
}
.isp-form-table tr {
display: block;
padding: 8px 0;
border-bottom: 1px solid var(--isp-border);
}
.isp-form-table td {
display: block;
border: none;
padding: 2px 0;
}
.isp-form-table td::before {
content: attr(data-th);
display: block;
font-size: 0.72rem;
color: var(--isp-muted);
margin-bottom: 2px;
}
}
/* lc:begin */
/* ---------------------------------------------------------------- 线路体检(0.3.0)
本段到文件末尾全部是 .lc-* 样式(体检页 / 配置页开关区),
FEATURE_LINECHECK=0 时整段物理删除。
教训(F7):标记必须包住样式体;只包一行标题注释,规则会裸奔进 0.2.3 包。 */
.lc-cards {
grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
}
.lc-card {
display: flex;
flex-direction: column;
gap: 10px;
padding: 14px 16px;
border-top: 3px solid var(--lc-accent, var(--isp-border-strong));
position: relative;
}
.lc-head {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 10px;
}
/* 与状态页同一个卡头语言(0.3.1):44px logo/glyph 左置。
映射不到运营商的 wan(isp 为空、自定义源)用线稿 glyph 占位,盒子同尺寸。 */
.lc-head-ico {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 44px;
width: 44px;
height: 44px;
}
.lc-title {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 8px;
min-width: 0;
/* 加了 44px 图标后,标题占中间的剩余宽度,评分仍然贴右 */
flex: 1 1 auto;
}
.lc-name {
font-size: 1.08rem;
font-weight: 650;
color: var(--isp-text);
letter-spacing: 0.01em;
}
.lc-dev {
font-size: 0.78rem;
color: var(--isp-muted);
background: var(--isp-card-bg-2);
border-radius: 999px;
padding: 1px 8px;
}
.lc-state {
font-size: 0.76rem;
color: var(--isp-muted);
}
.lc-state.is-on::before,
.lc-state.is-off::before {
content: "";
display: inline-block;
width: 7px;
height: 7px;
margin-right: 4px;
border-radius: 50%;
background: var(--isp-ok);
vertical-align: 1px;
}
.lc-state.is-off::before {
background: var(--isp-bad);
}
.lc-score {
display: flex;
align-items: baseline;
gap: 3px;
white-space: nowrap;
}
.lc-total {
font-size: 1.5rem;
font-weight: 700;
color: var(--isp-text);
line-height: 1;
}
.lc-max {
font-size: 0.75rem;
color: var(--isp-muted);
}
/* 评分徽标:A/B/C/D 四档,颜色只在徽标上,不铺满整张卡 */
.lc-grade {
display: inline-flex;
align-items: center;
justify-content: center;
width: 30px;
height: 30px;
margin-right: 6px;
border-radius: 9px;
font-size: 1rem;
font-weight: 700;
color: #fff;
background: var(--isp-muted);
}
.lc-grade.is-a { background: var(--isp-ok); }
.lc-grade.is-b { background: var(--isp-primary); }
.lc-grade.is-c { background: var(--isp-warn); }
.lc-grade.is-d { background: var(--isp-bad); }
.lc-kv {
display: flex;
flex-direction: column;
gap: 5px;
padding: 9px 10px;
border-radius: 10px;
background: var(--isp-card-bg-2);
}
.lc-row {
display: flex;
gap: 10px;
align-items: baseline;
font-size: 0.86rem;
line-height: 1.45;
}
.lc-key {
flex: 0 0 4.9em;
color: var(--isp-muted);
}
.lc-val {
flex: 1 1 auto;
min-width: 0;
color: var(--isp-text);
word-break: break-word;
display: flex;
flex-wrap: wrap;
gap: 6px;
align-items: baseline;
}
.lc-sub {
font-size: 0.76rem;
color: var(--isp-muted);
}
.lc-tag {
display: inline-block;
padding: 0 7px;
border-radius: 999px;
border: 1px solid var(--isp-border);
font-size: 0.72rem;
line-height: 1.6;
color: var(--isp-muted);
background: var(--isp-card-bg);
}
.lc-tag.is-ok { color: var(--isp-ok); border-color: currentColor; }
.lc-tag.is-warn { color: var(--isp-warn); border-color: currentColor; }
.lc-tag.is-bad { color: var(--isp-bad); border-color: currentColor; }
.lc-tag.is-muted { color: var(--isp-muted); }
/* 四段延迟:等宽四格,窄屏两列 */
.lc-segs {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 6px;
}
.lc-seg {
display: flex;
flex-direction: column;
gap: 1px;
padding: 7px 8px;
border: 1px solid var(--isp-border);
border-radius: 9px;
background: var(--isp-card-bg);
min-width: 0;
}
.lc-seg-label {
font-size: 0.7rem;
color: var(--isp-muted);
letter-spacing: 0.02em;
}
.lc-seg-value {
font-size: 0.95rem;
font-weight: 600;
color: var(--isp-text);
font-variant-numeric: tabular-nums;
}
.lc-line2 {
display: flex;
flex-wrap: wrap;
gap: 4px 12px;
font-size: 0.78rem;
color: var(--isp-muted);
}
.lc-advice {
display: flex;
gap: 7px;
align-items: flex-start;
padding: 8px 10px;
border-radius: 9px;
border-left: 3px solid var(--lc-accent, var(--isp-border-strong));
background: var(--isp-card-bg-2);
font-size: 0.84rem;
line-height: 1.5;
color: var(--isp-text);
}
.lc-advice .isp-ico {
flex: 0 0 auto;
margin-top: 2px;
color: var(--lc-accent, var(--isp-muted));
}
.lc-advice.is-bad {
border-left-color: var(--isp-bad);
}
.lc-toggle {
align-self: flex-start;
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 0;
border: 0;
background: none;
color: var(--isp-primary);
font-size: 0.8rem;
cursor: pointer;
}
.lc-toggle .isp-ico {
transition: transform 0.15s ease;
}
.lc-toggle.is-open .isp-ico {
transform: rotate(180deg);
}
.lc-detail {
display: flex;
flex-direction: column;
gap: 8px;
padding-top: 8px;
border-top: 1px dashed var(--isp-border);
}
.lc-detail[hidden] {
display: none !important;
}
.lc-detail h4 {
margin: 2px 0 0 0;
font-size: 0.8rem;
font-weight: 600;
color: var(--isp-muted);
}
.lc-table {
width: 100%;
border-collapse: collapse;
font-size: 0.78rem;
}
.lc-table th,
.lc-table td {
text-align: left;
padding: 4px 6px;
border-bottom: 1px solid var(--isp-border);
vertical-align: top;
word-break: break-word;
}
.lc-table th {
color: var(--isp-muted);
font-weight: 500;
white-space: nowrap;
}
.lc-table td:nth-child(3) {
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
.lc-caps {
margin: 0;
padding-left: 1.2em;
font-size: 0.78rem;
color: var(--isp-warn);
}
.lc-raw {
font-size: 0.74rem;
color: var(--isp-muted);
line-height: 1.5;
word-break: break-word;
}
.lc-meta {
font-size: 0.78rem;
color: var(--isp-muted);
margin: 0 0 10px 0;
line-height: 1.5;
}
.lc-privacy {
display: flex;
gap: 7px;
align-items: flex-start;
margin: 0 0 12px 0;
padding: 8px 10px;
border: 1px solid var(--isp-border);
border-radius: 10px;
background: var(--isp-card-bg);
font-size: 0.78rem;
color: var(--isp-muted);
line-height: 1.5;
}
.lc-privacy .isp-ico {
flex: 0 0 auto;
margin-top: 1px;
}
.lc-msg {
font-size: 0.82rem;
margin: 0 0 10px 0;
color: var(--isp-muted);
}
.lc-msg.is-info { color: var(--isp-primary); }
.lc-msg.is-ok { color: var(--isp-ok); }
.lc-msg.is-bad { color: var(--isp-bad); }
.lc-run:disabled {
opacity: 0.6;
cursor: default;
}
/* 尚未体检时的占位卡(BUG-23:没缓存也必须有一个能看的页面,不能白屏) */
.lc-placeholder {
grid-column: 1 / -1;
display: block;
padding: 18px 20px;
}
.lc-ph-head {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 8px;
font-size: 0.95rem;
color: var(--isp-text);
}
.lc-ph-head .isp-ico {
color: var(--isp-primary);
}
.lc-ph-text {
margin: 0 0 8px 0;
font-size: 0.84rem;
line-height: 1.65;
color: var(--isp-muted);
}
.lc-ph-note {
margin: 0;
font-size: 0.78rem;
line-height: 1.6;
color: var(--isp-muted);
opacity: 0.85;
}
@media (max-width: 520px) {
.lc-cards {
grid-template-columns: 1fr;
}
.lc-segs {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.lc-table thead {
display: none;
}
.lc-table tr {
display: block;
padding: 4px 0;
border-bottom: 1px solid var(--isp-border);
}
.lc-table td {
display: flex;
gap: 8px;
border: 0;
padding: 1px 0;
}
.lc-table td::before {
content: attr(data-th);
flex: 0 0 4.5em;
color: var(--isp-muted);
}
}
/* 配置页:线路体检开关区的小字/行内控件 */
.lc-hint {
font-size: 0.74rem;
color: var(--isp-muted);
line-height: 1.4;
margin-top: 2px;
}
.lc-inline {
display: flex;
align-items: center;
gap: 6px;
}
.lc-inline input[type="number"] {
max-width: 7em;
}
.lc-privacy-note {
border-left: 3px solid var(--isp-primary);
padding-left: 10px;
}
/* lc:end */