/* ==========================================================================
   无人机履历管理 · 共享设计系统
   风格：新野性主义（Neo-Brutalism） + 贴纸风（Sticker） + 游戏化（Gamified）
   规范文档：docs/前端视觉设计规范.md
   本文件为全局唯一视觉来源，页面内联 <style> 仅保留页面特有规则。
   ========================================================================== */

/* --- 1. 设计 token ------------------------------------------------------- */
:root {
  /* 声明本页面向浅色设计。这同时是「浏览器自绘部件使用哪套配色」的唯一开关：
     未声明等价于 light，但显式声明还能让浏览器放弃按系统偏好强制反色。
     深色主题在自己的块里改声明为 dark，见 §1.1。 */
  color-scheme: light;

  /* 墨色：所有边框、正文、硬阴影的唯一来源 */
  --ink: #0e0e10;
  --ink-soft: #4a4a52;

  /* 纸面层级：页面底 / 卡片 / 次级面 */
  --paper: #fffdf5;
  --surface: #ffffff;
  --surface-2: #fff6da;

  /* 强调色：主操作 / 贴纸高亮 / 贴纸点缀 */
  --accent: #1f4dff;
  --accent-deep: #0b2bb5;
  --pink: #ff4d8d;
  --yellow: #ffd400;

  /* 语义色：直接作为按钮/徽章底色，故取值须与白字达到 WCAG AA（≥4.5:1） */
  --ok: #0f7a3d;
  --amber: #f59e0b;
  --danger: #e11d48;

  /* 压在语义色/强调色实底上的文字色（白字与 --accent/--ok/--danger 均达 AA） */
  --on-accent: #ffffff;

  /* 提示条：浅底 + 深字，长文本提示不使用纯色底 */
  --notice-bg: #d9f7e4;
  --notice-fg: #0a6b36;
  --warn-bg: #fff0c2;
  --warn-fg: #7a4a05;
  --danger-bg: #ffe4e9;
  --danger-fg: #90122f;

  /* 分隔线：墨色的低透明度变体，用于列表项之间的虚线。
     必须独立成 token —— 主题会反转明暗，写死固定的深色 rgba 会在
     深色主题下变成深色虚线压在深色底上而彻底消失。 */
  --ink-line: rgba(14, 14, 16, 0.28);
  --ink-line-mid: rgba(14, 14, 16, 0.35);
  --ink-line-strong: rgba(14, 14, 16, 0.4);

  /* 纸面纹理：图案与尺寸成对定义，主题可整体替换。 */
  --paper-pattern: radial-gradient(var(--ink) 1px, transparent 1px);
  --paper-pattern-size: 18px 18px;

  /* 描边与圆角 */
  --line: 2px;
  --line-bold: 3px;
  --r-sm: 8px;
  --r: 12px;
  --r-lg: 16px;
  --r-pill: 999px;

  /* 硬阴影：野性主义的标志，无模糊 */
  --pop-sm: 2px 2px 0 var(--ink);
  --pop: 4px 4px 0 var(--ink);
  --pop-lg: 6px 6px 0 var(--ink);

  /* 动效节奏 */
  --t-fast: 0.08s;
  --t: 0.16s;

  --font-sans: "PingFang SC", "Microsoft YaHei", system-ui, -apple-system,
    "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;
}

