@charset "utf-8";
/* ==========================================================================
   ResDown - resource marketplace theme for Emlog Pro
   Part 1 / tokens, reset, layout, header, nav, buttons, forms, cards, footer
   ========================================================================== */

:root {
    --rd-primary: #3355ff;
    --rd-primary-2: #7b3fe4;
    --rd-primary-soft: #eef1ff;
    --rd-accent: #0ea5e9;
    --rd-gold: #f59e0b;
    --rd-gold-soft: #fff7e6;
    --rd-green: #10b981;
    --rd-red: #ef4444;
    --rd-bg: #f5f6fa;
    --rd-surface: #ffffff;
    --rd-surface-2: #fafbfe;
    /* 区块色带：比页面底色略深一档，用来把首页「热门资源」这类区块从底上「抬」起来，
       形成整屏横向的分隔。用底色本身（#f5f6fa）当色带是看不出边界的，
       用白色又会让带内的白卡片糊成一片，所以另开一个变量。 */
    --rd-band: #eceff8;
    --rd-text: #1b2234;
    --rd-text-2: #4d5569;
    --rd-muted: #8b93a7;
    --rd-border: #e8eaf2;
    --rd-border-2: #dfe3ef;
    --rd-shadow-sm: 0 1px 2px rgba(24, 33, 61, .05);
    --rd-shadow: 0 6px 20px -8px rgba(24, 33, 61, .14);
    --rd-shadow-lg: 0 20px 48px -20px rgba(24, 33, 61, .28);
    --rd-radius-sm: 8px;
    --rd-radius: 14px;
    --rd-radius-lg: 20px;
    --rd-radius-pill: 999px;
    --rd-header-h: 68px;
    /* 内容区总宽。与「一方主题」演示站（jybk.cc）实测对照：
       那一站内容区 1280px、卡片 303.5px、列间距 22px；本站原来 1240px、卡片 288px、
       间距 18px，同屏比过去明显「局促」。现在取 1340px（内容区 1300px），
       卡片落到 308.5px —— 比参考站还宽一点，正好对上「做宽一些」。
       ⚠️ 改这个值只需要改这一处：.rd-bleed 的 margin-left: calc(50% - 50vw) 里，
       50% 取的是容器内容盒的一半，(vw-max)/2 + pad + (max-2pad)/2 - vw/2 恒等于 0，
       跟 max 和 pad 的具体取值无关，所以通栏区块不会因为改宽而错位。 */
    --rd-max: 1340px;
    /* .rd-main 的上内边距。首页通栏头图要把这个空隙消掉（否则头图上方会留一条
       浅色边），消法是用负外边距抵掉它，所以必须能在这里改一处、两处同步。
       硬编码 -24px 的话，哪天把这里的 24 调成 16，头图就会把上面的内容盖住。 */
    --rd-main-pt: 24px;
    --rd-font: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif;
    --rd-grad: linear-gradient(120deg, var(--rd-primary) 0%, var(--rd-primary-2) 100%);
}

html[data-theme="dark"] {
    --rd-primary-soft: #1e2547;
    --rd-gold-soft: #2e2616;
    --rd-bg: #0e1119;
    --rd-surface: #161a26;
    --rd-surface-2: #1b2030;
    --rd-band: #121724;
    --rd-text: #eef1f8;
    --rd-text-2: #c2c9db;
    --rd-muted: #8a93aa;
    --rd-border: #262c3d;
    --rd-border-2: #2e3549;
    --rd-shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --rd-shadow: 0 6px 20px -8px rgba(0, 0, 0, .6);
    --rd-shadow-lg: 0 20px 48px -20px rgba(0, 0, 0, .8);
}

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

/* hidden 属性必须真的能藏住东西。
   浏览器默认的 [hidden]{display:none} 来自 UA 样式表，优先级低于作者样式 ——
   只要元素自己带了 display（.rd-btn 是 inline-flex、.rd-pager 是 flex），
   hidden 就会静默失效：元素照样显示，JS 里那句 el.hidden = true 看着执行了，
   界面上却什么都没变。这里统一兜住，省得每处都要写一遍 !important 级别的覆盖。 */
[hidden] {
    display: none !important;
}

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

body {
    margin: 0;
    font-family: var(--rd-font);
    /* 16px（原 15px）：与参考站一致。正文小一号会让整页在同屏对比里显得
       「什么都比人家小一圈」，这是「差距好大」的观感来源之一。 */
    font-size: 16px;
    line-height: 1.7;
    color: var(--rd-text);
    background: var(--rd-bg);
    -webkit-font-smoothing: antialiased;
}

img {
    max-width: 100%;
    height: auto;
    border: 0;
    vertical-align: middle;
}

a {
    color: inherit;
    text-decoration: none;
    transition: color .18s ease, opacity .18s ease;
}

a:hover {
    color: var(--rd-primary);
}

h1,
h2,
h3,
h4,
h5 {
    margin: 0 0 .5em;
    font-weight: 700;
    line-height: 1.35;
    color: var(--rd-text);
}

h1 {
    font-size: 26px;
}

h2 {
    font-size: 21px;
}

h3 {
    font-size: 17px;
}

p {
    margin: 0 0 1em;
}

ul,
ol {
    margin: 0;
    padding: 0;
    list-style: none;
}

button,
input,
select,
textarea {
    font: inherit;
    color: inherit;
}

hr {
    border: 0;
    border-top: 1px solid var(--rd-border);
    margin: 18px 0;
}

code,
pre {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13.5px;
}

pre {
    background: var(--rd-surface-2);
    border: 1px solid var(--rd-border);
    border-radius: var(--rd-radius-sm);
    padding: 14px;
    overflow: auto;
}

::selection {
    background: rgba(51, 85, 255, .18);
}

.rd-container {
    width: 100%;
    max-width: var(--rd-max);
    margin: 0 auto;
    padding: 0 20px;
}

.rd-main {
    padding: var(--rd-main-pt) 0 56px;
    /* 通栏区块（首页头图等）用 width:100vw 跳出 .rd-container 的 1240px 限制，
       而 100vw 把纵向滚动条的宽度也算进去了（桌面 Windows 上约 15px），
       于是会比可视区宽出一点点，横着溢出。
       这里用 clip 而不是 hidden 收掉它：hidden 会把 .rd-main 变成滚动容器，
       改变内部 position:sticky 元素的吸附参照；clip 明确不建立滚动容器。
       头图左右各有几十像素内边距，被裁掉的那几像素落在背景上，看不出来。 */
    overflow-x: clip;
}

/* ============================ 通栏 / 色带 ============================
   一对工具类，首页「整屏横向分隔」全靠它们：

   .rd-bleed    让一个区块跳出 .rd-container 的 1340px 限制，铺满整屏宽。
                算式是 margin-left: calc(50% - 50vw)：这里的 50% 取的是**父级
                内容盒**的一半，而 .rd-container 是「width:100% + 左右各 20px 内边距」，
                所以它的内容盒左边缘永远落在视口左边 20px 处（窄屏）或
                (vw-1340)/2+20 处（宽屏）。两处相减都恰好归零，头图左边缘就压在 0 上。
                换成 `left: 50%; transform: translateX(-50%)` 也能做到，但那会让
                元素脱离文档流，后面的内容要另外补高度，得不偿失。

   .rd-bleed-in 给通栏区块里的内容重新套回 1340px 与 20px 内边距，
                让「通栏的是背景、不脱轨的是文字」。 */
.rd-bleed {
    width: 100vw;
    margin-left: calc(50% - 50vw);
}

.rd-bleed-in {
    max-width: var(--rd-max);
    margin-left: auto;
    margin-right: auto;
    padding-left: 20px;
    padding-right: 20px;
}

/* 色带：整屏宽的一条底色分段。上下各一条发丝线，让它在深色头图与浅色页面之间
   有一道明确的「起止」，而不是靠颜色深浅变化让人猜边界在哪。 */
.rd-band {
    width: 100vw;
    margin-left: calc(50% - 50vw);
    padding: 34px 0;
}

.rd-band.is-tint {
    background: var(--rd-band);
    border-top: 1px solid var(--rd-border);
    border-bottom: 1px solid var(--rd-border);
}

/* 色带内最后一块的 .rd-section 自带 30px 下外边距，会和色带的 34px 下内边距叠加，
   变成 64px 的空档 —— 色带看着就「下重上轻」。这里抵掉它。 */
.rd-band .rd-bleed-in>.rd-section:last-child {
    margin-bottom: 0;
}

.rd-row {
    display: flex;
    gap: 22px;
    align-items: flex-start;
}

.rd-col-main {
    flex: 1 1 auto;
    min-width: 0;
}

.rd-col-side {
    /* 340px（原 320px）：侧栏要装「热门资源 / 最新上架 / 分类 / 标签云 / 站点统计」
       这些带缩略图的模块，320px 下两行标题会被压到逐字折行。 */
    width: 340px;
    flex: 0 0 340px;
}

.rd-hide {
    display: none !important;
}

.rd-only-mobile {
    display: none !important;
}

.rd-muted {
    color: var(--rd-muted);
}

