
:root {
  --bg: #f6f7f9;
  /* 登录页整页底色比通用 --bg 略偏蓝，是设计稿单独定的 */
  --bg-soft: #f7f9fc;
  --card: #ffffff;
  /* 输入框/搜索框底色：比卡片略深，浅色下才有「凹陷、可输入」的暗示 */
  --field: #f1f5f9;
  /* 输入框聚焦态：浅色下提亮到纯白，深色下比 --field 略亮 */
  --field-focus: #ffffff;
  /* 悬停底色（幽灵按钮、社交按钮） */
  --hover: #f8fafc;
  --text: #16181d;
  --text-soft: #3f444d;
  --muted: #6b7280;
  --border: #e5e7eb;
  --border-strong: #d5d8de;
  --divider: #e2e8f0;
  --border-hover: #b9c7da;
  /*
   * 登录页的一套前景色。原先都是写死在规则里的（#0f1c2e 那批），
   * 深色主题要求它们整体翻转，所以提升为变量。浅色值与原硬编码**逐字相同**，
   * 因此这次改动对浅色外观是零回归。
   */
  --title: #0f1c2e;
  --sub: #5f6c80;
  --label: #1e2a3e;
  --hint: #8696a9;
  --icon: #7e8b9d;
  --body-text: #2b3a4e;
  --social-text: #1e293b;
  --social-icon: #4b5b6e;
  --link-soft: #4d5d72;
  /* 品牌蓝取自图标底色（cikio-authserver.svg 是 #102C78）。它只负责**底色**：顶栏、主按钮、头像圈 */
  --primary: #102c78;
  --primary-hover: #0b2059;
  /*
   * 前景蓝：链接、图标、描边专用它，**不要**用 --primary。
   * 深色主题下「底色要够深才有品牌感、前景要够亮才看得清」是相反的需求，
   * 同一个值无法同时满足 —— 这就是它必须单独存在的理由。
   */
  --primary-ink: #102c78;
  --danger-bg: #fef3f2;
  --danger-border: #fecdca;
  --danger-text: #b42318;
  --ok-bg: #ecfdf5;
  --ok-text: #047857;
  --warn-bg: #fffbeb;
  --warn-text: #b45309;
  --info-bg: #f4f7fb;
  --info-border: #dbe3ef;
  --info-text: #33415c;
  --radius: 12px;
  --shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px -12px rgba(16, 24, 40, 0.18);
}

/*
 * ==================================================================
 * 深色主题
 *
 * 三态由 <html data-theme> 决定：
 *   无属性  → 跟随系统（下面的媒体查询生效）
 *   'light' → 强制浅色（媒体查询用 :not([data-theme='light']) 让位）
 *   'dark'  → 强制深色
 * 属性由一段内联在 head 里的脚本同步写入（见 lib/client-scripts.ts 的
 * themeInitScript），必须在首次绘制前完成，否则会闪一下浅色再跳深色。
 *
 * 为什么深色值写了两遍：CSS 变量没法跨块复用，而「无 JS 时跟随系统」与
 * 「有 JS 时手动指定」必须由两个不同入口触发。两处内容必须保持一致。
 * ==================================================================
 */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --bg: #0d1117;
    --bg-soft: #0d1117;
    --card: #161c26;
    --field: #1b2230;
    --field-focus: #232c3b;
    --hover: #1f2734;
    --text: #e6ebf3;
    --text-soft: #c3ccd9;
    --muted: #98a2b3;
    --border: #262d38;
    --border-strong: #364150;
    --divider: #2a3341;
    --border-hover: #3d4a5c;
    --title: #eaf0f8;
    --sub: #a7b2c2;
    --label: #dbe3ee;
    --hint: #8e99aa;
    --icon: #97a3b5;
    --body-text: #dde4ee;
    --social-text: #dbe3ee;
    --social-icon: #a9b4c4;
    --link-soft: #9aa5b6;
    --primary: #1b3f96;
    --primary-hover: #254da8;
    --primary-ink: #8fb4ff;
    --danger-bg: #3a1d1a;
    --danger-border: #5c2b26;
    --danger-text: #ff9c92;
    --ok-bg: #12301f;
    --ok-text: #6ee7a8;
    --warn-bg: #33270f;
    --warn-text: #f5c96b;
    --info-bg: #152438;
    --info-border: #23395c;
    --info-text: #a8c4ea;
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 28px -12px rgba(0, 0, 0, 0.6);
  }
}

:root[data-theme='dark'] {
  --bg: #0d1117;
  --bg-soft: #0d1117;
  --card: #161c26;
  --field: #1b2230;
  --field-focus: #232c3b;
  --hover: #1f2734;
  --text: #e6ebf3;
  --text-soft: #c3ccd9;
  --muted: #98a2b3;
  --border: #262d38;
  --border-strong: #364150;
  --divider: #2a3341;
  --border-hover: #3d4a5c;
  --title: #eaf0f8;
  --sub: #a7b2c2;
  --label: #dbe3ee;
  --hint: #8e99aa;
  --icon: #97a3b5;
  --body-text: #dde4ee;
  --social-text: #dbe3ee;
  --social-icon: #a9b4c4;
  --link-soft: #9aa5b6;
  --primary: #1b3f96;
  --primary-hover: #254da8;
  --primary-ink: #8fb4ff;
  --danger-bg: #3a1d1a;
  --danger-border: #5c2b26;
  --danger-text: #ff9c92;
  --ok-bg: #12301f;
  --ok-text: #6ee7a8;
  --warn-bg: #33270f;
  --warn-text: #f5c96b;
  --info-bg: #152438;
  --info-border: #23395c;
  --info-text: #a8c4ea;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 28px -12px rgba(0, 0, 0, 0.6);
}

/*
 * 原生控件的配色（滚动条、输入框内部、下拉箭头）交给 color-scheme，
 * 它是唯一能让浏览器自己那部分 UI 跟着切换的开关。
 */
:root {
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    color-scheme: dark;
  }
}

:root[data-theme='dark'] {
  color-scheme: dark;
}

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

/*
 * 让 hidden 属性真正生效。
 * 浏览器 UA 样式表里 [hidden] 的优先级低于任何 class 规则，而 .sso-field 声明了
 * display:flex —— 会把 hidden 顶掉（注册页预留的「邮箱验证码」字段就是这么意外露出来的）。
 * 想要「默认隐藏、以后启用」，就必须有这条兜底。
 * 注意：本文件整体是一个模板字符串，CSS 注释里不能出现反引号。
 */
[hidden] {
  display: none !important;
}

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
    "Hiragino Sans GB", "Microsoft YaHei", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

.page {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding: 40px 20px;
}

/* ---------- 品牌区（卡片之上） ---------- */

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
}

.brand__icon {
  width: 30px;
  height: 30px;
  border-radius: 8px;
  display: block;
}