/* --- 1.1 每日主题 ------------------------------------------------------- */
/* 主题由服务端按上海时区的自然日选定，写入 <html data-theme="...">，
   选取逻辑见 internal/httpapi/theme.go。

   选择器写作 html[data-theme="..."]（特异性 0,1,1）而非 [data-theme="..."]
   （0,1,0），以便稳定压过上面的 :root，不依赖两者的源顺序。

   【全部主题块必须位于 @media screen 之内】
   这是打印正确性的结构前提。打印上下文里主题块整体失效，配色直接回落到
   :root（取值即 classic，白纸黑墨），因此不存在「部分 token 被重置、其余
   仍是主题取值」的混合状态 —— 而混合状态是致命的：深色主题的 --accent-deep
   是为深色底提亮的浅蓝，一旦 --paper 变成白纸而它没有，链接在白纸上会
   几乎不可见（改造前实测 2.02:1）。
   由 theme_test.go 的 TestThemeBlocksAreScreenScoped 强制校验。

   每套主题的取值必须满足下列 WCAG AA（正文 4.5:1）配对，由
   contracts_test.go 的 TestThemePalettesMeetWCAGAA 强制校验：
     正文/纸面   ink→paper、ink→surface、ink→surface-2
     弱化文字    ink-soft→paper、ink-soft→surface、ink-soft→surface-2
     实底反白    on-accent→accent、on-accent→ok、on-accent→danger
     深字压亮底  ink→amber、ink→pink、ink→yellow
     反色胶囊    paper→ink
     链接        accent-deep→paper、accent-deep→surface
     提示条      *-fg→*-bg
   装饰性分隔线（--ink-line*）不属 WCAG 1.4.11 强制的组件边界，但不得比
   classic 基线（1.90:1）更不可见，同样由测试守护。

   每套主题还必须声明 color-scheme：它决定浏览器自绘部件（<select> 箭头、
   type=file 按钮、数字微调、滚动条）使用哪套配色。未声明即视为 light，
   于是深色主题下这些控件仍是浅色外观，深色箭头压在深色底上而看不见。
   --paper 比 --ink 暗的主题须写 dark，反之为 light，由
   TestEveryThemeDeclaresColorScheme 校验 —— 期望值由两者相对亮度推出，
   不写死主题名，故新增深色主题会自动适用。

   组件边界的可识别性由 --ink 描边（2px）保证而非填充色，因此深色主题
   即使 --accent 与 --surface 的对比度较低也能清晰分辨。 */

/* 主题块整体限定在屏幕媒体：打印输出的配色只由 :root 与 §13 的打印块决定，
   与当日轮换到哪套主题无关。 */
