/* ─── NimbusGate · 幻构云筑 —— 组件层样式  ───
   令牌前缀 --ng-*；主色 #6c5ce7。
   骨架与令牌取值对齐凌云海自有站点体系（acc/sup/dev/ylcmc 同一套设计系统），
   保证全站显示风格一致；本文件为组件层，Bootstrap 只承担栅格与工具类。 */

:root {
    /* 令牌取值对齐凌云海自有站点体系；主色按 NimbusGate 品牌色 #6c5ce7 */
    --ng-primary: #6c5ce7;
    --ng-primary-hover: #5a4bd1;
    --ng-primary-light: #efecfd;
    --ng-primary-bg: #f6f4fe;
    /* 时间轴连线/节点的「淡品牌色」：品牌紫约 30% 不透明度。
       单独做成 token 是为了让改主色时**有唯一一处要改**（否则又是一处写死的 rgba 近亲）。 */
    --ng-primary-line: rgba(108, 92, 231, .32);
    --ng-gradient: linear-gradient(135deg, #6c5ce7 0%, #8f7dff 100%);
    --ng-gradient-warm: linear-gradient(135deg, #ff6a00 0%, #ff9f43 100%);
    --ng-bg: #f5f6f8;
    --ng-bg-white: #ffffff;
    --ng-text: #1a1a2e;
    --ng-text-secondary: #5a6070;
    --ng-text-muted: #8a9099;
    --ng-border: #e8eaee;
    --ng-border-light: #f0f0f5;
    --ng-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.05);
    --ng-shadow: 0 2px 10px rgba(0, 0, 0, 0.07);
    --ng-shadow-lg: 0 6px 24px rgba(0, 0, 0, 0.10);
    --ng-radius: 0px;
    --ng-radius-control: 4px;
    --ng-radius-pill: 999px;
    /* 统一缓动（收敛自早期各页面自带的 --ease） */
    --ng-ease: cubic-bezier(.16, 1, .3, 1);

    /* 状态色（原为各处内联写死的 Bootstrap 默认值，收敛为单一来源） */
    --ng-danger: #dc3545;
    --ng-danger-hover: #bb2d3b;
    --ng-success: #22c55e;
    --ng-focus-ring: 0 0 0 3px rgba(108, 92, 231, 0.18);

    /* 导航栏高度：复刻月雨庭官网 65px。**全站唯一真源** —— 首屏高度、分类条吸顶、
       用户中心侧栏、锚点偏移都引用它，改高度只改这一处，别再各写各的 60px/65px。 */
    --ng-nav-h: 65px;
    --ng-logo-h: 36px;
}

/* ─── 基础 ─── */
body {
    background-color: var(--ng-bg);
    color: var(--ng-text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
    font-size: 14px;
    line-height: 1.6;
    min-height: 100vh;
    min-height: 100dvh; /* 移动端地址栏收起时 100vh 高于可视区，会把页脚顶到屏幕之外 */
    display: flex;
    flex-direction: column;
}

/* ═══════════════════════════════════════
   页面骨架：内容区至少占满一屏，页脚「顶部」与视口底部对齐
   链路 body(纵向 flex) → main 至少有「视口高 - 导航高」→ #appContent 填满 main
   → 内容不足一屏时，多出来的高度作为留白落在 main 内部，页脚顶边正好落在屏幕下边缘
     （页脚整块位于首屏之外，向下滚动才可见）；
   → 内容超过一屏时 main 由内容撑高，页脚随内容下移（正常滚动）。
   ═══════════════════════════════════════ */

/* 导航与页脚按自身高度占位，不参与 flex 压缩 */
body > .navbar-sup,
body > .footer-sup {
    flex: 0 0 auto;
}
/* 内容区外层：纵向 flex 容器；高度不足一屏时用留白补齐到「视口 - 导航高」 */
body > main.flex-grow-1 {
    display: flex;
    flex-direction: column;
    min-height: calc(100vh - var(--ng-nav-h));
    min-height: calc(100dvh - var(--ng-nav-h));  /* 移动端地址栏收起时 100vh 高于可视区，需 dvh 修正 */
}
/* 内容区：撑满 main（认证页也借这个高度做垂直居中） */
body > main.flex-grow-1 > #appContent {
    flex: 1 0 auto;
}

/* 圆角分层：卡片/导航直角(0)，控件 4px，主 CTA 胶囊 */
.card, .modal-content, .dropdown-menu, .toast, .list-group-item,
.navbar, .nav-pills .nav-link, .pagination .page-link {
    border-radius: var(--ng-radius) !important;
}
.btn, .form-control, .input-group-text, .badge, .alert {
    border-radius: var(--ng-radius-control) !important;
}
.btn-pill { border-radius: var(--ng-radius-pill) !important; }

/* 统一 logo 尺寸：三站同值，图片源集中到 www.mclinyunhai.com */
.navbar-brand img, .navbar-brand-centered img { height: var(--ng-logo-h); width: auto; }

/* ─── 前台导航栏（高度 / tab 区 / logo 区复刻月雨庭官网，右侧保持本站原样）─── */
.navbar-sup {
    /* tab 区尺寸真源：与月雨庭官网同值（字号 / 间距 / 逐字滚动时长与步进）。
       挂在 .navbar-sup 而不是 ul 上，是为了让 .container 的响应式 gap 与 tab gap 同源。 */
    --nav-fs: 14px;
    --nav-gap: 36px;
    --nav-roll-dur: .45s;
    --nav-roll-step: .0067s;

    background: #fff !important;
    border-bottom: 1px solid var(--ng-border);
    height: var(--ng-nav-h);
    padding: 0 24px;
    position: sticky;
    top: 0;
    z-index: 1030;
}
.navbar-sup .navbar-brand { font-weight: 700; font-size: 16px; color: var(--ng-text); display: flex; align-items: center; gap: 10px; }
.navbar-sup .navbar-brand img { height: var(--ng-logo-h); width: auto; display: block; }
.navbar-sup .nav-link { color: var(--ng-text-secondary); font-size: 14px; padding: 18px 16px !important; transition: color .2s; }
.navbar-sup .nav-link:hover, .navbar-sup .nav-link.active { color: var(--ng-primary); }
/* 三栏布局：中列相对整条导航栏严格居中，左右 1fr 对称（品牌靠左、用户区靠右）。
   容器宽度 / 内边距 / 列间距取月雨庭官网同值，三栏的可用宽度才与参考站一致；
   Bootstrap .container 自带的 1320px / 12px 会把中列整体挤偏。 */
.navbar-sup .container {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    max-width: 1436px;
    padding: 0 40px;
    gap: 40px;
}
.navbar-sup .nav-left { display: flex; align-items: center; gap: 12px; justify-self: start; min-width: 0; }
.navbar-sup .nav-center { justify-self: center; }
.navbar-sup .nav-right { display: flex; align-items: center; justify-self: end; min-width: 0; }
/* Bootstrap .navbar-brand 自带 margin-right:1rem，会把移动端居中 logo 顶偏 8px */
.navbar-brand-centered { margin-right: 0; }

/* ─── 导航 tab 区（复刻月雨庭官网）───
   ① tab 行高 64px、字号 14px、项间距 --nav-gap（36/26/18 三级），与参考站逐值一致；
      窄桌面同时收紧 .container 的列间距，避免中列被左右两块挤到换行；
   ② 高亮是底部 2px 品牌色横线，由右向左收、由左向右展开；
   ③ 标签文字逐字上滚替换（.lr 一族，由 header.php 的 $navLabelRoll 生成双层 span）。
   只作用于桌面导航 ul，移动端 .nav-mobile 与右侧用户区都不受影响。 */
.navbar-sup .navbar-nav.d-none.d-lg-flex {
    gap: var(--nav-gap);
    height: 64px;
    align-items: center;
}
@media (max-width: 1280px) {
    .navbar-sup { --nav-gap: 26px; }
    .navbar-sup .container { gap: 24px; }
}
@media (max-width: 1120px) {
    .navbar-sup { --nav-gap: 18px; }
    .navbar-sup .container { padding: 0 20px; gap: 16px; }
}

.navbar-sup .navbar-nav.d-none.d-lg-flex .nav-link {
    position: relative;
    padding: 6px 0 !important;
    font-size: var(--nav-fs);
    font-weight: 400;
    text-decoration: none;
    transition: all var(--nav-roll-dur) ease;
}
.navbar-sup .navbar-nav.d-none.d-lg-flex .nav-link::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 2px;
    border-radius: 2px;
    background: var(--ng-primary);
    transform: scaleX(0);
    transform-origin: right;
    transition: transform var(--nav-roll-dur) cubic-bezier(.4, 0, .2, 1);
}
.navbar-sup .navbar-nav.d-none.d-lg-flex .nav-link:hover::after,
.navbar-sup .navbar-nav.d-none.d-lg-flex .nav-link.active::after {
    transform: scaleX(1);
    transform-origin: left;
}
.navbar-sup .navbar-nav.d-none.d-lg-flex .nav-link.active { font-weight: 600; }

/* 逐字滚动：每个字一个 overflow:hidden 的小窗，里面两份同样的字上下叠放 */
.navbar-sup .navbar-nav.d-none.d-lg-flex .lr { display: inline-flex; }
.navbar-sup .navbar-nav.d-none.d-lg-flex .lr-i {
    position: relative; display: inline-block; overflow: hidden;
    flex-shrink: 0; line-height: 1.45;
}
.navbar-sup .navbar-nav.d-none.d-lg-flex .lr-a,
.navbar-sup .navbar-nav.d-none.d-lg-flex .lr-b {
    display: block;
    transition: transform var(--nav-roll-dur) cubic-bezier(.4, 0, .2, 1);
    transition-delay: calc(var(--i, 0) * var(--nav-roll-step));
}
.navbar-sup .navbar-nav.d-none.d-lg-flex .lr-b {
    position: absolute; inset: 0; transform: translateY(100%);
}
.navbar-sup .navbar-nav.d-none.d-lg-flex .nav-link:hover .lr-a { transform: translateY(-100%); }
.navbar-sup .navbar-nav.d-none.d-lg-flex .nav-link:hover .lr-b { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
    .navbar-sup .navbar-nav.d-none.d-lg-flex .lr-a,
    .navbar-sup .navbar-nav.d-none.d-lg-flex .lr-b,
    .navbar-sup .navbar-nav.d-none.d-lg-flex .nav-link::after { transition: none; }
}
/* 头像下拉触发器：悬停/聚焦都不出现系统黑框（UA 默认 outline），悬停反馈只做变色 */
.navbar-sup .dropdown-toggle { outline: none; }
.navbar-sup .dropdown-toggle:hover,
.navbar-sup .dropdown-toggle:focus,
.navbar-sup .dropdown-toggle:focus-visible,
.navbar-sup .dropdown-toggle.show { outline: none; box-shadow: none; }
/* 移动端下拉面板：absolute 浮层覆盖在内容上，不撑高导航栏（修复展开时导航栏变高/内容被顶开的问题） */
.navbar-sup .nav-mobile {
    position: absolute;
    top: var(--ng-nav-h);
    left: -24px;
    right: -24px;
    background: #fff;
    border-top: 1px solid var(--ng-border);
    box-shadow: 0 8px 20px rgba(0, 0, 0, .08);
    z-index: 1040;
    margin: 0;
    padding: 8px 10px; /* 移动端「菜单」下拉：选项左右边距 */
}
.navbar-sup .nav-mobile .nav-link {
    display: flex; align-items: center; justify-content: center; gap: 10px;
    padding: 11px 12px !important;
    font-size: 14px;
    border-radius: var(--ng-radius-control);
    transition: background-color .2s ease, color .2s ease;
}
.navbar-sup .nav-mobile .nav-link i { width: 18px; text-align: center; font-size: 15px; color: var(--ng-text-muted); }
.navbar-sup .nav-mobile .nav-link:hover { background: #f8f6ff; color: var(--ng-primary); }
.navbar-sup .nav-mobile .nav-link.active { background: var(--ng-primary-bg); color: var(--ng-primary); }
.navbar-sup .nav-mobile .nav-link.active i { color: var(--ng-primary); }
/* 未登录时导航栏的「登录 / 注册」：两个胶囊按钮。
   形状复用 .btn-pill（--ng-radius-pill 令牌，带 !important 可压过 .btn 的 4px 直角）；
   这里只定尺寸与排版 —— 加高的是按钮本身，--ng-nav-h 保持 65px 不动。
   已登录状态的头像下拉不套这些类，不受影响。 */
.navbar-sup .nav-right .btn { white-space: nowrap; flex-shrink: 0; }
.navbar-sup .nav-right .nav-auth-btn {
    height: 40px;
    padding: 0 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: 500;
    line-height: 1;
}
@media (max-width: 400px) {
    .navbar-sup .nav-right .nav-auth-btn { height: 34px; padding: 0 14px; font-size: 13px; }
    .navbar-sup .nav-right .btn i { display: none; } /* 极窄屏：登录按钮的图标让位给文字 */
}

/* ── 移动端菜单按钮：纯 CSS 三条线，展开时变 X ──
   照子比 .i-menu 的思路：不用图片，用 1 个 <i> + 2 个伪元素画三条，
   展开时上下两条 rotate(±45deg)、中间 opacity:0，配 transition 就是带过渡的 X。
   （Bootstrap 默认的 .navbar-toggler-icon 是 SVG 背景图，图不能动，故弃用。） */
.navbar-sup .navbar-toggler {
    width: 40px; height: 40px; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--ng-text); border: 0; background: none;
    outline: none; box-shadow: none;
}
/* 悬停/聚焦/按下都不出现系统黑框（与头像按钮同款处理） */
.navbar-sup .navbar-toggler:hover,
.navbar-sup .navbar-toggler:focus,
.navbar-sup .navbar-toggler:focus-visible,
.navbar-sup .navbar-toggler:active {
    outline: none; box-shadow: none; border: 0;
}
.navbar-sup .css-menu { position: relative; display: inline-block; width: 20px; height: 20px; }
.navbar-sup .css-menu > i,
.navbar-sup .css-menu::before,
.navbar-sup .css-menu::after {
    content: ''; position: absolute; left: 0; right: 0; height: 2px; border-radius: 2px;
    background: currentColor;
    transition: transform .4s ease, opacity .25s ease, bottom .4s ease, right .4s ease;
}
.navbar-sup .css-menu > i { bottom: 9px; right: 2px; }        /* 中：略短 */
.navbar-sup .css-menu::before { bottom: 16px; right: 4px; }   /* 上：更短 */
.navbar-sup .css-menu::after { bottom: 2px; }                 /* 下：全宽 */
/* 展开 → X：由 JS 在「点击瞬间」给按钮加 .is-open（show/hide.bs.collapse 在动画开始前触发），
   点下去就播放过渡，不等 Bootstrap 面板展开/收起完成（.show 是动画结束才加的，会慢半拍）。 */
.navbar-sup .navbar-toggler.is-open .css-menu > i { opacity: 0; }
.navbar-sup .navbar-toggler.is-open .css-menu::before { bottom: 9px; right: 0; transform: rotate(-45deg); }
.navbar-sup .navbar-toggler.is-open .css-menu::after { bottom: 9px; transform: rotate(45deg); }
/* 移动端 Logo 居中（nav-center 为 grid 中列自动居中；三栏：菜单左 / Logo 中 / 头像右） */
@media (max-width: 991.98px) {
    .navbar-sup .nav-center { display: flex; align-items: center; }
}
/* 产品生态下拉（对齐 www：浅色卡片网格） */
.navbar-sup .dropdown-menu { margin-top: 0; }

/* ── 导航栏用户下拉（子比风格：头部信息卡 + 图标菜单项）── */
.uc-dd { min-width: 240px; }
.uc-dd-head { display: flex; align-items: center; gap: 12px; padding: 16px; border-bottom: 1px solid var(--ng-border); background: #fafbfc; }
.uc-dd-who { min-width: 0; }
.uc-dd-name { display: flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 700; }
.uc-dd-mail { font-size: 12px; color: var(--ng-text-muted); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uc-dd-body { padding: 6px 8px; }
/* 下拉项与「用户中心侧边栏」同一套按钮样式：内缩 4px 圆角、悬停主色底+主色字、图标 18px 居中 */
.uc-dd-item { display: flex; align-items: center; gap: 10px; padding: 9px 10px; font-size: 14px; color: var(--ng-text-secondary); text-decoration: none; border-radius: var(--ng-radius-control); transition: background-color .2s ease, color .2s ease; }
.uc-dd-item + .uc-dd-item { margin-top: 2px; }
.uc-dd-item i { font-size: 15px; color: var(--ng-text-muted); width: 18px; text-align: center; flex: 0 0 auto; transition: color .2s ease; }
.uc-dd-item:hover { background: var(--ng-primary-bg); color: var(--ng-primary); }
.uc-dd-item:hover i { color: var(--ng-primary); }
.uc-dd-item.is-danger { color: var(--ng-danger); }
.uc-dd-item.is-danger i { color: var(--ng-danger); }
.uc-dd-item.is-danger:hover { background: #fff1f0; }
/* 分割线：中间实、向两端淡出 */
.uc-dd-divider { height: 1px; border: 0; margin: 6px 10px; background: linear-gradient(90deg, transparent, var(--ng-border) 50%, transparent); }
.navbar-sup .eco-drop-item { border-radius: 0; }
.navbar-sup .eco-drop-item:hover { background: var(--ng-primary-bg); }
.navbar-sup .eco-drop-item i { font-size: 18px; }

/* ═══════════════════════════════════════
   页面切换过渡（View Transitions）：本文件不放任何 VT 规则。
   - opt-in `@view-transition{navigation:auto}` 内联在三个外壳 head 的最前面
     （header.php / admin-header.php / auth-layout.php）；必须尽早注册，否则浏览器
     在 pagereveal 判定时还没认到，跨文档过渡会被整段跳过。
   - 动画规则（keyframes / ::view-transition-* / 命名 / reduced-motion）在 ng-ui.css，
     三个外壳都加载，认证页也覆盖得到。
   实现与 sup / acc 逐字一致：纯透明度交叉淡入淡出，不做位移；
   全站已移除 SPA 无刷，站内跳转都是跨文档导航，由浏览器原生接管。
   ═══════════════════════════════════════ */

/* 导航栏下拉菜单展开时的轻微淡入（悬停/点击均生效；不支持动画的浏览器直接显示） */
.navbar .dropdown-menu.show { animation: nav-dd-in .15s ease; }
@keyframes nav-dd-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
    .navbar .dropdown-menu.show { animation: none; }
}
/* 收起时淡出（配合 footer.php：桌面端鼠标移出 → 先淡出再收起，而不是"啪"地消失） */
@keyframes nav-dd-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: translateY(-4px); } }
.navbar .dropdown-menu.nav-dd-closing { animation: nav-dd-out .15s ease forwards; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
    .navbar .dropdown-menu.nav-dd-closing { animation: none; }
}

/* 用户中心侧栏 / 内容区都**不单独命名** view-transition-name：全站已移除 SPA 局部换页，
   侧栏跟着 root 一起淡即可（acc 的 account.css 也是这个结论）。
   另外非空 view-transition-name 会给元素建独立层叠上下文，里面 position:fixed 的抽屉/遮罩
   会被困住、被导航栏压在下面，看着像"顶部显示错误"，能不挂就不挂。 */

/* ─── 按钮 ───
   .btn-primary / .btn-secondary 一并纳入基础组：前台视图里这两个变体是**裸用**的
   （只写 class="btn-primary"，不写 .btn），而内边距与字号都来自 .btn —— 只写变体类会退回
   浏览器默认的 `padding: 1px 6px`，实测按钮只有 20px 高，看着像被压扁的文字
   （全站 13 处 btn-primary + 6 处 btn-secondary 都受影响）。
   纳入基础组后两种写法都能得到正确尺寸；.btn-sm / .btn-lg / .small 仍在其后声明，可正常覆盖。 */
.btn,
.btn-primary,
.btn-secondary {
    font-size: 14px;
    padding: 7px 20px;
    font-weight: 500;
    transition: all 0.2s;
}

/* ─── 导航栏「登录 / 注册」两枚按钮：悬停高亮缓入 ───
   必须放在上面 .btn 的 `transition: all 0.2s` 之后 —— 两者特异性同为 (0,3,0)，
   同特异性按源码顺序决定，.btn 在前会把自己的 transition 覆盖掉。
   1) 注册（描边底）：hover 时背景由透明渐变到主色。`.btn` 的 transition: all 会把
      background 简写一起带上，透明↔主色是 background-color 变化，本可过渡；
      这里显式列出属性并放宽到 0.28s，让填充是「缓亮」而非「啪」地变色。
   2) 登录（渐变底）：background-image 是渐变，**渐变不可插值**，换 --gh 必然瞬间跳色。
      故悬停保持底色不变，改用 filter: brightness 缓亮，配合外扩光晕形成平滑高亮。
   按下仍走站内渐变按钮的深色反馈（按压本就要即时响应，不做缓动）。 */
.navbar-sup .nav-right .nav-auth-btn {
    transition: color .28s ease, background-color .28s ease, border-color .28s ease,
                box-shadow .35s ease, filter .28s ease;
}
.navbar-sup .nav-right .nav-auth-btn.btn-grad-blue:hover {
    background-image: var(--g);
    filter: brightness(1.1);
}
.navbar-sup .nav-right .nav-auth-btn.btn-grad-blue:active {
    background-image: var(--ga);
    filter: brightness(0.96);
}
.btn-primary {
    background: var(--ng-gradient);
    border: none;
    color: #fff;
}
/* 悬停只换色 + 发光，不做上浮（原来的 transform:translateY(-1px) 已按要求去掉） */
.btn-primary:hover {
    background: linear-gradient(135deg, #5a4bd1 0%, #7c6ce9 100%);
    box-shadow: 0 4px 12px rgba(108, 92, 231, 0.3);
}
.btn-secondary {
    background: var(--ng-bg-white);
    border: 1px solid var(--ng-border);
    color: var(--ng-text-secondary);
}
.btn-secondary:hover {
    border-color: var(--ng-primary-light);
    background: var(--ng-primary-bg);
    color: var(--ng-primary);
}
.btn-outline-primary {
    border: 1px solid var(--ng-primary);
    color: var(--ng-primary);
    background: transparent;
}
.btn-outline-primary:hover {
    background: var(--ng-primary);
    border-color: var(--ng-primary);
    color: #fff;
}
.btn-lg {
    padding: 10px 32px;
    font-size: 16px;
}
.btn-sm {
    padding: 4px 12px;
    font-size: 12px;
}

/* ─── 通用渐变按钮组件（.btn-grad + 色系）───
   与品牌主按钮同款：135° 渐变（浅→深）、悬停加深、按下更深 + 内阴影；0 圆角。
   用法：<button class="btn btn-grad-red">删除</button>（色系类单独即可生效，无需再写 .btn-grad；
   两种写法都支持：.btn-grad + .btn-grad-red，或仅 .btn-grad-red。可与 .btn-sm / .btn-pill / .btn-lg 叠加）
   深色系白字；浅色系（lime/violet/yellow）自动改用深色字。 */
.btn-grad,
[class*="btn-grad-"] {
    --fg: #fff;
    --bs-btn-color: var(--fg);
    --bs-btn-hover-color: var(--fg);
    --bs-btn-active-color: var(--fg);
    --bs-btn-bg: transparent;
    --bs-btn-hover-bg: transparent;
    --bs-btn-active-bg: transparent;
    --bs-btn-border-color: transparent;
    --bs-btn-hover-border-color: transparent;
    --bs-btn-active-border-color: transparent;
    border: 0;
    color: var(--fg);
    background-image: var(--g);
    box-shadow: 0 2px 8px var(--gw, rgba(0, 0, 0, .12));
    /* 悬停发光缓慢过渡（背景渐变本身不可过渡，故只缓动发光与按压） */
    transition: box-shadow .35s ease, filter .2s ease;
}
.btn-grad:hover, [class*="btn-grad-"]:hover { background-image: var(--gh); box-shadow: 0 4px 14px var(--gw, rgba(0, 0, 0, .2)); }
.btn-grad:active, [class*="btn-grad-"]:active { background-image: var(--ga); box-shadow: inset 0 2px 5px rgba(0, 0, 0, .22); }
.btn-grad:disabled, .btn-grad.disabled, [class*="btn-grad-"]:disabled, [class*="btn-grad-"].disabled { opacity: .5; box-shadow: none; }

/* 主题色版本：品牌蓝，与 .btn-primary / sup 站点一致，不随子比重构改动 */
.btn-grad-blue    { --g: linear-gradient(135deg,#6c5ce7,#8f7dff); --gh: linear-gradient(135deg,#5a4bd1,#7c6ce9); --ga: linear-gradient(135deg,#4b3fb0,#6a5cd4); --gw: rgba(108,92,231,.32); }
/* 以下非品牌色系：色相与渐变方向对齐子比主题 .jb-*（浅→深 135deg），悬停/按下在子比端点基础上加深 */
.btn-grad-red     { --g: linear-gradient(135deg,#fd7a64 10%,#fb2d2d 100%); --gh: linear-gradient(135deg,#f25f49 10%,#e21d1d 100%); --ga: linear-gradient(135deg,#df4a35 10%,#c01515 100%); --gw: rgba(251,45,45,.28); }
.btn-grad-orange  { --g: linear-gradient(135deg,#f59f54 10%,#ff6922 100%); --gh: linear-gradient(135deg,#e88a3f 10%,#f2570f 100%); --ga: linear-gradient(135deg,#cf7533 10%,#d4450a 100%); --gw: rgba(255,105,34,.26); }
.btn-grad-magenta { --g: linear-gradient(135deg,#ff6ec7 10%,#d61ed6 100%); --gh: linear-gradient(135deg,#f055b6 10%,#c00fc0 100%); --ga: linear-gradient(135deg,#d63f9f 10%,#a60aa6 100%); --gw: rgba(214,30,214,.26); }
.btn-grad-green   { --g: linear-gradient(135deg,#60e464 10%,#5cb85b 100%); --gh: linear-gradient(135deg,#4cc84f 10%,#4aa449 100%); --ga: linear-gradient(135deg,#3fb843 10%,#3d8c3d 100%); --gw: rgba(92,184,91,.26); }
.btn-grad-lime    { --g: linear-gradient(135deg,#b5e655 10%,#84cc16 100%); --gh: linear-gradient(135deg,#a3d63f 10%,#74b40f 100%); --ga: linear-gradient(135deg,#8fbf33 10%,#629c0c 100%); --gw: rgba(132,204,22,.26); --fg: #2f4a00; }
.btn-grad-purple  { --g: linear-gradient(135deg,#f98dfb 10%,#ea00f9 100%); --gh: linear-gradient(135deg,#ec6cf0 10%,#c800d6 100%); --ga: linear-gradient(135deg,#d94fdc 10%,#a800b4 100%); --gw: rgba(234,0,249,.26); }
.btn-grad-violet  { --g: linear-gradient(135deg,#c9b6ff 10%,#a78bfa 100%); --gh: linear-gradient(135deg,#b8a2f5 10%,#9570f0 100%); --ga: linear-gradient(135deg,#a58ce8 10%,#8260d8 100%); --gw: rgba(140,110,240,.24); --fg: #3d2c78; }
.btn-grad-yellow  { --g: linear-gradient(135deg,#f9a158 10%,#f6b174 100%); --gh: linear-gradient(135deg,#eca144 10%,#eaa262 100%); --ga: linear-gradient(135deg,#d98f37 10%,#d8904f 100%); --gw: rgba(240,160,60,.26); --fg: #5a3a00; }
.btn-grad-gray    { --g: linear-gradient(317deg,#4d4c4c 30%,#7b7b7b 70%,#5f5c5c 100%); --gh: linear-gradient(317deg,#3f3e3e 30%,#6c6c6c 70%,#505050 100%); --ga: linear-gradient(317deg,#323131 30%,#5a5a5a 70%,#434141 100%); --gw: rgba(90,90,90,.20); }
/* 子比未直接提供的色系：按相同浅→深风格补齐 */
.btn-grad-cyan    { --g: linear-gradient(140deg,#039ab3 10%,#58dbcf 90%); --gh: linear-gradient(140deg,#028396 10%,#45c7bb 90%); --ga: linear-gradient(140deg,#017588 10%,#38b3a7 90%); --gw: rgba(3,154,179,.24); }
.btn-grad-pink    { --g: linear-gradient(135deg,#ff5e7f 30%,#ff967e 100%); --gh: linear-gradient(135deg,#f0486b 30%,#f57e6a 100%); --ga: linear-gradient(135deg,#d83a5b 30%,#e0695a 100%); --gw: rgba(255,94,127,.26); }
.btn-grad-gold    { --g: linear-gradient(25deg,#eabe7b 10%,#f5e3c7 70%,#edc788 100%); --gh: linear-gradient(25deg,#dcac63 10%,#ecd3b0 70%,#e0b76f 100%); --ga: linear-gradient(25deg,#c99950 10%,#ddc099 70%,#cfa258 100%); --gw: rgba(224,167,43,.26); --fg: #4a3600; }

/* 白底 + 品牌色文字：用于品牌色背景之上（如首页 CTA 的蓝色渐变底），0 圆角，可按需叠 .btn-pill */
.btn-white {
    --bs-btn-bg: #ffffff;
    --bs-btn-hover-bg: #f7f5ff;
    --bs-btn-active-bg: #efecfd;
    --bs-btn-border-color: #ffffff;
    --bs-btn-hover-border-color: #ffffff;
    --bs-btn-active-border-color: #ffffff;
    --bs-btn-color: var(--ng-primary);
    --bs-btn-hover-color: var(--ng-primary);
    --bs-btn-active-color: var(--ng-primary);
    background: #fff;
    color: var(--ng-primary);
    border: 1px solid #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .10);
    transition: box-shadow .35s ease, filter .2s ease;
}
.btn-white:hover { background: #f7f5ff; color: var(--ng-primary); box-shadow: 0 4px 14px rgba(0, 0, 0, .16); }
.btn-white:active { background: #efecfd; color: var(--ng-primary); box-shadow: inset 0 2px 5px rgba(0, 0, 0, .12); }
.btn-white:disabled, .btn-white.disabled { opacity: .6; box-shadow: none; }

/* 圆角「使用时定义」：默认 = 站点 0 圆角；下面两个工具类按需叠加。
   注册/登录这类主 CTA 用 .btn-pill（胶囊，已在文件上方定义）。 */
.btn-round { border-radius: var(--ng-radius-control) !important; }   /* 小圆角 4px */
.btn-square { border-radius: 0 !important; }                          /* 强制直角 */

/* ─── 全站按钮统一反馈（内容区 + 弹窗/抽屉/分页/回顶部；不含导航栏/侧栏/页脚）───
   悬停 = 各自规则（渐变加深 / 边框变色 / 底色浅蓝）+ 微亮；
   按下 = 统一变暗 + 内阴影；**一律不做位移/缩放**（站点规范）。 */
.btn:not(:disabled):active,
.uc-row-op:not(:disabled):active,
.auth-line-action:not(:disabled):active,
.auth-line-icon:not(:disabled):active,
.uc-xp-choice:not(:disabled):active,
.mailtest-chip:not(:disabled):active,
.uc-row-collapse:not(:disabled):active,
.uc-edit-actions .btn-save:active,
.uc-edit-actions .btn-cancel:active,
.uc-drawer-x:active,
.admin-modal-x:active,
.media-close-x:active,
.range-toggle button:active,
.page-link:active,
.btn-back-top:active,
.uc-filter .tab:active,
.auth-mode-tab:active {
    filter: brightness(.94);
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, .16);
}
/* 悬停微亮（叠加在各自改色之上，让反馈更明确） */
.uc-row-op:not(:disabled):hover,
.auth-line-action:not(:disabled):hover,
.auth-line-icon:not(:disabled):hover,
.uc-xp-choice:not(:disabled):hover,
.mailtest-chip:not(:disabled):hover,
.uc-row-collapse:not(:disabled):hover,
.uc-drawer-x:hover,
.admin-modal-x:hover,
.media-close-x:hover,
.range-toggle button:hover,
.page-link:hover,
.btn-back-top:hover,
.uc-filter .tab:hover {
    filter: brightness(.98);
}

/* 自定义按钮按下/悬停的亮度与阴影也缓慢过渡，避免瞬间变化 */
.btn,
.uc-row-op, .auth-line-action, .auth-line-icon, .uc-xp-choice,
.mailtest-chip, .uc-row-collapse, .uc-drawer-x, .admin-modal-x,
.media-close-x, .range-toggle button, .page-link, .btn-back-top,
.uc-filter .tab, .auth-mode-tab {
    transition: filter .2s ease, box-shadow .2s ease;
}
/* 纯文字折叠按钮原本没有 hover 反馈 */
.uc-row-collapse:hover { color: var(--ng-text); }
.uc-row-collapse:disabled { color: var(--ng-text-muted); cursor: default; }
/* 行内编辑的保存/取消（原先无 hover/active） */
.uc-edit-actions .btn-save:hover { background: var(--ng-primary-hover); }
.uc-edit-actions .btn-cancel:hover { border-color: var(--ng-primary); color: var(--ng-primary); }
/* 媒体库大图预览的关闭按钮（原先内联样式、无任何反馈） */
.media-close-x {
    position: absolute; top: 8px; right: 8px; width: 32px; height: 32px;
    border: none; background: rgba(0, 0, 0, .45); color: #fff; font-size: 16px;
    cursor: pointer; display: flex; align-items: center; justify-content: center;
    line-height: 1; z-index: 10; transition: background .15s ease;
}
.media-close-x:hover { background: rgba(0, 0, 0, .65); }

/* ─── 加载转圈（统一 Spinner）───
   用法：元素（按钮 / 文字按钮）加 .is-loading，内部放 <span class="sp"></span> + 进行中文案；
   推荐统一走 ui.js 的 Ui.loading(el, true, '发送中…')，它会记录并还原原文案与禁用态。
   颜色默认跟随文字色（currentColor）—— 白底按钮自动深色环、品牌渐变按钮自动白色环；
   需要指定颜色时，在元素上写 --sp-color（亮弧）与 --sp-track（轨道）。 */
@keyframes ng-spin {
    to { transform: rotate(360deg); }
}
.sp {
    display: inline-block;
    width: 1em;
    height: 1em;
    border: 2px solid var(--sp-track, rgba(0, 0, 0, .16));
    border-top-color: var(--sp-color, currentColor);
    border-radius: 50%;
    animation: ng-spin .7s linear infinite;
    vertical-align: -.125em;
    margin-right: .45em;
    flex: 0 0 auto;
}
/* 轨道跟随文字色（半透明）：无需为每种按钮单独配色 */
@supports (color: color-mix(in srgb, red 30%, transparent)) {
    .sp {
        border-color: color-mix(in srgb, var(--sp-color, currentColor) 22%, transparent);
        border-top-color: var(--sp-color, currentColor);
    }
}
/* 加载中：禁点。按钮本身还有 :disabled 的降透明；文字按钮（a）靠这条挡住重复点击 */
.is-loading { pointer-events: none; }
/* 尺寸档位：按钮内跟随字号（.sp 本体），卡片/网格用 --lg，整页加载占位用 --xl */
.sp--lg { width: 1.5rem; height: 1.5rem; }
.sp--xl { width: 2rem; height: 2rem; border-width: 3px; }
/* 品牌色：原本用 Bootstrap 的 text-primary，统一改为 .sp 后用它指定颜色 */
.sp-brand { --sp-color: var(--ng-primary); }
@media (prefers-reduced-motion: reduce) {
    /* 尊重系统「减少动效」：放慢而不是去掉（仍要能看出在等） */
    .sp { animation-duration: 2s; }
}

/* ─── 骨架屏 + 加载遮罩（用户中心 / 后台 SPA 切换内容区）───
   用法：内容区切换时先把 .sk 结构注入内容容器，加载完成后整体替换为真实内容。
   .sk-mask 是浮在骨架之上的淡白遮罩，中央放统一转圈（.sp）。 */
@keyframes sk-shimmer {
    100% { transform: translateX(100%); }
}
.sk {
    position: relative;
    overflow: hidden;
}
/* 骨架块本体：浅灰底 + 一道白色流光扫过（流光画在 ::after，省得每个块都写动画） */
.sk i,
.sk .sk-av {
    position: relative;
    display: block;
    overflow: hidden;
    background: #eaedf2;
}
.sk i::after,
.sk .sk-av::after {
    content: '';
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .75), transparent);
    animation: sk-shimmer 1.3s ease-in-out infinite;
}
/* 通用块：标题 / 副标题 */
.sk-h { width: 168px; height: 18px; margin-bottom: 10px; }
.sk-p { width: 264px; height: 12px; margin-bottom: 22px; }
/* 头像 + 两行文字 */
.sk-row { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.sk-av { width: 56px; height: 56px; border-radius: 50%; flex: 0 0 auto; }
.sk-lines { flex: 1 1 auto; }
.sk-lines i { height: 12px; margin-bottom: 9px; }
.sk-lines i:last-child { width: 42%; margin-bottom: 0; }
/* 卡片 + 卡内若干行 */
.sk-card { border: 1px solid var(--ng-border); padding: 18px 20px; margin-bottom: 16px; }
.sk-card i { height: 12px; margin-bottom: 12px; }
.sk-card i:last-child { margin-bottom: 0; }
.sk-w85 { width: 85%; }
.sk-w70 { width: 70%; }
.sk-w45 { width: 45%; }
/* 表格型骨架（后台列表页） */
.sk-trow { display: flex; gap: 16px; padding: 13px 0; border-bottom: 1px solid var(--ng-border); }
.sk-trow:last-child { border-bottom: 0; }
.sk-trow i { flex: 1 1 auto; height: 12px; margin: 0; }
.sk-trow i:first-child { flex: 0 0 140px; }
.sk-trow i:last-child { flex: 0 0 72px; }
/* 遮罩：淡白浮层 + 中央统一转圈 */
/* 加载幕：盖在内容之上（fixed，不依赖父级定位），真实页面结构保持可见 —— 腾讯控制台那种做法。
   仅用于 SPA 切换的等待期；参数位（数字/列表）自己的骨架块另有 .sk 系列。 */
.load-curtain {
    position: fixed;
    inset: 0;
    z-index: 1500;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, .45);
    transition: opacity .22s ease;      /* 页面内容拉取完淡出，而不是"啪"地消失 */
}
.load-curtain.is-hidden { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
    .load-curtain { transition: none; }
}

/* 遮罩：只用淡白薄薄压一层，避免把骨架糊成一团白雾（.72 太白，实测看不清骨架） */
.sk-mask {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, .35);
}
/* ── 叶子块尺寸（灰底与流光来自 .sk i，所以块一律用 <i> 且必须在 .sk 容器内）──
   外层布局一律复用页面自己的类名（.uc-card-hd / .uc-row / .uc-item / .uc-msg / .app-card /
   .uc-hero / .stats / .admin-card），内边距与分隔线因此与真实页面完全一致；这里只定义叶子灰块尺寸。 */
.sk-h    { width: 200px; height: 20px; }
.sk-hd   { width: 120px; height: 15px; }
.sk-sub  { width: 300px; height: 12px; }
.sk-line { width: 100%; height: 12px; }
.sk-line2{ width: 68%;  height: 12px; }
.sk-line3{ width: 45%;  height: 12px; }
.sk-av   { width: 56px; height: 56px; border-radius: 50%; flex: 0 0 auto; }
.sk-av-lg{ width: 72px; height: 72px; }
.sk-ico  { width: 38px; height: 38px; border-radius: 8px; flex: 0 0 auto; }
.sk-logo { width: 48px; height: 48px; border-radius: 50%; flex: 0 0 auto; }
.sk-val  { width: 72px; height: 12px; flex: 0 0 72px; }
.sk-btn  { width: 76px; height: 30px; flex: 0 0 auto; }
.sk-stat { width: 56px; height: 32px; }
/* 行内文本列：撑满剩余宽度，让内部 100% 宽的灰条有确定参照（对应真实 .uc-row-meta）*/
.sk-col  { flex: 1 1 auto; min-width: 0; }
.sk-col > i + i { margin-top: 9px; }
/* 表格骨架内边距（.admin-card 自身不带 padding）*/
.sk-pad  { padding: 10px 16px; }
.sk-table { display: block; }
/* 后台表格行：三段式 */
.sk-trow { display: flex; gap: 16px; padding: 13px 0; border-bottom: 1px solid var(--ng-border); }
.sk-trow:last-child { border-bottom: 0; }
.sk-trow i { flex: 1 1 auto; height: 12px; margin: 0; }
.sk-trow i:first-child { flex: 0 0 140px; }
.sk-trow i:last-child { flex: 0 0 72px; }

/* 消息行骨架（对应真实 .uc-msg）：内边距与真实行一致，灰块不贴卡片边框 */
.sk-msg { display: flex; align-items: flex-start; gap: 14px; padding: 16px 22px; border-bottom: 1px solid var(--ng-border); }
.sk-msg:last-child { border-bottom: 0; }
/* 卡片标题骨架（小号）*/
.sk-h-sm { width: 120px; height: 14px; }
/* 行内值骨架（.uc-row-val 这类"宽度由内容撑开"的容器内用）：
   必须定宽 + inline-block —— 用 .sk-line 的 width:100% 会因父级宽度依赖自身而退化成 auto → 宽度 0（整条不可见）。
   行内块还能吃父级的 text-align:right，右对齐与真实内容一致。 */
.sk .sk-inline { display: inline-block; width: 132px; height: 12px; }
@media (prefers-reduced-motion: reduce) {
    /* 减少动效时不闪流光，骨架静态显示 */
    .sk i::after,
    .sk .sk-av::after { animation: none; }
}

/* ─── 卡片 ─── */
.card {
    border: 1px solid var(--ng-border);
    background: #fff;
    box-shadow: var(--ng-shadow-sm);
    transition: box-shadow 0.2s, transform 0.2s;
}
.card-header {
    background: transparent;
    border-bottom: 1px solid var(--ng-border);
    padding: 16px 20px;
    font-weight: 500;
}

/* ─── 表单 ─── */
.form-control {
    font-size: 14px;
    padding: 8px 14px;
    border: 1px solid var(--ng-border);
    transition: border-color 0.2s, box-shadow 0.2s;
}
.form-control:focus, .form-select:focus {
    border-color: var(--ng-primary);
    box-shadow: var(--ng-focus-ring);
}
.btn:focus-visible { box-shadow: 0 0 0 3px rgba(108, 92, 231, 0.25); outline: none; }
.form-label {
    font-size: 13px;
    font-weight: 500;
    color: var(--ng-text);
    margin-bottom: 6px;
}

/* ─── 链接 ─── */
a { color: var(--ng-primary); text-decoration: none; }
a:hover { color: var(--ng-primary-hover); }

/* ─── Hero 区（云平台风格） ─── */
.hero-section {
    background: linear-gradient(180deg, #f6f4fe 0%, #efecfd 40%, #fff 100%);
    padding: 80px 0 60px;
    text-align: center;
    position: relative;
    overflow: hidden;
}
.hero-section::before {
    content: '';
    position: absolute;
    top: -50%;
    left: -50%;
    width: 200%;
    height: 200%;
    background: radial-gradient(ellipse at 30% 50%, rgba(108,92,231,0.03) 0%, transparent 60%),
                radial-gradient(ellipse at 70% 50%, rgba(77,127,255,0.03) 0%, transparent 60%);
    pointer-events: none;
}
.hero-section h1 {
    font-size: 38px;
    font-weight: 700;
    color: var(--ng-text);
    margin-bottom: 16px;
    position: relative;
}
.hero-section .hero-subtitle {
    font-size: 18px;
    color: var(--ng-text-secondary);
    max-width: 600px;
    margin: 0 auto 36px;
    line-height: 1.7;
    position: relative;
}
.hero-section .btn-hero {
    position: relative;
}

/* ─── 功能卡片（首页） ─── */
.feature-card {
    border: 1px solid var(--ng-border);
    background: #fff;
    padding: 36px 28px;
    text-align: center;
    transition: all 0.3s;
    box-shadow: var(--ng-shadow-sm);
}
.feature-card:hover { border-color: var(--ng-primary); box-shadow: var(--ng-shadow-lg); }
.feature-card .icon-wrap {
    width: 56px;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto 20px;
    font-size: 26px;
    color: var(--ng-primary);
}
.feature-card h5 {
    font-size: 16px;
    font-weight: 600;
    margin-bottom: 10px;
}
.feature-card p {
    font-size: 13px;
    color: var(--ng-text-secondary);
    margin: 0;
    line-height: 1.7;
}

/* ─── 后台菜单 ─── */
.sidebar-nav .nav-link {
    color: var(--ng-text-secondary);
    padding: 10px 18px;
    font-size: 14px;
    border-radius: 0;
    transition: all 0.2s;
}
.sidebar-nav .nav-link:hover {
    background: var(--ng-primary-bg);
    color: var(--ng-primary);
}
.sidebar-nav .nav-link.active {
    background: var(--ng-primary-bg);
    color: var(--ng-primary);
    font-weight: 600;
    border-left: 3px solid var(--ng-primary);
}
.sidebar-nav .nav-link i {
    margin-right: 10px;
    width: 18px;
    text-align: center;
    font-size: 15px;
}

/* ─── 后台表格增强 ─── */
.admin-table {
    margin-bottom: 0;
    border-collapse: separate;
    border-spacing: 0;
}
.admin-table thead th {
    background: #f7f8fa;
    font-size: 12px;
    font-weight: 600;
    color: var(--ng-text-muted);
    padding: 10px 14px;
    border-bottom: 2px solid var(--ng-border);
    white-space: nowrap;
    text-transform: uppercase;
    letter-spacing: 0.3px;
}
.admin-table tbody td {
    padding: 10px 14px;
    font-size: 13px;
    border-bottom: 1px solid var(--ng-border);
    vertical-align: middle;
}
.admin-table tbody tr:hover {
    background: #fafbfc;
}
.admin-table tbody tr:last-child td {
    border-bottom: none;
}

/* ─── 后台卡片统一风格 ─── */
.admin-card {
    background: #fff;
    border: 1px solid var(--ng-border);
    box-shadow: var(--ng-shadow-sm);
}
.admin-card .card-header {
    background: #fafbfc;
    padding: 12px 20px;
    border-bottom: 1px solid var(--ng-border);
    font-size: 13px;
    font-weight: 600;
}
.admin-card .card-body {
    padding: 20px;
}

/* ─── 状态指示器 ─── */
.status-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    margin-right: 4px;
    vertical-align: middle;
}
.status-dot.active {
    background: #22c55e;
}
.status-dot.inactive {
    background: #d1d5db;
}

/* ─── 表单分区 ─── */
.form-section {
    background: #fff;
    border: 1px solid var(--ng-border);
    padding: 20px 24px;
    box-shadow: var(--ng-shadow-sm);
}
.form-section h6 {
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 16px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--ng-border);
    color: var(--ng-text);
}

/* ─── 后台页面内容间距 ─── */
.admin-content-area > * + * {
    margin-top: 20px;
}

/* ─── 统计卡片（后台） ─── */
.stat-card {
    background: #fff;
    border: 1px solid var(--ng-border);
    padding: 24px;
    box-shadow: var(--ng-shadow-sm);
    transition: box-shadow 0.2s;
}
.stat-card .stat-number {
    font-size: 30px;
    font-weight: 700;
    color: var(--ng-primary);
    line-height: 1.2;
}
.stat-card .stat-label {
    font-size: 13px;
    color: var(--ng-text-secondary);
    margin-top: 4px;
}

/* ─── 表格 ─── */
.table {
    margin: 0;
    font-size: 13px;
}
.table th {
    border-top: none;
    border-bottom: 1px solid var(--ng-border);
    font-weight: 600;
    font-size: 12px;
    color: var(--ng-text-secondary);
    padding: 12px 12px;
    background: #fafbfc;
}
.table td {
    border-color: var(--ng-border);
    padding: 12px;
    vertical-align: middle;
}

/* ═══════════════════════════════════════
   认证页面（登录 / 注册 / 找回密码）
   PC：双栏 —— 左栏品牌区（≥992px 显示，纯文字无 logo 图）+ 右栏表单卡贴容器右侧；
   移动端：单列、卡片居中
   .auth-card 自包含，不依赖 .auth-page 外壳（「注册已关闭」提示卡仍直接复用）
   背景图：由 .auth-page 外壳带图（原图铺满清晰显示）——
          登录 login.jpg / 注册 register.jpg / 找回密码沿用登录那张（2026-09-18 起）
   找回密码页的外壳只借背景与居中，卡片仍是自包含平面卡，
   故另有一条 `.auth-page.auth-page--reset .auth-card` 把 padding / margin 复位。
   ═══════════════════════════════════════ */

/* 外壳：内容区撑满视口高度让卡片垂直居中（高度链见文件顶部「页面骨架」）；
   :has() 不支持时退化为普通上边距，不影响其他页面 */
.auth-page {
    flex: 1 0 auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 48px 0;
    /* 背景图：原图铺满、清晰显示（不加遮罩）。具体图片由页面修饰类给出 */
    --auth-bg: none;
    /* 左栏品牌区最大宽度：整栏靠右限宽后，这个值决定它离容器左边的距离 ——
       **值越小 → 整栏越靠右**；**值越大 → 越靠左**（等于列宽时基本贴容器左边）。
       以 1400 视口为例（容器 1320，左列右边界 744）：520 → 文字左边界 224；
       460 → 284；420 → 324。
       2026-09-13 用户最终要"品牌区整体左移"，故从 420 调到 520（比上一版左移 60px）。 */
    --auth-aside-w: 520px;
    /* 双栏整体左右偏移（仅 ≥992px 生效）：值 = 整个内容区从容器右边往左缩进的量，
       左右两栏会**一起**左移同样距离（卡片的右边缘也跟着离开容器右边线）。
       2026-09-13 用户「左右一起往左」→ 40px。 */
    --auth-grid-x: 40px;
    /* 左栏品牌区的垂直偏移（仅 ≥992px，且只影响品牌区，卡片不动）：
       **负数 = 上移，正数 = 下移**。网格本身是 align-items:center 居中的，
       这里只是把整栏相对居中位置再挪一点。2026-09-19 用户「品牌区整体上移一点」→ -24px。 */
    --auth-aside-y: -24px;
    background-color: var(--ng-bg);
    background-image: var(--auth-bg);
    background-size: cover;
    background-position: center center;
    background-repeat: no-repeat;
}
/* 各页背景图（3840×2560 原图）。图片为浅色极简几何，深色文字直接可读，无需反色或遮罩 */
.auth-page--login { --auth-bg: url("../images/bg/login.jpg"); }
.auth-page--register { --auth-bg: url("../images/bg/register.jpg"); }
/* 找回密码页：背景沿用登录页那张（2026-09-18 用户要求） */
.auth-page--reset { --auth-bg: url("../images/bg/login.jpg"); }

/* 找回密码页的卡片已改成与登录/注册一致的三段式（head + body），
   所以不再需要复位 padding / margin —— 直接沿用上面的 `.auth-page .auth-card` 即可。 */

#appContent:has(> .auth-page) {
    display: flex;
    flex-direction: column;
}

/* ─── 404 页：与认证页共用同一条「撑满内容区」链路（但不居中，见 .err404）───
   整页只有三块：插图 → 一行提示（中上英下）→ 两个按钮，全部水平居中。
   footer 在首屏之外，向下滚动才可见（与认证页一致）。 */
#appContent:has(> .err404) { display: flex; flex-direction: column; }
.err404 {
    flex: 1 0 auto;              /* 撑满 #appContent —— 高度由 body → main → #appContent 那条链保证 */
    display: flex;
    flex-direction: column;
    align-items: center;
    /* 顶部起排、且贴着导航（垂直居中会落在内容区正中、视觉偏低）。
       上间距用固定 28px 而非 vh —— 内容区本来就是「视口 − 导航」，固定值在大屏上也保持同样的"贴顶"感。 */
    justify-content: flex-start;
    text-align: center;
    padding: 28px 16px 48px;
}
/* 插图原始比例 400×240。上限 600px（本页内容区是**通栏**、没有 .container 收窄，
   所以不能照抄子比的 500px 绝对值）。窄屏按可用宽度 80% 收缩；高度 = 宽度 × 0.6（600 → 360px）。 */
.err404-img { width: 80%; max-width: 600px; height: auto; }
.err404-text { margin: 24px 0 0; font-size: 15px; color: var(--ng-text-muted); }
/* 英文副行：同色、小一号，与中文同段（中文在上、英文在下） */
.err404-text-en { display: block; margin-top: 4px; font-size: 13px; }
.err404-actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin-top: 28px; }
.auth-page .auth-grid {
    display: grid;
    grid-template-columns: 1fr;      /* 移动端：单列 */
    align-items: center;
    width: 100%;
}
.auth-page .auth-panel { display: flex; justify-content: center; }

/* ─── 左栏品牌区（仅 PC 显示；不放 logo 图，品牌识别交给文字）───
   内容 = 大标题 → 副文案 → 要点列表（顶部的品牌名文字行已于 2026-09-18 按用户要求去掉）；
   整栏在网格里垂直居中（.auth-grid 的 align-items:center）。
   排版：整栏靠右收窄（不贴容器左边缘，见下方 PC 媒体查询的 --auth-aside-w），
   标题用品牌色承担视觉重心，副文案与要点用次要色，形成"标题 → 说明 → 要点"三级。 */
.auth-page .auth-aside { display: none; }
.auth-aside-title {
    font-size: 36px;
    font-weight: 800;
    line-height: 1.24;
    letter-spacing: -.5px;
    color: var(--ng-primary);        /* 品牌色高亮 */
    margin-bottom: 16px;
}
.auth-aside-sub {
    font-size: 15px;
    color: var(--ng-text-secondary);
    line-height: 1.8;
    max-width: 420px;
    margin-bottom: 24px;
}
.auth-aside-list { list-style: none; margin: 0; padding: 0; }
.auth-aside-list li {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    color: var(--ng-text-secondary);
    padding: 8px 0;
}
.auth-aside-list li i { flex: 0 0 auto; width: 18px; text-align: center; font-size: 16px; color: var(--ng-primary); }

/* PC：双栏（左品牌区 + 右表单卡），表单卡贴容器右侧 */
@media (min-width: 992px) {
    /* 右列保留 minmax(420px,520px)。实测副作用（知悉即可，勿随手改）：
       列宽取到 520 而卡片 max-width 只有 400 → 多出 120px 死空间，品牌文字右端
       到卡片左端恒定 176px（120 + gap 56），与视口无关。这个"空隙"正是品牌区
       看起来偏左的来源，用户要的就是偏左，故保留。 */
    .auth-page .auth-grid {
        grid-template-columns: minmax(0, 1fr) minmax(420px, 520px);
        gap: 56px;
        /* 左右两栏一起左移：给网格容器加右内边距，内容盒整体变窄并左移，
           卡片不再贴容器右边缘、左栏也跟着左移同样的距离。 */
        padding-right: var(--auth-grid-x);
    }
    /* 整栏在网格列内靠右限宽：不限宽时 1fr 列很宽，正文会被拉到容器最左。
       --auth-aside-w 越小 → 整栏越靠右；越大 → 越靠左（大到等于列宽即贴容器左边）。 */
    .auth-page .auth-aside {
        display: block;
        width: 100%;
        max-width: var(--auth-aside-w);
        margin-left: auto;
        /* 相对居中位置再挪一点（相对定位，不影响卡片与网格） */
        position: relative;
        top: var(--auth-aside-y);
    }
    .auth-page .auth-panel { justify-content: flex-end; }
}

/* ─── 卡片本体（独立用法：找回密码页 / 提示卡，保留自身内边距）─── */
.auth-card {
    width: 100%;
    max-width: 400px;      /* 2026-09-13 用户要求卡片长度收紧：420 → 412 → 400（本轮再 −12） */
    margin: 64px auto;
    padding: 36px 32px;
    background: #fff;
    border: 1px solid var(--ng-border);
}

/* ─── 认证页卡片：标题 + 内容 + 链接，高度由内容决定 ───
   ① .auth-head   顶部标题区：左对齐标题文字（2026-09-18 起，原 logo 与顶部那条分割线撤掉）
   ② .auth-body   中部内容区：输入内容在其中垂直居中，主按钮跟在内容后面
   ③ .auth-links  底部链接区（忘记密码 / 立即注册…）
   现在只剩内容区与链接区之间一条通栏 .auth-rule；卡片内边距为 0，分割线自然通栏。
   **不锁卡片高度**：卡片按内容自然高度收合，靠 .auth-page 的 justify-content:center 在页面里上下居中。 */
.auth-page .auth-card {
    position: relative;          /* 右上角的 .auth-mode-tab 以卡片为定位基准 */
    display: flex;
    flex-direction: column;
    margin-top: 0;
    margin-bottom: 0;
    padding: 0;
    /* 阴影：默认一档、悬停再浮起一档。
       注意别退回"默认最重、悬停变轻"——那样悬停时卡片反而像沉下去了。
       成因：`.card:hover` 与 `.auth-page .auth-card` 优先级同为 (0,2,0)，
       后者在源码里更靠前，所以悬停时会被 `.card:hover` 的 var(--ng-shadow) 反压，
       必须显式写一条 :hover 规则把它盖回来。 */
    box-shadow: var(--ng-shadow);
}
.auth-page .auth-card:hover { box-shadow: 0 16px 40px rgba(16, 24, 40, .10); }
/* 用 [hidden] 切换卡片时，必须压掉上面的 display:flex，否则 hidden 会被覆盖而失效 */
.auth-card[hidden] { display: none !important; }
@media (min-width: 992px) {
    .auth-page .auth-card { margin-left: auto; margin-right: 0; }
}

/* ─── 卡片切换：只让内容淡入（2026-09-18 改，配合 signin.php 的 setMode()）───
   卡片本身即时显隐（背景与阴影不参与动画），只给它的直接子元素播一段淡入 ——
   这样切换时不会出现"整卡淡出 → 空白 → 重画"的闪烁，也不会先缩一下。
   JS 只负责加/去 .is-entering，不做定时，所以这里改时长不必同步改 JS。 */
@keyframes authContentIn { from { opacity: 0; } to { opacity: 1; } }
.auth-card.is-entering > *,
.auth-flow.is-entering > * { animation: authContentIn .2s ease; }
@media (prefers-reduced-motion: reduce) {
    .auth-card.is-entering > *,
    .auth-flow.is-entering > * { animation: none; }
}

/* 通栏分割线：从中间向两侧淡出（两端透明、中间实色）
   Bootstrap 的 hr 规则带 opacity:.25 + border-top，这里改成用 background 画线，
   顺手把 opacity 归位、border 清掉，否则这条线要么淡到看不见、要么被 border 叠出一条实线。 */
.auth-rule {
    flex: 0 0 auto;
    height: 1px;
    margin: 0;
    opacity: 1;
    border: 0;
    background: linear-gradient(90deg, transparent 0%, var(--ng-border) 50%, transparent 100%);
}

/* ─── ① 顶部标题区（2026-09-18 起：撤掉 logo 与顶部那条分割线，改为左对齐标题）───
   .auth-head 只给上/左内边距，下内边距为 0，标题与内容区之间的间距交给 .auth-body 的上内边距。
   注册/登录两页的卡片不再放 logo，品牌识别交给左栏品牌区（移动端就只剩这个标题文字）。 */
.auth-head { flex: 0 0 auto; padding: 28px 32px 0; }
.auth-title {
    margin: 0;
    font-size: 28px;
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: -.3px;
    color: var(--ng-text);
    text-align: left;
}
/* 标题下方、左对齐的小链接区（注册页「已有账号？立即登录」；登录页「没有账号？立即注册」「忘记密码？」）。
   横向排列、可换行；.auth-head 是普通块级容器，左端自动与标题左边缘、下方表单字段对齐。 */
.auth-head-links {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    margin-top: 10px;
    font-size: 13px;
    line-height: 1.5;
}
.auth-head-links a {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    color: var(--ng-text-secondary);
    text-decoration: none;
    transition: color .2s ease;
}
.auth-head-links a:hover { color: var(--ng-primary); }
.auth-head-links a i { font-size: 12px; }

/* ─── 登录方式切换 = 卡片右上角的斜边标签（2026-09-18，样式照用户给的参考图）───
   浅蓝底 + 左侧斜边（clip-path 最后那个 x = 左下角内缩量，决定斜边角度：约 36°），
   标签贴卡片右上角：顶边与卡片顶边齐平、右边与卡片右边缘齐平。
   装饰画在 ::before 这一层（isolate 建栈，避免它掉到卡片白色背景之后），文字浮在其上。
   左内边距 30px 要大于文字所在高度处的斜边内缩量，否则文字会被斜边切到。 */
.auth-mode-tab {
    position: absolute;
    top: 0;
    right: 0;
    z-index: 1;
    isolation: isolate;
    /* 标签底色 = 主题色同类的淡色；调这一个数即可（越大越接近主题色、白字越清楚） */
    --tab-fill: color-mix(in srgb, var(--ng-primary) 75%, #fff);
    border: 0;
    background: none;
    padding: 9px 16px 9px 30px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.4;
    color: #fff;
    cursor: pointer;
    white-space: nowrap;
}
.auth-mode-tab::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--tab-fill);
    clip-path: polygon(0 0, 100% 0, 100% 100%, 26px 100%);
    transition: background-color .2s ease;
}
/* 悬停：整块变成主题色 */
.auth-mode-tab:hover::before { background: var(--ng-primary); }
/* .auth-logo 仍被 views/oauth/authorize.php 使用，勿删。
   main-logo 是 900×400、内容只占 x 75~828 / y 62~337（上下各约 15.5% 透明），
   所以 img 的 height 不等于肉眼高度（height:54px 时可见约 37px）；换成裁边图后要重算。 */
.auth-logo { display: flex; justify-content: center; }
.auth-logo img { height: 54px; width: auto; display: block; }

/* ─── ② 中部内容区 ───
   .auth-flow  = 表单容器（密码登录 / 验证码登录 / 注册单页表单；一次只显示一份）
   .auth-fields= 输入行分组（可伸缩，卡片有余量时整组垂直居中）
   卡片不锁高度，正常没有余量；一旦外层给了高度（如某页要撑满），这里会自动居中。 */
.auth-body {
    display: flex;
    flex-direction: column;
    /* 上内边距 22 → 28px：用户要求「顶部分割线下方加 6px 空隙」（分割线下的第一段留白就是这里） */
    padding: 28px 32px 22px;
}
.auth-body > form,
.auth-body > .auth-flow {
    display: flex;
    flex-direction: column;
}
.auth-fields {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
}
/* 输入行不被压缩：高度不够时宁可外溢，也不要把标签 / 输入框挤变形 */
.auth-fields > * { flex: 0 0 auto; }
/* 最后一行的下外边距交给主按钮的 margin-top 负责，否则居中留白会偏下不均 */
.auth-fields > *:last-child { margin-bottom: 0; }
/* 内容区里除输入分组外的元素都不参与伸缩 */
.auth-flow > .auth-submit,
.auth-flow > .auth-msg { flex: 0 0 auto; }

/* ─── 选项卡（授权管理页 profile/apps.php 复用 .auth-tab 作钩子）───
   该页的视觉主要写在内联样式里，类规则只补内联没覆盖的部分：
   底部指示线与容器边框的 1px 叠合、字体继承、过渡。勿删，否则指示线会错位 1px。 */
.auth-tab {
    min-width: 0;
    margin-bottom: -1px;
    font-family: inherit;
    line-height: 1.5;
    cursor: pointer;
    transition: color .2s ease, border-color .2s ease;
}

/* ─── 填写线（下划线式输入行）───
   .auth-line      = 字段容器（小标签 + 输入行）
   .auth-line-box  = 输入行本体，下划线画在这一层；聚焦时整行变品牌蓝
   行内右侧可放小字动作（密码登录 / 验证码登录 / 获取验证码）与图标按钮（密码显隐） */
.auth-line { margin-bottom: 16px; }
.auth-line .form-label {
    font-size: 12px;
    color: var(--ng-text-muted);
    margin-bottom: 2px;
}
.auth-line-box {
    display: flex;
    align-items: center;
    gap: 10px;
    border-bottom: 1px solid var(--ng-border);
    transition: border-color .2s ease;
}
/* 有输入内容或悬停/聚焦时整行高亮：鼠标移到标签或输入行上就变品牌蓝 */
.auth-line:hover .auth-line-box,
.auth-line-box:hover,
.auth-line-box:focus-within { border-bottom-color: var(--ng-primary); }
.auth-line-box .form-control {
    flex: 1 1 auto;
    width: auto;          /* 压掉 Bootstrap 的 width:100%，交给 flex 分配剩余宽度 */
    min-width: 0;
    border: 0;
    border-radius: 0;
    padding: 8px 0;
    background: transparent;
    box-shadow: none;
    font-size: 14px;
}
.auth-line-box .form-control:focus { border: 0; box-shadow: none; }
.auth-line-box .form-control::placeholder { color: var(--ng-text-muted); }

/* 行内右侧小字动作 */
.auth-line-action {
    flex: 0 0 auto;
    border: 0;
    background: none;
    padding: 0;
    font-family: inherit;
    font-size: 13px;
    line-height: 1;
    color: var(--ng-primary);
    cursor: pointer;
    white-space: nowrap;
    transition: color .2s ease;
}
.auth-line-action:hover { color: var(--ng-primary-hover); }
.auth-line-action:disabled { color: var(--ng-text-muted); cursor: default; }
/* 登录方式切换（验证码登录 / 密码登录）：不在输入行里，而是换到「下划线下方」单独一行，
   紧贴下划线 + 靠右。.auth-line 是普通块级容器，所以靠右用 margin-left:auto 而不是 text-align。
   位置微调：第 1 个值 = 与下划线的间距；第 2 个值 = 距下划线右端的偏移
   （0 = 与右端齐平，正数往左内缩，负数往右超出下划线）。
   text-align:right 是兜底：万一某天 width 被覆盖成撑满整行，文字也不会跑到中间去。
   注意：2026-09-18 起两个切换按钮已移到卡片底部的 .auth-links（分割线下方第一位），
   这条选择器当前没有匹配项，先保留以备挪回。 */
.auth-line > .auth-line-action {
    display: block;
    width: fit-content;
    margin: 6px 0 0 auto;
    text-align: right;
}

/* 行内右侧图标按钮（密码显隐） */
.auth-line-icon {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    background: none;
    padding: 0;
    color: var(--ng-text-muted);
    font-size: 15px;
    cursor: pointer;
    transition: color .2s ease;
}
.auth-line-icon:hover { color: var(--ng-primary); }

/* 卡片主按钮（跟在输入行之后）：上间距即「按钮上方的空隙」，16 → 22px（用户要求 +6px） */
.auth-submit { flex: 0 0 auto; margin-top: 22px; }

/* 授权页的「并列选项」按钮组（第三方绑定页的「新建账号 / 绑定已有账号」）：
   按钮沿用用户中心 .uc-xp-choice 的方框样式（白底 + 描边、无圆角），这里排成**两行全宽**并补上组外间距。
   之所以不套 .auth-submit：那是「主按钮」的间距类，而这里是一组地位平等的选项。 */
.auth-choice { display: flex; flex-direction: column; gap: 10px; margin-top: 22px; }
.auth-choice form { display: block; }
.auth-choice .uc-xp-choice { width: 100%; justify-content: center; }

/* 授权页里跟在「账号卡片」下面的说明文字（第三方绑定页的「选择如何继续…」）：
   .uc-sec-sub 自带 margin: 0 0 6px（简写，把上边距也一起置 0），只有下边距，会紧贴上方卡片。
   注意必须用**复合选择器**：.auth-hint 单独写与 .uc-sec-sub 同优先级（都是 0,1,0），
   而 .uc-sec-sub 在样式表里更靠后 —— 只靠 .auth-hint 会被它覆盖掉（本文件里同类的覆盖
   也是这么处理的：.uc-page-head .uc-sec-sub）。 */
.uc-sec-sub.auth-hint { margin-top: 20px; }

/* ─── ③ 底部链接区（内容贴底）─── */
.auth-links {
    flex: 0 0 auto;
    padding: 18px 32px 26px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    gap: 12px;
    font-size: 13px;
}
.auth-links a {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    color: var(--ng-text-secondary);
    text-decoration: none;
    transition: color .2s ease;
}
.auth-links a:hover { color: var(--ng-primary); }
.auth-links a i { font-size: 12px; }
/* 链接区里也可能放按钮（如注册页 Step2 的「更换账号」）——
   注意不要给按钮写 display，否则 [hidden] 会失效 */
.auth-links button {
    border: 0;
    background: none;
    padding: 0;
    font-family: inherit;
    font-size: 13px;
    color: var(--ng-text-secondary);
    cursor: pointer;
    transition: color .2s ease;
}
.auth-links button:hover { color: var(--ng-primary); }

/* ─── 底部条款区（注册页）───
   通栏分割线下方整行放协议勾选；上下内边距与 .auth-links 对齐，保证两页底部条视觉一致。 */
.auth-terms-bar {
    flex: 0 0 auto;
    padding: 18px 32px 26px;
}
/* 内边距由容器给，label 自身不再留上边距；整行居中（用 fit-content + auto 外边距，
   比 justify-content:center 稳：文字换行时仍左对齐，只有整块居中） */
.auth-terms-bar .auth-terms { margin: 0 auto; width: fit-content; }

/* ─── 提示信息（纯文字；状态与颜色由 class 切换，不再内联写死）───
   提示行不放图标：图标与文字的对齐只能靠图标字体自身的度量做光学校正，跨页/跨图标
   表现不稳定（曾出现 signin 偏高、signup 正常）。改成纯文字后不存在对齐问题，
   也无需再维护 `.auth-msg > i` 那套居中规则。提示行本身是普通块级，行高继承即可。 */
.auth-msg {
    display: none;
    margin-top: 8px;
    font-size: 12px;
    line-height: 1.55;
}
.auth-msg.show { display: block; }
.auth-msg.is-hint { color: var(--ng-text-muted); }
.auth-msg.is-error { color: var(--ng-danger); }
.auth-msg.is-ok { color: var(--ng-success); }

/* ─── 社交账号登录（形态照子比 .social_loginbar / .social-login-item）───
   分隔文字 + **直接可见的图标按钮** —— 官方要求「QQ登录」标识必须易于用户查找，故不做二级入口。
   图标用它自带的 d-qq SVG（单色 path、跟随 currentColor），不为此引入 FontAwesome。
   hover/active 用本站统一反馈（变色 + 压暗），不做位移/缩放。 */
.auth-social-sep {
    display: flex; align-items: center; gap: 12px;
    margin: 18px 0 12px; font-size: 12px; color: var(--ng-text-muted);
}
.auth-social-sep::before, .auth-social-sep::after {
    content: ''; flex: 1 1 auto; height: 1px; background: var(--ng-border);
}
.auth-social { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }

/* 平台按钮：子比同款 —— 32×32 圆形、品牌色底、白色图标、**不带文字**（子比默认形态，`border-radius:50px` 同值）。
   官方规范里"小图标"本身是允许的一档，加文字只是"建议"；若审核真挑这条，加回一行文字即可。
   可发现性靠上面的「社交账号登录」分隔文字 + 按钮 title/aria-label。 */
.auth-social-item {
    --ng-social-bg: #1296db;          /* 默认底色；各平台由 .auth-social-item.<type> 覆盖 */
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; padding: 0;
    border: 0; border-radius: 50%;
    background: var(--ng-social-bg); color: #fff;
    cursor: pointer;
    transition: filter .12s ease, box-shadow .12s ease;
}
/* 各平台品牌底色（取自子比 .social-login-item.<type>；抖音子比未定义，用其品牌黑） */
.auth-social-item.qq       { --ng-social-bg: #1296db; }
.auth-social-item.weixin   { --ng-social-bg: #24b76a; }
.auth-social-item.weibo    { --ng-social-bg: #ea5d5c; }
.auth-social-item.douyin   { --ng-social-bg: #010101; }
.auth-social-item.gitee    { --ng-social-bg: #c2292f; }
.auth-social-item.github   { --ng-social-bg: #505050; }   /* 之前漏写 -> 掉回默认 QQ 蓝，看着"配色异常" */
.auth-social-item.alipay   { --ng-social-bg: #1677ff; }   /* 子比与 QQ 同为 #1296db，改用支付宝官方蓝以区分 */
.auth-social-item.baidu    { --ng-social-bg: #4e6ef2; }
.auth-social-item.dingtalk { --ng-social-bg: #399ffb; }
.auth-social-item.xiaomi   { --ng-social-bg: #ff6901; }
.auth-social-item.apple    { --ng-social-bg: #454545; }
.auth-social-item .icon { width: 18px; height: 18px; fill: currentColor; flex: 0 0 auto; }
.auth-social-item:hover { filter: brightness(1.08); }      /* 各平台底色不同，所以统一「提亮」而不改底色 */
.auth-social-item:active {
    filter: brightness(.94);
    box-shadow: inset 0 2px 4px rgba(0, 0, 0, .08);
}
.auth-social-item:focus-visible { outline: 0; box-shadow: 0 0 0 3px rgba(18, 183, 245, .25); }

.auth-social-item .bi { font-size: 18px; line-height: 1; }   /* GitHub 走 Bootstrap Icons（子比没有它的 SVG） */

/* 「更多」按钮：描边圆，与平台按钮区分开（一眼看出是控件、不是平台）+ 展开的气泡 */
.auth-social-more { position: relative; display: inline-flex; }
.auth-social-more-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; padding: 0;
    background: #fff; border: 1px solid var(--ng-border); border-radius: 50%;
    color: var(--ng-text-muted); font-size: 14px; cursor: pointer;
    transition: color .15s ease, border-color .15s ease, filter .12s ease;
}
.auth-social-more-btn:hover { color: var(--ng-primary); border-color: var(--ng-primary); }
.auth-social-more-btn:active { filter: brightness(.94); }
.auth-social-more-btn[aria-expanded="true"] { color: var(--ng-primary); border-color: var(--ng-primary); }
/* 气泡：居中挂在按钮下方，最多 4 个一行（7 家排成 4 + 3）。
   transform 只用来定位居中，不是 hover 动效（站点禁的是"位移/缩放"式的悬停反馈）。 */
.auth-social-pop {
    position: absolute; z-index: 20; top: calc(100% + 10px); left: 50%;
    display: flex; flex-wrap: wrap; gap: 10px; justify-content: center;
    width: max-content; max-width: 200px; padding: 10px;
    background: #fff; border: 1px solid var(--ng-border); box-shadow: var(--ng-shadow-sm);
    transform: translateX(-50%);
    /* 常驻渲染 + opacity/visibility 切换：display 切换无法过渡，做不出淡入淡出。
       关闭时把 visibility 延迟到淡出播完再隐藏，避免"啪"地消失。 */
    opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity .18s ease, visibility 0s linear .18s;
}
.auth-social-pop.open {
    opacity: 1; visibility: visible; pointer-events: auto;
    transition: opacity .18s ease;
}

/* ─── 第三方绑定页 / 邮箱绑定页（与登录、注册同架构）─── */
.auth-bound {
    display: flex; align-items: center; gap: 12px;
    padding: 12px; background: var(--ng-bg-white); border: 1px solid var(--ng-border);
}
.auth-bound-logo {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; flex: 0 0 auto; border-radius: 50%;
    background: var(--ng-primary-bg); color: var(--ng-primary); font-size: 18px; overflow: hidden;
}
.auth-bound-logo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.auth-bound-body { min-width: 0; display: flex; flex-direction: column; }
.auth-bound-name {
    font-size: 14px; font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.auth-bound-sub { font-size: 12px; color: var(--ng-text-muted); margin-top: 2px; }
/* 「稍后绑定」是表单按钮，要和链接排在同一行 */
.auth-links form { display: inline; }
@media (prefers-reduced-motion: reduce) {
    .auth-social-pop, .auth-social-pop.open { transition: none; }
}

/* ─── 服务条款确认 ─── */
.auth-terms {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 10px 0 0;
    font-size: 12px;
    line-height: 1.6;
    color: var(--ng-text-muted);
}
.auth-terms input { flex: 0 0 auto; margin-top: 3px; accent-color: var(--ng-primary); }
.auth-terms a { color: var(--ng-primary); }

@media (max-width: 768px) {
    .auth-page { padding: 32px 0; }
    .auth-card { margin: 40px auto; padding: 28px 22px; }
    /* 小屏：分段内边距收窄（.auth-head 下内边距同样为 0）、LOGO 略小（oauth 授权页用） */
    .auth-head { padding: 24px 22px 0; }
    .auth-body { padding: 22px 22px 20px; }
    .auth-links { padding: 16px 22px 22px; }
    .auth-terms-bar { padding: 16px 22px 22px; }
    .auth-logo img { height: 46px; }
}

/* ─── OAuth 授权页 ─── */
.authorize-card {
    max-width: 460px;
    margin: 80px auto;
    padding: 40px;
}
.authorize-card .app-icon {
    width: 72px;
    height: 72px;
    object-fit: contain;
    border: 1px solid var(--ng-border);
    padding: 10px;
    background: #fff;
}

/* ─── 面包屑/页面标题 ─── */
.page-title {
    font-size: 20px;
    font-weight: 600;
    margin-bottom: 20px;
}

/* ─── 徽标 ─── */
.badge {
    font-weight: 500;
    font-size: 12px;
    padding: 3px 10px;
}

/* ─── 分页 ─── */
.pagination {
    margin: 20px 0 0;
}
.page-link {
    border: 1px solid var(--ng-border);
    color: var(--ng-text);
    padding: 6px 14px;
    font-size: 13px;
}
.page-link:hover {
    border-color: var(--ng-primary);
    color: var(--ng-primary);
}
.page-item.active .page-link {
    background: var(--ng-primary);
    border-color: var(--ng-primary);
}

/* 后台外壳（侧栏 / 顶栏 / 面包屑 / 账号下拉）统一定义在后文「后台统一组件层」，
   此处不再放旧 .admin-topbar 规则，避免两处规则互相覆盖。 */

/* ─── 响应式 ─── */
@media (max-width: 768px) {
    .hero-section { padding: 40px 0 30px; }
    .hero-section h1 { font-size: 26px; }
    .hero-section .hero-subtitle { font-size: 15px; }
    .authorize-card { margin: 40px 20px; padding: 24px; }
}

/* ═══════════ 用户中心（控制台式：左导航 + 右内容）═══════════
   独立 .uc-* 命名 —— 刻意不复用后台的 .sidebar-nav / .nav-link（那是给后台定制的，
   改会连累后台）。子导航：个人信息 / 消息中心 / 安全设置 / 授权管理 / 退出登录。
   钩子：.uc-side 的 id=userSidebar、内容容器 id=userContent 现在只是语义标识 ——
   全站已移除 SPA 无刷，没有任何脚本再按 id 替换局部内容。 */
/* ── 骨架：左「侧栏区」＋ 右「内容区」 ──
   侧栏钉在导航栏下方（高度取 --ng-nav-h），高度取「视口高 − 导航高」：
   上沿紧贴导航栏、下沿正好落在首屏底部（即页脚的起始位置）；滚动时侧栏不动，内容区自己滚。
   宽度只有一个旋钮 `--uc-side-w`（改这一个数即可）。
   **通栏铺满**（2026-09-19 用户明确要求）—— 不套 .container，侧栏直接贴视口左边缘、内容区铺到右边缘。
   `padding` 必须为 0：底部一旦留内边距，侧栏下沿和页脚之间就会露出间隙。 */
.uc-shell {
    --uc-side-w: 260px;
    display: flex;
    align-items: flex-start;
    gap: 0;
    padding: 0;
}
.uc-side {
    width: var(--uc-side-w);
    flex: 0 0 auto;
    position: sticky;
    top: var(--ng-nav-h);
    height: calc(100vh - var(--ng-nav-h));
    height: calc(100dvh - var(--ng-nav-h));
    overflow-y: auto;
    /* 侧栏自身滚动到两端后不要再把滚动传给页面 —— 否则滚到底会「带着整页一起滚」，
       看起来像侧栏的滚动条失控。侧栏一旦因窗口变矮而出现自己的滚动条，这条就生效。 */
    overscroll-behavior: contain;
    background: #fff;
    border: 0;
    border-right: 1px solid var(--ng-border);
    padding: 16px 12px;
}
.uc-side-title { font-size: 12px; color: var(--ng-text-muted); padding: 4px 10px 8px; letter-spacing: .4px; }
.uc-side a {
    display: flex; align-items: center; gap: 10px; padding: 9px 10px; font-size: 14px;
    color: var(--ng-text-secondary); border-radius: var(--ng-radius-control);
    transition: background-color .2s ease, color .2s ease;
}
.uc-side a + a { margin-top: 2px; }
.uc-side a:hover { background: var(--ng-primary-bg); color: var(--ng-primary); }
.uc-side a.active { background: var(--ng-primary-bg); color: var(--ng-primary); font-weight: 600; }
.uc-side a i { width: 18px; text-align: center; font-size: 15px; flex: 0 0 auto; }
.uc-side hr { border: 0; border-top: 1px solid var(--ng-border); margin: 10px 6px; }
.uc-side .uc-logout { color: var(--ng-danger); }
.uc-side .uc-logout:hover { background: #fff1f0; color: var(--ng-danger); }
.uc-badge {
    margin-left: auto; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
    background: var(--ng-danger); color: #fff; font-size: 11px; line-height: 18px;
    text-align: center; font-weight: 600;
}
/* 内容区：通栏铺满，左右内边距给足；背景继承站点灰（方案 C 概览用），
   方案 B 的 /profile 在下方 :has(.uc-identity) 里单独铺白底。 */
.uc-main { flex: 1 1 auto; min-width: 0; padding: 24px 32px; }
/* 卡片（.uc-card）即普通块级元素，不再做多列网格（避免卡片被挤窄）。 */
.uc-title { font-size: 20px; font-weight: 700; letter-spacing: -.2px; margin: 0 0 18px; }
/* 用户中心子页统一页眉：标题↔介绍 6px、介绍↔内容 20px（根除各页间距不一） */
.uc-page-head { margin-bottom: 20px; }
.uc-page-head .uc-title { margin: 0 0 6px; }
.uc-page-head .uc-sec-sub { margin: 0; }
/* 页眉右侧带操作按钮（如消息中心「邮件接收管理」） */
.uc-page-head--split { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.uc-page-head--split .uc-page-head-main { min-width: 0; }

/* 邮件接收管理抽屉：开关行 */
.uc-switch-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 15px 0; border-bottom: 1px solid var(--ng-border); }
.uc-switch-row:last-child { border-bottom: 0; }
.uc-switch-row .uc-switch-txt { min-width: 0; }
.uc-switch-row .t { font-size: 14px; color: var(--ng-text); }
.uc-switch-row .d { font-size: 12px; color: var(--ng-text-muted); margin-top: 3px; line-height: 1.5; }
.uc-switch-row .form-check { margin: 0; padding-left: 0; min-height: 0; }
.uc-switch-row .form-check-input { float: none; margin-left: 0; cursor: pointer; }
.uc-switch-row .form-check-input:checked { background-color: var(--ng-primary); border-color: var(--ng-primary); }
.uc-switch-row .form-check-input:focus { box-shadow: none; border-color: var(--ng-primary); }

/* 卡片：扁平细边、**无阴影**；标题栏单独一行并带下边框。
   这是示例页的形态 —— 别退回 .user-content-card（那是 28/32 大内边距 + 外阴影 + 标题下划线，
   在控制台式布局里会显得又厚又散）。 */
.uc-card { background: #fff; border: 1px solid var(--ng-border); margin-bottom: 16px; }
.uc-card:last-child { margin-bottom: 0; }
.uc-card-hd {
    padding: 14px 20px; border-bottom: 1px solid var(--ng-border);
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.uc-card-hd h3 { font-size: 16px; font-weight: 600; margin: 0; }
.uc-card-hd .uc-card-sub { font-size: 13px; color: var(--ng-text-muted); }
.uc-card-hd .uc-head-op { margin-left: auto; display: inline-flex; }
/* 纯条目列表的卡片：内边距直接给内部容器，省一层 wrapper */
.uc-card > .uc-items  { padding: 6px 20px 10px; }
/* 卡片底部说明条（如第三方绑定「即将开放」） */
.uc-card-note {
    padding: 12px 20px;
    border-top: 1px solid var(--ng-border);
    font-size: 12px;
    line-height: 1.6;
    color: var(--ng-text-muted);
}
/* 第三方绑定「绑定 / 解绑」：纯文字提示（不接后端、避免点了没反应的死按钮），
   仅作占位、明确「即将开放」语义；用站内 muted 色，不套 .btn 以免误以为可点 */
.uc-soon { font-size: 13px; color: var(--ng-text-muted); }
/* /profile 个人信息页：白底铺满内容区（侧栏右侧整块），内容随宽度铺开（全屏显示）。
   注意：max-width / margin:0 auto 不要加在 .uc-main 自身上，否则白底只覆盖一窄列、
   左右露出灰色站点背景（即「左右空白」）。内容限宽应加在内层 wrapper，本页未用。 */
.uc-main:has(> .uc-identity) {
    display: block;
    padding: 44px 32px 72px;
    background: #fff;
}
.uc-sec { font-size: 16px; font-weight: 600; margin: 30px 0 2px; }
.uc-sec-sub { font-size: 13px; color: var(--ng-text-muted); margin: 0 0 6px; }
.uc-list { border-top: 1px solid var(--ng-border); }
.uc-note {
    margin-top: 36px; padding: 14px 16px;
    background: #f7f8fa; border-left: 3px solid var(--ng-primary-bg);
    font-size: 13px; line-height: 1.7; color: var(--ng-text-secondary);
}
.uc-note a { color: var(--ng-primary); }
.uc-note b { color: var(--ng-text); font-weight: 600; }

/* ── 安全设置页（阿里云风：概览 + 条目行 = 图标 + 标题/描述 | 值 + 操作）── */
.uc-ov { display:flex; align-items:center; gap:18px; padding:20px 22px; }
.uc-ov .uc-avatar { width:56px; height:56px; border-radius:50%; background:var(--ng-primary-bg); color:var(--ng-primary); display:flex; align-items:center; justify-content:center; font-size:22px; font-weight:700; flex:0 0 auto; overflow:hidden; }
.uc-ov .uc-avatar img { width:100%; height:100%; object-fit:cover; display:block; }
.uc-ov .uc-ov-name { font-size:16px; font-weight:600; }
.uc-ov .uc-ov-id { color:var(--ng-text-muted); font-size:13px; margin-top:2px; }
.uc-ov .uc-ov-lv { margin-left:auto; display:flex; flex-direction:column; align-items:flex-end; text-align:right; }
.uc-lv { font-size:13px; font-weight:600; }
.uc-lv-bar { width:120px; height:6px; border-radius:3px; background:var(--ng-primary-bg); margin-top:6px; overflow:hidden; }
.uc-lv-bar i { display:block; height:100%; background:var(--ng-primary); }
.uc-lv-sub { font-size:11px; color:var(--ng-text-muted); margin-top:4px; }
/* /users 概览条右侧的安全等级块（与 /security 概览卡同款语言） */
.uc-hero-lv { margin-left:24px; display:flex; flex-direction:column; align-items:flex-end; text-align:right; }
@media (max-width: 768px) {
    .uc-hero-lv { margin-left:0; width:100%; align-items:flex-start; text-align:left; }
}

.uc-row { display:flex; align-items:center; gap:14px; padding:18px 22px; border-bottom:1px solid var(--ng-border); }
.uc-row:last-child { border-bottom:0; }
.uc-row .uc-row-ico { width:38px; height:38px; border-radius:8px; background:var(--ng-primary-bg); color:var(--ng-primary); display:flex; align-items:center; justify-content:center; flex:0 0 auto; font-size:17px; }
/* .uc-row-ico 里塞 SVG 时定尺寸（<i> 靠 font-size，SVG 不认）—— 对齐登录页 .auth-social-item .icon 的 18px */
.uc-row-ico svg { width: 18px; height: 18px; fill: currentColor; flex: 0 0 auto; }
.uc-row .uc-row-meta { flex:1 1 auto; min-width:0; }
.uc-row .uc-row-meta .t { font-weight:600; }
.uc-row .uc-row-meta .d { color:var(--ng-text-muted); font-size:13px; margin-top:1px; }
.uc-row .uc-row-val { color:var(--ng-text-secondary); margin-right:18px; font-size:13px; text-align:right; }
.uc-row .uc-row-val b { color:var(--ng-text); font-weight:600; }
.uc-row .uc-row-val .em { color:var(--ng-text-muted); font-weight:400; margin-left:6px; font-size:12px; }
/* .uc-row-op = 通用「文字操作按钮」，不再限定在 .uc-row 内（通知中心卡片头 / 详情页也用它） */
.uc-row-op { color:var(--ng-primary); cursor:pointer; font-weight:500; font-size:14px; background:none; border:0; padding:4px 8px; border-radius:6px; text-decoration:none; }
.uc-row-op:hover { background:var(--ng-primary-bg); }
.uc-row-op.danger { color: var(--ng-danger); }
.uc-row-op.danger:hover { background: #fff1f0; }
.uc-row-op:disabled { color:var(--ng-text-muted); cursor:default; background:none; }
/* 行内展开面板（点「修改」下拉出的编辑区）。
   左缩进 74px = 行内边距22 + 图标38 + 间距14，面板内容与所属行的文字列对齐 */
.uc-row-panel { padding:16px 22px 20px 74px; background:#fafbfc; }
.uc-xp-head { display:flex; align-items:center; gap:10px; margin-bottom:12px; }
.uc-xp-head .uc-xp-title { font-weight:600; }
.uc-xp-head .uc-xp-sub { color:var(--ng-text-muted); font-size:13px; }
.uc-row-collapse { margin-left:auto; color:var(--ng-text-muted); font-size:13px; background:none; border:0; cursor:pointer; padding:0; flex:0 0 auto; }
.uc-row-collapse:hover { color:var(--ng-primary); }
.uc-xp-step { padding:14px 16px; background:#fff; border:1px solid var(--ng-border); }
.uc-xp-step + .uc-xp-step { margin-top:10px; }
.uc-xp-stepname { display:flex; align-items:center; gap:8px; font-weight:600; margin-bottom:10px; }
.uc-xp-stepname i { width:18px; height:18px; border:1px solid var(--ng-border); border-radius:50%; font-style:normal; font-size:11px; color:var(--ng-text-muted); display:flex; align-items:center; justify-content:center; background:#fff; flex:0 0 auto; }
.uc-xp-note { color:var(--ng-text-muted); font-size:13px; margin:0 0 10px; }
.uc-xp-form { display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
.uc-row-panel > * + *, .uc-xp-step > * + * { margin-top:10px; }
/* 验证渠道二选一按钮（同时绑定邮箱与手机时先选）+ 表单限宽（框太长不好看） */
.uc-xp-choice { display:inline-flex; align-items:center; gap:8px; padding:0 16px; line-height:36px; font-size:14px; background:#fff; border:1px solid var(--ng-border); color:var(--ng-text); cursor:pointer; transition:border-color .15s, color .15s; }
.uc-xp-choice:hover { border-color:var(--ng-primary); color:var(--ng-primary); }
.uc-xp-step .auth-line { max-width:360px; }
.uc-xp-step .uc-xp-note { max-width:460px; }
/* 行悬停微亮：提示该行可操作；只过渡背景色，无位移 */
.uc-card .uc-row { transition: background-color .15s ease; }
.uc-card .uc-row:hover { background: #fafbfc; }
/* 面板/步骤入场动画：display 切换会重新触发；仅入场淡入+4px 下移，无悬停位移 */
@keyframes uc-xp-in { from { opacity:0; transform:translateY(-4px); } to { opacity:1; transform:none; } }
.uc-row-panel, .uc-xp-step { animation: uc-xp-in .2s ease; }
@media (prefers-reduced-motion: reduce) {
    .uc-row-panel, .uc-xp-step { animation: none; }
}
/* 面板内填写行直接复用认证页的全局类 .auth-line / .auth-line-box / .auth-line-action / .auth-line-icon，
   输入框设计与注册/登录页完全同源，不再自造样式 */

.uc-tag { display:inline-block; font-size:12px; padding:1px 8px; border-radius:10px; background:#e8ffea; color:var(--ng-success); font-weight:600; }
.uc-tag.off { background:#fff1f0; color:var(--ng-danger); }
.uc-tag.warn { background:#fff7e6; color:#b76e00; }

/* OAuth 出生且未设独立密码的引导横幅 */
.uc-alert { display:flex; align-items:center; gap:10px; padding:12px 16px; border:1px solid #ffe2ad; background:#fffbe9; color:#7a5600; font-size:13px; line-height:1.6; border-radius:var(--ng-radius-control); margin:0 0 16px; }
.uc-alert .bi { font-size:16px; flex:0 0 auto; }
.uc-alert span { flex:1 1 auto; min-width:0; }
.uc-alert-link { flex:0 0 auto; color:var(--ng-primary); font-weight:600; text-decoration:none; }
.uc-alert-link:hover { color:var(--ng-primary-hover); text-decoration:underline; }

/* 通栏容器（/users 概览：内容限宽 1080 居中，参照方案 C） */
.uc-wrap { max-width: none; }
/* /users 双列布局：左=账号信息/最近登录，右=快捷入口；窄屏折单列 */
.uc-cols { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 16px; align-items: start; }
.uc-col-main, .uc-col-side { min-width: 0; }
.uc-col-main > * + * { margin-top: 16px; }
@media (max-width: 1100px) {
    .uc-cols { grid-template-columns: 1fr; }
}
.uc-hero .uc-face { width: 64px; height: 64px; border-radius: 50%; border: 1px solid var(--ng-border); flex: 0 0 auto; }
/* 快捷入口竖排卡 */
.uc-quick { padding: 6px 0; }
.uc-quick-item { display: flex; align-items: center; gap: 12px; padding: 11px 20px; color: var(--ng-text); text-decoration: none; border-bottom: 1px solid var(--ng-border); transition: background-color .15s ease; }
.uc-quick-item:last-child { border-bottom: 0; }
.uc-quick-item:hover { background: #fafbfc; }
.uc-quick-item .q-ico { width: 34px; height: 34px; border-radius: var(--ng-radius-control); background: var(--ng-primary-bg); color: var(--ng-primary); display: flex; align-items: center; justify-content: center; font-size: 15px; flex: 0 0 auto; }
.uc-quick-item .q-body { min-width: 0; }
.uc-quick-item b { display: block; font-size: 14px; font-weight: 600; }
.uc-quick-item .q-desc { display: block; font-size: 12px; color: var(--ng-text-muted); margin-top: 1px; }
.uc-quick-item .q-tail { margin-left: auto; color: var(--ng-text-muted); font-size: 12px; flex: 0 0 auto; }
.uc-quick-tag { margin-left: auto; background: var(--ng-danger); color: #fff; font-size: 10px; line-height: 1; padding: 2px 6px; border-radius: 8px; }

/* 概览 Hero（方案 C：头像 + 昵称 + 邮箱 + 右侧统计） */
.uc-hero {
    display: flex; align-items: center; gap: 22px;
    background: #fff; border: 1px solid var(--ng-border); padding: 22px 26px; margin-bottom: 20px;
}
.uc-hero .uc-who { min-width: 0; }
.uc-hero .uc-mail { font-size: 13px; color: var(--ng-text-muted); margin-top: 3px; }
.uc-hero .uc-stats { margin-left: auto; display: flex; gap: 36px; text-align: center; }
.uc-hero .uc-stats dt { font-size: 12px; color: var(--ng-text-muted); }
.uc-hero .uc-stats dd { font-size: 20px; font-weight: 700; line-height: 1.3; margin: 0; }

/* 功能卡网格（方案 C） */
.uc-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; margin-bottom: 20px; }
.uc-tile { background: #fff; border: 1px solid var(--ng-border); padding: 20px; display: block; transition: border-color .2s, box-shadow .2s; }
.uc-tile:hover { border-color: #c9cdd4; box-shadow: 0 6px 20px rgba(16,24,40,.06); }
.uc-tile .uc-tile-ico {
    width: 38px; height: 38px; border-radius: var(--ng-radius-control);
    background: var(--ng-primary-bg); color: var(--ng-primary);
    display: flex; align-items: center; justify-content: center; margin-bottom: 14px;
}
.uc-tile h3 { font-size: 15px; font-weight: 600; display: flex; align-items: center; gap: 6px; }
.uc-tile p { font-size: 13px; color: var(--ng-text-muted); margin-top: 4px; }
.uc-tile .uc-tile-tail { margin-top: 14px; font-size: 13px; color: var(--ng-primary); display: flex; align-items: center; gap: 4px; }
.uc-tile .uc-tile-tag { margin-left: auto; font-size: 12px; background: #fff1f0; color: var(--ng-danger); padding: 0 7px; border-radius: var(--ng-radius-pill); font-weight: 600; }

/* ── 账号预览卡（内容参照方案 B 示例：身份区 + 带图标的条目行）── */
.uc-identity {
    display: flex; align-items: center; gap: 20px; flex-wrap: wrap;
    padding-bottom: 32px; margin-bottom: 0;
    border-bottom: 1px solid var(--ng-border);
}
.uc-identity .uc-who { min-width: 0; }
.uc-identity .uc-face { width: 72px; height: 72px; }
.uc-identity .uc-id-actions { margin-left: auto; align-self: center; }
.uc-pen {
    color: var(--ng-text-muted); cursor: pointer; padding: 3px; border-radius: var(--ng-radius-control);
    display: inline-flex; align-items: center;
}
.uc-pen:hover { background: #f2f3f5; color: var(--ng-primary); }
/* 条目行：图标盒 + 「小标签 / 主值」两行 + 右侧文字操作；
   通栏卡里单列太宽（操作会被甩到很右边），故宽屏排成 2~3 列 */
.uc-items { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); column-gap: 48px; }
.uc-item { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 16px 0; border-bottom: 1px solid var(--ng-border); }
.uc-item .uc-item-ico {
    width: 38px; height: 38px; flex: 0 0 auto; background: var(--ng-primary-bg);
    color: var(--ng-primary); display: flex; align-items: center; justify-content: center;
    border-radius: 8px; font-size: 17px;
}
/* 头像更换弹窗（/profile）：常驻渲染 + .open 切换淡入淡出。
   不能用 hidden 属性——Bootstrap reboot 的 [hidden]{display:none!important} 会压过显示态规则，
   display:none→flex 会跳过 transition 造成闪现 */
.uc-avmodal { position: fixed; inset: 0; z-index: 1080; margin: 0; background: rgba(17, 24, 39, .45); display: flex; align-items: center; justify-content: center; padding: 16px; opacity: 0; visibility: hidden; transition: opacity .18s ease, visibility .18s; }
.uc-avmodal.open { opacity: 1; visibility: visible; }
.uc-avmodal-card { width: 360px; max-width: 100%; background: #fff; border: 1px solid var(--ng-border); border-radius: var(--ng-radius); box-shadow: var(--ng-shadow-lg); }
.uc-avmodal-hd { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid var(--ng-border); font-weight: 600; font-size: 15px; }
.uc-avmodal-hd .x { background: none; border: 0; color: var(--ng-text-muted); cursor: pointer; font-size: 15px; line-height: 1; padding: 4px 6px; border-radius: var(--ng-radius-control); }
.uc-avmodal-hd .x:hover { background: #f2f3f5; color: var(--ng-text); }
.uc-avmodal-bd { padding: 20px 18px 18px; text-align: center; }
.uc-avmodal-bd .pv { width: 96px; height: 96px; border-radius: 50%; object-fit: cover; border: 1px solid var(--ng-border); }
.uc-avmodal-drop { margin-top: 16px; display: block; padding: 16px 12px; border: 1px dashed var(--ng-border); border-radius: 8px; cursor: pointer; transition: border-color .15s ease, background .15s ease; }
.uc-avmodal-drop:hover { border-color: var(--ng-primary); background: var(--ng-primary-bg); }
.uc-avmodal-drop .bi { font-size: 20px; color: var(--ng-primary); }
.uc-avmodal-drop .t { display: block; margin-top: 6px; font-size: 13px; font-weight: 500; }
.uc-avmodal-drop .h { display: block; margin-top: 2px; font-size: 12px; color: var(--ng-text-muted); }
.uc-avmodal-msg { min-height: 18px; margin-top: 10px; font-size: 12px; }
.uc-avmodal-msg.is-ok { color: var(--ng-success); }
.uc-avmodal-msg.is-err { color: var(--ng-danger); }
.uc-avmodal-lib { margin-top: 6px; background: none; border: 0; color: var(--ng-primary); font-size: 13px; cursor: pointer; padding: 4px 8px; border-radius: var(--ng-radius-control); }
.uc-avmodal-lib:hover { background: var(--ng-primary-bg); }
.uc-item .uc-item-body { flex: 1 1 auto; min-width: 0; }
.uc-item .uc-item-label { display: block; font-size: 13px; color: var(--ng-text-muted); }
.uc-item .uc-item-value {
    display: block; margin-top: 1px; font-size: 14px; font-weight: 500;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.uc-item .uc-item-value em { font-style: normal; font-weight: 400; font-size: 13px; color: var(--ng-text-muted); margin-left: 8px; }
.uc-item .uc-item-op { flex: 0 0 auto; font-size: 13px; }
.uc-item .uc-item-op a, .uc-item .uc-item-op button {
    color: var(--ng-primary); padding: 4px 8px; border-radius: var(--ng-radius-control);
    background: none; border: 0; font: inherit; cursor: pointer;
}
.uc-item .uc-item-op a:hover, .uc-item .uc-item-op button:hover { background: var(--ng-primary-bg); }
/* 条目右侧也可能是小按钮（如第三方绑定的「绑定 / 解绑」），走站内 .btn 体系即可 */

/* 概览块（个人资料卡顶部：头像 + 昵称 + 邮箱 + 右侧元信息） */
/* 身份区内部的排版（外层容器是 .uc-identity，见上方「账号预览卡」段） */
.uc-face { width: 64px; height: 64px; flex: 0 0 auto; border-radius: 50%; object-fit: cover; border: 1px solid var(--ng-border); }
.uc-name { font-size: 20px; font-weight: 700; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.uc-sub { font-size: 13px; color: var(--ng-text-muted); margin-top: 2px; }
.uc-chip {
    display: inline-flex; align-items: center; gap: 4px; font-size: 12px; padding: 1px 8px;
    border-radius: var(--ng-radius-pill); background: var(--ng-primary-bg);
    color: var(--ng-primary); font-weight: 600;
}
.uc-chip.is-admin { background: #fff1f0; color: var(--ng-danger); }

/* 概览面包屑（方案 C：用户中心 / 账号概览） */
.uc-crumb { font-size: 13px; color: var(--ng-text-muted); margin: 0 0 14px; }

/* 详情卡（方案 C 概览页的「账号信息」只读列表：k / v / 操作 三栏） */
.uc-detail { background: #fff; border: 1px solid var(--ng-border); }
.uc-detail .uc-detail-hd { padding: 14px 22px; border-bottom: 1px solid var(--ng-border); display: flex; align-items: center; gap: 8px; }
.uc-detail .uc-detail-hd h3 { font-size: 15px; font-weight: 600; margin: 0; }
.uc-detail .uc-detail-hd .sub { font-size: 12px; color: var(--ng-text-muted); }
.uc-detail .uc-detail-bd { padding: 6px 22px; }
.uc-detail .uc-row { display: flex; align-items: center; gap: 16px; padding: 16px 0; border-bottom: 1px solid var(--ng-border); }
.uc-detail .uc-row:last-child { border-bottom: 0; }
.uc-detail .uc-row .k { width: 110px; flex: 0 0 auto; color: var(--ng-text-secondary); font-size: 13px; }
.uc-detail .uc-row .v { flex: 1 1 auto; min-width: 0; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uc-detail .uc-row .v em { font-style: normal; color: var(--ng-text-muted); font-weight: 400; font-size: 13px; margin-left: 6px; }
.uc-detail .uc-row .op { flex: 0 0 auto; color: var(--ng-primary); font-size: 13px; padding: 4px 9px; border-radius: var(--ng-radius-control); }
.uc-detail .uc-row .op:hover { background: var(--ng-primary-bg); }

/* 行内编辑表单（方案 B 信息行内的即时编辑：编辑态在行内展开） */
.uc-edit-form { flex: 1 1 100%; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 8px; }
.uc-edit-err { color: var(--ng-danger); font-size: 13px; }

/* 行内编辑态（方案 B 信息行内的即时编辑；不限定 .uc-item 作用域，
   身份区 .uc-identity 的昵称编辑同样命中——之前误删导致其输入框裸奔） */
.uc-empty { color: var(--ng-text-muted); }
.uc-edit-input {
    flex: 1 1 auto; min-width: 0; font-size: 14px; font-family: inherit;
    border: 1px solid var(--ng-border); border-radius: var(--ng-radius-control); padding: 6px 10px; margin: 4px 0;
}
.uc-edit-input:focus { outline: none; border-color: var(--ng-primary); box-shadow: var(--ng-focus-ring); }
.uc-edit-actions { flex: 0 0 auto; display: flex; gap: 6px; }
.uc-edit-actions .btn-save { color: #fff; background: var(--ng-primary); border: 0; border-radius: var(--ng-radius-control); padding: 5px 12px; cursor: pointer; font: inherit; font-size: 13px; }
.uc-edit-actions .btn-cancel { color: var(--ng-text-secondary); background: #fff; border: 1px solid var(--ng-border); border-radius: var(--ng-radius-control); padding: 5px 12px; cursor: pointer; font: inherit; font-size: 13px; }
/* 昵称编辑：表单整行折到身份区下方，输入字号贴近昵称本体 */
.uc-identity .uc-edit-form { flex-basis: 100%; }
.uc-identity .uc-edit-input { font-size: 16px; font-weight: 600; }

@media (max-width: 768px) {
    /* 小屏：侧栏不再钉住/通高，退回成一条横向区块，内容跟在下面 */
    .uc-shell { flex-direction: column; gap: 0; padding: 0 0 32px; }
    .uc-side {
        width: 100%; position: static; height: auto; overflow: visible;
        border-right: 0; border-bottom: 1px solid var(--ng-border); padding: 12px;
    }
    .uc-main { padding: 16px; }
    .uc-row-panel { padding-left: 22px; }
    .uc-hero { flex-wrap: wrap; }
    .uc-hero .uc-stats { margin-left: 0; width: 100%; justify-content: flex-start; gap: 28px; }
    .uc-tiles { grid-template-columns: 1fr; }
    .uc-identity { flex-wrap: wrap; }
    .uc-item { flex-wrap: wrap; }
    .uc-item .uc-item-op { width: 100%; }
}

/* ─── 用户中心内容区排版 ─── */
.user-content-card {
    background: #fff;
    border: 1px solid var(--ng-border);
    padding: 28px 32px;
    margin-bottom: 20px;
    box-shadow: var(--ng-shadow-sm);
}
.user-content-card:last-child {
    margin-bottom: 0;
}
.user-content-card h5.section-title {
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 20px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--ng-border);
}
.user-content-card .field-label {
    font-size: 12px;
    color: var(--ng-text-muted);
    margin-bottom: 4px;
}
.user-content-card .field-value {
    font-size: 14px;
    color: var(--ng-text);
}

/* ═══════════ 消息中心（/notifications）—— .uc-* 家族 + 大厂风 ═══════════ */
/* 筛选：极简文字标签，激活态蓝字 + 蓝下划线（无背景胶囊） */
/* 筛选条（消息中心 / 授权管理共用）。底部 1px 基线 + 激活 tab 的 2px 下划线：
   align-items:flex-end 让各 tab 底边对齐；tab 上 margin-bottom:-1px 把下划线压到基线上，
   两者底边重合 → 不再出现「蓝线下面漏出 1px 灰线」的错位。 */
.uc-filter { display: flex; align-items: flex-end; gap: 4px; border-bottom: 1px solid var(--ng-border); margin-bottom: 16px; }
.uc-filter .tab { background: none; border: 0; border-bottom: 2px solid transparent; color: var(--ng-text-muted); font: inherit; font-size: 14px; padding: 10px 4px; margin: 0 16px -1px 0; cursor: pointer; transition: color .15s ease, border-color .15s ease; }
.uc-filter .tab:hover { color: var(--ng-text); }
.uc-filter .tab.active { color: var(--ng-primary); border-bottom-color: var(--ng-primary); font-weight: 600; }
/* 卡片内的筛选条（消息中心）：左右 20px 与卡片内容对齐，且不额外占底部间距 */
.uc-card > .uc-filter { padding: 0 20px; margin-bottom: 0; }
/* 筛选条右侧操作区（刷新 / 返回等），与 tab 同排右对齐 */
.uc-filter-actions { margin-left: auto; display: inline-flex; gap: 8px; align-items: center; }
.uc-filter .n { color: var(--ng-text-muted); font-weight: 400; font-size: 13px; }

/* 消息条目：左图标盒 + 内容 + 右侧 hover 浮出操作（仅透明度过渡，无位移/缩放） */
.uc-msg { display: flex; align-items: flex-start; gap: 14px; padding: 16px 22px; border-bottom: 1px solid var(--ng-border); cursor: pointer; transition: background-color .15s ease; }
.uc-msg:last-child { border-bottom: 0; }
.uc-msg:hover { background: #fafbfc; }
.uc-msg.unread { background: #f8f6ff; }
.uc-msg.unread:hover { background: #eef3ff; }
.uc-msg .uc-msg-ico { width: 38px; height: 38px; flex: 0 0 auto; border-radius: 8px; background: var(--ng-primary-bg); color: var(--ng-primary); display: flex; align-items: center; justify-content: center; font-size: 17px; margin-top: 1px; }
.uc-msg.read .uc-msg-ico { color: var(--ng-text-muted); }
.uc-msg-body { flex: 1 1 auto; min-width: 0; }
/* 标题行：固定左内边距；未读蓝点绝对定位在留白内 —— 已读不渲染圆点，
   标题位置恒定，杜绝「圆点占位导致标题位移」。 */
.uc-msg-top { position: relative; padding-left: 14px; display: flex; align-items: center; gap: 8px; min-width: 0; }
.uc-msg .uc-msg-top .uc-dot { position: absolute; left: 0; top: 6px; width: 8px; height: 8px; border-radius: 50%; background: var(--ng-primary); }
.uc-msg-title { font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uc-msg.read .uc-msg-title { font-weight: 500; color: var(--ng-text-secondary); }
.uc-msg-type { font-size: 12px; padding: 1px 8px; border-radius: 10px; font-weight: 600; flex: 0 0 auto; }
.uc-msg-type.security     { background: #fff1f0; color: var(--ng-danger); }
.uc-msg-type.announcement { background: #e6f0ff; color: var(--ng-primary); }
.uc-msg-type.oauth        { background: #e8f8ee; color: var(--ng-success); }
.uc-msg-type.system       { background: #f2f3f5; color: var(--ng-text-muted); }
.uc-msg-prev { font-size: 13px; color: var(--ng-text-muted); margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uc-msg-time { font-size: 11px; color: var(--ng-text-muted); margin-top: 4px; }
.uc-msg-actions { margin-left: 12px; display: flex; gap: 2px; align-self: flex-start; opacity: 0; transition: opacity .15s ease; flex: 0 0 auto; }
.uc-msg:hover .uc-msg-actions, .uc-msg:focus-within .uc-msg-actions { opacity: 1; }
.uc-msg-actions button { background: none; border: 0; color: var(--ng-text-muted); cursor: pointer; padding: 6px 8px; border-radius: var(--ng-radius-control); font-size: 15px; line-height: 1; }
.uc-msg-actions button:hover { background: var(--ng-primary-bg); color: var(--ng-primary); }
/* 加载更多 / 空状态 */
.uc-msg-more { text-align: center; padding: 12px; border-top: 1px solid var(--ng-border); }
.uc-msg-empty { text-align: center; padding: 48px 20px; color: var(--ng-text-muted); }
.uc-msg-empty .bi { font-size: 36px; display: block; opacity: .4; margin-bottom: 10px; }

/* 内容区局部淡入（通用）：用户中心 / 消息中心的页内变更专用，只对内容容器重放 opacity 动画。
   注意与「页面间」的过渡是两套机制：页面间走 ng-ui.css 里的跨文档 View Transition
   （@view-transition + ::view-transition-*，root 与 site-nav 交叉淡入淡出）；
   这里不调用 document.startViewTransition，否则会把侧栏 / root 背景一起卷进来闪一下。
   SPA 移除后本类目前无调用者，保留给后续页内局部变更使用。 */
.uc-fade-in { animation: uc-fade-in-kf .18s ease; }
@keyframes uc-fade-in-kf { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .uc-fade-in { animation: none; } }

/* 详情页 */
.uc-detail-head { display: flex; align-items: center; gap: 10px; padding: 14px 20px; border-bottom: 1px solid var(--ng-border); }
.uc-detail-head h3 { font-size: 16px; font-weight: 600; margin: 0; }
.uc-detail-head .uc-head-op { margin-left: auto; display: flex; gap: 4px; }
.uc-detail-body { padding: 22px 24px; animation: uc-detail-in .2s ease; }
.uc-detail-hero { display: flex; align-items: flex-start; gap: 14px; padding-bottom: 18px; border-bottom: 1px solid var(--ng-border); }
.uc-detail-hero .uc-d-ico { width: 42px; height: 42px; flex: 0 0 auto; border-radius: 8px; background: var(--ng-primary-bg); color: var(--ng-primary); display: flex; align-items: center; justify-content: center; font-size: 19px; }
.uc-detail-hero .uc-d-title { font-size: 17px; font-weight: 700; }
.uc-detail-hero .uc-d-meta { font-size: 12px; color: var(--ng-text-muted); margin-top: 4px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.uc-detail-content { margin-top: 18px; font-size: 14px; line-height: 1.9; color: var(--ng-text); }
.uc-detail-content p { margin: 0 0 12px; }
.uc-detail-content ul { margin: 0 0 12px; padding-left: 20px; }
.uc-detail-content code { background: #f3f4f6; padding: 1px 5px; border-radius: var(--ng-radius-control); font-size: 12px; }
.uc-detail-actions { margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--ng-border); display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.uc-detail-actions .spacer { margin-left: auto; }
@keyframes uc-detail-in { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .uc-detail-body { animation: none; } }
@media (max-width: 768px) {
    .uc-msg-actions { opacity: 1; } /* 触屏无 hover，操作常显 */
    .uc-detail-body { padding: 18px 16px; }
}

/* ═══════════ 授权管理（/apps）—— 统计条 + 卡片列表（圆形图标）+ 详情抽屉 ═══════════ */
/* 统计条：单卡三分栏 */
.stats { display: grid; grid-template-columns: repeat(3, 1fr); background: #fff; border: 1px solid var(--ng-border); margin-bottom: 18px; }
.stat { padding: 18px 22px; border-right: 1px solid var(--ng-border); }
.stat:last-child { border-right: 0; }
.stat .k { font-size: 12px; color: var(--ng-text-muted); }
.stat .v { font-size: 26px; font-weight: 700; line-height: 1.3; margin-top: 3px; letter-spacing: -.5px; }
.stat .v small { font-size: 12px; font-weight: 400; color: var(--ng-text-muted); margin-left: 5px; letter-spacing: 0; }

/* 应用卡片：整卡可点开抽屉；左圆形 logo / 中信息 / 右操作，垂直居中 */
.app-card { background: #fff; border: 1px solid var(--ng-border); padding: 18px 22px; display: flex; align-items: center; gap: 16px; margin-bottom: 12px; cursor: pointer; transition: background-color .15s ease; }
.app-card:hover { background: #fafbfc; }
.app-card.removing { opacity: 0; transition: opacity .18s ease; }
.app-logo { width: 48px; height: 48px; flex: 0 0 auto; border-radius: 50%; background: var(--ng-primary-bg); color: var(--ng-primary); display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 700; overflow: hidden; }
.app-logo.third { background: #f2f3f5; color: var(--ng-text-secondary); }
.app-logo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.app-body { flex: 1 1 auto; min-width: 0; }
.app-name { font-size: 15px; font-weight: 600; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.app-tag { font-size: 11px; line-height: 16px; padding: 1px 7px; border-radius: 10px; font-weight: 600; }
.app-tag.internal { background: var(--ng-primary-bg); color: var(--ng-primary); }
.app-tag.third { background: #f2f3f5; color: var(--ng-text-muted); }
.app-time { font-size: 13px; color: var(--ng-text-muted); margin-top: 3px; }
.app-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 10px; font-size: 12px; color: var(--ng-text-muted); }
.app-scope { display: inline-flex; align-items: center; gap: 4px; background: #f7f8fa; border: 1px solid var(--ng-border); border-radius: 10px; padding: 1px 9px; font-size: 12px; color: var(--ng-text-secondary); }
.app-scope i { color: var(--ng-primary); font-size: 11px; }
.app-act { flex: 0 0 auto; display: flex; align-items: center; gap: 4px; }
.app-act .go { color: var(--ng-border); font-size: 15px; transition: color .15s; }
.app-card:hover .app-act .go { color: var(--ng-text-muted); }
.app-empty { text-align: center; padding: 48px 20px; color: var(--ng-text-muted); }
.app-empty .bi { font-size: 36px; display: block; opacity: .4; margin-bottom: 10px; }
/* 抽屉内设备备注（可点击编辑） */
.uc-dw-remark { display: flex; align-items: center; gap: 6px; padding: 10px 0; font-size: 13px; }
.uc-dw-remark-text { color: var(--ng-text); word-break: break-all; }
.uc-dw-remark .uc-dw-remark-edit { color: var(--ng-text-muted); cursor: pointer; }
.uc-dw-remark .uc-dw-remark-edit:hover { color: var(--ng-primary); }
.uc-dw-remark input { flex: 1 1 auto; }

/* 授权详情抽屉 */
/* 抽屉与遮罩层级高过顶部进度条(.page-progress z1100)与导航栏(1030)，避免被它们压在顶上；
   高度用 top:0 + bottom:0 撑满视口（比 height:100% 更稳）。 */
.uc-drawer-mask { position: fixed; inset: 0; background: rgba(17,24,39,.35); z-index: 2000; opacity: 0; visibility: hidden; transition: opacity .2s ease; }
.uc-drawer-mask.open { opacity: 1; visibility: visible; }
.uc-drawer { position: fixed; top: 0; right: 0; bottom: 0; width: 420px; max-width: 100%; background: #fff; border-left: 1px solid var(--ng-border); box-shadow: -8px 0 24px rgba(0,0,0,.10); z-index: 2010; display: flex; flex-direction: column; transform: translateX(100%); transition: transform .22s ease; }
.uc-drawer.open { transform: none; }
.uc-drawer-hd { padding: 15px 20px; border-bottom: 1px solid var(--ng-border); display: flex; align-items: center; gap: 10px; }
.uc-drawer-hd h3 { font-size: 16px; margin: 0; font-weight: 600; }
.uc-drawer-x { margin-left: auto; background: none; border: 0; color: var(--ng-text-muted); cursor: pointer; font-size: 16px; padding: 4px 7px; border-radius: var(--ng-radius-control); }
.uc-drawer-x:hover { background: #f2f3f5; color: var(--ng-text); }
.uc-drawer-bd { padding: 20px; overflow-y: auto; flex: 1; }
.uc-drawer-ft { padding: 14px 20px; border-top: 1px solid var(--ng-border); display: flex; justify-content: flex-end; gap: 8px; }
.uc-dw-app { display: flex; align-items: center; gap: 14px; padding-bottom: 18px; border-bottom: 1px solid var(--ng-border); }
.uc-dw-logo { width: 52px; height: 52px; flex: 0 0 auto; border-radius: 50%; background: var(--ng-primary-bg); color: var(--ng-primary); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 21px; overflow: hidden; }
.uc-dw-logo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.uc-dw-name { font-size: 16px; font-weight: 600; }
.uc-dw-sec { font-size: 13px; font-weight: 600; margin: 20px 0 6px; }
.uc-dw-row { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; border-bottom: 1px dashed var(--ng-border); font-size: 13px; }
.uc-dw-row:last-child { border-bottom: 0; }
.uc-dw-row .k { color: var(--ng-text-muted); }
.uc-dw-scope { display: flex; align-items: flex-start; gap: 8px; padding: 8px 0; font-size: 13px; }
.uc-dw-scope i { color: var(--ng-success); margin-top: 2px; }
.uc-dw-scope b { font-weight: 600; }
.uc-dw-scope span { display: block; color: var(--ng-text-muted); font-size: 12px; }
@media (max-width: 768px) {
    .stats { grid-template-columns: 1fr; }
    .stat { border-right: 0; border-bottom: 1px solid var(--ng-border); }
    .stat:last-child { border-bottom: 0; }
    .app-card { flex-wrap: wrap; }
    .app-act { width: 100%; justify-content: flex-end; }
    .uc-drawer { width: 100%; }
}

/* ─── 后台管理增强 ─── */

/* 页面标题栏 */
.admin-page-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 20px;
}
.admin-page-header h1 {
    font-size: 20px;
    font-weight: 700;
    margin: 0;
}

/* 筛选/搜索栏 */
.admin-filter-bar {
    background: #fff;
    border: 1px solid var(--ng-border);
    padding: 16px 20px;
    margin-bottom: 16px;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.admin-filter-bar .form-control,
.admin-filter-bar .form-select {
    width: auto;
    min-width: 180px;
}

/* 操作按钮组 */
.action-group {
    display: flex;
    gap: 6px;
}
.action-group .btn {
    padding: 3px 10px;
    font-size: 12px;
}

/* 空状态 */
.empty-state {
    text-align: center;
    padding: 60px 20px;
    color: var(--ng-text-muted);
}
.empty-state i {
    font-size: 40px;
    display: block;
    margin-bottom: 12px;
    opacity: 0.4;
}

/* 表单卡片 */
.form-section {
    background: #fff;
    border: 1px solid var(--ng-border);
    padding: 24px;
    margin-bottom: 20px;
}
.form-section h6 {
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 16px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--ng-border);
}

/* 状态标签 */
.status-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 6px;
}
.status-dot.active { background: #22c55e; }
.status-dot.inactive { background: #9ca3af; }

/* 卡片 hover 动效 */
.card-hover {
    transition: box-shadow 0.2s, transform 0.2s;
}

/* 搜索输入框组 */
.search-box {
    display: flex;
    gap: 0;
}
.search-box .form-control {
    border-right: none;
}
.search-box .btn {
    border: 1px solid var(--ng-border);
    border-left: none;
    background: #fff;
}
.search-box .btn:hover {
    color: var(--ng-primary);
}

/* 数字统计卡片 - 后台仪表盘增强 */
.stat-card-lg {
    background: #fff;
    border: 1px solid var(--ng-border);
    padding: 28px 24px;
    text-align: center;
    transition: box-shadow 0.2s;
}
.stat-card-lg .stat-icon {
    font-size: 28px;
    color: var(--ng-primary);
    margin-bottom: 12px;
}
.stat-card-lg .stat-number {
    font-size: 32px;
    font-weight: 700;
    color: var(--ng-text);
    line-height: 1.2;
}
.stat-card-lg .stat-label {
    font-size: 13px;
    color: var(--ng-text-secondary);
    margin-top: 4px;
}

/* ═══════════════════════════════════════
   顶部加载进度条：统一到 sup / acc / 月雨庭共同的**基线规则**（各站 main.min.css 那一层）。
   2px 直角、90deg 两段半透明渐变、transition 为 `width .2s ease, opacity .3s ease`。
   颜色思路（三站同源）：起点取品牌主色，终点取主色的亮一档或相邻辅助色，
   两端都 .85 半透明，压在任何底色上都不抢眼；只有两段，不叠加 ::after 双层。
   NG 取站点既有 --ng-gradient 的两个色标 #6c5ce7 到 #8f7dff，换成 rgba 后使用。
   注意：sup / acc 另有一层后加载的 nav-shell.min.css 把它覆盖成 3px 胶囊 + 七段渐变
   （月雨庭没有那一层），NG 之前抄的是覆盖层；这里统一回 2px 基线。
   秒加载驱动仍是 header.php 内联脚本（解析到即启动、rAF 1.2s easeOutQuad），
   与 sup / acc 一致；width transition 让每帧写入更柔和，不影响启动时机。
   ═══════════════════════════════════════ */
.page-progress {
    position: fixed;
    top: 0;
    left: 0;
    height: 2px;
    width: 0;
    background: linear-gradient(90deg, rgba(108, 92, 231, .85), rgba(143, 125, 255, .85));
    z-index: 1100;
    opacity: 0;
    transition: width .2s ease, opacity .3s ease;
}

.btn-back-top {
    position: fixed;
    bottom: 30px;
    right: 30px;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--ng-primary);
    color: #fff;
    border: none;
    font-size: 18px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s;
    z-index: 1050;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}
.btn-back-top.show {
    opacity: 1;
    visibility: visible;
}
.btn-back-top:hover {
    background: #5a4bd1;
}

/* 滚动进度圆环（戒指式：套在按钮最外围） */
.btn-back-top-ring {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 52px;
    height: 52px;
    transform: translate(-50%, -50%) rotate(-90deg);
    pointer-events: none;
}
.btn-back-top-ring circle {
    fill: none;
    stroke-width: 3;
}
.btn-back-top-ring-bg {
    stroke: rgba(255, 255, 255, 0.3);
}
.btn-back-top-ring-fg {
    stroke: #fff;
    stroke-linecap: round;
    stroke-dasharray: 131.9;
    stroke-dashoffset: 131.9;
    transition: stroke-dashoffset 0.1s linear;
}

/* 滚动中显示百分比；停止滚动（idle）或鼠标悬浮时淡入箭头 */
.btn-back-top i,
.btn-back-top-pct {
    position: absolute;
    transition: opacity 0.25s ease;
}
.btn-back-top-pct {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1;
    opacity: 1;
}
.btn-back-top i {
    font-size: 18px;
    opacity: 0;
}
.btn-back-top.idle .btn-back-top-pct,
.btn-back-top:hover .btn-back-top-pct {
    opacity: 0;
}
.btn-back-top.idle i,
.btn-back-top:hover i {
    opacity: 1;
}

/* ─── 前台页脚（与 sup 站完全相同：浅色 / 白底 + 上边框）─── */
.footer-sup { background: #fff !important; border-top: 1px solid var(--ng-border); padding: 32px 0 24px; color: var(--ng-text-muted); }
.footer-sup a { color: var(--ng-text-muted); }
.footer-sup a:hover { color: var(--ng-primary); }
.footer-sup .f-title { color: var(--ng-text); font-weight: 600; font-size: 14px; margin-bottom: 14px; }
.footer-sup .footer-brand-logo { height: 24px; width: auto; }
/* 页脚链接：文字不移动，悬停时右侧 ">" 箭头淡入 */
.footer-sup .footer-link { position: relative; align-self: flex-start; padding-right: 16px; }
.footer-sup .footer-link i {
    position: absolute; right: 0; top: 50%; margin: 0; width: auto;
    transform: translateY(-50%); opacity: 0;
    transition: opacity .45s ease;
    color: var(--ng-text-muted); font-size: 12px;
}
.footer-sup .footer-link:hover i { opacity: 1; color: var(--ng-primary); }

/* ─── 法律条款排版组件（协议/隐私政策，与 sup 一致）─── */
.legal-callout {
    background: #f6f4fe;
    border-left: 3px solid var(--ng-primary);
    padding: 14px 18px;
    margin: 20px 0;
    font-size: 15px;
    line-height: 1.9;
}
.legal-warning {
    background: #fff8e6;
    border-left: 3px solid #f5a623;
    padding: 14px 18px;
    margin: 20px 0;
    font-size: 15px;
    line-height: 1.9;
}
.legal-quote {
    background: #fafbfc;
    border-left: 3px solid #d5dbe3;
    padding: 14px 18px;
    margin: 16px 0;
    font-size: 15px;
    line-height: 2;
    color: var(--ng-text-secondary);
}

/* 法律条款正文列表排版（对齐论坛：子条款独立标题 + 有序列表逐条换行）
   display:block 覆盖 Bootstrap .card 的 flex：flex 容器内块级 margin 不折叠，
   会使 h5(mt-4) 与前一 ol(margin-bottom) 间距相加（42px）而比 sup 多出空行 */
.legal-body { display: block; }
.legal-body p { margin-bottom: 14px; }
.legal-body ol { padding-left: 24px; margin: 12px 0 18px; }
.legal-body ol li { margin-bottom: 10px; }
.legal-body h6 { font-weight: 700; font-size: 17px; margin: 26px 0 10px; }

/* ── 协议 / 隐私政策页版式（2026-09-22：桌面左侧栏目录 sticky 跟随滚动 + 标题块 + 分区锚点；移动端回落为顶部目录）── */
/* 桌面：正文在左、目录在右（目录 sticky 跟随滚动） */
.legal-wrap { max-width: 1200px; margin: 0 auto; display: grid; grid-template-columns: minmax(0, 1fr) 264px; gap: 24px; align-items: start; }
.legal-top { grid-column: 1 / -1; grid-row: 1; background: #fff; border: 1px solid var(--ng-border); padding: 28px 32px; }
.legal-body { grid-column: 1; grid-row: 2; }
.legal-top h1 { font-size: 24px; font-weight: 700; margin: 0 0 6px; letter-spacing: -.2px; }
.legal-top .legal-meta { font-size: 12px; color: var(--ng-text-muted); }
.legal-top .legal-links { margin-top: 14px; display: flex; gap: 18px; flex-wrap: wrap; font-size: 13px; }
.legal-top .legal-links a { color: var(--ng-primary); }
.legal-top .legal-links a.active { font-weight: 600; }
/* 左侧栏目录：sticky 跟随页面滚动 */
.legal-toc { grid-column: 2; grid-row: 2; position: sticky; top: 76px; background: #fff; border: 1px solid var(--ng-border); padding: 16px 18px; max-height: calc(100vh - 100px); max-height: calc(100dvh - 100px); overflow-y: auto; }
.legal-toc h3 { font-size: 13px; font-weight: 600; color: var(--ng-text-muted); margin: 0 0 10px; }
.legal-toc ol { margin: 0; padding-left: 18px; }
.legal-toc li { margin-bottom: 8px; font-size: 13px; line-height: 1.6; }
.legal-toc a { color: var(--ng-text-secondary); display: block; }
.legal-toc a:hover { color: var(--ng-primary); }
.legal-toc a.active { color: var(--ng-primary); font-weight: 600; }
.legal-body h5 { font-size: 18px; font-weight: 700; margin: 34px 0 10px; }
.legal-body h5:first-of-type { margin-top: 12px; }

/* 站内锚点跳转（协议/隐私政策的条款交叉引用）：平滑滚动 + 预留吸顶导航高度再加 16px 余量，
   否则跳转后目标标题会被上方固定导航遮住（scroll-padding-top 是全局生效的） */
html { scroll-behavior: smooth; scroll-padding-top: calc(var(--ng-nav-h) + 16px); }
/* 法务页正文中的交叉引用链接 */
.legal-body a { color: var(--ng-primary); text-decoration: none; }
.legal-body a:hover { text-decoration: underline; }
/* 正文允许超链接：站内蓝色 + 悬停下划线 */
.legal-body a { color: var(--ng-primary); }
.legal-body a:hover { text-decoration: underline; }
.legal-sec { scroll-margin-top: 76px; } /* 锚点跳转避开吸顶导航 */
/* 移动端 / 平板：目录回落为顶部（原样），正文在下 */
@media (max-width: 991px) {
    .legal-wrap { display: block; }
    .legal-top { margin-bottom: 16px; }
    .legal-toc { position: static; max-height: none; overflow: visible; margin-bottom: 16px; }
    .legal-toc ol { columns: 2; column-gap: 36px; }
    .legal-toc li { break-inside: avoid; }
}
@media (max-width: 768px) {
    .legal-top { padding: 20px; }
    .legal-toc ol { columns: 1; }
}

/* ─── 首页门户（浅色首屏 + 左上/右下 CSS 圆形淡蓝光晕 + 平台介绍 + 渐变 CTA）─── */
.docs-hero {
    position: relative; overflow: hidden;
    background: #ffffff;
    border-bottom: 1px solid var(--ng-border);
    padding: 88px 0;
}
.hero-grid { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; gap: 56px; padding-left: 2rem; }
.hero-copy { flex: 0 1 640px; min-width: 0; }
.hero-art { flex: 0 0 400px; max-width: 400px; display: flex; align-items: center; justify-content: center; }
.hero-art img { display: block; width: 100%; height: auto; }
.hero-eyebrow {
    display: inline-block; font-size: 12px; font-weight: 700; letter-spacing: 1.5px;
    text-transform: uppercase; color: var(--ng-primary); margin-bottom: 14px;
}
.hero-title {
    font-size: 46px; font-weight: 800; letter-spacing: -.5px; line-height: 1.18;
    color: var(--ng-text); margin: 0 0 16px;
}
.hero-hl { color: var(--ng-primary); }
.hero-sub { font-size: 17px; line-height: 1.8; color: var(--ng-text-secondary); margin: 0 0 28px; max-width: 560px; }
.hero-cta { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 22px; }
.hero-links { display: flex; flex-wrap: wrap; align-items: center; font-size: 13px; color: var(--ng-text-muted); }
.hero-links a { color: var(--ng-text-muted); margin-right: 18px; transition: color .15s; }
.hero-links a:hover { color: var(--ng-primary); }

/* 左上 / 右下：CSS 圆形淡蓝光晕（径向渐变） */
.hero-glow {
    position: absolute; z-index: 0; border-radius: 50%; pointer-events: none;
    background: radial-gradient(circle, rgba(108,92,231,.22) 0%, rgba(108,92,231,.10) 40%, rgba(108,92,231,.03) 65%, rgba(108,92,231,0) 78%);
}
.hero-glow--tl { width: 520px; height: 520px; top: -200px; left: -160px; }
.hero-glow--br { width: 580px; height: 580px; bottom: -220px; right: -160px; }

@media (max-width: 991px) {
    .docs-hero { padding: 56px 0; }
    .hero-grid { flex-direction: column; align-items: stretch; gap: 32px; padding-left: 0; }
    .hero-copy { max-width: none; }
    .hero-art { flex: none; width: 100%; max-width: 300px; margin: 0 auto; }
    .hero-title { font-size: 30px; }
    .hero-sub { font-size: 15px; max-width: none; }
    .hero-glow--tl { width: 340px; height: 340px; top: -140px; left: -120px; }
    .hero-glow--br { width: 380px; height: 380px; bottom: -150px; right: -120px; }
}

/* 首页平台介绍（左文右图 / 右文左图 交替；每段带背景区分） */
.home-intro { margin-bottom: 8px; }
.home-intro-row {
    display: flex; align-items: center; gap: 40px;
    background: #f7f9fc; padding: 36px 40px; margin-bottom: 20px;
}
.home-intro-row:last-child { margin-bottom: 0; }
.home-intro-row:nth-child(even) { background: #eef4ff; }
.home-intro-row.is-reverse { flex-direction: row-reverse; }
.home-intro-text { flex: 1 1 0; min-width: 0; }
.home-intro-en {
    display: block; font-size: 12px; font-weight: 700; letter-spacing: 1px;
    text-transform: uppercase; color: var(--ng-primary); margin-bottom: 8px;
}
.home-intro-title { font-size: 24px; font-weight: 700; color: var(--ng-text); margin: 0 0 10px; }
.home-intro-desc { font-size: 14px; line-height: 1.8; color: var(--ng-text-secondary); margin: 0 0 16px; }
.home-intro-list { list-style: none; counter-reset: intro; margin: 0; padding: 0; }
.home-intro-list li {
    position: relative; padding-left: 24px; font-size: 14px; line-height: 1.7;
    color: var(--ng-text-secondary); margin-bottom: 8px;
}
.home-intro-list li:last-child { margin-bottom: 0; }
.home-intro-list li::before {
    counter-increment: intro; content: counter(intro) ".";
    position: absolute; left: 0; top: 0; color: var(--ng-primary); font-weight: 700;
}
.home-intro-media { flex: 0 0 260px; max-width: 260px; }
.home-intro-media.is-sm { flex: 0 0 190px; max-width: 190px; }
.home-intro-media img { display: block; width: 100%; height: auto; }

@media (max-width: 991px) {
    .home-intro-row, .home-intro-row.is-reverse { flex-direction: column; gap: 20px; padding: 28px 24px; margin-bottom: 16px; }
    .home-intro-media { flex: none; width: 100%; max-width: 200px; margin: 0 auto; }
    .home-intro-media.is-sm { max-width: 160px; }
    .home-intro-title { font-size: 20px; }
}
/* 首页 CTA */
.home-cta {
    background: linear-gradient(135deg, #6c5ce7 0%, #8f7dff 100%);
    padding: 40px 24px; text-align: center;
}
.home-cta-title { color: #fff; font-size: 22px; font-weight: 700; margin: 0 0 8px; }
.home-cta-sub { color: rgba(255,255,255,.9); font-size: 15px; max-width: 520px; margin: 0 auto 24px; }
.home-cta-actions { display: flex; justify-content: center; gap: 12px; flex-wrap: wrap; }

.chart-box { position: relative; width: 100%; height: 260px; }
.chart-box--sm { height: 240px; }

.range-toggle { display: inline-flex; border: 1px solid var(--ng-border); border-radius: 4px; overflow: hidden; }
.range-toggle button {
    border: none; background: transparent; color: var(--ng-text-secondary, #5a6070);
    font-size: 12px; padding: 3px 11px; cursor: pointer; line-height: 1.5;
    transition: background .12s ease, color .12s ease;
}
.range-toggle button + button { border-left: 1px solid var(--ng-border); }
.range-toggle button:hover { color: var(--ng-primary); }
.range-toggle button.active { background: var(--ng-primary); color: #fff; }
/* === /仪表盘改进 === */

.card:hover { box-shadow: var(--ng-shadow); }

.stat-card:hover { box-shadow: var(--ng-shadow); }

.card-hover:hover { box-shadow: var(--ng-shadow); }

.stat-card-lg:hover { box-shadow: var(--ng-shadow); }

/* ═══════════════════════════════════════════════════════════════
   后台（/admin）统一组件层（2026-09-22 重构）
   外壳(flex) + 页头 + 工具条 + 卡片 + 表格 + 标签 + 空状态 + 分区 + 键值行。
   写在本文件最后：覆盖前面散落/重复的后台样式（.sidebar-nav/.admin-card/
   .admin-table/.status-dot/.form-section 等旧定义），页面统一改用这里的类。
   ═══════════════════════════════════════════════════════════════ */

/* ── 外壳：左全高侧栏 + 右侧顶栏（2026-11-15 复刻 acc / sup 后台骨架，令牌全用 --ng-*）──
   后台是工具型界面：品牌放侧栏顶部，顶栏只管面包屑与账号。
   侧栏本身不滚动，滚动交给 .admin-menu；窄屏抽屉由 admin-shell.js 驱动。 */
.admin-app { display: flex; min-height: 100vh; min-height: 100dvh; background: var(--ng-bg); }
.admin-side {
    width: 240px; flex: 0 0 auto; display: flex; flex-direction: column;
    position: sticky; top: 0; height: 100vh; height: 100dvh;
    background: var(--ng-bg-white); border-right: 1px solid var(--ng-border);
    overflow: visible; z-index: 100;
    transition: transform .36s cubic-bezier(.4, 0, .2, 1);
}
.admin-brand {
    height: 64px; flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
    padding: 0 20px; text-decoration: none;
    border-bottom: 1px solid var(--ng-border);
}
/* 组合标是 960×320 横版，按宽度铺开而不是给固定高度：
   168px 宽对应 56px 高，画布内文字约 12px，在 240px 侧栏里刚好。 */
.admin-brand img { width: 100%; max-width: 168px; height: auto; display: block; }

.admin-menu { flex: 1 1 auto; overflow-y: auto; overscroll-behavior: contain; padding: 8px 0; }
.admin-side .nav-link {
    display: flex; align-items: center; gap: 10px;
    height: 46px; padding: 0 16px; font-size: 13px;
    color: var(--ng-text-secondary); text-decoration: none;
    border-radius: 0; border-left: 0; cursor: pointer; user-select: none;
    transition: background-color .18s ease, color .18s ease;
}
.admin-side .nav-link i:first-child {
    width: 16px; font-size: 15px; text-align: center;
    color: var(--ng-text-muted); flex: 0 0 auto;
    transition: color .18s ease;
}
.admin-side .nav-link:hover { background: var(--ng-primary-bg); color: var(--ng-primary); }
.admin-side .nav-link:hover i:first-child { color: var(--ng-primary); }
.admin-side .nav-link.active {
    position: relative; background: var(--ng-primary-bg);
    color: var(--ng-primary); font-weight: 600;
}
.admin-side .nav-link.active i:first-child { color: var(--ng-primary); }
.admin-side .nav-link.active::after {
    content: ''; position: absolute; right: 0; top: 0; bottom: 0;
    width: 2px; background: var(--ng-primary);
}

/* 分组：grid-template-rows 0fr 到 1fr 做高度过渡，不用写死 max-height；
   折叠时补 visibility，避免隐藏的链接仍能被 Tab 聚焦。 */
.admin-side .nav-link .caret {
    margin-left: auto; font-size: 11px; color: var(--ng-text-muted);
    transition: transform .18s ease;
}
.admin-side .nav-group-toggle.is-open .caret { transform: rotate(90deg); }
.admin-side .nav-sub {
    display: grid; grid-template-rows: 0fr; overflow: hidden;
    transition: grid-template-rows .28s cubic-bezier(.4, 0, .2, 1);
}
.admin-side .nav-group.is-open .nav-sub { grid-template-rows: 1fr; }
.admin-side .nav-sub-inner {
    min-height: 0; overflow: hidden; opacity: 0; visibility: hidden;
    transition: opacity .22s ease, visibility 0s linear .28s;
}
.admin-side .nav-group.is-open .nav-sub-inner {
    opacity: 1; visibility: visible; transition: opacity .22s ease, visibility 0s;
}
.admin-side .nav-link.sub { height: 40px; padding-left: 42px; }
.admin-side .nav-group.has-active > .nav-group-toggle {
    background: var(--ng-primary-bg); color: var(--ng-primary); font-weight: 600;
}
.admin-side .nav-group.has-active > .nav-group-toggle i { color: var(--ng-primary); }

.admin-side-foot { flex: 0 0 auto; border-top: 1px solid var(--ng-border); padding: 8px 0 10px; }
.admin-side .nav-link.text-danger, .admin-side .nav-link.is-danger { color: var(--ng-danger); }
.admin-side .nav-link.text-danger:hover, .admin-side .nav-link.is-danger:hover { background: #fff1f0; color: var(--ng-danger); }
.admin-side .nav-link.text-danger:hover i:first-child, .admin-side .nav-link.is-danger:hover i:first-child { color: var(--ng-danger); }

.admin-mask { display: none; position: fixed; inset: 0; background: rgba(0,0,0,.4); z-index: 99; }

/* ── 右侧：顶栏 + 内容区 ── */
.admin-main-area { flex: 1 1 auto; display: flex; flex-direction: column; min-width: 0; }
.admin-header {
    height: 56px; flex: 0 0 auto; display: flex; align-items: center;
    justify-content: space-between; gap: 16px; padding: 0 24px;
    background: var(--ng-bg-white); border-bottom: 1px solid var(--ng-border);
    position: sticky; top: 0; z-index: 90;
}
.admin-header-left, .admin-header-right { display: flex; align-items: center; gap: 12px; min-width: 0; }
.admin-crumb {
    font-size: 13px; color: var(--ng-text-muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.admin-crumb a { color: var(--ng-text-muted); text-decoration: none; transition: color .2s ease; }
.admin-crumb a:hover { color: var(--ng-primary); }
.admin-crumb-sep { margin: 0 6px; }
.admin-crumb b { font-weight: 600; color: var(--ng-text); }
.admin-sep { width: 1px; height: 24px; background: var(--ng-border); flex: 0 0 auto; }
.admin-sep-burger { display: none; }
.admin-aux {
    font-size: 13px; color: var(--ng-text-secondary); text-decoration: none;
    white-space: nowrap; transition: color .2s ease;
}
.admin-aux:hover { color: var(--ng-primary); }
.admin-aux.is-danger:hover { color: var(--ng-danger); }

/* 汉堡：与前台导航同一套三横图标，打开时转成叉 */
.admin-burger {
    display: none; width: 36px; height: 36px; flex: 0 0 auto;
    padding: 0; align-items: center; justify-content: center;
    border: 0; background: transparent; color: var(--ng-text-secondary);
    cursor: pointer; outline: 0; box-shadow: none;
}
.admin-burger:hover, .admin-burger:focus, .admin-burger:focus-visible, .admin-burger:active {
    border: 0; outline: 0; box-shadow: none; color: var(--ng-primary);
}
.admin-burger .css-menu { position: relative; display: inline-block; width: 20px; height: 20px; }
.admin-burger .css-menu::after,
.admin-burger .css-menu::before,
.admin-burger .css-menu > i {
    content: ''; position: absolute; left: 0; right: 0; height: 2px;
    background: currentColor;
    transition: transform .4s ease, opacity .25s ease, bottom .4s ease, right .4s ease;
}
.admin-burger .css-menu > i { bottom: 9px; right: 2px; }
.admin-burger .css-menu::before { bottom: 16px; right: 4px; }
.admin-burger .css-menu::after { bottom: 2px; }
.admin-burger.is-open .css-menu > i { opacity: 0; }
.admin-burger.is-open .css-menu::before { bottom: 9px; right: 0; transform: rotate(-45deg); }
.admin-burger.is-open .css-menu::after { bottom: 9px; transform: rotate(45deg); }

/* 账号下拉：与前台导航同一套观感，0 圆角面板 */
.admin-user { display: flex; align-items: center; gap: 8px; text-decoration: none; color: var(--ng-text); cursor: pointer; }
.admin-user:hover { color: var(--ng-text); }
.admin-user img { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; border: 1px solid var(--ng-border); flex: 0 0 auto; }
.admin-user-name { max-width: 88px; min-width: 0; font-size: 12px; font-weight: 500; line-height: 1; overflow: hidden; white-space: nowrap; }
.admin-user-caret {
    width: 0; height: 0; flex: 0 0 auto;
    border-left: 4px solid transparent; border-right: 4px solid transparent;
    border-top: 5px solid var(--ng-text-muted);
    transition: transform .2s ease;
}
.admin-user[aria-expanded="true"] .admin-user-caret { transform: rotate(180deg); }
.admin-user-dd {
    min-width: 240px; border-radius: 0; border: 1px solid var(--ng-border);
    box-shadow: var(--ng-shadow); margin-top: 10px; padding: 0;
}
.admin-user-dd-head {
    display: flex; align-items: center; gap: 12px; padding: 14px 16px;
    border-bottom: 1px solid var(--ng-border); background: var(--ng-bg);
}
.admin-user-dd-head img { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.admin-user-dd-name { font-size: 13px; font-weight: 600; color: var(--ng-text); }
.admin-user-dd-mail { font-size: 11px; color: var(--ng-text-muted); margin-top: 2px; }
.admin-user-dd-body { padding: 6px 0; }
.admin-user-dd-body .dropdown-item { font-size: 13px; padding: 8px 16px; }

.admin-main { flex: 1 1 auto; min-width: 0; padding: 24px 28px 48px; background: #f7f8fa; }
.admin-main > * + * { margin-top: 18px; }
.admin-content-area { background: #f7f8fa; } /* 兼容旧 class */

/* ── 页头 ── */
.admin-page-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin: 0; }
.admin-page-header h1 { font-size: 20px; font-weight: 700; margin: 0; }
.admin-page-header .sub { font-size: 13px; color: var(--ng-text-muted); margin-top: 2px; }
.admin-page-header .admin-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* ── 工具条（搜索 / 筛选）── */
.admin-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; background: #fff; border: 1px solid var(--ng-border); padding: 12px 16px; }
.admin-toolbar .form-control, .admin-toolbar .form-select { width: auto; min-width: 180px; }
.admin-toolbar .spacer { margin-left: auto; }

/* ── 卡片 ── */
.admin-card { background: #fff; border: 1px solid var(--ng-border); box-shadow: none; margin: 0; }
.admin-card > .card-header { background: #fff; padding: 13px 20px; border-bottom: 1px solid var(--ng-border); font-size: 14px; font-weight: 600; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.admin-card > .card-header .sub { font-size: 12px; color: var(--ng-text-muted); font-weight: 400; }
.admin-card > .card-body { padding: 18px 20px; }
.admin-card > .card-body.p-0 { padding: 0; }

/* ── 表格 ── */
.admin-table { width: 100%; margin: 0; border-collapse: collapse; }
.admin-table thead th { background: #fafbfc; font-size: 12px; font-weight: 600; color: var(--ng-text-muted); padding: 11px 16px; border-bottom: 1px solid var(--ng-border); white-space: nowrap; text-transform: none; letter-spacing: 0; }
.admin-table tbody td { padding: 12px 16px; font-size: 13px; color: var(--ng-text-secondary); border-bottom: 1px solid var(--ng-border); vertical-align: middle; }
.admin-table tbody tr:hover { background: #fafbfc; }
.admin-table tbody tr:last-child td { border-bottom: 0; }

/* ── 标签（状态 / 角色）── */
.a-tag { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; line-height: 18px; padding: 0 8px; border-radius: 10px; font-weight: 600; white-space: nowrap; }
.a-tag.ok { background: #e8f8ee; color: #1a9c54; }
.a-tag.off { background: #f2f3f5; color: var(--ng-text-muted); }
.a-tag.warn { background: #fff4e6; color: #d9730d; }
.a-tag.danger { background: #fff1f0; color: var(--ng-danger); }
.a-tag.info { background: var(--ng-primary-bg); color: var(--ng-primary); }

/* ── 空状态 ── */
.admin-empty { text-align: center; padding: 56px 20px; color: var(--ng-text-muted); }
.admin-empty .bi { font-size: 38px; display: block; opacity: .4; margin-bottom: 10px; }

/* ── 分区（设置 / 新建客户端 / 用户详情）── */
.admin-section { background: #fff; border: 1px solid var(--ng-border); }
.admin-section + .admin-section { margin-top: 18px; }
.admin-section-hd { padding: 13px 20px; border-bottom: 1px solid var(--ng-border); font-size: 14px; font-weight: 600; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.admin-section-hd .sub { font-size: 12px; color: var(--ng-text-muted); font-weight: 400; }
.admin-section-bd { padding: 18px 20px; }

/* ── 键值行（信息展示）── */
.admin-kv { display: flex; align-items: flex-start; gap: 16px; padding: 13px 0; border-bottom: 1px solid var(--ng-border); font-size: 13px; }
.admin-kv:last-child { border-bottom: 0; }
.admin-kv .k { width: 120px; flex: 0 0 auto; color: var(--ng-text-muted); }
.admin-kv .v { flex: 1 1 auto; min-width: 0; color: var(--ng-text); font-weight: 500; word-break: break-all; }
.admin-kv .v em { font-style: normal; font-weight: 400; color: var(--ng-text-muted); margin-left: 6px; }

/* ── 后台弹窗（封禁 / 解封）── */
/* 后台弹窗必须待在**全站 UI 层之下**：ui.js 的 toast / confirm 是 3000、banner 3200，
   而 .uc-drawer 只到 2010 —— 既有约定就是「页面浮层 ≤ 2010，UI 层永远在最上面」。
   原先给到 4000/4010，后果是**在弹窗里触发的 confirm 和 toast 全被弹窗盖住**
   （2026-10-01 实测：删号弹窗里点确认，确认框跑到了弹窗下面）。故降到 2400/2410。 */
.admin-modal-mask { position: fixed; inset: 0; margin: 0; background: rgba(17,24,39,.45); z-index: 2400; opacity: 0; visibility: hidden; transition: opacity .18s ease, visibility .18s; }
.admin-modal-mask.open { opacity: 1; visibility: visible; }
/* 兜底：遮罩跟随弹窗自动显示（同级匹配），旧版页面 JS 漏开遮罩也能正常压暗背景 */
.admin-modal-mask:has(~ .admin-modal.open) { opacity: 1; visibility: visible; }
.admin-modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: 0; width: calc(100% - 32px); max-width: 460px; background: #fff; border: 1px solid var(--ng-border); z-index: 2410; opacity: 0; visibility: hidden; transition: opacity .18s ease, visibility .18s, transform .18s ease; }
.admin-modal.open { opacity: 1; visibility: visible; transform: translate(-50%, -50%); }
.admin-modal-hd { padding: 14px 20px; border-bottom: 1px solid var(--ng-border); display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.admin-modal-hd h3 { margin: 0; font-size: 15px; font-weight: 600; }
.admin-modal-x { background: none; border: 0; color: var(--ng-text-muted); cursor: pointer; font-size: 15px; padding: 2px 6px; }
.admin-modal-x:hover { color: var(--ng-text); }
.admin-modal-bd { padding: 18px 20px; }
.admin-modal-ft { padding: 14px 20px; border-top: 1px solid var(--ng-border); display: flex; justify-content: flex-end; gap: 8px; }

/* 用户详情头 */
.admin-detail-head { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }
.admin-avatar { width: 72px; height: 72px; border-radius: 50%; object-fit: cover; border: 1px solid var(--ng-border); flex: 0 0 auto; }
.admin-detail-name { font-size: 20px; font-weight: 700; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.admin-detail-sub { font-size: 13px; color: var(--ng-text-muted); margin-top: 2px; }

/* 危险操作区 */
.admin-danger { border: 1px solid #ffd7d5; }
.admin-danger > .admin-section-hd { color: var(--ng-danger); border-bottom-color: #ffe1e0; }
.admin-danger-actions { display: flex; flex-wrap: wrap; gap: 8px; }

/* ── 后台窄屏：侧栏改抽屉。层级顺序是顶栏 90 / 遮罩 99 / 侧栏 100 ── */
@media (max-width: 900px) {
    .admin-side { position: fixed; top: 0; bottom: 0; left: 0; height: auto; transform: translateX(-100%); box-shadow: 2px 0 16px rgba(0,0,0,.08); }
    .admin-side.is-open { transform: translateX(0); }
    .admin-mask.is-open { display: block; }
    .admin-burger { display: inline-flex; }
    .admin-header { padding: 0 16px; }
    .admin-aux, .admin-sep { display: none; }
    /* 汉堡与面包屑之间这条要保留，必须写在 .admin-sep 之后 */
    .admin-sep-burger { display: block; }
    .admin-user-name { display: none; }
    .admin-main { padding: 16px; }
}

/* 旧类归一：让仍在使用旧 class 的页面与新版观感一致 */
.form-section { background: #fff; border: 1px solid var(--ng-border); box-shadow: none; padding: 18px 20px; }
.form-section > h6 { margin: 0 0 16px; padding: 0 0 12px; border-bottom: 1px solid var(--ng-border); font-size: 14px; font-weight: 600; color: var(--ng-text); }
.empty-state { text-align: center; padding: 56px 20px; color: var(--ng-text-muted); }
.empty-state i, .empty-state .bi { font-size: 38px; display: block; opacity: .4; margin-bottom: 10px; }
.admin-filter-bar { background: #fff; border: 1px solid var(--ng-border); box-shadow: none; }
/* 表格内按钮/操作不许折行（否则窄列里"踢下线"会断成两行） */
.admin-table .btn { white-space: nowrap; }
.admin-table .action-group { flex-wrap: nowrap; }

/* ── 全局：页面滚动条 + 文本选中样式 ──
   这两组规则**已收敛到 ng-ui.css**（那里有完整实现与说明），此处不再重复一份。
   原因：main.css 只被前台与后台布局加载，而 auth-layout.php / layout.php 只加载 ng-ui.css；
   同一组规则在两处各写一份，既容易改一处漏一处，也会导出两条同样的规则。
   两条铁律仍适用（详见 ng-ui.css）：
     1) `scrollbar-width` / `scrollbar-color` 标准属性**只能放在 `@supports (-moz-appearance: none)` 里**
        留给 Firefox —— Chrome 121+ / Edge 只要看到元素上有这两个属性，就整组忽略 `::-webkit-scrollbar*`；
     2) `::selection` 与 `::-webkit-scrollbar*` 里直接写色值，不要用 var()。 */

@keyframes rl-card-in {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {                  /* 已声明减少动态效果时不做位移 */
}


/* ═══════════════════════════════════════════════════════════════════
   NimbusGate 自有区块
   ─────────────────────────────────────────────────────────────────
   1. 品牌锁定（导航栏 / 页脚）
   2. 页脚
   3. 通用占位页
   4. 页面组件（首页；后续 作品 / 套餐 / 公告 / 更新日志 续在此段）
   5. 响应式
   命名空间 .ng-* 与 .brand-*，与自有站点组件族（.uc-* / .auth-* / .admin-*）并列，互不冲突。
   ═══════════════════════════════════════════════════════════════════ */

/* ─── 1. 品牌锁定（门形标记 + 中英文文字）───
   组合标 nimbus-gate-logo-flat.svg 是 960×320 横版、文字仅占画布高度 22.5%，
   直接按 28px 渲染中文只有约 6px，故导航/页脚采用「标记图 + 文字」形态。 */
/* logo 区尺寸复刻月雨庭官网：标记图 36px，中文名 17px / 1px 字距，拉丁名 10px / 2px 字距。
   移动端居中的那份用小一号的 30px（对应月雨庭 .brand-logo-sm）。 */
.navbar-sup .navbar-brand { gap: 10px; }
.navbar-sup .navbar-brand img { height: var(--ng-logo-h); }
.navbar-sup .navbar-brand-centered img { height: 30px; }
.brand-text { display: flex; flex-direction: column; line-height: 1.25; }
.brand-mark { font-size: 17px; font-weight: 700; color: var(--ng-text); letter-spacing: 1px; }
.brand-latin { font-size: 10px; font-weight: 600; letter-spacing: 2px; color: var(--ng-text-muted); }

/* ─── 2. 页脚（结构对齐自有站点 .footer-sup）─── */
.footer-sup .footer-desc { font-size: 13px; line-height: 1.8; max-width: 360px; }
.footer-sup .footer-list { font-size: 13px; }
.footer-sup .footer-arrow { font-size: 11px; margin-right: 6px; }
.footer-sup .footer-cico { color: var(--ng-text-muted); margin-right: 8px; }
.footer-sup .footer-hr { border-color: var(--ng-border); margin: 24px 0 16px; opacity: 1; }
.footer-sup .footer-bottom { text-align: center; font-size: 12px; color: var(--ng-text-muted); }

/* ─── 3. 通用空状态 / 占位页：不加卡片，图标与文字直接落在页面背景上 ─── */
.ng-soon {
    padding: 72px 24px; text-align: center; max-width: 720px; margin: 0 auto;
}
.ng-soon > i { font-size: 40px; color: var(--ng-primary); opacity: .5; display: block; margin-bottom: 18px; }
.ng-soon-title { font-size: 22px; font-weight: 700; margin: 0 0 10px; }
.ng-soon-text { font-size: 14px; color: var(--ng-text-muted); margin: 0 0 26px; }
.ng-soon-actions { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }

/* ─── 4. 页面组件 ─── */

/* 4.1 Hero */
.ng-hero { background: var(--ng-bg-white); border-bottom: 1px solid var(--ng-border); padding: 72px 0 56px; }
/* 板块小标（kicker）：中文标题上方那一行英文。
   **不要给它背景、描边和左右内边距** —— 老版是个带 padding 的胶囊，
   字母起始位因此比下方的中文标题右移了 padding + border（13px），看起来就是「英文和中文没对齐」。
   现在做成纯文字块（display:block 保证左边缘与标题严格同一条线），靠字重与字距区分层级。 */
.ng-eyebrow {
    display: block;
    font-size: 12px; font-weight: 600; line-height: 1.4;
    letter-spacing: .12em;
    color: var(--ng-primary);
    margin-bottom: 12px;
}
.ng-hero-title { font-size: 40px; font-weight: 700; line-height: 1.2; margin: 0 0 12px; letter-spacing: -.01em; }
.ng-hl { color: var(--ng-primary); }
.ng-hero-sub { font-size: 18px; color: var(--ng-text-secondary); margin: 0 0 16px; }
.ng-hero-desc { font-size: 15px; color: var(--ng-text-muted); line-height: 1.8; margin: 0 0 28px; max-width: 520px; }
.ng-hero-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 36px; }
.ng-hero-stats { display: flex; flex-wrap: wrap; gap: 32px; padding-top: 24px; border-top: 1px solid var(--ng-border-light); }
.ng-stat b { display: block; font-size: 22px; font-weight: 700; color: var(--ng-text); line-height: 1.3; }
.ng-stat span { font-size: 13px; color: var(--ng-text-muted); }

/* 4.2 Hero 右侧状态面板 */
.ng-panel { background: var(--ng-bg-white); border: 1px solid var(--ng-border); box-shadow: var(--ng-shadow); }
.ng-panel-row { display: flex; align-items: center; gap: 14px; padding: 18px 20px; }
.ng-panel-row + .ng-panel-row { border-top: 1px solid var(--ng-border-light); }
.ng-dot { width: 8px; height: 8px; flex: 0 0 8px; }
.ng-dot--green  { background: var(--ng-success); }
.ng-dot--blue   { background: var(--ng-primary); }
.ng-dot--cyan   { background: #06b6d4; }
.ng-dot--purple { background: #8b5cf6; }
.ng-panel-copy { display: flex; flex-direction: column; min-width: 0; }
.ng-panel-label { font-size: 13px; color: var(--ng-text-muted); }
.ng-panel-desc { font-size: 12px; color: var(--ng-text-muted); opacity: .8; }
.ng-panel-value { margin-left: auto; font-size: 14px; font-weight: 600; color: var(--ng-text); white-space: nowrap; }

/* 4.3 通用区块 */
.ng-sec { padding: 64px 0; }
.ng-sec--soft { background: var(--ng-bg); }
.ng-sec-head { max-width: 640px; margin: 0 0 36px; }
.ng-sec-title { font-size: 26px; font-weight: 700; margin: 0 0 8px; }
.ng-sec-sub { font-size: 15px; color: var(--ng-text-muted); margin: 0; }
.ng-sec-foot { margin-top: 36px; }

/* 4.4 卡片 */
.ng-card {
    height: 100%; background: var(--ng-bg-white); border: 1px solid var(--ng-border);
    padding: 24px; transition: box-shadow .2s, border-color .2s;
}
.ng-card:hover { border-color: var(--ng-primary-light); box-shadow: var(--ng-shadow); }
.ng-card--lg { padding: 32px; }
.ng-card-ico {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; font-size: 18px; margin-bottom: 16px;
    background: var(--ng-primary-bg); color: var(--ng-primary);
}
.ng-ico--cyan   { background: #ecfeff; color: #06b6d4; }
.ng-ico--pink   { background: #fdf2f8; color: #ec4899; }
.ng-ico--purple { background: #f5f3ff; color: #8b5cf6; }
.ng-card-title { font-size: 16px; font-weight: 600; margin: 0 0 8px; }
.ng-card-desc { font-size: 14px; line-height: 1.75; color: var(--ng-text-secondary); margin: 0; }
.ng-tag {
    display: inline-block; font-size: 12px; font-weight: 600; color: var(--ng-primary);
    background: var(--ng-primary-bg); padding: 4px 10px; margin-bottom: 14px;
}
.ng-points { list-style: none; padding: 0; margin: 18px 0 0; display: grid; gap: 10px; }
.ng-points li { display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--ng-text-secondary); }
.ng-points li i { color: var(--ng-primary); }

/* 4.5 流程步骤 */
.ng-step { height: 100%; background: var(--ng-bg-white); border: 1px solid var(--ng-border); padding: 24px; }
.ng-step-num { display: block; font-size: 12px; font-weight: 700; letter-spacing: .1em; color: var(--ng-text-muted); margin-bottom: 12px; }
.ng-step-ico { display: block; font-size: 22px; color: var(--ng-primary); margin-bottom: 14px; }

/* 4.6 深色横幅 */
.ng-band { background: #1a1a2e; color: #fff; padding: 64px 0; }
.ng-band-title { font-size: 26px; font-weight: 700; margin: 0 0 8px; color: #fff; }
.ng-band-sub { font-size: 15px; color: rgba(255, 255, 255, .72); margin: 0 0 36px; }
.ng-band-points { margin-bottom: 8px; }
.ng-band-point { display: flex; flex-direction: column; gap: 6px; }
.ng-band-point i { font-size: 20px; color: #8f7dff; }
.ng-band-point b { font-size: 15px; font-weight: 600; color: #fff; }
.ng-band-point span { font-size: 13px; color: rgba(255, 255, 255, .65); line-height: 1.7; }
.ng-band-note {
    margin: 32px 0 0; padding-top: 20px; border-top: 1px solid rgba(255, 255, 255, .12);
    font-size: 13px; color: rgba(255, 255, 255, .55);
}

/* 4.7 FAQ */
.ng-faq { height: 100%; background: var(--ng-bg-white); border: 1px solid var(--ng-border); padding: 22px 24px; }
.ng-faq-q { font-size: 15px; font-weight: 600; margin: 0 0 8px; }
.ng-faq-a { font-size: 14px; line-height: 1.75; color: var(--ng-text-secondary); }

/* ─── 5. 响应式 ─── */
@media (max-width: 992px) {
    .navbar-sup .navbar-brand-centered { gap: 8px; }
    .navbar-sup .navbar-brand-centered .brand-mark { font-size: 14px; }
}

@media (max-width: 720px) {
    .ng-hero { padding: 48px 0 40px; }
    .ng-hero-title { font-size: 30px; }
    .ng-hero-sub { font-size: 16px; }
    .ng-hero-stats { gap: 20px; }
    .ng-hero-actions { margin-bottom: 28px; }
    .ng-hero-actions .btn { flex: 1 1 auto; }
    .ng-sec, .ng-band { padding: 44px 0; }
    .ng-sec-title, .ng-band-title { font-size: 22px; }
    .ng-soon { padding: 48px 20px; }
    .ng-soon-actions .btn { flex: 1 1 auto; }
}

/* ─── 4.8 产品介绍页（/product/）─── */

/* 页头（比首页 Hero 略矮） */
.ng-hero--page { padding: 56px 0 48px; }
/* 无边框卡片变体（用于「背景」「支持格式」这类纯文字块） */
.ng-card--plain { border-color: transparent; background: transparent; padding: 0; }
.ng-card--plain:hover { box-shadow: none; border-color: transparent; }
.ng-card--plain .ng-card-ico { background: var(--ng-primary-bg); }

/* 标签片 */
.ng-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.ng-chip { font-size: 12px; color: var(--ng-text-secondary); background: var(--ng-bg); border: 1px solid var(--ng-border); padding: 4px 10px; }
.ng-chip--brand { color: var(--ng-primary); background: var(--ng-primary-bg); border-color: var(--ng-primary-light); }
.ng-fmt-ico { color: var(--ng-primary); margin-right: 8px; }

/* 功能模块（左文右图，偶数行左右互换） */
.ng-module { display: grid; grid-template-columns: 0.85fr 1.15fr; gap: 40px; align-items: center; padding: 32px 0; }
.ng-module + .ng-module { border-top: 1px solid var(--ng-border); }
.ng-module:nth-child(even) .ng-module-copy { order: 2; }
.ng-module-title { font-size: 20px; font-weight: 700; margin: 0 0 10px; }
.ng-module-shots { min-width: 0; }
.ng-tabs { gap: 4px; border-bottom: 1px solid var(--ng-border); margin-bottom: 16px; }
.ng-tabs .nav-link {
    border: 0; border-bottom: 2px solid transparent; border-radius: 0;
    font-size: 14px; color: var(--ng-text-secondary); padding: 10px 14px; background: none;
}
.ng-tabs .nav-link:hover { color: var(--ng-primary); }
.ng-tabs .nav-link.active { color: var(--ng-primary); border-bottom-color: var(--ng-primary); font-weight: 600; background: none; }
.ng-tab-content img {
    display: block; width: 100%; height: auto;
    border: 1px solid var(--ng-border); background: var(--ng-bg-white);
}


@media (max-width: 992px) {
    .ng-module { grid-template-columns: 1fr; gap: 20px; }
    .ng-module:nth-child(even) .ng-module-copy { order: 0; }
}

@media (max-width: 720px) {
    .ng-hero--page { padding: 40px 0 32px; }
    .ng-tabs .nav-link { padding: 8px 10px; font-size: 13px; }
}

/* ─── 4.9 建筑广场（/plaza/）─── */
.ng-note { font-size: 13px; color: var(--ng-text-muted); margin: 0; }
.ng-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 26px; }
.ng-filter {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 13px; color: var(--ng-text-secondary);
    background: var(--ng-bg-white); border: 1px solid var(--ng-border); padding: 7px 14px;
}
.ng-filter.is-active { color: var(--ng-primary); border-color: var(--ng-primary-light); background: var(--ng-primary-bg); }
.ng-filter .ng-dot { display: inline-block; vertical-align: middle; }
.ng-work { height: 100%; background: var(--ng-bg-white); border: 1px solid var(--ng-border); padding: 20px; transition: border-color .2s, box-shadow .2s; }
.ng-work:hover { border-color: var(--ng-primary-light); box-shadow: var(--ng-shadow); }
.ng-work-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 14px; }
.ng-work-date { font-size: 12px; color: var(--ng-text-muted); }
.ng-work-title { font-size: 17px; font-weight: 600; margin: 0 0 14px; }
.ng-submit { display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap; }

/* ─── 4.10 帮助文档（/docs）：开放文档三栏 ───
   通栏铺满、不套 .container：左右栏直接贴视口左右边缘，中间占满剩余宽度（与 .uc-shell 同一套做法）。
   左右 sticky 钉在吸顶导航下方、高度取「视口高 − 导航高」，各自独立滚动
   （overscroll-behavior: contain 防止滚到底带着整页一起走）。
   中栏与两栏之间只留一条 1px 竖线，不再用卡片或大留白把内容挤到中间。
   三栏统一纯白底：容器与左右栏都显式给白，sticky 滚动时不会透出页面浅灰底。
   各栏底部留 96px 给底部悬浮购买按钮，避免滚到底时末行被压住。 */
.ng-doc-shell { display: grid; grid-template-columns: 280px minmax(0, 1fr) 240px; gap: 0; align-items: start; padding: 0; background: var(--ng-bg-white); }
.ng-doc-side, .ng-doc-toc { position: sticky; top: var(--ng-nav-h); height: calc(100vh - var(--ng-nav-h)); height: calc(100dvh - var(--ng-nav-h)); overflow-y: auto; overscroll-behavior: contain; background: var(--ng-bg-white); }
.ng-doc-side { padding: 32px 28px 96px clamp(20px, 2.5vw, 44px); }
.ng-doc-toc { padding: 32px clamp(20px, 2.5vw, 44px) 96px 28px; }

/* 左栏：分组 + 条目 + 纯前端过滤框 */
.ng-doc-nav-toggle { display: none; }
.ng-doc-filter { position: relative; margin-bottom: 20px; }
.ng-doc-filter i { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); font-size: 13px; color: var(--ng-text-muted); }
.ng-doc-filter input { width: 100%; height: 36px; padding: 0 12px 0 34px; border: 1px solid var(--ng-border); border-radius: 8px; background: var(--ng-bg-white); font-size: 13px; color: var(--ng-text); }
.ng-doc-filter input:focus { outline: none; border-color: var(--ng-primary); }
.ng-doc-nav-group { margin-bottom: 20px; }
.ng-doc-nav-group[hidden] { display: none; }
.ng-doc-nav-cap { font-size: 11px; font-weight: 700; letter-spacing: .08em; color: var(--ng-text-muted); margin: 0 0 8px; padding-left: 10px; }
.ng-doc-nav-list { list-style: none; margin: 0; padding: 0; }
.ng-doc-nav-item[hidden] { display: none; }
.ng-doc-nav-link { display: block; padding: 7px 10px; font-size: 13px; line-height: 1.5; color: var(--ng-text-secondary); text-decoration: none; border-left: 2px solid transparent; }
.ng-doc-nav-link:hover { color: var(--ng-primary); background: rgba(108, 92, 231, .05); }

/* 中栏：白底阅读面（承载正文，与空状态卡片不是一回事），通栏后占满剩余宽度 */
.ng-doc-main { min-width: 0; padding: 32px clamp(28px, 5vw, 88px) 96px; background: var(--ng-bg-white); border-left: 1px solid var(--ng-border); border-right: 1px solid var(--ng-border); }
.ng-doc-crumb { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--ng-text-muted); }
.ng-doc-crumb a { color: var(--ng-text-muted); text-decoration: none; }
.ng-doc-crumb a:hover { color: var(--ng-primary); }
.ng-doc-crumb i { font-size: 10px; }
.ng-doc-head { padding-bottom: 32px; border-bottom: 1px solid var(--ng-border); margin-bottom: 8px; }
.ng-doc-title { font-size: 30px; font-weight: 700; margin: 12px 0 16px; }
.ng-doc-lead { font-size: 14px; color: var(--ng-text-muted); line-height: 1.9; margin: 0; }
.ng-doc-sec { padding-top: 56px; }
.ng-doc-sec, .ng-doc-md h2, .ng-doc-md h3[id], .ng-doc-md li[id] { scroll-margin-top: calc(var(--ng-nav-h) + 20px); }

/* md 排版：中栏正文只用 Markdown 能表达的元素，样式一次备齐，
   以后换成真正的 Markdown 渲染结果也能直接套用，不必再补样式。
   阅读节奏按「松」处理：正文行高 2.15、段间 22px、标题上方留白 44px，
   长文档滚动时标题能明显把上下两段分开，不会糊成一片。 */
.ng-doc-md { font-size: 15px; line-height: 2.15; letter-spacing: .02em; color: var(--ng-text-secondary); }
.ng-doc-md h2 { font-size: 22px; font-weight: 700; color: var(--ng-text); margin: 0 0 26px; padding-bottom: 16px; border-bottom: 1px solid var(--ng-border-light); }
.ng-doc-md h3 { font-size: 16px; font-weight: 700; color: var(--ng-text); margin: 44px 0 16px; }
.ng-doc-md h4 { font-size: 14px; font-weight: 700; color: var(--ng-text); margin: 34px 0 12px; }
.ng-doc-md p { margin: 0 0 22px; }
.ng-doc-md ul, .ng-doc-md ol { margin: 0 0 26px; padding-left: 1.6em; }
.ng-doc-md li { margin-bottom: 12px; }
.ng-doc-md li::marker { color: var(--ng-primary); font-weight: 600; }
.ng-doc-md strong { color: var(--ng-text); font-weight: 600; }
.ng-doc-md a { color: var(--ng-primary); text-decoration: none; border-bottom: 1px solid rgba(108, 92, 231, .35); }
.ng-doc-md a:hover { border-bottom-color: var(--ng-primary); }
.ng-doc-md blockquote { margin: 0 0 18px; padding: 6px 0 6px 16px; border-left: 3px solid var(--ng-primary); color: var(--ng-text-muted); }
.ng-doc-md blockquote p:last-child { margin: 0; }
.ng-doc-md code { padding: 2px 6px; border-radius: 4px; background: rgba(108, 92, 231, .08); color: var(--ng-primary); font-size: .9em; }
.ng-doc-md pre { margin: 0 0 18px; padding: 16px 18px; overflow-x: auto; background: #f7f7fb; border: 1px solid var(--ng-border); }
.ng-doc-md pre code { padding: 0; background: none; color: var(--ng-text); font-size: 13px; }
.ng-doc-md table { width: 100%; margin: 0 0 18px; border-collapse: collapse; font-size: 14px; }
.ng-doc-md th, .ng-doc-md td { padding: 10px 12px; border: 1px solid var(--ng-border); text-align: left; }
.ng-doc-md th { background: #fafafd; color: var(--ng-text); font-weight: 600; }
.ng-doc-md hr { margin: 32px 0; border: 0; border-top: 1px solid var(--ng-border); }
.ng-doc-md img { max-width: 100%; height: auto; }
.ng-doc-sec-lead { color: var(--ng-text-muted); }

/* 右栏：本页目录树。一级加粗深色、二级缩进浅色，共用一条左侧轨道线；
   当前小节由脚本切 is-active，用主色竖条加极浅主色底把位置点出来。 */
.ng-doc-toc-cap {
    font-size: 11px; font-weight: 700; letter-spacing: .1em;
    color: var(--ng-text-muted); text-transform: uppercase;
    margin: 0 0 18px; padding-bottom: 12px;
    border-bottom: 1px solid var(--ng-border-light);
}
.ng-doc-toc-list, .ng-doc-toc-sub { list-style: none; margin: 0; padding: 0; }
.ng-doc-toc-list > li { margin-bottom: 2px; }
.ng-doc-toc a {
    display: block;
    padding: 7px 10px 7px 14px;
    font-size: 13px; line-height: 1.6;
    color: var(--ng-text-secondary);
    text-decoration: none;
    border-left: 2px solid var(--ng-border);
    transition: color .2s, border-color .2s, background-color .2s;
}
.ng-doc-toc-list > li > a { color: var(--ng-text); font-weight: 600; }
.ng-doc-toc a:hover { color: var(--ng-primary); background: rgba(108, 92, 231, .04); }
.ng-doc-toc a.is-active {
    color: var(--ng-primary);
    border-left-color: var(--ng-primary);
    background: rgba(108, 92, 231, .06);
    font-weight: 600;
}
.ng-doc-toc-sub { margin: 2px 0 10px 0; }
.ng-doc-toc-sub a {
    font-size: 12.5px;
    padding: 5px 10px 5px 24px;
    color: var(--ng-text-muted);
    border-left: 2px solid var(--ng-border-light);
}
.ng-doc-toc-sub a.is-active { color: var(--ng-primary); border-left-color: var(--ng-primary); }

@media (max-width: 1199.98px) {
    .ng-doc-shell { grid-template-columns: 240px minmax(0, 1fr); }
    .ng-doc-toc { display: none; }
    .ng-doc-main { border-right: 0; }
}
@media (max-width: 991.98px) {
    .ng-doc-shell { grid-template-columns: minmax(0, 1fr); }
    .ng-doc-side { position: static; height: auto; overflow: visible; padding: 14px 20px; background: var(--ng-bg-white); border-bottom: 1px solid var(--ng-border); }
    .ng-doc-nav-toggle { display: flex; align-items: center; gap: 8px; width: 100%; padding: 0; border: 0; background: none; font-size: 14px; font-weight: 600; color: var(--ng-text); }
    .ng-doc-nav-toggle i:last-child { margin-left: auto; transition: transform .2s; }
    .ng-doc-side.is-open .ng-doc-nav-toggle i:last-child { transform: rotate(180deg); }
    .ng-doc-side-body { max-height: 0; overflow: hidden; transition: max-height .28s var(--ng-ease); }
    .ng-doc-side.is-open .ng-doc-side-body { max-height: 70vh; overflow-y: auto; margin-top: 14px; }
    .ng-doc-main { border-left: 0; padding: 24px 20px 96px; }
    .ng-doc-title { font-size: 24px; }
}

/* ─── 4.11 官方公告（/notices/）─── */
/* ══ 官方公告列表（2026-11-14 照参考图重做：居中大标题 + 分类 tab + 行式列表）══
   参考图是「新闻资讯」那套：标题居中带英文副标题、分类条选中项实心、
   每行左边一个类型小标签、中间标题加摘要、右边日期与「详情」，行间一条细线。
   配色沿用站内品牌紫（参考图是绿色，这里不照搬色相）。 */

/* 页头 */
.ng-nt-head {
    padding: 54px 0 36px;
    text-align: center;
}
.ng-nt-head-title {
    margin: 0 0 10px;
    font-size: clamp(26px, 2.4vw, 36px);
    font-weight: 800;
    letter-spacing: 2px;
    color: var(--ng-text);
}
.ng-nt-head-sub {
    display: block;
    font-size: 11px;
    letter-spacing: 5px;
    text-transform: uppercase;
    color: var(--ng-text-muted);
}

/* 分类条：整条浅灰底，tab 居中排开，选中项实心 */
.ng-nt-tabs-wrap {
    background: var(--ng-bg);
    border-top: 1px solid var(--ng-border-light);
    border-bottom: 1px solid var(--ng-border-light);
}
.ng-nt-tabs {
    display: flex;
    align-items: stretch;
    justify-content: center;
    flex-wrap: wrap;
    max-width: 1000px;
    margin: 0 auto;
}
.ng-nt-tab {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 15px clamp(18px, 3vw, 40px);
    font-size: 14px;
    font-weight: 500;
    color: var(--ng-text-secondary);
    text-decoration: none;
    white-space: nowrap;
    transition: background-color .2s ease, color .2s ease;
}
.ng-nt-tab-n {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--ng-text-muted);
    font-variant-numeric: tabular-nums;
    transition: color .2s ease;
}
.ng-nt-tab:hover { color: var(--ng-primary); }
.ng-nt-tab:hover .ng-nt-tab-n { color: var(--ng-primary); }
.ng-nt-tab.is-active {
    background: var(--ng-primary);
    color: #fff;
}
.ng-nt-tab.is-active .ng-nt-tab-n { color: rgba(255, 255, 255, .78); }

/* 列表主体 */
.ng-nt-body {
    max-width: 1000px;
    margin: 0 auto;
    padding: 8px 24px 72px;
}
.ng-nt-list { border-top: 1px solid var(--ng-border); }

/* 单行：标签 | 标题+摘要 | 日期+详情 */
.ng-nt-row {
    display: grid;
    grid-template-columns: 62px minmax(0, 1fr) 92px;
    align-items: center;
    gap: 22px;
    padding: 20px 14px;
    border-bottom: 1px solid var(--ng-border-light);
    text-decoration: none;
    transition: background-color .18s ease;
}
.ng-nt-row:hover { background: var(--ng-primary-bg); }

/* 类型标签：默认浅灰底，悬停时整行高亮、标签跟着变实心主色 */
.ng-nt-tag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    height: 26px;
    padding: 0 10px;
    background: var(--ng-bg);
    color: var(--ng-text-secondary);
    font-size: 12px;
    line-height: 1;
    white-space: nowrap;
    transition: background-color .18s ease, color .18s ease;
}
.ng-nt-row:hover .ng-nt-tag {
    background: var(--ng-primary);
    color: #fff;
}
/* 置顶行：标签常亮，一眼能认出来 */
.ng-nt-row.is-pinned .ng-nt-tag {
    background: var(--ng-primary);
    color: #fff;
}

.ng-nt-main {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}
.ng-nt-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--ng-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: color .18s ease;
}
.ng-nt-row:hover .ng-nt-title { color: var(--ng-primary); }
.ng-nt-sum {
    font-size: 12.5px;
    color: var(--ng-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ng-nt-side {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
}
.ng-nt-date {
    font-size: 13px;
    color: var(--ng-text-muted);
    font-variant-numeric: tabular-nums;
}
.ng-nt-more {
    display: inline-flex;
    align-items: center;
    gap: 1px;
    font-size: 12.5px;
    color: var(--ng-primary);
}
.ng-nt-more i { font-size: 10px; transition: transform .18s ease; }
.ng-nt-row:hover .ng-nt-more i { transform: translateX(2px); }

/* 窄屏：标签移到标题上方，右侧只留日期 */
@media (max-width: 640px) {
    .ng-nt-head { padding: 36px 0 26px; }
    .ng-nt-body { padding: 4px 16px 52px; }
    .ng-nt-row {
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 8px 14px;
        padding: 16px 4px;
    }
    .ng-nt-tag {
        grid-column: 1 / -1;
        justify-self: start;
        height: 22px;
        padding: 0 8px;
        font-size: 11px;
    }
    .ng-nt-side { flex-direction: row; align-items: center; gap: 10px; }
    .ng-nt-title { white-space: normal; }
    .ng-nt-sum { display: none; }
}

.ng-notice-list { display: grid; gap: 1px; background: var(--ng-border); border: 1px solid var(--ng-border); }
.ng-notice {
    display: block; background: var(--ng-bg-white); padding: 22px 24px;
    text-decoration: none; color: inherit; transition: background-color .15s;
}
.ng-notice:hover { background: var(--ng-primary-bg); }
.ng-notice--pinned { border: 1px solid var(--ng-primary-light); background: var(--ng-primary-bg); margin-bottom: 24px; }
.ng-notice-top { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 10px; }
.ng-notice-date { font-size: 12px; color: var(--ng-text-muted); }
.ng-notice-slug { font-size: 12px; color: var(--ng-text-muted); }
.ng-notice-title { font-size: 17px; font-weight: 600; margin: 0 0 8px; }
.ng-notice-summary { font-size: 14px; line-height: 1.75; color: var(--ng-text-secondary); margin: 0; }
.ng-notice-type {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: 12px; font-weight: 600; padding: 3px 9px;
    color: var(--ng-primary); background: var(--ng-primary-light);
}
.ng-notice-type--blue   { color: #6c5ce7; background: #efecfd; }
.ng-notice-type--green  { color: #1a9c54; background: #e8f8ee; }
.ng-notice-type--orange { color: #d9730d; background: #fff4e6; }
.ng-notice-type--red    { color: #c92a2a; background: #fff1f0; }
.ng-notice-type--purple { color: #7c5ce7; background: #f3efff; }
.ng-notice-type--pink   { color: #c2337d; background: #fdeef5; }
.ng-notice-type--cyan   { color: #0b8fa8; background: #e6f8fb; }

/* ─── 4.12 公告详情（/notices/{slug}）与 404 ─── */
.ng-nd { padding: 36px 0 76px; }
.ng-nd-wrap { max-width: 860px; margin: 0 auto; }
.ng-crumb { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ng-text-muted); margin-bottom: 16px; }
.ng-crumb a { color: var(--ng-text-muted); text-decoration: none; transition: color .15s ease; }
.ng-crumb a:hover { color: var(--ng-primary); }
.ng-crumb span:last-child { color: var(--ng-text-secondary); }

/* 正文白底卡片：0 圆角，靠 1px 描边与浅灰页面底色分层 */
.ng-nd-card { background: var(--ng-bg-white); border: 1px solid var(--ng-border); }
.ng-nd-head { padding: 40px 44px 0; }
.ng-nd-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; margin-bottom: 16px; }
.ng-nd-date { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--ng-text-muted); }
.ng-nd-title { font-size: 26px; font-weight: 700; line-height: 1.42; letter-spacing: -.2px; margin: 0; color: var(--ng-text); }
.ng-nd-summary {
    margin: 18px 0 0; padding: 14px 18px;
    font-size: 14px; line-height: 1.8; color: var(--ng-text-secondary);
    background: var(--ng-bg); border-left: 3px solid var(--ng-primary);
}
.ng-nd-body {
    margin-top: 26px; padding: 28px 44px 32px;
    border-top: 1px solid var(--ng-border-light);
    font-size: 15px; line-height: 1.9; color: var(--ng-text-secondary);
}
.ng-nd-body p { margin: 0 0 18px; }
.ng-nd-body > :last-child { margin-bottom: 0; }
.ng-nd-body ul,
.ng-nd-body ol { margin: 0 0 18px; padding-left: 22px; }
.ng-nd-body li { margin-bottom: 8px; }
.ng-nd-body li:last-child { margin-bottom: 0; }
.ng-nd-body li::marker { color: var(--ng-primary); }
/* 富文本产出的排版元素（后台编辑器里的小标题 / 引用 / 行内代码 / 链接） */
.ng-nd-body h1,
.ng-nd-body h2,
.ng-nd-body h3,
.ng-nd-body h4 {
    margin: 26px 0 12px; font-weight: 600; line-height: 1.5; color: var(--ng-text);
}
.ng-nd-body h1 { font-size: 21px; }
.ng-nd-body h2 { font-size: 19px; }
.ng-nd-body h3 { font-size: 17px; }
.ng-nd-body h4 { font-size: 15px; }
.ng-nd-body h1:first-child,
.ng-nd-body h2:first-child,
.ng-nd-body h3:first-child,
.ng-nd-body h4:first-child { margin-top: 0; }
.ng-nd-body blockquote {
    margin: 0 0 18px; padding: 12px 16px;
    background: var(--ng-bg); border-left: 3px solid var(--ng-primary);
    color: var(--ng-text-secondary);
}
.ng-nd-body blockquote p:last-child { margin-bottom: 0; }
.ng-nd-body a { color: var(--ng-primary); text-decoration: none; border-bottom: 1px solid var(--ng-primary-light); }
.ng-nd-body a:hover { border-bottom-color: var(--ng-primary); }
.ng-nd-body strong { font-weight: 600; color: var(--ng-text); }
.ng-nd-body code {
    padding: 1px 6px; background: var(--ng-bg); border: 1px solid var(--ng-border-light);
    font-size: 13px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    color: #c7254e;
}
.ng-nd-foot {
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    padding: 18px 44px; background: #fafbfc; border-top: 1px solid var(--ng-border);
}
.ng-nd-back { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ng-text-secondary); text-decoration: none; transition: color .15s ease, gap .18s ease; }
.ng-nd-back:hover { color: var(--ng-primary); gap: 9px; }
.ng-nd-slug { font-size: 12px; color: var(--ng-text-muted); font-variant-numeric: tabular-nums; }

.ng-err-code { font-size: 72px; font-weight: 700; line-height: 1; color: var(--ng-primary); opacity: .18; margin-bottom: 8px; }

@media (max-width: 720px) {
    .ng-submit { flex-direction: column; align-items: flex-start; }
    .ng-submit .btn { width: 100%; }
    .ng-nd { padding: 24px 0 56px; }
    .ng-nd-head { padding: 26px 20px 0; }
    .ng-nd-title { font-size: 21px; }
    .ng-nd-body { margin-top: 20px; padding: 22px 20px 26px; font-size: 14px; }
    .ng-nd-foot { flex-direction: column; align-items: flex-start; gap: 10px; padding: 16px 20px; }
    .ng-notice, .ng-notice--pinned { padding: 18px; }
    .ng-err-code { font-size: 56px; }
}

/* ─── 4.13 后台仪表盘指标卡（对齐 acc 的 .dash-stat 组件）─── */
.dash-stat {
    background: var(--ng-bg-white); border: 1px solid var(--ng-border);
    padding: 16px 18px; display: flex; align-items: center; gap: 14px; height: 100%;
    transition: box-shadow .15s ease, border-color .15s ease;
}
.dash-stat:hover { border-color: var(--ng-primary); box-shadow: var(--ng-shadow); }
.dash-stat__icon {
    flex: 0 0 auto; width: 44px; height: 44px;
    display: flex; align-items: center; justify-content: center; font-size: 20px;
    background: var(--ng-primary-bg); color: var(--ng-primary); border-radius: 4px;
}
.dash-stat--warn .dash-stat__icon { background: #fff4e6; color: #d9730d; }
.dash-stat--ok   .dash-stat__icon { background: #e6f7ed; color: #1a9c54; }
.dash-stat--info .dash-stat__icon { background: #efecfd; color: var(--ng-primary); }
.dash-stat__body { min-width: 0; }
.dash-stat__num { font-size: 24px; font-weight: 700; color: var(--ng-text); line-height: 1.1; font-variant-numeric: tabular-nums; }
.dash-stat--warn .dash-stat__num { color: #d9730d; }
.dash-stat__label { font-size: 12px; color: var(--ng-text-secondary); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dash-stat__sub { font-size: 11px; color: var(--ng-text-muted); margin-top: 4px; }

/* 仪表盘页头与日期徽标 */
.dash-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 20px; }
.dash-head .dash-title { font-size: 22px; font-weight: 700; margin: 0; letter-spacing: -.2px; }
.dash-head .dash-sub { font-size: 13px; color: var(--ng-text-muted); margin-top: 6px; }
.dash-date {
    display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px;
    border: 1px solid var(--ng-border); border-radius: 999px; font-size: 13px;
    color: var(--ng-text-secondary); background: var(--ng-bg-white); white-space: nowrap;
}
.dash-date i { color: var(--ng-primary); }
.dash-env-row { display: flex; justify-content: space-between; font-size: 13px; padding: 7px 0; border-bottom: 1px solid var(--ng-border-light); }
.dash-env-row:last-child { border-bottom: none; }
.dash-quick .btn { justify-content: flex-start; text-align: left; }

@media (max-width: 576px) {
    .dash-date { display: none; }
}

/* ─── 4.13b 轻量页头（`.ng-phead`）───
   不是每个页面都需要通栏 hero。列表页 / 工具页（更新日志、官方公告、发布表单）用这套：
   一行标题 + 计数 + 一句说明，竖向留白只有 .ng-hero--page（72+56）的三分之一左右。
   判断口径：页面主体是「一列可滚动的条目」而不是「要说服访客的卖点」时，用轻量页头。 */
.ng-phead { padding: 44px 0 26px; }
.ng-phead-row { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.ng-phead-title { font-size: 26px; font-weight: 700; line-height: 1.25; letter-spacing: -.01em; margin: 0; }
.ng-phead-sub { font-size: 13px; color: var(--ng-text-muted); margin: 0; }
.ng-phead-desc { font-size: 14px; line-height: 1.8; color: var(--ng-text-secondary); margin: 10px 0 0; max-width: 620px; }

/* 紧跟轻量页头的内容区：去掉 .ng-sec 的上留白，避免两段留白叠在一起 */
.ng-sec--tight { padding-top: 0; }

/* ─── 4.14 更新日志时间轴（/changelog）───
   排版三列（2026-10-16 用户定）：**时间 → 时间线 → 卡片**
     · 左列 = 时间（只有日期）
     · 中列 = 时间线（圆点 + 连线画在左列的**右端**，所以顺序读起来是「时间、时间线、卡片」）
     · 右列 = 卡片 + 详情（版本号、版本类型、更新内容、下载）
   圆点是**圆形**（用户明确要求）—— 本站其它地方一律零圆角，这是有意为之的例外，别当遗留问题「修正」。
   行距 `--ng-tl-gap`、圆点位置 `--ng-tl-dot-top`／大小 `--ng-tl-dot-size` 三个 token 驱动，
   连线长度按 `-(gap + dot-top)` 算，**改行距只动 gap**。 */
.ng-tl {
    position: relative;
    --ng-tl-gap: 26px;
    --ng-tl-dot-top: 28px;
    --ng-tl-dot-size: 11px;
    /* 连线：品牌淡色 + 2px，比原先 1px 的灰线明显得多（用户要求「线条高亮」） */
    --ng-tl-line: var(--ng-primary-line);
    --ng-tl-line-w: 2px;
}
.ng-tl-item { display: grid; grid-template-columns: 128px minmax(0, 1fr); gap: 30px; padding-bottom: var(--ng-tl-gap); }
.ng-tl-item:last-child { padding-bottom: 0; }
/* 21px ≈ 卡片内边距（20px + 1px 边框），让左侧日期与右侧卡片首行（版本号）落在同一水平线上。
   不用 padding-left：圆点现在挂在左列的右端，不需要给左端留线槽。 */
.ng-tl-aside {
    position: relative;
    display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
    padding: 21px 0 0 0;
}
.ng-tl-dot {
    position: absolute; right: 0; top: var(--ng-tl-dot-top);
    width: var(--ng-tl-dot-size); height: var(--ng-tl-dot-size); box-sizing: border-box;
    border-radius: 50%;
    background: var(--ng-bg-white); border: 2px solid var(--ng-tl-line);
}
/* 最新版「聚焦」：实心品牌色 + 一圈浅色光晕 */
.ng-tl-dot.is-latest { background: var(--ng-primary); border-color: var(--ng-primary); box-shadow: 0 0 0 3px var(--ng-primary-light); }
/* 连线：从本行圆点下方一直画到下一行圆点的上沿（末行不画），线正好停在最后一个点上。
   right 取「圆点半径 − 线宽一半」让线正落在圆心的竖线上。 */
.ng-tl-aside::after {
    content: ''; position: absolute;
    right: calc((var(--ng-tl-dot-size) - var(--ng-tl-line-w)) / 2);
    top: calc(var(--ng-tl-dot-top) + var(--ng-tl-dot-size));
    bottom: calc(-1 * (var(--ng-tl-gap) + var(--ng-tl-dot-top)));
    width: var(--ng-tl-line-w); background: var(--ng-tl-line);
}
.ng-tl-item:last-child .ng-tl-aside::after { display: none; }
.ng-tl-date { font-size: 16px; font-weight: 600; color: var(--ng-text); font-variant-numeric: tabular-nums; }

.ng-tl-card { background: var(--ng-bg-white); border: 1px solid var(--ng-border); padding: 20px 22px 20px; min-width: 0; }
.ng-tl-card-hd {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-bottom: 14px; padding-bottom: 14px; border-bottom: 1px solid var(--ng-border-light);
}
.ng-tl-ver { font-size: 15px; font-weight: 700; color: var(--ng-text); font-variant-numeric: tabular-nums; }
.ng-tl-latest { font-size: 12px; color: var(--ng-primary); background: var(--ng-primary-bg); border: 1px solid var(--ng-primary-light); padding: 2px 8px; }
.ng-tl-notes { font-size: 14px; line-height: 1.85; color: var(--ng-text-secondary); }
/* 分组 + 列表（更新说明按「新增 / 修复 / …」分组录入时的渲染，见 Controller::releaseNoteGroups）
   标题样式 = **下划线式**（2026-10-16 用户否掉了原先的「左侧竖条」，并要求把标题拉大）。
   对齐约定（改的时候别破坏）：**以「卡片内容左缘」为唯一基准线** ——
   顶部版本号、分组标题、列表项圆点都压在这条线上（实测都是 261px）；
   列表项文字因为要给圆点让位，才自然缩进 12px —— 这是列表的常规缩进，不是没对齐。
   原先给标题加了 padding-left: 12px，结果标题比版本号多缩进一格，用户一眼就看出来了。 */
.ng-tl-group-title {
    font-size: 16px; font-weight: 700; line-height: 1.4; color: var(--ng-text);
    margin: 24px 0 14px; padding: 0 0 10px 0;
    border-bottom: 1px solid var(--ng-border-light);
    position: relative;
}
.ng-tl-notes > .ng-tl-group-title:first-child { margin-top: 0; }
.ng-tl-group-title::before {
    content: ''; position: absolute; left: 0; bottom: -1px;
    width: 34px; height: 2px; background: var(--ng-primary);
}
.ng-tl-group-title + .ng-tl-list { margin-top: 0; }
.ng-tl-list { list-style: none; margin: 0 0 14px; padding: 0; display: grid; gap: 7px; }
.ng-tl-list:last-child { margin-bottom: 0; }
.ng-tl-list li { position: relative; padding-left: 12px; }
.ng-tl-list li::before {
    content: ''; position: absolute; left: 0; top: .68em;
    width: 5px; height: 5px; border-radius: 50%; background: var(--ng-primary);
    opacity: .55;
}
/* 最新版那张卡额外强调一下边框，与圆点/徽标互相呼应（「最新版聚焦」） */
.ng-tl-item.is-latest .ng-tl-card { border-color: var(--ng-primary-light); }
.ng-tl-actions { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--ng-border-light); }

@media (max-width: 720px) {
    .ng-tl-item { grid-template-columns: minmax(0, 1fr); gap: 12px; padding-bottom: 22px; }
    /* 折单列后圆点无处可挂，挪到日期左边做「圆点 + 日期」一行，连线隐藏 */
    .ng-tl-aside { padding: 0 0 0 20px; }
    .ng-tl-dot { right: auto; left: 0; top: 6px; }
    .ng-tl-aside::after { display: none; }
    .ng-tl-card { padding: 16px 18px; }
}

/* =========================================================
   用户中心 · 既有 .uc-* 控制台组件族的补充件
   （main.css 里原有 139 个 uc-* 类覆盖了外壳/卡片/条目行/状态块，
     这里只补用户中心确实缺的几块：订阅状态卡、卡密分格输入、表单、步骤条、分页）
   全部使用 --ng-* 令牌，与其它页面同属一套设计系统。
   ========================================================= */

/* 卡片内容区（无标题栏时直接放内容） */
.uc-card-bd { padding: 16px 20px; }

/* ---------- 授权状态卡（展示规格对齐客户端：四态 / 7 天阈值 / 进度条） ---------- */

.uc-subcard-bd {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 18px 20px 20px;
}

.uc-sub-badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: var(--ng-radius-control);
    font-size: 12px;
    font-weight: 600;
    line-height: 1.7;
    white-space: nowrap;
}

.uc-subcard--lifetime .uc-sub-badge,
.uc-subcard--active .uc-sub-badge {
    background: rgba(34, 197, 94, .12);
    color: #1a9c54;
}

.uc-subcard--expiring .uc-sub-badge {
    background: rgba(245, 158, 11, .14);
    color: #b45309;
}

.uc-subcard--inactive .uc-sub-badge {
    background: rgba(239, 68, 68, .12);
    color: #dc2626;
}

.uc-sub-time {
    font-size: 2.4rem;
    font-weight: 700;
    line-height: 1.1;
    color: #1a9c54;
    font-family: "SF Mono", Consolas, Menlo, monospace;
}

.uc-sub-time span {
    margin-left: 6px;
    font-size: .9rem;
    font-weight: 600;
}

.uc-subcard--expiring .uc-sub-time { color: #b45309; }

.uc-subcard--inactive .uc-sub-time { color: #8a9099; }

.uc-sub-track {
    height: 6px;
    overflow: hidden;
    background: var(--ng-border-light);
}

.uc-sub-track i {
    display: block;
    height: 100%;
    background: #1a9c54;
    transition: width .4s var(--ng-ease);
}

.uc-subcard--expiring .uc-sub-track i { background: #f59e0b; }

.uc-subcard--inactive .uc-sub-track i { background: var(--ng-border); }

.uc-sub-details {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
    font-size: 13px;
    color: var(--ng-text-muted);
}

.uc-sub-note {
    margin: 0;
    padding: 8px 10px;
    background: rgba(245, 158, 11, .1);
    font-size: 12px;
    line-height: 1.6;
    color: #b45309;
}

.uc-sub-actions { display: flex; gap: 10px; }

/* ---------- 卡密分格输入（6-6-6-6-2） ---------- */

.uc-redeem-group {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: nowrap;
    justify-content: flex-start;
}

.uc-redeem-prefix {
    font-family: "SF Mono", Consolas, Menlo, monospace;
    font-size: 14px;
    font-weight: 700;
    color: var(--ng-primary);
}

.uc-redeem-dash { color: var(--ng-text-muted); }

.uc-redeem-box {
    width: 58px;
    min-height: 38px;
    padding: 8px 6px;
    border: 1px solid var(--ng-border);
    border-radius: var(--ng-radius-control);
    background: var(--ng-bg-white);
    color: var(--ng-text);
    font-family: "SF Mono", Consolas, Menlo, monospace;
    font-size: 14px;
    letter-spacing: 1px;
    text-align: center;
    text-transform: uppercase;
}

.uc-redeem-box:focus {
    outline: none;
    border-color: var(--ng-primary);
    box-shadow: var(--ng-focus-ring);
}

/* ---------- 表单（控制台风：紧凑、细边、无阴影） ---------- */

.uc-form { display: block; }

.uc-field { margin-bottom: 14px; }

.uc-field > label {
    display: block;
    margin-bottom: 6px;
    font-size: 13px;
    color: var(--ng-text-secondary);
}

.uc-field input[type="text"],
.uc-field input[type="password"],
.uc-field input[type="email"] {
    width: 100%;
    min-height: 38px;
    padding: 8px 12px;
    border: 1px solid var(--ng-border);
    border-radius: var(--ng-radius-control);
    background: var(--ng-bg-white);
    color: var(--ng-text);
    font-family: inherit;
    font-size: 14px;
}

.uc-field input:focus {
    outline: none;
    border-color: var(--ng-primary);
    box-shadow: var(--ng-focus-ring);
}

.uc-field input[readonly] { background: var(--ng-bg); color: var(--ng-text-muted); }

.uc-field-tip {
    display: block;
    margin-top: 6px;
    font-size: 12px;
    line-height: 1.6;
    color: var(--ng-text-muted);
}

.uc-form-actions {
    display: flex;
    gap: 10px;
    margin-top: 4px;
}

/* 验证码行：输入 + 发送按钮 */
.uc-code-row {
    display: flex;
    gap: 8px;
    align-items: stretch;
}

.uc-code-row input { flex: 1 1 auto; min-width: 0; }

.uc-code-btn {
    flex: 0 0 auto;
    padding: 8px 16px;
    border: 1px solid var(--ng-border);
    border-radius: var(--ng-radius-control);
    background: var(--ng-bg-white);
    color: var(--ng-text-secondary);
    font-family: inherit;
    font-size: 13px;
    white-space: nowrap;
    cursor: pointer;
    transition: border-color .15s ease, color .15s ease, background-color .15s ease;
}

.uc-code-btn:hover {
    border-color: var(--ng-primary);
    background: var(--ng-primary-bg);
    color: var(--ng-primary);
}

.uc-code-btn:disabled { opacity: .55; cursor: not-allowed; }

/* ---------- 步骤条（两步换邮箱） ---------- */

.uc-steps {
    display: flex;
    gap: 24px;
    margin: 0 0 16px;
    padding: 0;
    list-style: none;
}

.uc-step {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--ng-text-muted);
}

.uc-step i {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    border: 1px solid var(--ng-border);
    border-radius: 50%;
    font-style: normal;
    font-size: 11px;
    font-weight: 600;
}

.uc-step.active { color: var(--ng-primary); }

.uc-step.active i {
    border-color: var(--ng-primary);
    background: var(--ng-primary);
    color: #fff;
}

/* ---------- 分页条（积分明细） ---------- */

.uc-pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.uc-pager a { color: var(--ng-primary); text-decoration: none; }

.uc-pager a:hover { text-decoration: underline; }

@media (max-width: 720px) {
    .uc-redeem-group { flex-wrap: wrap; }

    .uc-redeem-box { width: 44px; font-size: 12px; }
}

/* ═══════════ 积分商城（/user/mall）═══════════
   复用既有的 .uc-shell / .uc-card / .uc-row / .uc-tiles / .uc-tile 组件族，
   这里只补它们确实缺的三件：商品卡的元信息行、结算行、空态的留白。
   空态此前是写死在视图里的 inline style（views/user.php 两处重复），一并收成类。 */

.uc-empty--pad { padding: 36px 20px; text-align: center; }

/* 空态图标：此前三处都靠 inline style 写同一组值（font-size/opacity/display/margin），收成一条规则 */
.uc-empty > i { font-size: 28px; opacity: .5; display: block; margin-bottom: 10px; }

/* 商品卡的元信息行（库存 / 每人限购 / 不限量） */
.uc-tile-meta {
    display: flex; flex-wrap: wrap; gap: 6px 14px;
    margin-top: 10px; font-size: 12px; color: var(--ng-text-muted);
}
.uc-tile-meta span { display: inline-flex; align-items: center; gap: 4px; }

/* 商品卡的结算行（积分价格 + 兑换按钮），与上方内容用一条浅分隔线隔开 */
.uc-tile-foot {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--ng-border-light);
}
.uc-tile-cost {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 16px; font-weight: 700; color: var(--ng-text);
    font-variant-numeric: tabular-nums;
}
.uc-tile-cost i { color: var(--ng-primary); font-size: 14px; }

/* 类型标签与标题之间留气口（.uc-tile-ico 自带 14px，标签需要自己的下间距） */
.uc-tile .uc-chip { margin-bottom: 10px; }

/* 商品卡是块级卡片，按下间距而非行内对齐；按钮不参与拉伸 */
.uc-tile-foot .btn { flex: 0 0 auto; }

/* ═══════════ 购买授权（/purchase/）═══════════
   营销页，结构与 .ng-* 体系一致（ng-hero--page / ng-sec / ng-card / ng-band / ng-chips）。
   这里补的是这一页特有、别处没有的几件：价格条、套餐卡、信任行、好评卡、深色统计条、折叠 FAQ。
   注意刻意**不做**旧版的 blur 光斑装饰（.pay-hero-glow 那几个绝对定位大圆）——
   它们越出视口 120px 是上一轮「底部多一条横向滚动条」的成因之一，扁平体系也不需要装饰光斑。 */

/* 价格条（Hero：大价格 + 单位 + 促销说明） */
.ng-price { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 12px; margin: 26px 0 28px; }
.ng-price b { font-size: 42px; font-weight: 800; line-height: 1; letter-spacing: -.02em; color: var(--ng-text); }
.ng-price i { font-style: normal; font-size: 14px; color: var(--ng-text-muted); }
.ng-price s { color: var(--ng-text-muted); font-weight: 400; }
.ng-price span {
    font-size: 13px; font-weight: 600; color: var(--ng-primary);
    background: var(--ng-primary-bg); border: 1px solid var(--ng-primary-light); padding: 3px 10px;
}

/* Hero 右侧主视觉：截图 + 两枚说明 chip（代替旧版的浮标定位） */
.ng-hero-shot { position: relative; }
.ng-hero-shot img { display: block; width: 100%; height: auto; border: 1px solid var(--ng-border); }
/* 截图上的悬浮标签：半透明白底 + 背景模糊，**一左上、一右下**对角分布，各自缓慢上下浮动。
   两个方向相反的 keyframes（一个往上飘、一个往下沉）——用同一组动画会像两块一起抖。
   容器铺满图片并 pointer-events:none，避免挡住画面上的点击。 */
.ng-float-tags { position: absolute; inset: 0; pointer-events: none; }
.ng-float-tag {
    position: absolute;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 7px 13px;
    font-size: 12px; font-weight: 600; color: var(--ng-text);
    background: rgba(255, 255, 255, .9);
    border: 1px solid rgba(255, 255, 255, .65);
    border-radius: 999px;
    box-shadow: 0 4px 14px rgba(16, 24, 40, .12);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    will-change: transform;
}
.ng-float-tag i { color: var(--ng-primary); font-size: 13px; }
.ng-float-tag:nth-child(1) { top: 16px; left: 16px; animation: ngFloatUp 5.2s ease-in-out infinite; }
.ng-float-tag:nth-child(2) { right: 16px; bottom: 16px; animation: ngFloatDown 6.4s ease-in-out infinite; }

@keyframes ngFloatUp {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-7px); }
}
@keyframes ngFloatDown {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(7px); }
}
/* 系统开了「减少动态效果」就停掉浮动，静态摆在那里即可 */
@media (prefers-reduced-motion: reduce) {
    .ng-float-tag { animation: none !important; }
}

@media (max-width: 575.98px) {
    .ng-float-tag { padding: 6px 10px; font-size: 11px; }
    .ng-float-tag:nth-child(1) { top: 10px; left: 10px; }
    .ng-float-tag:nth-child(2) { right: 10px; bottom: 10px; }
}

/* 套餐卡：等高等宽，推荐款用品牌色描边 + 左上角标 */
/* 套餐卡：等高等宽，圆角 + 顶部居中的「推荐」标签。
   这里**刻意破一次 0 圆角的规矩**（用户 2026-11-14 指定）：定价卡是全站唯一要「软」一点的组件，
   圆角与居中的标签一起把它从周围的直角卡片里区分出来。 */
.ng-plan {
    height: 100%; display: flex; flex-direction: column; position: relative;
    background: var(--ng-bg-white); border: 1px solid var(--ng-border);
    border-radius: 14px; padding: 28px 24px 26px;
    transition: border-color .2s ease, box-shadow .2s ease;
}
/* 悬停 = 边缘高亮：描边直接转主色，不做位移与缩放（全站约定禁用 scale/translate）。
   注意顺序与权重：`.ng-plan--hot` 单独一条权重只有 (0,1,0)，会被 `.ng-plan:hover`(0,2,0) 盖掉 ——
   所以推荐档的描边要**连 hover 一起**写进同一条选择器，否则鼠标移上去它反而从主色退回浅色，
   等于「推荐档被取消高亮」（2026-11-14 用户报的就是这个）。 */
.ng-plan:hover { border-color: var(--ng-primary); box-shadow: 0 8px 24px rgba(108, 92, 231, .12); }
.ng-plan--hot,
.ng-plan--hot:hover {
    border-color: var(--ng-primary);
    box-shadow: 0 10px 28px rgba(108, 92, 231, .14);
}
.ng-plan--hot:hover { box-shadow: 0 12px 32px rgba(108, 92, 231, .22); }
/* 「推荐」标签骑在卡片上边缘、左右居中（父级要留出上方空间，否则被 section 裁掉） */
.ng-plan-flag {
    position: absolute; top: -13px; left: 50%; transform: translateX(-50%);
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 12px; font-weight: 600; line-height: 1; color: #fff;
    background: var(--ng-primary); border-radius: 999px; padding: 7px 14px;
    white-space: nowrap;
}
/* 套餐卡的说明行（折合月价 / 一句话描述） */
.ng-plan-note { font-size: 12.5px; font-weight: 600; color: var(--ng-primary); margin: 0 0 10px; }
.ng-plan-desc { font-size: 13px; line-height: 1.75; color: var(--ng-text-secondary); margin: 0; }
.ng-plan-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 14px; }
.ng-plan-head b { font-size: 17px; font-weight: 700; color: var(--ng-text); }
.ng-plan-head span { font-size: 12px; color: var(--ng-text-muted); }
.ng-plan-price { display: flex; align-items: baseline; gap: 6px; margin-bottom: 10px; }
.ng-plan-price b { font-size: 32px; font-weight: 800; line-height: 1; letter-spacing: -.02em; color: var(--ng-text); }
.ng-plan-price span { font-size: 13px; color: var(--ng-text-muted); }
.ng-plan .ng-points {
    margin-top: 18px; padding-top: 16px;
    border-top: 1px solid var(--ng-border-light);
    gap: 9px;
}
.ng-plan .ng-points li { font-size: 13px; }
.ng-plan .ng-points li i { font-size: 14px; }
.ng-plan-foot { margin-top: auto; padding-top: 22px; }
.ng-plan-foot .btn { width: 100%; }

/* 信任条 / 为什么选择：图标与文案横向排（复用 .ng-card--plain 的骨架） */
.ng-trust { display: flex; align-items: flex-start; gap: 14px; }
.ng-trust .ng-card-ico { margin-bottom: 0; flex: 0 0 auto; }


/* 深色横幅内的数字条：用 1px 缝隙当分隔线（底色与 .ng-band 一致） */
.ng-band-stats {
    display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
    background: rgba(255, 255, 255, .14); border: 1px solid rgba(255, 255, 255, .14);
}
.ng-band-stat { background: #1a1a2e; padding: 22px 18px; text-align: center; }
.ng-band-stat b { display: block; font-size: 26px; font-weight: 800; letter-spacing: -.02em; color: #fff; }
.ng-band-stat span { font-size: 13px; color: rgba(255, 255, 255, .66); }
@media (max-width: 767px) { .ng-band-stats { grid-template-columns: repeat(2, 1fr); } }

/* FAQ 折叠列表。
   折叠块本身**不自己实现** —— ng-ui.js 的 disclosure 组件会接管全站所有 <details>
   （转成 .ng-disc-hd + .ng-disc-bd，样式在 ng-ui.css），视图里写裸 <details><summary> 即可。
   这里只负责两件事：列表排布，以及营销页需要比后台更醒目的标题（组件默认 13px 是后台的紧凑尺寸）。
   选择器全部限定在 .ng-disc-list 内，后台那些折叠块不受影响。 */
.ng-disc-list { display: grid; gap: 10px; max-width: 880px; margin: 0 auto; }
.ng-disc-list .ng-disc-hd { padding: 15px 20px; font-size: 15px; font-weight: 600; color: var(--ng-text); }
.ng-disc-list .ng-disc[open] > .ng-disc-hd { color: var(--ng-primary); }
.ng-disc-list .ng-disc-bd { padding: 12px 20px 18px; }

/* ═══════════ 首页视频 Hero（.ng-vhero）═══════════
   首页首屏专用。与内容型页头 .ng-hero（公告/文档/广场/产品/购买/更新日志在用）是两套东西，别互相改。
   三层结构：z0 视频（z 序最低）→ z1 淡黑遮罩 → z2 左下角标题图。
   2026-10-16 定稿：首页 hero **只保留这三层**；原本的徽标文案 / 主副标题 / CTA 按钮 / 右侧状态面板 /
   数据统计已按用户要求全部删除（config/content/home.php 里那些键先留着没删，以后想复用还在）。 */

.ng-vhero {
    --ng-vhero-nav: var(--ng-nav-h);        /* = .navbar-sup 的 height，用来把首屏高度扣准 */
    /* 标题图距视口左右边缘的间隙。
       2026-10-16 用户先要求「贴边」→ 24px；随后给了 ±50px 的微调（先说左移、后更正为右移）：
       从 14px 右移 50px → 64px。
       注意这是**固定值**，而 .container 的内容列是**随视口变**的：1440 下下方区块标题在 70px（差 6px），
       但 768 下在 34px、414 下只有 12px —— 也就是窄屏时标题会比正文更往里缩。
       若要各视口都与内容列严丝合缝，把这行删掉、给 .ng-vhero-body 套回 .container 即可。 */
    --ng-vhero-gutter: 64px;
    --ng-vhero-veil: rgba(6, 9, 18, .30);   /* 淡黑遮罩浓度 */
    --ng-vhero-w-en: min(44vw, 700px);      /* 英文标题图宽度（基准） */
    --ng-vhero-w-zh: 1.27;                  /* 中文标题图倍数；必须 > 1.013 才会比英文右端更长 */
    --ng-vhero-gap: -0.006;                 /* 两行间距（负值吃掉图自带的上下留白） */
    --ng-vhero-zoom: 1;                     /* 画面缩放，>1 可裁掉来源视频顶部的水印，1 = 不裁 */
    position: relative;
    /* 高度扣掉导航栏高度：导航栏在文档流里（sticky），不扣的话左下角标题会被压到首屏之外 */
    min-height: calc(100vh - var(--ng-vhero-nav));
    min-height: calc(100svh - var(--ng-vhero-nav));
    display: flex;
    align-items: flex-end;
    overflow: hidden;
    background: #0b1020;
    isolation: isolate;                     /* 自成层叠上下文，避免 z-index 外溢到别的区块 */
}

/* ── z0 视频层 ── */
.ng-vhero-media { position: absolute; inset: 0; z-index: 0; }
.ng-vhero-media video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;                      /* 铺满并裁切，不变形 */
    pointer-events: none;
    /* 必须定位 + z-index:1 —— 下面那条 ::before 兜底渐变是 absolute，video 不定位就会被它整个盖住
       （实测踩过：截图里看到的其实是渐变，视频等于白放）。 */
    position: relative;
    z-index: 1;
    transform-origin: 50% 100%;             /* 缩放锚在底边、向上生长 → 顶部被父层裁掉 */
    transform: scale(var(--ng-vhero-zoom));
}
/* 视频没加载出来时的兜底底色，避免一片死黑 */
.ng-vhero-media::before {
    content: "";
    position: absolute;
    inset: 0;
    background:
        radial-gradient(120% 90% at 18% 78%, rgba(108, 92, 231, .30) 0%, rgba(108, 92, 231, 0) 58%),
        radial-gradient(90% 70% at 82% 12%, rgba(58, 169, 255, .18) 0%, rgba(58, 169, 255, 0) 60%),
        linear-gradient(160deg, #0d1428 0%, #131a33 48%, #0a0f1e 100%);
    animation: ng-vhero-drift 24s ease-in-out infinite alternate;
}
@keyframes ng-vhero-drift {
    from { transform: translate3d(-1.2%, -0.8%, 0) scale(1.04); }
    to   { transform: translate3d(1.2%, 0.8%, 0) scale(1.08); }
}

/* ── z1 淡黑遮罩：底部加深，压住左下角的标题 ── */
.ng-vhero-veil {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: var(--ng-vhero-veil);
}
.ng-vhero-veil::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(6, 9, 18, 0) 0%, rgba(6, 9, 18, .10) 52%, rgba(6, 9, 18, .48) 100%);
}

/* ── z2 左下角标题图：左对齐，用 .container 与全站内容列对齐 ── */
.ng-vhero-body {
    position: relative;
    z-index: 2;
    width: 100%;
    /* 左右只留 gutter —— 不套 .container，标题贴向视口边缘 */
    padding-left: var(--ng-vhero-gutter);
    padding-right: var(--ng-vhero-gutter);
    padding-bottom: clamp(36px, 7vh, 96px);
}
.ng-vhero-brand {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    /* 两张图自身带透明留白、且两侧不一致，用 translateX 按「元素自身宽度」的百分比抵消 ——
       百分比按自身宽度解算，所以任何缩放比例下内容边缘都对齐（实测 0.0px 误差）。
       取值来源：ehero 左留白 28/1647 = 1.70%；zhero 左留白 5/2576 = 0.19%。
       注意：验证是否对齐要比「内容边缘」，不要比 img 盒子的左边缘 —— 盒子本就该错开，
       第一版就是比盒子才误判出「偏差 12px」的。 */
    --ng-pad-en: 1.70%;
    --ng-pad-zh: 0.19%;
}
.ng-vhero-brand img { display: block; height: auto; }
.ng-vhero-brand .en {
    width: var(--ng-vhero-w-en);
    transform: translateX(calc(-1 * var(--ng-pad-en)));
}
.ng-vhero-brand .zh {
    width: calc(var(--ng-vhero-w-en) * var(--ng-vhero-w-zh));
    transform: translateX(calc(-1 * var(--ng-pad-zh)));
    margin-top: calc(var(--ng-vhero-w-en) * var(--ng-vhero-gap));
}

@media (max-width: 991.98px) {
    .ng-vhero { --ng-vhero-w-en: min(56vw, 420px); }
}
@media (max-width: 575.98px) {
    .ng-vhero { --ng-vhero-w-en: 62vw; }
    .ng-vhero-body { padding-bottom: clamp(28px, 6vh, 56px); }
}
@media (prefers-reduced-motion: reduce) {
    .ng-vhero-media::before { animation: none; }
}

/* ============================================================
   蓝图工坊与用户主页（2026-10-16 新增）
   /plaza 列表 · /plaza/{slug} 详情 · /addplaza 发布 · /a/{uid} 用户主页
   沿用 --ng-* 令牌与扁平设计：零圆角、1px 细边、克制阴影。
   骨架复用既有 .ng-chip / .ng-sec 等，不重造排版。
   ============================================================ */

.ng-bp-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }

/* ── 蓝图卡（列表页与用户主页共用 views/plaza/_card.php） ──
   版式对齐 Steam 商城（用户 2026-10-17 要求）：**五列密排、窄卡**，卡片本身不带边框与白底，
   只有「封面（3:2）+ 一行标题 + 一行小字元信息」三层。悬停靠封面提亮 + 标题转品牌色，
   不加位移/缩放（十几张卡同时抖动会很脏）。 */
/* 列表用**全宽**而不是 1200px 容器（用户 2026-10-17：「不需要限制宽度」）。
   列数交给 auto-fill 自适应：每张卡至少 300px，屏幕越宽列越多，不再写死 5 列
   —— 写死列数在 2K 屏上卡片会被拉得很扁，而 5 列在 1280 下又只有 220px，两头都不合适。 */
/* 列表整体左右留白（用户 2026-10-17 定 100px）。
   窄屏必须收窄，否则一行 5 张会被压到 100px 以内、标题全成省略号。 */
/* 工坊列表容器：左右留白到大屏各 500px（用户 2026-11-14）。
   窄屏必须逐级收窄 —— 否则一行 5 张会被压成小方块、标题全成省略号。
   取值：>=1800 给足 500；再窄按 300 / 100 / 40 / 14 逐级让路。 */
.ng-pz-list-wrap {
    /* 左右留白的计算（用户 2026-11-14 要求「左右留 500px」）：
       **先保证一行 5 张卡片各至少 300px**，剩下的空间才平分给两侧，上限 500px。
       直接写死 500px 会在 1920 屏把卡片压到 169px（5 列分 920px），
       与「卡片尽量做大」直接矛盾；这样算下来：
         1920 屏 -> 两侧各 174px，卡宽 300px
         2560 屏 -> 两侧各 494px，卡宽 300px
         2880 屏 -> 两侧各 500px（封顶），卡宽 361px
       即：小屏卡片不被挤扁，大屏留白能到 500px。 */
    --pz-side: min(500px, max(14px, calc((100vw - 5 * 300px - 4 * 18px) / 2)));
    padding-inline: var(--pz-side);
    padding-top: 26px;
    padding-bottom: 40px;
}

/* 平铺网格：一行 5 张（用户 2026-11-14 要求，不再按分类分段、不再横向滚动单行）。
   列数写死 5，窄屏逐级降到 4 / 3 / 2，保证任何宽度下卡片都够大。 */
.ng-pz-grid-list {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 22px 18px;
    /* 左右各留 2px：悬停投影不被网格边缘裁掉 */
    padding: 4px 2px 8px;
}
@media (max-width: 1199.98px) { .ng-pz-grid-list { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 991.98px)  { .ng-pz-grid-list { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 767.98px)  { .ng-pz-grid-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 12px; } }

/* 追加加载的哨兵：放在网格末尾，滚到可视区就触发下一批（不占高度，纯触发器） */
.ng-pz-sentinel { height: 1px; }

/* 列表底部状态：加载中 / 没有更多。两者互斥显示 */
.ng-pz-status {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    margin: 26px 0 0; padding: 14px 0;
    color: var(--ng-text-muted); font-size: 13px;
}
.ng-pz-status[hidden] { display: none; }
.ng-pz-status i.bi-arrow-repeat { animation: ng-pz-spin .9s linear infinite; }
@keyframes ng-pz-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .ng-pz-status i.bi-arrow-repeat { animation: none; } }

/* ── 蓝图卡片骨架屏（追加加载时先铺这一批，数据到了整体替换）──
   结构对齐 .ng-bp：封面（同 3:2）+ 标题 + 元信息，尺寸一致才不会跳版。 */
/* 尺寸严格对齐 .ng-bp 的文字区构成，否则骨架换真卡时网格行高会跳：
   真卡 = padding 10 + 边框 1 + 封面(3:2) + body(padding-top 9) + 标题 20+4 + meta 18 + 作者行 43 */
.sk-bp { display: flex; flex-direction: column; padding: 10px; border: 1px solid var(--ng-border-light); background: var(--ng-bg-white); }
.sk-bp-cover { width: 100%; aspect-ratio: 3 / 2; background: var(--ng-bg); position: relative; overflow: hidden; }
.sk-bp-title { height: 20px; margin: 9px 0 4px; width: 82%; background: var(--ng-bg); position: relative; overflow: hidden; }
.sk-bp-meta { height: 19px; width: 56%; background: var(--ng-bg); position: relative; overflow: hidden; }
/* 作者行带一条上边框，与真卡的 .ng-bp-foot 一致 */
.sk-bp-foot {
    /* 39px 是实卡 .ng-bp-foot 的实际占位（margin-top 10 + padding-top 10 + 边框 1 + 头像行 18）：
       卡片高度受同行最高那张拉伸，骨架单独成行，这里按实测值对齐才能让换卡时行高不变。 */
    height: 39px; margin-top: 10px; padding-top: 10px; width: 64%;
    border-top: 1px solid var(--ng-border-light);
    background: var(--ng-bg); position: relative; overflow: hidden;
}

/* 微光扫过。动画只动自身伪元素，不触发重排。 */
.sk-bp-cover::after, .sk-bp-title::after, .sk-bp-meta::after, .sk-bp-foot::after {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .55), transparent);
    transform: translateX(-100%);
    animation: ng-sk-sweep 1.2s ease-in-out infinite;
}
@keyframes ng-sk-sweep { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) {
    .sk-bp-cover::after, .sk-bp-title::after, .sk-bp-meta::after, .sk-bp-foot::after { animation: none; }
}

/* 左右翻页按钮（用户 2026-10-17：隐藏滚动条，但可滚动时要有 < > 标记）
   默认透明且不可点；JS 判定「确实溢出」才给 .is-scrollable，滚到某一端时那一侧再加 .is-off。 */
.ng-pz-nav {
    /* 垂直居中在**封面**而不是整行：整行 50% 会落在标题上，把标题第一个字压住。
       卡片封面下方固定约 80px（标题 + meta + 分隔 + 作者行），减掉它再取一半即可。 */
    position: absolute; top: calc((100% - 80px) / 2); transform: translateY(-50%); z-index: 2;
    width: 34px; height: 34px;
    display: flex; align-items: center; justify-content: center;
    /* 样式对齐用户给的参考图：深色半透明方块 + 白色箭头 + 6px 圆角，压在内容边缘 */
    border: 0; border-radius: 6px;
    background: rgba(32, 36, 46, .58);
    color: #fff; font-size: 15px;
    backdrop-filter: blur(2px);
    cursor: pointer;
    opacity: 0; pointer-events: none;
    transition: opacity .18s ease, color .18s ease, border-color .18s ease;
}
.ng-pz-track.is-scrollable .ng-pz-nav { opacity: 1; pointer-events: auto; }
.ng-pz-nav:hover { background: rgba(32, 36, 46, .82); }
.ng-pz-nav.is-off { opacity: 0; pointer-events: none; }
.ng-pz-nav--prev { left: 8px; }
.ng-pz-nav--next { right: 8px; }

/* 「更多 >」卡片：虚线框 + 居中箭头，和真卡片同高同宽，排在同一行末尾 */
.ng-bp-more {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
    min-height: 200px;
    border: 1px dashed var(--ng-border);
    border-radius: 0;
    color: var(--ng-text-muted);
    font-size: 14px; font-weight: 600; text-decoration: none;
    transition: border-color .2s ease, color .2s ease, background-color .2s ease;
}
.ng-bp-more i { font-size: 22px; }
.ng-bp-more:hover { border-color: var(--ng-primary-light); background: var(--ng-primary-bg); color: var(--ng-primary); }

.ng-bp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 28px 20px; }
@media (max-width: 767.98px) { .ng-bp-grid { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 22px 14px; } }

/* 卡片要有自己的底色，不再只是「图 + 文字」贴在页面灰底上（用户 2026-10-17 要求区分） */
.ng-bp {
    display: flex; flex-direction: column; height: 100%; min-width: 0;
    position: relative;          /* 给「整卡可点」的透明覆盖层当定位基准 */
    background: var(--ng-bg-white);
    border: 1px solid var(--ng-border-light);
    border-radius: 0;
    padding: 10px;
    transition: border-color .2s ease, box-shadow .2s ease;
}
.ng-bp:hover { border-color: var(--ng-border); box-shadow: 0 6px 18px rgba(24, 20, 46, .10); }
/* 铺满整卡的透明链接：点卡片任何位置（图、空白、meta）都进详情页 */
.ng-bp-hit { position: absolute; inset: 0; z-index: 1; }

/* 卡片底部：作者头像（圆形）+ 名称，整块可点进作者主页 */
.ng-bp-foot {
    position: relative; z-index: 2;   /* 压在整卡覆盖层之上，作者链接才能单独点 */
    margin-top: 10px; padding-top: 10px;
    border-top: 1px solid var(--ng-border-light);
}
.ng-bp-author {
    display: inline-flex; align-items: center; gap: 7px;
    min-width: 0; max-width: 100%;
    font-size: 12.5px; color: var(--ng-text-secondary); text-decoration: none;
}
.ng-bp-author span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 作者名悬停：只转字色 + 头像加一圈淡品牌色描边。
   **不加下划线**（2026-11-14 用户指出）：站内链接的约定是只变色不加线，
   卡片里作者名本来就不像正文链接，加下划线反而显得脏。 */
.ng-bp-author:hover { color: var(--ng-primary); text-decoration: none; }
.ng-bp-author { transition: color .18s ease; }
.ng-bp-avatar {
    flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
    object-fit: cover; background: var(--ng-bg);
    transition: box-shadow .18s ease;
}
.ng-bp-author:hover .ng-bp-avatar { box-shadow: 0 0 0 2px var(--ng-primary-light); }
.ng-bp-author.is-plain { color: var(--ng-text-muted); }
.ng-bp-cover {
    position: relative; display: block;
    /* 与详情页主图统一为 3:2（2026-11-14 用户要求「卡片缩略图比例一起改」）。
       原先是 2.14:1，蓝图俯瞰图被压得太扁、细节看不清。 */
    aspect-ratio: 3 / 2;
    overflow: hidden;
    background: var(--ng-bg);
    /* 圆角已按用户要求去掉：卡片家族一律 0 圆角，与全站设计体系一致 */
    border-radius: 0;
}
.ng-bp-cover img { display: block; width: 100%; height: 100%; object-fit: cover; transition: filter .2s ease; }
.ng-bp:hover .ng-bp-cover img { filter: brightness(1.14); }
.ng-bp-cover-empty {
    display: flex; align-items: center; justify-content: center;
    width: 100%; height: 100%; font-size: 26px; color: var(--ng-primary); opacity: .35;
}
/* 价格/免费标签压在封面右上角（Steam 也是把价格贴在图上下沿/角上） */
.ng-bp-badge {
    position: absolute; right: 6px; top: 6px;
    /* 胶囊形（用户 2026-10-17 指定）：标签这类小徽标用 pill 是设计体系允许的，
       与卡片本体的 0 圆角不冲突。内距同步加大一点，胶囊才不会显得方。 */
    padding: 3px 10px; font-size: 11px; font-weight: 700; line-height: 1.6;
    background: rgba(255, 255, 255, .92); color: var(--ng-text);
    border-radius: var(--ng-radius-pill);
}
.ng-bp-badge.is-paid { background: var(--ng-primary); color: #fff; }

.ng-bp-body { display: flex; flex-direction: column; flex: 1; padding: 9px 1px 0; min-width: 0; }
.ng-bp-title {
    font-size: 14px; font-weight: 600; line-height: 1.4; margin: 0 0 4px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ng-bp-title a { color: var(--ng-text); text-decoration: none; transition: color .2s ease; }
.ng-bp:hover .ng-bp-title a { color: var(--ng-primary); }
.ng-bp-meta {
    display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
    font-size: 12px; color: var(--ng-text-muted); margin: 0;
}
.ng-bp-meta a { color: var(--ng-text-muted); text-decoration: none; }
.ng-bp-meta a:hover { color: var(--ng-primary); }
.ng-bp-sep { opacity: .6; }
/* 详情页的作者链接仍用 .ng-bp-author（列表卡已改成小字元信息，但详情页要明显可点） */
.ng-bp-author { color: var(--ng-primary); text-decoration: none; }
.ng-bp-author:hover { text-decoration: none; }
.ng-bp-pager { margin-top: 32px; }

/* ── 详情页 ── */
.ng-bp-crumb { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ng-text-muted); margin-bottom: 22px; }
.ng-bp-crumb a { color: var(--ng-text-muted); text-decoration: none; }
.ng-bp-crumb a:hover { color: var(--ng-primary); }
.ng-bp-crumb i { font-size: 11px; }

/* ── 发布表单 ── */
.ng-bp-form { max-width: 760px; background: var(--ng-bg-white); border: 1px solid var(--ng-border); padding: 32px; }
.ng-bp-form .form-label { font-size: 13px; font-weight: 500; }
.ng-bp-form .form-text { font-size: 12px; }
.ng-bp-form-err { font-size: 12px; color: var(--ng-danger); margin: 6px 0 0; }
.ng-bp-form-foot {
    display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
    margin-top: 28px; padding-top: 24px; border-top: 1px solid var(--ng-border-light);
}
.ng-bp-form-foot .ng-note { margin: 0; }

/* ── 用户主页（/a/{uid}） ──
   版式：背景条 → 信息横条 → 头像压住背景条下缘 → 右侧两行名称信息。
   两条横条都是**通栏**（横向铺满到页面左右边缘）：所以它们不能套 .container，
   只给横条内部的 .ng-pf-bar-in 套，正文列照旧用 .container。
   同一套类也用在「用户中心 > 个人资料」的外观预览里（外层加 .ng-pf--mini 缩放 +
   .ng-pf-card 给预览包一个边框），所以预览与实际主页不会漂 —— 改这里两边一起变。 */
.ng-pf {
    /* 背景条高度：调高矮只改这一个 token（用户 2026-10-16 要求拉高，200 → 280） */
    --ng-pf-banner-h: 280px;
}
.ng-pf-banner {
    height: var(--ng-pf-banner-h);
    background-color: var(--ng-bg);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
}
/* 未设置背景图时的回退：品牌色渐变（用户 2026-10-16 选定） */
.ng-pf-banner.is-default { background-image: var(--ng-gradient); }
.ng-pf-bar { background: var(--ng-bg-white); border-top: 1px solid var(--ng-border); }
/* 只写上下（不要用 padding 简写）：这个元素同时挂着 .container，
   简写会把 Bootstrap 容器那 12px 左右内边距一并清成 0，头像就会比正文标题多凸出 12px。 */
.ng-pf-bar-in { display: flex; align-items: center; gap: 20px; padding-top: 20px; padding-bottom: 24px; }
.ng-pf-avatar {
    flex: 0 0 auto; width: 104px; height: 104px; overflow: hidden;
    border-radius: 50%;
    background: var(--ng-bg-white);
    /* 白色描边用 box-shadow 画（不占布局尺寸），压在背景条上时边缘才分得开 */
    box-shadow: 0 0 0 4px var(--ng-bg-white);
    /* 关键：负 margin 只把头像自己提上去压住背景条，**不动横条本身**。
       若改成给 .ng-pf-bar 加负 margin，横条的白色底也会一起上移、把背景条下缘盖住，
       看上去就成了「头像浮在白条上」而不是压在背景条上。
       搭配 align-self: flex-start，负 margin 才能把外框顶出横条上边界。 */
    align-self: flex-start;
    margin-top: -56px;
}
.ng-pf-avatar img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ng-pf-meta { flex: 1; min-width: 0; }
.ng-pf-name { font-size: 24px; font-weight: 700; line-height: 1.3; margin: 0 0 6px; }
.ng-pf-sub { font-size: 13px; color: var(--ng-text-muted); }
.ng-sec--pf { padding-top: 40px; }

/* 用户中心「个人资料」里的外观预览：等比缩小 + 一个预览边框，别抢主内容的视觉重量 */
.ng-pf-card { border: 1px solid var(--ng-border); }
.ng-pf--mini .ng-pf-card { overflow: hidden; margin-bottom: 24px; }
.ng-pf--mini .ng-pf-banner { height: 128px; }
.ng-pf--mini .ng-pf-bar-in { gap: 14px; padding: 12px 16px 14px; }
.ng-pf--mini .ng-pf-avatar { width: 56px; height: 56px; box-shadow: 0 0 0 3px var(--ng-bg-white); margin-top: -30px; }
.ng-pf--mini .ng-pf-name { font-size: 15px; margin-bottom: 2px; }
.ng-pf--mini .ng-pf-sub { font-size: 12px; }

@media (max-width: 991.98px) {
    .ng-pf { --ng-pf-banner-h: 220px; }
}
@media (max-width: 575.98px) {
    .ng-pf { --ng-pf-banner-h: 160px; }
    .ng-pf-bar-in { flex-wrap: wrap; gap: 14px; padding-top: 16px; padding-bottom: 18px; }
    .ng-pf-avatar { width: 80px; height: 80px; margin-top: -44px; }
    .ng-pf-name { font-size: 20px; }
    .ng-pf--mini .ng-pf-banner { height: 96px; }
    .ng-pf--mini .ng-pf-bar-in { padding: 10px 14px 12px; }
    .ng-pf--mini .ng-pf-avatar { width: 48px; height: 48px; margin-top: -26px; }
}

@media (max-width: 991.98px) {
}
@media (max-width: 575.98px) {
    .ng-bp-form { padding: 22px 18px; }
}

/* ============================================================
   蓝图工坊首屏（/plaza）
   参考 Zibll 活动页的版式（用户 2026-10-17 指定）：左侧「大色块 + 三块小彩卡」，
   右侧一张整高大图，两者等高。原先是通栏 hero + 独立的「蓝图怎么用」三卡区 ——
   现在把三卡并进首屏，列表因此能直接露出来（不再被科普块挡在下面）。
   本区块是全站唯一带圆角的地方（参考图就是圆角），要做全域 0 圆角只需把 --ng-pz-radius 改成 0。
   ============================================================ */
.ng-pz-hero { --ng-pz-radius: 10px; padding: 26px 0 26px; }
.ng-pz-grid { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); gap: 16px; align-items: stretch; }
.ng-pz-left { display: grid; grid-template-rows: minmax(0, 1fr) auto; gap: 16px; min-width: 0; }

/* 左上大色块：品牌渐变 + 两个虚化光斑 + 纸飞机水印 + 左下角大字 */
.ng-pz-main {
    position: relative; display: flex; align-items: flex-end; overflow: hidden;
    min-height: 368px; padding: 32px 36px;
    border-radius: var(--ng-pz-radius);
    background: var(--ng-gradient);
    text-decoration: none;
    transition: filter .25s ease;
}
.ng-pz-main:hover { filter: brightness(1.06); color: #fff; }
.ng-pz-main::before,
.ng-pz-main::after {
    content: ''; position: absolute; border-radius: 50%; pointer-events: none;
    background: rgba(255, 255, 255, .16); filter: blur(2px);
}
.ng-pz-main::before { width: 150px; height: 150px; right: 26%; top: -34px; transition: transform .6s var(--ng-ease); }
.ng-pz-main:hover::before { transform: translate(-16px, 10px); }
.ng-pz-main::after  { width: 84px;  height: 84px;  right: 34%; bottom: -18px; background: rgba(255, 255, 255, .12); }
.ng-pz-deco {
    /* 装饰用大号水印：居中 + 放大（用户 2026-10-17 定），透明度再压低一点，避免压过左下角的标题 */
    position: absolute; right: 44px; top: 50%;
    font-size: 118px; line-height: 1; color: rgba(255, 255, 255, .24);
    transform: translateY(-50%) rotate(-14deg); pointer-events: none;
}
.ng-pz-cta {
    position: relative; display: flex; align-items: center; gap: 10px;
    font-size: 38px; font-weight: 800; letter-spacing: -.01em; color: #fff;
}
.ng-pz-cta i { font-size: 32px; transition: transform .2s var(--ng-ease); }
.ng-pz-main:hover .ng-pz-cta i { transform: translateX(4px); }

/* 左下三块小彩卡：取自「三种获取方式」配置，颜色按参考图的三色区分 */
.ng-pz-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.ng-pz-card {
    position: relative; display: flex; align-items: flex-end; overflow: hidden;
    min-height: 86px; padding: 14px 18px;
    border-radius: var(--ng-pz-radius);
    color: #fff; font-size: 17px; font-weight: 700; text-decoration: none;
    box-shadow: 0 0 0 rgba(24, 20, 46, 0);
    transition: filter .22s ease, box-shadow .22s ease;
}
/* 显式声明 hover 的字色：全局 `a:hover{color:var(--ng-primary-hover)}` 的特异性是 (0,1,1)，
   会压过 `.ng-pz-card` 的 (0,1,0) —— 不写这一条，悬停时白字会变成深紫色、几乎看不清。 */
.ng-pz-card:hover { filter: brightness(1.1); box-shadow: 0 10px 22px rgba(24, 20, 46, .20); color: #fff; }
.ng-pz-card.is-a:hover { box-shadow: 0 10px 22px rgba(108, 92, 231, .34); }
.ng-pz-card.is-b:hover { box-shadow: 0 10px 22px rgba(20, 168, 154, .32); }
.ng-pz-card.is-c:hover { box-shadow: 0 10px 22px rgba(242, 112, 58, .32); }
.ng-pz-card-ico {
    /* 图标位置（2026-10-17 用户要求优化）：**右侧垂直居中、完整可见**。
       原先用 right:8px / bottom:2px 贴右下角，图标会被卡片边缘裁掉一半，三张卡裁切量还各不相同。 */
    position: absolute; right: 16px; top: 50%; transform: translateY(-50%);
    font-size: 42px; line-height: 1; color: rgba(255, 255, 255, .20);
    pointer-events: none;
    transition: color .22s ease;
}
.ng-pz-card:hover .ng-pz-card-ico { color: rgba(255, 255, 255, .44); }
/* 分类条 —— Steam 商城的「横向分类导航」（用户 2026-10-17 指定，随后两轮微调）：
   ① **通栏一条，直贴视口左右边缘**，不做圆角卡片（`.ng-pz-band` 铺满，内部不再套 .container）；
   ② tab 之间留间距（`gap`），不再是紧挨的无边框小方块；
   ③ 选中项白字 + 底部 2px 品牌色短横，悬停浅白蒙层。 */
/* 宽行：左右直贴视口边缘，上下留出间隙（用户 2026-10-17 定），白底 */
/* 上下留白对齐：首屏下内距 26px + 本行 margin 0 + 列表上内距 26px（见 .ng-pz-band + .ng-sec）
   —— 原先首屏 38px + margin 26px 与下方 26px 差了一倍，就是「上下不一致」的来源。 */
/* 滚到下面时吸在导航栏下方（用户 2026-10-17 要求）：
   top 取 --ng-nav-h；z-index 20 低于导航栏的 1030，卡片在下面不会盖住它。 */
.ng-pz-band { background: var(--ng-bg-white); margin: 0; position: sticky; top: var(--ng-nav-h); z-index: 20; }
.ng-pz-band + .ng-sec { padding-top: 26px; }
/* 单行**横向滚动**（用户 2026-10-17 指定，对齐网易版《我的世界》资源中心的分类条）：
   永远不换行，放不下就左右滑（Shift+滚轮 / 触控板横扫）。
   两端加渐隐遮罩提示「还能滑」，否则右边被切一半会让人以为坏了。 */
.ng-pz-filter {
    /* 居中：用 safe center —— 放得下时整排居中，放不下（内容比视口宽）时自动回退成左对齐，
       否则溢出会把左边几个 tab 推到负坐标、滚不回来。 */
    display: flex; align-items: center; justify-content: safe center;
    flex-wrap: nowrap;
    gap: 0 20px;
    padding: 28px 18px;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    /* 只淡出右侧：默认停在最左，左侧不该有渐隐（否则「全部」会被糊掉一半）。
       滚到最右时右边仍有一点淡出，无伤大雅。 */
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%);
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 26px), transparent 100%);
}
.ng-pz-filter::-webkit-scrollbar { height: 0; }
.ng-pz-filter .ng-filter { scroll-snap-align: start; }
.ng-pz-filter .ng-filter {
    flex: 0 0 auto;
    padding: 5px 4px;
    border: 0; background: transparent;
    color: var(--ng-text-secondary);
    font-size: 15px; font-weight: 500; line-height: 1.8;
    white-space: nowrap; text-align: center; text-decoration: none;
    transition: color .18s ease;
}
/* 文字按钮：悬停只换字色，不加底色 */
.ng-pz-filter .ng-filter:hover { color: var(--ng-primary); }
/* 选中态用**文字下划线**而不是绝对定位的假线 —— 宽度天然跟着文字走，
   换行/字号变化时不会出现长度对不齐的「异常」观感 */
.ng-pz-filter .ng-filter.is-active {
    color: var(--ng-primary); font-weight: 700;
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 7px;
}
@media (max-width: 991.98px) {
    .ng-pz-filter { gap: 10px 14px; padding: 22px 12px; }
    .ng-pz-filter .ng-filter { font-size: 14px; }
}


.ng-pz-card.is-a { background: #6c5ce7; }
.ng-pz-card.is-b { background: #14a89a; }
.ng-pz-card.is-c { background: #f2703a; }

/* 右侧整高大图 + 右下角胶囊按钮 */
.ng-pz-media {
    position: relative; display: block; overflow: hidden;
    border-radius: var(--ng-pz-radius); min-height: 368px;
}
/* object-position 往下压：素材首帧左上角烙着 B 站水印，靠裁切把它挤出可视区 */
.ng-pz-media img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 74%; transition: transform .5s var(--ng-ease); }
.ng-pz-media:hover img { transform: scale(1.04); }
.ng-pz-media-cta { transition: background-color .22s ease; }
.ng-pz-media:hover .ng-pz-media-cta { background: var(--ng-primary); color: #fff; }
.ng-pz-media::after {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(180deg, rgba(8, 10, 18, 0) 55%, rgba(8, 10, 18, .38) 100%);
    pointer-events: none;
}
.ng-pz-media-cta {
    position: absolute; right: 14px; bottom: 14px; z-index: 1;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 16px; border-radius: 999px;
    /* 原来是半透明深色 + 模糊，压在暗色配图上看不见（用户 2026-10-17 反馈）。
       改成实心白底 + 深色字：任何图上都有足够对比度，悬停再转成品牌色。 */
    background: #fff; color: var(--ng-text); font-size: 13px; font-weight: 600;
    box-shadow: 0 4px 14px rgba(12, 14, 22, .28);
}

@media (max-width: 991.98px) {
    .ng-pz-grid { grid-template-columns: minmax(0, 1fr); }
    .ng-pz-media { min-height: 180px; order: -1; }
}
@media (max-width: 575.98px) {
    .ng-pz-main { min-height: 150px; padding: 20px 20px; }
    .ng-pz-cta { font-size: 24px; }
    .ng-pz-deco { font-size: 86px; }
    .ng-pz-cards { grid-template-columns: minmax(0, 1fr); gap: 10px; }
    .ng-pz-card { min-height: 54px; }
    .ng-pz-media { min-height: 150px; }
}

/* ============================================================
   发布蓝图（/addplaza）—— 参考网易版《我的世界》资源投稿页的纵向分段表单
   版式（用户 2026-10-17 定）：**不要 hero**；编辑区占满宽度、左右各留 300px；
   自上而下四段（基本信息 / 展示图片 / 类型定价 / 文件上传），每段 = 标题条 + 标签左·控件右。
   ============================================================ */
.ng-be { padding: 34px 300px 64px; }
@media (max-width: 1599.98px) { .ng-be { padding: 30px 120px 56px; } }
@media (max-width: 1199.98px) { .ng-be { padding: 26px 48px 48px; } }
@media (max-width: 767.98px)  { .ng-be { padding: 20px 16px 40px; } }

.ng-be-title { font-size: 26px; font-weight: 800; letter-spacing: -.01em; margin: 0 0 6px; }
.ng-be-sub { font-size: 14px; line-height: 1.8; color: var(--ng-text-secondary); margin: 0 0 26px; }
.ng-be-sub a { color: var(--ng-primary); }

.ng-be-sec { background: var(--ng-bg-white); border: 1px solid var(--ng-border-light); margin-bottom: 18px; }
.ng-be-hd {
    margin: 0; padding: 13px 22px;
    font-size: 15px; font-weight: 700; color: var(--ng-text);
    /* 标题条底色加深（用户 2026-10-17）：原来用 --ng-bg 只比白底灰一点点，
       分段的边界看不出来。这里给一档明显更深的冷灰。 */
    background: #e4e8ef;
    border-bottom: 1px solid #d8dde6;
}
.ng-be-bd { padding: 6px 22px; }

/* 一行 = 标签 | 控件；行间用细线分隔（参考图就是这个骨架） */
.ng-be-row { display: grid; grid-template-columns: 132px minmax(0, 1fr); gap: 20px; padding: 16px 0; }
.ng-be-row + .ng-be-row { border-top: 1px solid var(--ng-border-light); }
.ng-be-label {
    font-size: 14px; font-weight: 600; color: var(--ng-text);
    /* 与单行控件（39px 高）同高的行高 —— 这样标签文字和输入框里的文字落在同一水平线上，
       用 padding-top 猜位置总会差几像素（实测差 4px，看着就是「没对齐」）。 */
    line-height: 38px; padding-top: 0;
}
.ng-be-row:has(.rich-editor) .ng-be-label { line-height: 30px; }
.ng-be-req { color: var(--ng-danger); margin-left: 3px; }
.ng-be-ctl { min-width: 0; }
.ng-be-err { margin: 7px 0 0; font-size: 13px; color: var(--ng-danger); }
.ng-be-sublabel { display: block; font-size: 13px; color: var(--ng-text-secondary); margin-bottom: 6px; }

/* 展示图片：3:2 的格子，第一个格子是「+」 */
.ng-be-imgs { display: grid; grid-template-columns: repeat(auto-fill, 136px); gap: 12px; }
.ng-be-file { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
/* ng-ui.js 会自动给 input[type=file] 包一层 .ng-file 并塞一个「选择文件」按钮 ——
   这里已经有「+」格子做多图选择，那个按钮必须藏掉，否则两个入口并存（2026-10-17 实测）。 */
.ng-be-imgs .ng-file { display: none; }
.ng-be-pick,
.ng-be-img {
    position: relative; width: 136px; height: 91px;
    display: flex; align-items: center; justify-content: center;
    border: 1px dashed var(--ng-border); background: var(--ng-bg);
    color: var(--ng-text-muted);
}
.ng-be-pick { cursor: pointer; transition: border-color .18s ease, color .18s ease; }
.ng-be-pick:hover { border-color: var(--ng-primary); color: var(--ng-primary); }
.ng-be-pick i { font-size: 22px; }
.ng-be-pick[hidden] { display: none; }
.ng-be-img { border-style: solid; border-color: var(--ng-border-light); overflow: hidden; }
.ng-be-img img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ng-be-img-x {
    position: absolute; right: 0; top: 0; width: 22px; height: 22px;
    border: 0; background: rgba(16, 18, 26, .6); color: #fff;
    font-size: 14px; line-height: 1; cursor: pointer;
}
.ng-be-img-x:hover { background: rgba(220, 53, 69, .9); }
.ng-be-img-badge {
    position: absolute; left: 0; bottom: 0;
    padding: 2px 8px; font-size: 11px; font-weight: 700;
    background: var(--ng-primary); color: #fff;
}

/* 类型定价。单选圆点用品牌色 —— Bootstrap 默认勾选态是 #0d6efd 的蓝，和全站主色打架 */
/* 这里的单选是原生 input（没挂 .form-check-input），勾选色由 accent-color 决定，
   不改它就会是浏览器默认的蓝。 */
.ng-be-radio input { accent-color: var(--ng-primary); }
.ng-be .form-check-input:checked {
    background-color: var(--ng-primary);
    border-color: var(--ng-primary);
}
.ng-be-radios { display: flex; gap: 24px; padding-top: 8px; }
.ng-be-radio { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; cursor: pointer; }
.ng-be-radio input { margin: 0; }
.ng-be-points { margin-top: 16px; max-width: 220px; }
.ng-be-points[hidden] { display: none; }

.ng-be-actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 10px; }

/* 自定义下拉的触发器要跟着表单宽度走 */
.ng-be .ng-sel { width: 100%; }
.ng-be .ng-sel-trigger { width: 100%; }

/* ============================================================
   富文本编辑器外壳（wangEditor v5，与 sup 同款；资源在 assets/{js,css}/wangeditor/）
   —— 只在发布页加载（header.php 依据 $editor 开关）。
   外观基本由 --w-e-* 变量驱动，变量管不到的（工具条分隔线、svg 的 fill）单独补。
   注意：**不要把 opacity 加在 .w-e-toolbar 上** —— wangEditor 的下拉渲染在工具条内部，
   父级 opacity<1 会建层叠上下文，下拉会被后面的正文区盖住（sup 那边踩过）。
   ============================================================ */
.rich-editor {
    border: 1px solid var(--ng-border);
    background: #fff;
    --w-e-toolbar-color: var(--ng-text-secondary);
    --w-e-toolbar-active-color: var(--ng-primary);
    --w-e-toolbar-active-bg-color: var(--ng-border-light);
    --w-e-toolbar-border-color: var(--ng-border-light);
    --w-e-textarea-border-color: var(--ng-border);
    --w-e-textarea-slight-color: var(--ng-text-muted);
    --w-e-textarea-slight-bg-color: var(--ng-bg);
    --w-e-textarea-selected-border-color: var(--ng-primary);
    --w-e-textarea-handler-bg-color: var(--ng-primary);
}
.rich-editor-toolbar { position: relative; z-index: 2; }
.rich-editor .w-e-toolbar { background: #fafbfc; border-bottom: 1px solid var(--ng-border); padding: 0; }
.rich-editor .w-e-bar-item > button,
.rich-editor .w-e-bar-divider { opacity: .85; transition: opacity .2s; }
.rich-editor .w-e-toolbar:hover .w-e-bar-item > button,
.rich-editor .w-e-toolbar:hover .w-e-bar-divider { opacity: 1; }
.rich-editor .w-e-bar-item button { border-radius: 0; }
.rich-editor .w-e-bar-item button:hover svg,
.rich-editor .w-e-bar-item button.active svg { fill: var(--ng-primary); }
.rich-editor .w-e-bar-item button.active { box-shadow: inset 0 0 0 1px var(--ng-primary); }
.rich-editor .w-e-select-list,
.rich-editor .w-e-drop-panel,
.rich-editor .w-e-modal {
    border: 1px solid var(--ng-border);
    border-radius: 0;
    box-shadow: var(--ng-shadow);
}
.rich-editor .w-e-bar-divider { background-color: var(--ng-border-light); }
/* wangEditor 弹窗（链接、表格等）的关闭按钮类名也叫 .btn-close，
   Bootstrap 会按自己的规格给它塞一张自绘的 × 背景图（--bs-btn-close-bg），
   于是和 wangEditor 自己内联的 svg × 叠成「双 X」（用户 2026-10-17 反馈）。
   这里把 Bootstrap 那张背景图与透明度复位，只留 wangEditor 的 svg。 */
.w-e-modal .btn-close,
.rich-editor .btn-close {
    background: none !important;
    background-image: none !important;
    opacity: 1;
    box-shadow: none;
}
.w-e-modal .btn-close:hover,
.rich-editor .btn-close:hover { opacity: .65; }
.rich-editor-box { height: 240px; min-height: 0; overflow: hidden; }
/* 加高版（后台公告正文用，data-rich-tall）：一次性编辑的长度远超蓝图简介 */
.rich-editor--tall .rich-editor-box { height: 440px; }
.rich-editor-box .w-e-text-container { min-height: 0; }
.rich-editor-box .w-e-text-container p { margin-bottom: .5em; }
.rich-editor-box .w-e-text-container img { max-width: 100%; }
/* 正文区：**去掉 wangEditor 自带的那层 #333 边框**（外层 .rich-editor 已有 1px 站内边框，
   里面再套一条深灰线就是「框中有框」，实测 border 为 #333）。 */
.rich-editor .w-e-text-container { padding: 0; border: 0; }
.rich-editor .w-e-textarea-cntr,
.rich-editor .w-e-textarea-container { border: 0; border-radius: 0; }

/* 内距要给「正文」和「占位文字」**同时**加：
   wangEditor 的占位符是 absolute（自带 top:17px / left:10px，相对 padding box 定位），
   只给容器加 padding 会把正文推下去而占位符不动 —— 表现就是「提示文字和光标错位」。
   所以容器 padding 归零，正文与占位符各自给同一组值。 */
.rich-editor .w-e-text-container [data-slate-editor] { padding: 12px 14px; }
/* 正文首段的 margin-top 会把文字整体压下去（实测 15px），而占位符是按容器顶定位的 —— 两者就错开一行。
   编辑器里的块级元素一律不要上边距，位置完全由容器内距决定；段间仍留 10px。
   **选择器必须带上 `[data-slate-editor]`**：wangEditor 自带
   `.w-e-text-container [data-slate-editor] p { margin: 15px 0 }` 是 (0,2,1)，
   而 editor.css 在 main.css 之后加载 —— 同特异性下它赢，只写 `.rich-editor .w-e-text-container p` 无效，
   这里 (0,3,1) 才压得住。 */
.rich-editor .w-e-text-container [data-slate-editor] p,
.rich-editor .w-e-text-container [data-slate-editor] h1,
.rich-editor .w-e-text-container [data-slate-editor] h2,
.rich-editor .w-e-text-container [data-slate-editor] h3,
.rich-editor .w-e-text-container [data-slate-editor] h4,
.rich-editor .w-e-text-container [data-slate-editor] h5,
.rich-editor .w-e-text-container [data-slate-editor] blockquote,
.rich-editor .w-e-text-container [data-slate-editor] ul,
.rich-editor .w-e-text-container [data-slate-editor] ol { margin-top: 0; margin-bottom: 10px; }
.rich-editor .w-e-text-container [data-slate-editor] > *:last-child { margin-bottom: 0; }
/* 占位符的行高与字号对齐正文（正文 p 是 line-height 1.5），基线才一致 */
.rich-editor .w-e-text-placeholder {
    top: 12px; left: 14px;
    font-style: normal; font-size: 14px; line-height: 1.5;
    width: auto; max-width: calc(100% - 28px);
}

/* 详情页正文（富文本渲染） */
.ng-bp-rich { font-size: 15px; line-height: 1.9; color: var(--ng-text-secondary); }
.ng-bp-rich p { margin: 0 0 .8em; }
.ng-bp-rich h2, .ng-bp-rich h3 { font-size: 17px; color: var(--ng-text); margin: 1.2em 0 .5em; }
.ng-bp-rich ul, .ng-bp-rich ol { margin: 0 0 .8em; padding-left: 1.4em; }
.ng-bp-rich li { margin-bottom: .3em; }
.ng-bp-rich blockquote { margin: 0 0 .8em; padding: 8px 14px; border-left: 3px solid var(--ng-primary-light); background: var(--ng-bg); color: var(--ng-text-secondary); }
.ng-bp-rich a { color: var(--ng-primary); }

/* ============================================================
   蓝图详情（/plaza/{slug}）—— 三列版式（用户 2026-10-17 画注释定的）
   左：主图（左右 <> 换图）+ 缩略图选图区 / 中：标题·元信息·价格·下载 / 右：作者卡 + 介绍区
   ============================================================ */
/* 左右各留 200px（用户 2026-10-17 定，300 → 200）。**从 1200 起就给足 200**，
   再往下才收窄 —— 否则 1280 的屏幕上只剩 100，跟「改 200」的预期不符。 */
.ng-bpd { padding: 30px 200px 10px; }
@media (max-width: 1199.98px) { .ng-bpd { padding: 24px 50px 10px; } }
@media (max-width: 767.98px)  { .ng-bpd { padding: 18px 14px 10px; } }

/* 两列：左 = 主图 + 选图区；右 = 作者卡 / 信息卡 / 下载卡 三张卡竖排 */
.ng-bpd-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(340px, 420px);
    gap: 24px;
    align-items: start;
    /* 主图被 max-height 卡到 1000 宽后，列里会剩下几十像素空隙 —— 让整组居中，左右平分，不偏向一侧 */
    justify-content: center;
}
.ng-bpd-side > * + * { margin-top: 16px; }
/* 右列跟随滚动（2026-11-14）：主图比右列高近 180px，底部留白明显；
   让右列吸在导航下方，看长图时价格与购买按钮始终在视野内，留白也不再刺眼。
   窄屏单列布局下无效（此时右列在主图下方，跟随会打架）。 */
@media (min-width: 900px) {
    .ng-bpd-side {
        position: sticky;
        top: calc(var(--ng-nav-h) + 20px);
        align-self: start;
    }
}   /* 三张卡之间的统一间距 */
@media (max-width: 1199.98px) {
    .ng-bpd-grid { grid-template-columns: minmax(0, 1fr) minmax(300px, 360px); }
}
@media (max-width: 899.98px) {
    .ng-bpd-grid { grid-template-columns: minmax(0, 1fr); }
}

/* 主图 */
/* 主图区按 **3:2** 开框（2026-11-14 用户由 2:1 改成 3:2），图片一律 cover 居中裁剪。
   比原来的 2:1 更高一些，蓝图俯瞰图的信息量能完整露出；随列宽等比缩放，
   不会因为上传的图是竖的还是超宽而变形。 */
.ng-bpd-stage {
    position: relative; background: var(--ng-bg); border: 1px solid var(--ng-border-light);
    overflow: hidden;
    aspect-ratio: 3 / 2;
    max-height: 900px;
}
/* 换图轨道：所有展示图并排，换图只改 translateX（用户 2026-10-17 要「切换带横向滚动动画」）。
   轨道由 flex 自己撑到「100% × 张数」，stage 的 overflow:hidden 负责裁掉出画的部分。 */
.ng-bpd-track {
    display: flex; height: 100%;
    will-change: transform;
    transition: transform .42s cubic-bezier(.22, .61, .36, 1);
}
.ng-bpd-slide { flex: 0 0 100%; height: 100%; }
@media (prefers-reduced-motion: reduce) {
    .ng-bpd-track { transition: none; }
}
.ng-bpd-img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center; }
.ng-bpd-img--empty { display: flex; align-items: center; justify-content: center; font-size: 40px; color: var(--ng-primary); opacity: .35; }
/* 换图按钮沿用列表那套深色方块；但这里没有 .ng-pz-track 的溢出判定，得显式放出并垂直居中
   （.ng-pz-nav 默认 opacity:0 + top: calc((100% - 80px)/2)，那是给卡片行用的） */
.ng-bpd-stage .ng-pz-nav { opacity: 1; pointer-events: auto; top: 50%; }
.ng-bpd-stage .ng-pz-nav:hover { opacity: 1; }

/* 选图区 */
.ng-bpd-thumbs { display: flex; gap: 10px; margin-top: 12px; flex-wrap: wrap; }
.ng-bpd-thumb {
    /* 与主图同 3:2，缩略图与主图比例一致，切图时观感统一 */
    width: 132px; height: 88px; padding: 0; cursor: pointer;
    border: 2px solid transparent; background: var(--ng-bg); overflow: hidden;
    transition: border-color .18s ease;
}
.ng-bpd-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ng-bpd-thumb:hover { border-color: var(--ng-primary-light); }
.ng-bpd-thumb.is-active { border-color: var(--ng-primary); }

/* 信息卡：标题 + 元信息，规格与作者卡/下载卡一致 */
/* 信息卡：标题 + 元信息。label 列放宽到 54px，四字标签不挤；行距 10px 让三行不显散。 */
.ng-bpd-info { padding: 20px; background: var(--ng-bg-white); border: 1px solid var(--ng-border-light); }
.ng-bpd-title { font-size: 21px; font-weight: 800; line-height: 1.4; margin: 0 0 16px; }
.ng-bpd-meta { margin: 0; display: grid; gap: 10px; }
.ng-bpd-meta > div { display: grid; grid-template-columns: 54px minmax(0, 1fr); gap: 10px; font-size: 13px; }
.ng-bpd-meta dt { color: var(--ng-text-muted); }
.ng-bpd-meta dd { margin: 0; color: var(--ng-text); }
.ng-bpd-price { font-size: 26px; font-weight: 800; color: var(--ng-primary); line-height: 1; }
.ng-bpd-price small { font-size: 12px; font-weight: 600; color: var(--ng-text-muted); margin-left: 3px; }
.ng-bpd-hint { font-size: 12.5px; line-height: 1.8; color: var(--ng-text-muted); margin: 12px 0 0; }

/* 右列：作者卡 + 介绍区 */
.ng-bpd-author {
    display: grid; grid-template-columns: 52px minmax(0, 1fr); gap: 12px; align-items: center;
    padding: 16px; background: var(--ng-bg-white); border: 1px solid var(--ng-border-light);
}
.ng-bpd-avatar { width: 52px; height: 52px; border-radius: 50%; object-fit: cover; background: var(--ng-bg); display: block; }
.ng-bpd-who { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ng-bpd-name {
    font-size: 15px; font-weight: 700; color: var(--ng-text); text-decoration: none;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ng-bpd-name:hover { color: var(--ng-primary); }
.ng-bpd-fans { font-size: 12px; color: var(--ng-text-muted); }
.ng-bpd-actions { grid-column: 1 / -1; display: flex; gap: 10px; margin-top: 6px; }
.ng-bpd-btn {
    flex: 1; display: flex; align-items: center; justify-content: center;
    height: 34px; padding: 0 12px;
    border: 1px solid var(--ng-border); background: var(--ng-bg-white);
    color: var(--ng-text-secondary); font-size: 13px; text-decoration: none; cursor: pointer;
    transition: color .18s ease, border-color .18s ease, background-color .18s ease;
}
.ng-bpd-btn:hover { border-color: var(--ng-primary-light); color: var(--ng-primary); }
.ng-bpd-btn--main { background: var(--ng-primary); border-color: var(--ng-primary); color: #fff; }
.ng-bpd-btn--main:hover { background: var(--ng-primary-hover); border-color: var(--ng-primary-hover); color: #fff; }
/* 已关注：退成描边态，免得和「未关注」长得一样 */
.ng-bpd-btn--main[data-on="1"] { background: var(--ng-bg-white); border-color: var(--ng-border); color: var(--ng-text-secondary); }

/* 下载块：独立卡片（用户 2026-10-17），放在标题·元信息下方 */
/* 下载卡（2026-11-14 重构）：价格与计数一行 → 整宽主按钮 → 提示 → 文件明细一行小字。
   重心交给价格和按钮，文件明细退为次要信息。 */
.ng-bpd-dl {
    padding: 20px; background: var(--ng-bg-white); border: 1px solid var(--ng-border-light);
    display: flex; flex-direction: column;
}

/* 顶部：左边大号价格，右边下载次数，基线对齐 */
.ng-bpd-dl-top {
    display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
    padding-bottom: 16px; border-bottom: 1px solid var(--ng-border-light);
}
.ng-bpd-dl-count { font-size: 12.5px; color: var(--ng-text-muted); white-space: nowrap; }
.ng-bpd-dl-count b { font-weight: 600; color: var(--ng-text-secondary); }

/* 主按钮整宽：原来只有 110px，作为整卡的唯一转化动作太弱 */
.ng-bpd-dl-act { margin-top: 16px; }
.ng-bpd-dl-act .btn {
    display: flex; align-items: center; justify-content: center;
    width: 100%; height: 44px; padding: 0 16px;
    font-size: 14px;
}

.ng-bpd-dl .ng-bpd-hint { margin-top: 10px; }

/* 文件明细：一行小字，间隔点分隔；过长时省略号，不换行撑高卡片 */
.ng-bpd-fileline {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: 0 8px;
    margin: 16px 0 0; padding: 14px 0 0;
    border-top: 1px solid var(--ng-border-light);
    list-style: none;
    font-size: 12px; color: var(--ng-text-muted);
}
.ng-bpd-fileline li { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.ng-bpd-fileline li + li::before {
    /* 间隔点用次要文字色而不是边框色 —— 边框色在这层灰字上几乎看不见 */
    content: '·'; color: var(--ng-text-muted);
}
.ng-bpd-fileline-name {
    max-width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 767.98px) {
    /* 窄屏文件名可以独占一行 */
    .ng-bpd-fileline-name { flex-basis: 100%; max-width: 100%; }
    .ng-bpd-fileline-name::before { display: none; }
}

/* ── 社区评价（2026-11-14）──
   布局：上方输入框 → 一条分割线 → 下方评论列表（最新在上）。
   评论条与条之间也用分割线隔开，不套卡片、不加底色，保持整块干净。 */
.ng-cmt { display: flex; flex-direction: column; }

/* 输入区 */
.ng-cmt-textarea {
    width: 100%;
    padding: 12px 14px;
    border: 1px solid var(--ng-border);
    /* 10px：与认证页表单控件同值。站内「0 圆角」只约束卡片/区块，
       输入框、按钮这类控件本来就可以用圆角（按钮还有 .btn-pill 胶囊）。 */
    border-radius: 10px;
    background: #fff;
    font: inherit; font-size: 13.5px; line-height: 1.7;
    color: var(--ng-text);
    resize: vertical;
    min-height: 84px;
    outline: none;
    transition: border-color .2s ease;
}
.ng-cmt-textarea::placeholder { color: var(--ng-text-muted); }
.ng-cmt-textarea:focus { border-color: var(--ng-primary); }

.ng-cmt-actions {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    margin-top: 10px;
}
.ng-cmt-counter {
    font-size: 12px; color: var(--ng-text-muted);
    font-variant-numeric: tabular-nums;
}
.ng-cmt-counter.is-over { color: #d93a2e; }
.ng-cmt-submit { padding: 9px 22px; font-size: 13px; }
.ng-cmt-submit:disabled { opacity: .6; cursor: not-allowed; }

/* 未登录：一行提示 + 登录按钮 */
.ng-cmt-signin {
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    padding: 18px 0;
    font-size: 13px; color: var(--ng-text-muted);
}

/* 输入区与列表之间的分割线（用户要求的「然后下划线」） */
.ng-cmt-divider {
    height: 1px;
    /* 用 --ng-border 而不是 -light：light 那档在纯白卡面上几乎看不见，
       用户明确要求「输入框和显示区之间要有下划线」，得能看出来。 */
    background: var(--ng-border);
    margin: 20px 0 0;
}

/* 评论列表 */
.ng-cmt-list { display: flex; flex-direction: column; }
.ng-cmt-empty {
    margin: 0; padding: 30px 0;
    text-align: center;
    font-size: 13px; color: var(--ng-text-muted);
}

/* 单条评论：条与条之间用上边框当分割线（第一条不需要） */
.ng-cmt-item { padding: 18px 0; border-top: 1px solid var(--ng-border); }
.ng-cmt-item:first-child { border-top: 0; }

.ng-cmt-head { display: flex; align-items: center; gap: 9px; margin-bottom: 8px; }
.ng-cmt-ava {
    flex: 0 0 auto; width: 26px; height: 26px;
    border-radius: 50%; object-fit: cover;
    background: var(--ng-bg);
}
.ng-cmt-name { font-size: 13px; font-weight: 600; color: var(--ng-text); }
.ng-cmt-time {
    margin-left: auto;
    font-size: 12px; color: var(--ng-text-muted);
    font-variant-numeric: tabular-nums;
}
/* 评论内容：缩进到与昵称左边缘对齐（头像 26 + 间距 9 = 35），
   并单独铺一层浅灰圆角底 —— 只包内容，不含头像与昵称行，读起来像一条气泡。 */
.ng-cmt-body {
    margin-left: 35px;
    padding: 10px 14px;
    /* 与输入框同为 10px，气泡与输入区形成同一套圆角语言 */
    border-radius: 10px;
    background: var(--ng-bg);
    font-size: 13.5px; line-height: 1.85; color: var(--ng-text-secondary);
    overflow-wrap: anywhere;
}

/* ── 购买确认框正文（塞进 NGUI.confirm 的 Node body）──
   逐项「标签 / 值」两列，数字右对齐并等宽，扫一眼就能看清扣多少、剩多少。 */
.ng-buy-confirm { font-size: 13px; color: var(--ng-text); }
.ng-buy-name {
    margin: 0 0 14px;
    font-size: 14px; font-weight: 700; line-height: 1.5;
    overflow-wrap: anywhere;
}
.ng-buy-row {
    display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
    padding: 7px 0;
    border-bottom: 1px solid var(--ng-border-light);
}
.ng-buy-row:last-child { border-bottom: 0; padding-bottom: 0; }
.ng-buy-k { flex: 0 0 auto; color: var(--ng-text-muted); }
.ng-buy-v {
    flex: 1 1 auto; text-align: right;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
/* 最后一行（购买后剩余）用品牌色强调 */
.ng-buy-row:last-child .ng-buy-v { color: var(--ng-primary); }

/* ── 详情区三标签（蓝图介绍 / 作品详情 / 社区评价）──
   用户 2026-11-14 要求：标签按钮**居中**，内容整宽铺在下面。
   原来这里是一个单块的「介绍」区，现在扩成三块；社区评价先占位，评论区后续再做。 */
.ng-bpd-tabs {
    margin-top: 18px;
    background: var(--ng-bg-white);
    border: 1px solid var(--ng-border-light);
}

/* 标签栏：居中排布，底部一条细线把栏与内容分开 */
.ng-bpd-tabnav {
    display: flex; align-items: center; justify-content: center;
    gap: 6px;
    padding: 0 16px;
    border-bottom: 1px solid var(--ng-border-light);
}

/* 单个标签：无底色，选中时字重 + 品牌色 + 底部 2px 实线 */
.ng-bpd-tab {
    position: relative;
    padding: 15px 18px;
    border: 0; background: none;
    font: inherit; font-size: 14px; font-weight: 500;
    color: var(--ng-text-secondary);
    cursor: pointer;
    transition: color .2s ease;
}
.ng-bpd-tab::after {
    content: ''; position: absolute; left: 18px; right: 18px; bottom: -1px;
    height: 2px; background: transparent;
    transition: background-color .2s ease;
}
.ng-bpd-tab:hover { color: var(--ng-primary); }
.ng-bpd-tab.is-active { color: var(--ng-primary); font-weight: 700; }
.ng-bpd-tab.is-active::after { background: var(--ng-primary); }
.ng-bpd-tab:focus-visible { outline: 2px solid var(--ng-primary); outline-offset: -4px; }

/* 内容面板 */
.ng-bpd-panel { padding: 22px; }
.ng-bpd-panel[hidden] { display: none; }

/* 规格表：作品详情用，两列自适应，窄屏堆成一列 */
.ng-bpd-spec {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 32px;
    margin: 0;
}
@media (max-width: 767.98px) { .ng-bpd-spec { grid-template-columns: 1fr; } }
.ng-bpd-spec > div {
    display: flex; align-items: baseline; gap: 12px;
    padding: 11px 0;
    border-bottom: 1px solid var(--ng-border-light);
    font-size: 13px;
}
.ng-bpd-spec dt { flex: 0 0 72px; color: var(--ng-text-muted); font-weight: 400; }
.ng-bpd-spec dd { flex: 1 1 auto; min-width: 0; margin: 0; color: var(--ng-text); overflow-wrap: anywhere; }

/* 社区评价占位：后续接评论区，先把版位占住，避免标签点进去是空白 */
.ng-bpd-empty {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 10px;
    padding: 46px 20px;
    text-align: center;
    color: var(--ng-text-muted);
}
.ng-bpd-empty i { font-size: 30px; opacity: .35; }
.ng-bpd-empty p { margin: 0; font-size: 13px; }

.ng-bpd-desc-empty { font-size: 13px; color: var(--ng-text-muted); margin: 0; }

/* ============================================================
   用户主页：蓝图 / 关注 / 粉丝 三个标签页（用户 2026-10-17 定）
   ============================================================ */
.ng-pf-tabs { display: flex; gap: 26px; border-bottom: 1px solid var(--ng-border-light); margin-bottom: 24px; }
.ng-pf-tab { position: relative; padding: 10px 2px; font-size: 15px; color: var(--ng-text-secondary); text-decoration: none; }
.ng-pf-tab:hover { color: var(--ng-primary); }
.ng-pf-tab.is-active { color: var(--ng-primary); font-weight: 700; }
.ng-pf-tab.is-active::after { content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: var(--ng-primary); }
.ng-pf-tab b { margin-left: 6px; font-size: 12px; font-weight: 600; color: var(--ng-text-muted); }

.ng-pf-users { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
.ng-pf-user {
    display: flex; align-items: center; gap: 12px; padding: 14px;
    background: var(--ng-bg-white); border: 1px solid var(--ng-border-light); text-decoration: none;
    transition: border-color .18s ease;
}
.ng-pf-user:hover { border-color: var(--ng-border); }
.ng-pf-user img { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; background: var(--ng-bg); flex: 0 0 auto; }
.ng-pf-user-name { font-size: 14px; font-weight: 600; color: var(--ng-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ng-pf-user:hover .ng-pf-user-name { color: var(--ng-primary); }

/* ============================================================
   4.14 首页改版（2026-11-14）
   —— 除英雄区外的五段全部重排：作品打头、能力改行式清单、场景带截图、
      隐私横幅压成一条、公告与 FAQ 收尾。底色节奏 浅灰→白→浅灰→深色→白→浅灰。
   命名前缀 ng-hw / ng-cap / ng-scene / ng-band--tight，避免和老的卡片体系搅在一起。
   ============================================================ */

/* 白底整段：页身底色是 #f5f6f8，白底段用来切节奏（原 .ng-sec--soft 与页身同色，其实看不出来） */
.ng-sec--white { background: var(--ng-bg-white); }

/* 区块头：标题在左、入口链接在右（大屏一行，窄屏折行） */
.ng-sec-head--row {
    display: flex; align-items: flex-end; justify-content: space-between;
    gap: 16px 32px; max-width: none; flex-wrap: wrap;
}
.ng-more-link {
    display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
    font-size: 14px; color: var(--ng-text-secondary); text-decoration: none;
    padding-bottom: 3px; border-bottom: 1px solid transparent;
    transition: color .18s ease, gap .18s ease, border-color .18s ease;
}
.ng-more-link i { font-size: 13px; }
.ng-more-link:hover { color: var(--ng-primary); gap: 10px; border-bottom-color: var(--ng-primary-light); }

/* ── 1. 最新蓝图：一行 5 张，与蓝图工坊列表同一套网格 ── */
.ng-hw-grid {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 22px 18px;
    padding: 4px 2px 8px;
}
@media (max-width: 1199.98px) { .ng-hw-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 991.98px)  { .ng-hw-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 767.98px)  { .ng-hw-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 12px; } }

/* ── 2. 核心能力：左 sticky 导语 + 右行式清单 ── */
.ng-split {
    display: grid;
    grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
    gap: 24px 64px;
    align-items: start;
}
.ng-split-copy { position: sticky; top: calc(var(--ng-nav-h) + 28px); }
.ng-split-copy .ng-sec-sub { margin-bottom: 24px; max-width: 300px; }

.ng-cap-list { border-top: 1px solid var(--ng-border); }
.ng-cap {
    display: flex; align-items: flex-start; gap: 16px;
    padding: 20px 4px 20px 0;
    border-bottom: 1px solid var(--ng-border);
    transition: background-color .18s ease, padding-left .18s ease;
}
.ng-cap:hover { background: var(--ng-primary-bg); padding-left: 12px; }
.ng-cap-ico {
    flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
    width: 38px; height: 38px; font-size: 17px;
    background: var(--ng-primary-bg); color: var(--ng-primary);
}
.ng-cap-body { min-width: 0; }
.ng-cap-title { font-size: 16px; font-weight: 600; margin: 0 0 6px; color: var(--ng-text); }
.ng-cap-desc { font-size: 14px; line-height: 1.7; color: var(--ng-text-secondary); margin: 0; }

@media (max-width: 991.98px) {
    .ng-split { grid-template-columns: minmax(0, 1fr); gap: 28px; }
    .ng-split-copy { position: static; }
    .ng-split-copy .ng-sec-sub { max-width: none; }
}

/* ── 3. 适用场景：左右错位双栏，媒体带 1px 描边 ── */
.ng-scene {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    gap: 40px 56px;
    align-items: center;
    padding: 44px 0;
    border-top: 1px solid var(--ng-border);
}
.ng-scene:last-of-type { border-bottom: 1px solid var(--ng-border); }
.ng-scene.is-reverse .ng-scene-media { order: 2; }
.ng-scene-media { min-width: 0; }
.ng-scene-media img {
    display: block; width: 100%; height: auto;
    border: 1px solid var(--ng-border); background: var(--ng-bg-white);
}
.ng-scene-copy { min-width: 0; }
.ng-scene-title { font-size: 22px; font-weight: 700; line-height: 1.4; margin: 0 0 12px; }
.ng-scene-desc { font-size: 15px; line-height: 1.8; color: var(--ng-text-secondary); margin: 0; }
.ng-scene-link {
    display: inline-flex; align-items: center; gap: 6px; margin-top: 20px;
    font-size: 14px; font-weight: 600; color: var(--ng-primary); text-decoration: none;
    transition: gap .18s ease;
}
.ng-scene-link:hover { gap: 10px; }

@media (max-width: 991.98px) {
    .ng-scene { grid-template-columns: minmax(0, 1fr); gap: 22px; padding: 32px 0; }
    .ng-scene.is-reverse .ng-scene-media { order: 0; }
    .ng-scene-title { font-size: 19px; }
}

/* ── 4. 隐私横幅：标题在左、三点在右，整体约半屏高 ── */
.ng-band--tight { padding: 48px 0; }
.ng-band-lead { max-width: 620px; margin-bottom: 28px; }
.ng-band-lead .ng-band-sub { margin-bottom: 0; }
.ng-band-row {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 20px 40px;
    padding-top: 24px; border-top: 1px solid rgba(255, 255, 255, .12);
}
.ng-band-item { display: flex; align-items: flex-start; gap: 12px; min-width: 0; }
.ng-band-item > i { font-size: 18px; color: #8f7dff; line-height: 1.5; flex: 0 0 auto; }
.ng-band-item b { display: block; font-size: 14px; font-weight: 600; color: #fff; margin-bottom: 4px; }
.ng-band-item span { font-size: 13px; color: rgba(255, 255, 255, .62); line-height: 1.65; }
.ng-band--tight .ng-band-note { margin-top: 24px; padding-top: 18px; }

@media (max-width: 767.98px) {
    .ng-band-row { grid-template-columns: minmax(0, 1fr); gap: 16px; }
}

/* ── 6. FAQ：手风琴（Bootstrap 5 accordion，靠 bootstrap.bundle 的 collapse 做展开动画） ──
   为什么不用裸 details：原生 details 的展开是「瞬间跳高」，没有高度过渡；
   Bootstrap 的 collapse 会给 .collapsing 逐帧写 height，才有那种推开的动画。
   样式全部走 --bs-accordion-* 变量 + 去掉圆角/背景/描边，保持站内的扁平体系。 */
.ng-acc {
    max-width: 880px; margin: 0 auto;
    border-top: 1px solid var(--ng-border);
    --bs-accordion-color: var(--ng-text-secondary);
    --bs-accordion-bg: transparent;
    --bs-accordion-border-width: 0;
    --bs-accordion-border-radius: 0;
    --bs-accordion-inner-border-radius: 0;
    --bs-accordion-btn-color: var(--ng-text);
    --bs-accordion-btn-bg: transparent;
    --bs-accordion-btn-focus-box-shadow: none;
    --bs-accordion-btn-focus-border-color: transparent;
    --bs-accordion-active-color: var(--ng-primary);
    --bs-accordion-active-bg: transparent;
    /* 折线图标按站内配色换掉 Bootstrap 的深灰（fill 用 %23 转义，不能写 #） */
    --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%235a6070'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
    --bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236c5ce7'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
}
.ng-acc .accordion-item {
    background: transparent;
    border: 0;
    border-bottom: 1px solid var(--ng-border);
}
.ng-acc .accordion-header { margin: 0; }
.ng-acc .accordion-button {
    padding: 20px 4px 20px 0;
    font-size: 16px; font-weight: 600; line-height: 1.5;
    box-shadow: none;
}
.ng-acc .accordion-button:hover { color: var(--ng-primary); }
.ng-acc .accordion-button:not(.collapsed) { box-shadow: none; }
.ng-acc .accordion-button::after { width: 13px; height: 13px; background-size: 13px; }
.ng-acc .accordion-body {
    padding: 0 44px 22px 0;
    font-size: 14px; line-height: 1.85; color: var(--ng-text-secondary);
}
.ng-acc .accordion-body p { margin: 0; }

@media (max-width: 767.98px) {
    .ng-acc .accordion-button { font-size: 15px; padding: 16px 2px 16px 0; }
    .ng-acc .accordion-body { padding: 0 24px 18px 0; }
}

/* 居中版区块头（FAQ 这类收尾段用） */
.ng-sec-head--center { max-width: 640px; margin: 0 auto 36px; text-align: center; }

/* ============================================================
   4.15 产品介绍页改版（2026-11-14）
   —— 版式与首页同一轮重排：页头换成截图、数字压成细条、界面区提前、
      背景改两列对照表、能力沿用 .ng-split/.ng-cap、两条步骤流合成一条、
      格式改紧凑表。新增前缀：ng-shot / ng-strip / ng-vs / ng-flow / ng-fmt。
   ============================================================ */

/* 页头截图：8px 内衬当「相框」，不用圆角 */
.ng-shot {
    background: var(--ng-bg-white);
    border: 1px solid var(--ng-border);
    padding: 8px;
    box-shadow: var(--ng-shadow);
}
.ng-shot img { display: block; width: 100%; height: auto; }

/* 数字条：hero 下方的四项横排，项间用 1px 竖线分隔 */
.ng-strip { background: var(--ng-bg-white); border-bottom: 1px solid var(--ng-border); }
.ng-strip-inner { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ng-strip-item { padding: 22px 28px; border-left: 1px solid var(--ng-border-light); }
.ng-strip-item:first-child { border-left: 0; padding-left: 0; }
.ng-strip-item b { display: block; font-size: 24px; font-weight: 700; line-height: 1.25; color: var(--ng-text); }
.ng-strip-item span { font-size: 13px; color: var(--ng-text-muted); }

@media (max-width: 991.98px) {
    .ng-strip-inner { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .ng-strip-item { padding: 16px 0 16px 18px; }
    /* 第二项起按 2 列折行，第 3 项回到行首，去掉竖线 */
    .ng-strip-item:nth-child(odd) { border-left: 0; padding-left: 0; }
    .ng-strip-item:nth-child(n+3) { border-top: 1px solid var(--ng-border-light); }
}

/* 对照表：两列 × N 行，格子逐行对应（用 grid 行对齐，不用两个独立列，
   否则左右文案长短不一会错行） */
.ng-vs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    border: 1px solid var(--ng-border);
    background: var(--ng-bg-white);
}
.ng-vs-hd {
    padding: 14px 24px;
    font-size: 13px; font-weight: 600; letter-spacing: .04em;
    border-bottom: 1px solid var(--ng-border);
}
.ng-vs-hd.is-old { color: var(--ng-text-muted); background: #fafbfc; }
.ng-vs-hd.is-new { color: var(--ng-primary); background: var(--ng-primary-bg); border-left: 1px solid var(--ng-border); }
.ng-vs-cell { padding: 18px 24px; font-size: 14px; line-height: 1.75; }
.ng-vs-cell.is-old { color: var(--ng-text-muted); }
.ng-vs-cell.is-new { color: var(--ng-text); border-left: 1px solid var(--ng-border); }
.ng-vs-cell.is-old::before {
    content: ''; display: inline-block; width: 6px; height: 6px;
    margin-right: 10px; vertical-align: 2px;
    background: var(--ng-text-muted); opacity: .45;
}
.ng-vs-cell.is-new::before {
    content: ''; display: inline-block; width: 6px; height: 6px;
    margin-right: 10px; vertical-align: 2px;
    background: var(--ng-primary);
}
/* 除表头外，每两格一条横线 */
.ng-vs-cell:nth-child(n+5) { border-top: 1px solid var(--ng-border-light); }

/* 窄屏：两列并排塞不下（每格只剩 150px 左右），改成一列，
   表头隐藏、把列名贴回每一格上方（用 data-label，避免把文案写死在 CSS 里） */
@media (max-width: 767.98px) {
    .ng-vs { display: block; border: 0; background: transparent; border-top: 1px solid var(--ng-border); }
    .ng-vs-hd { display: none; }
    .ng-vs-cell { padding: 14px 0; border-bottom: 1px solid var(--ng-border-light); }
    .ng-vs-cell.is-new { border-left: 0; }
    .ng-vs-cell.is-old::before,
    .ng-vs-cell.is-new::before {
        content: attr(data-label);
        display: block; width: auto; height: auto;
        margin: 0 0 5px; padding: 0;
        background: none; opacity: 1;
        font-size: 11px; font-weight: 600; letter-spacing: .08em;
        color: var(--ng-text-muted);
    }
    .ng-vs-cell.is-new::before { color: var(--ng-primary); }
    .ng-vs-cell:nth-child(n+5) { border-top: 0; }
}

/* 四步流程：横向时间轴（顶部一条线 + 方点 + 序号） */
.ng-flow {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0 28px;
}
.ng-flow-item {
    position: relative;
    padding: 22px 0 0;
    border-top: 1px solid var(--ng-border);
}
.ng-flow-item::before {
    content: ''; position: absolute; left: 0; top: -3.5px;
    width: 7px; height: 7px; background: var(--ng-primary);
}
.ng-flow-num {
    display: block; font-size: 12px; font-weight: 700; letter-spacing: .1em;
    color: var(--ng-text-muted); margin-bottom: 8px;
}
.ng-flow-title { font-size: 16px; font-weight: 600; margin: 0 0 8px; display: flex; align-items: center; gap: 8px; }
.ng-flow-title i { color: var(--ng-primary); font-size: 15px; }
.ng-flow-desc { font-size: 13.5px; line-height: 1.75; color: var(--ng-text-secondary); margin: 0; }

/* 原「技术原理」压成一条注释带 */
.ng-flow-note {
    display: grid; grid-template-columns: minmax(0, 240px) minmax(0, 1fr);
    gap: 8px 32px;
    margin-top: 44px; padding: 20px 24px;
    background: var(--ng-bg);
}
.ng-flow-note b { font-size: 14px; font-weight: 600; color: var(--ng-text); }
.ng-flow-note span { font-size: 13.5px; line-height: 1.8; color: var(--ng-text-secondary); }

@media (max-width: 991.98px) {
    .ng-flow { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px; }
    .ng-flow-note { grid-template-columns: minmax(0, 1fr); margin-top: 32px; }
}

/* 支持格式：两列紧凑表（分组名 120px + 标签行） */
.ng-fmt {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 48px;
    border-top: 1px solid var(--ng-border);
}
.ng-fmt-row {
    display: grid; grid-template-columns: 128px minmax(0, 1fr);
    gap: 16px; align-items: start;
    padding: 18px 0;
    border-bottom: 1px solid var(--ng-border);
}
.ng-fmt-name { font-size: 14px; font-weight: 600; color: var(--ng-text); line-height: 26px; }
.ng-fmt-tags { display: flex; flex-wrap: wrap; gap: 8px; }

@media (max-width: 767.98px) {
    .ng-fmt { grid-template-columns: minmax(0, 1fr); }
    .ng-fmt-row { grid-template-columns: minmax(0, 1fr); gap: 8px; }
    .ng-fmt-name { line-height: 1.5; }
}

/* ── 功能模块的截图区：固定比例画框 + 交叉淡入淡出 ──
   Bootstrap 的 tab 切的是 display，旧图瞬间消失、新图再来一次淡入，看起来是「闪一下」。
   这里把全部面板绝对定位叠在一起（覆盖 .tab-pane 的 display:none），只切 opacity，
   切换时两张图同时在，才是真正的交叉淡入。
   画框用 aspect-ratio 锁死比例（截图原始 1905×924），换标签时高度不会跳。 */
.ng-module-shots .ng-tab-content {
    position: relative;
    aspect-ratio: 1905 / 924;
    border: 1px solid var(--ng-border);
    background: var(--ng-bg-white);
    overflow: hidden;
}
.ng-module-shots .ng-tab-content > .tab-pane {
    position: absolute;
    inset: 0;
    display: block !important;
    opacity: 0;
    pointer-events: none;
    transition: opacity .32s var(--ng-ease);
}
.ng-module-shots .ng-tab-content > .tab-pane.active { opacity: 1; pointer-events: auto; }
.ng-module-shots .ng-tab-content img {
    display: block; width: 100%; height: 100%;
    object-fit: cover;
    border: 0;
}

/* ── 下载区（2026-11-14 重构：去掉卡片嵌套） ──
   原来是一张白卡（border + bg）里再放一块渐变色块 + 一块正文 + 一条规格表，
   在白底段落里就是「卡片套卡片」。现在整块直接落在页面上：
   顶部一条细线分隔，左侧一块渐变 OS 图标（元素，不是卡片），右侧标题/说明/规格/按钮全部平铺。 */
.ng-dl2 {
    display: grid;
    grid-template-columns: 168px minmax(0, 1fr);
    gap: 24px 48px;
    padding-top: 40px;
    border-top: 1px solid var(--ng-border);
    align-items: start;
}
.ng-dl2-os {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 4px;
    padding: 30px 16px;
    background: var(--ng-gradient);
    color: #fff;
}
.ng-dl2-os i { font-size: 34px; line-height: 1; margin-bottom: 6px; }
.ng-dl2-os b { font-size: 16px; font-weight: 700; }
.ng-dl2-os span { font-size: 12px; color: rgba(255, 255, 255, .82); }

.ng-dl2-body { min-width: 0; }
.ng-dl2-body .ng-sec-title { margin-bottom: 8px; }
.ng-dl2-body .ng-sec-sub { max-width: 560px; }

/* 规格：一行内联，项间用竖线分隔（原来是 4~5 列的表格块，也是一种「框」） */
.ng-dl2-specs {
    display: flex; flex-wrap: wrap; align-items: stretch;
    gap: 0; margin: 24px 0 0;
    border-top: 1px solid var(--ng-border-light);
    border-bottom: 1px solid var(--ng-border-light);
}
.ng-dl2-specs > div { padding: 12px 22px 12px 0; margin-right: 22px; border-right: 1px solid var(--ng-border-light); }
.ng-dl2-specs > div:last-child { border-right: 0; margin-right: 0; padding-right: 0; }
.ng-dl2-specs dt { font-size: 12px; font-weight: 500; color: var(--ng-text-muted); margin: 0 0 3px; }
.ng-dl2-specs dd { font-size: 14px; font-weight: 600; color: var(--ng-text); margin: 0; }

.ng-dl2-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 26px; }

@media (max-width: 767.98px) {
    .ng-dl2 { grid-template-columns: minmax(0, 1fr); gap: 22px; padding-top: 28px; }
    .ng-dl2-os { flex-direction: row; gap: 8px; padding: 14px 18px; justify-content: flex-start; }
    .ng-dl2-os i { font-size: 22px; margin: 0 4px 0 0; }
    .ng-dl2-specs > div { padding: 10px 16px 10px 0; margin-right: 16px; }
    .ng-dl2-actions .btn { flex: 1 1 auto; }
}

/* ── 购买页改版补件（2026-11-14） ──
   套餐卡本体的圆角与居中标签已在 .ng-plan 里改过，这里只补新加的四块：
   通用权益、信任条、购买须知、为什么（纯文字网格）、扁平好评。 */

/* 套餐行：卡片顶部要留出「推荐」标签骑边的空间，否则会被 section 裁掉 */
.ng-plans { padding-top: 16px; }


/* 信任条：一条 inline，四项等分，项间竖线 */
.ng-sec--bar { padding: 30px 0; }
.ng-trust-row { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ng-trust-item {
    display: flex; align-items: flex-start; gap: 12px;
    padding: 0 24px; border-left: 1px solid var(--ng-border-light);
}
.ng-trust-item:first-child { border-left: 0; padding-left: 0; }
.ng-trust-item > i { font-size: 18px; color: var(--ng-primary); line-height: 1.55; flex: 0 0 auto; }
.ng-trust-item b { display: block; font-size: 14px; font-weight: 600; color: var(--ng-text); margin-bottom: 3px; }
.ng-trust-item span { font-size: 12.5px; line-height: 1.6; color: var(--ng-text-muted); }

@media (max-width: 991.98px) {
    .ng-trust-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 0; }
    .ng-trust-item:nth-child(odd) { border-left: 0; padding-left: 0; }
}

/* 购买须知：2×2 无缝网格（容器底色当分隔线，四格白底），像一张规格表 */
.ng-policy {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1px; background: var(--ng-border);
    border: 1px solid var(--ng-border);
}
.ng-policy-item {
    display: flex; align-items: flex-start; gap: 14px;
    background: var(--ng-bg-white);
    padding: 26px 28px;
}
.ng-policy-item > i { font-size: 18px; color: var(--ng-primary); line-height: 1.5; flex: 0 0 auto; }
.ng-policy-item b { display: block; font-size: 15px; font-weight: 600; color: var(--ng-text); margin-bottom: 6px; }
.ng-policy-item p { font-size: 13.5px; line-height: 1.8; color: var(--ng-text-secondary); margin: 0; }

@media (max-width: 767.98px) {
    .ng-policy { grid-template-columns: minmax(0, 1fr); }
    .ng-policy-item { padding: 20px 18px; }
}

/* 为什么选择：8 点纯文字网格（4 × 2），左侧图标 + 右侧两行文字，靠顶线切分成格子 */
.ng-why {
    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0 32px;
}
.ng-why-item {
    display: flex; align-items: flex-start; gap: 12px; min-width: 0;
    padding: 20px 0;
    border-top: 1px solid var(--ng-border);
}
.ng-why-item > i { font-size: 17px; color: var(--ng-primary); line-height: 1.5; flex: 0 0 auto; }
.ng-why-item b { display: block; font-size: 14px; font-weight: 600; color: var(--ng-text); margin-bottom: 4px; }
.ng-why-item span { font-size: 12.5px; line-height: 1.65; color: var(--ng-text-muted); }

@media (max-width: 991.98px) {
    .ng-why { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 24px; }
}
@media (max-width: 575.98px) { .ng-why { grid-template-columns: minmax(0, 1fr); } }

/* 区块副标题里的行内链接（如购买页「功能细节在产品介绍」） */
.ng-sec-sub a { color: var(--ng-primary); text-decoration: none; border-bottom: 1px solid var(--ng-primary-light); }
.ng-sec-sub a:hover { border-bottom-color: var(--ng-primary); }

/* ── 购买页二次美化（2026-11-14 晚）──
   套餐区换到浅紫底上，让白卡浮起来；卡片里加「折合月价」对比条（同组价格除出来的，不是新优惠）。 */

/* 浅紫整段：比 .ng-primary-bg 再淡一档，避免和卡片里的权益底色撞 */
.ng-sec--tint {
    background: #f8f7ff;
    border-top: 1px solid var(--ng-border-light);
    border-bottom: 1px solid var(--ng-border-light);
}

/* 卡片顶部：名称与时长胶囊同一行，时长靠右 */
.ng-plan-head { align-items: center; }
.ng-plan-duration {
    margin-left: auto;
    font-size: 11.5px; font-weight: 500; color: var(--ng-text-muted);
    background: var(--ng-bg); padding: 3px 9px; border-radius: 999px;
}
.ng-plan--hot .ng-plan-duration { background: var(--ng-primary-bg); color: var(--ng-primary); }

/* 折合月价对比条：以月卡为满格，其它档按比例缩短（纯视觉对比，不参与计价） */
.ng-plan-bar {
    height: 5px; margin: 2px 0 10px;
    background: var(--ng-border-light);
    border-radius: 999px; overflow: hidden;
}
.ng-plan-bar-fill {
    display: block; height: 100%;
    background: var(--ng-primary); opacity: .45;
    border-radius: 999px;
    transition: width .3s var(--ng-ease);
}
.ng-plan--hot .ng-plan-bar-fill { opacity: 1; }

/* 对比条下方的一句说明 */
.ng-plans-note {
    display: flex; align-items: flex-start; gap: 6px;
    justify-content: center;
    margin: 22px 0 0;
    font-size: 12.5px; color: var(--ng-text-muted); text-align: center;
}
.ng-plans-note i { font-size: 13px; line-height: 1.6; }

/* ============================================================
   底部悬浮气泡（营销条）
   —— 白色胶囊 + NEW 角标 + 主色胶囊按钮，固定在视口底部居中。
   只在 layouts/footer.php 输出，所以后台与认证页不会出现；具体的显示/隐藏路径在
   config/site.php 的 bubble 里配。
   与右下角返回顶部按钮（bottom:30px; right:30px; 44px）错开：气泡是居中的，
   窄屏时留出右侧 72px 的避让宽度，避免两者叠在一起。
   ============================================================ */
.ng-bubble {
    position: fixed;
    left: 50%;
    bottom: 22px;
    z-index: 1040;                     /* 低于返回顶部(1050)与进度条(1100) */
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 14px;
    max-width: calc(100vw - 110px);
    padding: 8px 8px 8px 20px;
    background: var(--ng-bg-white);
    border: 1px solid var(--ng-border);
    border-radius: 999px;
    box-shadow: 0 8px 28px rgba(16, 24, 40, .14);
    animation: ngBubbleIn .5s var(--ng-ease) both;
}
@keyframes ngBubbleIn {
    from { opacity: 0; transform: translate(-50%, 14px); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}

.ng-bubble-ico {
    flex: 0 0 auto;
    font-size: 16px; line-height: 1;
    color: var(--ng-primary);
}
.ng-bubble-text {
    font-size: 13.5px; color: var(--ng-text);
    line-height: 1.4;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ng-bubble-cta {
    flex: 0 0 auto;
    display: inline-flex; align-items: center;
    height: 34px; padding: 0 18px;
    font-size: 13px; font-weight: 600; color: #fff;
    background: var(--ng-gradient);
    border-radius: 999px;
    text-decoration: none;
    transition: filter .18s ease;
}
.ng-bubble-cta:hover { color: #fff; filter: brightness(1.06); }


@media (max-width: 767.98px) {
    .ng-bubble {
        left: 12px; right: 12px; bottom: 12px;
        max-width: none;
        transform: none;
        gap: 10px;
        padding: 7px 7px 7px 14px;
        animation: ngBubbleInSm .5s var(--ng-ease) both;
    }
    @keyframes ngBubbleInSm {
        from { opacity: 0; transform: translateY(14px); }
        to   { opacity: 1; transform: translateY(0); }
    }
    .ng-bubble-text { font-size: 12.5px; }
    .ng-bubble-cta { height: 32px; padding: 0 14px; font-size: 12.5px; }
    /* 窄屏时右下角的返回顶部按钮会盖到气泡，把它抬到气泡上方 */
    .btn-back-top { bottom: 82px; }
}

@media (prefers-reduced-motion: reduce) {
    .ng-bubble { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════
   用户中心视觉重构（2026-11-15）
   全部规则限定在 .uc-shell 作用域，消息中心 / 用户主页 / 导航栏下拉等复用 .uc-* 的
   页面不受影响。方向：内容区加大留白、去卡片描边、页头层级化、
   账号总览两栏 + 信息网格、授权卡主视觉化、图标去胶囊底、侧栏当前项指示。
   只改视觉，不改任何 id / name / data-* 钩子。
   ═══════════════════════════════════════════════════════════════ */

.uc-shell { --uc-side-w: 248px; }

/* ── 侧栏：分组留白、当前项左侧主色指示条 ── */
.uc-shell .uc-side {
    padding: 28px 14px 24px;
    background: var(--ng-bg-white);
    border-right: 1px solid var(--ng-border);
}
.uc-shell .uc-side-title {
    padding: 0 12px 14px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .12em;
    color: var(--ng-text-muted);
}
.uc-shell .uc-side a {
    position: relative;
    padding: 10px 12px;
    border-radius: var(--ng-radius-control);
    font-size: 14px;
}
.uc-shell .uc-side a + a { margin-top: 3px; }
.uc-shell .uc-side a.active {
    background: var(--ng-primary-bg);
    color: var(--ng-primary);
    font-weight: 600;
}
.uc-shell .uc-side a.active::before {
    content: '';
    position: absolute;
    left: 0; top: 8px; bottom: 8px;
    width: 3px;
    background: var(--ng-primary);
}
.uc-shell .uc-side a i { width: 20px; font-size: 16px; }
.uc-shell .uc-side hr { margin: 20px 10px; border-top-color: var(--ng-border-light); }
.uc-shell .uc-side .uc-logout { color: var(--ng-text-muted); }
.uc-shell .uc-side .uc-logout:hover { background: #fff1f0; color: var(--ng-danger); }

/* ── 内容区：保持通栏铺满（不套限宽容器，否则侧栏右缘会露出灰底），
   只靠左右内边距给足呼吸空间 ── */
.uc-shell .uc-main {
    padding: 36px 48px 72px;
}
.uc-shell .uc-page-head {
    margin: 0 0 28px;
    padding: 0 0 22px;
    border-bottom: 1px solid var(--ng-border);
}
.uc-shell .uc-title {
    margin: 0 0 8px;
    font-size: 26px;
    font-weight: 700;
    letter-spacing: -.4px;
}
.uc-shell .uc-page-head .uc-sec-sub { margin: 0; font-size: 13px; line-height: 1.7; }

/* ── 卡片：去四边描边，靠白底与间距分层 ── */
.uc-shell .uc-card { border: 0; box-shadow: none; margin-bottom: 20px; }
.uc-shell .uc-card:last-child { margin-bottom: 0; }
.uc-shell .uc-card-hd {
    padding: 20px 24px 16px;
    border-bottom: 1px solid var(--ng-border-light);
    gap: 10px;
}
.uc-shell .uc-card-hd h3 { font-size: 16px; font-weight: 700; }
.uc-shell .uc-card-hd .uc-card-sub { font-size: 12px; }
.uc-shell .uc-card-hd .uc-head-op .uc-row-op {
    border: 1px solid var(--ng-border);
    border-radius: var(--ng-radius-control);
    padding: 5px 12px;
    font-size: 13px;
}
.uc-shell .uc-card-bd { padding: 22px 24px 26px; }
.uc-shell .uc-card-note { padding: 14px 24px; border-top: 1px solid var(--ng-border-light); }

/* ── 账号总览：身份主卡 + 分区标题 + 四宫格；不补数据，靠层级与留白立住 ── */
.uc-shell .uc-overview { max-width: 1200px; }
.uc-shell .uc-hero-card { background: var(--ng-bg-white); }
.uc-shell .uc-hero-main {
    display: flex;
    align-items: center;
    gap: 24px;
    padding: 34px 36px 38px;
}
.uc-shell .uc-hero-main .uc-avatar {
    width: 84px; height: 84px;
    flex: 0 0 auto;
    border-radius: 50%;
    overflow: hidden;
    background: var(--ng-primary-bg);
    display: flex; align-items: center; justify-content: center;
}
.uc-shell .uc-hero-main .uc-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.uc-shell .uc-hero-who { flex: 1 1 auto; min-width: 0; }
.uc-shell .uc-hero-name { font-size: 26px; font-weight: 700; letter-spacing: -.4px; line-height: 1.3; }
.uc-shell .uc-hero-mail { margin-top: 4px; font-size: 14px; color: var(--ng-text-secondary); word-break: break-all; }
.uc-shell .uc-hero-meta { margin-top: 12px; font-size: 12px; color: var(--ng-text-muted); }
.uc-shell .uc-hero-side {
    margin-left: auto; flex: 0 0 auto;
    display: flex; flex-direction: column; align-items: flex-end; gap: 14px;
}
.uc-shell .uc-hero-badge {
    font-size: 13px; font-weight: 600; color: var(--ng-primary);
    padding-bottom: 4px; border-bottom: 1px solid var(--ng-primary-line);
}
.uc-shell .uc-hero-side .uc-row-op { font-size: 13px; }

/* 分区标题：把原本挤在卡片头里的层级提到内容层 */
.uc-shell .uc-overview-sec { margin-top: 38px; }
.uc-shell .uc-sec-label {
    margin: 0 0 14px;
    font-size: 12px; font-weight: 700; letter-spacing: .14em;
    color: var(--ng-text-muted);
}

/* 授权状态卡：顶部状态行 + 左数值 / 右详情两栏，去掉旧卡片头那一层 */
.uc-shell .uc-subcard-bd { display: block; padding: 24px 32px 30px; gap: 0; }
.uc-shell .uc-sub-top {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 16px; flex-wrap: wrap;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--ng-border-light);
}
.uc-shell .uc-sub-top-txt { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.uc-shell .uc-sub-label { font-size: 12px; font-weight: 700; letter-spacing: .1em; color: var(--ng-text-muted); }
.uc-shell .uc-sub-hint { font-size: 13px; color: var(--ng-text-secondary); }
.uc-shell .uc-sub-top .uc-sub-badge { font-size: 12px; padding: 3px 10px; }
.uc-shell .uc-sub-body {
    display: grid;
    grid-template-columns: minmax(0, 250px) minmax(0, 1fr);
    gap: 24px 40px;
    align-items: center;
    padding-top: 24px;
}
.uc-shell .uc-sub-primary { min-width: 0; }
.uc-shell .uc-sub-time { font-size: 48px; letter-spacing: -1.5px; line-height: 1.1; }
.uc-shell .uc-sub-track { height: 8px; margin-top: 16px; }
.uc-shell .uc-sub-meta { min-width: 0; display: flex; flex-direction: column; gap: 12px; }
.uc-shell .uc-sub-details { flex-direction: column; gap: 6px; font-size: 13px; }
.uc-shell .uc-sub-actions { margin-top: 4px; }
.uc-shell .uc-sub-note { margin: 0; }

/* 个人资料：预览与表单拆成两个平级分区，预览卡不再嵌进白卡 */
.uc-shell .uc-profile-sec { max-width: 1200px; }
.uc-shell .uc-sec-label--split {
    display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
}
.uc-shell .uc-sec-label--split .uc-head-op { margin-left: auto; display: inline-flex; }
.uc-shell .uc-profile-sec .ng-pf--mini .ng-pf-card { margin-bottom: 0; }
.uc-shell .uc-profile-tip {
    margin: 0 0 14px;
    font-size: 12px; line-height: 1.7;
    color: var(--ng-text-muted);
}
.uc-shell .uc-profile-tip code { color: var(--ng-text-secondary); }
.uc-shell .uc-profile-sec .uc-card + .uc-profile-tip { margin: 12px 0 0; }
.uc-shell .uc-profile-sec .uc-card-bd { padding: 24px 28px 28px; }

/* 账号信息四宫格：浅色十字分隔，值放大 */
.uc-shell .uc-card > .uc-items { padding: 4px 24px 12px; grid-template-columns: 1fr; column-gap: 0; }
.uc-shell .uc-card > .uc-info-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0;
    padding: 10px 32px 22px;
}
.uc-shell .uc-info-grid .uc-item {
    padding: 24px 24px 24px 0;
    gap: 14px;
    border-bottom: 1px solid var(--ng-border-light);
}
.uc-shell .uc-info-grid .uc-item:nth-child(odd) { border-right: 1px solid var(--ng-border-light); }
.uc-shell .uc-info-grid .uc-item:nth-child(even) { padding-left: 36px; }
.uc-shell .uc-info-grid .uc-item:nth-last-child(-n+2) { border-bottom: 0; }
.uc-shell .uc-info-grid .uc-item .uc-item-ico {
    width: 24px; height: 24px;
    background: none; border-radius: 0;
    font-size: 17px;
}
.uc-shell .uc-info-grid .uc-item-label { font-size: 12px; }
.uc-shell .uc-info-grid .uc-item-value { font-size: 16px; font-weight: 600; }
.uc-shell .uc-item { padding: 15px 0; gap: 12px; border-bottom-color: var(--ng-border-light); }
.uc-shell .uc-item .uc-item-label { font-size: 12px; }
.uc-shell .uc-item .uc-item-value { font-size: 14px; }

/* ── 通用行：更紧凑、图标去底、值右对齐 ── */
.uc-shell .uc-row { padding: 18px 24px; gap: 16px; }
.uc-shell .uc-row .uc-row-ico {
    width: 30px; height: 30px;
    background: none; border-radius: 0;
    font-size: 18px;
}
.uc-shell .uc-row .uc-row-meta .t { font-size: 14px; }
.uc-shell .uc-row .uc-row-meta .d { font-size: 12px; line-height: 1.6; }
.uc-shell .uc-row-panel { padding: 20px 24px 24px 70px; }

/* ── 表单与按钮：统一高度和留白 ── */
.uc-shell .uc-field { margin-bottom: 18px; }
.uc-shell .uc-field > label { font-size: 13px; font-weight: 600; margin-bottom: 8px; }
.uc-shell .uc-field input[type="text"],
.uc-shell .uc-field input[type="password"],
.uc-shell .uc-field input[type="email"],
.uc-shell .uc-field input[type="file"] { min-height: 42px; }
.uc-shell .uc-form-actions { gap: 10px; padding-top: 4px; }
.uc-shell .uc-code-row { gap: 10px; }

/* ── 空状态与分页：与全站「不加卡片」保持一致 ── */
.uc-shell .uc-empty { padding: 44px 24px; text-align: center; }
.uc-shell .uc-empty i { font-size: 26px; display: block; margin-bottom: 8px; }
.uc-shell .uc-pager { display: flex; justify-content: space-between; align-items: center; }
/* 积分商城商品卡沿用同一套「无阴影、无位移」约束 */
.uc-shell .uc-tile { transition: border-color .2s ease; }
.uc-shell .uc-tile:hover { border-color: var(--ng-primary); box-shadow: none; }

/* ── 窄屏：两栏折单列、内边距收紧 ── */
@media (max-width: 991.98px) {
    .uc-shell .uc-main { padding: 24px 20px 56px; }
    .uc-shell .uc-card > .uc-info-grid { grid-template-columns: 1fr; padding-left: 20px; padding-right: 20px; }
    .uc-shell .uc-info-grid .uc-item:nth-child(odd) { border-right: 0; }
    .uc-shell .uc-info-grid .uc-item:nth-child(even) { padding-left: 0; }
    .uc-shell .uc-info-grid .uc-item:nth-last-child(-n+2) { border-bottom: 1px solid var(--ng-border-light); }
    .uc-shell .uc-info-grid .uc-item:last-child { border-bottom: 0; }
    .uc-shell .uc-hero-main,
    .uc-shell .uc-card-hd,
    .uc-shell .uc-card-bd,
    .uc-shell .uc-card-note,
    .uc-shell .uc-subcard-bd { padding-left: 20px; padding-right: 20px; }
    .uc-shell .uc-sub-body { grid-template-columns: 1fr; gap: 20px; }
    .uc-shell .uc-profile-sec .uc-card-bd { padding: 20px; }
    .uc-shell .uc-card > .uc-items { padding-left: 20px; padding-right: 20px; }
    .uc-shell .uc-row { padding-left: 20px; padding-right: 20px; }
}
@media (max-width: 767.98px) {
    .uc-shell .uc-main { padding: 20px 16px 48px; }
    .uc-shell .uc-hero-main { flex-wrap: wrap; gap: 16px; padding: 24px 20px 26px; }
    .uc-shell .uc-hero-main .uc-avatar { width: 64px; height: 64px; }
    .uc-shell .uc-hero-name { font-size: 22px; }
    .uc-shell .uc-hero-side { margin-left: 0; width: 100%; align-items: flex-start; }
    .uc-shell .uc-overview-sec { margin-top: 28px; }
    .uc-shell .uc-sub-time { font-size: 40px; }
    .uc-shell .uc-card > .uc-info-grid { padding: 6px 20px 14px; }
    .uc-shell .uc-title { font-size: 22px; }
    .uc-shell .uc-row { flex-wrap: wrap; }
    .uc-shell .uc-row-panel { padding-left: 18px; padding-right: 18px; }
}

/* ═══════════════════════════════════════════════════════════════
   用户中心复刻客户端 profile 视觉（2026-11-15 追加层）
   用户确认激进改造：六个板块统一、可破 0 圆角与不用色块的约束。
   本层放在 .uc-shell 覆盖区块末尾，覆盖前几轮的账号总览与授权卡规则。
   只用 --ng-* 主色系，不引入参考图的蓝色；文案与链接全部取真实配置。
   ═══════════════════════════════════════════════════════════════ */
.uc-shell {
    --uc-radius: 12px;
    --uc-radius-sm: 8px;
    --uc-shadow: 0 2px 12px rgba(25, 40, 68, .05);
}

/* 六个板块统一的卡片：小圆角 + 极轻阴影 */
.uc-shell .uc-card {
    border: 1px solid var(--ng-border);
    border-radius: var(--uc-radius);
    box-shadow: var(--uc-shadow);
    margin-bottom: 16px;
}
.uc-shell .uc-card:last-child { margin-bottom: 0; }
.uc-shell .uc-card-hd { border-radius: var(--uc-radius) var(--uc-radius) 0 0; }

/* 内容限宽居中：参考图的容器感，本次按用户授权放宽通栏铺满约束 */
.uc-shell .uc-main { padding: 28px 32px 72px; }
.uc-shell .uc-main > .uc-banner,
.uc-shell .uc-main > .uc-overview,
.uc-shell .uc-main > .uc-profile-sec,
.uc-shell .uc-main > .uc-card,
.uc-shell .uc-main > section {
    max-width: 1200px;
    margin-left: auto;
    margin-right: auto;
}

/* ── 全局渐变横幅：六板块共用 ── */
.uc-shell .uc-banner {
    position: relative;
    overflow: hidden;
    display: flex; align-items: center; justify-content: space-between;
    gap: 24px; flex-wrap: wrap;
    padding: 26px 30px;
    margin-bottom: 24px;
    border-radius: var(--uc-radius);
    background: linear-gradient(115deg, #3b2f8f 0%, var(--ng-primary) 62%, #8f7dff 100%);
    color: #fff;
}
.uc-shell .uc-banner::after {
    content: '';
    position: absolute;
    width: 300px; height: 300px;
    right: -80px; top: -150px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, .16);
    box-shadow: 0 0 0 38px rgba(255, 255, 255, .04), 0 0 0 76px rgba(255, 255, 255, .025);
    pointer-events: none;
}
.uc-shell .uc-banner-user,
.uc-shell .uc-banner-meta-box { position: relative; z-index: 1; }
.uc-shell .uc-banner-user { display: flex; align-items: center; gap: 16px; min-width: 0; }
.uc-shell .uc-banner-avatar {
    width: 58px; height: 58px; flex: 0 0 auto;
    border-radius: 50%; overflow: hidden;
    background: rgba(255, 255, 255, .18);
    display: flex; align-items: center; justify-content: center;
    font-size: 22px; font-weight: 700;
}
.uc-shell .uc-banner-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.uc-shell .uc-banner-who { min-width: 0; }
.uc-shell .uc-banner-who h2 { margin: 0; font-size: 20px; font-weight: 700; line-height: 1.3; }
.uc-shell .uc-banner-who p { margin: 3px 0 0; font-size: 13px; color: rgba(255, 255, 255, .82); word-break: break-all; }
.uc-shell .uc-banner-who .uc-banner-meta { display: block; margin-top: 6px; font-size: 12px; color: rgba(255, 255, 255, .65); }
.uc-shell .uc-banner-meta-box { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; text-align: right; }
.uc-shell .uc-banner-badge { font-size: 14px; font-weight: 700; }
.uc-shell .uc-banner-uid { font-size: 12px; color: rgba(255, 255, 255, .72); }
.uc-shell .uc-banner-edit {
    margin-top: 6px; padding: 5px 14px;
    border: 1px solid rgba(255, 255, 255, .45);
    border-radius: var(--uc-radius-sm);
    background: rgba(255, 255, 255, .12);
    color: #fff; font-size: 12px; font-family: inherit; cursor: pointer;
    transition: background-color .18s ease;
}
.uc-shell .uc-banner-edit:hover { background: rgba(255, 255, 255, .24); }

/* ── 账号总览双栏 ── */
.uc-shell .uc-overview {
    max-width: 1200px;
    display: grid;
    grid-template-columns: 1.12fr .88fr;
    gap: 20px;
    align-items: start;
}
.uc-shell .uc-ov-col-main,
.uc-shell .uc-ov-col-side { min-width: 0; }
.uc-shell .uc-ov-col-main > .uc-overview-sec:first-child,
.uc-shell .uc-ov-col-side > .uc-overview-sec:first-child { margin-top: 0; }
.uc-shell .uc-overview-sec { margin-top: 24px; }
.uc-shell .uc-sec-label { margin: 0 0 12px; }

/* ── 设置行：图标 + 标题 + 描述 + 右侧值 ── */
.uc-shell .uc-set-list { padding: 4px 22px 8px; }
.uc-shell .uc-set-row {
    display: flex; align-items: center; gap: 14px;
    padding: 15px 0;
    border-bottom: 1px solid var(--ng-border-light);
}
.uc-shell .uc-set-row:last-child { border-bottom: 0; }
.uc-shell .uc-set-ico {
    width: 34px; height: 34px; flex: 0 0 auto;
    border-radius: var(--uc-radius-sm);
    background: var(--ng-primary-bg);
    color: var(--ng-primary);
    display: grid; place-items: center; font-size: 16px;
}
.uc-shell .uc-set-copy { flex: 1 1 auto; min-width: 0; }
.uc-shell .uc-set-copy b { display: block; font-size: 13px; font-weight: 600; }
.uc-shell .uc-set-copy span { display: block; margin-top: 2px; font-size: 12px; color: var(--ng-text-muted); }
.uc-shell .uc-set-val { flex: 0 0 auto; max-width: 45%; font-size: 13px; font-weight: 600; text-align: right; word-break: break-all; }

/* ── 右栏：社区与支持 ── */
.uc-shell .uc-support-card { padding: 20px 22px 22px; }
.uc-shell .uc-mini-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.uc-shell .uc-mini-box {
    display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
    padding: 14px; text-decoration: none;
    border: 1px solid var(--ng-border);
    border-radius: var(--uc-radius-sm);
    background: #fbfcfe;
    transition: border-color .18s ease;
}
.uc-shell .uc-mini-box:hover { border-color: var(--ng-primary); }
.uc-shell .uc-mini-ico { font-size: 18px; color: var(--ng-primary); }
.uc-shell .uc-mini-box b { font-size: 13px; font-weight: 600; line-height: 1.5; color: var(--ng-text); }
.uc-shell .uc-mini-link { font-size: 12px; color: var(--ng-primary); font-weight: 600; }
.uc-shell .uc-note-box {
    margin-top: 16px; padding: 14px 16px;
    border: 1px solid #e2e9fb; border-radius: var(--uc-radius-sm);
    background: #f8faff;
}
.uc-shell .uc-note-box b { display: block; font-size: 13px; }
.uc-shell .uc-note-box p { margin: 5px 0 0; font-size: 12px; line-height: 1.7; color: var(--ng-text-muted); }
.uc-shell .uc-support-links { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 16px; }
.uc-shell .uc-support-links .uc-row-op { font-size: 12px; padding-left: 0; padding-right: 0; }
.uc-shell .uc-support-logout {
    display: inline-block; margin-top: 18px; padding: 7px 16px;
    border: 1px solid #f7cdd3; border-radius: var(--uc-radius-sm);
    background: #fff6f7; color: var(--ng-danger);
    font-size: 12px; font-weight: 600; text-decoration: none;
}
.uc-shell .uc-support-logout:hover { background: #ffedef; }

/* ── 授权状态卡：复刻 usage-card ── */
.uc-shell .uc-subcard-bd { display: block; padding: 22px 24px 24px; }
.uc-shell .uc-usage-title { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.uc-shell .uc-usage-title h3 { margin: 0; font-size: 15px; font-weight: 700; }
.uc-shell .uc-usage-hint { margin: 4px 0 0; font-size: 12px; color: var(--ng-text-muted); }
.uc-shell .uc-usage-title .uc-sub-badge { flex: 0 0 auto; }
.uc-shell .uc-sub-time { margin: 18px 0 4px; font-size: 40px; letter-spacing: -1px; line-height: 1.1; color: var(--ng-primary); }
.uc-shell .uc-sub-time span { margin-left: 5px; font-size: 15px; font-weight: 600; color: var(--ng-text-muted); }
.uc-shell .uc-sub-track { height: 8px; border-radius: 99px; background: #edf1f6; margin: 14px 0 10px; overflow: hidden; }
.uc-shell .uc-sub-track i { border-radius: 99px; background: var(--ng-gradient); }
.uc-shell .uc-sub-details { flex-direction: row; justify-content: space-between; gap: 12px; font-size: 12px; }
.uc-shell .uc-sub-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; }
.uc-shell .uc-sub-actions .btn-secondary { border-radius: var(--uc-radius-sm); }
.uc-shell .uc-sub-note { margin: 12px 0 0; }
/* 骨架里的按钮占位：保证 Ajax 替换前后按钮行不跳版 */
.uc-shell .uc-sk-btn {
    display: inline-block; width: 108px; height: 30px;
    border-radius: var(--uc-radius-sm);
    background: var(--ng-border-light);
}
.uc-shell .uc-subcard--expiring .uc-sub-time { color: #b45309; }
.uc-shell .uc-subcard--inactive .uc-sub-time { color: var(--ng-text-muted); }
.uc-shell .uc-subcard--expiring .uc-sub-track i { background: #f59e0b; }
.uc-shell .uc-subcard--inactive .uc-sub-track i { background: var(--ng-border); }

/* ── 窄屏 ── */
@media (max-width: 991.98px) {
    .uc-shell .uc-overview { grid-template-columns: 1fr; }
    .uc-shell .uc-main { padding: 20px 18px 56px; }
    .uc-shell .uc-banner { padding: 22px 20px; }
}
@media (max-width: 767.98px) {
    .uc-shell .uc-banner { flex-direction: column; align-items: flex-start; }
    .uc-shell .uc-banner-meta-box { align-items: flex-start; text-align: left; }
    .uc-shell .uc-mini-grid { grid-template-columns: 1fr; }
    .uc-shell .uc-subcard-bd { padding: 18px; }
    .uc-shell .uc-sub-time { font-size: 34px; }
    .uc-shell .uc-set-list { padding-left: 16px; padding-right: 16px; }
}