.brand__name {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

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

.card {
  width: 100%;
  max-width: 400px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 32px;
}

.card--wide {
  max-width: 480px;
}

.card__title {
  margin: 0 0 6px;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.card__subtitle {
  margin: 0 0 22px;
  font-size: 13px;
  color: var(--muted);
}

/* ---------- 结果 / 错误提示页（message.tsx） ----------
   层次：彩色圆徽（+状态码角标）→ 标题 → 说明 → 操作按钮。
   配色全部走令牌，深浅色自动跟随。 */

.msg-icon {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.msg {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 36px 28px 32px;
  text-align: center;
}

.msg__badge {
  position: relative;
  width: 56px;
  height: 56px;
  border-radius: 999px;
  display: grid;
  place-items: center;
}

.msg__badge[data-tone='danger'] {
  background: var(--danger-bg);
  color: var(--danger-text);
}

.msg__badge[data-tone='warn'] {
  background: var(--warn-bg);
  color: var(--warn-text);
}

.msg__badge[data-tone='info'] {
  background: var(--field);
  color: var(--text-soft);
}

/* 状态码角标：盖在圆徽右下角，一眼看出「这是 HTTP 层面的拒绝」 */
.msg__code {
  position: absolute;
  right: -10px;
  bottom: -4px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--text);
  color: var(--card);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.msg__title {
  margin: 2px 0 0;
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.msg__desc {
  margin: 0;
  max-width: 340px;
  color: var(--muted);
  font-size: 14px;
  line-height: 1.7;
}

/*
 * 正文较长时的提示页（目前只有封禁页）：居中排版对一两句短句很好看，
 * 但正文到三行以上，参差的居中文本会明显更难读 —— 需要让人读进去的内容一律左对齐，
 * 并把宽度放宽一点，避免每行只有七八个字。
 */
.msg__desc--long {
  max-width: 430px;
  text-align: left;
}

/*
 * 一句话结论。提示页的层次是「标题说发生了什么 → 结论行说具体到什么程度 → 事实 → 说明」，
 * 这一行是用户扫页面时真正要找的信息（封禁到什么时候），所以比正文更大更实，
 * 但字号仍低于标题，不抢标题的层级。
 */
.msg__headline {
  margin: 0;
  max-width: 430px;
  color: var(--title);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.6;
}

/*
 * 结构化事实（目前只有封禁页的账号信息）。
 * 做成带底色的卡片而不是裸文本：它是一块「凭据」，视觉上要与说明文字分开 ——
 * 拿到截图的人能一眼找到该核对哪个字段。
 * 值用等宽字体：账号 ID 是要被人抄下来/逐字核对的字符串，0 与 O、1 与 l 不能看混。
 */
.msg__facts {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 8px 16px;
  width: 100%;
  max-width: 430px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--field);
  text-align: left;
  font-size: 13px;
  line-height: 1.5;
}

.msg__facts dt {
  color: var(--muted);
  white-space: nowrap;
}

.msg__facts dd {
  margin: 0;
  color: var(--text);
  word-break: break-all;
}

.msg__facts dd.is-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

.msg__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 8px;
}

/* 提示页的操作按钮不像表单那样通栏：居中、按内容宽度 */
.msg__actions .btn--primary {
  width: auto;
  padding: 0 22px;
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 40px;
  padding: 0 16px;
  border: 1px solid transparent;
  border-radius: 8px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.btn--primary {
  width: 100%;
  background: var(--primary);
  color: #fff;
}

.btn--primary:hover {
  background: var(--primary-hover);
}

.btn--ghost {
  background: var(--card);
  border-color: var(--border-strong);
  color: var(--text);
}

.btn--ghost:hover {
  background: var(--hover);
}

.btn[disabled] {
  opacity: 0.65;
  cursor: default;
}

/* ---------- 图标（用 class 控制描边，避免在 JSX 里写 svg 的连字符/驼峰属性） ---------- */

.icon {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon--sm {
  width: 15px;
  height: 15px;
}

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

.alert {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  margin: 0 0 16px;
  padding: 10px 12px;
  border: 1px solid var(--danger-border);
  border-radius: 6px;
  background: var(--danger-bg);
  color: var(--danger-text);
  font-size: 13px;
}

.alert__icon {
  flex: none;
  margin-top: 1px;
}

/* ---------- 卡片底部链接 ---------- */

.links {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
  font-size: 13px;
  color: var(--muted);
  text-align: center;
}

/* ==================================================================
   账号中心（/account/*，见 src/pages/account-*.tsx）
   app 式布局：深色顶栏 + 居中内容区（比认证页宽，信息密度更高）。
   布局参考用户给的学校「安全中心」：用户卡在顶部，下面左安全项 / 右常见问题。
   ================================================================== */

.acct-body {
  background: var(--bg);
}

/*
 * toast 默认停在 top: 1rem，那是为「居中卡片的认证页」定的；
 * 账号中心顶部有一条 56px 的深色顶栏，默认位置会正好压住导航页签。
 * 这里把容器整体下移到底栏下方。
 */
body.acct-body .toast-root,
body.adm-body .toast-root {
  top: 72px;
}

.acct-top {
  /* 顶栏高度。窄屏面板要用它算「最多能占多高」——别在面板里再写死一遍数字 */
  --acct-topbar-h: 56px;
  background: var(--primary);
  color: #fff;
}

/*
 * 顶栏通栏、左右内边距与 .acct-layout 一致（32px）——
 * 之前它是一个 max-width:1040px 的居中容器，于是「品牌区」比下面侧栏的左缘更靠右，
 * 两条竖线对不齐。现在 logo 与侧栏左边缘、右侧身份区与内容区右缘各在同一条线上。
 * （窄屏仍由 860px 断点改成 space-between 的三段式，不参与这套对齐。）
 */
.acct-top__inner,
.adm-top__inner {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 0 32px;
  min-height: 56px;
}

/*
 * 宽屏（>=861px）没有顶栏：账户信息与外观切换都在侧栏底部（用户 2026-10-06 要求）。
 * 顶栏那套（汉堡 / 面板）只服务窄屏，所以整块 display:none —— 面板是它的子元素，
 * 跟着一起隐藏，不必单独处理。
 * 顺带把 toast 落点上移：body 级那条 top:72px 是为「顶栏下方」定的，宽屏没有顶栏，
 * 72px 会让提示悬在半空。
 */
@media (min-width: 861px) {
  .acct-top,
  .adm-top {
    display: none;
  }

  body.acct-body .toast-root,
  body.adm-body .toast-root {
    top: 16px;
  }
}

.acct-brand,
.adm-top__brand {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  color: #fff;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
}

/* 窄屏顶栏的站名可能很长（「CIKIO 管理后台」），截断而不是把右侧那组挤掉 */
.acct-brand span,
.adm-top__brand span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * 顶栏品牌区允许被压窄、文字可截断：不加 min-width:0 时 flex 项按内容宽度计算，
 * 窄屏上会把右侧的主题切换顶出去；加了之后最坏情况是站名带省略号。
 */
.acct-brand {
  min-width: 0;
}

.acct-brand span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * 品牌图形：内联 SVG（不引 favicon.svg，省一次请求且颜色可控）。
 * fill 用 currentColor，于是它跟着顶栏白字走，深浅色都不用换图。
 * 宽高比 592:458（viewBox 已裁到图形包围盒），高 17px 时宽约 22px ——
 * 可见高度与 16px 字号的文字基本等高（此前沿用 1254 原画布，图形只占中间
 * 一小半，缩到 18px 时可见部分只剩约 7px，看起来就是「logo 特别小」）。
 */
.acct-brand__mark {
  display: block;
  flex: none;
  width: 22px;
  height: 17px;
  fill: currentColor;
}

/*
 * 顶栏右侧：外观切换 → 退出（窄屏顶栏的最后两样）。
 * 身份块与「头像+邮箱」已从顶栏移除 —— 它们和宽屏侧栏底部那张账户卡是同一份信息，
 * 顶栏（只剩窄屏）放不下四样以上的东西。margin-left:auto 把它俩推到最右。
 */
.acct-me,
.adm-me {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
  font-size: 13px;
}

.acct-me__out,
.adm-me__out {
  height: 30px;
  padding: 0 12px;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 8px;
  background: transparent;
  color: #fff;
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
}

.acct-me__out:hover,
.adm-me__out:hover {
  background: rgba(255, 255, 255, 0.14);
}

/*
 * 宽屏主体：左右分栏。**外框锁死一屏、只有右侧内容区滚动**（用户 2026-10-06 要求）。
 *
 * 与上一版（整页滚动 + 侧栏 sticky）的区别，以及为什么换：
 *  - sticky 只是「滚到某处就停住」，侧栏在**首屏滚动过程中仍会跟着动**（上去 20px 才钉住），
 *    而且滚动条属于整个文档 —— 滚到底时页脚和侧栏一起被顶掉。
 *  - 现在是应用外壳的形态：外框 height = 一屏、overflow: hidden，滚动交给内容区。
 *    侧栏连 sticky 都不需要（父容器根本不滚），页脚在内容区里跟着内容滚。
 * 用 dvh 而不是 vh：移动端浏览器地址栏折叠时 vh 与实际可视区不一致（宽屏虽用不到，
 * 但调试窗口拖到 861 附近时这一套规则也会命中）。
 * 右侧**不留 padding**：内容区的滚动条要贴着窗口右缘，留了就成了「滚动条浮在中间」。
 *
 * ⚠️ 2026-10-07 起这一套**账号中心与管理后台共用**（.adm-layout 是管理后台那份，
 * 见 admin-shell.tsx）。用户要求把后台统一成账号中心的设计，与其抄一份、不如共用：
 * 下面所有「A, B」成对的选择器都是这个意思，改动一处两个界面同步生效。
 * 两边差异只在侧栏内部（后台是分组 + 图标 + 角标，账号中心是平铺六项）。
 */
.acct-layout,
.adm-layout {
  display: grid;
  grid-template-columns: 248px minmax(0, 1fr);
  /*
   * 行高必须钉死成「剩余的一屏」。只写 height:100dvh 是不够的：隐式行是 auto，
   * 一旦格子里的内容比一屏高（典型是后台侧栏展开二级菜单），行就被内容撑高 ——
   * 侧栏跟着长到 769px，底部那块深浅色切换直接掉到屏幕下面点不到（2026-10-09 实测）。
   * minmax(0, 1fr) 让行最多就是一屏，超出的部分交给侧栏内部的滚动条。
   */
  grid-template-rows: minmax(0, 1fr);
  gap: 36px;
  align-items: stretch;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  padding: 20px 0 20px 32px;
}

/*
 * 侧栏 = 一张撑满一屏的白底容器（用户 2026-10-06 要求「加一个白底容器包边」）。
 * 它和内容卡片用同一套语言（--card 底 + --border 边 + --shadow），于是左边一条、
 * 右边一片，页面整体读起来是「两块面板」而不是「一排裸着的链接」。
 *
 * height: 100% = 外框的一屏减去上下 20px 留白（不再是 calc(100vh - 40px)，
 * 高度由父容器给，改外框留白时不必再同步这个数字）。
 * flex column 把「账户卡 + 外观切换」压到最底部；菜单区 flex:1 且可滚 ——
 * 菜单项将来变多时不会把底部那两块顶出视口。
 * box-sizing 全站是 border-box，所以 padding 不会把高度顶破。
 *
 * 管理后台在窄屏会把这同一张容器变成左侧抽屉（见文末 860 断点），
 * 所以这里不写 position —— 免得到那边要覆盖一堆属性。
 */
.acct-side,
.adm-side {
  display: flex;
  flex-direction: column;
  gap: 14px;
  height: 100%;
  min-width: 0;
  padding: 14px 12px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--card);
  box-shadow: var(--shadow);
}

/*
 * 侧栏顶部品牌区（用户 2026-10-06 要求「分割出一块区域，专用展示 logo + 名称」）。
 * 一条 --border 分隔线与下面的菜单切开；左内边距 14px = 菜单项的内边距，
 * 于是图形与菜单文字落在同一条竖线上（否则顶部这块看起来是歪的）。
 * 文字取 --title（浅色深字 / 深色浅字），图形是 currentColor，跟着走，不用第二套变量。
 * 图形样式复用 .acct-brand__mark（顶栏、账号中心侧栏、后台侧栏三处都是同一个 SVG 组件）。
 */
.acct-side__brand,
.adm-side__brand {
  display: flex;
  flex: none;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 6px 14px 14px;
  /* 与菜单之间的距离交给侧栏容器的 gap（14px），这里不再叠 margin */
  border-bottom: 1px solid var(--border);
  color: var(--title);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
}

/* 站名可能很长（「CIKIO 管理后台」），截断而不是撑破侧栏 */
.acct-side__brand span,
.adm-side__brand span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.acct-side__brand:hover,
.adm-side__brand:hover {
  color: var(--primary-ink);
  text-decoration: none;
}

.acct-side__nav,
.adm-side__nav {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 2px;
  min-height: 0;
  overflow-y: auto;
  /*
   * 无论有没有滚动条，都先把滚动条那条槽位留出来（用户 2026-10-09 要求）。
   * 不加这一条时：展开二级菜单 → 菜单区变高 → 出现滚动条 → 菜单可用宽度少 6px，
   * 整排条目连同右端那列展开箭头一起横移，看起来像在跳。
   * 内容区 .acct-main 本来就有同一条（见下），这里补齐，两处口径一致。
   */
  scrollbar-gutter: stable;
}

/*
 * 细滚动条（用户 2026-10-09 要求「滚动条优化成更细的版本」）。
 *
 * 原生滚动条在 Windows 上是 15px，落在 248px 宽的侧栏里等于凭空吃掉 6% 宽度；
 * 而且它和上面那条 stable 槽位是同一件事的两面 —— **槽位宽度就是滚动条宽度**，
 * 所以槽位不需要单独给数字，滚动条一细，槽位自动跟着细。
 *
 * ⚠️ 引擎差异必须拆开写，不能两个都写：**Chrome 只要看到 scrollbar-width 或
 * scrollbar-color 的非 auto 值，就改用内置渲染并彻底忽略 ::-webkit-scrollbar**
 * （2026-10-09 实测：只写 scrollbar-width: thin 时，下面 ::-webkit-scrollbar 的 6px
 * 被顶掉，实际变成内置 thin 的 10px；把两个标准属性改回 auto，6px 立刻生效）。
 * 内置 thin 的宽度不可控，而我们要的是「刚好 6px」，于是按引擎分流：
 *   - Chromium / WebKit → ::-webkit-scrollbar（唯一能精确指定像素的途径）；
 *   - 其它（Firefox）   → scrollbar-width: thin + scrollbar-color。
 * 判据用 @supports selector(::-webkit-scrollbar)：Chrome/Safari 认得它（true，跳过标准
 * 属性），Firefox 不认（false，走标准属性）。这样也顺带处理了 Safari。
 *
 * 配色只借现有变量：滑块 --border-strong（浅色 #d5d8de / 深色 #364150），
 * 轨道透明、滑块全圆角，两个主题下都是一条安静的分隔感提示；hover 才加深到 --muted。
 *
 * 作用面：**应用自己的滚动容器**（宽屏外壳的侧栏与内容区、窄屏顶栏的导航面板、
 * 头像弹窗），刻意不用全局通配选择器 —— 登录页等不带滚动条的页面保持原生外观，
 * 改动面越小越好核对。选择器用 :is() 收成一行，以后加容器只改这一处。
 *
 * 注：只有侧栏那一条额外要 scrollbar-gutter: stable（见上），其余容器不加 ——
 * 内容区本来就有；导航面板 / 弹窗是按内容定高的卡片，常留一条 6px 空槽反而看得见。
 */
:is(.acct-side__nav, .adm-side__nav, .acct-main, .adm-main, .nav-panel, .avmodal__panel)::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

:is(.acct-side__nav, .adm-side__nav, .acct-main, .adm-main, .nav-panel, .avmodal__panel)::-webkit-scrollbar-track {
  background: transparent;
}

:is(.acct-side__nav, .adm-side__nav, .acct-main, .adm-main, .nav-panel, .avmodal__panel)::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: var(--border-strong);
}

:is(.acct-side__nav, .adm-side__nav, .acct-main, .adm-main, .nav-panel, .avmodal__panel)::-webkit-scrollbar-thumb:hover {
  background: var(--muted);
}

/* Firefox 及其它不认 ::-webkit-scrollbar 的引擎：退回标准属性 */
@supports not selector(::-webkit-scrollbar) {
  :is(.acct-side__nav, .adm-side__nav, .acct-main, .adm-main, .nav-panel, .avmodal__panel) {
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
  }
}

.acct-side__foot,
.adm-side__foot {
  display: grid;
  flex: none;
  gap: 10px;
}

/*
 * 账户卡：头像 + 昵称 + 邮箱 + 退出键。
 * 侧栏整体已是白底容器，所以这里用「内嵌的浅色块」表达（--field 底 + 无边框无投影），
 * 层次是「白容器 > 浅块 > 白按钮」——比白底上再叠一张白卡清楚。
 */
.acct-side__card,
.adm-side__card {
  display: grid;
  gap: 10px;
  min-width: 0;
  padding: 12px;
  border-radius: 12px;
  background: var(--field);
}

/* 退出键：浅块上的白按钮（深色主题下自动变成比浅块更暗的实心块） */
.acct-side__out,
.adm-side__out {
  width: 100%;
  height: 34px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: var(--card);
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
}

.acct-side__out:hover,
.adm-side__out:hover {
  background: var(--field);
}

.acct-side__item {
  display: block;
  padding: 8px 14px;
  border-radius: 8px;
  font-size: 14px;
  text-decoration: none;
}

/*
 * 悬停只给「色块」这一种反馈，不给文字任何变化 ——
 * 全局有一条 a:hover 加下划线的规则，而菜单项整行都是可点区域，
 * 再叠一条下划线既多余又和选中态打架。可点性由整块的底色承担。
 * 底色用 --field 而不用 --hover：侧栏是白底容器，--hover（#f8fafc）落在白底上
 * 几乎看不出来。同一份菜单在窄屏面板里也是白底（.nav-panel），两处口径一致。
 * （提醒：本文件整段是模板字符串，CSS 注释里不能出现反引号。）
 */
.acct-side__item:hover,
.adm-side__item:hover {
  background: var(--field);
  text-decoration: none;
}

/*
 * 当前项 = 一整块单色底（用户 2026-10-06：不要左侧颜色点缀，直接单色块包裹）。
 * 于是它与窄屏面板里的 .nav-panel__item.is-active 完全同款 —— 同一份菜单的两种呈现
 * 不应该有两种选中语言。
 * ⚠️ 底色用 --field 而不是 --card：侧栏整体是白底容器（见 .acct-side），
 * 白色小卡片放进白容器里等于没有选中态（加投影也救不回来，投影落在同色白底上）。
 * --field 在浅色下比 --card 略深、深色下略亮，两个主题里都是一块看得见的色块。
 */
.acct-side__item.is-active,
.adm-side__item.is-active {
  background: var(--field);
  color: var(--primary-ink);
  font-weight: 600;
}

/*
 * 内容区 = **唯一会滚的那块板**（宽屏）。height:100% 由外框的一屏高决定。
 * scrollbar-gutter: stable 让滚动条出现时不推动内容 —— 否则从短页切到长页，
 * 整块内容会横向跳一下。
 *
 * ⚠️ 宽度限制**不能写在这一层**（2026-10-09 修）：
 * 滚动条画在元素的右缘（padding 之外，见 CSS Overflow 的 scrollbar gutter 定义），
 * 所以给滚动容器加 max-width 时，容器右侧会留出一段没有内容的空白，滚动条就停在
 * 那段空白的内侧 —— 用户看到的就是「滚动条浮在页面中间，不在右边」。
 * 现在容器铺满剩余宽度（滚动条贴窗口右缘），限宽下沉到里面的 body / foot 两层并居中。
 *
 * flex column + .acct-main__body{flex:1}：页脚**贴住内容区底部**
 * （用户 2026-10-06：「页脚别紧贴内容，要落在内容区底部、与内容之间有间隔」）。
 * 内容不满一屏时，多出来的空间全部由 body 吸收，于是页脚落在最下方而不是紧跟在内容后面。
 */
.acct-main,
.adm-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  height: 100%;
  /* 左内边距留 0：内容区紧接侧栏那一列（间隔已由 grid 的 gap 给）。
     右侧留 32 是为了内容与滚动条之间有呼吸位 —— 滚动条仍贴窗口右缘，
     它画在 padding 之外，不会被这 32 顶到里面去。 */
  padding: 4px 32px 8px 0;
  overflow-y: auto;
  scrollbar-gutter: stable;
}

/*
 * 页面内容这一层。flex:1 1 auto 让它吸收剩余高度（把页脚顶到底部）；
 * min-height 兜底用 auto（默认值）—— 内容超过一屏时它自然长高，页脚跟在后面。
 *
 * 限宽（1080）+ 居中都在这里：内容窄一点更好读，但滚动容器要贴窗口右缘
 * （见 .acct-main 的说明）。超宽屏上这层被 max-width 卡住，auto 外边距把
 * 剩下的空白平分到两侧 —— 卡片落在「侧栏右边那块区域」的正中间。
 */
.acct-main__body,
.adm-main__body {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  max-width: 1080px;
  margin-inline: auto;
}

/*
 * 「头像 + 昵称 + 邮箱」身份块（侧栏与窄屏面板共用，见 nav.tsx 的 AccountIdentity）。
 * 头像没有时显示首字母；两行文字都要能截断 —— 长邮箱不能把侧栏撑破。
 */
.acct-id {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.acct-id__avatar {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  font-size: 18px;
  font-weight: 600;
  overflow: hidden;
}

.acct-id__avatar img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.acct-id__meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.acct-id__name {
  overflow: hidden;
  font-size: 14px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.acct-id__mail {
  overflow: hidden;
  font-size: 12px;
  color: var(--muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * 页面标题行：左标题、右快捷入口（参考微软「您的信息」右上角的「更改密码/安全性」）。
 * 只在个人资料页用 —— 其他页没有对应的快捷动作，硬放就成装饰了。
 */
.acct-h1bar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.acct-h1bar .acct-h1 {
  margin: 0;
}

.acct-shortcut {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}

.acct-shortcut svg {
  display: block;
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: var(--primary-ink);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.acct-shortcut__t {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--primary-ink);
}

.acct-shortcut__sub {
  display: block;
  font-size: 12px;
  color: var(--muted);
}

/*
 * 个人资料页的单列卡片堆叠（微软「您的信息」的形态）—— 不走 .acct-grid 两列：
 * 照片卡与信息卡都是「行式内容」，通栏才放得下四列的行布局。
 */
.prof-stack {
  display: grid;
  gap: 20px;
  margin-top: 20px;
}

/* 照片区：大圆头像（96px，页面唯一的大图）+ 说明 + 更改照片控件 */
.prof-photo {
  display: flex;
  align-items: flex-start;
  gap: 28px;
}

.prof-photo__avatar {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  font-size: 34px;
  font-weight: 600;
  overflow: hidden;
}

.prof-photo__avatar img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.prof-photo__body {
  min-width: 0;
  max-width: 520px;
}

.prof-photo__body .acct-sub {
  margin: 0;
}

.prof-photo__form {
  margin-top: 14px;
}

.prof-photo__form .acct-file {
  max-width: 360px;
}

.prof-photo__form .acct-actions {
  margin: 12px 0 0;
}

/*
 * 微软式信息行：标签 | 值 | 说明 | 操作。
 * 说明列是「这个字段是干什么的」的灰字，操作列放编辑入口（details 展开表单）
 * 或「不可修改」的静默标注。窄屏（560px 以下）退化为上下堆叠。
 */
.prof-row {
  display: grid;
  grid-template-columns: 140px minmax(0, 1.2fr) minmax(0, 1fr) auto;
  gap: 16px;
  align-items: start;
  padding: 14px 0;
  border-top: 1px solid var(--border);
}

.acct-card__title + .prof-row {
  border-top: 0;
  padding-top: 2px;
}

.prof-row__label {
  padding-top: 2px;
  font-size: 13px;
  color: var(--muted);
}

.prof-row__value {
  font-size: 14px;
  overflow-wrap: anywhere;
}

.prof-row__note {
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--muted);
}

.prof-row__action {
  justify-self: end;
  font-size: 13px;
  text-align: right;
}

.prof-row__action--muted {
  color: var(--muted);
}

/* 编辑昵称：details 收起时是一行信息，展开才是表单（零 JS 的编辑态） */
.prof-edit summary {
  cursor: pointer;
  color: var(--primary-ink);
  font-size: 13px;
  list-style: none;
}

.prof-edit summary::-webkit-details-marker {
  display: none;
}

.prof-edit summary:hover {
  text-decoration: underline;
}

.prof-edit[open] summary {
  margin-bottom: 12px;
}

.prof-edit form {
  max-width: 420px;
  text-align: left;
}

/* 窄屏：照片区纵向、信息行退化为上下堆叠（标签在上） */
@media (max-width: 560px) {
  .prof-photo {
    flex-direction: column;
    gap: 16px;
  }

  .prof-row {
    grid-template-columns: 1fr;
    gap: 4px;
    padding: 12px 0;
  }

  .prof-row__action {
    justify-self: start;
    text-align: left;
  }

  .acct-h1bar {
    flex-direction: column;
    gap: 10px;
  }
}

/*
 * 更改照片弹窗（参考微软账户的更改照片对话框）。
 * PC：居中一张 460px 白卡 + 遮罩；≤560px：铺满视口（微软移动端同款）。
 * 结构与钩子见 account-profile.tsx，交互见 AVATAR_EDITOR_SCRIPT。
 */
.avmodal {
  position: fixed;
  inset: 0;
  z-index: 60;
}

.avmodal[hidden] {
  display: none;
}

.avmodal__mask {
  position: absolute;
  inset: 0;
  background: rgba(8, 15, 30, 0.55);
}

.avmodal__panel {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(460px, calc(100vw - 32px));
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  background: var(--card);
  border-radius: 12px;
  box-shadow: 0 24px 60px rgba(8, 15, 30, 0.35);
  padding: 20px 24px 24px;
}

.avmodal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}

.avmodal__title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
}

.avmodal__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}

.avmodal__close:hover {
  background: var(--hover);
  color: var(--title);
}

.avmodal__close svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

/* 裁剪舞台：canvas 自带浅灰底与圆外遮罩，容器只负责尺寸与圆角 */
.avmodal__stage {
  position: relative;
  width: 280px;
  margin: 0 auto;
}

.avmodal__stage canvas {
  display: block;
  width: 280px;
  height: 280px;
  border-radius: 8px;
  touch-action: none;
  cursor: grab;
}

.avmodal__empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0 32px;
  font-size: 13px;
  color: var(--muted);
  text-align: center;
}