.rd-ellipsis {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rd-clamp-1,
.rd-clamp-2,
.rd-clamp-3 {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.rd-clamp-1 {
    -webkit-line-clamp: 1;
}

.rd-clamp-2 {
    -webkit-line-clamp: 2;
}

.rd-clamp-3 {
    -webkit-line-clamp: 3;
}

/* ============================ buttons ============================ */

.rd-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 40px;
    padding: 0 18px;
    border: 1px solid transparent;
    border-radius: var(--rd-radius-pill);
    background: var(--rd-surface);
    color: var(--rd-text);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: all .18s ease;
}

.rd-btn:hover {
    transform: translateY(-1px);
    color: var(--rd-text);
    box-shadow: var(--rd-shadow);
}

.rd-btn:active {
    transform: translateY(0);
}

.rd-btn-primary {
    background: var(--rd-grad);
    color: #fff;
    box-shadow: 0 8px 18px -10px rgba(51, 85, 255, .9);
}

.rd-btn-primary:hover {
    color: #fff;
}

.rd-btn-gold {
    background: linear-gradient(120deg, #f7b733 0%, #f59e0b 100%);
    color: #4a2c00;
}

.rd-btn-gold:hover {
    color: #4a2c00;
}

.rd-btn-ghost {
    background: transparent;
    border-color: var(--rd-border-2);
    color: var(--rd-text-2);
}

.rd-btn-block {
    width: 100%;
}

.rd-btn-lg {
    height: 48px;
    font-size: 16px;
    padding: 0 26px;
}

.rd-btn-sm {
    height: 32px;
    font-size: 13px;
    padding: 0 14px;
}

/* 禁用 / 不可用状态：不能只靠降不透明度。
   主色渐变、金色渐变在 55% 不透明度下依然像「可点」，点了没反应会被当成故障。
   这里统一降级为中性填充，并用 :hover 变体盖掉各按钮在悬停时设的颜色。 */
.rd-btn[disabled],
.rd-btn.is-disabled,
.rd-btn[disabled]:hover,
.rd-btn.is-disabled:hover {
    opacity: 1;
    background: var(--rd-surface-2);
    background-image: none;
    color: var(--rd-muted);
    border-color: var(--rd-border);
    cursor: not-allowed;
    transform: none !important;
    box-shadow: none !important;
}

/* ============================ badges ============================ */

.rd-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 22px;
    padding: 0 9px;
    border-radius: var(--rd-radius-pill);
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
}

.rd-badge-free {
    background: rgba(16, 185, 129, .12);
    color: var(--rd-green);
}

.rd-badge-vip {
    background: var(--rd-gold-soft);
    color: #b45309;
}

.rd-badge-paid {
    background: var(--rd-primary-soft);
    color: var(--rd-primary);
}

.rd-badge-login {
    background: rgba(14, 165, 233, .12);
    color: var(--rd-accent);
}

.rd-badge-plain {
    background: var(--rd-surface-2);
    color: var(--rd-muted);
}

/* 「还没上传文件」用的角标。
   刻意不复用 .rd-badge-vip：那条是金色、语义是「会员」，借来当占位角标，
   以后调会员配色就会连带把这里改歪，而且同一张卡上可能出现两个金色角标分不清。 */
.rd-badge-pending {
    background: var(--rd-gold-soft);
    color: #b45309;
}

.rd-price {
    color: var(--rd-red);
    font-weight: 800;
}

.rd-price-cur {
    font-size: 13px;
    margin-right: 1px;
}

html[data-theme="dark"] .rd-price {
    color: #ff7a7a;
}

/* ============================ forms ============================ */

.rd-input,
.rd-select,
.rd-textarea {
    width: 100%;
    min-height: 42px;
    padding: 9px 13px;
    border: 1px solid var(--rd-border-2);
    border-radius: var(--rd-radius-sm);
    background: var(--rd-surface);
    color: var(--rd-text);
    outline: none;
    transition: border-color .18s ease, box-shadow .18s ease;
}

.rd-textarea {
    min-height: 110px;
    resize: vertical;
    line-height: 1.7;
}

.rd-input:focus,
.rd-select:focus,
.rd-textarea:focus {
    border-color: var(--rd-primary);
    box-shadow: 0 0 0 3px rgba(51, 85, 255, .14);
}

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

.rd-label {
    display: block;
    margin-bottom: 6px;
    font-size: 13px;
    font-weight: 600;
    color: var(--rd-text-2);
}

.rd-help {
    margin-top: 5px;
    font-size: 12px;
    color: var(--rd-muted);
}

.rd-check {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    color: var(--rd-text-2);
    cursor: pointer;
}

.rd-check input {
    width: 15px;
    height: 15px;
    accent-color: var(--rd-primary);
}

/* ============================ header ============================ */

.rd-header {
    position: sticky;
    top: 0;
    z-index: 900;
    background: rgba(255, 255, 255, .86);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-bottom: 1px solid var(--rd-border);
}

/* 顶部 3px 品牌渐变线：整个站点唯一的「贯穿性」渐变，成本极低但辨识度很高 */
.rd-header::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 3px;
    background: var(--rd-grad);
    pointer-events: none;
}

html[data-theme="dark"] .rd-header {
    background: rgba(18, 22, 33, .86);
}

.rd-header-in {
    display: flex;
    align-items: center;
    gap: 18px;
    height: var(--rd-header-h);
}

.rd-logo {
    display: flex;
    align-items: center;
    gap: 9px;
    flex: 0 0 auto;
    font-size: 19px;
    font-weight: 800;
    letter-spacing: -.2px;
}

.rd-logo img {
    max-height: 34px;
    width: auto;
}

.rd-logo-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    background: var(--rd-grad);
    color: #fff;
    font-size: 18px;
    font-weight: 800;
    box-shadow: 0 8px 16px -10px rgba(51, 85, 255, .95);
}

.rd-nav {
    flex: 1 1 auto;
    min-width: 0;
}

.rd-nav>ul {
    display: flex;
    align-items: center;
    gap: 4px;
}

.rd-nav a {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 38px;
    padding: 0 13px;
    border-radius: var(--rd-radius-pill);
    font-size: 14.5px;
    /* 导航是「方位盘」，不是正文。上一轮统一清理多余加粗时把它一起降到了 500，
       结果导航项和正文一样粗、看着不像导航（站长反馈「加粗被去掉了」）——
       这里恢复 600。 */
    font-weight: 600;
    color: var(--rd-text-2);
    white-space: nowrap;
}

/* 悬停与「当前栏目」共用一套视觉：主色文字 + 浅色药丸底。
   鼠标一移开，全场就只剩当前栏目还亮着 —— 这是访客唯一的「我在哪」提示，
   所以它必须由 is-current 驱动（rd_nav() 里输出），不能只靠 :hover。 */
.rd-nav a:hover,
.rd-nav .is-current>a {
    color: var(--rd-primary);
    background: var(--rd-primary-soft);
}

.rd-nav li {
    position: relative;
}

.rd-nav .rd-sub {
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 172px;
    padding: 8px;
    border-radius: var(--rd-radius);
    background: var(--rd-surface);
    border: 1px solid var(--rd-border);
    box-shadow: var(--rd-shadow-lg);
    opacity: 0;
    visibility: hidden;
    transform: translateY(6px);
    transition: all .18s ease;
}

.rd-nav li:hover>.rd-sub {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.rd-nav .rd-sub a {
    display: block;
    height: auto;
    padding: 8px 12px;
    border-radius: var(--rd-radius-sm);
}

.rd-head-tools {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 0 0 auto;
    /* 把「搜索 / 用户 / 菜单」这一整组钉在最右边。
       桌面端 .rd-nav 是 flex:1 1 auto，自己就把剩余空间吃光了，
       这条不起作用（也不会改变什么）；手机端 .rd-nav 被 display:none 摘掉，
       这一组就会紧贴着 Logo 站在偏左的位置 —— 这正是用户反馈的
       「菜单和用户按钮在中间而不是最右侧」。 */
    margin-left: auto;
}

.rd-search-box {
    display: flex;
    align-items: center;
    gap: 6px;
    height: 40px;
    padding: 0 6px 0 14px;
    border: 1px solid var(--rd-border-2);
    border-radius: var(--rd-radius-pill);
    background: var(--rd-surface-2);
}

.rd-search-box input {
    width: 148px;
    border: 0;
    background: transparent;
    outline: none;
    font-size: 14px;
}

.rd-search-box button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: 0;
    border-radius: 50%;
    background: var(--rd-grad);
    color: #fff;
    cursor: pointer;
}

.rd-user-chip {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    padding: 0 12px 0 5px;
    border-radius: var(--rd-radius-pill);
    border: 1px solid var(--rd-border-2);
    background: var(--rd-surface);
    font-size: 13.5px;
    font-weight: 500;
}

.rd-user-chip img {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    object-fit: cover;
}

.rd-user-menu {
    position: relative;
}