@media screen {
  /* classic：默认配色，取值与 :root 一致。:root 负责「无 data-theme 属性」
     的回退，本块负责让主题名与样式块一一对应，便于测试遍历。 */
  html[data-theme="classic"] {
    color-scheme: light;
    --ink: #0e0e10;
    --ink-soft: #4a4a52;
    --ink-line: rgba(14, 14, 16, 0.28);
    --ink-line-mid: rgba(14, 14, 16, 0.35);
    --ink-line-strong: rgba(14, 14, 16, 0.4);
    --paper: #fffdf5;
    --surface: #ffffff;
    --surface-2: #fff6da;
    --accent: #1f4dff;
    --accent-deep: #0b2bb5;
    --pink: #ff4d8d;
    --yellow: #ffd400;
    --ok: #0f7a3d;
    --amber: #f59e0b;
    --danger: #e11d48;
    --on-accent: #ffffff;
    --notice-bg: #d9f7e4;
    --notice-fg: #0a6b36;
    --warn-bg: #fff0c2;
    --warn-fg: #7a4a05;
    --danger-bg: #ffe4e9;
    --danger-fg: #90122f;
    --paper-pattern: radial-gradient(var(--ink) 1px, transparent 1px);
    --paper-pattern-size: 18px 18px;
  }

  /* sakura：樱色纸面 + 玫红强调，点阵加密到 13px 以贴近和纸的颗粒感。 */
  html[data-theme="sakura"] {
    color-scheme: light;
    --ink: #1a0d14;
    --ink-soft: #5c3a48;
    --ink-line: rgba(26, 13, 20, 0.3);
    --ink-line-mid: rgba(26, 13, 20, 0.37);
    --ink-line-strong: rgba(26, 13, 20, 0.42);
    --paper: #fff7fa;
    --surface: #ffffff;
    --surface-2: #ffe6ef;
    --accent: #c2185b;
    --accent-deep: #8e0b3f;
    --pink: #ff6fa5;
    --yellow: #ffd400;
    --ok: #0f7a3d;
    --amber: #f59e0b;
    --danger: #e11d48;
    --on-accent: #ffffff;
    --notice-bg: #dcf7e6;
    --notice-fg: #0a6b36;
    --warn-bg: #fff0c2;
    --warn-fg: #7a4a05;
    --danger-bg: #ffe0e8;
    --danger-fg: #8e1030;
    --paper-pattern: radial-gradient(var(--ink) 1px, transparent 1px);
    --paper-pattern-size: 13px 13px;
  }

  /* lagoon：冷青纸面 + 深青强调，横向细线模拟水面层理。 */
  html[data-theme="lagoon"] {
    color-scheme: light;
    --ink: #08161c;
    --ink-soft: #3d5a66;
    --ink-line: rgba(8, 22, 28, 0.3);
    --ink-line-mid: rgba(8, 22, 28, 0.37);
    --ink-line-strong: rgba(8, 22, 28, 0.42);
    --paper: #f2fafd;
    --surface: #ffffff;
    --surface-2: #d9eff9;
    --accent: #0e7490;
    --accent-deep: #0a5568;
    --pink: #f2497f;
    --yellow: #ffc400;
    --ok: #0f7a3d;
    --amber: #f59e0b;
    --danger: #e11d48;
    --on-accent: #ffffff;
    --notice-bg: #d5f5ec;
    --notice-fg: #0a6350;
    --warn-bg: #fff0c2;
    --warn-fg: #7a4a05;
    --danger-bg: #ffe4e9;
    --danger-fg: #90122f;
    --paper-pattern: repeating-linear-gradient(
      0deg,
      var(--ink) 0 1px,
      transparent 1px 16px
    );
    --paper-pattern-size: auto;
  }

  /* sunset：暖橙纸面 + 赭石强调。 */
  html[data-theme="sunset"] {
    color-scheme: light;
    --ink: #1c0f06;
    --ink-soft: #604532;
    --ink-line: rgba(28, 15, 6, 0.3);
    --ink-line-mid: rgba(28, 15, 6, 0.37);
    --ink-line-strong: rgba(28, 15, 6, 0.42);
    --paper: #fff8f0;
    --surface: #ffffff;
    --surface-2: #ffe6cc;
    --accent: #b5460f;
    --accent-deep: #8a3208;
    --pink: #e8478b;
    --yellow: #ffc400;
    --ok: #0f7a3d;
    --amber: #f59e0b;
    --danger: #e11d48;
    --on-accent: #ffffff;
    --notice-bg: #ddf7e2;
    --notice-fg: #0a6b36;
    --warn-bg: #ffeec2;
    --warn-fg: #7a4a05;
    --danger-bg: #ffe4e9;
    --danger-fg: #90122f;
    --paper-pattern: radial-gradient(var(--ink) 1px, transparent 1px);
    --paper-pattern-size: 18px 18px;
  }

  /* grape：藕紫纸面 + 深紫强调，点阵放宽到 26px 显得疏朗。 */
  html[data-theme="grape"] {
    color-scheme: light;
    --ink: #120c1e;
    --ink-soft: #4e4266;
    --ink-line: rgba(18, 12, 30, 0.3);
    --ink-line-mid: rgba(18, 12, 30, 0.37);
    --ink-line-strong: rgba(18, 12, 30, 0.42);
    --paper: #f9f7ff;
    --surface: #ffffff;
    --surface-2: #eae0ff;
    --accent: #6d28d9;
    --accent-deep: #4c1d95;
    --pink: #ff5fa2;
    --yellow: #ffd400;
    --ok: #0f7a3d;
    --amber: #f59e0b;
    --danger: #e11d48;
    --on-accent: #ffffff;
    --notice-bg: #dcf7e6;
    --notice-fg: #0a6b36;
    --warn-bg: #fff0c2;
    --warn-fg: #7a4a05;
    --danger-bg: #ffe4e9;
    --danger-fg: #90122f;
    --paper-pattern: radial-gradient(var(--ink) 1px, transparent 1px);
    --paper-pattern-size: 26px 26px;
  }
}

/* --- 2. 基础排版 -------------------------------------------------------- */
* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100dvh;
  padding: 20px;
  padding-bottom: calc(20px + env(safe-area-inset-bottom));
  background-color: var(--paper);
  /* 纸面纹理：纯 CSS，无图片依赖 */
  background-image: var(--paper-pattern);
  background-size: var(--paper-pattern-size);
  background-position: -1px -1px;
  background-attachment: fixed;
  color: var(--ink);
  font: 16px/1.6 var(--font-sans);
  overflow-wrap: break-word;
}

main {
  max-width: 860px;
  margin: 0 auto;
}

h1,
h2,
h3 {
  margin: 0 0 10px;
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.25;
}

h1 {
  font-size: 26px;
}

h2 {
  font-size: 19px;
}

h3 {
  font-size: 16px;
}

p {
  margin: 8px 0;
}

a {
  color: var(--accent-deep);
}

strong,
b {
  font-weight: 800;
}

