/* ============================================================================
   frp 控制台 —— 工业运维控制台设计系统
   ----------------------------------------------------------------------------
   方向：精密 · 粗粝 · 不废话。形态由功能决定，没有一处装饰是多余的。
   参考物是机房配线架、KVM 切换器、航空仪表盘——不是消费级 SaaS。

   三条硬规则：
     1. 颜色只表达状态与品牌，绝不做装饰
     2. 数据用等宽字体 + 表格数字，方便纵向比对
     3. 硬边比圆角诚实：1px 描边、2–5px 小圆角、无玻璃拟态、无发光
   ========================================================================= */

/* ---------------------------------------------------------------- 1. 复位 */

*,
*::before,
*::after { box-sizing: border-box; }

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

body {
  min-height: 100dvh;
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { display: block; max-width: 100%; }

button, input, select, textarea { font: inherit; color: inherit; }

button { background: none; border: none; cursor: pointer; }

a { color: inherit; }

table { border-collapse: collapse; border-spacing: 0; }

ul, ol { list-style: none; padding: 0; }

[hidden] { display: none !important; }

/* ---------------------------------------------------------------- 2. 令牌 */

:root {
  /* --- 品牌：琥珀。CRT 磷光、机房告警灯、航空仪表刻度 ---
     刻意避开两条 AI 陈词滥调路线：青紫渐变、霓虹绿黑客风 */
  --brand:        oklch(0.790 0.150 73);
  --brand-bright: oklch(0.870 0.158 78);
  --brand-deep:   oklch(0.560 0.108 68);
  --brand-wash:   oklch(0.790 0.150 73 / 0.13);
  --brand-edge:   oklch(0.790 0.150 73 / 0.42);

  /* --- 中性色向品牌色相（73°）轻微偏移。哪怕 0.008 的彩度，
         也能让整个界面与品牌色产生潜意识上的统一 --- */
  --bg:          oklch(0.176 0.007 73);
  --bg-deep:     oklch(0.146 0.006 73);
  --surface:     oklch(0.217 0.008 73);
  --surface-2:   oklch(0.252 0.009 73);
  --surface-3:   oklch(0.294 0.010 73);

  --line:        oklch(0.330 0.010 73);
  --line-soft:   oklch(0.272 0.009 73);
  --line-strong: oklch(0.430 0.013 73);

  --text:        oklch(0.947 0.005 73);
  --text-2:      oklch(0.762 0.009 73);
  --text-3:      oklch(0.598 0.010 73);
  --text-4:      oklch(0.470 0.010 73);

  /* --- 状态色独立于品牌色：琥珀留给品牌与焦点，稀有才有力量 --- */
  --ok:        oklch(0.760 0.128 155);
  --ok-wash:   oklch(0.760 0.128 155 / 0.14);
  --warn:      oklch(0.810 0.140 88);
  --warn-wash: oklch(0.810 0.140 88 / 0.14);
  --danger:    oklch(0.660 0.180 27);
  --danger-wash: oklch(0.660 0.180 27 / 0.15);
  --info:      oklch(0.735 0.092 240);
  --info-wash: oklch(0.735 0.092 240 / 0.14);
  --idle:      oklch(0.520 0.008 73);
  --idle-wash: oklch(0.520 0.008 73 / 0.16);

  /* --- 字体：拉丁文用自托管字体承担，中文交给系统字体。
         界面主体是中文，而最有"性格"的位置恰好是数字、端口、ID、代码 --- */
  --font-display: 'Archivo', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei',
                  'Noto Sans CJK SC', system-ui, sans-serif;
  --font-ui: 'Saira', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei',
             'Noto Sans CJK SC', system-ui, sans-serif;
  --font-mono: 'Sometype Mono', ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo,
               Consolas, 'Liberation Mono', monospace;

  /* 固定 rem 尺度（产品 UI 不用 fluid clamp），相邻比例 ≈1.25 */
  --fs-xs:  0.75rem;    /* 12 — 微型标签 */
  --fs-sm:  0.875rem;   /* 14 — 表格数据、次要信息 */
  --fs-md:  1.0625rem;  /* 17 — 正文 */
  --fs-lg:  1.3125rem;  /* 21 — 区块标题 */
  --fs-xl:  1.625rem;   /* 26 */
  --fs-2xl: 2rem;       /* 32 */
  --fs-3xl: 2.5rem;     /* 40 */

  /* 4pt 间距尺度，语义命名而非像素命名 */
  --sp-3xs: 2px;
  --sp-2xs: 4px;
  --sp-xs:  8px;
  --sp-sm:  12px;
  --sp-md:  16px;
  --sp-lg:  24px;
  --sp-xl:  32px;
  --sp-2xl: 48px;
  --sp-3xl: 64px;

  --r-sm: 2px;
  --r:    4px;
  --r-lg: 6px;

  --shadow: 0 1px 0 oklch(1 0 0 / 0.03) inset, 0 6px 20px oklch(0 0 0 / 0.28);

  --rail: 244px;      /* 桌面侧栏宽度 */
  --rail-md: 68px;    /* 平板折叠后的图标栏 */
  --topbar: 52px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1); /* ease-out-quint，自然减速 */
}