.rd-user-menu .rd-sub {
    position: absolute;
    right: 0;
    left: auto;
    top: calc(100% + 8px);
    min-width: 190px;
    padding: 8px;
    border-radius: var(--rd-radius);
    background: var(--rd-surface);
    border: 1px solid var(--rd-border);
    box-shadow: var(--rd-shadow-lg);
    opacity: 0;
    visibility: hidden;
    transform: translateY(6px);
    transition: all .18s ease;
    z-index: 50;
}

.rd-user-menu:hover .rd-sub {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.rd-user-menu .rd-sub a {
    display: block;
    padding: 9px 12px;
    border-radius: var(--rd-radius-sm);
    font-size: 14px;
    color: var(--rd-text-2);
}

.rd-user-menu .rd-sub a:hover {
    background: var(--rd-surface-2);
    color: var(--rd-primary);
}

/* 注意：这里必须是 column。
   历史上这里写的是 display:flex（默认 row），三根 <span> 横条被排成一行并挤在一起，
   手机上汉堡按钮看起来只有「一根横线」，也会被误判成「按钮没做样式」。 */
.rd-nav-toggle {
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    width: 40px;
    height: 40px;
    border: 1px solid var(--rd-border-2);
    border-radius: 12px;
    background: var(--rd-surface);
    cursor: pointer;
}

.rd-nav-toggle span {
    display: block;
    width: 17px;
    height: 2px;
    margin: 0;
    border-radius: 2px;
    background: var(--rd-text);
    transition: transform .22s ease, opacity .18s ease;
}

/* 抽屉打开时汉堡变成「X」，给用户一个明确的可关闭信号 */
.rd-nav-toggle.is-open span:nth-child(1) {
    transform: translateY(6px) rotate(45deg);
}

.rd-nav-toggle.is-open span:nth-child(2) {
    opacity: 0;
}

.rd-nav-toggle.is-open span:nth-child(3) {
    transform: translateY(-6px) rotate(-45deg);
}

/* 移动端导航：从右侧滑入的抽屉。
   必须放在 .rd-header 之外 —— header 上有 backdrop-filter，
   会给 position:fixed 的后代创建包含块，导致抽屉无法相对视口定位。 */
.rd-mobile-nav {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 1200;
    width: min(84vw, 320px);
    padding: 14px 18px 26px;
    background: var(--rd-surface);
    border-left: 1px solid var(--rd-border);
    box-shadow: -18px 0 48px -24px rgba(10, 16, 40, .5);
    overflow-y: auto;
    overscroll-behavior: contain;
    transform: translateX(101%);
    visibility: hidden;
    transition: transform .26s cubic-bezier(.32, .72, .28, 1), visibility .26s;
}

.rd-mobile-nav.is-open {
    transform: translateX(0);
    visibility: visible;
}

.rd-mobile-nav-hd {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 10px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--rd-border);
    font-size: 13px;
    font-weight: 700;
    color: var(--rd-muted);
}

.rd-mobile-nav-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 1px solid var(--rd-border-2);
    border-radius: 10px;
    background: var(--rd-surface-2);
    color: var(--rd-text-2);
    cursor: pointer;
}

.rd-mobile-nav-list {
    margin-bottom: 16px;
}

.rd-mobile-nav-list a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 2px;
    font-size: 15px;
    font-weight: 600;
    border-bottom: 1px solid var(--rd-border);
}

/* 抽屉导航里的「当前栏目」。桌面端有药丸底色，这里只用主色文字 + 再加一档字重：
   抽屉是竖排列表，整行铺底或加竖条都会把行高和左边缘推来推去，
   未选中的行看着就参差不齐。 */
.rd-mobile-nav-list .is-current>a {
    color: var(--rd-primary);
    font-weight: 700;
}

.rd-mobile-nav-list .is-current>a::after {
    opacity: .8;
}

.rd-mobile-nav-list a::after {
    content: "";
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    border-right: 1.8px solid currentColor;
    border-bottom: 1.8px solid currentColor;
    transform: rotate(-45deg);
    opacity: .38;
}

.rd-mobile-nav-acts {
    display: grid;
    gap: 9px;
}

.rd-mobile-nav-acts .rd-btn {
    justify-content: flex-start;
}

/* 抽屉底部四个按钮原先长得一模一样，用户得逐个读字才能找到「退出登录」。
   给它一层弱红描边 + 弱红字，从「去哪儿逛逛」里分出来；
   不做成实心红块 —— 退出不是这一屏的主操作，抢眼会误导。 */
.rd-mobile-nav-acts .rd-btn.is-danger {
    border-color: rgba(239, 68, 68, .34);
    color: var(--rd-red);
}

.rd-mobile-nav-acts .rd-btn.is-danger:hover {
    background: rgba(239, 68, 68, .08);
    color: var(--rd-red);
}

.rd-mobile-nav-scrim {
    position: fixed;
    inset: 0;
    z-index: 1100;
    background: rgba(12, 17, 38, .48);
    opacity: 0;
    visibility: hidden;
    transition: opacity .26s ease, visibility .26s;
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
}

.rd-mobile-nav-scrim.is-open {
    opacity: 1;
    visibility: visible;
}

html.rd-nav-locked,
html.rd-nav-locked body {
    overflow: hidden;
}

/* ============================ cards ============================ */

.rd-card {
    background: var(--rd-surface);
    border: 1px solid var(--rd-border);
    border-radius: var(--rd-radius);
    box-shadow: var(--rd-shadow-sm);
}

.rd-card-hd {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 15px 18px;
    border-bottom: 1px solid var(--rd-border);
}

.rd-card-hd h2,
.rd-card-hd h3 {
    margin: 0;
    font-size: 16.5px;
}

.rd-card-bd {
    padding: 18px;
}

.rd-section {
    margin-bottom: 30px;
}

.rd-section-hd {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 14px;
    margin-bottom: 16px;
}

.rd-section-title {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    min-width: 0;
    margin: 0;
    font-size: 20px;
    /* 800 的字重在中文点阵上会把字撑成一坨黑块，标题一多整页就显得闷。
       降到 700、把字距收紧从 -.2px 放到 0，笔画之间重新透出背景，才「通透」。 */
    font-weight: 700;
    letter-spacing: 0;
    color: var(--rd-text);
}

/* 分区名不允许逐字折行（窄屏时改为把描述挤到下一行） */
.rd-section-name {
    white-space: nowrap;
}

.rd-section-title::before {
    content: "";
    flex: 0 0 4px;
    width: 4px;
    height: 19px;
    border-radius: 3px;
    background: var(--rd-grad);
}

.rd-section-sub {
    font-size: 13px;
    color: var(--rd-muted);
    font-weight: 400;
}

.rd-more {
    flex: 0 0 auto;
    white-space: nowrap;
    font-size: 13.5px;
    color: var(--rd-muted);
    font-weight: 500;
}

.rd-more:hover {
    color: var(--rd-primary);
}

/* resource grid
   列数由 html[data-rd-view] 提供的 --rd-cols 决定：
   xl（大图 3 列）/ grid（标准 4 列）/ list（紧凑单列）。
   这样前台「显示方式」切换只需要改一个属性，不必重写每条网格规则，
   也避免多份 grid-template-columns 在各断点里互相打架。 */

.rd-grid {
    display: grid;
    grid-template-columns: repeat(var(--rd-cols, 4), minmax(0, 1fr));
    /* 22px 与参考站一致（原来 18px）。列间距偏小会让四张卡看着像「挤在一起」，
       加宽容器之后间距也必须跟着放大，否则只是每张卡变大、整体节奏还是紧的。 */
    gap: var(--rd-gap, 22px);
}

/* 固定 3 列：会员套餐、购买流程、权益卡这类「非资源列表」用的网格。
   它们必须写死列数，否则会跟着前台的「显示方式」一起变成单列或大图。 */
.rd-grid-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

html[data-rd-view="xl"] {
    --rd-cols: 3;
    --rd-gap: 22px;
}

html[data-rd-view="grid"] {
    --rd-cols: 4;
}

html[data-rd-view="list"] {
    /* 电脑端默认双列。
       单列时每行卡片横跨整屏（约 1200px），封面与正文之间空出一大片，
       一屏真正能看到的条目反而比 4 列还少；双列才是这个密度该有的样子。
       窄屏在下面的断点里退回单列 —— 那里横向空间本来就不够。 */
    --rd-cols: 2;
}

/* 紧凑列表：封面缩到左侧固定宽度、正文横排，一屏能看到更多条目 */
html[data-rd-view="list"] .rd-item {
    flex-direction: row;
    align-items: stretch;
}

html[data-rd-view="list"] .rd-item-cover {
    flex: 0 0 196px;
    width: 196px;
    aspect-ratio: auto;
}

html[data-rd-view="list"] .rd-item-body {
    padding: 14px 18px;
}

html[data-rd-view="list"] .rd-item-title {
    min-height: 0;
    font-size: 16px;
}

html[data-rd-view="list"] .rd-item-desc {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    min-height: 0;
    margin-bottom: 0;
}

.rd-item {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--rd-surface);
    border: 1px solid var(--rd-border);
    border-radius: var(--rd-radius);
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}

.rd-item:hover {
    transform: translateY(-4px);
    border-color: rgba(51, 85, 255, .35);
    box-shadow: var(--rd-shadow-lg);
}