code,
.uid,
.qr-number {
  font-family: var(--font-mono);
}

/* 可点击元素统一触感与可达性 */
:where(a, button, input, select, textarea, summary):focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* --- 3. 贴纸基元 -------------------------------------------------------- */
/* 贴纸 = 粗墨边 + 内白边（模切效果）+ 硬阴影 */
.sticker {
  border: var(--line) solid var(--ink);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: inset 0 0 0 3px var(--surface), var(--pop);
}

/* 轻微倾斜：打破网格，制造手贴上去的感觉 */
.tilt-l {
  transform: rotate(-1.2deg);
}

.tilt-r {
  transform: rotate(1.2deg);
}

/* 成就徽章 / 状态贴纸 */
.badge,
.sticker-badge {
  display: inline-block;
  padding: 3px 11px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--yellow);
  color: var(--ink);
  font-size: 12px;
  font-weight: 800;
  line-height: 1.5;
  white-space: nowrap;
  box-shadow: var(--pop-sm);
  transform: rotate(-1.6deg);
}

.badge-ok {
  background: var(--ok);
  color: var(--on-accent);
}

.badge-info {
  background: var(--accent);
  color: var(--on-accent);
}

.badge-warn {
  background: var(--amber);
}

.badge-danger {
  background: var(--danger);
  color: var(--on-accent);
}

/* 小圆点计数标志 */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 10px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--surface);
  font-size: 12px;
  font-weight: 800;
  box-shadow: var(--pop-sm);
}

/* --- 4. 容器与布局 ------------------------------------------------------ */
.panel {
  margin-top: 16px;
  padding: 18px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--pop);
}

/* 首页/入口卡片：贴纸卡，悬停时摆正并抬起 */
.card {
  display: block;
  padding: 18px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-lg);
  background: var(--surface);
  color: var(--ink);
  text-decoration: none;
  box-shadow: var(--pop);
  transform: rotate(-0.8deg);
  transition: transform var(--t) ease, box-shadow var(--t) ease,
    background var(--t) ease;
}

.card:nth-child(even) {
  transform: rotate(0.8deg);
}

.card:hover {
  background: var(--surface-2);
  transform: rotate(0) translate(-2px, -2px);
  box-shadow: var(--pop-lg);
}

.card:active {
  transform: rotate(0) translate(2px, 2px);
  box-shadow: none;
}

.card > b,
.card > strong {
  display: block;
  margin-bottom: 4px;
  font-size: 18px;
  font-weight: 800;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
  margin-top: 16px;
}

.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
}

.actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 14px;
}

.module-grid {
  display: grid;
  gap: 14px;
}

.module {
  padding: 14px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--pop-sm);
}

.module-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.module-header h3 {
  margin: 0;
}

.module-link {
  display: block;
  color: var(--ink);
  text-decoration: none;
}

.module-link:hover h3 {
  text-decoration: underline;
  text-decoration-thickness: 3px;
}

/* 分段切换：做成物理拨片 */
.tabs {
  display: flex;
  gap: 8px;
  margin-top: 14px;
}

.tab {
  flex: 1;
  padding: 11px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  text-align: center;
  font-weight: 800;
  text-decoration: none;
  box-shadow: var(--pop-sm);
  transition: transform var(--t-fast) ease, box-shadow var(--t-fast) ease;
}

.tab:hover {
  transform: translate(-1px, -1px);
  box-shadow: var(--pop);
}

.tab.active {
  background: var(--ink);
  color: var(--paper);
}

/* --- 5. 按钮 ------------------------------------------------------------ */
/* 未指定类的 <button> 也必须落在设计系统内。
   此前本文件只给「带类按钮」定义了外观，没有类的 <button> 会直接落到浏览器
   默认控件（灰色渐变底、系统圆角、13px 系统字体），在整站的新野性主义视觉里
   表现为一块突兀的灰色控件 —— 线上出现在自定义组件的「移除」按钮等处。

   选择器特异性 (0,0,1) 低于下面所有带类按钮 (0,1,0)，因此不会干扰
   .button/.primary/.secondary/.scan/.complete 等既有选择器链；
   :hover/:active 的 (0,1,1) 同样低于带类按钮的 (0,2,0)。
   默认取「次级」外观（纸面底 + 墨色字），需要主操作语义时请显式加类。 */