/* 浅色主题：白天的办公室是真实场景，不是"为了安全而默认浅色" */
[data-theme='light'] {
  --brand:        oklch(0.596 0.138 66);
  --brand-bright: oklch(0.520 0.140 62);
  --brand-deep:   oklch(0.480 0.110 62);
  --brand-wash:   oklch(0.596 0.138 66 / 0.11);
  --brand-edge:   oklch(0.596 0.138 66 / 0.40);

  /* 浅色下彩度必须降低，否则显得刺眼 */
  --bg:        oklch(0.962 0.006 73);
  --bg-deep:   oklch(0.935 0.007 73);
  --surface:   oklch(0.992 0.003 73);
  --surface-2: oklch(0.968 0.005 73);
  --surface-3: oklch(0.944 0.006 73);

  --line:        oklch(0.878 0.007 73);
  --line-soft:   oklch(0.918 0.006 73);
  --line-strong: oklch(0.780 0.010 73);

  --text:   oklch(0.235 0.010 73);
  --text-2: oklch(0.418 0.010 73);
  --text-3: oklch(0.545 0.009 73);
  --text-4: oklch(0.650 0.008 73);

  --ok:        oklch(0.560 0.125 155);
  --ok-wash:   oklch(0.560 0.125 155 / 0.12);
  --warn:      oklch(0.620 0.130 82);
  --warn-wash: oklch(0.620 0.130 82 / 0.13);
  --danger:    oklch(0.545 0.190 27);
  --danger-wash: oklch(0.545 0.190 27 / 0.11);
  --info:      oklch(0.545 0.115 240);
  --info-wash: oklch(0.545 0.115 240 / 0.11);
  --idle:      oklch(0.640 0.008 73);
  --idle-wash: oklch(0.640 0.008 73 / 0.13);

  --shadow: 0 1px 0 oklch(1 0 0 / 0.6) inset, 0 4px 14px oklch(0.4 0.02 73 / 0.10);
}

/* ---------------------------------------------------------------- 3. 基础 */

body {
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  /* 深色底上的浅色字看起来更细，需要多给一点行距 */
  line-height: 1.6;
  color: var(--text);
  background-color: var(--bg);

  /* 极淡的工程网格：给纯色底一点"图纸/机房地板"的质感。
     用两层 repeating-linear-gradient，尺寸与背景一致，几乎不可见但可感知 */
  background-image:
    repeating-linear-gradient(
      0deg,
      oklch(from var(--line) l c h / 0.30) 0 1px,
      transparent 1px 32px
    ),
    repeating-linear-gradient(
      90deg,
      oklch(from var(--line) l c h / 0.30) 0 1px,
      transparent 1px 32px
    );
  background-attachment: fixed;
}

[data-theme='light'] body {
  background-image:
    repeating-linear-gradient(0deg, oklch(from var(--line) l c h / 0.45) 0 1px, transparent 1px 32px),
    repeating-linear-gradient(90deg, oklch(from var(--line) l c h / 0.45) 0 1px, transparent 1px 32px);
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.011em;
}

/* 数据一律等宽 + 表格数字，多行数字才能纵向对齐 */
.mono,
code,
kbd {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'zero' 1;
}

::selection { background: var(--brand-wash); color: var(--text); }

/* 焦点环用品牌色，且只在键盘导航时出现 */
:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
}

.skip-link {
  position: absolute;
  left: var(--sp-sm);
  top: -60px;
  z-index: 100;
  padding: var(--sp-xs) var(--sp-md);
  background: var(--brand);
  color: oklch(0.16 0.02 73);
  font-size: var(--fs-sm);
  font-weight: 600;
  border-radius: var(--r);
  transition: top 0.15s var(--ease);
}
.skip-link:focus { top: var(--sp-sm); }

/* 顶部扫描线：整个界面唯一的装饰性动效，暗示"设备通电" */
.scanline {
  position: fixed;
  inset-inline: 0;
  top: 0;
  height: 1px;
  z-index: 60;
  pointer-events: none;
  background: linear-gradient(
    90deg,
    transparent,
    var(--brand-edge) 18%,
    var(--brand) 50%,
    var(--brand-edge) 82%,
    transparent
  );
  opacity: 0.7;
}
.scanline::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, var(--brand-bright), transparent);
  width: 22%;
  animation: sweep 9s var(--ease) infinite;
}
@keyframes sweep {
  0%   { transform: translateX(-100%); opacity: 0; }
  8%   { opacity: 1; }
  55%  { opacity: 1; }
  70%  { transform: translateX(560%); opacity: 0; }
  100% { transform: translateX(560%); opacity: 0; }
}

/* ---------------------------------------------------------------- 4. 外壳 */

.root { min-height: 100dvh; }

.boot-splash {
  display: grid;
  place-content: center;
  justify-items: center;
  gap: var(--sp-md);
  min-height: 100dvh;
  color: var(--text-3);
}
.boot-mark {
  width: 34px;
  height: 34px;
  border: 2px solid var(--line-strong);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.boot-text { font-size: var(--fs-sm); letter-spacing: 0.02em; }

.shell {
  display: grid;
  grid-template-columns: var(--rail) minmax(0, 1fr);
  min-height: 100dvh;
}

/* --- 侧栏 --- */
.sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  gap: var(--sp-lg);
  padding: var(--sp-lg) var(--sp-sm) var(--sp-md);
  background: var(--bg-deep);
  border-right: 1px solid var(--line);
  z-index: 40;
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-sm);
  padding-inline: var(--sp-sm);
  min-width: 0;
}
.brand-mark {
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: var(--r);
  border: 1px solid var(--line-strong);
  background: var(--surface);
}
.brand-text { min-width: 0; }
/* 标识用 Archivo 的宽体轴，工业标识感来自这个字宽 */
.brand-name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-md);
  font-stretch: 118%;
  letter-spacing: 0.005em;
  line-height: 1.1;
  white-space: nowrap;
}
.brand-sub {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: var(--text-4);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.nav { display: flex; flex-direction: column; gap: var(--sp-3xs); }
.nav-group {
  padding: var(--sp-md) var(--sp-sm) var(--sp-2xs);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-4);
}

.nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-sm);
  padding: 9px var(--sp-sm);
  border-radius: var(--r);
  color: var(--text-2);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-decoration: none;
  transition: background 0.13s var(--ease), color 0.13s var(--ease);
}
.nav-item:hover { background: var(--surface); color: var(--text); }
.nav-item[aria-current='page'] {
  background: var(--surface-2);
  color: var(--text);
  font-weight: 600;
}
/* 选中态用左侧一道琥珀竖条——这是仪器面板的指示位，不是装饰色条 */
.nav-item[aria-current='page']::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  translate: 0 -50%;
  width: 2px;
  height: 17px;
  background: var(--brand);
  border-radius: 1px;
}
.nav-icon { width: 16px; height: 16px; flex: none; opacity: 0.9; }
.nav-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.nav-count {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: var(--text-4);
}

.sidebar-foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-sm);
  padding: var(--sp-sm);
  border-top: 1px solid var(--line-soft);
}

/* 侧栏里的服务端指示灯 */
.rail-status {
  display: flex;
  align-items: center;
  gap: var(--sp-xs);
  font-size: var(--fs-xs);
  color: var(--text-3);
}
.rail-status .mono { color: var(--text-2); }

/* --- 主区 --- */
.main {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: var(--sp-sm);
  min-height: var(--topbar);
  padding: var(--sp-xs) var(--sp-lg);
  background: oklch(from var(--bg) l c h / 0.86);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

/* 汉堡按钮只在窄屏出现——桌面端侧栏常驻，再放一个开关只会增加噪音。
   用双类选择器提高优先级，避免被后面的 .icon-btn 规则按书写顺序覆盖。 */
.icon-btn.menu-btn { display: none; }

.topbar-title {
  font-family: var(--font-display);
  font-size: var(--fs-md);
  font-weight: 700;
  letter-spacing: -0.01em;
}
.topbar-sub {
  font-size: var(--fs-xs);
  color: var(--text-3);
  font-family: var(--font-mono);
}
.topbar-spacer { flex: 1; }

.content {
  flex: 1;
  min-width: 0;
  padding: var(--sp-lg);
  display: flex;
  flex-direction: column;
  gap: var(--sp-lg);
  max-width: 1480px;
  width: 100%;
}

/* ------------------------------------------------------- 5. 面板 / 区块 */

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  /* 顶部一道极细高光，模拟仪器面板的倒角 */
  box-shadow: 0 1px 0 oklch(1 0 0 / 0.035) inset;
  min-width: 0;
}
[data-theme='light'] .panel { box-shadow: var(--shadow); }

.panel-head {
  display: flex;
  align-items: center;
  gap: var(--sp-sm);
  padding: var(--sp-sm) var(--sp-md);
  border-bottom: 1px solid var(--line-soft);
}
.panel-title {
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.005em;
}
.panel-hint {
  font-size: var(--fs-xs);
  color: var(--text-3);
}
.panel-actions { margin-left: auto; display: flex; align-items: center; gap: var(--sp-xs); }
.panel-body { padding: var(--sp-md); }
.panel-body.flush { padding: 0; }
.panel-foot {
  padding: var(--sp-sm) var(--sp-md);
  border-top: 1px solid var(--line-soft);
  display: flex;
  align-items: center;
  gap: var(--sp-sm);
  font-size: var(--fs-xs);
  color: var(--text-3);
}

/* 分区小标题：等宽大写，像仪器上的丝印标识 */
.section-label {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-4);
}

/* 页面级标题：左边一道琥珀刻度，像仪表的零位标记 */
.page-head { display: flex; align-items: flex-end; gap: var(--sp-md); flex-wrap: wrap; }
.page-title {
  font-size: var(--fs-xl);
  font-weight: 800;
  letter-spacing: -0.02em;
  padding-left: var(--sp-sm);
  border-left: 3px solid var(--brand);
  line-height: 1.15;
}
.page-desc { font-size: var(--fs-sm); color: var(--text-3); max-width: 62ch; }

/* ---------------------------------------------------------- 6. 统计读数 */

/* 刻意不做成"大数字 + 小标签 + 渐变强调"的 hero 模板，
   而是像仪器面板上并排的读数窗，用 1px 分隔线切分。

   分隔线用 item 的 border 而不是 gap+背景色：读数个数常常凑不满整行，
   用 gap+背景会在末尾留下一个和分隔线同色的"空洞"，看起来像缺了一块。 */
.readouts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}
.readout {
  background: var(--surface);
  padding: var(--sp-sm) var(--sp-md);
  border-right: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3xs);
  min-width: 0;
}
.readout-label {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-4);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.readout-value {
  font-family: var(--font-mono);
  font-size: var(--fs-xl);
  font-weight: 500;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  display: flex;
  align-items: baseline;
  gap: var(--sp-2xs);
  /* "2 分 10 秒" 这类带单位的读数必须单行显示，折行会把读数窗撑高、破坏对齐 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.readout-unit { font-size: var(--fs-xs); color: var(--text-3); font-family: var(--font-ui); }
.readout-note { font-size: var(--fs-xs); color: var(--text-3); }
.readout.is-brand .readout-value { color: var(--brand); }
.readout.is-ok .readout-value { color: var(--ok); }
.readout.is-danger .readout-value { color: var(--danger); }

/* 端口占用率条 */
.meter {
  height: 6px;
  border-radius: 1px;
  background: var(--surface-3);
  overflow: hidden;
  border: 1px solid var(--line-soft);
}
.meter-fill {
  height: 100%;
  background: var(--brand);
  transition: width 0.4s var(--ease);
}
.meter-fill.is-warn { background: var(--warn); }
.meter-fill.is-danger { background: var(--danger); }

/* ---------------------------------------------------------------- 7. 状态 */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px var(--sp-xs) 2px 6px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--surface-2);
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1.5;
  white-space: nowrap;
}
.pill::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex: none;
  background: var(--idle);
}
.pill.is-online { border-color: oklch(from var(--ok) l c h / 0.42); background: var(--ok-wash); color: var(--ok); }
.pill.is-online::before { background: var(--ok); box-shadow: 0 0 0 2px oklch(from var(--ok) l c h / 0.22); }
.pill.is-offline { color: var(--text-3); }
.pill.is-disabled { border-color: var(--line-soft); background: var(--idle-wash); color: var(--text-4); }
.pill.is-error { border-color: oklch(from var(--danger) l c h / 0.42); background: var(--danger-wash); color: var(--danger); }
.pill.is-error::before { background: var(--danger); }
.pill.is-warn { border-color: oklch(from var(--warn) l c h / 0.42); background: var(--warn-wash); color: var(--warn); }
.pill.is-warn::before { background: var(--warn); }
.pill.is-brand { border-color: var(--brand-edge); background: var(--brand-wash); color: var(--brand); }
.pill.is-brand::before { background: var(--brand); }
.pill.no-dot::before { display: none; }