.avmodal__zoom {
  display: flex;
  align-items: center;
  gap: 12px;
  width: min(340px, 100%);
  margin: 18px auto 0;
}

.avmodal__zoom-mark {
  flex: none;
  min-width: 16px;
  font-size: 15px;
  color: var(--muted);
  text-align: center;
}

.avmodal__zoom input[type='range'] {
  flex: 1;
  accent-color: var(--primary);
}

.avmodal__tools {
  display: flex;
  justify-content: center;
  gap: 28px;
  margin-top: 12px;
}

.avmodal__tool {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 6px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  font-family: inherit;
  font-size: 12.5px;
  cursor: pointer;
}

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

.avmodal__tool svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.avmodal__hint {
  margin: 14px 0 0;
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--muted);
}

.avmodal__links {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  margin: 14px 0 0;
}

.avmodal__links form {
  margin: 0;
}

.avmodal__link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 2px 0;
  border: 0;
  background: transparent;
  color: var(--primary-ink);
  font-family: inherit;
  font-size: 13.5px;
  cursor: pointer;
}

.avmodal__link:hover {
  text-decoration: underline;
}

.avmodal__link--danger {
  color: var(--danger, #b91c1c);
}

.avmodal__link svg {
  width: 17px;
  height: 17px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.avmodal__foot {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 20px;
}

/* 弹窗里的主按钮不用通栏（那是认证页「一页一表单」的规格） */
.avmodal__foot .btn--primary,
.avmodal__foot .btn--ghost {
  width: auto;
  min-width: 76px;
}

/* ≤560px：铺满视口（微软移动端同款），画布自适应缩放 */
@media (max-width: 560px) {
  .avmodal__panel {
    inset: 0;
    left: 0;
    top: 0;
    transform: none;
    width: 100%;
    max-height: none;
    border-radius: 0;
    padding: 16px 16px 24px;
  }

  .avmodal__stage {
    width: min(280px, 100%);
  }

  .avmodal__stage canvas {
    width: 100%;
    height: auto;
    aspect-ratio: 1;
  }
}

.acct-h1 {
  margin: 0 0 4px;
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.acct-sub {
  margin: 0 0 20px;
  font-size: 13px;
  color: var(--muted);
}

/*
 * 面包屑（2026-10-09 三分类重构引入）：侧栏从「六个平铺页签」收敛成
 * 「个人资料 / 安全设置 / 会话管理」三类后，账号概览不再是侧栏里的一项 ——
 * 「我在哪一层、怎么回去」就全靠它补回来。除末级外每一级都是真链接，
 * 末级是纯文本（它指向的就是当前页，做成链接只会让读屏多念一个无效项）。
 */
.acct-crumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0 0 8px;
  font-size: 12px;
  color: var(--muted);
}

.acct-crumb a {
  color: var(--muted);
  text-decoration: none;
}

.acct-crumb a:hover {
  color: var(--primary-ink);
  text-decoration: underline;
}

/* 分隔符用边框色而不是文字色：它是结构，不该和内容抢注意力 */
.acct-crumb__sep {
  color: var(--border-strong);
}

.acct-crumb__now {
  color: var(--text-soft);
}

/*
 * 卡片网格用默认的 stretch 对齐：同一行的卡片等高、边框上下对齐。
 * 之前写的是 align-items: start，内容少的卡（如「当前绑定」的空态）比邻居矮一截，
 * 下方留出一大块空白（2026-10-04 用户反馈）。内容的多少应该只影响卡内留白，
 * 不该影响卡片的框 —— 通栏收尾行（.acct-card--full）解决的是同一件事的另一半。
 */
.acct-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
  gap: 20px;
  margin-top: 20px;
}

/*
 * 全站唯一的「卡片」外观。2026-10-07 起后台首页的统计卡与入口卡也**并进这一份**
 * （它们此前是自己写的一套：没有投影、内边距 14/16 —— 同一个页面里出现两种「卡片」，
 * 是「设计不统一」最直接的观感来源）。差异只留在排版（统计卡竖排数字、入口卡是链接）。
 */
.acct-card,
.adm-stat,
.adm-tile {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px;
}

.acct-card__title {
  margin: 0 0 14px;
  font-size: 15px;
  font-weight: 600;
}

/* 通栏卡片：占满整行，用于「该行只剩一张卡」的收尾行，避免对面留白 */
.acct-card--full {
  grid-column: 1 / -1;
}

/*
 * 卡片在内容区里**上下堆叠**时（安全设置、后台的列表页），彼此留出间隔。
 * 此前没有这条规则，相邻两张卡是紧贴的 —— 两条 1px 边框叠在一起，读起来像一张
 * 被划了几道线的长卡，而不是几个独立分区（2026-10-09 用户反馈「卡片间距」）。
 *
 * 只认**内容区的直接子级**：账号绑定页的卡片住在 .acct-grid 里，那边由 grid 的
 * gap 负责间距，在这里再叠一层 margin-top 会把同一行的第二张卡往下推、边框错开。
 * 20 与 .acct-grid 的 gap 取同一个值，两处的「卡片之间」口径一致。
 */
.acct-main__body > .acct-card + .acct-card,
.adm-main__body > .acct-card + .acct-card {
  margin-top: 20px;
}

.acct-user {
  display: flex;
  align-items: center;
  gap: 16px;
}

.acct-avatar {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  font-size: 20px;
  font-weight: 600;
  /* 有头像时要把它裁成圆 —— 少了这行，方形照片会盖住圆角（四角露在外面） */
  overflow: hidden;
}

.acct-avatar img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.acct-user__name {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 17px;
  font-weight: 600;
}

.acct-user__mail {
  margin-top: 2px;
  font-size: 13px;
  color: var(--muted);
}

.acct-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
}