button {
  padding: 11px 16px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-weight: 800;
  cursor: pointer;
  box-shadow: var(--pop-sm);
  transition: transform var(--t-fast) ease, box-shadow var(--t-fast) ease,
    background var(--t-fast) ease;
}

button:hover {
  transform: translate(-2px, -2px);
  box-shadow: var(--pop);
}

button:active {
  transform: translate(2px, 2px);
  box-shadow: 0 0 0 var(--ink);
}

.button,
.submit,
.complete,
.retry,
.sync,
.scan,
.print-button,
.primary,
.secondary {
  display: inline-block;
  padding: 11px 16px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-sm);
  background: var(--accent);
  color: var(--on-accent);
  font: inherit;
  font-weight: 800;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  box-shadow: var(--pop-sm);
  transition: transform var(--t-fast) ease, box-shadow var(--t-fast) ease,
    background var(--t-fast) ease;
}

.button:hover,
.submit:hover,
.complete:hover,
.retry:hover,
.sync:hover,
.scan:hover,
.print-button:hover,
.primary:hover,
.secondary:hover {
  transform: translate(-2px, -2px);
  box-shadow: var(--pop);
}

/* 按下时下沉、阴影收拢：强化实体按键的反馈 */
.button:active,
.submit:active,
.complete:active,
.retry:active,
.sync:active,
.scan:active,
.print-button:active,
.primary:active,
.secondary:active {
  transform: translate(2px, 2px);
  box-shadow: 0 0 0 var(--ink);
}

.button:disabled,
.submit:disabled,
.scan:disabled,
.complete:disabled,
.print-button:disabled,
.primary:disabled,
button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
  box-shadow: var(--pop-sm);
}

.secondary {
  background: var(--surface);
  color: var(--ink);
}

.primary {
  background: var(--pink);
  color: var(--ink);
}

.scan {
  background: var(--yellow);
  color: var(--ink);
}

.retry,
.sync {
  background: var(--surface);
  color: var(--ink);
}

.complete {
  background: var(--ok);
  color: var(--on-accent);
}

.back {
  display: inline-block;
  margin-bottom: 4px;
  padding: 6px 12px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink);
  font-size: 13px;
  font-weight: 800;
  text-decoration: none;
  box-shadow: var(--pop-sm);
}

.back:hover {
  background: var(--yellow);
}

/* --- 6. 文字与状态 ------------------------------------------------------ */
.meta {
  color: var(--ink-soft);
  font-size: 14px;
}

/* 弱化文字：必须使用 --ink-soft。切勿改用更浅的灰——13px/400 属普通正文，
   门限为 4.5:1，浅灰会直接跌破 WCAG AA。 */
.muted {
  color: var(--ink-soft);
  font-size: 13px;
}

.hint {
  color: var(--ink-soft);
  font-size: 13px;
}

.empty {
  margin: 10px 0 0;
  color: var(--ink-soft);
  font-size: 14px;
}

.sdk-state {
  margin-top: 10px;
  color: var(--ink-soft);
  font-size: 13px;
}

.subheading {
  margin-top: 22px;
}

.uid {
  color: var(--ink-soft);
  font-size: 13px;
  word-break: break-all;
}

.status {
  display: inline-block;
  padding: 2px 10px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--ink);
  font-size: 12px;
  font-weight: 800;
  white-space: nowrap;
  box-shadow: var(--pop-sm);
}

/* 同步状态：徽章化，颜色即语义 */
.sync-status {
  display: inline-block;
  padding: 2px 10px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--surface);
  font-size: 12px;
  font-weight: 800;
  white-space: nowrap;
  box-shadow: var(--pop-sm);
}

.sync-sent {
  background: var(--ok);
  color: var(--on-accent);
}

.sync-pending {
  background: var(--yellow);
  color: var(--ink);
}

.sync-failed {
  background: var(--danger);
  color: var(--on-accent);
}

/* 提示条：左侧色块 + 粗边 */
.error,
.notice,
.warning {
  margin-top: 14px;
  padding: 12px 14px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r);
  box-shadow: var(--pop-sm);
  font-weight: 700;
}

.error {
  background: var(--danger-bg);
  color: var(--danger-fg);
}

.notice {
  background: var(--notice-bg);
  color: var(--notice-fg);
  /* 成功提示弹跳出现一次：对应操作成功后的即时反馈 */
  animation: toast-pop 0.28s ease-out;
}