/* 类型标签：纯描边，不抢状态色的注意力 */
.tag {
  display: inline-block;
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* ---------------------------------------------------------------- 8. 按钮 */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-xs);
  min-height: 34px;
  padding: 0 var(--sp-sm);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  background: var(--surface-2);
  color: var(--text);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background 0.12s var(--ease), border-color 0.12s var(--ease),
              transform 0.06s var(--ease);
}
.btn:hover { background: var(--surface-3); border-color: var(--text-4); }
/* 按下立即反馈，不等网络往返 */
.btn:active { transform: translateY(1px); }
.btn:disabled,
.btn[aria-busy='true'] { opacity: 0.5; pointer-events: none; }

.btn.is-primary {
  background: var(--brand);
  border-color: var(--brand);
  color: oklch(0.19 0.03 73);
}
.btn.is-primary:hover { background: var(--brand-bright); border-color: var(--brand-bright); }

.btn.is-ghost { background: transparent; border-color: transparent; color: var(--text-2); }
.btn.is-ghost:hover { background: var(--surface-2); color: var(--text); }

.btn.is-danger { border-color: oklch(from var(--danger) l c h / 0.5); color: var(--danger); background: transparent; }
.btn.is-danger:hover { background: var(--danger-wash); border-color: var(--danger); }

.btn.is-sm { min-height: 27px; padding: 0 var(--sp-xs); font-size: var(--fs-xs); }
.btn.is-block { width: 100%; }
.btn .btn-icon { width: 14px; height: 14px; flex: none; }

/* 按钮里的图标统一收窄一点，和 14px 的行高更协调。
   图标本身带 width/height 属性兜底，这条规则只是把尺寸调紧。 */
.btn > svg,
.btn-row > .btn > svg,
.drawer-foot .btn > svg { width: 14px; height: 14px; flex: none; }

.notice-mark > svg { width: 18px; height: 18px; }
.toast-mark > svg { width: 15px; height: 15px; }

/* 图标按钮：移动端必须保证 44px 触控目标 */
.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 1px solid transparent;
  border-radius: var(--r);
  color: var(--text-3);
  transition: background 0.12s var(--ease), color 0.12s var(--ease);
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); }
.icon-btn svg { width: 16px; height: 16px; }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--sp-xs); }

/* ---------------------------------------------------------------- 9. 表单 */

.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field-label {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-2);
  display: flex;
  align-items: baseline;
  gap: var(--sp-xs);
}
.field-req { color: var(--brand); font-size: var(--fs-xs); }
.field-hint { font-size: var(--fs-xs); color: var(--text-4); line-height: 1.45; }
.field-error { font-size: var(--fs-xs); color: var(--danger); }

.input,
.select,
.textarea {
  width: 100%;
  min-height: 36px;
  padding: 6px var(--sp-sm);
  background: var(--bg-deep);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  color: var(--text);
  font-size: var(--fs-sm);
  transition: border-color 0.12s var(--ease), box-shadow 0.12s var(--ease);
}
[data-theme='light'] .input,
[data-theme='light'] .select,
[data-theme='light'] .textarea { background: var(--surface); }

.input::placeholder, .textarea::placeholder { color: var(--text-4); }

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-wash);
}

.input.is-mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

.select {
  appearance: none;
  padding-right: var(--sp-lg);
  background-image: linear-gradient(45deg, transparent 50%, var(--text-3) 50%),
                    linear-gradient(135deg, var(--text-3) 50%, transparent 50%);
  background-position: calc(100% - 15px) 15px, calc(100% - 10px) 15px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

.textarea { min-height: 72px; resize: vertical; line-height: 1.55; }

.input[aria-invalid='true'],
.select[aria-invalid='true'] { border-color: var(--danger); }

/* 输入组：前缀/后缀贴在输入框两侧，像仪表上的单位标注 */
.input-group {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  background: var(--bg-deep);
  overflow: hidden;
  transition: border-color 0.12s var(--ease), box-shadow 0.12s var(--ease);
}
[data-theme='light'] .input-group { background: var(--surface); }
.input-group:focus-within { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-wash); }
.input-group > .input,
.input-group > .select {
  border: none;
  background: transparent;
  box-shadow: none !important;
  min-height: 34px;
}
.input-group > .select {
  background-image: none;
  padding-right: var(--sp-sm);
}
.input-affix {
  display: grid;
  place-items: center;
  padding-inline: var(--sp-xs);
  background: var(--surface-2);
  border-inline: 1px solid var(--line-soft);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-3);
  white-space: nowrap;
}
.input-affix:first-child { border-left: none; }
.input-affix:last-child { border-right: none; }
.input-group > .input:first-child { padding-left: var(--sp-sm); }

