/* ==========================================================================
   QForm 设计系统
   颜色、间距、圆角、阴影都走变量，改配色只动下面这一处。
   ========================================================================== */

:root {
  color-scheme: light;

  --bg:          #f4f7fd;
  --bg-soft:     #e9f0fb;
  --surface:     #ffffff;
  --surface-2:   #f8fafc;
  --surface-3:   #f1f5f9;
  --line:        #e5e7eb;
  --line-strong: #cdd5e1;

  --ink:   #111827;
  --ink-2: #374151;
  --muted: #6b7280;
  --faint: #9ca3af;

  --accent:      #2563eb;
  --accent-2:    #1d4ed8;
  --accent-light:#3b82f6;
  --accent-soft: #eff4ff;
  --accent-line: #c7d9fd;
  --on-accent:   #ffffff;

  --good:      #0f9d63;
  --good-soft: #e7f8f0;
  --good-line: #bde9d3;
  --warn:      #b45309;
  --warn-soft: #fef4e6;
  --warn-line: #f5ddb4;
  --bad:       #dc2626;
  --bad-soft:  #fdecec;
  --bad-line:  #f6cbcb;

  --shadow-xs: 0 1px 2px rgba(17, 24, 39, .06);
  --shadow-sm: 0 2px 8px rgba(17, 24, 39, .08);
  --shadow-md: 0 6px 20px -8px rgba(17, 24, 39, .18);
  --shadow-lg: 0 20px 48px -20px rgba(17, 24, 39, .3);

  --r-xs: 8px;
  --r-sm: 10px;
  --r-md: 12px;
  --r-lg: 14px;
  --r-full: 999px;

  --nav-h: 68px;
  --maxw: 1280px;
  --ring: 0 0 0 3px rgba(37, 99, 235, .16);

  /* 顶栏的蓝色渐变：深蓝起、浅蓝收，左上角一点白、右下角一点粉。
     斜着走 + 两处柔光，蓝面就不会是死板的一块色。
     配色取自参考站 quickform.cn 的顶栏。 */
  --nav-grad:
    radial-gradient(112% 122% at 82% 86%, rgba(244, 114, 182, .10), transparent 38%),
    radial-gradient(90% 100% at 16% 12%, rgba(255, 255, 255, .16), transparent 34%),
    linear-gradient(148deg, #1d4ed8 0%, #2b65e6 60%, #1fa9e8 100%);

  /* 卡片头部沿用同一族蓝，收尾稍收一点，不跟顶栏抢 */
  --head-grad: linear-gradient(148deg, #1d4ed8 0%, #2b65e6 62%, #1a8fd4 100%);
}

/* ------------------------------------------------------------ 基础 */

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

html {
  -webkit-text-size-adjust: 100%;
  /* 滚动条常驻。页面高度参差不齐，有没有滚动条会让可视宽度差出 15px，
     居中的内容和顶栏那条满色蓝边就会跟着横跳一下。
     这里不用 scrollbar-gutter: stable：它预留的是"空槽位"，确实能防抖，
     但槽位里不画滚动条，顶栏的蓝边会在右边缩进 15px、露出一条白缝，
     比抖动还难看。让它一直显示，可视宽度就永远一致，各浏览器行为也统一。 */
  overflow-y: scroll;
}

body {
  margin: 0;
  background: linear-gradient(180deg, #f8fbff 0%, var(--bg) 46%) fixed;
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
               "Hiragino Sans GB", "Microsoft YaHei", system-ui, sans-serif;
  font-size: 15.5px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background-color .2s ease, color .2s ease;
}

a { color: var(--accent); text-decoration: none; transition: color .12s; }
a:hover { color: var(--accent-2); text-decoration: underline; text-underline-offset: 2px; }

h1, h2, h3 { margin: 0; font-weight: 650; line-height: 1.3; letter-spacing: -.015em; }
h1 { font-size: 1.7rem; }
h2 { font-size: 1.14rem; }
h3 { font-size: 1.03rem; }
p { margin: 0 0 .7rem; }
p:last-child { margin-bottom: 0; }

code, pre, .mono {
  font-family: ui-monospace, "Cascadia Mono", "SF Mono", Consolas, Menlo, monospace;
}

::selection { background: var(--accent-soft); color: var(--ink); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

.ico { flex: none; display: block; }

/* <summary> 里是行内排版，图标不能按块级渲染，否则会另起一行 */
.ico.summary-ico { display: inline; vertical-align: -2px; margin-right: 5px; }

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

/* ------------------------------------------------------------ 顶栏 */

.nav {
  position: sticky; top: 0; z-index: 50;
  /* 与卡片头部同一族蓝，顶栏和内容区连成一体 */
  background: var(--nav-grad);
  color: #fff;
  box-shadow: 0 2px 8px rgba(15, 33, 71, .16);
}
.nav-inner {
  max-width: var(--maxw); margin: 0 auto; padding: 0 24px;
  height: var(--nav-h);
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
}

.brand { display: inline-flex; align-items: center; gap: 10px; color: #fff; }
.brand:hover { text-decoration: none; color: #fff; }
/* 站名就是一枚粗体白字，跟参考站 quickform.cn 的 QuickForm 同一个调子 */
.brand-name { font-weight: 700; font-size: 1.5rem; letter-spacing: .5px; }

.nav-links { display: flex; align-items: center; gap: 4px; }
.nav-link {
  display: inline-flex; align-items: center; gap: 6px;
  color: rgba(255, 255, 255, .9); padding: 9px 14px; border-radius: var(--r-sm);
  font-size: .95rem; font-weight: 560;
  transition: background .2s ease, color .2s ease;
}
.nav-link:hover { background: rgba(255, 255, 255, .15); color: #fff; text-decoration: none; }
/* 当前页：底色亮一档，再压一圈极淡的白边，蓝底上才不会糊 */
.nav-link.active {
  background: rgba(255, 255, 255, .22);
  color: #fff;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .2);
}
.nav-sep { width: 1px; height: 20px; background: rgba(255, 255, 255, .22); margin: 0 4px; }
/* 顶栏里的按钮：白底蓝字，在蓝底上最清楚 */
.nav .btn {
  background: #fff; border-color: #fff; color: var(--accent-2); box-shadow: none;
}
.nav .btn:hover { background: rgba(255, 255, 255, .88); border-color: rgba(255, 255, 255, .88); color: var(--accent-2); }

.inline { display: inline; }
.linkish {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; padding: 9px 14px; border-radius: var(--r-sm);
  font: inherit; font-size: .95rem; font-weight: 560;
  color: var(--ink-2); cursor: pointer;
  transition: background .2s ease, color .2s ease;
}
.linkish:hover { background: var(--surface-3); color: var(--ink); }
/* 顶栏里的"退出登录"跟着顶栏走白字 */
.nav .linkish { color: rgba(255, 255, 255, .9); }
.nav .linkish:hover { background: rgba(255, 255, 255, .15); color: #fff; }

/* ------------------------------------------------------------ 布局 */

.page { max-width: var(--maxw); margin: 0 auto; padding: 30px 24px 80px; }
.page.narrow { max-width: 480px; padding-top: 54px; }

.stack { display: flex; flex-direction: column; gap: 16px; }
.stack.dense { gap: 10px; }
.row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.row.tight { gap: 6px; }
.row.end { justify-content: flex-end; }

/* 输入框默认 width:100%，放进 flex 行里会各自占满一行，所以这里改用网格 */
.create-form {
  display: grid; gap: 10px; align-items: center;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) auto;
}
@media (max-width: 780px) { .create-form { grid-template-columns: minmax(0, 1fr); } }
.spread {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.grid { display: grid; gap: 16px; }
.grid.two { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.grid.side { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); }
.grid.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 900px) {
  /* minmax(0,1fr) 而不是 1fr：否则长 URL / 宽表格会把网格撑破 */
  .grid.two, .grid.side, .grid.three { grid-template-columns: minmax(0, 1fr); }
}

.muted { color: var(--muted); }
.faint { color: var(--faint); }
.small { font-size: .9rem; }
.tiny { font-size: .82rem; }
.strong { font-weight: 620; }
.nowrap { white-space: nowrap; }
.center { text-align: center; }
.grow { flex: 1 1 auto; min-width: 0; }
.section-gap { margin-top: 22px; }

/* ------------------------------------------------------------ 卡片 */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  transition: border-color .15s, box-shadow .18s, transform .18s;
}
.card-head {
  padding: 15px 22px;
  border-bottom: 0;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  background: var(--head-grad);
  color: #fff;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}
.card-head h2 {
  font-size: 1.06rem; color: #fff;
  display: inline-flex; align-items: center; gap: 9px;
}
.card-head .ico { color: rgba(255, 255, 255, .88); }
/* 渐变底上的小徽标 / 按钮改用半透明白，保证对比度 */
.card-head .chip {
  font-size: .78rem; color: #fff;
  background: rgba(255, 255, 255, .18); border-color: rgba(255, 255, 255, .3);
}
.card-head .btn {
  background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .32);
  color: #fff; box-shadow: none;
}
.card-head .btn:hover {
  background: rgba(255, 255, 255, .28); border-color: rgba(255, 255, 255, .5);
  color: #fff;
}
.card-head .btn-danger {
  background: rgba(255, 255, 255, .16); border-color: rgba(255, 255, 255, .32); color: #fff;
}
.card-head .btn-danger:hover { background: rgba(255, 255, 255, .3); color: #fff; }
/* 危险卡片：头部用淡红底 + 深红字，比实心红更看得清 */
.card.danger .card-head {
  background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%);
  border-bottom: 1px solid #f6cbcb;
}
.card.danger .card-head h2 { color: #b91c1c; }
.card.danger .card-head .ico { color: #dc2626; }
.card.danger .btn-danger {
  background: var(--bad); border-color: var(--bad); color: #fff;
}
.card.danger .btn-danger:hover { background: #b91c1c; border-color: #b91c1c; color: #fff; }
.card-body { padding: 22px; }
.card-body.tight { padding: 16px 22px; }
.card.dashed { border-style: dashed; background: var(--surface-2); }
.card.accent { border-color: var(--accent-line); }
/* 只有标题栏是红的，正文保持白底，读起来更清楚 */
.card.danger { border-color: var(--bad-line); background: var(--surface); }

/* 可折叠的卡片：整条标题就是开关，右边一个箭头指示展开方向 */
details.card > summary { cursor: pointer; list-style: none; }
details.card > summary::-webkit-details-marker { display: none; }
/* 收起时卡片只剩标题栏，四个角都要圆 */
details.card:not([open]) > summary { border-radius: var(--r-lg); }
.card-caret {
  display: inline-flex; flex: none;
  color: rgba(255, 255, 255, .8);
  transition: transform .18s ease;
}
details.card[open] .card-caret { transform: rotate(90deg); }
details.card > summary:hover .card-caret { color: #fff; }

/* ------------------------------------------------------------ 说明浮层 */

/* ------------------------------------------------------ 接口访问统计 */

/* 24 小时的迷你柱状图：没有请求的小时也留一条淡色底线，
   这样"哪几个小时没人用"和"哪几个小时爆了"一眼能分开 */
.stat-inline { font-size: 1.55rem; font-weight: 700; line-height: 1; color: var(--ink); }
.spark {
  display: flex; align-items: flex-end; gap: 2px; height: 52px;
  margin-top: 14px; border-bottom: 1px solid var(--line);
}
.spark-bar {
  flex: 1 1 0; min-width: 0; height: 3px;
  border-radius: 2px 2px 0 0; background: var(--surface-3);
}
.spark-bar.on { background: var(--accent-line); }
.spark-bar.on:hover { background: var(--accent); }
.spark-axis { display: flex; justify-content: space-between; margin-top: 4px; }
.stat-list {
  list-style: none; margin: 14px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.stat-list li { display: flex; justify-content: space-between; gap: 10px; font-size: .86rem; }
.stat-list li b { color: var(--ink); font-variant-numeric: tabular-nums; }
.stat-warn { margin: 12px 0 0; font-size: .82rem; line-height: 1.65; color: var(--warn); }

/* ------------------------------------------------------ 实时状态面板 */

/* 右栏的卡片比左栏少，让状态卡把剩下的高度占满，两栏底部就齐了。
   列表长了在卡片内部滚动，不把整页撑长。 */
.state-fill { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 300px; }
.state-fill .card-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

.state-group + .state-group { margin-top: 12px; }
.state-prefix {
  font-size: .86rem; font-weight: 620; color: var(--accent-2);
  display: flex; align-items: baseline; gap: 6px; margin-bottom: 6px;
}
.state-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.state-item {
  display: flex; align-items: baseline; gap: 9px;
  padding: 7px 10px; border-radius: var(--r-xs);
  background: var(--surface-2); font-size: .88rem;
}
.state-key { color: var(--ink); flex: none; }
/* 值可能很长，占中间那一栏，超出用省略号 */
.state-val {
  flex: 1 1 auto; min-width: 0; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.state-time { flex: none; }

/* 卡片标题旁的「i」。平时收起来，鼠标移上去 / 键盘聚焦 / 手机上点一下
   才把说明浮出来，不占版面。 */
.tip { position: relative; display: inline-flex; }
.tip-btn {
  position: relative;
  width: 22px; height: 22px; padding: 0; flex: none;
  display: grid; place-items: center;
  border: 1px solid rgba(255, 255, 255, .55); border-radius: 50%;
  background: rgba(255, 255, 255, .12); color: #fff;
  font: italic 700 13px/1 Georgia, "Times New Roman", serif;
  cursor: pointer; transition: background .13s, border-color .13s;
}
/* 视觉上只有 22px，但手指的落点要够大 */
.tip-btn::after { content: ""; position: absolute; inset: -10px; }
.tip-btn:hover, .tip-btn:focus-visible {
  background: rgba(255, 255, 255, .3); border-color: #fff;
}
.tip-panel {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 40;
  width: min(360px, calc(100vw - 44px));
  padding: 14px 16px;
  background: var(--surface); color: var(--ink-2);
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  font-size: .85rem; line-height: 1.65; text-align: left;
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity .14s ease, transform .14s ease, visibility .14s;
}
.tip:hover .tip-panel,
.tip:focus-within .tip-panel,
.tip.is-open .tip-panel { opacity: 1; visibility: visible; transform: none; }
.tip-title {
  display: block; margin-bottom: 8px;
  font-size: .82rem; font-weight: 660; color: var(--ink);
}
.tip-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 10px; }
.tip-list li { font-size: .82rem; color: var(--muted); }
.tip-list b { font-weight: 620; color: var(--ink-2); }

/* ------------------------------------------------------------ 按钮 */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  font: inherit; font-size: .95rem; font-weight: 600; line-height: 1;
  min-height: 42px; padding: 11px 18px; border-radius: var(--r-sm);
  border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink);
  cursor: pointer; white-space: nowrap; user-select: none;
  box-shadow: var(--shadow-xs);
  transition: background .13s, border-color .13s, color .13s, transform .08s;
}
.btn:hover {
  background: var(--accent-soft); border-color: var(--accent-line);
  color: var(--accent-2); text-decoration: none;
}
.btn:active { transform: translateY(1px); }
.btn-primary {
  background: var(--accent);
  border-color: var(--accent); color: var(--on-accent);
  box-shadow: 0 4px 10px rgba(37, 99, 235, .28);
}
.btn-primary:hover {
  background: var(--accent-2);
  border-color: var(--accent-2); color: var(--on-accent);
}
.btn-ghost { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent-2); box-shadow: none; }
.btn-ghost:hover { background: #e2ebff; border-color: var(--accent); color: var(--accent-2); }
.btn-quiet { background: transparent; border-color: transparent; box-shadow: none; color: var(--ink-2); }
.btn-quiet:hover { background: var(--surface-3); }
.btn-danger { color: var(--bad); border-color: var(--bad-line); background: var(--bad-soft); }
.btn-danger:hover { background: var(--bad); border-color: var(--bad); color: #fff; }
.btn-sm { min-height: 38px; padding: 8px 14px; font-size: .89rem; border-radius: var(--r-xs); gap: 6px; }
.btn-lg { min-height: 50px; padding: 14px 26px; font-size: 1.02rem; border-radius: var(--r-md); }
.btn-block { width: 100%; }
.btn[disabled] { opacity: .55; cursor: not-allowed; transform: none; }
.btn.copied { border-color: var(--good-line); color: var(--good); background: var(--good-soft); }

/* ------------------------------------------------------------ 表单 */

.field { margin-bottom: 16px; }
.field:last-child { margin-bottom: 0; }
.label {
  display: block; font-size: .9rem; font-weight: 640; color: var(--ink-2);
  margin-bottom: 8px;
}
.label .opt { font-weight: 400; color: var(--faint); }
.input, .textarea, .select {
  width: 100%; font: inherit; font-size: .97rem; color: var(--ink);
  padding: 11px 14px; border: 1px solid var(--line-strong);
  border-radius: var(--r-sm); background: var(--surface);
  transition: border-color .13s, box-shadow .13s;
}
.input::placeholder, .textarea::placeholder { color: var(--faint); }
.input:hover, .textarea:hover, .select:hover { border-color: var(--faint); }
.input:focus, .textarea:focus, .select:focus {
  outline: 0; border-color: var(--accent); box-shadow: var(--ring);
}
.textarea { resize: vertical; min-height: 86px; line-height: 1.6; }
.select {
  cursor: pointer; appearance: none; padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236a7288' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
}
.hint { font-size: .8rem; color: var(--muted); margin-top: 6px; }
.input-group { display: flex; gap: 8px; }
.input-group .input { flex: 1; }

/* 密码框右侧的小眼睛：点一下在明文 / 密文之间切换 */
.pw { position: relative; }
.pw .input { padding-right: 42px; }
.pw-toggle {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 30px; height: 30px; padding: 0;
  display: grid; place-items: center;
  border: 0; background: transparent; color: var(--faint);
  border-radius: var(--r-xs); cursor: pointer;
  transition: color .13s, background .13s;
}
.pw-toggle:hover { color: var(--ink-2); background: var(--surface-3); }
.pw-toggle span { line-height: 0; }
.pw-toggle span[hidden] { display: none; }

/* 单选卡片：比下拉框更适合"带说明的选项" */
.radio-cards { display: grid; gap: 8px; }
.radio-card {
  display: flex; align-items: flex-start; gap: 11px;
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  padding: 12px 14px; cursor: pointer; background: var(--surface);
  transition: border-color .13s, background .13s, box-shadow .13s;
}
.radio-card:hover { border-color: var(--faint); background: var(--surface-2); }
.radio-card input { margin: 3px 0 0; accent-color: var(--accent); flex: none; }
.radio-card-body { min-width: 0; }
.radio-card-title { font-weight: 600; font-size: .9rem; }
.radio-card-desc { font-size: .8rem; color: var(--muted); margin-top: 2px; }
.radio-card:has(input:checked) {
  border-color: var(--accent); background: var(--accent-soft);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent);
}
.radio-card:has(input:checked) .radio-card-title { color: var(--accent); }

/* ------------------------------------------------------------ 提示条 */

.flashes { display: flex; flex-direction: column; gap: 9px; margin-bottom: 20px; }
.flash {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 12px 16px; border-radius: var(--r-md); font-size: .92rem;
  border: 1px solid var(--line); background: var(--surface);
  animation: slide-in .26s cubic-bezier(.22, 1, .36, 1) both;
}
.flash .ico { margin-top: 2px; }
.flash-success { background: var(--good-soft); border-color: var(--good-line); color: var(--good); }
.flash-error   { background: var(--bad-soft);  border-color: var(--bad-line);  color: var(--bad); }
.flash-info    { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); }

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

/* ------------------------------------------------------------ 徽标 */

.chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .78rem; font-weight: 620; line-height: 1;
  padding: 6px 11px; border-radius: var(--r-full);
  background: var(--surface-3); color: var(--ink-2);
  border: 1px solid transparent; white-space: nowrap;
}
.chip-read_write { background: var(--good-soft); color: var(--good); border-color: var(--good-line); }
.chip-read_only  { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.chip-write_only { background: var(--warn-soft); color: var(--warn); border-color: var(--warn-line); }
.chip-closed     { background: var(--surface-3); color: var(--muted); border-color: var(--line); }
.chip-count {
  background: var(--accent-soft); color: var(--accent);
  border-color: var(--accent-line); font-variant-numeric: tabular-nums;
}
.chip-plain { background: var(--surface-3); color: var(--muted); border-color: var(--line); }

/* ------------------------------------------------------------ 表格 */

.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: .93rem; }
.table th {
  text-align: left; font-size: .8rem; font-weight: 660; color: var(--muted);
  letter-spacing: .02em; padding: 12px 14px;
  border-bottom: 1px solid var(--line); white-space: nowrap;
  background: var(--surface-2);
}
.table td {
  padding: 14px; border-bottom: 1px solid var(--line);
  vertical-align: top; color: var(--ink-2);
}
.table tbody tr { transition: background .1s; }
.table tbody tr:nth-child(even) { background: color-mix(in srgb, var(--surface-2) 60%, transparent); }
.table tbody tr:hover { background: var(--accent-soft); }
.table tbody tr:last-child td { border-bottom: 0; }
.table .num { text-align: right; font-variant-numeric: tabular-nums; }
.table .actions { text-align: right; white-space: nowrap; }
.table .cell-lead { font-weight: 560; color: var(--ink); }

/* 任务列表：一行里要放任务说明和两个动作，单独调一版。
   数据页那种密表不受影响，还是上面这套默认值。 */
.table-tasks th { padding: 11px 16px; font-size: .78rem; letter-spacing: .03em; }
.table-tasks td { padding: 14px 16px; vertical-align: middle; }
.table-tasks .tight { white-space: nowrap; }
/* 窄内容的列不参与摊分，宽度全留给任务那一列。
   只在表格形态下生效 —— 窄屏是卡片布局，给了宽度会把内容挤扁 */
@media (min-width: 681px) {
  .table-tasks .tight, .table-tasks .num, .table-tasks .actions { width: 1%; }
}
.table-tasks .cell-task { min-width: 220px; }
.table-tasks .cell-task-body { min-width: 0; }
.table-tasks .cell-lead { font-weight: 620; }
.table-tasks .cell-desc {
  margin-top: 3px; font-size: .82rem; line-height: 1.55; color: var(--muted);
  max-width: 52ch; overflow: hidden;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}

/* 学生端 / 教师端横着并排；按钮做轻一点，别把数据压下去 */
.actions-row { display: inline-flex; align-items: center; gap: 8px; }
.table-tasks .actions-row .btn {
  min-width: 88px; justify-content: center; box-shadow: none;
  background: var(--surface); border-color: var(--line-strong); color: var(--ink-2);
}
.table-tasks .actions-row .btn:hover {
  background: var(--accent-soft); border-color: var(--accent-line);
  color: var(--accent-2); text-decoration: none;
}
.cell-clip {
  max-width: 280px; overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}

/* 窄屏把表格变成卡片列表 */
@media (max-width: 680px) {
  .table.responsive thead { display: none; }
  .table.responsive tbody tr {
    display: block; border-bottom: 1px solid var(--line);
    padding: 12px 16px; background: transparent !important;
  }
  /* text-align 要显式归位：数字列默认是右对齐，卡片布局里会把标签顶到中间去 */
  .table.responsive tbody td {
    display: flex; gap: 12px; border: 0; padding: 4px 0; text-align: left;
  }
  .table.responsive tbody td::before {
    content: attr(data-label);
    flex: 0 0 78px; font-size: .76rem; font-weight: 620; color: var(--muted);
    padding-top: 2px;
  }
  .table.responsive tbody td.actions { justify-content: flex-end; }
  .table.responsive tbody td.actions::before { display: none; }
  .table.responsive tbody td:empty { display: none; }
  .cell-clip { max-width: none; -webkit-line-clamp: 4; }

  /* 任务卡在手机上别铺成五行星号表：标题单独占一行，
     编号和三个统计挤成一行，一条任务才不至于占掉一屏 */
  .table-tasks tbody td { padding: 3px 0; }
  .table-tasks tbody td.cell-task { display: block; padding-bottom: 8px; }
  .table-tasks tbody td.cell-task::before { display: none; }
  .table-tasks tbody td.tight,
  .table-tasks tbody td.num {
    display: inline-flex; align-items: baseline; gap: 5px; margin-right: 14px;
  }
  /* 标签不再占那 78px 的固定格子，否则一行的宽度全被标签吃掉、
     统计值会被挤到下一行去 */
  .table-tasks tbody td.tight::before { flex: none; font-size: .72rem; }
  /* 数字当量词读：「5 提交」比「提交 5」顺 */
  .table-tasks tbody td.num::before { order: 2; }
  /* 接口编号本身就是一串等宽字符，再挂「编号」二字是浪费一行宽度 */
  .table-tasks tbody td.cell-id::before { display: none; }
  /* 创建时间固定另起一行：一行宽度预算有限，让它跟着挤就会
     出现"这条两行、那条三行"的参差 */
  .table-tasks tbody td.cell-date { flex-basis: 100%; margin-top: 3px; }
  .table-tasks tbody td.actions { display: block; padding-top: 10px; }
  /* 标题是整张卡的主入口，给足手指的落点 */
  .table-tasks .cell-lead { display: inline-block; padding: 3px 0; }

  /* 数据卡：删除按钮挪到右上角，省掉末尾那一行空白，
     也避免误触（原来它孤零零吊在卡片右下） */
  .table-data tbody tr { position: relative; padding-right: 58px; }
  .table-data tbody td.actions {
    position: absolute; top: 12px; right: 16px;
    display: block; padding: 0; margin: 0;
  }
}

/* ------------------------------------------------------------ 空状态 */

.empty { text-align: center; padding: 46px 24px; color: var(--muted); }
.empty-icon {
  width: 46px; height: 46px; margin: 0 auto 14px;
  border-radius: var(--r-md); display: grid; place-items: center;
  background: var(--surface-3); color: var(--faint);
}
.empty-title { font-weight: 620; color: var(--ink-2); margin-bottom: 5px; font-size: 1.02rem; }
.empty p { font-size: .9rem; max-width: 44ch; margin-inline: auto; }

/* ------------------------------------------------------------ 代码 / 复制框 */

.code {
  background: #141826; color: #d5ddf0; border: 1px solid #232b40;
  border-radius: var(--r-md); padding: 14px 16px;
  font-size: .85rem; line-height: 1.68; overflow-x: auto; margin: 0;
}

.copybox {
  display: flex; align-items: center; gap: 10px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 7px 7px 7px 13px;
  transition: border-color .13s;
}
.copybox:hover { border-color: var(--line-strong); }
.copybox .value {
  flex: 1; min-width: 0; font-size: .87rem; color: var(--ink-2);
  font-family: ui-monospace, "Cascadia Mono", Consolas, Menlo, monospace;
  overflow-x: auto; white-space: nowrap; scrollbar-width: none;
}
.copybox .value::-webkit-scrollbar { height: 0; }
.copybox.wrap .value {
  white-space: normal; word-break: normal; overflow-wrap: anywhere;
}

/* ------------------------------------------------------------ 任务详情 */

.task-head { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }
.task-title { flex: 1 1 300px; min-width: 0; }
.task-title h1 { font-size: 1.68rem; margin-bottom: 7px; }
.task-meta { display: flex; align-items: center; gap: 4px 10px; flex-wrap: wrap; }
/* 分隔点用 ::before 生成，换行时不会孤零零挂在行尾 */
.task-meta > * + *::before {
  content: "·"; color: var(--faint); margin-right: 10px;
}

.tabs {
  display: flex; gap: 4px; margin: 22px 0 20px;
  border-bottom: 1px solid var(--line); overflow-x: auto;
}
.tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 11px 16px; font-size: .95rem; font-weight: 580;
  color: var(--muted); border-bottom: 2px solid transparent;
  margin-bottom: -1px; white-space: nowrap;
  transition: color .13s, border-color .13s;
}
.tab:hover { color: var(--ink); background: var(--surface-3); border-radius: var(--r-sm) var(--r-sm) 0 0; text-decoration: none; }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 640; }

/* 窄屏：导航只留图标，标签页的滚动条藏起来 */
@media (max-width: 720px) {
  .nav-inner { padding: 0 14px; gap: 8px; }
  .nav-links { gap: 2px; }
  .nav-label { display: none; }
  .nav-sep { display: none; }
  .nav-link, .linkish { padding: 8px; }
  .brand { gap: 7px; }
  .page { padding: 22px 14px 64px; }
  .card-body { padding: 16px; }
  .card-head { padding: 14px 16px; }
  .fileitem { padding: 13px 16px; flex-wrap: wrap; }
  .tabs { scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .table-wrap { overflow-x: visible; }
}
@media (max-width: 400px) {
  /* 站名收小一点，但不能再藏起来 —— 已经没有徽标可顶替了 */
  .brand-name { font-size: 1.24rem; }
}

/* ------------------------------------------------------------ 二维码 */

.qr-box { display: flex; gap: 20px; align-items: center; flex-wrap: wrap; }
.qr-pair {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px; margin-bottom: 18px;
}
.qr-item { margin: 0; text-align: center; }
.qr-item figcaption {
  margin-top: 8px; font-size: .8rem; font-weight: 620; color: var(--ink-2);
}
/* 二维码也能点开看大图 */
.qr-frame { cursor: zoom-in; transition: border-color .13s, box-shadow .13s; }
.qr-frame:hover { border-color: var(--accent-line); box-shadow: var(--shadow-sm); }
.qr-frame:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.lightbox img.is-qr {
  background: #fff; padding: 14px; border-radius: 14px;
  width: min(78vmin, 560px); max-width: 92vw; height: auto;
}
.qr-copy { align-items: flex-start; }
.qr-pair .qr-frame { width: 100%; display: grid; place-items: center; }
.qr-pair .qr-frame svg { width: 100%; max-width: 150px; height: auto; }
.qr-frame {
  background: #fff; border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 12px; line-height: 0; box-shadow: var(--shadow-xs); flex: none;
}
.qr-frame svg { width: 150px; height: 150px; display: block; }
@media (max-width: 360px) {
  .qr-pair { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------------------------------ 统计 */

.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.stats.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 720px) { .stats, .stats.two { grid-template-columns: minmax(0, 1fr); } }
.stat { padding: 20px 22px; position: relative; overflow: hidden; }
.stat-icon { position: absolute; top: 18px; right: 18px; color: var(--accent); opacity: .32; }
.stat-num {
  font-size: 2.2rem; font-weight: 720; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; line-height: 1.1; color: var(--ink);
}
.stat-num.small { font-size: 1.06rem; font-weight: 620; letter-spacing: -.01em; }
.stat-label { font-size: .88rem; color: var(--muted); margin-top: 4px; }
@media (max-width: 720px) {
  .stat-num { font-size: 1.6rem; }
  .stat-num.small { font-size: .95rem; }
}

/* ------------------------------------------------------------ 附件 */

.thumbs { display: flex; flex-wrap: wrap; gap: 6px; }
.thumb {
  width: 60px; height: 60px; object-fit: cover; display: block;
  border-radius: var(--r-xs); border: 1px solid var(--line);
  transition: transform .13s, border-color .13s;
}
a:hover > .thumb { transform: scale(1.04); border-color: var(--accent); }
.filechip {
  display: inline-flex; align-items: center; gap: 5px; max-width: 210px;
  font-size: .78rem; padding: 5px 10px; border-radius: var(--r-full);
  border: 1px solid var(--line); background: var(--surface-2); color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* 图片放大浮层 */
.lightbox {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center; padding: 34px 24px 54px;
  background: rgba(11, 15, 25, .88);
  animation: lb-in .16s ease-out both;
}
.lightbox[hidden] { display: none; }
@keyframes lb-in { from { opacity: 0; } to { opacity: 1; } }
.lightbox img {
  max-width: min(94vw, 1400px); max-height: calc(100vh - 108px);
  border-radius: 12px; background: #fff;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .5);
  image-rendering: auto;
}
.lightbox-close {
  position: fixed; top: 18px; right: 20px;
  width: 40px; height: 40px; border-radius: 50%; padding: 0;
  display: grid; place-items: center;
  font-size: 17px; line-height: 1; color: #fff; cursor: pointer;
  background: rgba(255, 255, 255, .16); border: 0;
  transition: background .13s;
}
.lightbox-close:hover { background: rgba(255, 255, 255, .3); }
.lightbox-hint {
  position: fixed; left: 0; right: 0; bottom: 18px; text-align: center;
  color: rgba(255, 255, 255, .58); font-size: .76rem; pointer-events: none;
}
.filechip:hover { background: var(--accent-soft); border-color: var(--accent-line); text-decoration: none; }

/* 音视频附件：就地播放，省得再点开一个页面 */
.play-cell {
  display: inline-flex; flex-direction: column; gap: 3px;
  width: 100%; max-width: 260px; min-width: 200px; vertical-align: top;
}
.play-cell audio { width: 100%; height: 34px; display: block; }
.play-cell video {
  width: 100%; max-height: 190px; border-radius: var(--r-xs);
  border: 1px solid var(--line); background: #000; display: block;
}
.play-name {
  font-size: .72rem; color: var(--muted); text-decoration: none;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.play-name:hover { color: var(--accent); text-decoration: underline; }
/* 表格里的两行截断会把播放器裁掉，这里放开 */
.cell-clip:has(.play-cell) {
  display: block; -webkit-line-clamp: none; overflow: visible; max-width: none;
}

/* ------------------------------------------------------------ 拖放上传 */

.drop {
  border: 1.5px dashed var(--line-strong); border-radius: var(--r-lg);
  padding: 34px 22px; text-align: center; background: var(--surface-2);
  cursor: pointer; transition: border-color .15s, background .15s, transform .12s;
}
.drop:hover { border-color: var(--accent); }
.drop.over {
  border-color: var(--accent); background: var(--accent-soft);
  transform: scale(1.01); box-shadow: var(--ring);
}
.drop input[type=file] { display: none; }
.drop-icon { color: var(--accent); margin: 0 auto 10px; }
.drop-title { font-weight: 620; margin-bottom: 3px; }
.drop-count { color: var(--accent); font-weight: 600; font-size: .84rem; margin-top: 6px; }

/* ------------------------------------------------------------ 页面清单 */

.filelist { display: flex; flex-direction: column; }
.fileitem {
  display: flex; align-items: center; gap: 13px;
  padding: 14px 20px; border-bottom: 1px solid var(--line);
  transition: background .1s;
}
.fileitem:last-child { border-bottom: 0; }
.fileitem:hover { background: var(--surface-2); }
.fileicon {
  width: 38px; height: 38px; border-radius: var(--r-sm); flex: none;
  display: grid; place-items: center; font-size: .64rem; font-weight: 700;
  letter-spacing: .02em;
  background: var(--accent-soft); color: var(--accent);
  border: 1px solid var(--accent-line);
}
.fileicon.asset { background: var(--surface-3); color: var(--faint); border-color: var(--line); }
.filemeta { flex: 1; min-width: 0; }
.filename {
  font-weight: 570; color: var(--ink); word-break: break-all;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}

/* ------------------------------------------------------------ 分页 */

.pager {
  display: flex; align-items: center; gap: 10px; justify-content: center;
  padding: 16px; font-size: .85rem; color: var(--muted);
  border-top: 1px solid var(--line);
}

/* ==========================================================================
   首页（landing page）
   统一用 lp- 前缀，和后台页面那套样式分开，互不影响
   ========================================================================== */

.home-page { max-width: 1160px; }

/* ------------------------------------------------------------ Hero */

.lp-hero {
  text-align: center; max-width: 720px; margin: 0 auto;
  padding: 84px 0 60px;
  /* 顶部一片很淡的光晕，给页面一个重心。
     圆心放到元素上方，否则光晕会在紧贴导航的地方留一条硬边 */
  background: radial-gradient(78% 70% at 50% -30%,
              color-mix(in srgb, var(--accent) 20%, transparent) 0%,
              transparent 70%) no-repeat;
}
.lp-hero h1 {
  font-size: clamp(2.4rem, 6.5vw, 3.5rem);
  letter-spacing: -.045em; line-height: 1.06; margin-bottom: 22px;
}
.lp-sub {
  font-size: 1.06rem; color: var(--muted); line-height: 1.72;
  max-width: 46ch; margin: 0 auto 30px;
}
.lp-cta { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }

/* 首屏入场：轻微上浮，不要做过头 */
@keyframes lp-rise {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}
/* 入场动画压短：原来延迟 0.06~0.22s、时长 0.7s，首屏文字要 0.9s 才完全显形，
   现在 0.5s 内到位 —— 动画是给"有变化"的感觉，不该拖慢内容出现 */
.lp-hero > * { animation: lp-rise .42s cubic-bezier(.22, 1, .36, 1) both; }
.lp-hero > h1      { animation-delay: .02s; }
.lp-hero > .lp-sub { animation-delay: .05s; }
.lp-hero > .lp-cta { animation-delay: .09s; }

/* ------------------------------------------------------- 产品示意窗口 */

/* 产品示意是首页最后一块，下边距交给 .page 自己的 padding */
.lp-showcase { margin-bottom: 0; animation: lp-rise .46s cubic-bezier(.22, 1, .36, 1) .12s both; }
.lp-window {
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--r-lg); overflow: hidden; box-shadow: var(--shadow-lg);
}
.lp-window-bar {
  display: flex; align-items: center; gap: 14px;
  padding: 11px 16px; background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}
.lp-lights { display: inline-flex; gap: 6px; flex: none; }
.lp-lights i { width: 10px; height: 10px; border-radius: 50%; background: var(--line-strong); }
.lp-window-url { font-size: .78rem; color: var(--muted); }

.lp-window-body {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  background: #141826;
}
.lp-pane { padding: 20px 22px; min-width: 0; }
.lp-pane + .lp-pane { border-left: 1px solid #232b40; }
.lp-pane-label {
  display: flex; align-items: center; gap: 7px;
  font-size: .76rem; font-weight: 600; color: #8b98b8; margin-bottom: 13px;
}
.lp-code {
  margin: 0; color: #d5ddf0; font-size: .8rem; line-height: 1.78;
  font-family: ui-monospace, "Cascadia Mono", "SF Mono", Consolas, Menlo, monospace;
  white-space: pre; overflow-x: auto;
}

/* ------------------------------------------------------------ 窄屏 */

@media (max-width: 760px) {
  .lp-hero { padding: 56px 0 44px; }
  .lp-window-body { grid-template-columns: minmax(0, 1fr); }
  .lp-pane + .lp-pane { border-left: 0; border-top: 1px solid #232b40; }
}

.feature-list { margin: 0; padding-left: 19px; }
.feature-list li { margin-bottom: 7px; font-size: .89rem; color: var(--ink-2); }
.feature-list li::marker { color: var(--faint); }

/* ------------------------------------------------------------ 杂项 */

.divider { height: 1px; background: var(--line); margin: 18px 0; }

/* 键值对行：用来紧凑展示"字段很多但都不长"的提交记录 */
.kv-list { display: flex; flex-wrap: wrap; gap: 4px 20px; }
.kv { display: inline-flex; align-items: baseline; gap: 7px; font-size: .84rem; min-width: 0; }
.kv-k { color: var(--muted); flex: none; }
/* 长值（比如一整包行为记录 JSON）截到三行，免得把「最近提交」撑得老长 */
.kv-v {
  color: var(--ink); font-weight: 520; word-break: break-word;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* 值里带缩略图时改成居中对齐，否则标签会贴到图片底边 */
.kv:has(.thumb) { align-items: center; }
.kv .thumb { width: 46px; height: 46px; }

.badge-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--good);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--good) 20%, transparent);
}

/* ============================================================== 手机端
   这一块专门处理"在手机上用"的细节：iOS 聚焦不放大、手指点得中、
   任务页顶部不占掉半屏、二维码在窄屏也并排。
   ============================================================== */

@media (max-width: 640px) {
  :root { --nav-h: 54px; }

  /* iOS 上输入框字号小于 16px，聚焦时会把整页放大 */
  .input, .textarea, .select, input, select, textarea { font-size: 16px; }
  .input, .select { padding: 11px 13px; }

  /* 手指点得着的按钮 */
  .btn { min-height: 42px; padding: 11px 16px; }
  .btn-sm { min-height: 40px; padding: 8px 12px; font-size: .82rem; }
  .nav-link, .linkish { min-width: 44px; min-height: 44px; justify-content: center; }
  .tab { padding: 12px 14px; }

  /* 地址在窄屏一行放不下，横向滚动几乎没法用 ——
     让整条地址换行显示完整，复制按钮落到下一行 */
  .copybox { flex-wrap: wrap; gap: 8px; padding: 10px 12px; }
  .copybox .value {
    flex: 1 1 100%; white-space: normal; overflow-wrap: anywhere;
    overflow-x: visible; font-size: .84rem; line-height: 1.6;
  }
  .copybox .btn { flex: none; }

  /* 剩下的都是"手指够不着"的小东西 */
  .pw-toggle { width: 40px; height: 40px; right: 4px; }
  summary { padding: 10px 0; }
  .brand { padding: 6px 0; }

  /* 四个标签在 320~360 的机器上一行排不下。它外面是可横滑的，
     但滚动条是隐藏的 —— 看不出来右边还有内容，人就不会去滑，
     所以宁可把内边距收窄也要让四个都露出来 */
  .tab { padding: 12px 9px; gap: 5px; font-size: .92rem; }

  /* 登录、注册页的表单往上提一点 */
  .page.narrow { padding-top: 30px; }

  /* 任务头部：简介收成一行，创建时间让位给正文 */
  .task-head { gap: 10px; }
  .task-title h1 { font-size: 1.24rem; margin-bottom: 4px; }
  .task-meta { font-size: .78rem; gap: 2px 8px; }
  .task-desc {
    display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .task-time { display: none; }
  .tabs { margin: 16px 0 14px; }

  /* 统计卡改成横排的一行，三张卡不再各占半屏 */
  .stats { gap: 9px; }
  .stat {
    display: flex; align-items: baseline; gap: 9px;
    padding: 12px 15px;
  }
  .stat-num { font-size: 1.45rem; }
  .stat-num.small { font-size: .88rem; }
  .stat-label { margin-top: 0; font-size: .8rem; }
  .stat-icon { top: 10px; right: 12px; opacity: .32; }

  /* 两个二维码在 375 宽的手机上也左右排 */
  .qr-pair { gap: 10px; }
  .qr-item figcaption { font-size: .76rem; margin-top: 6px; }
  .copybox .value { font-size: .76rem; }

  /* 提交记录里的字段行 */
  .kv { font-size: .82rem; }
  .filechip { max-width: 60vw; }

  /* 底部留出 iPhone 的横条位置 */
  .page { padding-bottom: calc(56px + env(safe-area-inset-bottom)); }
  .empty { padding: 34px 18px; }
}