.warning {
  background: var(--warn-bg);
  color: var(--warn-fg);
}

/* --- 7. 列表与记录 ------------------------------------------------------ */
.row {
  padding: 12px 0;
  border-bottom: var(--line) dotted var(--ink-line);
}

.row:last-child {
  border-bottom: 0;
}

.task {
  padding: 14px 0;
  border-bottom: var(--line) dotted var(--ink-line);
}

.task:last-child {
  border-bottom: 0;
}

.task-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.aircraft {
  color: var(--accent-deep);
  font-size: 13px;
  font-weight: 800;
  text-decoration: none;
}

.aircraft:hover {
  text-decoration: underline;
  text-decoration-thickness: 3px;
}

.record {
  padding: 16px 0;
  border-bottom: var(--line) dotted var(--ink-line);
}

.record:last-child {
  border-bottom: 0;
}

.record-head {
  display: flex;
  justify-content: space-between;
  gap: 16px;
}

.record-content {
  margin: 8px 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.record-notes {
  padding: 9px 11px;
  border: var(--line) dashed var(--ink-line-mid);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.binding {
  padding: 9px 0;
}

.binding:last-child {
  border-bottom: 0;
}

.file {
  padding: 14px 0;
  border-bottom: var(--line) dotted var(--ink-line);
}

.file:last-child {
  border-bottom: 0;
}

.change {
  padding: 12px 0;
  border-bottom: var(--line) dotted var(--ink-line);
}

.change:last-child {
  border-bottom: 0;
}

/* 变更记录容器：仅在屏幕增加间距，避免影响 A4 打印的分页位置 */
@media screen {
  .changes {
    margin-top: 6px;
  }
}

.change-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.change-values {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-top: 8px;
}

.change-value,
.base-value {
  padding: 8px 10px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-weight: 600;
}

/* --- 8. 键值详情 -------------------------------------------------------- */
.detail {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 6px 12px;
  margin-top: 6px;
}

.detail b,
.detail strong {
  color: var(--ink-soft);
}

.details {
  width: 100%;
  margin-top: 8px;
  border-collapse: collapse;
}

.details th {
  width: 42%;
}

.details th,
.details td {
  color: var(--ink);
  text-align: left;
  border: 0;
  vertical-align: top;
}

.pagination {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 18px;
}

.pagination a {
  padding: 8px 14px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink);
  font-weight: 800;
  text-decoration: none;
  box-shadow: var(--pop-sm);
}

.pagination a:hover {
  background: var(--yellow);
  transform: translate(-1px, -1px);
  box-shadow: var(--pop);
}

/* --- 9. 表单控件 -------------------------------------------------------- */
label {
  display: block;
  margin: 14px 0 6px;
  font-size: 14px;
  font-weight: 800;
}

input,
select,
textarea {
  width: 100%;
  padding: 11px 12px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
}

input:focus,
select:focus,
textarea:focus {
  background: var(--surface-2);
}

textarea {
  resize: vertical;
}

/* 搜索行：输入框 + 提交按钮作为一个整体控件组。
   此前这类组合由各页面在自己的 <style> 里重复定义，取值互不一致（间距 8px/10px、
   有无上边距、有无最大宽度），同一组件在设备列表与飞机列表呈现两种几何；
   更严重的是提交按钮借用 .button 后，会被 §11 手机断点的「width: 100%」拉满
   整行 —— 一个两字按钮霸占一行，把输入框挤到最小内容宽度。收敛到此处后，
   两个列表页共享同一套几何，页面 <style> 只保留各自特有的规则。

   几何基准：输入框与按钮同为 padding 11px、border 2px、font:inherit，
   再以 align-items:stretch 拉平成同一高度，两侧不会出现半像素级高度差。 */
.search {
  display: flex;
  align-items: stretch;
  gap: 10px;
  margin-top: 14px; /* 与 .tabs / .actions 的纵向节奏一致，避免与 .toolbar 贴死 */
  max-width: 520px;
}

/* 输入框吃掉全部剩余宽度。flex-basis 显式取 0 而非 auto：§9 开头的 input 规则
   给了 width:100%，会把基准尺寸抬到整行宽，在窄屏上放大收缩计算的不确定性。
   min-width:0 取消 flex 项的 min-content 下限 —— 否则输入框拒绝收缩，
   只能靠压缩按钮来腾地方，等于把问题转移给按钮。 */
.search > input:not([type="hidden"]) {
  flex: 1 1 0;
  min-width: 0;
}

/* 提交按钮保持内容宽度。特异性 (0,2,0) 高于 §11 手机断点里的 .button (0,1,0)，
   而媒体查询不改变特异性，故这一条无需重复声明断点即可生效。
   若删掉本规则，手机端搜索按钮会重新被拉满整行。 */
.search > .button,
.search > .submit {
  flex: 0 0 auto;
  width: auto;
}

/* 上传进度区：贴纸面板 + 进度条外观 */
.upload-status {
  margin-top: 14px;
  padding: 12px 14px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r);
  background: var(--surface-2);
  box-shadow: var(--pop-sm);
  font-weight: 700;
}