.switch { display: inline-flex; align-items: center; gap: var(--sp-xs); cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch-track {
  width: 34px;
  height: 19px;
  flex: none;
  border-radius: 10px;
  background: var(--surface-3);
  border: 1px solid var(--line-strong);
  position: relative;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease);
}
.switch-track::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--text-3);
  transition: transform 0.18s var(--ease), background 0.15s var(--ease);
}
.switch input:checked + .switch-track { background: var(--brand-wash); border-color: var(--brand); }
.switch input:checked + .switch-track::after { transform: translateX(15px); background: var(--brand); }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--brand); outline-offset: 2px; }
.switch-label { font-size: var(--fs-sm); }

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--sp-md);
}
.form-grid .span-2 { grid-column: 1 / -1; }

/* 选项卡片组：用于隧道类型这类"选一个"的场景 */
.choice-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--sp-xs);
}
.choice {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--sp-sm);
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface-2);
  cursor: pointer;
  transition: border-color 0.13s var(--ease), background 0.13s var(--ease);
}
.choice:hover { border-color: var(--line-strong); background: var(--surface-3); }
.choice input { position: absolute; opacity: 0; }
.choice:has(input:checked) { border-color: var(--brand); background: var(--brand-wash); }
.choice:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }
.choice-name { font-family: var(--font-mono); font-size: var(--fs-sm); font-weight: 600; letter-spacing: 0.04em; }
.choice-desc { font-size: var(--fs-xs); color: var(--text-3); line-height: 1.4; }

/* ---------------------------------------------------------------- 10. 列表 */

/* 用 CSS Grid 而不是 <table>：宽屏像数据表，窄屏自然重排成卡片，
   同一份标记同时服务两种形态，不用渲染两遍 */
.datalist { display: flex; flex-direction: column; }

.datarow {
  display: grid;
  /* 裸用的 .datarow 也要有个合理缺省：主体在左、次要信息在右。
     带具体列定义的 .tunnels-grid 等类在下方，会覆盖这一条。 */
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-sm);
  padding: 10px var(--sp-md);
  border-bottom: 1px solid var(--line-soft);
  min-width: 0;
}
.datarow:last-child { border-bottom: none; }
.datarow.is-head {
  padding-block: var(--sp-xs);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: var(--topbar);
  z-index: 10;
}
.datarow.is-head .cell {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-4);
}
.datarow:not(.is-head):hover { background: oklch(from var(--surface-2) l c h / 0.55); }

/* 列宽要放得下真实内容：IP:端口 约 150px，流量 "↑ 999 MB" 约 90px。
   列太窄会让用户看到 "127.0.0...." 这种没用的截断。 */
.tunnels-grid { grid-template-columns: minmax(120px, 1.5fr) minmax(142px, 1fr) minmax(120px, 1.2fr) 104px 92px 84px; }
.users-grid   { grid-template-columns: minmax(110px, 1.2fr) 74px 84px minmax(96px, 0.9fr) 116px 84px; }
.audit-grid   { grid-template-columns: 148px minmax(88px, 0.8fr) minmax(150px, 1.7fr) 108px; }
.platform-grid { grid-template-columns: minmax(0, 1fr) 96px 116px; }
.certs-grid   { grid-template-columns: minmax(130px, 1.2fr) minmax(150px, 1.5fr) 152px 84px; }

.cell { min-width: 0; font-size: var(--fs-sm); }
.cell.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cell.is-mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.cell.is-end { text-align: right; }
.cell.is-muted { color: var(--text-3); }
.cell.is-tiny { font-size: var(--fs-xs); }

.cell-stack { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.cell-main { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cell-sub { font-size: var(--fs-xs); color: var(--text-4); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.row-actions { display: flex; gap: var(--sp-3xs); justify-content: flex-end; }

/* 可复制字段：等宽 + 点击即复制 */
.copyable {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  max-width: 100%;
  padding: 1px 5px;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--text);
  background: none;
  text-align: left;
  transition: background 0.12s var(--ease), border-color 0.12s var(--ease);
}
.copyable:hover { background: var(--surface-2); border-color: var(--line); }
.copyable:active { background: var(--surface-3); }
.copyable svg { width: 12px; height: 12px; flex: none; opacity: 0; transition: opacity 0.12s var(--ease); }
.copyable:hover svg, .copyable:focus-visible svg { opacity: 0.6; }

/* ---------------------------------------------------------------- 11. 空态 */

.empty {
  display: grid;
  place-items: center;
  gap: var(--sp-sm);
  padding: var(--sp-2xl) var(--sp-lg);
  text-align: center;
}
/* 空态要教会用户怎么用，而不只是说"这里没有东西" */
.empty-mark {
  width: 38px;
  height: 38px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r);
  display: grid;
  place-items: center;
  color: var(--text-4);
}
.empty-title { font-size: var(--fs-sm); font-weight: 600; }
.empty-desc { font-size: var(--fs-xs); color: var(--text-3); max-width: 44ch; line-height: 1.55; }

/* 骨架屏 */
.skeleton {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 37%, var(--surface-2) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.3s ease-in-out infinite;
  border-radius: var(--r-sm);
  height: 12px;
}
@keyframes shimmer {
  0% { background-position: 100% 0; }
  100% { background-position: 0 0; }
}

/* ---------------------------------------------------------------- 12. 提示 */

.toasts {
  position: fixed;
  right: var(--sp-md);
  bottom: var(--sp-md);
  z-index: 90;
  display: flex;
  flex-direction: column;
  gap: var(--sp-xs);
  max-width: min(380px, calc(100vw - 2 * var(--sp-md)));
  pointer-events: none;
}
.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-xs);
  padding: var(--sp-sm);
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  box-shadow: var(--shadow);
  font-size: var(--fs-sm);
  color: var(--text);
  pointer-events: auto;
  animation: toast-in 0.22s var(--ease);
}
.toast.is-ok { border-color: oklch(from var(--ok) l c h / 0.5); }
.toast.is-error { border-color: oklch(from var(--danger) l c h / 0.55); }
.toast.is-warn { border-color: oklch(from var(--warn) l c h / 0.5); }
.toast-mark { font-family: var(--font-mono); font-size: var(--fs-sm); flex: none; line-height: 1.5; }
.toast.is-ok .toast-mark { color: var(--ok); }
.toast.is-error .toast-mark { color: var(--danger); }
.toast.is-warn .toast-mark { color: var(--warn); }
.toast-body { min-width: 0; }
.toast-title { font-weight: 600; }
.toast-desc { font-size: var(--fs-xs); color: var(--text-3); margin-top: 1px; word-break: break-word; }
.toast-close { margin-left: auto; color: var(--text-4); flex: none; }
.toast-close:hover { color: var(--text); }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