.acct-badge--ok {
  background: var(--ok-bg);
  color: var(--ok-text); /* emerald-700 */
}

.acct-badge--warn {
  background: var(--warn-bg);
  color: var(--warn-text); /* amber-700 */
}

.acct-meta {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.acct-meta__k {
  font-size: 12px;
  color: var(--muted);
}

.acct-meta__v {
  font-size: 13px;
  overflow-wrap: anywhere;
}

.acct-rows {
  list-style: none;
  margin: 0;
  padding: 0;
}

.acct-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-top: 1px solid var(--border);
}

.acct-row:first-child {
  border-top: 0;
  padding-top: 0;
}

.acct-row__main {
  flex: 1 1 auto;
  min-width: 0;
}

.acct-row__title {
  font-size: 14px;
  font-weight: 500;
}

.acct-row__desc {
  font-size: 12px;
  line-height: 1.6;
  color: var(--muted);
  overflow-wrap: anywhere;
}

.acct-row__state {
  flex: none;
  font-size: 13px;
  color: var(--muted);
}

.acct-row__state--warn {
  color: var(--warn-text);
}

.acct-row__action {
  flex: none;
}

.acct-link {
  flex: none;
  color: var(--primary-ink);
  font-size: 13px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

.acct-link:hover {
  text-decoration: underline;
}

/*
 * 行首图标（安全设置页「一行一事项」用）：图标本身不承载信息，
 * 只是给每行的语义一个可扫的锚点，所以做成一个浅底方块 ——
 * 底色用 --field，与侧栏选中态同一口径（浅色下比 --card 略深，深色下略亮）。
 */
.acct-row__icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background: var(--field);
  color: var(--text-soft);
}

.acct-row__icon svg {
  display: block;
}

/*
 * 破坏性操作的行（注销账号）：标题、图标与动作链接整行走 danger 色，
 * 与同页「启用 / 修改」这类中性操作分开 —— 扫一眼就知道这行点下去不可逆。
 */
.acct-row--danger .acct-row__icon {
  background: var(--danger-bg);
}

.acct-row--danger .acct-row__icon,
.acct-row--danger .acct-row__title,
.acct-row--danger .acct-link {
  color: var(--danger-text);
}

.acct-faq {
  margin: 0;
  padding-left: 18px;
  font-size: 13px;
  line-height: 1.7;
  color: var(--muted);
}

.acct-faq li {
  margin-bottom: 8px;
}

.acct-faq li:last-child {
  margin-bottom: 0;
}

.acct-session {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 0;
  border-top: 1px solid var(--border);
}

.acct-session:first-child {
  border-top: 0;
  padding-top: 0;
}

.acct-session__dot {
  flex: none;
  width: 8px;
  height: 8px;
  margin-top: 7px;
  border-radius: 50%;
  background: var(--border-strong);
}

.acct-session__dot--now {
  background: #10b981;
}

.acct-session__title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 14px;
  font-weight: 500;
}

.acct-session__meta {
  margin-top: 2px;
  font-size: 12px;
  color: var(--muted);
}

.acct-session__action {
  flex: none;
  margin-left: auto;
}

.acct-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 12px;
}

.acct-form-narrow {
  max-width: 420px;
}

/*
 * 账号中心表单的纵向节奏与提交按钮规格（2026-10-04 用户反馈）。
 *
 * 这套页面复用了认证页的 AuthForm（.sso-form__body）与 SubmitButton（.sso-submit），
 * 但认证页那套规格是「一页一表单」的大按钮 —— 通栏、16px 字号、16px 圆角、带投影。
 * 放进卡片后比例失衡：整卡宽的大蓝块紧贴输入框，聚焦环都被盖住。
 * 这里收回与 .btn 一致的规格；间隔统一交给 gap —— 绑定页用的 .field 与 .acct-label
 * 此前根本没有样式定义，label 是贴着控件的（后台表单 .adm-form 靠自己的 gap，不在此列）。
 */
.acct-card .sso-form__body {
  gap: 16px;
}

/* .sso-field 自带的 18px 下边距换成上面的 gap，两处只留一个间距来源 */
.acct-card .sso-form__body .sso-field {
  margin-bottom: 0;
}

.acct-card .field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.acct-card .sso-submit {
  width: auto;
  align-self: flex-start;
  height: 40px;
  padding: 0 20px;
  border-radius: 8px;
  font-size: 14px;
  letter-spacing: 0;
  box-shadow: none;
}

/*
 * 账号中心的独立输入控件（input / select / textarea 通吃）。
 *
 * 为什么不是复用 ".sso-input"：那是登录页的**包装器**样式——它假定结构是
 * ".sso-input > .sso-input__slot + .sso-input__field"，靠 ":focus-within" 在外层
 * 画聚焦环。直接把 "sso-input" 类贴在原生 select / input 上，得到的是
 * 一个没有内边距高度、聚焦环失效的「透明框」（绑定页曾经就是这样）。
 * 账号中心的表单是裸控件，所以给一套自成一体、直接贴在控件上的样式。
 */
.acct-input {
  width: 100%;
  box-sizing: border-box;
  padding: 10px 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--card);
  color: var(--title);
  font-family: inherit;
  font-size: 14px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.acct-input:focus {
  outline: none;
  border-color: var(--primary-ink);
  box-shadow: 0 0 0 3px rgba(16, 44, 120, 0.12);
}

.acct-input::placeholder {
  color: var(--icon);
}

/* 文件选择框：原生控件太素（裸的「选择文件」按钮），只够用的定制点是伪元素 */
.acct-file {
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  border: 1px dashed var(--border-strong);
  border-radius: 10px;
  background: var(--card);
  color: var(--muted);
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
}