.upload-status progress {
  display: block;
  width: 100%;
  height: 14px;
  margin-bottom: 8px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--surface);
  overflow: hidden;
  appearance: none;
}

.upload-status progress::-webkit-progress-bar {
  background: var(--surface);
}

.upload-status progress::-webkit-progress-value {
  background: var(--accent);
}

.upload-status progress::-moz-progress-bar {
  background: var(--accent);
}

.upload-status[data-state="success"] {
  background: var(--notice-bg);
  color: var(--notice-fg);
}

.upload-status[data-state="error"] {
  background: var(--danger-bg);
  color: var(--danger-fg);
}

.file-upload {
  margin-top: 20px;
  padding-top: 12px;
  border-top: var(--line) dashed var(--ink-line-strong);
}

/* --- 10. 游戏化组件 ----------------------------------------------------- */
/* 10.1 进度条：值通过容器上的 --value 传入（0-100%），由模板按真实计数计算 */
.progress {
  position: relative;
  height: 26px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--surface);
  box-shadow: var(--pop-sm);
  overflow: hidden;
}

.progress > .progress-fill {
  display: block;
  height: 100%;
  width: var(--value, 0%);
  border-right: var(--line) solid var(--ink);
  background: var(--accent);
  animation: progress-grow 0.5s ease-out;
}

.progress-ok > .progress-fill {
  background: var(--ok);
}

/* 标签居中覆盖在填充条之上。为避免文字直接压在 --accent 填充色上（墨字压蓝底仅 3.27:1），
   标签内容承载在 --surface 底的小胶囊里；同色内描边把胶囊与填充色隔开。 */
.progress > .progress-label {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.progress > .progress-label > span {
  padding: 0 10px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--surface);
  box-shadow: 0 0 0 2px var(--surface);
  color: var(--ink);
  font-size: 12px;
  font-weight: 800;
  line-height: 1.35;
  white-space: nowrap;
}

@keyframes progress-grow {
  from {
    width: 0;
  }
}

/* 10.2 等级 / 经验提示：把真实累计量呈现为等级与经验值 */
.level {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--paper);
  font-size: 12px;
  font-weight: 800;
  box-shadow: var(--pop-sm);
}

/* 等级/经验数值：用在 .stat 内的主数字上，字号高于普通正文 */
.stat .xp {
  display: block;
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.stat {
  padding: 12px 14px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r);
  background: var(--surface-2);
  box-shadow: var(--pop-sm);
}

.stat b {
  display: block;
  font-size: 22px;
  font-weight: 800;
}

.stat-label {
  font-size: 12px;
  font-weight: 800;
  color: var(--ink-soft);
}

/* auto-fit 而非 auto-fill：项数少于轨道数时让已有项撑满整行，
   避免单项统计页面右侧留下大片空白。 */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 10px;
  margin-top: 16px;
}

/* 10.3 积分/成就反馈条：成功后弹出一次，不做循环动画 */
.toast {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 14px;
  padding: 11px 14px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r);
  background: var(--yellow);
  box-shadow: var(--pop-sm);
  font-weight: 800;
  animation: toast-pop 0.28s ease-out;
}

.toast-earned {
  flex: none;
  padding: 2px 10px;
  border: var(--line) solid var(--ink);
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--paper);
  font-size: 13px;
  font-weight: 800;
}

@keyframes toast-pop {
  from {
    transform: translateY(-6px) scale(0.96);
    opacity: 0;
  }
}