/* 行内提示条 */
.notice {
  display: flex;
  gap: var(--sp-sm);
  padding: var(--sp-sm) var(--sp-md);
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface-2);
  font-size: var(--fs-sm);
  line-height: 1.55;
}
.notice.is-warn { border-color: oklch(from var(--warn) l c h / 0.42); background: var(--warn-wash); }
.notice.is-danger { border-color: oklch(from var(--danger) l c h / 0.42); background: var(--danger-wash); }
.notice.is-brand { border-color: var(--brand-edge); background: var(--brand-wash); }
.notice-mark { font-family: var(--font-mono); flex: none; }
.notice-body { min-width: 0; }
.notice-title { font-weight: 600; }
.notice-text { color: var(--text-2); font-size: var(--fs-xs); margin-top: 2px; }

/* 代码块 */
.code {
  position: relative;
  padding: var(--sp-sm);
  background: var(--bg-deep);
  border: 1px solid var(--line);
  border-radius: var(--r);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: 1.65;
  color: var(--text-2);
  overflow-x: auto;
  white-space: pre;
  tab-size: 2;
}
.code-toolbar { position: absolute; top: var(--sp-xs); right: var(--sp-xs); }

/* 登录页里的凭据展示 */
.credential {
  display: flex;
  align-items: center;
  gap: var(--sp-sm);
  padding: var(--sp-sm);
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--bg-deep);
}
.credential-label { font-size: var(--fs-xs); color: var(--text-3); flex: none; min-width: 56px; }
.credential-value {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  word-break: break-all;
  flex: 1;
  min-width: 0;
}

/* 日志查看器 */
.logview {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: 1.6;
  max-height: 460px;
  overflow: auto;
  background: var(--bg-deep);
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
}
.logline {
  display: grid;
  grid-template-columns: 74px 52px 1fr;
  gap: var(--sp-xs);
  padding: 2px var(--sp-sm);
  border-bottom: 1px solid oklch(from var(--line-soft) l c h / 0.5);
}
.logline:last-child { border-bottom: none; }
.log-ts { color: var(--text-4); }
.log-level { font-weight: 600; }
.logline.is-info .log-level { color: var(--info); }
.logline.is-warn .log-level { color: var(--warn); }
.logline.is-error .log-level { color: var(--danger); }
.logline.is-debug .log-level { color: var(--text-4); }
.log-msg { color: var(--text-2); white-space: pre-wrap; word-break: break-word; }
.log-msg mark {
  background: oklch(from var(--brand) l c h / 0.22);
  color: var(--text);
  border-radius: 2px;
  padding: 0 1px;
}

/* 表格里的迷你进度条 */
.usage { display: flex; align-items: center; gap: var(--sp-xs); min-width: 0; }
.usage .meter { flex: 1; min-width: 44px; }

/* 页内标签切换 */
.tabs {
  display: flex;
  gap: var(--sp-3xs);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  position: relative;
  padding: var(--sp-xs) var(--sp-sm);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-3);
  white-space: nowrap;
  transition: color 0.12s var(--ease);
}
.tab:hover { color: var(--text); }
.tab[aria-selected='true'] { color: var(--text); font-weight: 600; }
.tab[aria-selected='true']::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  bottom: -1px;
  height: 2px;
  background: var(--brand);
}

/* ---------------------------------------------------------------- 13. 登录 */

.auth {
  min-height: 100dvh;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
}

/* 左半：品牌 + 一段"机房指示灯"的意象 */
.auth-brand {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--sp-xl);
  padding: var(--sp-2xl);
  background: var(--bg-deep);
  border-right: 1px solid var(--line);
  overflow: hidden;
}
.auth-brand::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle at 18% 12%, var(--brand-wash), transparent 42%);
  pointer-events: none;
}
.auth-brand > * { position: relative; }

/* 背景里的一排状态灯，暗示"设备在运行" */
.auth-rack {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(26px, 1fr));
  gap: var(--sp-xs);
  opacity: 0.5;
}
.auth-rack i {
  height: 3px;
  border-radius: 1px;
  background: var(--line-strong);
}
.auth-rack i:nth-child(7n + 1) { background: var(--brand); }
.auth-rack i:nth-child(11n + 3) { background: var(--ok); }

