/* 本地单人用的小系统，样式够看就行，不引入框架 */
:root {
  --bg: #f6f7f9; --card: #fff; --line: #e3e6ea; --text: #1f2328;
  --muted: #656d76; --accent: #0969da; --ok: #1a7f37; --warn: #9a6700;
  --bad: #cf222e;
}
* { box-sizing: border-box; }
body { margin: 0; background: var(--bg); color: var(--text);
  font: 14px/1.6 "Microsoft YaHei", -apple-system, Segoe UI, sans-serif; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
header { background: var(--card); border-bottom: 1px solid var(--line);
  padding: 10px 20px; display: flex; align-items: center; gap: 18px;
  flex-wrap: wrap;                      /* 窄屏时状态条换行，而不是把导航挤没 */
  position: sticky; top: 0; z-index: 10; }
header .brand { font-weight: 700; }
header nav { display: flex; gap: 14px; flex-wrap: wrap; }
header nav a { padding: 4px 2px; }
header nav a.on { border-bottom: 2px solid var(--accent); font-weight: 600; }
header .spacer { flex: 1; min-width: 0; }
/* 满宽：这是个数据密集的表格系统，宽屏上留白等于浪费 */
main { padding: 20px; width: 100%; }
.card { background: var(--card); border: 1px solid var(--line);
  border-radius: 8px; padding: 16px; margin-bottom: 16px; }
.card h2 { margin: 0 0 12px; font-size: 15px; }
.row { display: flex; gap: 16px; flex-wrap: wrap; }
.row > .card { flex: 1; min-width: 320px; }
.stat { display: flex; gap: 24px; flex-wrap: wrap; }
.stat div { min-width: 90px; }
.stat b { display: block; font-size: 24px; line-height: 1.2; }
.stat span { color: var(--muted); font-size: 12px; }
table { border-collapse: collapse; width: 100%; font-size: 13px; }
th, td { border-bottom: 1px solid var(--line); padding: 7px 8px;
  text-align: left; vertical-align: top; }
th { background: #fafbfc; font-weight: 600; white-space: nowrap; }
tr.delisted { background: #fff5f5; }
/* 鼠标划过整行高亮。写在 td 上而不是 tr 上 —— 表头那行用的是 th，
   这样就不会跟着一起变色 */
.table-wrap tr:hover td { background: #eef3f9; }
.table-wrap tr.delisted:hover td { background: #ffe9e9; }
/* 单击选中的那一行。和 hover 同为 (0,2,2) 特指度，靠**写在后面**取胜 ——
   换个顺序就会被 hover 盖掉。左边一道竖线，免得只靠颜色区分。 */
.table-wrap tr.selected td { background: #d6e4f5; }
.table-wrap tr.selected td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.table-wrap tr.selected:hover td { background: #cbdcf0; }
.table-wrap tr.delisted.selected td { background: #fbd5d5; }
.table-wrap tr.delisted.selected td:first-child { box-shadow: inset 3px 0 0 var(--bad); }
.table-wrap tr.delisted.selected:hover td { background: #f8c9c9; }
td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* 宽表格的滚动容器 ------------------------------------------------------
   列一多（「所有应用」有 14 列）就一定会超出视口。没有这个容器时表格直接被
   裁掉，右边几列看都看不到 —— 实测在高 DPI / 放大的屏幕上必然发生。

   纵向也交给它滚，表头才能 sticky：CSS 规范里 overflow-x:auto 会把
   overflow-y 也算成 auto，于是这里变成滚动容器，表头的 sticky 就只认它而不认
   视口。所以索性让它同时管两个方向，top:0 贴在容器顶上。
   高度用 vh 算，屏幕多高就用多高，不写死像素。 */
.table-wrap { overflow: auto; max-height: calc(100vh - var(--table-offset, 230px));
  border: 1px solid var(--line); border-radius: 6px; }
.table-wrap table { min-width: var(--table-min, 1100px); }
/* 行数本来就少的表（首页那几个）只要横向能滚就够，不必限高。
   width:auto 是为了超宽屏 —— 撑满的话「开始/结束」这种窄内容的列会被拉开
   老远，一行字散在 2000px 上没法读。按内容宽度排，放左边。
   fit-content 是配套的：表格窄了容器也要跟着窄，否则边框框出一大块空白。 */
.table-wrap.short { max-height: none; width: fit-content; max-width: 100%; }
.table-wrap.short table { width: auto; min-width: min(100%, var(--table-min, 520px)); }
.table-wrap th { position: sticky; top: 0; z-index: 2;
  box-shadow: inset 0 -1px 0 var(--line); }
/* 表格里的输入控件跟着列宽走，别用固定像素把列撑死 */
.table-wrap input[type=text], .table-wrap select { width: 100%; min-width: 0;
  padding: 4px 6px; }
td.id { word-break: break-all; min-width: 128px; }
td.nowrap, th.nowrap { white-space: nowrap; }
/* 逗号拼起来的 token 串（Permissions / Data Safety）。浏览器不在逗号处断行，
   "share:apps,contacts,financial" 会把列撑到 200 多像素，两列就吃掉近 400。
   给个上限让它换行，省下来的宽度够别的列把整张表塞进一屏。 */
td.tokens { max-width: 132px; overflow-wrap: anywhere; }
/* 操作列的按钮小一号 —— 表格已经 17 列了，默认内边距一列就吃掉近百像素 */
td.act button { padding: 3px 8px; font-size: 12px; }
td.act > div + div { margin-top: 4px; }
/* 已经写了备注的行，按钮显眼一点 —— 不然得一个个点开才知道哪行有 */
td.act button.has { color: var(--accent); font-weight: 700; }
/* 「上下架日期」列：上架日期在上，下架日期换行跟在下面。
   pre-line 是必须的 —— 下架那格是人工能编辑的自由文本，台账里有一行同时写了
   下架日期和「重新上架」（中间是换行），不保留换行就会挤成一行读不出来。 */
td.dates { min-width: 92px; }
td.dates .off { display: block; color: var(--bad); white-space: pre-line; }
/* 有没读过的更新日志。加粗是因为光靠颜色不够 ——
   红绿色弱的人分不出来，表格里一片蓝字中也不显眼 */
a.unread { color: var(--bad); font-weight: 700; }
a.unread:hover { color: var(--bad); }
/* 弹窗里本次新增的那几条 */
tr.fresh td { background: #fff5f5; }
.pill { display: inline-block; padding: 1px 7px; border-radius: 10px;
  font-size: 12px; background: #eef1f4; color: var(--muted); }
.pill.ok { background: #e6f4ea; color: var(--ok); }
.pill.bad { background: #ffe9e9; color: var(--bad); }
.pill.warn { background: #fff4d6; color: var(--warn); }
button, .btn { font: inherit; padding: 5px 12px; border-radius: 6px;
  border: 1px solid var(--line); background: var(--card); cursor: pointer; }
button:hover, .btn:hover { background: #f0f2f5; text-decoration: none; }
/* 选中/主按钮。必须写 `.btn.primary` 而不只是 `button.primary` ——
   筛选条里的「待处理」「印度」这些是 <a class="btn primary">，元素选择器
   `button` 根本匹配不到它们，选中态等于没写（实测选中和未选中的计算样式
   一模一样，白底蓝字，看不出当前选的是哪个）。 */
button.primary, .btn.primary { background: var(--accent); color: #fff;
  border-color: var(--accent); font-weight: 600; }
button.primary:hover, .btn.primary:hover { background: #0860ca;
  color: #fff; border-color: #0860ca; }
button.danger { color: var(--bad); }
button:disabled { opacity: .5; cursor: not-allowed; }
input[type=text], input[type=time], input[type=number], select, textarea {
  font: inherit; padding: 6px 8px; border: 1px solid var(--line);
  border-radius: 6px; width: 100%; background: #fff; }
textarea { min-height: 64px; resize: vertical; }
label { display: block; margin-bottom: 10px; }
label > span { display: block; color: var(--muted); font-size: 12px;
  margin-bottom: 3px; }
/* 批量操作条。单独一行，和筛选条分开 —— 这俩一个是「看什么」一个是
   「对看到的做什么」，混在一起容易手滑 */
.bulk { display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  margin: -4px 0 12px; padding: 8px 10px; border-radius: 6px;
  background: #fafbfc; border: 1px solid var(--line); }
/* 筛选条：按钮和搜索框排一行，挤了就换行 */
.filters { display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  margin-bottom: 12px; }
/* 搜索框推到最右；窄屏换行后 margin-left:auto 不生效，正好贴左排 */
.filters .search { display: flex; gap: 6px; margin-left: auto; }
.filters .search input[type=text] { width: 220px; }
/* 日期区间：两个 date 控件贴在一起，中间一个波浪号 */
.filters .daterange { display: inline-flex; align-items: center; gap: 4px; }
.filters .daterange input[type=date] { width: auto; padding: 5px 6px;
  font: inherit; border: 1px solid var(--line); border-radius: 6px; }
/* 全局 select 是 width:100%，放进 flex 会被撑成一整条 */
.filters .search select { width: auto; min-width: 104px; }
.checks { display: flex; gap: 12px; flex-wrap: wrap; }
.checks label { display: flex; align-items: center; gap: 4px; margin: 0; }
.checks input { width: auto; }
#log { background: #0d1117; color: #c9d1d9; font-family: Consolas, monospace;
  font-size: 12px; padding: 12px; border-radius: 6px;
  /* 屏幕高就多显示几行，矮也不至于只剩一条缝 */
  height: clamp(240px, 55vh, 640px);
  overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; }
#log .WARN { color: #d29922; }
#log .ERROR { color: #ff7b72; }
#log .ts { color: #6e7681; }
dialog { border: 1px solid var(--line); border-radius: 8px; padding: 0;
  max-width: min(820px, 94vw); width: 94%; max-height: 90vh; }
dialog .head { padding: 12px 16px; border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: 10px; }
dialog .head b { flex: 1; min-width: 0; overflow-wrap: anywhere; }
dialog .body { padding: 16px; max-height: 72vh; overflow: auto; }
dialog::backdrop { background: rgba(0,0,0,.35); }
/* 详情弹窗：左标签右值的两列表 */
table.kv { width: 100%; }
table.kv th { background: none; font-weight: 400; color: var(--muted);
  vertical-align: top; white-space: normal; }
table.kv td { overflow-wrap: anywhere; }
.dl-h { font-size: 13px; margin: 16px 0 6px; color: var(--muted);
  border-bottom: 1px solid var(--line); padding-bottom: 4px; }
.dl-h:first-child { margin-top: 0; }
/* 描述可能几千字，给个高度上限自己滚，别把弹窗撑穿 */
.desc { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 13px;
  max-height: 220px; overflow: auto; background: #fafbfc;
  border: 1px solid var(--line); border-radius: 6px; padding: 8px 10px; }
/* 确认框的底部按钮区 */
dialog .foot { padding: 12px 16px; border-top: 1px solid var(--line);
  display: flex; gap: 8px; justify-content: flex-end; }
.ask-msg { white-space: pre-wrap; margin: 0 0 10px; }
#ask { max-width: min(460px, 92vw); }
#ask-input { margin-top: 4px; }
/* 提示条。替代 alert —— 原生 alert 在这个浏览器里根本不显示 */
.toast { position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%);
  background: #1f2328; color: #fff; padding: 9px 16px; border-radius: 8px;
  font-size: 13px; z-index: 100; max-width: 80vw;
  box-shadow: 0 4px 16px rgba(0,0,0,.25); }
.muted { color: var(--muted); }
.small { font-size: 12px; }
.bar { display: inline-block; height: 9px; background: var(--accent);
  border-radius: 2px; vertical-align: middle; max-width: 100%; }

/* 窄屏 / 高倍缩放 ------------------------------------------------------
   这套东西本来就是桌面用的，不做手机版，只保证挤的时候不崩：
   边距收一点、表单卡片别再被 max-width 顶着不收缩。 */
@media (max-width: 900px) {
  main { padding: 12px; }
  header { padding: 8px 12px; gap: 12px; }
  .card { padding: 12px; }
  .table-wrap { --table-offset: 190px; }
}
/* 表单类卡片：读起来舒服的宽度，但窄屏上要能收回来，所以是 min() 不是写死 */
.card.narrow { width: min(100%, 860px); }

/* --- 登录页 --------------------------------------------------------------
   不继承 base.html，所以这几条得自己写全 */
body.login-page { display: flex; align-items: center; justify-content: center;
  min-height: 100vh; margin: 0; }
.login-box { width: min(92vw, 340px); margin: 0; }
.login-box h2 { margin-top: 0; }
.loginerr { background: #ffe9e9; color: var(--bad); border-radius: 6px;
  padding: 8px 10px; font-size: 13px; margin: 0 0 12px; }

/* 顶栏右侧的「谁登录着」 */
.whoami { display: flex; align-items: center; gap: 6px; }
.rolechip { background: #eef1f4; border-radius: 10px; padding: 1px 7px;
  font-size: 12px; }
/* 退出做成链接的样子 —— 它必须是 form 里的 button（POST，防跨站点一下就退） */
button.linklike { border: 0; background: none; color: var(--accent);
  padding: 0 2px; font: inherit; cursor: pointer; }
button.linklike:hover { text-decoration: underline; background: none; }