.rd-item-cover {
    position: relative;
    display: block;
    aspect-ratio: 16 / 10;
    overflow: hidden;
    background: var(--rd-surface-2);
}

.rd-item-cover img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .4s ease;
}

.rd-item:hover .rd-item-cover img {
    transform: scale(1.06);
}

.rd-item-cover-ph {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, #e9edfb, #f3f5fd);
    color: #a9b3d1;
    font-size: 30px;
    font-weight: 800;
    letter-spacing: .06em;
    user-select: none;
}

.rd-item-cover-ph::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: radial-gradient(circle at 22% 18%, rgba(255, 255, 255, .55), transparent 46%);
    pointer-events: none;
}

/* 无封面时的多套渐变底，按资源 ID 轮播，避免整屏灰块 */
.rd-item-cover-ph.rd-ph-1 {
    background: linear-gradient(135deg, #e5e9ff, #f4f6ff);
    color: #6b78c9;
}

.rd-item-cover-ph.rd-ph-2 {
    background: linear-gradient(135deg, #e2f2ff, #f2f9ff);
    color: #4c8dbb;
}

.rd-item-cover-ph.rd-ph-3 {
    background: linear-gradient(135deg, #fff1e0, #fff8ee);
    color: #c1884a;
}

.rd-item-cover-ph.rd-ph-4 {
    background: linear-gradient(135deg, #e3f7f0, #f1fbf7);
    color: #4e9b83;
}

.rd-item-cover-ph.rd-ph-5 {
    background: linear-gradient(135deg, #f2e9ff, #f9f4ff);
    color: #8a68c4;
}

html[data-theme="dark"] .rd-item-cover-ph {
    background: linear-gradient(135deg, #1c2233, #161b2a);
    color: #39405a;
}

html[data-theme="dark"] .rd-item-cover-ph::after {
    background-image: radial-gradient(circle at 22% 18%, rgba(255, 255, 255, .06), transparent 46%);
}

html[data-theme="dark"] .rd-item-cover-ph.rd-ph-1 {
    color: #5a67b0;
}

html[data-theme="dark"] .rd-item-cover-ph.rd-ph-2 {
    color: #3f7ba3;
}

html[data-theme="dark"] .rd-item-cover-ph.rd-ph-3 {
    color: #a9743c;
}

html[data-theme="dark"] .rd-item-cover-ph.rd-ph-4 {
    color: #3f8570;
}

html[data-theme="dark"] .rd-item-cover-ph.rd-ph-5 {
    color: #7a5cae;
}

/* 封面角标（.rd-item-tags）与右上角版本号（.rd-item-ver）的样式已撤掉。
   原因：封面上最多时同时挂着权益徽章、「待补文件」、版本号、价签四样东西，
   而封面本来就小，四周被标签占满、图反而看不清（反馈原话：「四周的各种标签
   把本就不大的封面占用太多了」，并且点名不要版本号）。
   现在封面最多只留底部一个价签 /「会员」小标，纯免费资源则完全干净（见 module.php）。
   「待补文件」改成 .rd-item-pending，挪到标题下方的 meta 行，不再占封面。 */

/* 「还没上传文件」的提示：从封面角标改成 meta 行里的小字。
   放在分类旁边，用金色和普通灰色信息区分开 —— 它是一条要站长动手的待办，
   不该被淹没在灰色小字里。 */
.rd-item-pending {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-left: 8px;
    font-size: 12px;
    font-weight: 500;
    color: #b45309;
    white-space: nowrap;
}

.rd-item-pending .rd-svg {
    width: 12px;
    height: 12px;
    flex: 0 0 12px;
}

html[data-theme="dark"] .rd-item-ver {
    background: rgba(255, 255, 255, .14);
}

.rd-item-price {
    position: absolute;
    right: 10px;
    bottom: 10px;
    z-index: 3;
    display: inline-flex;
    align-items: baseline;
    gap: 1px;
    height: 28px;
    padding: 0 11px;
    border-radius: var(--rd-radius-pill);
    background: rgba(255, 255, 255, .97);
    color: var(--rd-red);
    font-size: 15px;
    font-weight: 800;
    line-height: 28px;
    box-shadow: 0 6px 16px -8px rgba(20, 28, 60, .5);
}

.rd-item-price .rd-cur {
    font-size: 11.5px;
    font-weight: 700;
}

.rd-item-price.is-member {
    color: #b45309;
    font-size: 13px;
}

html[data-theme="dark"] .rd-item-price {
    background: rgba(20, 24, 35, .94);
    color: #ff8b8b;
}

html[data-theme="dark"] .rd-item-price.is-member {
    color: #f0b45c;
}

/* 悬停遮罩与「免费下载 / 立即获取」浮层已移除。
   原因：封面本身就是「点击进详情」的一整块热区，鼠标一放上去再压一层暗色渐变、
   中间浮出一枚蓝色胶囊，等于在同一个位置上摆了两个都指向详情的入口 ——
   信息量为零，只是把封面盖住了。资源状态交给常驻的角标（免费 / 会员专享 /
   待补文件）和价格区去讲，不靠悬停才出现的浮层。 */

/* 无封面占位块：加一道斜向高光，避免整片纯色发闷 */
.rd-item-cover-ph::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(118deg, rgba(255, 255, 255, .5) 0%, rgba(255, 255, 255, 0) 42%);
    pointer-events: none;
}

html[data-theme="dark"] .rd-item-cover-ph::before {
    background: linear-gradient(118deg, rgba(255, 255, 255, .07) 0%, rgba(255, 255, 255, 0) 42%);
}

.rd-item-body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    padding: 13px 15px 15px;
}

.rd-item-title {
    /* flex 只为一件事：让里面的 <a> **拉伸到标题区的高度**（交叉轴 stretch），
       于是「只有一行文字」的标题也有一整块可点区域。
       这替换掉了原来「给 <a> 补 padding、再用负外边距抵消」的做法 ——
       那个做法会把 line-clamp 的裁切线下移、露出下一行的上半截。
       ⚠️ 拉伸的是 <a> 自身的**高度**，不是把内容区撑高让第二行显形：
       clamp 仍然按 1 / 2 行裁切，多出来的只是空白。 */
    display: flex;
    margin: 0 0 7px;
    font-size: 15.5px;
    font-weight: 700;
    line-height: 1.45;
    /* 标题只占一行（见下面 .rd-item-title a 的 line-clamp）。
       min-height 用 1.45em 而不是写死 45px：写死的值 = 原来的两行高度，
       标题收成一行之后会在卡片里留出一条空白带 —— 而在手机上字号会降到
       14.5px，em 跟着字号走，三档断点都不用各写一遍。 */
    min-height: 1.45em;
}

.rd-item-title a {
    flex: 1 1 auto;
    min-width: 0;
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
    /* ⚠️ 这里曾经用「padding: 6px 0 + margin: -6px 0」给单行标题扩大手机端命中区
       （把 21px 的行盒撑到 33px）。那是个陷阱：
       -webkit-line-clamp 的裁切边界在 **padding box 的外沿**，补了 6px 下内边距
       = 把裁切线下移 6px，于是被截掉的第二行会**露出上半截**
       （"PHP 从入门到实战…" 底下挂着一小条残字，正是用户说的「排版乱」）。
       现在不再补内边距：电脑端用鼠标、精度够；手机端见下面 640px 断点 ——
       标题放开到两行，行盒本身就有 39px，命中区反而更大。 */
}

.rd-item:hover .rd-item-title a {
    color: var(--rd-primary);
}

.rd-item-desc {
    /* 摘要也收成一行。原来靠 rd_lead($desc, 60) 截到 60 字、由 min-height: 43px
       留出两行位置 —— 卡片一多，摘要的折行位置各不相同，网格里看着参差不齐。
       改成 clamp 1 之后每张卡的正文高度完全一致（一方主题那种做法）。
       ⚠️ 紧凑列表（data-rd-view="list"）不受影响：那一条更靠前，
       但选择器带 html[data-rd-view="list"]，特异性更高，仍是两行。 */
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin: 0 0 12px;
    font-size: 13px;
    line-height: 1.65;
    color: var(--rd-muted);
    /* 同样跟着字号走：手机端字号会变，em 自动对上 */
    min-height: 1.65em;
}

.rd-item-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: auto;
    padding-top: 11px;
    border-top: 1px dashed var(--rd-border);
    font-size: 12.5px;
    color: var(--rd-muted);
}

.rd-item-meta-l,
.rd-item-meta-r {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.rd-item-meta .rd-cat {
    color: var(--rd-primary);
    font-weight: 400;
    /* 分类名是可点元素，但纯文字行盒只有 20px 高 —— 手机上很难按准。
       补上内边距与极淡底色后到 28px，同时也更像「标签」而不是正文。
       负的 margin-left 抵消左侧内边距，让它与上方标题仍然对齐。 */
    padding: 3px 10px;
    margin-left: 0;
    border-radius: var(--rd-radius-pill);
    background: var(--rd-primary-soft);
}

.rd-item-meta .rd-item-sales {
    color: var(--rd-text-2);
    font-weight: 400;
}

.rd-item-meta span {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.rd-svg {
    width: 14px;
    height: 14px;
    flex: 0 0 14px;
}

/* compact list rows：侧栏排行行（编号 + 标题）用的就是下面这两个类。 */

/* ⚠️ 这里原有三个类已经删掉，不是留着不用：
   · .rd-list-row / .rd-list-title —— 「带缩略图的紧凑列表行」的遗留，
     全项目已经没有任何模板在用（连探针里的选择器都指向不存在的东西）；
   · .rd-list-thumb（74×48 缩略图）—— 唯一使用者是 module.php 的
     rd_side_rank_rows()，随本轮「侧栏只留编号 + 标题」一起下线。
   .rd-list-idx 保留：侧栏排行行的序号仍在用它，尺寸在 pages.css 里
   被 .rd-rank-row .rd-list-idx 覆盖成 20px。 */

.rd-list-idx {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 22px;
    height: 22px;
    border-radius: 7px;
    background: var(--rd-surface-2);
    color: var(--rd-muted);
    font-size: 12px;
    font-weight: 800;
}

.rd-list-idx.is-top {
    background: var(--rd-grad);
    color: #fff;
}

/* ============================ footer ============================ */

.rd-links {
    padding: 18px 20px;
    background: var(--rd-surface);
    border: 1px solid var(--rd-border);
    border-radius: var(--rd-radius);
    margin-bottom: 18px;
}

.rd-links-hd {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
    font-size: 14px;
    font-weight: 700;
}

.rd-links-hd::before {
    content: "";
    width: 4px;
    height: 15px;
    border-radius: 3px;
    background: var(--rd-grad);
}

.rd-links ul {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.rd-links a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border-radius: var(--rd-radius-pill);
    background: var(--rd-surface-2);
    border: 1px solid var(--rd-border);
    font-size: 13px;
    color: var(--rd-text-2);
}

.rd-links a:hover {
    border-color: var(--rd-primary);
    color: var(--rd-primary);
}

.rd-links a img {
    width: 16px;
    height: 16px;
    border-radius: 4px;
}

/* 下内边距 164px 不是随手给的：右下角悬浮工具条是 position:fixed、
   贴视口底 24px、竖排三枚 38px 按钮 + 6px 间距 = 126px 高，
   也就是说「滚到最底时」它占掉视口底部往上 150px 的一条带。
   版权行必须整体躲在它上面：150 + 14 余量 = 164。
   ⚠️ 改 .rd-tool 的尺寸 / gap / bottom，或改按钮个数，这个数都要一起改
   （三者相加就是那条带的高度）。 */
.rd-footer {
    margin-top: 8px;
    padding: 20px 0 20px;
    /* ⚠️ 这一行不是冗余，别当成重复声明删掉：
       右下角悬浮工具条是 position: fixed（高 126px、距视口底 24px），
       滚到页底时会把版权行压住。整条占 126 + 24 = 150px，
       这里留 164px（150 + 14 余量）把版权行顶到它上方。
       改工具条的尺寸/位置时，**这三个数必须一起改**：
       `.rd-toolbar` 的 bottom、这里、以及 ≤900 段那一处。
       判据：.workbuddy/tools/probe-layout.js「版权行在工具条上方」。 */
    padding-bottom: 164px;
    background: var(--rd-surface);
    border-top: 1px solid var(--rd-border);
}

/* 品牌 + N 个链接组。
   列数**跟着实际有内容的组数走**（模板按组数输出 .is-1 / .is-2 / .is-3）：
   站长在后台把某一组的链接全删光时，不该剩下一个空列 ——
   原来写死 1.5fr 1fr 1fr 1fr，关掉一组就会看到右边空出一格，
   跟「手机端页脚错位」是同一类观感问题。
   兜底（没有 .is-N 类时）按一组处理，宁可窄也不要留空列。 */
.rd-footer-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
    gap: 30px 34px;
}

.rd-footer-grid.is-2 {
    grid-template-columns: minmax(0, 1.5fr) repeat(2, minmax(0, 1fr));
}

.rd-footer-grid.is-3 {
    grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
}

/* 三组链接全关掉时只剩品牌区，让它独占一行 ——
   否则品牌区只占 1.5/2.5 的宽度，右边留一条说不出理由的空白。 */
.rd-footer-grid.is-0 {
    grid-template-columns: minmax(0, 1fr);
}

/* 只剩一组链接时补一条 —— 缺了它会退回上面那条默认的两列轨道，
   一组内容只占一格，右边空出一整格。 */
.rd-footer-grid.is-1 {
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
}

/* 三组链接 + 客服区同时开着时的四列版本 */
.rd-footer-grid.is-4 {
    grid-template-columns: minmax(0, 1.5fr) repeat(4, minmax(0, 1fr));
}

/* ---------- 页脚 · 客服区 ----------
   .is-N 里的 N = 页脚实际有几列内容（链接组按非空组数算，客服区开着时也算一列）。
   grid 的轨道是写死的：多一个子元素**不会**自动多出一条轨道，
   所以客服区开着（.has-srv）的每一档都得单独写一遍。
   漏掉一档，那一档会退回默认两列 —— 多出来的内容被挤到第二行、
   右边空一整格，正是「页脚错位」最典型的长相。 */

@media (min-width: 901px) {
    /* 客服列比链接列宽一些：二维码要占一个实心方块，
       1fr 在 1024 宽的屏上只有约 150px，两张二维码并排会挤到折行。 */
    .rd-footer-grid.is-1.has-srv {
        grid-template-columns: minmax(0, 1.5fr) minmax(0, 1.25fr);
    }

    .rd-footer-grid.is-2.has-srv {
        grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1.25fr);
    }

    .rd-footer-grid.is-3.has-srv {
        grid-template-columns: minmax(0, 1.5fr) repeat(2, minmax(0, 1fr)) minmax(0, 1.25fr);
    }

    .rd-footer-grid.is-4.has-srv {
        grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr)) minmax(0, 1.25fr);
    }
}

/* 641~900px：页脚是「品牌独占一行 + 链接组按列数排」。
   客服区在这个区间不显示（见下面的 ≤900 段），但 .is-N 里的 N 仍然把它算了一列，
   所以这里要把链接组的列数减回来，否则最后一行的右边会空出一整格。 */
@media (min-width: 641px) and (max-width: 900px) {
    .rd-footer-grid.is-2.has-srv {
        grid-template-columns: minmax(0, 1fr);
    }

    .rd-footer-grid.is-3.has-srv {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .rd-footer-grid.is-4.has-srv {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

/* 客服区只在电脑端出现。
   手机上页脚本来就被压成一条可换行的链接带（约 76px），再塞进两张二维码
   会把它拉回 600px 以上 —— 那正是「每翻一页都要先滚过一整屏重复内容」的老毛病。
   手机上要联系客服，走页脚已有的「售后工单」，或侧栏的「二维码」模块。 */
@media (max-width: 900px) {
    .rd-footer-srv {
        display: none;
    }
}

.rd-footer-srv {
    min-width: 0;
}

.rd-srv-list {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 14px 16px;
}

/* 二维码：图在上、名称在下 */
.rd-srv-qr {
    margin: 0;
}

.rd-srv-qr img {
    display: block;
    width: 84px;
    height: 84px;
    object-fit: contain;
    border-radius: var(--rd-radius-sm);
    /* 二维码要求「深色码点 + 白色底」，微信码本身几乎都是白底，
       但站长传了透明 PNG 时这里必须给白底，否则浅色主题下会糊成一片。 */
    background: #fff;
    padding: 4px;
    border: 1px solid var(--rd-border);
}

.rd-srv-qr figcaption {
    margin-top: 7px;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--rd-muted);
    text-align: center;
}

/* QQ 客服：一条可点的横条。
   强制占满一行 —— 和二维码挤在同一行时它比二维码矮一截（二维码下面还有名称），
   顶端对齐会看着「飘」在半空；单独一行也更好点。 */
.rd-srv-qq {
    display: inline-flex;
    flex: 0 0 100%;
    align-items: center;
    gap: 7px;
    height: 34px;
    padding: 0 13px;
    border-radius: var(--rd-radius-pill);
    border: 1px solid var(--rd-border);
    font-size: 13px;
    font-weight: 600;
    color: var(--rd-text-2);
}

.rd-srv-qq:hover {
    color: var(--rd-primary);
    border-color: var(--rd-primary);
    background: var(--rd-primary-soft);
}

/* 图标用主色点一下：整条白底 + 灰字 + 细边框，不加这一点的话
   它和输入框长得一模一样，没人会去点。 */
.rd-srv-qq .rd-srv-ico {
    width: 15px;
    height: 15px;
    flex: 0 0 15px;
    color: var(--rd-primary);
}

/* 品牌区：Logo 与简介之间固定 12px（原先写在这两个元素的行内样式上，
   行内样式会被媒体查询里的规则压不住，挪到这里统一管）。 */
.rd-footer .rd-logo {
    margin-bottom: 12px;
}

/* 页脚链接区包一层容器，但桌面端必须「不存在」——
   display:contents 让它不产生盒子，里面三组仍然是 .rd-footer-grid 的直接列，
   所以上面的 1.6fr 1fr 1fr 1fr 依旧是「品牌 + 三个链接组」四列。
   只有手机端它才变成真正的 flex 容器（见 ≤640 的媒体查询）。
   别把这条删掉去「简化结构」：删了之后桌面端会变成
   「品牌 | 一个占满剩余宽度的容器」，三个组挤在一起。 */
.rd-footer-nav {
    display: contents;
}

/* 组标题压到 14px：15px 的标题和 13.5px 的链接只差 1.5px，
   三列并排时整片看起来是一样粗细的文字，分不出「这是标题、那是链接」。
   靠 14px + 字色带到正文色（链接仍是 muted）拉开层级。 */
.rd-footer h4 {
    margin: 0 0 14px;
    font-size: 14px;
    color: var(--rd-text);
    letter-spacing: .2px;
}

.rd-footer-links li {
    margin-bottom: 9px;
}

.rd-footer-links a {
    display: inline-block;
    font-size: 13.5px;
    color: var(--rd-muted);
    transition: color .16s ease, transform .16s ease;
}

.rd-footer-links a:hover {
    color: var(--rd-primary);
    transform: translateX(2px);
}

.rd-footer-about {
    max-width: 300px;
    font-size: 13.5px;
    color: var(--rd-muted);
    line-height: 1.8;
}

.rd-footer-about+.rd-footer-about {
    margin-top: 8px;
}

/* 版权行。左右两组都以容器内容盒的两端为准 ——
   这里**不加任何横向内边距**。上一版为了让文字躲开右下角工具条，
   给整行加了 padding-right:56px，结果在 769~900px 之间版权行比它上面的
   链接网格窄了 56px，肉眼就是「最底部错位」。躲工具条要靠**纵向留白**
   （见 .rd-footer 的下内边距），不能靠把整行挤窄。 */
.rd-copy {
    margin-top: 26px;
    padding-top: 18px;
    border-top: 1px solid var(--rd-border);
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    align-items: center;
    justify-content: space-between;
    font-size: 13px;
    color: var(--rd-muted);
}

/* 左段是一句连续的话（ICP · 版权 · Powered by），按普通文字流换行，
   不拆成多个 flex 项 —— 拆了的话「·」会独自留在行尾。 */
.rd-copy-main .rd-dot {
    margin: 0 6px;
    color: var(--rd-border);
}

.rd-copy-main .rd-powered {
    white-space: nowrap;
}

/* 版权行里的链接同样要够手指点：13px 的纯文字行盒只有 17px 高 */
.rd-copy a {
    display: inline-block;
    padding: 6px 0;
}

.rd-copy a:hover {
    color: var(--rd-primary);
}

.rd-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}

.rd-stats b {
    color: var(--rd-primary);
    font-weight: 800;
}

/* toolbar */

/* 悬浮工具条：**竖排一列**（恢复原样）。
   中间的插曲：竖排时 3 个按钮高 126px，而它贴在视口底部上方 24px，
   滚到页面最底时正好压住页脚版权行右端那组统计数字 ——
   当时的处置是「把它改成横排」，观感一下就变了，不像原来那个悬浮选单。
   现在回到竖排，改用**页脚留白**避让：整条 126px + bottom 24px = 顶端距视口底
   150px，页脚下内边距给到 164px（150 + 14 余量，见 .rd-footer）。
   两条路都试过，结论是「纵向留白」比「横向躲开」正确 ——
   横向躲开会把版权行撑得比上面的网格窄一截，那就是之前反映的「最底部错位」。 */
.rd-toolbar {
    position: fixed;
    right: 20px;
    /* ⚠️ 这个 24px 是「页脚下内边距 164px」的一半依据（126 + 24 + 14 = 164），
       见 .rd-footer 的说明。R20 曾被改成 80px，页脚没跟着加，于是滚到页底时
       工具条把版权行压住了（probe-layout 报 9 条 FAIL）。改这里必须同时改页脚。 */
    bottom: 24px;
    z-index: 800;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.rd-tool {
    display: flex;
    align-items: center;
    justify-content: center;
    /* 38 而不是 42：竖排三枚就是 126px 高，页脚要留的空白直接跟着涨，
       缩这 4px 能少留 12px 空白 —— 页脚底部那一大片空地能省则省。 */
    width: 38px;
    height: 38px;
    border-radius: 12px;
    background: var(--rd-surface);
    border: 1px solid var(--rd-border);
    box-shadow: var(--rd-shadow);
    color: var(--rd-text-2);
    cursor: pointer;
    transition: all .18s ease;
}

.rd-tool:hover {
    color: var(--rd-primary);
    transform: translateY(-2px);
}

.rd-tool svg {
    width: 19px;
    height: 19px;
}

/* 深浅色按钮：浅色下显示月亮，深色下显示太阳 */
.rd-ico-light,
.rd-ico-dark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.rd-ico-dark {
    display: none;
}

html[data-theme="dark"] .rd-ico-light {
    display: none;
}

html[data-theme="dark"] .rd-ico-dark {
    display: inline-flex;
}

/* 列表「显示方式」：收起态就是浮动工具栏里的一个按钮，悬停 / 键盘聚焦 / 点击
   （触屏）才向左展开三档，避免常驻一条工具栏位置。
   按钮上的图标跟着当前档位走 —— 三个图标都输出，由 html[data-rd-view] 决定显示
   哪个，纯 CSS 决定，首屏不会出现「图标还指着旧档位」。
   元素挂在 footer 的 .rd-toolbar 里，必须在 <main> 之外：header 上的
   backdrop-filter 会给 position:fixed 的后代创建包含块。 */
.rd-viewsw {
    position: relative;
}

.rd-viewsw-ico {
    display: none;
    align-items: center;
    justify-content: center;
}

html[data-rd-view="xl"] .rd-viewsw-ico-xl,
html[data-rd-view="grid"] .rd-viewsw-ico-grid,
html[data-rd-view="list"] .rd-viewsw-ico-list {
    display: inline-flex;
}

.rd-viewsw-menu {
    position: absolute;
    right: 100%;
    top: 50%;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 2px;
    margin-right: 8px;
    padding: 3px;
    border: 1px solid var(--rd-border);
    border-radius: var(--rd-radius-pill);
    background: var(--rd-surface);
    box-shadow: var(--rd-shadow);
    white-space: nowrap;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translate(10px, -50%);
    transition: opacity .18s ease, transform .18s ease, visibility .18s ease;
}

/* 按钮与菜单之间那 8px 空隙得由伪元素兜住：否则鼠标从按钮移向菜单的途中会
   「离开」.rd-viewsw，菜单在手指到达前就收起了，等于点不动。 */
.rd-viewsw-menu::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    right: -8px;
    width: 8px;
}

.rd-viewsw.is-open .rd-viewsw-menu,
.rd-viewsw:hover .rd-viewsw-menu,
.rd-viewsw:focus-within .rd-viewsw-menu {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translate(0, -50%);
}

.rd-viewsw-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 30px;
    padding: 0 11px;
    border: 0;
    border-radius: var(--rd-radius-pill);
    background: transparent;
    color: var(--rd-text-2);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 500;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    transition: background .18s ease, color .18s ease;
}

.rd-viewsw-btn .rd-svg {
    width: 15px;
    height: 15px;
}

.rd-viewsw-btn:hover {
    color: var(--rd-text);
    background: var(--rd-surface-2);
}

.rd-viewsw-btn.is-active {
    background: var(--rd-primary-soft);
    color: var(--rd-primary);
}

/* 窄屏：展开态只留三个图标，免得横着铺太长 */
@media (max-width: 640px) {
    .rd-viewsw-btn span {
        display: none;
    }

    .rd-viewsw-btn {
        padding: 0 10px;
    }
}

/* pagination */

.rd-pager {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 7px;
    margin: 26px 0 6px;
}

.rd-pager a,
.rd-pager span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 38px;
    height: 38px;
    padding: 0 12px;
    border-radius: 11px;
    border: 1px solid var(--rd-border);
    background: var(--rd-surface);
    font-size: 14px;
    font-weight: 500;
    color: var(--rd-text-2);
}