.auth-headline {
  font-size: var(--fs-3xl);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.08;
  max-width: 15ch;
}
.auth-headline em {
  font-style: normal;
  color: var(--brand);
}
.auth-lede {
  margin-top: var(--sp-sm);
  font-size: var(--fs-md);
  color: var(--text-3);
  max-width: 38ch;
  line-height: 1.6;
}
.auth-points { display: flex; flex-direction: column; gap: var(--sp-sm); }
.auth-point {
  display: flex;
  gap: var(--sp-sm);
  align-items: baseline;
  font-size: var(--fs-sm);
  color: var(--text-2);
}
.auth-point-key {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--brand);
  flex: none;
  min-width: 2.4em;
}

.auth-form-side {
  display: grid;
  place-items: center;
  padding: var(--sp-xl) var(--sp-lg);
}
.auth-card { width: 100%; max-width: 380px; display: flex; flex-direction: column; gap: var(--sp-lg); }
.auth-title { font-size: var(--fs-lg); font-weight: 700; }
.auth-sub { font-size: var(--fs-sm); color: var(--text-3); margin-top: 3px; }
.auth-form { display: flex; flex-direction: column; gap: var(--sp-md); }

/* ---------------------------------------------------------------- 14. 抽屉 */

.drawer-scrim {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: oklch(0.1 0.01 73 / 0.62);
  backdrop-filter: blur(2px);
  animation: fade-in 0.16s var(--ease);
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.drawer {
  position: fixed;
  z-index: 71;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(440px, 100vw);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--line-strong);
  box-shadow: -14px 0 40px oklch(0 0 0 / 0.34);
  animation: drawer-in 0.22s var(--ease);
}
@keyframes drawer-in { from { transform: translateX(20px); opacity: 0; } to { transform: none; opacity: 1; } }

.drawer-head {
  display: flex;
  align-items: center;
  gap: var(--sp-sm);
  padding: var(--sp-sm) var(--sp-md);
  border-bottom: 1px solid var(--line);
  min-height: var(--topbar);
}
.drawer-title { font-family: var(--font-display); font-size: var(--fs-md); font-weight: 700; }
.drawer-body { flex: 1; overflow-y: auto; padding: var(--sp-md); display: flex; flex-direction: column; gap: var(--sp-md); }
.drawer-foot {
  display: flex;
  gap: var(--sp-xs);
  padding: var(--sp-sm) var(--sp-md);
  border-top: 1px solid var(--line);
  background: var(--surface-2);
}
.drawer-foot .btn { flex: 1; }

/* 移动端侧栏改为抽屉 */
.sidebar-scrim { display: none; }

/* ---------------------------------------------------------------- 15. 工具类 */