.acct-file::file-selector-button {
  margin-right: 10px;
  padding: 7px 14px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: var(--card);
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.acct-file::file-selector-button:hover {
  background: var(--hover);
}

.acct-note {
  margin: 14px 0 0;
  font-size: 12px;
  line-height: 1.7;
  color: var(--muted);
}

.acct-note--inline {
  margin: 0;
}

/*
 * 页脚长在 .acct-main 里（宽屏跟着内容区滚、窄屏就是普通页面末尾）。
 * 限宽与居中和 .acct-main__body 对齐 —— 它们是上下相邻的两层，
 * 口径不一致时页脚会相对内容左右错开。
 *
 * margin-top 是「与内容之间的最小间隔」：内容长时页脚在末尾（隔 32px），
 * 内容短时被 .acct-main__body 的 flex:1 推到底部（间隔更大）。
 * flex: none 让它不被压缩 —— 早前有过「退出」按钮被压成两行的先例，同一类问题。
 */
.acct-foot,
.adm-foot {
  flex: none;
  width: 100%;
  max-width: 1080px;
  margin: 32px auto 0;
  padding: 0 0 8px;
  font-size: 12px;
  color: var(--muted);
  text-align: center;
}

@media (max-width: 860px) {
  .acct-grid {
    grid-template-columns: 1fr;
  }

  .acct-meta {
    grid-template-columns: 1fr 1fr;
  }
}

@media (max-width: 560px) {
  /*
   * 这里曾经把顶栏改成换行、并把导航挪到第二行。768px 以下顶栏已切成三段式
   * （导航进汉堡面板，见文末），那套换行规则与它直接冲突，已删除。
   * 这一段现在只管内容区。
   */
  .acct-meta {
    grid-template-columns: 1fr;
  }

  .acct-main {
    padding: 16px 16px 8px;
  }

  .acct-session {
    flex-wrap: wrap;
  }

  .acct-session__action {
    margin-left: 20px;
  }
}

a {
  color: var(--text);
  font-weight: 500;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* ---------- 同意页 ---------- */

.client {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}

.client__icon {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 11px;
  background: var(--field);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  font-weight: 600;
  color: var(--text-soft);
  overflow: hidden;
}

.client__icon img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.client__meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.client__title {
  margin: 0;
  font-size: 17px;
  line-height: 1.4;
}

.client__host {
  font-size: 12.5px;
  color: var(--muted);
}

.scopes {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}

.scope {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 12px 14px;
}

.scope + .scope {
  border-top: 1px solid var(--border);
}

.scope__check {
  flex: none;
  margin-top: 1px;
  color: var(--text-soft);
}

.scope__title,
.scope__desc {
  display: block;
}

.scope__title {
  font-size: 13.5px;
  font-weight: 500;
}

.scope__desc {
  font-size: 12.5px;
  color: var(--muted);
}

.consent__actions {
  display: flex;
  gap: 10px;
}

.consent__actions form {
  display: flex;
  margin: 0;
}

.consent__actions form:first-child {
  flex: 0 0 auto;
}

.consent__actions form:last-child {
  flex: 1 1 auto;
}

.consent__actions .btn {
  width: 100%;
}

.signed-in-as {
  margin: 18px 0 0;
  font-size: 12.5px;
  color: var(--muted);
  text-align: center;
}

/* ---------- 页脚 ---------- */

.page__footer {
  font-size: 12px;
  color: var(--muted);
}

/*
 * 法务链接（《服务条款》/《隐私政策》）。
 * 三处页脚共用一套：认证页卡片底部（.sso-legal）、提示页页脚（.page__footer）、
 * 账号中心页脚（.acct-foot）。颜色**继承容器色**，保证它在深浅色与三种底色上
 * 都不会跳出既定色板；悬停才给品牌色。
 *
 * 下划线是**悬停/键盘聚焦时才出现**（2026-10-04 用户反馈：页脚是静态说明区，
 * 常驻下划线让两个链接看起来像正文里的强调，盖过了同一行里的品牌署名）。
 * 保留 :focus-visible 是为了键盘用户 —— 只写 :hover 的话，Tab 过去什么也看不到，
 * 而这正是"不靠颜色表达可点"那部分价值的唯一残余。
 */
.legal__link {
  color: inherit;
  text-decoration: none;
  text-underline-offset: 2px;
}

.legal__link:hover,
.legal__link:focus-visible {
  color: var(--primary-ink);
  text-decoration: underline;
}

/* ---------- 窄屏：卡片撑满宽度，仅保留页面内边距 ---------- */

@media (max-width: 480px) {
  .page {
    gap: 16px;
    padding: 24px 16px;
  }

  .card,
  .card--wide {
    max-width: none;
    padding: 24px 20px;
  }

  .card__title {
    font-size: 18px;
  }
}

/* 中性提示（如「功能尚未开放」）：与红色错误条区分开，避免把「未开通」演成「你填错了」 */
.alert--info {
  border-color: var(--info-border);
  background: var(--info-bg);
  color: var(--info-text);
}

/* ==================================================================
   toast（瞬时提示）
   移植自 CCU-MC：去掉 Tailwind 改为语义 class，三态沿用原设计的实色
   （success=emerald-600 / error=rose-600 / info=slate-800），不跟随主题变量。
   位置：顶部居中（前台约定）。z-index 120 —— 本项目目前没有弹窗/抽屉/菜单，无需再往上抬；
   将来若要加模态，需保证 toast 高于它，或接受「模态打开时 toast 被盖住」这个取舍，全站统一即可。
   ================================================================== */

.toast-root {
  position: fixed;
  left: 0;
  right: 0;
  top: 1rem;
  z-index: 120;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  padding: 0 1rem;
  /* 容器整体不接收点击，避免遮挡页面；单条 toast 自己恢复 pointer-events */
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  max-width: 100%;
  padding: 0.625rem 1rem;
  border-radius: 0.5rem;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.4;
  color: #fff;
  box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity 0.2s ease, transform 0.2s ease;
  pointer-events: auto;
}

.toast.is-in {
  opacity: 1;
  transform: none;
}

.toast--success {
  background: #059669; /* emerald-600 */
}

.toast--error {
  background: #e11d48; /* rose-600 */
}

.toast--info {
  background: #1e293b; /* slate-800 */
}

.toast__icon {
  flex: none;
  width: 16px;
  height: 16px;
}

.toast__msg {
  overflow-wrap: anywhere;
}

/* ==================================================================
   登录页（卡片式分栏）—— 与其余三页的 AuthShell 是两套外观，互不影响。
   结构：整页浅灰底 → 居中一张大圆角卡片（左深色渐变品牌区 / 右白色表单区）。
   窄屏（<=800px）隐藏品牌区，只留表单卡片。
   颜色：交互色一律用 var(--primary)，它等于图标底色 #102C78；
   悬停用 var(--primary-hover)（#0b2059）。品牌区与按钮的深色沿用设计稿的
   #0b1e33 / #12325c（渐变两端）。
   ================================================================== */

body.sso-body {
  background: var(--bg-soft);
  /* 只用系统字体栈：本页不加载任何 Web 字体（设计稿里的 Inter 已弃用） */
  font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
    'PingFang SC', 'Microsoft YaHei', sans-serif;
}

/* 均匀留白：卡片靠 auto margin 居中，卡片高于视口时自动退化为顶部对齐 */
.sso-page {
  display: flex;
  min-height: 100vh;
  min-height: 100dvh;
  padding: 24px;
}

.sso-card {
  margin: auto;
  width: 100%;
  max-width: 1200px;
  min-height: 640px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  overflow: hidden;
  background: var(--card);
  border-radius: 40px;
  box-shadow:
    0 30px 60px -20px rgba(0, 20, 40, 0.25),
    0 8px 20px -8px rgba(0, 20, 40, 0.15);
}

/* ---------- 图标 ---------- */

/* 线性图标（Lucide）：描边取当前色、不填充 */
.sso-icon {
  width: 20px;
  height: 20px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* 实心图标（互锁六边形 / 微软 / GitHub 品牌 mark） */
.sso-icon--solid {
  fill: currentColor;
  stroke: none;
}

/* ---------- 左：品牌区（深色渐变） ---------- */

.sso-brand {
  position: relative;
  /* 让 ::before / ::after 的 z-index:-1 只在本区块内生效 */
  isolation: isolate;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 32px;
  padding: 48px 40px;
  background: linear-gradient(145deg, #0b1e33 0%, #12325c 100%);
  color: #fff;
}

/* 两处装饰光斑 */
.sso-brand::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(circle at 20% 30%, rgba(0, 180, 255, 0.25) 0%, transparent 45%),
    radial-gradient(circle at 90% 70%, rgba(100, 210, 255, 0.18) 0%, transparent 50%);
}

/* 40px 细网格（透明度 0.03） */
.sso-brand::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
  background-size: 40px 40px;
}

.sso-brand__head {
  display: flex;
  align-items: center;
  gap: 12px;
}

/*
 * 品牌 logo：直接用我们自己的品牌 SVG（public/favicon.svg，与
 * assets/cikio-authserver.svg 是同一份）。它自带 #102C78 深色底板 + 白色互锁六边形，
 * 在深色品牌区里靠圆角把底板读成一块 logo 方牌；
 * 颜色不用 CSS 管 —— img 里的图形颜色改不了，也不该改。
 *
 * 尺寸 = 旁边文字组合的整体高度：
 *   词标 24px × 1.15 行高 ≈ 27.6 + 小字 12px × 1.15 ≈ 13.8 + 2px 间距 ≈ 43.4 → 取 44px。
 */
.sso-brand__mark {
  display: block;
  width: 44px;
  height: 44px;
  border-radius: 11px;
  /*
   * 品牌 SVG 自带 #102C78 深色底板，而品牌区本身就是深蓝渐变，
   * 两者色差很小、方牌边界会糊掉。加一道 1px 半透明亮边把它「框」出来
   * （box-shadow 而不是 border：不占布局、不影响 44px 的尺寸）。
   */
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.16);
}

/* 词标 + 正式全称（全称是第二行小字，所以两者需要一列） */
.sso-brand__title {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}

.sso-brand__name {
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -0.02em;
}

/* 正式全称：不抢词标，只在它下面点一句 */
.sso-brand__sub {
  margin-top: 2px;
  font-size: 12px;
  letter-spacing: 0.02em;
  opacity: 0.72;
}

.sso-brand__main {
  display: flex;
  flex-direction: column;
}

/* 品牌区大标题（h1）。⚠️ 词标小列用的是另一个类 .sso-brand__title —— 
 * 曾经两类同名，这条的 margin/line-height 会漏到词标上，把它的盒子撑高 20px，
 * 图标就再也无法和文字对齐；拆开后各管各的。 */
.sso-brand__headline {
  margin: 0 0 20px;
  font-size: 42px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.03em;
}

/* 渐变文字：背景渐变裁到文字上 */
.sso-brand__hl {
  background-image: linear-gradient(to right, #9ad0ff, #c3e2ff);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.sso-brand__text {
  margin: 0;
  max-width: 90%;
  font-size: 17px;
  line-height: 1.6;
  color: #b6d0e8;
}

.sso-brand__foot {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  font-size: 14px;
  color: #9bb5d0;
}

.sso-brand__shield {
  color: #7bc9ff;
}

/* ---------- 右：表单区 ---------- */

.sso-form {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 48px 40px;
  background: var(--card);
}

.sso-form__head {
  margin-bottom: 32px;
}

.sso-form__title {
  margin: 0 0 8px;
  font-size: 32px;
  font-weight: 600;
  letter-spacing: -0.03em;
  color: var(--title);
}

.sso-form__sub {
  margin: 0;
  font-size: 16px;
  color: var(--sub);
}

/* 表单级错误紧贴副标题下方 */
.sso-form__head .alert {
  margin: 16px 0 0;
  border-radius: 12px;
}

.sso-form__body {
  display: flex;
  flex-direction: column;
  margin: 0;
}

/* ---------- 字段 ---------- */

.sso-field {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 18px;
}

.sso-field__label {
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--label);
}

.sso-field__error {
  margin: 0;
  font-size: 13px;
  color: var(--danger-text);
}

/* 字段说明（如「至少 8 个字符」）：常驻，不像错误那样只在出错时出现 */
.sso-field__hint {
  font-size: 13px;
  color: var(--hint);
}

/* 灰底无边框输入框：图标 + 输入 + 可选眼睛 */
.sso-input {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  border: 1.5px solid transparent;
  border-radius: 16px;
  background: var(--field);
  transition: background-color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.sso-input:focus-within {
  background: var(--field-focus);
  border-color: var(--primary-ink);
  box-shadow: 0 0 0 4px rgba(16, 44, 120, 0.15);
}

.sso-input__slot {
  display: flex;
  flex: none;
  color: var(--icon);
  transition: color 0.2s ease;
}

.sso-input:focus-within .sso-input__slot {
  color: var(--primary-ink);
}

.sso-input__field {
  flex: 1 1 auto;
  min-width: 0;
  padding: 15px 0;
  border: 0;
  background: none;
  outline: none;
  color: var(--title);
  font-family: inherit;
  font-size: 16px;
}

.sso-input__eye {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--icon);
  cursor: pointer;
  transition: color 0.2s ease;
}

.sso-input__eye:hover {
  color: var(--primary-ink);
}

.sso-input__eye:focus-visible {
  outline: 2px solid var(--primary-ink);
  outline-offset: 1px;
}

/* 文字按钮（注册第二步的「重新发送验证码」） */
.sso-text-btn {
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  color: var(--primary-ink);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
}

.sso-text-btn:hover {
  text-decoration: underline;
}

.sso-text-btn[disabled] {
  color: var(--hint);
  cursor: default;
  text-decoration: none;
}

/* 注册第二步：「没收到？重新发送验证码」 */
.sso-resend {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 18px;
  font-size: 14px;
  color: var(--hint);
}

.sso-resend__form {
  margin: 0;
}

/* ---------- 记住我 / 忘记密码 ---------- */

.sso-options {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 4px 0 22px;
}

.sso-checkbox {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  color: var(--body-text);
  cursor: pointer;
}

.sso-checkbox input {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--primary-ink);
  cursor: pointer;
}

.sso-link {
  color: var(--primary-ink);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
}

.sso-link:hover {
  text-decoration: underline;
}

/*
 * 认证页底部的法务入口。放在卡片最底、四个认证页统一出现：
 * 它是"随时查得到条款"的兜底位，不是同意声明 —— 同意的表达由注册页的勾选框承担。
 */
.sso-legal {
  margin: 14px 0 0;
  text-align: center;
  font-size: 12.5px;
  color: var(--muted);
}

/* 注册页的同意勾选框（复用「记住我」的 .sso-checkbox，只调对齐与字号） */
.sso-consent {
  margin: 2px 0 20px;
}

/*
 * 文案会折成两行（窄屏尤其明显），所以不能沿用 center 对齐：
 * 顶端对齐能让勾选框与第一行文字齐平，折行时不会浮在两行中间。
 */
.sso-checkbox--legal {
  align-items: flex-start;
  font-size: 13.5px;
  line-height: 1.7;
}

.sso-checkbox--legal input {
  width: 16px;
  height: 16px;
  margin-top: 3px;
}

.sso-consent .sso-field__error {
  margin-top: 6px;
}

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

.sso-submit {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 16px 24px;
  border: 0;
  border-radius: 16px;
  background: var(--primary);
  color: #fff;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  cursor: pointer;
  box-shadow: 0 4px 8px -2px rgba(16, 44, 120, 0.25);
  /* 悬浮只变色：位移会让人误以为按钮「可拖拽/未对齐」，而且大按钮上浮显得躁 */
  transition: background-color 0.2s ease, box-shadow 0.2s ease;
}

.sso-submit:hover {
  background: var(--primary-hover);
}

.sso-submit:focus-visible {
  outline: 2px solid var(--primary-ink);
  outline-offset: 2px;
}

/* 提交中（脚本置灰）：不吃 hover */
.sso-submit[disabled] {
  opacity: 0.7;
  cursor: default;
}

/* ---------- 分隔线与第三方 ---------- */

.sso-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 28px 0;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--hint);
}

.sso-divider::before,
.sso-divider::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--divider);
}

.sso-social {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin-bottom: 28px;
}

.sso-social__btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 10px;
  border: 1.5px solid var(--divider);
  border-radius: 14px;
  background: var(--card);
  color: var(--social-text);
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}

.sso-social__btn:hover {
  background: var(--hover);
  border-color: var(--border-hover);
}

.sso-social__btn .sso-icon {
  width: 18px;
  height: 18px;
  color: var(--social-icon);
}

/* 尚未接入：保持可见但不可点 */
.sso-social__btn[aria-disabled='true'] {
  cursor: default;
}

/*
 * 微软登录按钮是 <button>（原生表单提交），不是 <a>：外层 form 需要撑满网格单元，
 * 按钮再撑满 form。font-family 必须显式 inherit —— 表单控件默认不继承字体，
 * 少了它按钮文案会变成浏览器默认的衬线体，与旁边的 GitHub 占位按钮明显不一致。
 */
.sso-social__form {
  display: flex;
}

.sso-social__form .sso-social__btn {
  flex: 1 1 auto;
  font-family: inherit;
  cursor: pointer;
}

.sso-signup {
  margin: 0;
  text-align: center;
  font-size: 15px;
  color: var(--link-soft);
}

/*
 * 底部链接紧跟在表单后面时（注册 / 忘记密码 / 重置）需要留白，
 * 否则会贴着提交按钮。登录页的底部链接前面是社交按钮（自带 28px 下边距），
 * 所以用相邻兄弟选择器而不是无条件 margin，避免那页多出一截。
 */