/* 10.4 贴纸头图：首页门面 */
.hero {
  position: relative;
  padding: 22px;
  border: var(--line-bold) solid var(--ink);
  border-radius: var(--r-lg);
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--pop-lg);
  transform: rotate(-0.6deg);
}

.hero h1 {
  margin-bottom: 6px;
  font-size: 28px;
}

.hero p {
  margin: 0;
  opacity: 0.95;
}

.hero .badge {
  position: absolute;
  top: -12px;
  right: 16px;
  background: var(--yellow);
}

/* --- 11. 响应式 --------------------------------------------------------- */
/* 手机：单列、放大触控目标、改用动态视口高度 */
@media (max-width: 640px) {
  body {
    padding: 14px;
    padding-bottom: calc(14px + env(safe-area-inset-bottom));
    font-size: 15px;
  }

  h1 {
    font-size: 22px;
  }

  .panel {
    padding: 15px;
    border-radius: var(--r);
    box-shadow: var(--pop-sm);
  }

  .grid {
    grid-template-columns: 1fr;
    gap: 12px;
  }

  /* 触控目标不小于 44px */
  .button,
  .submit,
  .complete,
  .retry,
  .sync,
  .scan,
  .print-button,
  .primary,
  .secondary,
  .tab,
  .back {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* 主操作按钮整行铺满，便于拇指触达。
     注意「搜索行」内的提交按钮不在此列 —— 它由 §9 的 .search > .button
     保持内容宽度（特异性 0,2,0 高于此处的 0,1,0）。若要让搜索按钮也铺满，
     必须同时删掉那一条，否则改了这里也不会生效。 */
  .button,
  .submit,
  .complete {
    width: 100%;
  }

  .toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .detail {
    grid-template-columns: 1fr;
    gap: 2px;
  }

  .detail b,
  .detail strong {
    font-size: 12px;
  }

  .change-values,
  .change-value {
    grid-template-columns: 1fr;
  }

  .card {
    transform: none;
  }

  .hero {
    transform: none;
    padding: 18px;
  }
}

@media (min-width: 641px) and (max-width: 899px) {
  .grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* --- 12. 减少动效偏好 --------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  .card,
  .hero,
  .badge,
  .sticker-badge {
    transform: none !important;
  }
}

/* --- 13. 打印 ----------------------------------------------------------- */
/* 打印页自带完整打印规则；此处兜底剥掉装饰，保证可读 */
@media print {
  /* 打印一律回落为「白纸 + 黑墨」。
     这一步之所以是安全的，前提是 §1.1 的主题块全部位于 @media screen 内：
     打印上下文里所有主题块均失效，24 个 token 一致取到 :root（即 classic），
     因此下面的重置对每套主题都作用在同一个基线上，不存在「一侧被重置、
     另一侧仍取主题值」的混合配对。
     反例（改造前）：只重置墨/纸一侧的 9 个 token，其余 15 个仍是主题取值。
     这在浅色主题上是净收益，在深色主题上却是净损失 —— --paper 变白而
     --accent-deep 仍是提亮的浅蓝，链接对比度从 9.15:1 掉到 2.02:1。
     由 theme_test.go 的 TestPrintContextIgnoresTheme 守护「打印块不得再按
     data-theme 分支」。 */
  :root {
    --ink: #000000 !important;
    --ink-soft: #333333 !important;
    --ink-line: rgba(0, 0, 0, 0.35) !important;
    --ink-line-mid: rgba(0, 0, 0, 0.42) !important;
    --ink-line-strong: rgba(0, 0, 0, 0.5) !important;
    --paper: #ffffff !important;
    --surface: #ffffff !important;
    --surface-2: #ffffff !important;
    --paper-pattern: none !important;
  }

  body {
    padding: 0;
    background: #fff !important;
    background-image: none !important;
    color: #000;
  }

  /* .hero 是页面上唯一的大面积实色块，打印时置白以免整页出墨 */
  .hero {
    background: #fff !important;
    color: #000 !important;
  }

  .panel,
  .card,
  .module,
  .stat,
  .sticker,
  .badge,
  .toast,
  .progress {
    box-shadow: none !important;
    transform: none !important;
  }

  .no-print,
  .toolbar,
  .tabs,
  .actions,
  .pagination {
    display: none !important;
  }

  .card,
  .panel,
  .module {
    border-color: #000 !important;
    break-inside: avoid;
  }
}