.stack   { display: flex; flex-direction: column; gap: var(--sp-md); }
.stack-sm{ display: flex; flex-direction: column; gap: var(--sp-xs); }
.row     { display: flex; align-items: center; gap: var(--sp-sm); flex-wrap: wrap; }
.row-tight { display: flex; align-items: center; gap: var(--sp-xs); }
.mt-sm  { margin-top: var(--sp-sm); }
.mb-sm  { margin-bottom: var(--sp-sm); }
.spacer  { flex: 1; }
.grid-2  { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--sp-lg); }
.muted   { color: var(--text-3); }
.dim     { color: var(--text-4); }
.ok      { color: var(--ok); }
.warn    { color: var(--warn); }
.danger  { color: var(--danger); }
.brand   { color: var(--brand); }
.nowrap  { white-space: nowrap; }
.truncate{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.break   { word-break: break-all; }
.center  { text-align: center; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.noscript {
  position: fixed; inset: 0; display: grid; place-items: center;
  background: var(--bg); color: var(--text); padding: var(--sp-lg); text-align: center;
}

/* 入场动效：面板错位淡入。一次编排好的入场，比零散的微交互更让人愉悦 */
.stagger > * {
  animation: rise 0.34s var(--ease) backwards;
}
.stagger > *:nth-child(1) { animation-delay: 0.02s; }
.stagger > *:nth-child(2) { animation-delay: 0.06s; }
.stagger > *:nth-child(3) { animation-delay: 0.10s; }
.stagger > *:nth-child(4) { animation-delay: 0.14s; }
.stagger > *:nth-child(5) { animation-delay: 0.18s; }
.stagger > *:nth-child(6) { animation-delay: 0.22s; }
@keyframes rise {
  from { opacity: 0; transform: translateY(7px); }
  to { opacity: 1; transform: none; }
}

/* ==========================================================================
   16. 自适应 —— 三档重排，不是把桌面版压扁
   ========================================================================== */

/* --- 平板：侧栏收成图标栏，双栏内容 --- */
@media (max-width: 1080px) {
  .shell { grid-template-columns: var(--rail-md) minmax(0, 1fr); }
  .sidebar { padding-inline: var(--sp-xs); align-items: center; }
  .brand { padding-inline: 0; }
  .brand-text { display: none; }
  .nav { width: 100%; align-items: center; }
  .nav-group { display: none; }
  .nav-item {
    justify-content: center;
    padding: 10px;
    width: 44px;
    height: 44px;
  }
  .nav-label, .nav-count { display: none; }
  .nav-item[aria-current='page']::before { left: -6px; }
  .rail-status { justify-content: center; }
  .rail-status .rail-text { display: none; }
  .sidebar-foot { align-items: center; padding-inline: 0; width: 100%; }
  /* 图标栏只有 68px，按钮里的文字必须收起来，否则会撑出栏外。
     按钮本身带 aria-label，隐藏文字不影响可访问性。 */
  .sidebar-foot .btn { width: 44px; height: 44px; padding-inline: 0; justify-content: center; }
  .sidebar-foot .btn > span { display: none; }
}

/* --- 手机：侧栏变抽屉，数据行重排成卡片 --- */
@media (max-width: 720px) {
  :root { --topbar: 50px; }

  .shell { grid-template-columns: minmax(0, 1fr); }

  .sidebar {
    position: fixed;
    inset-block: 0;
    left: 0;
    width: min(272px, 84vw);
    height: 100dvh;
    align-items: stretch;
    padding: var(--sp-lg) var(--sp-sm) var(--sp-md);
    border-right: 1px solid var(--line-strong);
    box-shadow: 14px 0 40px oklch(0 0 0 / 0.34);
    transform: translateX(-102%);
    transition: transform 0.24s var(--ease);
    z-index: 71;
  }
  .sidebar.is-open { transform: none; }
  .sidebar .brand { padding-inline: var(--sp-sm); }
  .sidebar .brand-text { display: block; }
  .sidebar .nav { align-items: stretch; }
  .sidebar .nav-group { display: block; }
  .sidebar .nav-item { justify-content: flex-start; width: auto; height: auto; padding: 11px var(--sp-sm); }
  .sidebar .nav-label, .sidebar .nav-count { display: block; }
  .sidebar .nav-item[aria-current='page']::before { left: 0; }
  .sidebar .rail-status { justify-content: flex-start; }
  .sidebar .rail-status .rail-text { display: inline; }
  .sidebar .sidebar-foot { align-items: stretch; }

  .sidebar-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 70;
    background: oklch(0.1 0.01 73 / 0.6);
    animation: fade-in 0.16s var(--ease);
  }

  .content { padding: var(--sp-md) var(--sp-sm) var(--sp-2xl); gap: var(--sp-md); }
  .topbar { padding-inline: var(--sp-sm); }
  .menu-btn.icon-btn { display: inline-grid; }

  .page-title { font-size: var(--fs-lg); }

  /* 数据行 → 卡片：标签从 data-label 取，值右对齐 */
  .datarow.is-head { display: none; }
  .datarow {
    grid-template-columns: minmax(0, 1fr) !important;
    gap: var(--sp-xs);
    padding: var(--sp-sm) var(--sp-md);
    margin-bottom: var(--sp-xs);
    border: 1px solid var(--line);
    border-radius: var(--r);
    background: var(--surface);
  }
  .datarow:last-child { margin-bottom: 0; }
  .datarow:not(.is-head):hover { background: var(--surface); }

  .cell {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-sm);
    text-align: right;
  }
  .cell::before {
    content: attr(data-label);
    flex: none;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-4);
    text-align: left;
  }
  /* 主字段在卡片顶部单独成行，不做左右分栏 */
  .cell.is-primary {
    display: block;
    text-align: left;
    padding-bottom: var(--sp-xs);
    border-bottom: 1px solid var(--line-soft);
    margin-bottom: var(--sp-2xs);
  }
  .cell.is-primary::before { display: none; }
  .cell.is-primary .cell-main { font-size: var(--fs-md); }

  .cell.is-end { text-align: right; }
  .cell.is-mono, .cell .copyable { justify-content: flex-end; }
  .cell-stack { align-items: flex-end; }
  .cell-stack .cell-main, .cell-stack .cell-sub { text-align: right; }

  .row-actions { justify-content: flex-end; padding-top: var(--sp-2xs); }
  /* 触控目标不小于 44px */
  .row-actions .icon-btn { width: 44px; height: 44px; }
  .icon-btn { width: 40px; height: 40px; }
  .btn { min-height: 42px; }
  .btn.is-sm { min-height: 34px; }

  /* 表单控件放大到 16px，避免 iOS 聚焦时自动缩放 */
  .input, .select, .textarea { font-size: 1rem; min-height: 44px; }
  .input-group > .input, .input-group > .select { min-height: 42px; }

  .readouts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 读数为奇数时让最后一个占满整行，否则右下角会留出一个像是"缺了一块"的格子 */
  .readouts > :last-child:nth-child(odd) { grid-column: 1 / -1; }
  .readout-value { font-size: var(--fs-lg); }

  .toasts { right: var(--sp-sm); bottom: var(--sp-sm); left: var(--sp-sm); max-width: none; }

  .drawer { width: 100vw; border-left: none; }

  .logline { grid-template-columns: 62px 44px 1fr; font-size: 0.6875rem; }

  /* 登录页：品牌区收缩成页头，表单是主角 */
  .auth { grid-template-columns: minmax(0, 1fr); }
  .auth-brand {
    padding: var(--sp-lg) var(--sp-md);
    border-right: none;
    border-bottom: 1px solid var(--line);
    gap: var(--sp-md);
  }
  .auth-rack, .auth-points { display: none; }
  .auth-headline { font-size: var(--fs-xl); max-width: none; }
  .auth-lede { font-size: var(--fs-sm); }
  .auth-form-side { padding: var(--sp-lg) var(--sp-md) var(--sp-2xl); align-items: start; }
  .auth-card { max-width: none; }
}

@media (max-width: 380px) {
  .readouts { grid-template-columns: minmax(0, 1fr); }
  .page-head { gap: var(--sp-xs); }
}

/* --- 横屏手机：品牌区收得更高，把纵向空间让给表单 --- */
@media (max-width: 900px) and (orientation: landscape) and (max-height: 520px) {
  .auth-brand { padding: var(--sp-md); }
  .auth-headline { font-size: var(--fs-lg); }
}

/* --- 无障碍：尊重系统的减少动效设置 --- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .scanline::after { display: none; }
}

/* --- 打印：去掉一切交互与装饰 --- */
@media print {
  .sidebar, .topbar, .scanline, .toasts, .row-actions, .panel-actions { display: none !important; }
  body { background: #fff; color: #000; }
  .panel { border-color: #999; box-shadow: none; }
}