.sso-form__body + .sso-signup {
  margin-top: 22px;
}

/* ---------- 窄屏：单列，只留表单 ---------- */

@media (max-width: 800px) {
  .sso-page {
    padding: 16px;
  }

  .sso-card {
    grid-template-columns: 1fr;
    min-height: 0;
    border-radius: 32px;
  }

  /* 品牌区整块隐藏 */
  .sso-brand {
    display: none;
  }

  .sso-form {
    padding: 32px 24px;
  }

  .sso-form__title {
    font-size: 28px;
  }
}

@media (max-width: 480px) {
  .sso-page {
    padding: 12px;
  }

  .sso-card {
    border-radius: 28px;
  }

  .sso-form {
    padding: 28px 20px;
  }

  .sso-social {
    grid-template-columns: 1fr;
  }

  .sso-options {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
}

/* ==================================================================
   管理后台（/admin/*，见 src/pages/admin-*.tsx）

   2026-10-07 起与账号中心**共用同一套外壳**（用户要求「先把后台统一成账号中心
   的整体设计，再逐个改子页面」）：骨架、侧栏容器、品牌区、底部账户卡、外观分段、
   内容区、页脚、顶栏、窄屏断点全部是上面那些成对选择器里的一份。
   这里只放后台特有的东西 —— 侧栏内部的分组/图标/角标、表格、
   面包屑（宽屏顶栏取消后它落在内容区顶部），以及那些页面级零件。
   ================================================================== */

.adm-body {
  background: var(--bg);
}

/* ---------- 管理后台的侧栏内部（账号中心没有这几条） ----------
 *
 * 容器、品牌区、底部账户卡、内容区、顶栏、页脚**全部与账号中心共用一份规则**
 * （见 .acct-side, .adm-side 那一组，2026-10-07 用户要求两个界面统一）。
 * 这里只留后台比账号中心深的那一层信息架构：分组 + 图标 + 待处理角标。
 */

/* 分组之间留出章节感；组内间距靠 item 自己的 padding 形成密度 */
.adm-side__group + .adm-side__group {
  margin-top: 10px;
}

/* 分组标题：小号大写字母间距拉开的「章节名」，与导航项形成两级层次 */
.adm-side__title {
  padding: 0 8px 4px;
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
}

.adm-side__block {
  display: flex;
  flex-direction: column;
}

/*
 * 「链接 + 展开箭头」并排的一行。箭头只能是 <a> 的**兄弟**（按钮嵌在链接里是非法
 * 结构），所以外层多这一层 flex 容器把两者放在同一条水平线上。
 * 只有带二级项的条目才需要它 —— 没有子项的条目直接渲染裸链接，右缘与箭头位对齐留白。
 */
.adm-side__row {
  display: flex;
  align-items: center;
  min-width: 0;
}

.adm-side__row .adm-side__item {
  flex: 1 1 auto;
  min-width: 0;
}

/*
 * 二级菜单的展开/收起箭头。做成独立按钮而不是「整行点击展开」：
 * 整行是链接（点它要跳页），展开是另一件事，抢同一个点击区必然有一方不好用。
 * 无 JS 时这颗按钮不会做任何事 —— 但侧栏高亮所在分组仍由服务端展开（is-open），
 * 所以「看不见自己在哪一支」这个核心问题不依赖脚本。
 */
.adm-side__caret {
  display: grid;
  flex: none;
  place-items: center;
  width: 26px;
  height: 26px;
  margin-right: 4px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--muted);
  cursor: pointer;
}

.adm-side__caret:hover {
  background: var(--field);
  color: var(--text);
}

.adm-side__caret svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.18s ease;
}

.adm-side__block.is-open .adm-side__caret svg {
  transform: rotate(180deg);
}

/*
 * 占位箭头位：同一分组里「没有二级项」的条目用它把右端对齐。
 * 尺寸与 .adm-side__caret 完全一致（含 margin-right），差一像素角标就会错位。
 */
.adm-side__caret-slot {
  flex: none;
  width: 26px;
  height: 26px;
  margin-right: 4px;
}

/* 左内边距 14px 与品牌区一致 —— 图标与「CIKIO 管理后台」的图形落在同一条竖线上 */
.adm-side__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border-radius: 8px;
  color: var(--text);
  font-size: 14px;
  text-decoration: none;
}
/* 悬停 / 当前项的底色由共用规则给（见 .acct-side__item:hover 与 .is-active） */

.adm-side__icon {
  display: flex;
  flex: none;
}

.adm-side__icon svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.adm-side__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 待处理角标：后台里最实用的一处信息（两个参考项目的侧栏都有） */
.adm-side__badge {
  flex: none;
  min-width: 20px;
  margin-left: auto;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--danger-bg);
  color: var(--danger-text);
  font-size: 11px;
  font-weight: 600;
  text-align: center;
}

/*
 * 二级项：只跟随**当前项**展开（无 JS）。收起态用 display:none 而不是位移 ——
 * 侧栏是常态滚动区，隐藏项不该占据滚动高度或能被 Tab 到。
 */
.adm-side__sub {
  display: none;
  flex-direction: column;
  margin: 1px 0 3px 19px;
  padding-left: 11px;
  border-left: 1px solid var(--border);
}

.adm-side__block.is-open .adm-side__sub {
  display: flex;
}

.adm-side__subitem {
  padding: 5px 8px;
  border-radius: 6px;
  color: var(--muted);
  font-size: 13px;
  text-decoration: none;
}

/* 悬停底色用 --field：侧栏是白底容器，--hover 在白底上看不出来（与一级项同一口径） */
.adm-side__subitem:hover {
  background: var(--field);
  color: var(--text);
  text-decoration: none;
}

.adm-side__subitem.is-active {
  color: var(--primary-ink);
  font-weight: 600;
}

/*
 * 顶栏。只在窄屏出现（宽屏由 861 断点藏掉，与账号中心一致），
 * 配色取品牌蓝 —— 早前后台是深蓝近黑（刻意与账号中心区分），2026-10-07 用户要求
 * 两个界面统一，这层区分改由顶栏站名「CIKIO 管理后台」承担。
 * 侧栏底部的账户卡 / 外观分段 / 抽屉开关全部与账号中心共用一份规则。
 */
.adm-top {
  background: var(--primary);
  color: #fff;
}

/*
 * 面包屑（内容区顶部、页面 h1 之上）。
 * 2026-10-07 从顶栏搬进来：宽屏不再有顶栏，子页面的「我在第几层、怎么回去」
 * 只能由它承担。配色随内容区（--muted / --primary-ink），不再是顶栏那套白字。
 * 概览页不传面包屑时它整块不渲染（见 admin-nav.tsx 的 AdminBreadcrumb）。
 */
.adm-crumb {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  margin: 0 0 8px;
  font-size: 13px;
}

.adm-crumb__link {
  color: var(--primary-ink);
  text-decoration: none;
}

.adm-crumb__link:hover {
  text-decoration: underline;
}

.adm-crumb__sep {
  color: var(--muted);
}

.adm-crumb__current {
  overflow: hidden;
  color: var(--muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 注：.adm-me / .adm-me__out 与账号中心共用一份（见 .acct-me, .adm-me）；
   .adm-me__email 随「顶栏身份信息下移到侧栏账户卡」一并废弃 —— 邮箱在账户卡里。 */

/* 抽屉遮罩：常驻 DOM，显隐只切 class（与账号中心的面板同一约定） */
.adm-mask {
  position: fixed;
  inset: 0;
  z-index: 10;
  background: rgba(8, 15, 30, 0.5);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.18s ease, visibility 0.18s;
}

.adm-mask--open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

/* 注：.adm-main / .adm-main__body / .adm-foot 与账号中心共用一份规则
   （见 .acct-main, .adm-main 那一组），这里不再重复声明。 */

/*
 * ≤860px：侧栏变左侧抽屉 —— 与账号中心**同一个断点**（2026-10-07 统一前是 1024）。
 * 后台的导航是常驻的，窄屏只是把它**收起来**（不是换成另一种导航），
 * 所以抽屉里就是那张完整的侧栏：品牌 + 分组导航 + 账户卡 + 外观分段。
 * 861–1024 这段现在显示常驻侧栏，表格靠 .adm-table-wrap 的横向滚动兜住。
 */
@media (max-width: 860px) {
  .adm-side {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 40;
    width: 268px;
    height: auto;
    /* 抽屉贴着视口边：去掉容器形态的圆角与四周边框，只留右侧分隔线 */
    border: 0;
    border-right: 1px solid var(--border);
    border-radius: 0;
    background: var(--card);
    transform: translateX(-100%);
    transition: transform 0.25s ease;
  }

  .adm-side--open {
    transform: translateX(0);
  }

  /*
   * ⚠️ 必须带 body.adm-body 作用域：汉堡的基础规则（.nav-burger, .adm-burger
   * { display: none }）在本文件**靠后**的位置，同特异度下会盖掉这里 ——
   * 账号中心那条也是这么写的（body.acct-body .nav-burger）。
   */
  body.adm-body .adm-burger {
    display: inline-flex;
  }
  /* 顶栏内边距与「四项」布局的窄屏口径与账号中心共用一份（见文件末尾的 860 块） */
}

/*
 * 页内的「窄栏」宽度**统一 520px**（搜索条 / 封禁表单 / 词条表单三处此前分别是
 * 440 / 480 / 520，用户看到的是「每页内容宽度都不一样」）。
 * 这个值的意思是「输入类控件不横跨整条内容区」，不是页面容器宽度 ——
 * 页面容器（.adm-main）与账号中心共用 1080。
 */
.adm-search {
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 520px;
  margin: 0 0 16px;
}

.adm-search input {
  flex: 1 1 auto;
  height: 38px;
  padding: 0 12px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: var(--card);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
}

.adm-search input:focus {
  outline: 2px solid rgba(16, 44, 120, 0.35);
  border-color: var(--primary-ink);
}

/* 审计页的动作下拉：与输入框同一套框线，不然浏览器默认样式和旁边格格不入 */
.adm-search select {
  flex: 0 1 auto;
  height: 38px;
  padding: 0 30px 0 10px;
}

/*
 * 绑定码展示块（/account/links）。
 * 这是**全站唯一一处只显示一次的敏感串**（库里只有哈希），所以要给足视觉分量：
 * 等宽大字 + 浅底 + 虚线边框，和邮箱验证码邮件的样式同一语汇。
 */
.link-code {
  margin: 16px 0 20px;
  padding: 16px 18px;
  border: 1px dashed var(--primary-ink);
  border-radius: 12px;
  background: var(--code-bg, rgba(16, 44, 120, 0.06));
  text-align: center;
}

.link-code__label {
  font-size: 12.5px;
  color: var(--muted);
}

.link-code__value {
  margin: 8px 0 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: 3px;
  color: var(--primary-ink);
  word-break: break-all;
}

.link-code__hint {
  font-size: 12.5px;
  color: var(--muted);
}

/* 注销申请页用到的小零件 */
.adm-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  color: var(--muted);
  word-break: break-all;
}

.adm-link {
  color: var(--primary-ink);
}

.adm-link:hover {
  text-decoration: underline;
}

/* 表格：行高与分隔线都取认证页的密度，不加斑马纹（列多时反而乱） */
/*
 * 表格容器：**常驻**横向滚动（不是只在窄屏）。
 * 侧栏收进抽屉的断点从 1024 收到 860 之后，861–1024 这一段的常驻侧栏 + 内容区
 * 比从前更挤，没有这条时一张宽表就能把整页顶宽、连带把侧栏挤出屏幕
 * （.adm-main 的 min-width:0 挡不住表格自身的固有宽度）。
 * 更窄的屏（≤560）走「一条记录一张卡片」，那时再改回 visible（见那条断点）。
 */
.adm-table-wrap {
  overflow-x: auto;
}

.adm-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.adm-table th {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  color: var(--muted);
  font-weight: 500;
  text-align: left;
  white-space: nowrap;
}

.adm-table td {
  padding: 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  overflow-wrap: anywhere;
}

.adm-table tr:last-child td {
  border-bottom: 0;
}

.adm-cell-strong {
  font-weight: 500;
}

/* 表格主列里的副行（如审核表的「昵称 + 邮箱」）：小一号、与主行贴紧 */
.adm-cell-strong .acct-row__desc {
  margin-top: 2px;
  font-size: 12px;
}

/* 行内主按钮不收窄（.btn--primary 全局是通栏，放在表格行里会撑满整格） */
.adm-rowform .btn--primary {
  width: auto;
}

/*
 * 审核缩略图：44px 圆形，点开是新标签里的原图。
 * 审核要看细节，而缩略图只负责「这条是谁的、大概什么样」。
 */
.adm-thumb {
  display: block;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--field);
}

