/* ==========================================================================
   内部管理系统 · 设计系统
   风格：现代简约（Modern Minimal，参考 yiliao / 寻医专家平台）
   特征：充足留白 / 柔和层次 / 圆角 / 克制动效 / 支持暗色模式
   说明：保留全部既有 class 名与旧 CSS 变量别名，模块无需改动即可换肤。
   ========================================================================== */

/* ---------- 设计令牌 ---------- */
:root{
  /* 品牌主色（可由「系统设置」覆盖：--theme）——默认现代蓝 */
  --theme:#2563EB;
  --theme-soft:#2563EB1a;
  --theme-soft:color-mix(in srgb, var(--theme) 12%, transparent);

  --brand-600:#2563EB;  --brand-600:var(--theme);
  --brand-700:#1D4ED8;  --brand-700:color-mix(in srgb, var(--theme) 84%, #000);
  --brand-800:#1E40AF;  --brand-800:color-mix(in srgb, var(--theme) 70%, #000);
  --brand-900:#1E3A8A;  --brand-900:color-mix(in srgb, var(--theme) 56%, #000);
  --brand-500:#3B7AF6;  --brand-500:color-mix(in srgb, var(--theme) 90%, #fff);
  --brand-400:#6096FA;  --brand-400:color-mix(in srgb, var(--theme) 74%, #fff);
  --brand-300:#93BAFD;  --brand-300:color-mix(in srgb, var(--theme) 56%, #fff);
  --brand-200:#BFD6FE;  --brand-200:color-mix(in srgb, var(--theme) 38%, #fff);
  --brand-100:#DBE8FE;  --brand-100:color-mix(in srgb, var(--theme) 16%, #fff);
  --brand-50:#EFF5FF;   --brand-50:color-mix(in srgb, var(--theme) 8%, #fff);

  /* 中性阶 */
  --ink-50:#F8FAFC;  --ink-100:#F1F5F9; --ink-200:#E2E8F0; --ink-300:#CBD5E1;
  --ink-400:#94A3B8; --ink-500:#64748B; --ink-600:#475569; --ink-700:#334155;
  --ink-800:#1E293B; --ink-900:#0F172A;

  /* 语义色 */
  --ok-50:#ECFDF5;    --ok-500:#10B981;   --ok-600:#059669;   --ok-700:#047857;
  --warn-50:#FFFBEB;  --warn-500:#F59E0B; --warn-600:#D97706; --warn-700:#B45309;
  --danger-50:#FEF2F2;--danger-500:#EF4444;--danger-600:#DC2626;--danger-700:#B91C1C;
  --violet-50:#F5F3FF;--violet-500:#8B5CF6;--violet-600:#7C3AED;

  /* 语义映射 */
  --bg:          var(--ink-50);
  --surface:     #FFFFFF;
  --surface-2:   var(--ink-100);
  --border:      var(--ink-200);
  --border-soft: #EEF2F7;
  --text:        var(--ink-900);
  --text-2:      var(--ink-600);
  --text-3:      var(--ink-400);

  /* 圆角 */
  --r-xs:6px; --r-sm:8px; --r-md:12px; --r-lg:16px; --r-xl:20px; --r-full:999px;

  /* 阴影：多层柔和 */
  --shadow-xs:0 1px 2px rgba(15,23,42,.04);
  --shadow-sm:0 1px 3px rgba(15,23,42,.06),0 1px 2px rgba(15,23,42,.04);
  --shadow-md:0 4px 12px rgba(15,23,42,.07),0 2px 4px rgba(15,23,42,.04);
  --shadow-lg:0 12px 28px rgba(15,23,42,.10),0 4px 8px rgba(15,23,42,.04);
  --shadow-xl:0 24px 48px rgba(15,23,42,.14);
  --shadow-brand:0 6px 20px rgba(37,99,235,.22);
  --shadow-brand:0 6px 20px color-mix(in srgb, var(--theme) 30%, transparent);

  /* 动效 */
  --ease:cubic-bezier(.4,0,.2,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
  --dur:.18s;

  /* 控件尺寸 */
  --input-h:42px; --input-bd:var(--ink-200);
  --radius:var(--r-sm); --radius-lg:var(--r-lg);
  --btn-sh:var(--shadow-sm);

  /* ---------- 旧变量名兼容别名（模块内联/历史样式引用） ---------- */
  --blue-900:var(--brand-800); --blue-800:var(--brand-700); --blue-700:var(--brand-600);
  --blue-600:var(--brand-500); --blue-200:var(--brand-200); --blue-100:var(--brand-100);
  --blue-50:var(--brand-50);
  --ink:var(--text); --sub:var(--text-2); --line:var(--border-soft); --card:var(--surface);
  --green:var(--ok-600); --amber:var(--warn-600); --red:var(--danger-600);
}

/* ---------- 根字号档位（A2） ----------
   全站字号统一用 rem，根字号由 <html data-fs="sm|md|lg|xl"> 决定。
   这样「字号档位」能真的放大所有文字（含按钮、表格、提示），而不是只有正文变大；
   浏览器的「最小字号」设置也终于能生效（原来全是 px，浏览器设置完全无效）。
   布局尺寸（padding/宽度）仍用 px —— 跟着字号一起放大反而会把宽表撑得更难用。 */
html{font-size:16px}
html[data-fs="sm"]{font-size:14px}
html[data-fs="md"]{font-size:16px}
html[data-fs="lg"]{font-size:18px}
html[data-fs="xl"]{font-size:20px}

/* ---------- 暗色模式（手动切换：html[data-theme="dark"]；默认浅色，不随系统） ---------- */
[data-theme="dark"]{
  --bg:#0B1120;
  --surface:#131C2E;
  --surface-2:#1B2740;
  --border:#253352;
  --border-soft:#1E2A44;
  --text:#F1F5F9;
  --text-2:#A9B7CC;
  --text-3:#6B7B94;
  --input-bd:#2A3A5C;

  --ink-50:#0B1120; --ink-100:#161F33; --ink-200:#253352; --ink-300:#33425F;

  --brand-50:#16213C; --brand-100:#1B2B4D; --brand-200:#24406F;
  --ok-50:#0C2B21; --warn-50:#2E2408; --danger-50:#2E1414; --violet-50:#1F1B3A;
  /* 深色主题只把 *-50 压暗、*-700 仍是浅色主题那套深绿/深红 → `.tag-ok`/`.alert-error`
     这类「浅底 + 深字」组合会变成「深底 + 深字」，实测对比度只有 1.6:1（「✅ 已审」整块糊掉）。
     这里把 700 档一并翻成浅色，保持「同一语义、明暗各一套」的对应关系。 */
  --ok-700:#6EE7B7; --warn-700:#FCD34D; --danger-700:#FCA5A5;

  --shadow-xs:0 1px 2px rgba(0,0,0,.5);
  --shadow-sm:0 1px 3px rgba(0,0,0,.4);
  --shadow-md:0 4px 12px rgba(0,0,0,.45);
  --shadow-lg:0 12px 28px rgba(0,0,0,.55);
  --shadow-xl:0 24px 48px rgba(0,0,0,.6);
}

/* ---------- 基础 ---------- */
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
html{-webkit-text-size-adjust:100%}
body{
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",
              "Hiragino Sans GB","Microsoft YaHei",sans-serif;
  color:var(--text); background:var(--bg); font-size:0.9062rem; line-height:1.65;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
}
a{color:var(--brand-600);text-decoration:none;transition:color var(--dur) var(--ease)}
a:hover{color:var(--brand-700)}
h1,h2,h3,h4,h5{font-weight:600;letter-spacing:-.015em;line-height:1.35}
::selection{background:var(--brand-200);color:var(--brand-900)}
:focus-visible{outline:2px solid var(--brand-500);outline-offset:2px;border-radius:4px}

/* ===== 后台布局 ===== */
.app{display:flex;min-height:100vh}
.sidebar{
  width:244px;flex:none;background:var(--surface);
  border-right:1px solid var(--border-soft);
  padding:16px 12px 24px;position:sticky;top:0;height:100vh;overflow-y:auto;
}
.brand{
  display:flex;align-items:center;gap:10px;padding:8px 10px 18px;
  font-size:1rem;font-weight:600;color:var(--text);letter-spacing:-.01em;
}
.brand .logo-mark{
  width:30px;height:30px;flex:none;border-radius:9px;display:grid;place-items:center;
  font-size:0.9375rem;color:#fff;background:linear-gradient(135deg,var(--brand-500),var(--brand-700));
  box-shadow:var(--shadow-brand);
}
.brand .brand-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.nav{display:flex;flex-direction:column;gap:2px}
.nav-group{
  padding:15px 12px 6px;font-size:0.7188rem;font-weight:600;color:var(--text-3);
  letter-spacing:.06em;text-transform:uppercase;
}
.nav-item{
  display:flex;align-items:center;gap:10px;padding:9px 12px;margin:0;
  border-radius:var(--r-sm);color:var(--text-2);font-size:0.875rem;font-weight:500;
  transition:all var(--dur) var(--ease);
}
.nav-item:hover{background:var(--surface-2);color:var(--text);text-decoration:none}
.nav-item.active{background:var(--brand-600);color:#fff;font-weight:600;box-shadow:var(--shadow-brand)}
.nav-item.active:hover{background:var(--brand-700);color:#fff}

.main{flex:1;display:flex;flex-direction:column;min-width:0}
.topbar{
  height:60px;position:sticky;top:0;z-index:20;
  display:flex;align-items:center;justify-content:space-between;gap:16px;padding:0 24px;
  background:var(--surface);
  background:color-mix(in srgb, var(--surface) 82%, transparent);
  border-bottom:1px solid var(--border-soft);
  backdrop-filter:saturate(180%) blur(14px);
  -webkit-backdrop-filter:saturate(180%) blur(14px);
}
.top-left{display:flex;align-items:center;gap:12px}
.top-right{display:flex;align-items:center;gap:14px;min-width:0}
.menu-toggle{display:none;cursor:pointer;font-size:1.1875rem;line-height:1;color:var(--text-2)}
.bell{position:relative;font-size:1.125rem;line-height:1;color:var(--text-2)}
.bell:hover{text-decoration:none}
.bell .badge{
  position:absolute;top:-7px;right:-9px;min-width:16px;height:16px;padding:0 4px;
  display:grid;place-items:center;background:var(--danger-600);color:#fff;
  border-radius:var(--r-full);font-size:0.6562rem;font-weight:600;line-height:1;
}
.bell.has{animation:pulse 1.6s infinite}
@keyframes pulse{0%,100%{transform:scale(1)}50%{transform:scale(1.16)}}
.user{color:var(--text-2);font-size:0.8438rem;font-weight:500}
.logout{
  color:var(--text-2);font-size:0.8125rem;padding:5px 10px;border-radius:var(--r-sm);
  transition:all var(--dur) var(--ease);
}
.logout:hover{background:var(--surface-2);color:var(--text);text-decoration:none}
.icon-btn{
  display:inline-grid;place-items:center;width:34px;height:34px;
  border:1px solid transparent;border-radius:var(--r-sm);background:transparent;
  color:var(--text-2);cursor:pointer;font-size:1rem;line-height:1;
  transition:all var(--dur) var(--ease);
}
.icon-btn:hover{background:var(--surface-2);color:var(--text);border-color:var(--border-soft)}
/* A4：内容区最大宽度。1920 下原来正文铺到 1676px，行长过长不好扫读；
   封顶 1400px 居中，宽表仍可横向滚动（滚动发生在 .table-scroll 内部，不撑破布局）。 */
.content{padding:24px 28px 48px;flex:1;min-width:0;max-width:1400px;margin:0 auto;width:100%}
/* 大屏（≥1600）：左右留白更大，正文仍封顶；KPI 网格也放到 4 列。
   注意 .cards 本身是 auto-fit 自适应，不要再给它设固定列数（会把自适应打死）。 */
@media screen and (min-width:1600px){
  .content{max-width:1560px;padding:28px 40px 56px}
  .kpi-grid{grid-template-columns:repeat(4,minmax(0,1fr))}
}
@media screen and (min-width:1280px) and (max-width:1599px){
  .kpi-grid{grid-template-columns:repeat(4,minmax(0,1fr))}
}

/* ===== 页面头 / 卡片 ===== */
.page-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:20px}
.page-head h2{font-size:1.3125rem;color:var(--text);font-weight:600;letter-spacing:-.02em}
.page-head h1{font-size:1.375rem;letter-spacing:-.02em}
.page-head p{color:var(--text-3);font-size:0.8438rem;margin-top:4px}
.page-head .btn{white-space:nowrap}
.card{
  background:var(--surface);border:1px solid var(--border-soft);border-radius:var(--r-lg);
  padding:22px 24px;margin-bottom:16px;box-shadow:var(--shadow-xs);
}
.card + .card{margin-top:0}
.muted{color:var(--text-3);font-size:0.7812rem}
.section-title{
  margin:22px 0 10px;padding-left:10px;font-size:0.9688rem;font-weight:600;color:var(--text);
  border-left:3px solid var(--brand-500);
}

/* ===== 按钮 ===== */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  height:38px;padding:0 16px;border:1px solid var(--border);border-radius:var(--r-sm);
  background:var(--surface);color:var(--text-2);cursor:pointer;
  font-family:inherit;font-size:0.875rem;font-weight:500;line-height:1;white-space:nowrap;
  box-shadow:var(--shadow-xs);transition:all var(--dur) var(--ease);
}
.btn:hover{border-color:var(--ink-300);background:var(--surface-2);color:var(--text);text-decoration:none;box-shadow:var(--shadow-sm)}
.btn:active{transform:translateY(1px)}
.btn:disabled,.btn.disabled{opacity:.5;cursor:not-allowed;transform:none;box-shadow:none}
.btn-primary{background:var(--brand-600);border-color:var(--brand-600);color:#fff}
.btn-primary:hover{background:var(--brand-700);border-color:var(--brand-700);color:#fff;box-shadow:var(--shadow-brand);transform:translateY(-1px)}
.btn-danger{background:var(--surface);border-color:#FBD5D5;color:var(--danger-600)}
.btn-danger:hover{background:var(--danger-600);border-color:var(--danger-600);color:#fff;box-shadow:0 6px 20px rgba(220,38,38,.22)}
.btn-block{width:100%;height:46px;font-size:0.9688rem;font-weight:600;margin-top:8px;border-radius:var(--r-md)}
.btn-sm{height:32px;padding:0 12px;font-size:0.7812rem;border-radius:var(--r-xs)}

/* ===== 表单 ===== */
.form-wrap{max-width:780px}
form label{display:block;margin:16px 0 6px;font-size:0.8125rem;font-weight:500;color:var(--text-2)}
form label .req{color:var(--danger-600);margin-left:2px}
form label .pre{color:var(--text-2);margin-right:4px}
form input[type=text],form input[type=number],form input[type=date],form input[type=datetime-local],
form input[type=password],form input[type=email],form input[type=tel],form input[type=search],
form input:not([type]),form select,form textarea{
  width:100%;min-height:var(--input-h);padding:10px 13px;
  border:1px solid var(--input-bd);border-radius:var(--r-sm);
  font-size:0.9062rem;line-height:1.4;font-family:inherit;background:var(--surface);color:var(--text);
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
form input::placeholder,form textarea::placeholder{color:var(--text-3)}
form input:hover,form select:hover,form textarea:hover{border-color:var(--ink-300)}
form input:focus,form select:focus,form textarea:focus{
  outline:none;border-color:var(--brand-500);box-shadow:0 0 0 3px var(--brand-100);
}
form select{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;padding-right:32px;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394A3B8' stroke-width='3' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 12px center;
}
form textarea{min-height:104px;resize:vertical}
.form-row{display:flex;gap:14px;flex-wrap:wrap;align-items:flex-end}
.form-row label{margin-bottom:6px}
.form-row input,.form-row select{width:auto;min-width:170px}
.form-actions{margin-top:22px;display:flex;gap:10px;flex-wrap:wrap}
.check{display:flex;align-items:center;gap:7px;font-size:0.875rem;font-weight:500;color:var(--text)}
.check.inline{display:inline-flex;margin-right:16px;font-weight:400}
.check input{width:17px;height:17px;flex-shrink:0;accent-color:var(--brand-600)}
.formula{background:var(--surface-2);color:var(--text-2)}
.readonly{
  display:inline-block;padding:8px 12px;background:var(--surface-2);
  border:1px solid var(--border-soft);border-radius:var(--r-sm);color:var(--text);font-size:0.875rem;
}
.hint{display:block;margin-top:5px;font-size:0.75rem;color:var(--text-3);font-weight:400}

/* ===== 表格 ===== */
.table-scroll{
  overflow:auto;background:var(--surface);border:1px solid var(--border-soft);
  border-radius:var(--r-md);box-shadow:var(--shadow-xs);
  /* A1：横向滚动时给左右边缘渐变遮罩，提示「这边还有内容」。
     用 background-attachment:local 的经典双背景技巧 —— 内容滚到底时阴影自动消失，
     不需要 JS 监听滚动。 */
  background-image:
    linear-gradient(to right, var(--surface), rgba(255,255,255,0)),
    linear-gradient(to right, rgba(255,255,255,0), var(--surface)),
    linear-gradient(to right, rgba(15,23,42,.10), rgba(15,23,42,0)),
    linear-gradient(to left,  rgba(15,23,42,.10), rgba(15,23,42,0));
  background-position:0 0, 100% 0, 0 0, 100% 0;
  background-repeat:no-repeat;
  background-size:40px 100%, 40px 100%, 18px 100%, 18px 100%;
  background-attachment:local, local, scroll, scroll;
}
[data-theme="dark"] .table-scroll{background-image:
    linear-gradient(to right, var(--surface), rgba(19,28,46,0)),
    linear-gradient(to right, rgba(19,28,46,0), var(--surface)),
    linear-gradient(to right, rgba(0,0,0,.45), rgba(0,0,0,0)),
    linear-gradient(to left,  rgba(0,0,0,.45), rgba(0,0,0,0));}
.grid-table{width:100%;border-collapse:collapse;font-size:0.8438rem;background:transparent}
.grid-table th{
  position:sticky;top:0;z-index:5;white-space:nowrap;text-align:left;
  padding:11px 14px;background:var(--surface-2);color:var(--text-2);
  font-weight:600;font-size:0.7812rem;letter-spacing:.01em;border-bottom:1px solid var(--border);
}
.grid-table td{padding:11px 14px;border-bottom:1px solid var(--border-soft);vertical-align:top}

/* A1：冻结首列（序号）与操作列。宽表滚到右边时仍能看出这是哪一行、能操作。
   z-index 分层：表头(sticky top) 5 > 冻结单元格 4 > 普通单元格。
   冻结列必须给背景色，否则下面滚过的内容会透出来。 */
.grid-table.excel th.idx,
.grid-table.excel td.idx{
  position:sticky;left:0;z-index:4;background:var(--surface);
}
.grid-table.excel th.idx{background:var(--surface-2);z-index:6}
.grid-table.excel th.sel,
.grid-table.excel td.sel{
  position:sticky;left:0;z-index:4;background:var(--surface);
}
.grid-table.excel th.sel{background:var(--surface-2);z-index:6}
/* 有勾选列时，序号列紧贴其右（勾选列宽 40px） */
.grid-table.excel.has-sel th.idx,
.grid-table.excel.has-sel td.idx{left:40px}
.grid-table.excel th.row-actions,
.grid-table.excel td.row-actions{
  position:sticky;right:0;z-index:4;background:var(--surface);
  box-shadow:-6px 0 8px -6px rgba(15,23,42,.14);
}
.grid-table.excel th.row-actions{background:var(--surface-2);z-index:6}
.grid-table.excel tbody tr:hover td.idx,
.grid-table.excel tbody tr:hover td.sel,
.grid-table.excel tbody tr:hover td.row-actions{background:var(--surface-2)}

/* A5：表格密度（html[data-density]），默认标准。
   只改 padding / 行内边距，**不动字号** —— 字号归 A2 的档位管，
   两个维度混在一起调会让用户没法分别控制「字多大」和「一行多高」。 */
html[data-density="tight"] .grid-table th{padding:6px 10px}
html[data-density="tight"] .grid-table td{padding:6px 10px}
html[data-density="tight"] .row-actions a{padding:3px 8px}
html[data-density="loose"] .grid-table th{padding:14px 16px}
html[data-density="loose"] .grid-table td{padding:15px 16px}

/* A1：表格上方「还有 N 列在右侧」提示条 */
.cols-hint{
  display:none;align-items:center;gap:6px;margin:0 0 8px;
  font-size:0.75rem;color:var(--text-3);
}
.cols-hint.show{display:flex}

/* B1：列宽拖拽手柄（挂在表头右侧，hover 时显现） */
/* 列宽拖拽手柄。
 * ⚠️ 曾经是 right:-3px（往外溢出手柄的一半），本意是让「正好点在列边界上」也能抓到，
 * 但相邻的表头单元格在 DOM 里更靠后，会把溢出的那 3px 盖住 —— 手柄中点恰好落在
 * 下一个 th 上（实测 elementFromPoint 命中 TH 而不是 SPAN），于是**根本拖不动**。
 * 现在改成本列内部最右侧 7px、不外溢；边界手势由「左列手柄」承接，符合直觉。
 * touch-action:none 让触屏拖动不被页面滚动抢走。 */
.grid-table th[data-colw]{position:relative}
.col-resizer{
  position:absolute;top:0;right:0;width:7px;height:100%;
  cursor:col-resize;z-index:7;user-select:none;touch-action:none;
  background:transparent;transition:background var(--dur) var(--ease);
}
/* 「操作」列（sticky 贴右）的**左边缘**手柄。
 * 为什么单独做一个：这一列 fixed 在容器右侧，右边缘就是表格尽头、常被滚动条压住，
 * 而用户真正想拖的是「审核 | 操作」那条线 —— 也就是这一列的左边界。
 * 只给左手柄、不给右手柄，避免同一条列上出现两个都能拖的把手造成误解。
 * z-index 要比 sticky 表头(6)/单元格(4) 都高，否则会被自己那一列盖住。 */
.col-resizer-l{
  position:absolute;top:0;left:0;width:8px;height:100%;
  cursor:col-resize;z-index:9;user-select:none;touch-action:none;
  background:transparent;transition:background var(--dur) var(--ease);
}
.grid-table th:hover .col-resizer-l{background:var(--brand-200)}
.col-resizer-l.dragging{background:var(--brand-500)}
.grid-table th:hover .col-resizer{background:var(--brand-200)}
.col-resizer.dragging{background:var(--brand-500)}
.grid-table tbody tr{transition:background var(--dur) var(--ease)}
.grid-table tbody tr:hover{background:var(--surface-2)}
.grid-table tbody tr:last-child td{border-bottom:none}
.grid-table.excel th{top:0}
.grid-table .idx{color:var(--text-3);width:52px;text-align:center}
/* 行操作列的横向排列。⚠️ 只能作用在 <td> 上。
 * 这个类现在也会挂在 <th class="row-actions">（列宽拖拽的左手柄要靠它定位、sticky 表头要对齐），
 * 而 `display:flex` 一旦落到 <th> 上，它就**不再是 table-cell** ——
 * 表头的 border-bottom 不再按表格单元格的算法拉伸，于是「操作」这一列的下划线和其它列对不上
 * （数据比对页最明显）。表头保留 table-cell，只把内边距/对齐交给下面这条规则。 */
/* 行操作列（表格最右那一列）。
 * 🔴 这里**绝不能**把 <td> 改成 display:flex。
 * 单元格一旦不是 table-cell，高度就不再随行高拉伸：同一行里别的列因为内容换行被撑高，
 * 而操作列只有自身内容高 —— 它的 border-bottom 会比其它列高出一截，
 * 看起来就是「操作部分的下划线不在一条线上」
 * （数据比对页实测：其它列 bottom=277.2，操作列 262.8，差 14.4px）。
 * 横向排列改用 <a> 的 margin 实现：inline-flex 的按钮在窄列里会自然折行，不需要 flex-wrap。
 * 表头（<th class="row-actions">）同理保留 table-cell，只补对齐方式。 */
.grid-table td.row-actions{
  text-align:center;vertical-align:middle;
  padding-left:6px;padding-right:6px;
}
.grid-table td.row-actions a{margin:3px 2px}
.grid-table th.row-actions{text-align:center;white-space:nowrap}
.row-actions a{
  display:inline-flex;align-items:center;justify-content:center;gap:4px;
  padding:5px 11px;margin:0;font-size:0.7812rem;font-weight:500;line-height:1.45;
  border:1px solid var(--border);border-radius:var(--r-xs);background:var(--surface);
  color:var(--brand-700);text-decoration:none;white-space:nowrap;
  transition:all var(--dur) var(--ease);
}
.row-actions a:hover{background:var(--brand-600);border-color:var(--brand-600);color:#fff;text-decoration:none;box-shadow:var(--shadow-sm)}
.row-actions a:active{transform:translateY(1px)}
.row-actions a.danger{border-color:#FBD5D5;background:var(--danger-50);color:var(--danger-600)}
.row-actions a.danger:hover{background:var(--danger-600);border-color:var(--danger-600);color:#fff;box-shadow:0 2px 8px rgba(214,69,69,.28)}

/* B8：锁定操作区（工具栏里的「锁定操作区」勾选框，状态在 ui-plus.js）。
 * 解决两件事：① 宽表滚到右边时「操作」列跟着跑掉，看不见也点不到；
 * ② 列一窄，几个按钮就折成两三行，行高忽高忽低。
 * ⚠️ 「不换行」只能靠 white-space:nowrap，**绝不能**用 display 去改 ——
 * 见上面那条注释：<td> 一旦不再是 table-cell，同一行各列的下划线就会错位。
 * 这里对 .excel（本来就 sticky）也生效：它只多一个「不换行」，粘右是它原本就有的。 */
.grid-table.lock-actions th.row-actions,
.grid-table.lock-actions td.row-actions{
  position:sticky;right:0;z-index:4;background:var(--surface);
  box-shadow:-6px 0 8px -6px rgba(15,23,42,.14);
  white-space:nowrap;
}
.grid-table.lock-actions th.row-actions{background:var(--surface-2);z-index:6}
.grid-table.lock-actions tbody tr:hover td.row-actions{background:var(--surface-2)}
[data-theme="dark"] .grid-table.lock-actions th.row-actions,
[data-theme="dark"] .grid-table.lock-actions td.row-actions{
  box-shadow:-6px 0 8px -6px rgba(0,0,0,.55);
}

/* B8：锁定开关所在的小工具条。贴在表格上方、右对齐，行高尽量压扁 ——
 * 它是「顺手一勾」的控件，不该把表格往下挤掉一屏。 */
.table-tools{
  display:flex;align-items:center;justify-content:flex-end;gap:12px;flex-wrap:wrap;
  margin:0 0 8px;font-size:0.75rem;color:var(--text-3);
}
.table-tools .check.inline{
  margin:0;font-size:0.75rem;font-weight:400;color:var(--text-2);gap:6px;cursor:pointer;
  line-height:1.2;
}
.table-tools .check.inline input{width:15px;height:15px}

/* 窄屏（≤700px）自动不锁定。
 * 列表页的操作列在 390px 竖屏上要有 180~230px 宽，钉在右边等于把数据全遮住
 * （实测：只剩「操作」表头能看见，中间的数据列被挤没）。此时横向滚动本来就得滑，
 * 钉住反而更难用。所以窄屏放弃 sticky/nowrap，恢复成普通列。
 * ⚠️ 只针对**非 .excel** 的表：数据页的冻结列是 A1 的既有设计，
 * 这条规则若一并套上去，会悄悄改掉它（特异性相同、位置更靠后，会盖住 .excel 的规则）。 */
@media (max-width:700px){
  .grid-table.lock-actions:not(.excel) th.row-actions,
  .grid-table.lock-actions:not(.excel) td.row-actions{
    position:static;box-shadow:none;white-space:normal;
  }
  .table-tools .check.inline::after{content:"（窄屏不生效）";color:var(--text-3)}
}

/* ===== 分页 ===== */
.pager{
  display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;
  padding:11px 14px;background:var(--surface-2);border-bottom:1px solid var(--border-soft);
  font-size:0.8125rem;color:var(--text-2);
}
.table-scroll>.pager:last-child{border-top:1px solid var(--border-soft);border-bottom:none}
.pager-form{display:flex;align-items:center;gap:8px}
.pager-form select{
  width:auto;min-width:86px;min-height:34px;padding:6px 30px 6px 10px;font-size:0.8438rem;
  border:1px solid var(--input-bd);border-radius:var(--r-sm);background:var(--surface);color:var(--text);
  font-family:inherit;cursor:pointer;
}
.pager-form select:focus{outline:none;border-color:var(--brand-500);box-shadow:0 0 0 3px var(--brand-100)}
.pager-nav{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.pager-nav a,.pager-nav .disabled{
  padding:6px 11px;border:1px solid var(--border);border-radius:var(--r-sm);
  background:var(--surface);color:var(--text-2);font-size:0.8125rem;line-height:1.2;
  transition:all var(--dur) var(--ease);
}
.pager-nav a:hover{text-decoration:none;border-color:var(--brand-300);color:var(--brand-600);background:var(--brand-50)}
.pager-nav .disabled{color:var(--text-3);border-color:var(--border-soft);background:var(--surface-2);cursor:default;opacity:.7}
.pager-info{color:var(--text);font-weight:600;margin:0 6px;white-space:nowrap}

/* ===== 提示 / 标签 ===== */
.alert{
  display:flex;gap:11px;padding:12px 15px;margin:12px 0;font-size:0.8438rem;line-height:1.6;
  border:1px solid transparent;border-radius:var(--r-md);
}
.alert-error{background:var(--danger-50);color:var(--danger-700);border-color:#FECACA}
.alert-ok{background:var(--ok-50);color:var(--ok-700);border-color:#A7F3D0}
/* 警示（不是错误）：用于「数据被截断」「筛选被忽略」这类「能用但要知道」的提示 */
.alert-warn{background:var(--warn-50);color:var(--warn-700);border-color:#FDE68A}
[data-theme="dark"] .alert-warn{background:#2E2408;color:#FAC775;border-color:#633806}
.pill{
  display:inline-flex;align-items:center;gap:4px;padding:2px 10px;border-radius:var(--r-full);
  font-size:0.75rem;font-weight:600;line-height:1.7;white-space:nowrap;
  background:var(--surface-2);color:var(--text-2);
}
.pill.green{background:var(--ok-50);color:var(--ok-700)}
.pill.amber{background:var(--warn-50);color:var(--warn-700)}
.pill.red{background:var(--danger-50);color:var(--danger-700)}
.tag{
  display:inline-block;padding:2px 10px;border-radius:var(--r-full);font-size:0.75rem;font-weight:600;
  line-height:1.7;background:var(--surface-2);color:var(--text-2);white-space:nowrap;
}
.tag-ok{background:var(--ok-50);color:var(--ok-700)}
.tag-err{background:var(--danger-50);color:var(--danger-700)}
.tag-warn{background:var(--warn-50);color:var(--warn-700)}

/* ===== 仪表盘 / 统计卡 ===== */
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:16px;margin-bottom:18px}
.stat{
  background:var(--surface);border:1px solid var(--border-soft);border-radius:var(--r-md);
  padding:18px;text-align:center;color:var(--text);transition:all var(--dur) var(--ease);
}
.stat:hover{text-decoration:none;border-color:var(--border);box-shadow:var(--shadow-md);transform:translateY(-2px)}
.stat-num{font-size:1.875rem;font-weight:700;color:var(--brand-600);letter-spacing:-.02em;line-height:1.15}
.stat-label{color:var(--text-3);font-size:0.7812rem;margin-top:4px}
.stat-value{font-size:1rem;font-weight:600;color:var(--text)}
.grid2{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px}
.link-list{list-style:none}
.link-list li{padding:8px 0;border-bottom:1px solid var(--border-soft)}
.link-list li:last-child{border-bottom:none}



/* ===== 权限分配 ===== */
.perm-group{border:1px solid var(--border-soft);border-radius:var(--r-md);padding:14px 16px;margin:12px 0}
.perm-group h4{color:var(--brand-700);font-size:0.8438rem;margin-bottom:8px}

/* ===== 搜索 / 筛选栏 ===== */
.search-bar{
  display:flex;gap:8px;align-items:center;flex-wrap:wrap;
  background:var(--surface);border:1px solid var(--border-soft);border-radius:var(--r-md);
  padding:12px 14px;box-shadow:var(--shadow-xs);margin-bottom:16px;
}
.search-bar input[type=text],.search-bar input:not([type]){
  width:auto;min-height:38px;padding:8px 12px;border:1px solid var(--input-bd);border-radius:var(--r-sm);
  background:var(--surface);font-size:0.875rem;font-family:inherit;color:var(--text);
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.search-bar input[type=text]:focus,.search-bar input:not([type]):focus{
  outline:none;border-color:var(--brand-500);box-shadow:0 0 0 3px var(--brand-100);
}
.search-bar select{
  width:auto;min-height:38px;padding:8px 30px 8px 12px;border:1px solid var(--input-bd);
  border-radius:var(--r-sm);background:var(--surface);font-size:0.875rem;font-family:inherit;color:var(--text);cursor:pointer;
}
.search-bar select:focus{outline:none;border-color:var(--brand-500);box-shadow:0 0 0 3px var(--brand-100)}

/* ===== 台账数据分析看板 =====
   自适应口径：所有列数/宽度跟随容器，不写死。
   - .kpi-grid / .analysis-grid 用 auto-fit + minmax(min(N,100%),1fr)：
     min() 保证容器比 N 还窄时轨道退化为 100%，绝不横向溢出。
   - 卡片一律 min-width:0，避免内部宽内容（长标签/长数字）反向撑破父级。
   - 少卡片时不要让最后一行孤零零占 1/3 宽：.analysis-grid 用 flex + flex-grow，
     最后一行的卡片会撑满整行，右侧不留大片空白。 */
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(150px,100%),1fr));gap:14px;margin:14px 0 4px}
.kpi-card{
  min-width:0;background:var(--surface);border:1px solid var(--border-soft);
  border-radius:var(--r-md);padding:15px 17px;box-shadow:var(--shadow-xs);
}
.kpi-value{font-size:1.5rem;font-weight:700;color:var(--brand-600);line-height:1.2;letter-spacing:-.02em;overflow-wrap:break-word}
.kpi-unit{font-size:0.8125rem;font-weight:500;color:var(--text-2);margin-left:4px}
.kpi-title{margin-top:4px;font-size:0.7812rem;color:var(--text-3)}

/* justify-content:center —— 卡片不满一行时整体居中（左右对称留白），
   而不是贴着左边、右边空一大块；窄屏单列时无影响。 */
.analysis-grid{display:flex;flex-wrap:wrap;gap:16px;align-items:stretch;justify-content:center}
.chart-card{
  flex:1 1 300px;min-width:min(300px,100%);max-width:640px;min-height:0;
  background:var(--surface);border:1px solid var(--border-soft);border-radius:var(--r-md);
  padding:15px 17px;box-shadow:var(--shadow-xs);overflow-wrap:break-word;
}
.chart-card-title{font-weight:600;color:var(--text);margin-bottom:10px;font-size:0.875rem}
.chart-card-body{min-height:60px;min-width:0}

/* 数值汇总的 6 个指标格：宽卡片最多 4 列，窄卡片自动降到 2 列。
   每格最小 112px 是「1,598,282.00」这类金额不被折断的下限
   （92px 会折成两行，104px 在 1920 宽下仍会挤到 5 列而折行）。 */
.stat-list{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(112px,100%),1fr));gap:8px 12px}
.stat-list .stat{background:var(--surface-2);border:none;border-radius:var(--r-sm);padding:8px 10px;text-align:left;min-width:0}
.stat-list .stat:hover{transform:none;box-shadow:none}
.stat-label{display:block}
.hist-title{margin:12px 0 6px;font-size:0.8125rem;color:var(--text-2)}

/* 横向条形：标签列可收缩（flex-shrink:1），窄容器里先让标签变窄，别把进度条挤没 */
.bars-h{display:flex;flex-direction:column;gap:8px}
.bar-row{display:flex;align-items:center;gap:8px;font-size:0.8125rem}
.bar-label{flex:0 1 110px;min-width:0;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bar-track{flex:1;min-width:32px;background:var(--surface-2);border-radius:var(--r-full);height:14px;overflow:hidden}
.bar-fill{display:block;height:100%;border-radius:var(--r-full);background:linear-gradient(90deg,var(--brand-500),var(--brand-600))}
.bar-val{flex:0 0 40px;text-align:right;color:var(--text-3)}

/* 竖向条形
   注意：容器必须 align-items:stretch。若用 flex-end，.bar-col 会收缩到内容高度，
   使 .bar-col-track 的 flex:1 拿不到剩余空间 → 柱子被压成 min-height 的 2px 细线。
   底部留 40px 给旋转后的坐标标签，避免标签溢出卡片/压到下一区块。
   自适应：柱子有最大宽度（数据少时不成巨柱），也有最小宽度 + 容器横向滚动
   （月份/年份多时柱子不会被压成细线，标签也不至于叠在一起）。 */
.bars-v{display:flex;align-items:stretch;gap:8px;height:186px;padding:6px 14px 40px;overflow-x:auto;overflow-y:hidden}
.bar-col{flex:1 0 44px;max-width:88px;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-end}
/* 用 auto margin 做「安全居中」：空间够则居中，不够则退化为 0（不像 justify-content:center 会裁掉左侧） */
.bars-v>.bar-col:first-child{margin-left:auto}
.bars-v>.bar-col:last-child{margin-right:auto}
.bar-col-val{font-size:0.75rem;color:var(--text);margin-bottom:3px;flex:0 0 auto}
.bar-col-track{width:100%;flex:1 1 0;display:flex;align-items:flex-end;min-height:0}
.bar-col-fill{width:100%;background:linear-gradient(180deg,var(--brand-500),var(--brand-600));border-radius:var(--r-xs) var(--r-xs) 0 0;min-height:2px}
.bar-col-label{font-size:0.6875rem;color:var(--text-3);margin-top:6px;flex:0 0 auto;white-space:nowrap;transform:rotate(-40deg);transform-origin:top right;max-width:none;overflow:visible}

/* 饼图图例：宽卡片自动分多列，卡片不会因为图例过长被撑得很高 */
.chart-svg{width:100%;max-width:min(380px,100%);height:auto;display:block;margin:0 auto}
.legend{margin-top:10px;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(140px,100%),1fr));gap:4px 14px;font-size:0.8125rem}
.legend-item{display:flex;align-items:center;gap:6px;color:var(--text);min-width:0}
.legend-dot{width:10px;height:10px;border-radius:50%;flex:0 0 10px}

/* ===== 登录页 ===== */
.login-page{
  display:flex;align-items:center;justify-content:center;min-height:100vh;padding:32px 16px;
  background:
    radial-gradient(640px 320px at 18% -10%, var(--brand-50), transparent 60%),
    radial-gradient(520px 260px at 88% 8%, var(--violet-50), transparent 55%),
    var(--bg);
}
.login-card{
  background:var(--surface);width:400px;max-width:92vw;border:1px solid var(--border-soft);
  border-radius:var(--r-xl);padding:34px 32px;box-shadow:var(--shadow-lg);
}
.login-head{text-align:center;margin-bottom:22px}
.login-logo{font-size:2.5rem;line-height:1}
.login-head h1{font-size:1.375rem;color:var(--text);margin-top:8px;font-weight:600;letter-spacing:-.02em}
.login-head p{color:var(--text-3);font-size:0.75rem;letter-spacing:2px;margin-top:2px}
.login-card label{display:block;margin:14px 0 6px;font-size:0.8125rem;font-weight:500;color:var(--text-2)}
.login-card input{
  width:100%;min-height:46px;padding:12px 14px;border:1px solid var(--input-bd);border-radius:var(--r-sm);
  font-size:0.9375rem;background:var(--surface);color:var(--text);
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.login-card input:focus{outline:none;border-color:var(--brand-500);box-shadow:0 0 0 3px var(--brand-100)}

/* ===== 安装页 ===== */
.setup-box{
  background:var(--surface);width:560px;max-width:92vw;margin:8vh auto;
  border:1px solid var(--border-soft);border-radius:var(--r-xl);padding:34px;box-shadow:var(--shadow-lg);
}
.setup-box h1{color:var(--text);font-size:1.375rem;margin-bottom:14px;letter-spacing:-.02em}
.setup-log{list-style:disc;padding-left:22px;margin:10px 0}
.setup-log li{margin:6px 0;color:var(--text)}
.setup-tip{color:var(--text-2);font-size:0.8125rem;margin:14px 0}
.setup-box .btn{margin-top:8px}
.setup-box code{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:0.7812rem;
  background:var(--surface-2);padding:1px 6px;border-radius:var(--r-xs);
}

/* ===== 打印模板编辑器（含自由排版富文本）=====
   注意：编辑器页走 View::layout（只加载 ui.css），所以这些样式必须放这里，
   放 print.css 是不生效的（print.css 只在独立打印页加载）。 */
.pt-form-table th{width:150px;text-align:left;vertical-align:middle}
.pt-hint{color:var(--text-2);font-size:0.75rem;margin-top:4px}
.pt-hint code,.pt-editor code{
  background:var(--surface-2);border:1px solid var(--border-soft);border-radius:var(--r-xs);padding:0 4px;font-size:0.75rem;
}
.pt-items td{vertical-align:middle}
.pt-items .pt-fname{font-weight:600}
.pt-items .pt-fmeta{color:var(--text-3);font-size:0.75rem}
.pt-items .btn-sm{padding:2px 9px}
.pt-list-name{font-weight:600}
.pt-skel-row{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:6px 0 10px}
.pt-skel-lab{color:var(--text-2);font-size:0.8125rem}

/* 自由排版：工具栏 + 纸面编辑区 */
.rte-wrap{border:1px solid var(--border);border-radius:var(--r-md);background:var(--surface);overflow:hidden}
.rte-bar{
  display:flex;flex-wrap:wrap;align-items:center;gap:4px;
  padding:6px 8px;background:var(--surface-2);border-bottom:1px solid var(--border);
  position:sticky;top:0;z-index:5;
}
.rte-btn{
  min-width:30px;padding:4px 8px;border:1px solid var(--border);border-radius:var(--r-xs);
  background:var(--surface);color:var(--text);font-size:0.8125rem;line-height:1.4;cursor:pointer;
}
.rte-btn:hover{border-color:var(--brand-400);color:var(--brand-700)}
.rte-sep{width:1px;height:18px;background:var(--border);margin:0 3px}
.rte-sel{
  padding:4px 6px;border:1px solid var(--border);border-radius:var(--r-xs);
  background:var(--surface);color:var(--text);font-size:0.8125rem;max-width:180px;
}
.rte-ins{border-color:var(--brand-300);color:var(--brand-700);font-weight:600}
.rte-color{
  width:32px;height:26px;padding:1px;border:1px solid var(--border);border-radius:var(--r-xs);
  background:var(--surface);cursor:pointer;
}
/* 编辑区刻意固定为「白纸黑字」：它模拟的就是打印出来的纸面，不跟随暗色主题 */
.rte-area{
  min-height:380px;max-height:70vh;overflow:auto;
  padding:16mm 14mm;outline:none;background:#fff;color:#000;
  font-family:"Songti SC","STSong","SimSun","Noto Serif CJK SC",serif;
  font-size:10.5pt;line-height:1.75;
}
.rte-area:focus{box-shadow:inset 0 0 0 2px var(--brand-200)}
.rte-area p{margin:0 0 6px}
.rte-area h1{font-size:18pt;font-weight:700;text-align:center;letter-spacing:.1em;margin:0 0 12px}
.rte-area h2{font-size:14pt;font-weight:700;margin:12px 0 6px}
.rte-area h3{font-size:12pt;font-weight:700;margin:10px 0 4px}
.rte-area table{width:100%;border-collapse:collapse;margin:6px 0;table-layout:fixed}
.rte-area th,.rte-area td{border:1px solid #999;padding:3px 5px;vertical-align:middle}
.rte-area thead th{background:#f2f2f2;text-align:center}
.rte-area blockquote{margin:6px 0;padding-left:10px;border-left:3px solid #b8bec7;color:#333}
.rte-area pre{
  font-family:ui-monospace,Menlo,Consolas,monospace;font-size:9.5pt;white-space:pre-wrap;
  background:#f6f7f9;border:1px solid #dcdfe4;border-radius:3px;padding:6px 8px;
}
.rte-area hr{border:0;border-top:1px solid #000;margin:8px 0}
.rte-area .bf{display:inline-block;min-width:90px;border-bottom:1px solid #000;height:1em;vertical-align:-2px}
.rte-area .pb{display:block;height:0;border-top:1px dashed #93bafd;margin:8px 0}
.rte-area .ph{background:#dbe8fe;color:#1e40af;border-radius:3px;padding:0 3px;font-size:10pt}
.rte-adv{margin-top:10px}
.rte-adv summary{cursor:pointer;color:var(--text-2);font-size:0.8125rem}
.rte-adv textarea{
  width:100%;margin-top:6px;padding:8px 10px;border:1px solid var(--border);border-radius:var(--r-xs);
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:0.75rem;line-height:1.6;
  background:var(--surface-2);color:var(--text);resize:vertical;
}
/* 排版方式切换：按 form 上的 mode-free 类显隐对应区块（纯 CSS，无 JS 也能看到完整表单） */
.pt-editor.mode-free [data-mode-block="fields"]{display:none}
.pt-editor:not(.mode-free) [data-mode-block="free"]{display:none}

/* ===== 响应式 ===== */
@media (max-width:860px){
  .cards{grid-template-columns:repeat(2,1fr)}
  .grid2{grid-template-columns:1fr}
  .sidebar{
    position:fixed;left:0;top:0;bottom:0;z-index:60;height:100vh;
    transform:translateX(-100%);transition:transform .22s var(--ease);
    box-shadow:var(--shadow-xl);
  }
  .sidebar.open{transform:translateX(0)}
  .menu-toggle{display:inline-block}
  .content{padding:18px 16px 40px}
  .topbar{padding:0 16px}
  /* 分析看板：窄屏收紧留白，图表别占太高 */
  .analysis-grid{gap:12px}
  .chart-card{padding:13px 14px}
  .kpi-grid{gap:12px}
  .bars-v{height:164px;padding:4px 10px 36px}
  .bar-col{max-width:72px}
}
@media (max-width:560px){
  .cards{grid-template-columns:1fr}
  .form-row input,.form-row select{min-width:0;width:100%}
  /* 分析看板：手机上一屏内尽量多给图表空间 */
  .analysis-grid{gap:10px}
  .chart-card{padding:12px 13px;flex-basis:100%}
  .kpi-card{padding:12px 14px}
  .kpi-value{font-size:1.3125rem}
  .bars-v{height:150px;gap:6px;padding:4px 8px 32px}
  .bar-col{flex-basis:40px;max-width:64px}
  .bar-col-label{font-size:0.625rem}
  .bar-label{flex-basis:84px}
  .stat-list{gap:6px 8px}
  .stat-list .stat{padding:7px 8px}
  .legend{grid-template-columns:1fr}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;transition-duration:.01ms !important}
}

/* ---------- 列表勾选导出（台账数据页） ---------- */
.sel-bar{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:0 0 12px;font-size:0.8125rem;
}
.sel-bar .btn{padding:4px 12px;font-size:0.8125rem}
.sel-bar .hint{margin-left:auto;font-size:0.75rem}
.grid-table th.sel,.grid-table td.sel{width:36px;min-width:36px;text-align:center;padding-left:8px;padding-right:8px}
.grid-table th.sel{cursor:pointer}
.grid-table th.sel input,.grid-table td.sel input{width:15px;height:15px;margin:0;cursor:pointer}

/* ---------- 导入列映射确认页 ---------- */
.map-table td,.map-table th{vertical-align:top}
.map-table td select{width:100%;max-width:260px}
.map-table .map-status{white-space:nowrap;color:var(--text-2)}


/* ---------- 附件上传：逐文件进度（static/upload.js） ---------- */
.up-wrap{display:block;border-radius:var(--r-sm)}
.up-wrap.up-drag{outline:2px dashed var(--theme);outline-offset:4px;background:var(--theme-soft)}
.up-hint{display:block;margin-top:4px}

/* 附件字段的「选取文件」按钮。
   原生 <input type=file> 的按钮由浏览器决定尺寸，在 macOS 上只有 20 来像素高，
   比旁边的输入框小一大截，点起来也费劲 —— 尤其这个系统的主要用户是在
   工伤档案场景下批量录材料，一天要点几十次。
   做法：把整个 input 撑成一块可点区域（不靠 ::file-selector-button 单独放大），
   这样点框内任意位置都能唤起文件选择，而不只是那几个字的按钮。
   ::file-selector-button 只负责把按钮本身也做成主色实心块，视觉上有个明确目标。 */
.up-wrap input[type=file]{
  display:block;width:100%;box-sizing:border-box;
  min-height:42px;padding:6px 12px;
  border:1.5px dashed var(--border);border-radius:var(--r-sm);
  background:var(--surface);color:var(--text-2);
  font-family:inherit;font-size:0.875rem;
  cursor:pointer;
  transition:border-color .15s,background .15s;
}
.up-wrap input[type=file]:hover{
  border-color:var(--theme);background:var(--theme-soft);
}
.up-wrap input[type=file]:focus-visible{
  outline:2px solid var(--theme);outline-offset:2px;
}
.up-wrap input[type=file]::file-selector-button,
.up-wrap input[type=file]::-webkit-file-upload-button{
  margin-right:12px;padding:8px 20px;
  border:0;border-radius:var(--r-xs);
  background:var(--theme);color:#fff;
  font-family:inherit;font-size:0.875rem;font-weight:500;line-height:1.4;
  cursor:pointer;
  transition:filter .15s;
}
.up-wrap input[type=file]::file-selector-button:hover,
.up-wrap input[type=file]::-webkit-file-upload-button:hover{filter:brightness(.92)}

.up-list{display:flex;flex-direction:column;gap:6px;margin-top:8px}
.up-list:empty{margin-top:0}
.up-row{
  display:grid;gap:8px;align-items:center;font-size:0.8125rem;
  grid-template-columns:minmax(120px,1.5fr) 64px minmax(90px,1.2fr) 44px minmax(84px,auto) auto auto;
  padding:6px 10px;border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface-2);
}
.up-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text)}
.up-size{color:var(--text-3);font-variant-numeric:tabular-nums;white-space:nowrap}
.up-barwrap{height:8px;background:var(--border);border-radius:var(--r-full);overflow:hidden}
.up-bar{display:block;height:100%;width:0;background:var(--theme);transition:width .18s var(--ease)}
.up-pct{color:var(--text-2);text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
.up-st{color:var(--text-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.up-row .up-view,.up-row button{
  padding:2px 9px;font-size:0.75rem;line-height:1.6;border-radius:var(--r-xs);
  border:1px solid var(--border);background:var(--surface);color:var(--text-2);cursor:pointer;text-decoration:none;
}
.up-row .up-view:hover,.up-row button:hover{border-color:var(--theme);color:var(--theme)}
.up-row[data-st="ok"] .up-bar{background:var(--ok-600)}
.up-row[data-st="ok"] .up-st{color:var(--ok-600)}
.up-row[data-st="err"] .up-bar{background:var(--danger-600)}
.up-row[data-st="err"] .up-st{color:var(--danger-600)}
.up-row[data-st="err"]{border-color:var(--danger-500);background:var(--danger-50)}
@media screen and (max-width:560px){
  .up-row{grid-template-columns:1fr auto;row-gap:4px}
  .up-barwrap{grid-column:1 / -1}
  .up-pct{grid-column:1 / -1;text-align:left}
}

/* ---------- 一档视图：卡片 / 看板 / 日历 ---------- */
.lg-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px}
.lg-card{display:block;background:var(--surface);border:1px solid var(--border-soft);border-radius:var(--r-md);
  padding:14px 16px;color:var(--text);transition:all var(--dur) var(--ease);text-decoration:none}
.lg-card:hover{border-color:var(--theme);box-shadow:var(--shadow-md);transform:translateY(-2px);text-decoration:none}
.lg-card-title{font-weight:600;font-size:0.9375rem;margin-bottom:8px;line-height:1.4;word-break:break-all}
.lg-card-body{display:flex;flex-direction:column;gap:4px}
.lg-card-row{display:flex;gap:8px;font-size:0.7812rem;line-height:1.6}
.lg-card-row .k{color:var(--text-3);flex:0 0 auto;min-width:52px}
.lg-card-row .v{color:var(--text-2);flex:1 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lg-card-foot{margin-top:10px;padding-top:8px;border-top:1px dashed var(--border-soft);color:var(--text-3);font-size:0.7188rem}

.lg-board{display:flex;gap:12px;overflow-x:auto;padding-bottom:8px}
.lg-board-col{flex:0 0 240px;min-width:240px;background:var(--surface-2);border:1px solid var(--border-soft);border-radius:var(--r-md);display:flex;flex-direction:column}
.lg-board-head{padding:10px 12px;font-weight:600;font-size:0.8125rem;border-bottom:1px solid var(--border-soft);display:flex;justify-content:space-between;align-items:center;gap:6px}
.lg-board-body{padding:8px;display:flex;flex-direction:column;gap:8px;max-height:62vh;overflow-y:auto}
.lg-board-card{display:block;background:var(--surface);border:1px solid var(--border-soft);border-radius:var(--r-sm);
  padding:9px 11px;font-size:0.8125rem;color:var(--text);line-height:1.5;transition:all var(--dur) var(--ease)}
.lg-board-card:hover{border-color:var(--theme);box-shadow:var(--shadow-sm);text-decoration:none}
/* 卡片上的快捷流转按钮（触屏没法 drag&drop，靠它改状态） */
.lg-bc-title{word-break:break-all}
.lg-bc-foot{display:flex;align-items:center;justify-content:space-between;gap:6px;margin-top:6px;flex-wrap:wrap}
.lg-bc-foot .muted{font-size:0.6875rem}
.lg-move{display:inline-flex;align-items:center;padding:3px 9px;border:1px solid var(--theme);border-radius:999px;
  background:var(--theme-soft);color:var(--theme);font-size:0.7188rem;line-height:1.5;min-height:26px;
  cursor:pointer;white-space:nowrap;user-select:none;-webkit-user-select:none;-webkit-tap-highlight-color:transparent}
.lg-move:hover{background:var(--theme);color:#fff;text-decoration:none}
.lg-move.is-busy{opacity:.45;pointer-events:none}

.lg-cal{width:100%;border-collapse:collapse;table-layout:fixed}
.lg-cal th{padding:6px 4px;font-size:0.75rem;color:var(--text-3);font-weight:600;border-bottom:1px solid var(--border);background:var(--surface-2)}
.lg-cal td{border:1px solid var(--border-soft);vertical-align:top;padding:4px;height:96px;font-size:0.75rem}
.lg-cal-empty{background:var(--surface-2)}
.lg-cal-day.is-today{background:var(--theme-soft);outline:1px solid var(--theme)}
.lg-cal-num{color:var(--text-3);font-size:0.7188rem;margin-bottom:3px}
.lg-cal-day.is-today .lg-cal-num{color:var(--theme);font-weight:700}
.lg-cal-item{display:block;background:var(--theme-soft);color:var(--theme);border-radius:4px;padding:1px 5px;margin-bottom:3px;
  font-size:0.7188rem;line-height:1.6;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-decoration:none}
.lg-cal-item:hover{background:var(--theme);color:#fff}
.lg-cal-more{color:var(--text-3);font-size:0.6875rem;padding-left:4px}
@media screen and (max-width:860px){
  .lg-cards{grid-template-columns:repeat(auto-fill,minmax(180px,1fr))}
  .lg-board-col{flex:0 0 200px;min-width:200px}
  .lg-cal td{height:72px}
}
/* 触屏：命中区放大到 34px，手指点得中 */
@media screen and (max-width:560px){
  .lg-move{min-height:34px;padding:6px 12px;font-size:0.7812rem}
}

/* ---------- 顶栏全局搜索 ---------- */
/* ===== 顶栏全局搜索：输入框 + 按钮必须「同高、同字体、同边框」=====
 * 原来两者高度差 12.4px、顶端差 6.2px，看着像两个控件硬拼在一起。原因是：
 *   ① 输入框在 <form> 里，吃到 `form input[type=text]{min-height:var(--input-h)}` = 42px；
 *      而 <button> 没有对应规则，只有 padding 6+6 + line-height 15.6 + 边框 = 29.6px。
 *   ② 按钮没有继承 body 字体（浏览器默认 button 用 Arial），输入框是 -apple-system。
 * 修法：显式钉死同一个 height / font-family / line-height / box-sizing，
 * 不再依赖「谁继承了谁」。高度取 36px：顶栏本身 60px，42px 的输入框在里面太满。
 * ============================================================ */
.top-search{display:flex;align-items:center;gap:0;margin-right:8px}
.top-search input[type="text"],
.top-search button{
  height:36px;box-sizing:border-box;
  margin:0;padding-top:0;padding-bottom:0;
  font-family:inherit;font-size:0.8125rem;line-height:1;
  border:1px solid var(--border);
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease),
             box-shadow var(--dur) var(--ease),width var(--dur) var(--ease);
}
.top-search input[type="text"]{
  /* min-height 必须显式归零：form input 的 42px 会把它顶高，两边就又不齐了 */
  min-height:0;width:200px;padding-left:11px;padding-right:11px;
  color:var(--text);background:var(--surface-2);
  border-right:0;border-radius:var(--r-sm) 0 0 var(--r-sm);outline:none;
}
.top-search input[type="text"]:hover{border-color:var(--ink-300)}
.top-search input[type="text"]:focus{
  background:var(--surface);border-color:var(--theme);width:240px;
  box-shadow:inset 0 0 0 1px var(--theme);   /* 只描内圈：外圈光晕会被相邻按钮切断，反而更难看 */
}
.top-search input[type="text"]::placeholder{color:var(--text-3)}
.top-search button{
  /* 固定宽度：🔍 在不同系统里的字宽不一样，不给宽度按钮会忽宽忽窄 */
  display:inline-flex;align-items:center;justify-content:center;
  width:40px;padding-left:0;padding-right:0;
  background:var(--surface-2);color:var(--text-2);
  border-radius:0 var(--r-sm) var(--r-sm) 0;
  cursor:pointer;
}
.top-search button:hover{background:var(--theme);color:#fff;border-color:var(--theme)}
.top-search button:active{transform:translateY(1px)}
.top-search input[type="text"]:focus + button{border-color:var(--theme)}
/* 900px 左右顶栏排不下（实测整页横滚 21px）：搜索框先收窄，再往下才隐藏。
 * 顺序很关键 —— 先缩搜索框，不够再收字号/密度下拉。 */
@media screen and (max-width:1000px){
  .top-search input[type="text"]{width:150px}
  .top-search input[type="text"]:focus{width:190px}
  .top-right{gap:10px}
  .ui-prefs{gap:4px}
  .ui-prefs select{max-width:64px}
}
@media screen and (max-width:860px){
  .top-search input[type="text"]{width:130px}
  .top-search input[type="text"]:focus{width:160px}
}
@media screen and (max-width:560px){.top-search{display:none}}

/* ===== 办公协同：页签 / 任务列表 ===== */
.tabs{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin:0 0 14px}
.tabs .pill{margin-left:4px}
@media screen and (max-width:560px){.tabs{gap:4px}.tabs .btn-sm{padding:4px 8px;font-size:0.75rem}}

/* ===== 看板拖拽改状态（目标状态需在「审批流转」里勾选「允许无意见直达」）===== */
.lg-board-card[draggable="true"]{cursor:grab}
.lg-board-card[draggable="true"]:active{cursor:grabbing}
.lg-board-col.lg-drop-on{border-color:var(--theme);box-shadow:inset 0 0 0 2px var(--theme-soft)}
.lg-board-col.lg-drop-on .lg-board-head{background:var(--theme-soft);color:var(--theme)}
/* 折叠的空列：仍在 DOM 里（拖到看板边缘时由脚本去掉这个类临时展开），不能删节点 */
.lg-board-col.lg-col-hide{display:none}
/* 临时展开的列淡入：横排布局里竖向位移会跟滚动条打架，改成从左侧轻微滑入 + 淡入，
   时长压到 .14s —— 拖拽期间的动画越长，用户越觉得"手跟不上了"。脚本已做 scrollLeft
   锚定补偿，所以动画只负责"看得出多了一列"，不需要再靠位移表达方向。 */
.lg-board-col[data-just="1"]{animation:lgColIn .14s ease-out}
@keyframes lgColIn{from{opacity:0;transform:translateX(-6px)}to{opacity:1;transform:none}}
@media print{.lg-board-card[draggable="true"]{cursor:auto}.lg-move{display:none}.lg-board-col.lg-col-hide{display:none}}

/* ===== A6：详情页宽屏左右分栏 =====
   左 = 字段表（主内容），右 = 提醒 / 审批流转 / 变更时间线（辅助信息）。
   窄屏（<1200）自然堆叠成一列，不改变原有阅读顺序。 */
.detail-split{display:grid;grid-template-columns:minmax(0,1fr);gap:16px;align-items:start}
@media screen and (min-width:1200px){
  .detail-split{grid-template-columns:minmax(0,1.55fr) minmax(320px,1fr)}
  /* 右栏跟随滚动，长字段表往下翻时辅助信息始终可见 */
  .detail-side{position:sticky;top:76px}
  .detail-split > .detail-main > .card:last-child{margin-bottom:0}
  .detail-side > .card:last-child{margin-bottom:0}
}

/* ===== B4：移动端底部固定操作栏 =====
   ≤560px 时把最常用的动作固定在拇指区，省得每次滚回顶部。
   内容区补 padding-bottom，避免最后一行被栏盖住。 */
.mobile-bar{
  display:none;position:fixed;left:0;right:0;bottom:0;z-index:40;
  padding:8px 10px calc(8px + env(safe-area-inset-bottom,0px));
  background:var(--surface);
  background:color-mix(in srgb, var(--surface) 94%, transparent);
  border-top:1px solid var(--border);
  backdrop-filter:saturate(180%) blur(12px);
  -webkit-backdrop-filter:saturate(180%) blur(12px);
  box-shadow:0 -4px 16px rgba(15,23,42,.06);
}
.mobile-bar-inner{display:flex;align-items:center;gap:8px}
.mobile-bar a,.mobile-bar button{
  flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  padding:7px 4px;border:1px solid transparent;border-radius:var(--r-sm);
  background:transparent;color:var(--text-2);font-size:0.6875rem;font-family:inherit;
  line-height:1.2;cursor:pointer;white-space:nowrap;overflow:hidden;
}
.mobile-bar a:active,.mobile-bar button:active{background:var(--surface-2)}
.mobile-bar .mb-ico{font-size:1.0625rem;line-height:1}
.mobile-bar .mb-primary{color:var(--theme);font-weight:500}
@media screen and (max-width:560px){
  .mobile-bar{display:block}
  .app-body.has-mobile-bar .content{padding-bottom:84px}
}

/* ===== B5：全局命令面板（Ctrl/⌘+K） ===== */
.cmdk{
  position:fixed;inset:0;z-index:200;display:none;
  background:rgba(15,23,42,.42);
  padding:10vh 16px 16px;
}
.cmdk.open{display:block}
.cmdk-box{
  max-width:620px;margin:0 auto;background:var(--surface);
  border:1px solid var(--border);border-radius:var(--r-lg);
  box-shadow:var(--shadow-xl);overflow:hidden;
}
.cmdk-input{
  width:100%;border:0;border-bottom:1px solid var(--border-soft);
  padding:15px 18px;font-size:1rem;font-family:inherit;
  background:transparent;color:var(--text);outline:none;
}
.cmdk-list{max-height:52vh;overflow-y:auto;padding:6px}
.cmdk-item{
  display:flex;align-items:center;gap:10px;padding:9px 12px;
  border-radius:var(--r-sm);cursor:pointer;font-size:0.875rem;color:var(--text);
}
.cmdk-item .ck-ico{flex:none;width:20px;text-align:center;color:var(--text-3)}
.cmdk-item .ck-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cmdk-item .ck-type{flex:none;font-size:0.6875rem;color:var(--text-3);
  border:1px solid var(--border-soft);border-radius:var(--r-full);padding:1px 7px}
.cmdk-item.on{background:var(--brand-600);color:#fff}
.cmdk-item.on .ck-ico,.cmdk-item.on .ck-type{color:#fff;border-color:rgba(255,255,255,.4)}
.cmdk-empty{padding:22px 16px;text-align:center;color:var(--text-3);font-size:0.8125rem}
.cmdk-foot{
  padding:8px 14px;border-top:1px solid var(--border-soft);
  font-size:0.6875rem;color:var(--text-3);display:flex;gap:14px;flex-wrap:wrap;
}
.cmdk-foot kbd{
  font-family:inherit;font-size:0.6875rem;padding:1px 5px;
  border:1px solid var(--border);border-radius:4px;background:var(--surface-2);
}

/* ===== B3：本地草稿恢复提示 ===== */
.draft-tip{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:10px 14px;margin:0 0 14px;
  background:var(--warn-50);border:1px solid var(--warn-500);
  border-radius:var(--r-md);font-size:0.8125rem;color:var(--text);
}
.draft-tip .btn{height:30px;padding:0 12px;font-size:0.7812rem}

/* ===== 键盘焦点行（B2 j/k 导航） ===== */
.grid-table tbody tr.kb-cur{outline:2px solid var(--brand-500);outline-offset:-2px}
.grid-table tbody tr.kb-cur td{background:var(--brand-50)}
[data-theme="dark"] .grid-table tbody tr.kb-cur td{background:var(--brand-100)}

/* ===== A2/A5：顶栏字号与密度下拉 ===== */
.ui-prefs{display:inline-flex;align-items:center;gap:6px}
.ui-prefs select{
  height:30px;padding:0 6px;font-size:0.75rem;font-family:inherit;
  color:var(--text-2);background:var(--surface-2);
  border:1px solid var(--border);border-radius:var(--r-sm);cursor:pointer;
}
.ui-prefs select:hover{color:var(--text);border-color:var(--border-secondary,var(--border))}
/* 手机上顶栏太挤：密度那个藏掉（还能用 Ctrl+K 或列设置里改） */
@media screen and (max-width:860px){
  [data-density-select]{display:none}
}
@media screen and (max-width:560px){
  .ui-prefs{display:none}
}

/* 列显隐（列表「列设置」用）。必须放在全局样式里：
 * 这组 class 由页面内联脚本动态加，任何模块（台账 / 知识库）都要能生效。 */
.lg-hide{display:none!important}

/* ============================================================
 * 扫码录入（移动端）—— 文本字段旁的「⛶」按钮 + 取景弹层
 * 尺寸都用 rem/px 混排：弹层是浮层，不该跟着字号档位一起放大
 * ============================================================ */
.scan-btn{
  display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;margin-left:6px;flex:0 0 auto;
  border:1px solid var(--input-bd,var(--border));border-radius:var(--r-md,8px);
  background:var(--card);color:var(--ink-600,#475467);font-size:1rem;line-height:1;
  cursor:pointer;vertical-align:middle;transition:background var(--dur,.15s);
}
.scan-btn:hover{background:var(--ink-50,#f8fafc);color:var(--brand-600)}
.scan-ok{
  margin:4px 0 0;font-size:.8125rem;color:var(--ok-700,#047857);
}
.scan-modal{
  position:fixed;inset:0;z-index:9998;display:none;
  align-items:center;justify-content:center;padding:16px;
  background:rgba(15,23,42,.62);
}
.scan-modal.open{display:flex}
.scan-box{
  width:100%;max-width:420px;background:var(--card);color:var(--ink-800,#1d2939);
  border-radius:var(--r-lg,12px);padding:16px;box-shadow:0 24px 60px rgba(0,0,0,.35);
  max-height:92vh;overflow:auto;
}
.scan-box h3{
  margin:0 0 12px;font-size:1rem;display:flex;align-items:center;justify-content:space-between;gap:8px;
}
.scan-x{
  border:0;background:transparent;font-size:1.375rem;line-height:1;cursor:pointer;
  color:var(--ink-400,#98a2b3);padding:0 4px;
}
.scan-stage{
  position:relative;background:#0b1220;border-radius:var(--r-md,8px);
  aspect-ratio:4/3;overflow:hidden;display:flex;align-items:center;justify-content:center;
}
.scan-stage video{width:100%;height:100%;object-fit:cover;display:block}
.scan-frame{
  position:absolute;left:50%;top:50%;width:62%;aspect-ratio:1/1;
  transform:translate(-50%,-50%);border:2px solid rgba(255,255,255,.85);
  border-radius:10px;box-shadow:0 0 0 9999px rgba(0,0,0,.28);pointer-events:none;
}
.scan-msg{margin:10px 0 0;font-size:.8125rem;color:var(--ink-600,#475467)}
.scan-acts{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
.scan-acts .btn{flex:1 1 auto;justify-content:center;text-align:center}
.scan-tip{margin:10px 0 0;font-size:.75rem;color:var(--ink-400,#98a2b3);line-height:1.5}
@media (max-width:560px){
  .scan-box{max-width:none}
  .scan-stage{aspect-ratio:3/4}
}

/* ===== 应用管理（m=setting&a=apps）=====
   一张卡片 = 一个应用，整张卡片可点（label 包住 input）。
   开关是纯 CSS 的：input 绝对定位透明（保留键盘焦点与无障碍语义），
   可见的圆角滑块是紧跟其后的 .switch-track，靠 :checked 兄弟选择器换色/位移。 */
.app-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(238px,1fr));gap:12px;margin:4px 0 18px}
.app-card{
  position:relative;display:block;padding:14px 16px;cursor:pointer;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.app-card:hover{border-color:var(--brand-300)}
.app-card.on{border-color:var(--brand-400);box-shadow:0 0 0 3px var(--brand-50)}
.app-card-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.app-card-name{font-weight:600;color:var(--text)}
.app-card-desc{display:block;margin:6px 0 12px;font-size:0.8125rem;line-height:1.55;color:var(--text-3)}
.app-card-foot{display:flex;align-items:center;justify-content:space-between;gap:10px}
.app-card-foot code{font-size:0.75rem;color:var(--text-3)}
.app-card input[type=checkbox]{position:absolute;width:1px;height:1px;opacity:0;margin:0}
.switch{display:inline-flex;align-items:center;flex:0 0 auto}
.switch-track{
  display:inline-block;width:38px;height:21px;border-radius:11px;background:var(--ink-300,#cbd5e1);
  position:relative;transition:background var(--dur) var(--ease);
}
.switch-track::after{
  content:"";position:absolute;left:2px;top:2px;width:17px;height:17px;border-radius:50%;
  background:#fff;box-shadow:0 1px 2px rgba(15,23,42,.25);transition:transform var(--dur) var(--ease);
}
.app-card input:checked + .switch-track{background:var(--brand-600)}
.app-card input:checked + .switch-track::after{transform:translateX(17px)}
.app-card input:focus-visible + .switch-track{box-shadow:0 0 0 3px var(--brand-100)}