.rd-pager a:hover {
    border-color: var(--rd-primary);
    color: var(--rd-primary);
}

.rd-pager .is-active {
    background: var(--rd-grad);
    border-color: transparent;
    color: #fff;
}

.rd-pager .is-disabled {
    opacity: .45;
    cursor: not-allowed;
}

/* empty state */

.rd-empty {
    padding: 46px 20px;
    text-align: center;
    color: var(--rd-muted);
}

.rd-empty-ico {
    font-size: 34px;
    margin-bottom: 8px;
    opacity: .5;
}

/* toast */

.rd-toast-wrap {
    position: fixed;
    top: 84px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 3000;
    display: flex;
    flex-direction: column;
    gap: 9px;
    pointer-events: none;
}

.rd-toast {
    min-width: 180px;
    max-width: 340px;
    padding: 10px 16px;
    border-radius: var(--rd-radius-pill);
    background: rgba(24, 30, 45, .93);
    color: #fff;
    font-size: 14px;
    text-align: center;
    box-shadow: var(--rd-shadow-lg);
    animation: rdToastIn .24s ease;
}

.rd-toast.is-ok {
    background: rgba(16, 150, 110, .95);
}

.rd-toast.is-err {
    background: rgba(206, 60, 60, .95);
}

@keyframes rdToastIn {
    from {
        opacity: 0;
        transform: translateY(-8px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ============================ responsive ============================ */

@media (max-width: 1080px) {
    .rd-search-box input {
        width: 110px;
    }

    .rd-col-side {
        width: 288px;
        flex: 0 0 288px;
    }

    /* 这里只改列数变量，不直接写 grid-template-columns：
       直接写会盖掉用户在「显示方式」里选的密度，切换按钮就白点了。 */
    html[data-rd-view="xl"] {
        --rd-cols: 2;
    }

    html[data-rd-view="grid"] {
        --rd-cols: 3;
    }

    /* 紧凑列表在窄一些的屏幕上退回单列：此时每列只剩约 480px，
       再横着塞一个封面加正文，标题和描述都会被压到逐字折行。 */
    html[data-rd-view="list"] {
        --rd-cols: 1;
    }

    html[data-rd-view="list"] .rd-item-cover {
        flex: 0 0 210px;
        width: 210px;
    }
}

@media (max-width: 900px) {
    .rd-nav {
        display: none;
    }

    .rd-nav-toggle {
        display: flex;
    }

    /* 手机端登录态只留头像。
       36px 高的顶栏里塞「头像 + 昵称」，昵称稍长就被 ellipsis 吃掉一半，
       而且它把右侧整组控件往左推，反过来又挤压搜索框。
       名字在「用户中心 → 个人资料」里完整显示，点头像即达。
       注意 .rd-user-chip 的 gap 是 8px，span 一旦 display:none 就退出 flex 布局，
       gap 不会留下空隙，所以只要把左右内边距收平就是正圆。 */
    .rd-only-name {
        display: none;
    }

    /* 宽高必须成对给出：这个胶囊的高度在基础样式里是 40px，在 <=420px 块里被改成 36px。
       只写 width:36px 会让 421~900px 区间拿到 36×40 的**竖椭圆** ——
       不是圆、也不是横条，看着像渲染坏了。
       与 .rd-nav-toggle（本区间 40×40）同高，并排才齐。
       改动任一处高度都要同步这里，探针里有 assertChipRound 兜底。 */
    .rd-user-chip {
        width: 40px;
        padding: 0;
        justify-content: center;
    }

    .rd-row {
        flex-direction: column;
        /* 必须显式改回 stretch。
           基础样式是 align-items:flex-start，在 column 方向上它意味着「按 max-content 定宽」——
           列宽不再等于容器宽，里面任何 nowrap 元素（如分区标题的描述）都会把整列顶出屏幕。 */
        align-items: stretch;
    }

    .rd-col-side {
        width: 100%;
        flex: 1 1 auto;
    }

    .rd-search-box {
        display: none;
    }

    /* 页脚：品牌块独占一行 —— 它的说明文字需要宽度，
       挤在 1fr 里会折成六七行。
       链接组按**实际组数**排（.is-1 / .is-2 / .is-3）：
       三组排两列会剩下一组单独落在第三行、右边空出一整格，
       看着像布局坏了 —— 这正是「页脚错位」的观感来源之一。
       三组时正好收进同一行，标题短、列宽够（768px 下每列约 233px）。 */
    .rd-footer-grid,
    .rd-footer-grid.is-2,
    .rd-footer-grid.is-3 {
        gap: 22px 16px;
    }

    .rd-footer-grid.is-3 {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .rd-footer-grid.is-2 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .rd-footer-grid.is-1 {
        grid-template-columns: minmax(0, 1fr);
    }

    .rd-footer-grid > div:first-child {
        grid-column: 1 / -1;
    }

    /* 页脚链接在手机上要够手指点：13.5px 的行盒只有 18px 高，
       五行挨着排，误点率很高。给链接补纵向内边距、撤掉 li 的下间距，
       整块高度基本不变但每个目标都到了 32px 以上。 */
    .rd-footer-links li {
        margin-bottom: 0;
    }

    .rd-footer-links a {
        display: inline-block;
        padding: 7px 0;
    }

    /* 悬浮工具条在窄屏同样是竖排（126px 高）、距视口底 20px，
       留白与桌面一致给 164px —— 不再给版权行加右内边距去「横向躲开」，
       那会把版权行挤窄 → 看着就是错位。 */
    .rd-footer {
        padding-bottom: 164px;
    }

    /* 品牌区在手机上只有 30px 高，2px 之差就掉到常用触摸尺寸（32px）以下 */
    .rd-logo {
        min-height: 34px;
    }

    .rd-only-mobile {
        display: block !important;
    }
}

@media (max-width: 640px) {
    body {
        font-size: 14.5px;
    }

    /* 手机端页脚的三组链接压成「一条可换行的链接带」。
       实测 390px 下页脚高 698px，其中约 480px 是这三组带标题的竖列 ——
       占掉近一整屏，而里面的 12 条链接在页头抽屉导航与用户中心菜单里全都有，
       用户每翻一页都要先滚过一整屏重复导航才能看到版权行。
       压成链接带后只剩两行、约 76px，链接一条没少（对 SEO 也友好）。
       做法：组容器与 ul 统统 display:contents，把 li 直接交给外层的 flex，
       标题藏掉 —— 扁平链接带不需要分组，分组反而又长出三行来。 */
    .rd-footer-grid {
        display: block;
    }

    .rd-footer-nav {
        display: flex;
        flex-wrap: wrap;
        gap: 2px 18px;
        margin-top: 16px;
    }

    .rd-footer-nav > div,
    .rd-footer-nav ul {
        display: contents;
    }

    .rd-footer-nav h4 {
        display: none;
    }

    /* 手机上三种密度差异要明显，切换才有意义：
       大图 = 单列大卡，标准 = 2 列，列表 = 单列横向卡。 */
    html[data-rd-view] {
        --rd-cols: 2;
        --rd-gap: 12px;
    }

    html[data-rd-view="xl"] {
        --rd-cols: 1;
    }

    html[data-rd-view="list"] {
        --rd-cols: 1;
    }

    /* 套餐 / 步骤卡在手机上 3 列会挤成逐字竖排，压成 2 列 */
    .rd-grid-3 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    html[data-rd-view="list"] .rd-item-cover {
        flex: 0 0 116px;
        width: 116px;
    }

    html[data-rd-view="list"] .rd-item-body {
        padding: 11px 13px;
    }

    html[data-rd-view="list"] .rd-item-title {
        font-size: 14.5px;
    }

    /* 手机端卡片只有约 170px 宽，一行只放得下 10 个汉字 ——
       "多语言外贸站模板 GlobalBiz" 会被截成 "多语言外贸站模板…"，
       一屏里每张卡都缺一截，这才是「排版乱」的主要来源。
       对标参考站（一方主题演示站，390px 实测）：封面 124px 高 / 标题 13px·800·两行，
       这里放开到两行，并把封面从 16:10 抬到 10:7（从「半张图」变回主体）。 */
    .rd-item-cover {
        aspect-ratio: 10 / 7;
    }

    .rd-item-cover-ph {
        font-size: 26px;
    }

    .rd-item-title {
        font-size: 14px;
        line-height: 1.4;
        /* 两行的高度。标题只有一行的卡片也占满两行，网格里标题与底栏才对齐 ——
           否则短标题的卡片会在标题和底栏之间空出一块，正是「排版散」的来源。 */
        min-height: 2.8em;
        margin-bottom: 6px;
    }

    .rd-item-title a {
        -webkit-line-clamp: 2;
    }

    .rd-item-desc {
        display: none;
    }

    .rd-item-body {
        padding: 11px 12px 12px;
    }

    /* 小屏卡片只有约 151px 可用宽度：
       「分类 + 浏览量 + 日期」三组信息会挤到逐字折行（"09-29" 断成两行），
       所以这里收掉日期、缩小字号，并禁止 meta 行换行。
       另外底栏原来靠给分类名补 7px 内边距撑命中区，一撑就是 45px 高 ——
       占了卡片正文的近一半，「标题一行 + 一大块底栏」让整张卡看着头重脚轻。 */
    .rd-item-meta {
        flex-wrap: nowrap;
        gap: 6px;
        font-size: 11.5px;
        line-height: 1.4;
        /* 底栏原来靠给分类名补 7px 内边距撑命中区，一撑就是 45px 高 ——
           占了卡片正文的近一半。这里把留白从「分类名内部」挪到「整行之间」：
           分类名保住 ≥32px 的触控区（项目规矩，audit-mobile 会查），
           行间距压到 7px，底栏整体从 45.5px 收到约 41px。 */
        padding-top: 7px;
    }

    .rd-item-meta-l,
    .rd-item-meta-r {
        gap: 7px;
    }

    .rd-item-meta-l {
        min-width: 0;
        /* ⚠️ 这里原来有一句 overflow: hidden（本意是别让长分类名把这一行撑宽）。
           它会连分类名 `::after` 撑出来的那块命中区一起裁掉 —— 而 computed style
           照样报着 top:-5px，CSS 读起来一切正常，只有**真点一下**才发现点不到
           （probe-mobile「分类名的命中区」那条就是这么抓出来的）。
           分类名自己已经是 overflow:hidden + text-overflow:ellipsis，
           裁得干净；这一层是多余的。**别再加回来。** */
    }

    .rd-item-meta .rd-cat {
        /* ⚠️ 命中区（手指能点到的那块）必须 ≥32px：`audit-mobile` 会逐个量 <a>，
           低于 32px 就算「小触摸目标」。

           做法：**把高度做在元素自己身上**（34px，比阈值多留 2px ——
           `elementFromPoint` 会把采样坐标取整到像素，判据自带 ±1px 噪声，
           卡在 32 整上容易假红），再用等量负 margin 把多出来的 12px 抵回去 ——
           底栏高度、文字位置、胶囊大小全都和原来一模一样。

           为什么不用 `::after` 上下外扩（项目里其它胶囊是那么做的）？
           因为这里**自身就带 `overflow: hidden`**（下面那句，截断长分类名必需：
           它是 flex 子项，不裁就没法收缩，长分类名会把整行撑破）。
           `::after` 是宿主自己的子盒，宿主的 overflow 会把它一起裁掉 ——
           而 `getComputedStyle(el,'::after')` 照样报着 `top:-5px`，
           CSS 读起来完全正常，只有真点一下才发现点不到。
           实测：外扩 5px 后点「上边缘外 3px」拿到的是 `div.rd-item-meta`。

           所以这里改成「元素自身够高 + 负 margin 抵消 + ::before 画底色」：
           底色那 22px 由 ::before 画在盒子中间，`overflow: hidden` 裁不到它
           （它整个都在 padding box 里面）。 */
        height: 34px;
        line-height: 34px;
        padding: 0 10px;
        margin: -6px 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        background: none;
        /* z-index:0 让本元素自成层叠上下文，::before 的 -1 就只降到
           「本元素背景之上、文字之下」—— 不会掉到卡片背景后面去。 */
        position: relative;
        z-index: 0;
    }

    /* 视觉上的那枚 22px 胶囊（等宽，居中 22px 高，圆角跟着变量走）。
       文字仍是 .rd-cat 自己的（上面 line-height: 34px 让它在盒内垂直居中），
       所以这一层只负责「底色」。 */
    .rd-item-meta .rd-cat::before {
        content: "";
        position: absolute;
        left: 0;
        right: 0;
        top: 6px;
        bottom: 6px;
        z-index: -1;
        border-radius: var(--rd-radius-pill);
        background: var(--rd-primary-soft);
    }

    .rd-item-meta-r {
        flex: 0 0 auto;
    }

    .rd-item-meta .rd-item-date {
        display: none;
    }

    /* 小屏分区标题：原名 + 描述 +「更多」挤在一行会把标题撑成三行，
       这里锁成单行，描述超出用省略号收尾。 */
    .rd-section-hd {
        align-items: center;
        gap: 10px;
        margin-bottom: 12px;
    }

    .rd-section-title {
        flex-wrap: nowrap;
        font-size: 17.5px;
        letter-spacing: -.3px;
    }

    .rd-section-sub {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .rd-toolbar {
        right: 12px;
        bottom: 20px;
        gap: 7px;
    }

    /* 小屏浮动工具区会压到卡片右下角，缩小一点，减少抢视线。
       但**不能像原来那样再压不透明度**（原来是 opacity:.86）：
       半透明的按钮会把底下的正文透出来，用户看到的是「文字被切了两半」，
       读起来像渲染错位，而不是「这里有个浮层」。
       要压低存在感就靠缩小 + 更实的底 + 稍重的阴影，让它明确地"浮"在上面。 */
    .rd-tool {
        width: 38px;
        height: 38px;
        border-radius: 11px;
        box-shadow: 0 6px 18px -6px rgba(24, 33, 61, .3);
    }

    .rd-tool svg {
        width: 17px;
        height: 17px;
    }

    /* 手机上版权行竖排、左对齐。
       左段是一句连续的话（版权 · Powered by），右段是三个统计数字 ——
       竖排后正好两行收完。上一版「Powered by」被放在统计数字那一组的末尾，
       它在 390px 下装不下就自己折到第三行、孤零零占一行，看着像排版散了。 */
    .rd-copy {
        flex-direction: column;
        align-items: flex-start;
        gap: 4px;
    }

    .rd-stats {
        gap: 12px;
    }
}

@media (max-width: 420px) {
    html[data-rd-view] {
        --rd-gap: 10px;
    }

    .rd-item-price {
        height: 24px;
        line-height: 24px;
        font-size: 12.5px;
        padding: 0 8px;
    }

    .rd-item-price .rd-cur {
        font-size: 10.5px;
    }

    /* 小屏头部：收紧间距并允许 Logo 文字收缩，避免 320px 下顶栏横向溢出 */
    .rd-container {
        padding: 0 14px;
    }

    .rd-header-in {
        gap: 10px;
    }

    .rd-logo {
        flex: 0 1 auto;
        min-width: 0;
        gap: 7px;
        font-size: 16px;
    }

    .rd-logo img {
        max-height: 28px;
    }

    .rd-logo-mark {
        width: 30px;
        height: 30px;
        border-radius: 9px;
        font-size: 16px;
    }

    .rd-logo>span:not(.rd-logo-mark) {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
    }

    .rd-head-tools {
        gap: 8px;
        min-width: 0;
    }

    .rd-header .rd-btn {
        height: 36px;
        padding: 0 12px;
        font-size: 13px;
        white-space: nowrap;
    }

    /* 本块(<=420px)排在 900px 块之后，两侧都是同特异性的 .rd-user-chip，
       后写的赢 —— 所以这里必须把宽、内边距再给一次，
       否则 <=420px 时头像胶囊要么被原值 0 10px 0 4px 撑成椭圆，
       要么变成 40 宽 × 36 高的横椭圆。此处高度与 .rd-nav-toggle 一致，都是 36。 */
    .rd-user-chip {
        width: 36px;
        height: 36px;
        padding: 0;
        font-size: 13px;
    }

    .rd-user-chip img {
        width: 27px;
        height: 27px;
    }

    .rd-nav-toggle {
        width: 36px;
        height: 36px;
        flex: 0 0 auto;
    }
}

/* ============================ utilities ============================ */
.is-hidden {
    display: none !important;
}

.rd-flex {
    display: flex;
}

.rd-flex-wrap {
    flex-wrap: wrap;
}

.rd-items-center {
    align-items: center;
}

.rd-justify-between {
    justify-content: space-between;
}

.rd-gap-8 {
    gap: 8px;
}

.rd-gap-12 {
    gap: 12px;
}

.rd-mt-8 {
    margin-top: 8px;
}

.rd-mt-16 {
    margin-top: 16px;
}

.rd-mb-16 {
    margin-bottom: 16px;
}

.rd-nowrap {
    white-space: nowrap;
}

.rd-text-c {
    text-align: center;
}

.rd-text-r {
    text-align: right;
}

/* ==========================================================================
   梯度商城风 v2 —— 详情页手机端吸底购买条
   仅在「真的能购买/下载」时由 JS 打开（.is-on），桌面端永不显示。
   ========================================================================== */

.rd-buybar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 880;
    display: none;
    align-items: center;
    gap: 12px;
    padding: 9px 14px calc(9px + env(safe-area-inset-bottom, 0px));
    background: rgba(255, 255, 255, .97);
    border-top: 1px solid var(--rd-border);
    box-shadow: 0 -10px 30px -20px rgba(12, 17, 40, .55);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
}

html[data-theme="dark"] .rd-buybar {
    background: rgba(18, 22, 33, .97);
}

.rd-buybar-price {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
    line-height: 1.15;
}

.rd-buybar-label {
    font-size: 11px;
    color: var(--rd-muted);
}

.rd-buybar-price b {
    font-size: 19px;
    font-weight: 800;
    color: var(--rd-red);
}

.rd-buybar-price.is-free b {
    color: var(--rd-green);
}

.rd-buybar-price s {
    font-size: 12px;
    color: var(--rd-muted);
    font-weight: 500;
}

.rd-buybar-acts {
    display: flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
}

.rd-buybar .rd-btn {
    height: 42px;
}

.rd-buybar-acts .rd-btn-primary {
    min-width: 122px;
}

/* 手机端详情页出现吸底购买条时，右下悬浮工具条**直接让位**。
   两者都是浮层，叠在一起右下角会挤成一团（吸底条还会把工具条整体抬高一截，
   竖排的 126px 一抬就顶到屏幕中间）。吸底条本来已经给了购买/下载入口，
   少一枚「回到顶部」不影响。这时页脚只需为吸底条本身留白：
   吸底条高约 62px，给 96px 留余量。 */
@media (max-width: 900px) {
    .rd-buybar.is-on {
        display: flex;
    }

    body.rd-has-buybar .rd-toolbar {
        display: none;
    }

    body.rd-has-buybar .rd-footer {
        padding-bottom: 96px;
    }
}