.adm-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/*
 * 行内「驳回」：默认只露一个按钮，点开才出现原因输入 ——
 * 一页 20 条待审件不该变成 20 个常驻输入框（也免得「原因」被误当成必填）。
 */
.adm-reject summary {
  cursor: pointer;
  list-style: none;
}

.adm-reject summary::-webkit-details-marker {
  display: none;
}

.adm-reject__form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
}

.adm-reject__input {
  width: 220px;
  height: 32px;
  padding: 0 8px;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--card);
  color: var(--text);
  font-family: inherit;
  font-size: 12px;
}

.adm-reject__input:focus {
  outline: 2px solid rgba(16, 44, 120, 0.35);
  border-color: var(--primary-ink);
}

.acct-badge--danger {
  background: var(--danger-bg);
  color: var(--danger-text);
}

.adm-empty {
  padding: 24px 12px;
  color: var(--muted);
  text-align: center;
}

.adm-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.adm-pager__links {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* 注：原先这里有一条 ≤720px 的 .adm-main 内边距规则、一条隐藏顶栏邮箱的规则、
   以及「≤720 才让表格横向滚动」——2026-10-07 统一外壳后：内容区的内边距由共用规则给、
   顶栏邮箱已废弃、表格横向滚动改成**常驻**（见 .adm-table-wrap 的基础规则：
   侧栏断点从 1024 收到 860 后，861–1024 这段内容区比从前窄，不能等到 720 才允许横滚）。 */

/*
 * 极窄屏（<=560px）：表格改「一条记录一张卡片」。
 *
 * 为什么不再横向滚动：列多时用户根本不知道右边还有内容（邮箱、理由这类长字段
 * 还会被截成半截），横滑在手机上又容易误触翻页。改成卡片后字段全部保留、
 * 长文本自动折行，代价只是纵向变长 —— 列表一屏 3～5 条，可以接受。
 * 依赖每个 <td> 上的 data-label：表头隐藏后由它显示字段名。
 */
@media (max-width: 560px) {
  .adm-table thead {
    display: none;
  }

  .adm-table,
  .adm-table tbody,
  .adm-table tr,
  .adm-table td {
    display: block;
    width: 100%;
  }

  .adm-table tr {
    margin-bottom: 10px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
  }

  .adm-table td {
    padding: 4px 0;
    border-bottom: 0;
  }

  /* 只有带 data-label 的单元格才画字段名（空态那格没有，别给它一个光秃秃的冒号） */
  .adm-table td[data-label]::before {
    content: attr(data-label) '：';
    display: inline-block;
    min-width: 72px;
    color: var(--muted);
    font-size: 12px;
  }

  .adm-table tr:last-child td {
    border-bottom: 0;
  }

  .adm-table-wrap {
    overflow-x: visible;
  }

  /* 筛选栏与分页：窄屏换行，别把控件压成竖排一长条 */
  .adm-search {
    flex-wrap: wrap;
    max-width: none;
  }

  .adm-search select,
  .adm-search input {
    flex: 1 1 140px;
  }

  .adm-pager {
    flex-wrap: wrap;
    gap: 8px;
  }
}

/* 详情页窄屏：标签改到值上方，长串（邮箱 / 账号 ID）才不会被挤到溢出 */
@media (max-width: 560px) {
  .adm-cards {
    gap: 14px;
  }

  .adm-detail {
    gap: 12px;
  }

  .adm-detail__row {
    flex-direction: column;
    gap: 2px;
  }

  .adm-detail__k {
    width: auto;
    font-size: 12px;
  }

  .adm-detail__v,
  .adm-copyable {
    gap: 6px;
  }
}

/* ==================================================================
   三段式顶栏的窄屏形态（账号中心与管理后台共用同一套结构）

   窄屏（<=768px）顶栏只放三样：左汉堡 / 中站名 / 右主题切换；
   导航、邮箱、退出都移进汉堡展开的全宽面板。桌面端（>=769px）不变：
   品牌居左、导航可见、右侧是主题 + 邮箱 + 退出。断点取 768px，
   与参考实现（message 站）和 CCU 站保持同一口径。

   为什么导航在 DOM 里渲染了两份（顶栏一份、面板一份）：
   服务端渲染下没法用 CSS 把一个元素搬进另一个容器，而用 JS 搬运会让
   无 JS 时的窄屏彻底没有导航。两份的成本只是几十字节 HTML，换来的
   是「面板里的导航在任何情况下都在正确的位置」。
   ================================================================== */

/* 面板与汉堡的定位基准。顶栏本身是深色，面板用的是页面底色。
   z-index 要盖过 .nav-mask（30）：遮罩只压下方页面，不压顶栏自己。 */
.acct-top,
.adm-top {
  position: relative;
  z-index: 40;
}

/* 汉堡：只在窄屏出现（见文末断点）。颜色跟所在顶栏走 —— 两套顶栏都是深底白字。
   账号中心的 NavBurger 与后台的 SideDrawerButton 是同一个按钮的两种数据绑定
   （前者开全宽面板、后者开左侧抽屉），外观共用这一份。 */
.nav-burger,
.adm-burger {
  display: none;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 9px;
  background: transparent;
  color: #fff;
  cursor: pointer;
}

.nav-burger:hover {
  background: rgba(255, 255, 255, 0.14);
}

.nav-burger svg {
  display: block;
  width: 18px;
  height: 18px;
  /* 描边在这里统一给（与 .theme-toggle__icon svg 同一约定）。漏了它，
     MenuIcon 的三条直线是「默认黑色填充的开放路径」—— 零面积，整根图标隐形。 */
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/*
 * 窄屏汉堡展开的**全宽面板**：贴着顶栏下沿、占满整行宽，从左边缘整块滑入。
 * 这是 message 站（.mc-menu-panel / .mc-menu-closed）与 CCU（#header-menu）同款形态
 * —— 不是 300px 的侧边抽屉：抽屉版右上角会留一块圆角 + 右侧描边，观感是「浮着的
 * 一张卡」，而 message 是「从顶栏垂下来的一片」。
 *
 * 收起态不能只用 translateX(-100%)：box-shadow 会向外延伸（向下约 12px、向两侧也有），
 * 收到 -100% 时右缘会留一条阴影残影，所以与 message / CCU 一样多移 1.5rem 把阴影
 * 一起推出视窗。
 *
 * 收起态用 visibility 而不只是位移 + pointer-events —— 否则看不见时仍能用 Tab 聚焦进去。
 */
.nav-panel {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  /* 高度随内容（到最后一行导航为止），不是通到屏幕底 —— 与 message 一致；
     只用 max-height 兜底：页签极多或横屏过矮时面板内部自己滚。
     ⚠️ 上限必须是「视口高 - 顶栏高」，不能写 calc(100vh - 100%) ——
     百分比在 max-height 里解析不出这样的语义，等于没写；面板一高就会超出视口底部，
     用户看到的正是「展开后被盖住」。顶栏高由 .acct-top 的 --acct-topbar-h 给。 */
  height: auto;
  max-height: calc(100vh - var(--acct-topbar-h, 56px));
  z-index: 40;
  background: var(--card);
  box-shadow: var(--shadow);
  /* 面板长在 header 里，会继承顶栏的 color:#fff —— 浅底上就是白字（昵称曾因此隐形）。
     显式落回正文色，别依赖继承链上恰好没人改过 color。 */
  color: var(--title);
  transform: translateX(0);
  transition: transform 0.3s ease-in-out, visibility 0.3s ease-in-out;
  visibility: visible;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.nav-panel--closed {
  transform: translateX(calc(-100% - 1.5rem));
  visibility: hidden;
  pointer-events: none;
}

/*
 * 面板展开时盖住页面的遮罩（与 message 站同一交互）：点遮罩即收起。
 * 只在窄屏存在（桌面由断点 display:none）。z-index 关系：顶栏整体 40 > 遮罩 30，
 * 所以顶栏与面板浮在遮罩上，遮罩只压住下方页面内容。
 */
.nav-mask {
  position: fixed;
  inset: 0;
  z-index: 30;
  background: rgba(8, 15, 30, 0.5);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.18s ease, visibility 0.18s;
}

.nav-mask--open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
}

/* 全宽面板没有「跟着内容区对齐」的限宽需求，内容直接通栏铺开（与 message 一致）。
   行距全部来自行自己的内边距（message 是 p-3 容器 + py-2 行，行间不加 gap），
   别再加行间 gap —— 加了就又不是 message 的密度了。 */
.nav-panel__inner {
  display: grid;
  gap: 0;
  padding: 12px;
}

/* 面板顶部的身份块：宽屏侧栏底部那张账户卡在这里的镜像（用户要求窄屏菜单按宽屏设计放） */
.nav-panel__id {
  margin-bottom: 6px;
  padding: 4px 10px 12px;
  border-bottom: 1px solid var(--border);
}

.nav-panel__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 10px;
  border-radius: 12px;
  color: var(--text);
  font-size: 14px;
  text-decoration: none;
}

/* 与左侧栏同一口径：悬停只给底色（白底上用 --field，--hover 在白底上看不出来），
   不叠全局的 a:hover 下划线 */
.nav-panel__item:hover {
  background: var(--field);
  text-decoration: none;
}

.nav-panel__item.is-active {
  background: var(--field);
  color: var(--primary-ink);
  font-weight: 600;
}

/* 注：面板底部的「谁在登录 + 退出」整段已删（2026-10-06）——
   浅色顶栏那份退出按钮现在是窄屏顶栏四样之一，同一动作不必在同一个抽屉里出现两次。 */

/* ---------- 主题切换。两个形态：单按钮三态循环（顶栏/认证页）+ 三格分段（侧栏底部） ---------- */

.theme-toggle {
  display: grid;
  place-items: center;
  flex: none;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 9px;
  background: transparent;
  color: #fff;
  cursor: pointer;
}

.theme-toggle:hover {
  background: rgba(255, 255, 255, 0.14);
}

.theme-toggle:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.7);
  outline-offset: 1px;
}

/* 三个图标叠在同一格：按钮尺寸固定，切换时不会因为图标大小不同而抖动 */
.theme-toggle__icon {
  display: grid;
  grid-area: 1 / 1;
}

/* 描边属性统一在这里给：图标组件本身不带属性（与 .icon / .sso-icon 同一约定）。
   线宽 2 与 lucide 原图形一致，别调小 —— 调了就不再是 CCU 那套观感。 */
.theme-toggle__icon svg {
  display: block;
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/*
 * 由 <html data-theme-mode> 决定显示哪个图标 —— 该属性由 THEME_INIT_SCRIPT 在
 * 首帧绘制前写好（见 lib/client-scripts.ts）。用 HTML 属性 + CSS 而不是 JS 逐个
 * 开关图标，是为了无 JS 时也不会三个图标叠在一起。选择器依赖 data-theme-icon
 * 的取值与模式名同名（light / dark / auto）。
 */
[data-theme-mode='light'] .theme-toggle__icon:not([data-theme-icon='light']),
[data-theme-mode='dark'] .theme-toggle__icon:not([data-theme-icon='dark']),
[data-theme-mode='auto'] .theme-toggle__icon:not([data-theme-icon='auto']) {
  display: none;
}

/* 浮在卡片右上角（认证页 / 同意页 / 提示页）：配色取页面令牌，随深浅色自适应 */
.theme-toggle--float {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 3;
  width: 32px;
  height: 32px;
  border-color: var(--border);
  background: var(--field);
  color: var(--text-soft);
}

.theme-toggle--float:hover {
  background: var(--hover);
  color: var(--text);
}

.theme-toggle--float:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 1px;
}

/*
 * 三格分段的外观切换（账号中心宽屏侧栏底部）。用户 2026-10-06 要求：
 * 「深浅色改成一个长条栏三个分栏的点击滑动切换的按钮」。
 *
 * 滑块（.theme-seg__thumb）的位置**只由 html[data-theme-mode] 决定**，不靠 JS 定位：
 * 无 JS 时首帧它也在正确的那一格上（只是点不动）。三格等宽 ——
 * 内边距左右各 3px，于是每格是 (100% - 6px) / 3，位移按 100% / 200% 步进。
 */
.theme-seg {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--field);
}

.theme-seg__thumb {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  width: calc((100% - 6px) / 3);
  border-radius: 7px;
  background: var(--card);
  box-shadow: var(--shadow);
  transition: transform 0.22s ease;
}

[data-theme-mode='light'] .theme-seg__thumb {
  transform: translateX(0);
}

[data-theme-mode='dark'] .theme-seg__thumb {
  transform: translateX(100%);
}

[data-theme-mode='auto'] .theme-seg__thumb {
  transform: translateX(200%);
}

.theme-seg__opt {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}

.theme-seg__opt:hover {
  color: var(--text);
}

.theme-seg__opt[aria-pressed='true'] {
  color: var(--primary-ink);
}

.theme-seg__opt:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -1px;
}

/* 与 .theme-toggle__icon svg 同一约定：描边属性在这里给，组件本身不带 */
.theme-seg__opt svg {
  display: block;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* 点击切换时图标转一圈（与 message / CCU 的 animate-spin-once 同款）。
   ⚠️ 这个类只加在按钮内部的图标上（见 THEME_TOGGLE_SCRIPT）—— 加到按钮上会把边框一起转。 */
@keyframes spin-once {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.spin-once {
  animation: spin-once 0.3s ease-in-out;
}

/* 两张卡片都需要定位基准：主题按钮浮在它们的右上角 */
.sso-card,
.card {
  position: relative;
}

/* iOS 回弹区会露出 html 的背景，别让它一直是白的 */
html {
  background: var(--bg);
}

/* ---------- 断点：768px 是三段式的开关 ---------- */

@media (max-width: 768px) {
  .nav-burger {
    display: inline-flex;
  }

  /*
   * 这里**不再隐藏顶栏里的任何东西**。原先有一条「邮箱与退出让位给面板」的规则，
   * 2026-10-06 起窄屏顶栏固定是「汉堡 / logo / 外观切换 / 退出」四样，
   * 那条规则会把退出按钮一起藏掉（用户明确要求顶栏保留退出）。
   * 管理后台不在这里：它已换成左侧抽屉 + 自己的 1024 断点（见 .adm-side 那段）。
   */
}

/*
 * 账号中心的「侧栏 ↔ 面板」开关是 860px，不是三段式通用的 768px ——
 * 必须与 .acct-grid 的单列断点一致：若用 768，769–860 的区间里
 * 「侧栏没了（跟着 860 走）、汉堡也没了（跟着 768 走）」，导航就无处可寻。
 * 账号中心的规则都以 body.acct-body 作用域收窄，管理后台（仍是 768）不受影响。
 */
@media (max-width: 860px) {
  body.acct-body .nav-burger {
    display: inline-flex;
  }

  /* 侧栏整体退场，内容区回到通栏（内边距也回到页面级的老值） */
  .acct-side {
    display: none;
  }

  /*
   * 窄屏交回给文档流：整页滚动（顶栏在顶部、页脚在末尾，都随页面滚）。
   * 宽屏那套「外框锁一屏 + 内容区自己滚」必须在这里显式撤掉 ——
   * 不撤的话窄屏会同时出现「内容区内部滚动条」与「文档滚动条」两条，很难看也不好用。
   */
  .acct-layout,
  .adm-layout {
    display: block;
    height: auto;
    overflow: visible;
    padding: 24px 20px 8px;
  }

  .acct-main,
  .adm-main {
    /* 撤掉 flex：窄屏没有「内容区底部」这个概念，页脚就是文档末尾的一段，
       margin-top 仍留着 —— 与内容之间照样有 32px 间隔 */
    display: block;
    height: auto;
    padding: 0;
    overflow-y: visible;
  }

  /*
   * 限宽与居中都是宽屏「外框锁一屏」那套的配套，窄屏一律撤掉：
   * 布局的左右内边距已经写在 .acct-layout 上（20px），再叠一层会把内容挤到中间。
   */
  .acct-main__body,
  .adm-main__body,
  .acct-foot,
  .adm-foot {
    max-width: none;
    margin-inline: 0;
  }

  /*
   * 顶栏四项：汉堡 / logo 靠左，外观切换 / 退出靠右。
   * 靠 .acct-me 的 margin-left:auto 把右侧那组推到底 —— 不用 space-between，
   * 那会让四样均分整个宽度（logo 会被推到中间去）。
   * 身份块不在顶栏：它在抽屉顶部（与宽屏侧栏底部那张账户卡同一份信息）。
   */
  .acct-top__inner,
  .adm-top__inner {
    gap: 10px;
    padding: 0 14px;
  }
}

/* 769–860 区间：面板被通用断点（min-width:769）按桌面藏掉，这里为账号中心打开 */
@media (min-width: 769px) and (max-width: 860px) {
  body.acct-body .nav-panel {
    display: block;
  }
}

/*
 * 极窄屏：站名**不隐藏**（用户要看到自己在哪个站），改成可截断。
 * 之前这里写的是 display:none，结果 390px 手机上顶栏只剩一个光秃秃的 logo。
 * 实测「CIKIO 管理后台」在 320px 宽也放得下（汉堡 34 + 主题 34 + 内边距 28，
 * 剩下约 200px，站名 + 图标约 140px），截断只是极端情况的兜底。
 */
@media (max-width: 420px) {
  .adm-brand span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* 桌面端不需要面板（它只在窄屏作为导航的容器） */
@media (min-width: 769px) {
  .nav-panel {
    display: none;
  }
}


/* ---------- 用户详情页 ---------- */

/* 卡片之间留出呼吸：之前卡片紧贴，看不出信息分组 */
.adm-cards {
  display: grid;
  gap: 20px;
}

/* 一级返回链接：统一在「面包屑之下、页面标题之上」（用户详情 / 封禁 / 角色三页同位置） */
.adm-back {
  margin: 0 0 10px;
  font-size: 13px;
}

/* 操作按钮组：按钮多了要换行，别挤成一条 */
.acct-actions {
  flex-wrap: wrap;
}

/* 账号信息卡的「标签 / 值」两列行 */
.adm-detail {
  display: grid;
  gap: 8px;
}

.adm-detail__row {
  display: flex;
  gap: 12px;
  font-size: 14px;
  /* 邮箱、账号 ID 这类长串允许在任意位置换行，否则窄屏会顶破卡片 */
  overflow-wrap: anywhere;
}

.adm-detail__k {
  flex: none;
  width: 76px;
  color: var(--muted);
}

/* 值这一列可能是「文本 + 徽标 + 复制按钮」，允许换行与收缩 */
.adm-detail__v {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-width: 0;
}

/* 点值即复制：外观就是普通文本（无边框、继承字体），只在悬停时给一点提示 */
.adm-copyable {
  display: inline;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  text-align: left;
  cursor: pointer;
  overflow-wrap: anywhere;
}

.adm-copyable:hover {
  color: var(--primary-ink);
  text-decoration: underline dotted;
}

.adm-copyable--mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px;
}

/* 复制成功的一瞬：由 COPY_SCRIPT 加类，反馈用角标而不是改写值本身 */
.adm-copyable.is-copied {
  color: var(--ok-text);
}

.adm-copyable.is-copied::after {
  content: '已复制';
  margin-left: 6px;
  font-family: inherit;
  font-size: 12px;
}

.adm-providers {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}

/* 危险动作按钮（封禁子页面的「确认封禁」） */
.btn--danger {
  background: var(--danger-bg);
  border-color: var(--danger-border);
  color: var(--danger-text);
}

.btn--danger:hover {
  background: var(--danger-border);
}

/* 子页面里的主按钮不像表单那样通栏 */
.adm-form__submit {
  width: auto;
  padding: 0 22px;
}

/* 封禁 / 角色表单：字段纵向堆叠（不加的话 textarea 和 select 会挤在同一行） */
.adm-form {
  display: grid;
  gap: 8px;
  max-width: 520px;
}

.adm-form textarea,
.adm-form select {
  width: 100%;
}

/*
 * 下拉框：原生 <select> 的弹出列表改不了（那是操作系统画的），
 * 但收起状态的框可以完全对齐我们的输入框——去默认箭头、画同款边框圆角、
 * 用内联 SVG 自绘一枚同色 chevron。
 */
.adm-form select,
.adm-search select,
.adm-rowform select,
.adm-wordform select {
  appearance: none;
  padding-right: 34px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background-color: var(--card);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 14px;
  cursor: pointer;
}

.adm-form select:focus,
.adm-search select:focus,
.adm-rowform select:focus,
.adm-wordform select:focus {
  outline: 2px solid rgba(16, 44, 120, 0.35);
  border-color: var(--primary-ink);
}

.adm-form textarea {
  min-height: 84px;
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: var(--card);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  line-height: 1.6;
  resize: vertical;
}

.adm-form textarea:focus {
  outline: 2px solid rgba(16, 44, 120, 0.35);
  border-color: var(--primary-ink);
}

.adm-form .acct-actions {
  margin-top: 4px;
}

/* ---------- 内容审核（词库 + 复核队列） ---------- */

/*
 * 注：二级导航（.adm-subnav）原在这里，2026-10-06 后台改版时**提到侧栏**了
 * ——「内容审核」在侧栏下有「复核队列 / 词库」两个子项。页内再放一份是同一件事说两遍，
 * 所以整套样式一并删除，不是暂时注释掉。
 */

/* 状态条：左边说明、右边发布按钮。允许换行，窄屏上下堆叠 */
.adm-status {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.adm-status__text {
  display: grid;
  gap: 4px;
  min-width: 0;
}

/*
 * 表格行内的紧凑表单：一行放下「处置 + 作用域 + 替换文本 + 保存」。
 * 必须紧凑 —— 逐行展开成块会让一页 50 条变成几千像素的滚动条，
 * 而这一页的目的是「快速扫一遍并改掉几个」。
 */
.adm-rowform {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.adm-rowform select,
.adm-rowform input {
  height: 32px;
  padding: 0 8px;
  border: 1px solid var(--border-strong);
  border-radius: 6px;
  background: var(--card);
  color: var(--text);
  font-family: inherit;
  font-size: 12px;
}

.adm-rowform input {
  width: 120px;
}

/* 给自绘的 chevron 留位。上面的简写 padding 会把 .adm-form select 那套的 34px 一起盖掉，
   所以这里必须补回来 —— 否则下拉箭头会压在文字上 */
.adm-rowform select {
  padding-right: 30px;
}

.adm-wordform select {
  padding-right: 34px;
}

/* 表格内的按钮：与旁边的下拉/输入框齐平 */
.adm-btn-sm {
  height: 32px;
  padding: 0 10px;
  border-radius: 6px;
  font-size: 12px;
}

/*
 * 新增表单：标签与控件两列对齐。用 grid 而不是靠 label 宽度，
 * 是因为保存按钮要跨到第二列（否则它会落在标签那一列里，看起来像另一个字段）。
 */
.adm-wordform {
  display: grid;
  grid-template-columns: 84px minmax(0, 1fr);
  align-items: center;
  gap: 8px 12px;
  max-width: 520px;
  margin: 12px 0;
}

.adm-wordform input,
.adm-wordform select {
  height: 36px;
  padding: 0 10px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: var(--card);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
}

.adm-wordform .acct-actions {
  grid-column: 2;
  margin: 0;
}

@media (max-width: 560px) {
  .adm-wordform {
    grid-template-columns: 1fr;
  }

  .adm-wordform .acct-actions {
    grid-column: 1;
  }
}

/* ---------- 后台首页（概览） ---------- */

.adm-h2 {
  margin: 26px 0 12px;
  font-size: 15px;
  font-weight: 600;
  color: var(--text-soft);
}

/* 统计卡片：每张一个数字 + 一行标签，数字要一眼看到，标签退到后面 */
/* 卡片间距统一 20px —— 与 .acct-grid 同一个值（此前这里是 12px，两边的卡片间距不同） */
.adm-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px;
}

/* 外观（底色/边框/圆角/投影/内边距）与 .acct-card 共用上面那一份，这里只留排版 */
.adm-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.adm-stat__v {
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.adm-stat__k {
  font-size: 12px;
  color: var(--muted);
}

/* 功能入口 */
.adm-tiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
}

/* 同上：外观与 .acct-card 共用，这里只留排版与链接态 */
.adm-tile {
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--text);
  text-decoration: none;
}

a.adm-tile:hover {
  border-color: var(--primary-ink);
}

.adm-tile__title {
  font-size: 15px;
  font-weight: 600;
  color: var(--primary-ink);
}

.adm-tile__desc {
  font-size: 13px;
  line-height: 1.6;
  color: var(--muted);
}

@media (max-width: 720px) {
  .adm-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .adm-tiles {
    grid-template-columns: 1fr;
  }
}

