/* ==========================================================================
   快速导航系统 —— 样式表
   风格：浅色、清爽、边框分明；色阶统一由下面的变量控制。
   ========================================================================== */

:root {
    /* 底色与层次 */
    --bg: #f3f6fb;
    --bg-tint-a: #e9effc;
    --bg-tint-b: #eef7fd;
    --surface: #ffffff;
    --surface-2: #f8fafd;
    --surface-3: #eef2f8;

    /* 描边：比底色略深一点，让分块更清晰 */
    --border: #dfe5ef;
    --border-strong: #c3cddd;

    /* 文字：三档对比 */
    --text: #0f172a;
    --text-2: #475467;
    --text-3: #94a0b3;

    /* 强调色 */
    --primary: #2563eb;
    --primary-dark: #1d4ed8;
    --primary-soft: #edf3ff;
    --primary-border: #cddcff;

    --accent: #0891b2;
    --warn: #c2740a;
    --warn-soft: #fff6e6;
    --warn-border: #fbd9a0;

    --danger: #dc2626;
    --danger-dark: #b91c1c;
    --danger-soft: #fdeeee;

    --success: #0f9d58;
    --success-soft: #e9f8ef;

    --radius: 14px;
    --radius-sm: 10px;

    /* 右侧管理工具悬浮栏：宽度 + 与域区域的间距。
       栏宽用来给按钮定宽，间距用来算看板要让出多少空间（见 .board-footer）。 */
    --rail-w: 136px;
    --rail-gap: 10px;
    /* 看板右侧预留量：JS 的 layoutRail() 会按实测余量改写；
       这里给的是最保守的兜底值（栏完全落在内容区里，绝不会压住域框）。 */
    --rail-reserve: calc(var(--rail-w) + var(--rail-gap));

    --shadow-xs: 0 1px 2px rgba(15, 23, 42, .05);
    --shadow-sm: 0 1px 2px rgba(15, 23, 42, .06), 0 2px 8px rgba(15, 23, 42, .05);
    --shadow-md: 0 4px 14px rgba(15, 23, 42, .09), 0 1px 3px rgba(15, 23, 42, .06);
    --shadow-lg: 0 20px 48px rgba(15, 23, 42, .2);
}

* { box-sizing: border-box; }

/* 统一处理 hidden 属性：.btn 等类里的 display 会盖掉浏览器默认的 [hidden]，
   这里显式兜底，避免「隐藏」失效 */
[hidden] { display: none !important; }

html { height: 100%; }

/* 纵向 flex + margin-top:auto：内容不足一屏时页脚也贴在窗口最底部 */
body {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    margin: 0;
    font-family: "PingFang SC", "Microsoft YaHei", "Helvetica Neue", Arial, "Noto Sans SC", sans-serif;
    font-size: 14px;
    line-height: 1.5;
    color: var(--text);
    background:
        radial-gradient(1000px 460px at 8% -12%, var(--bg-tint-a), transparent 62%),
        radial-gradient(880px 420px at 102% -6%, var(--bg-tint-b), transparent 58%),
        var(--bg);
    -webkit-font-smoothing: antialiased;
}

/* 拖拽过程中禁止选择文本 / 触发原生拖图 */
body.is-dragging { user-select: none; -webkit-user-select: none; cursor: grabbing !important; }

h1, h2, h3, h4, p { margin: 0; }

button { font-family: inherit; }

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

code {
    font-family: Consolas, Monaco, "Courier New", monospace;
    background: var(--surface-3);
    padding: 1px 5px;
    border-radius: 5px;
    font-size: .92em;
    color: var(--text-2);
}

/* 运行模式下隐藏所有管理类元素 */
body[data-mode="run"] .manage-only { display: none !important; }

/* 管理员专属元素（用户 Tab、管理模式说明卡…）：非管理员一律不显示。
   data-role 由 renderAuthUi() 写在 body 上；没写（脚本还没跑到）时按「非管理员」处理，
   这样普通用户不会在刚进页面的一瞬间闪出「管理模式」的说明卡。 */
body:not([data-role="admin"]) .admin-only { display: none !important; }

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

.topbar {
    position: sticky;
    top: 0;
    z-index: 40;
    flex: 0 0 auto;
    /* 不透明度：基础白 .86 乘 --o-head（0~1，默认 1）。调小滑块 = 顶栏更透 */
    background: color-mix(in srgb, #fff calc(var(--o-head, 1) * 86%), transparent);
    backdrop-filter: saturate(180%) blur(14px);
    border-bottom: 1px solid var(--border);
}

.topbar-inner {
    max-width: 1440px;
    margin: 0 auto;
    padding: 11px 24px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}

.brand { display: flex; align-items: center; gap: 11px; min-width: 0; }

/* 站点图标：无边框无底色的「纯图标」，图片按原尺寸自适应（仅做上限保护）；
   宽高可在「站点设置」里自定义，自定义后由 JS 写成内联样式覆盖这里的 auto。
   曾是 emoji 时只做字号控制，不再画圆角底。 */
.brand-logo {
    font-size: 26px;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    background: none;
    border: 0;
    border-radius: 0;
    overflow: visible;
}

/* 图片图标：默认 width/height auto = 按图片原始大小显示；
   max-* 只是防巨大图把顶栏撑爆，自定义尺寸时由内联样式覆盖。 */
.brand-logo img {
    display: block;
    width: auto;
    height: auto;
    max-width: 240px;
    max-height: 40px;
    object-fit: contain;
}

.brand-text { min-width: 0; }
.brand-text h1 {
    font-size: 16.5px; font-weight: 700; letter-spacing: .2px;
    /* 防止品牌区被右侧按钮挤成「一字竖排」：宁可单行省略也不拆字换行 */
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}

.brand-text p { font-size: 12px; color: var(--text-3); margin-top: 1px; }

/* 右对齐：窄屏换成多行时每一行都靠右，保证「登录 / 退出登录」按钮的右缘
   始终与下方 .hint 提示条的右缘在同一条竖线上 */
.topbar-right {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 9px;
    flex-wrap: wrap;
}

.mode-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 600;
    padding: 4px 11px;
    border-radius: 999px;
    background: var(--surface-3);
    color: var(--text-2);
    border: 1px solid var(--border);
    white-space: nowrap;
}

.mode-badge::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--success);
}

body[data-mode="manage"] .mode-badge {
    background: var(--warn-soft);
    color: var(--warn);
    border-color: var(--warn-border);
}

body[data-mode="manage"] .mode-badge::before { background: var(--warn); }

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

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 15px;
    border-radius: 10px;
    border: 1px solid transparent;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background .15s, border-color .15s, color .15s, box-shadow .15s, transform .08s;
    white-space: nowrap;
    user-select: none;
}

.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .6; cursor: not-allowed; }

.btn-primary {
    background: var(--primary);
    color: #fff;
    box-shadow: 0 1px 2px rgba(37, 99, 235, .28);
}
.btn-primary:hover:not(:disabled) { background: var(--primary-dark); }

.btn-ghost {
    background: var(--surface);
    color: var(--text-2);
    border-color: var(--border-strong);
}
.btn-ghost:hover:not(:disabled) {
    background: var(--surface-2);
    color: var(--primary);
    border-color: var(--primary);
}

.btn-danger { background: var(--danger); color: #fff; }
.btn-danger:hover:not(:disabled) { background: var(--danger-dark); }

.btn-block { width: 100%; }

.btn-mini { padding: 4px 10px; font-size: 12px; border-radius: 8px; }

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

.wrap {
    flex: 1 0 auto;
    width: 100%;
    max-width: 1440px;
    margin: 0 auto;
    padding: 20px 24px 36px;
}

.hint {
    margin-bottom: 14px;
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    background: var(--primary-soft);
    border: 1px solid var(--primary-border);
    color: #1e40af;
    font-size: 13px;
    line-height: 1.65;
    overflow-wrap: anywhere;
}

.hint b { font-weight: 700; }

/* ------------------ 多用户视图：管理员的用户 Tab ------------------ */

.user-tabs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 7px;
    margin-bottom: 14px;
    padding-bottom: 10px;
    border-bottom: 1px dashed var(--border);
}

/* 用户 Tab 的容器：display:contents 让它从布局里「消失」，
   里面的 tab 按钮依旧是 .user-tabs 的 flex 子项（gap / 换行规则不变）。
   有这一层是为了让「一键对齐」按钮能和 tab 列表并列而不会被 innerHTML 重绘掉。 */
.user-tab-list { display: contents; }

/* 一键对齐：常驻在这一行的最右侧（margin-left:auto 把它顶到行尾）；
   内边距按「和用户 Tab 等高」调（6px + 12.5px 字号 ≈ 31px），一行看上去是一条线 */
.user-tab-align { margin-left: auto; padding: 6px 13px; font-size: 12.5px; }

.user-tab {
    padding: 6px 14px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text-2);
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    transition: border-color .12s, background .12s, color .12s;
}

.user-tab:hover {
    border-color: var(--border-strong);
    color: var(--text);
}

.user-tab.is-active {
    border-color: var(--primary);
    background: var(--primary-soft);
    color: var(--primary);
}

/* JS 用 hidden 控制显隐；display:flex 会盖掉 UA 的 hidden 样式，这里显式声明 */
.user-tabs[hidden] { display: none !important; }

.hint-warn {
    background: var(--warn-soft);
    border-color: var(--warn-border);
    color: #8a5600;
}

/* 看板：自由布局下是绝对定位画布；窄屏退回文档流。
   画板同时是「右侧管理工具悬浮栏」的定位参照（栏是它的绝对定位子元素）。 */
.board { position: relative; }

body[data-layout="flow"] .board {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 16px;
    align-items: start;
    /* 文档流下悬浮栏退回底部横排，不再预留右侧空间 */
    margin-right: 0;
}

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

/*
 * 域卡片的外观由元素上的 CSS 自定义属性驱动（由 app.js 的 applyAppearance 写入）：
 *   --dm-accent      域框主色（描边 / 角标 / 标题渐变 / 悬停高亮）；空 = 主题默认
 *   --dm-icon-size   emoji 尺寸（默认 42px，即 42×42）
 *   --dm-title-*     标题的字号 / 颜色 / 字族 / 斜体
 *   --dm-note-*      备注的字号 / 颜色 / 字族 / 斜体
 * 变量为空时一律回落到 var(--primary) / var(--text) 等主题色。
 */
.domain {
    /* 主色：没设就跟随主题 */
    --dm-accent: var(--primary);
    --dm-title-size: 14px;
    --dm-note-size: 11px;

    display: flex;
    flex-direction: column;
    /* 文档流布局下 .domain 不是绝对定位，角标（position:absolute）会跑到 board 角上；
       这里兜一个定位上下文，两种布局行为一致。free 布局由下面的绝对定位覆盖。 */
    position: relative;
    /* 不透明度：域框基础底色乘 --o-domain（0~1，默认 1）。调小滑块 = 域框更透 */
    background: color-mix(in srgb, var(--surface) calc(var(--o-domain, 1) * 100%), transparent);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    transition: box-shadow .18s, border-color .18s;
}

body[data-layout="free"] .domain {
    position: absolute;
    transition: left .24s cubic-bezier(.22, .61, .36, 1),
                top .24s cubic-bezier(.22, .61, .36, 1),
                width .18s, height .18s,
                box-shadow .18s, border-color .18s;
}

body[data-layout="flow"] .domain {
    /* 注意：不能写 static —— 本地域角标是 position:absolute，
       域框一旦不是定位元素，角标就会跑到 board（position:relative）的角上。 */
    position: relative;
    width: auto !important;
    height: auto !important;
}

.domain:hover { box-shadow: var(--shadow-md); border-color: var(--border-strong); }

/* 本地域专属角标：内联 SVG 的「显示器 + 刷新箭头」图标。
   位置 = 删除域按钮（域标题栏最右那个 ✕）的正上方，并且上移半个身位，
   让一半探出域框外，做出「悬浮在域框角上」的效果。
   删除按钮几何：标题栏 padding-right 12px + 按钮宽 23px → 中心距内边 23.5px；
   角标宽 30px，所以 right = 23.5 - 15 = 8.5px。 */
.domain-local-badge {
    position: absolute;
    top: -15px;
    right: 8.5px;
    /* 必须高于域的缩放把手（.domain > .rz 是 12）：角标探出域框上沿后正压在北侧把手上，
       层级不够就会被把手抢走命中 → 按钮点不动。角标只有 30px 宽，
       北侧把手其余部分与 NE 角把手（占右侧 7px 内）都还留得下，缩放不受影响。 */
    z-index: 14;
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    line-height: 1;
    padding: 0;
    border: 1px solid var(--border-strong);
    border-radius: 9px;
    background: var(--surface);
    cursor: pointer;
    color: var(--text-2);
    /* 悬浮感：一圈描边光 + 落地阴影 */
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--surface) 88%, transparent),
                0 4px 12px rgba(15, 23, 42, .18);
    transition: transform .15s, border-color .15s, background .15s, color .15s, box-shadow .15s;
}
/* 本地域图标（显示器 + 刷新箭头）本身是内联 SVG，跟随按钮文字色 */
.domain-local-badge .local-ico {
    width: 19px;
    height: 19px;
    display: block;
}
.domain-local-badge:hover {
    color: var(--primary);
    transform: translateY(-2px) scale(1.07);
    border-color: var(--primary);
    background: color-mix(in srgb, var(--primary) 12%, var(--surface));
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--surface) 88%, transparent),
                0 8px 20px color-mix(in srgb, var(--primary) 34%, transparent);
}
.domain-local-badge:active { transform: translateY(-1px) scale(.95); }

/* 设了自定义主色的域，悬停时描边直接用它，颜色反馈更明显 */
.domain[style*="--dm-accent:"]:hover {
    border-color: color-mix(in srgb, var(--dm-accent) 55%, #ffffff);
    box-shadow: 0 4px 16px color-mix(in srgb, var(--dm-accent) 18%, transparent),
                var(--shadow-sm);
}

/* 域头部 */
.domain-head {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
    /* 标题区跟着主色走：用 color-mix 调出一层很淡的同色底 */
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--dm-accent) 7%, #ffffff),
        var(--surface));
    border-radius: var(--radius) var(--radius) 0 0;
}

body[data-mode="manage"] .domain-head { cursor: grab; }
body[data-mode="manage"] .domain-head:active { cursor: grabbing; }

.domain-icon {
    /* 默认 42×42（编辑域默认尺寸），可由 --dm-icon-size 覆盖 */
    position: relative;
    font-size: calc(var(--dm-icon-size, 42px) * 0.5);
    line-height: 1;
    width: var(--dm-icon-size, 42px);
    height: var(--dm-icon-size, 42px);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    background: color-mix(in srgb, var(--dm-accent) 12%, #ffffff);
    border: 1px solid color-mix(in srgb, var(--dm-accent) 30%, #ffffff);
    flex: 0 0 auto;
    overflow: visible;
}

/* 图片图标：让圆角跟随外层 .domain-icon（外层不再 overflow:hidden，否则会裁掉角标）。
   填满图标框：拟物彩色图标（winicons）也走这里，别按 SVG 的固有尺寸 32px 撑出框外。 */
.domain-icon img { border-radius: inherit; display: block; width: 100%; height: 100%; object-fit: contain; }

.domain-title { flex: 1 1 auto; min-width: 0; }

.domain-name {
    font-size: var(--dm-title-size, 14px);
    font-weight: 700;
    color: var(--dm-title-color, var(--text));
    font-family: var(--dm-title-font, inherit);
    font-style: var(--dm-title-style, normal);
    line-height: 1.35;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 名称下方的备注 */
.domain-note {
    font-size: var(--dm-note-size, 11px);
    color: var(--dm-note-color, var(--text-3));
    font-family: var(--dm-note-font, inherit);
    font-style: var(--dm-note-style, normal);
    line-height: 1.45;
    margin-top: 3px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.domain-count {
    position: absolute;
    top: -7px;
    right: -7px;
    font-size: 12px;
    /* font-weight: 800; */
    /* line-height: 1; */
    /* 颜色由 JS 按网址数量内联（domainCountColor），这里只是兜底 */
    color: var(--text-2);
    background: none;
    border: 0;
    padding: 0;
    /* text-shadow: 0 0 2px #000, 0 0 1px #000; */
    pointer-events: none;
}

.domain-actions { display: flex; gap: 3px; flex: 0 0 auto; }

/* 标题栏右侧 4 个按钮（⊞ 网址对齐 / ＋ 添加网址 / ✎ 编辑域 / ✕ 删除域）：
   尺寸收紧一点，保证默认 340px 域宽下标题仍有足够显示空间 */
.domain-actions .icon-btn { width: 23px; height: 23px; font-size: 12px; }

/* 窄屏文档流布局下网址框本来就是顺序排列的，不需要「网址框一键对齐」 */
body[data-layout="flow"] .domain-actions .act-align { display: none; }

/* 图标按钮 */
.icon-btn {
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid transparent;
    background: transparent;
    border-radius: 8px;
    cursor: pointer;
    color: var(--text-3);
    font-size: 13px;
    line-height: 1;
    padding: 0;
    transition: background .15s, color .15s, border-color .15s;
}

.icon-btn:hover { background: var(--surface-3); color: var(--text); border-color: var(--border); }
.icon-btn.danger:hover { background: var(--danger-soft); color: var(--danger); border-color: #f7cccc; }

/* 域内画布：网址框的定位容器。
   overflow 用 hidden 而不是 auto —— 域框内不出现上下 / 左右的拉动条；
   网址框超出域框的部分直接裁掉（域框缩放时网址框会等比例跟随，正常不会溢出）。 */
.domain-canvas {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

.links {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    min-height: 100%;
}

body[data-layout="flow"] .domain-canvas { overflow: visible; }

body[data-layout="flow"] .links {
    position: static;
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 12px;
    min-height: 0;
}

.links.drag-over { background: rgba(37, 99, 235, .04); }

/* ------------------------------- 网址框 -------------------------------- */

.link {
    position: absolute;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    transition: border-color .15s, box-shadow .15s, background .15s, opacity .15s;
    min-width: 0;
}

body[data-layout="flow"] .link {
    position: static !important;
    width: auto !important;
    height: auto !important;
    left: auto !important;
    top: auto !important;
}

.link:hover {
    border-color: var(--primary);
    background: #fff;
    box-shadow: 0 3px 10px rgba(37, 99, 235, .13);
}

body[data-mode="manage"] .link { cursor: grab; }
body[data-mode="manage"] .link:active { cursor: grabbing; }

/* 本地域网址不可达被禁用：变灰 + 红框提醒 + 不可点击 */
/* 本地域里的网址连续 3 次不可达：整卡变灰 + 边框变红提醒 + 不可点击。
   注意：红框要「醒目」，所以不能对整卡用 filter/opacity（会把红也冲淡），
   改为只把内容（图标 / 名称 / 域名）去色压暗，边框保持鲜红。 */
.link.is-disabled {
    background: color-mix(in srgb, var(--danger, #dc2626) 7%, var(--surface-2));
    border-color: var(--danger, #dc2626);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--danger, #dc2626) 15%, transparent);
}
.link.is-disabled .link-icon-box,
.link.is-disabled .link-name,
.link.is-disabled .link-host {
    filter: grayscale(1);
    opacity: .5;
}
/* 状态角标也标红，一眼能看出是「已禁用」而不是普通离线（两行文字一起红，颜色更统一） */
.link.is-disabled .link-probe { color: var(--danger, #dc2626); }
.link.is-disabled .link-probe .probe-dot { background: var(--danger, #dc2626); }
.link.is-disabled:hover {
    border-color: var(--danger, #dc2626);
    background: color-mix(in srgb, var(--danger, #dc2626) 11%, var(--surface-2));
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--danger, #dc2626) 22%, transparent),
                0 3px 10px color-mix(in srgb, var(--danger, #dc2626) 20%, transparent);
}
/* 禁用态下整条不可点（包括图标与文字），但保留编辑/删除按钮与状态角标可用 */
.link.is-disabled .link-main {
    pointer-events: none;
    cursor: not-allowed;
}
/* 角标要能 hover 出「已禁用」提示，所以单独放行鼠标事件 */
.link.is-disabled .link-probe {
    pointer-events: auto;
    cursor: help;
}

.link-main {
    display: flex;
    align-items: center;
    gap: 9px;
    text-decoration: none;
    color: inherit;
    min-width: 0;
    flex: 1 1 auto;
    height: 100%;
}

/* 图标：优先显示站点图标，加载失败后换成首字母色块 */
.link-icon-box {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.link-icon-img {
    width: 20px;
    height: 20px;
    object-fit: contain;
    border-radius: 5px;
    display: block;
}

/* emoji / 纯文字图标（网址图标支持 emoji 选择，与站点 / Logo emoji 一致） */
.link-icon-emoji {
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    line-height: 1;
    user-select: none;
}

.link-icon-fallback {
    width: 24px;
    height: 24px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 700;
    color: #fff;
    background: var(--primary);
    text-transform: uppercase;
    user-select: none;
}

.link-body { min-width: 0; flex: 1 1 auto; }

.link-name {
    display: block;
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.link-host {
    display: block;
    font-size: 11px;
    color: var(--text-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.link:hover .link-name { color: var(--primary); }

/*
 * 网址框的编辑 / 删除按钮：浮在框外右上角。
 * 绝对定位到 .link 的右上角（向外偏移），完全不占框内空间，
 * 也不会遮住网址名称与域名，悬停时才淡入。
 * z-index 须高于网址框自身的缩放把手（.rz = 8、角把手 = 9），
 * 否则点击按钮会误触缩放；又须低于域级把手（12）。
 */
.link-actions {
    position: absolute;
    right: -7px;
    top: -9px;
    z-index: 10;
    display: flex;
    gap: 3px;
    padding: 2px;
    border-radius: 999px;
    background: var(--surface);
    box-shadow: 0 2px 8px rgba(15, 23, 42, .16);
    opacity: 0;
    pointer-events: none;
    transform: translateY(2px) scale(.94);
    transition: opacity .15s, transform .15s;
}

.link:hover .link-actions,
.link:focus-within .link-actions {
    opacity: 1;
    pointer-events: auto;
    transform: none;
}

.link-actions .icon-btn {
    width: 20px;
    height: 20px;
    font-size: 11px;
    border-radius: 999px;
}

/* 窄屏 / 文档流布局：退回内联摆放，避免浮动按钮盖到相邻网址框上 */
body[data-layout="flow"] .link-actions {
    position: static;
    padding: 0;
    background: none;
    box-shadow: none;
    transform: none;
}

body[data-layout="flow"] .link-actions .icon-btn { width: 22px; height: 22px; font-size: 12px; }

/* 拖拽态 */
.link.dragging,
.domain.dragging {
    opacity: .55;
    z-index: 60;
    box-shadow: var(--shadow-lg);
    border-color: var(--primary);
}

/* 拖拽中不吃指针事件，方便用 elementFromPoint 命中下方容器 */
.link.dragging, .domain.dragging { pointer-events: none; }

.domain.dragging {
    transition: none !important;
    z-index: 60;
}

/* 文档流下的插入占位符 */
.link-placeholder {
    position: static;
    border: 1.5px dashed var(--primary);
    background: var(--primary-soft);
    border-radius: var(--radius-sm);
    height: 40px;
    pointer-events: none;
}

.link-placeholder[hidden] { display: none; }

/* 自由布局下的落点占位框：绝对定位，尺寸 = 被拖走那个框的尺寸 */
.link-placeholder.is-abs {
    position: absolute;
    height: auto;
    z-index: 0;
}

/* 拖拽中把网址框提到 body 上当「跟手幽灵」：
   脱离原域排版（原域剩余的框立刻自动占位），且能精确跟着鼠标走，不受任何夹取影响。
   用 body 前缀提权，压过 `body[data-layout="flow"] .link` 的 position/width !important。 */
body .link.link-ghost {
    position: fixed !important;
    left: 0 !important;
    top: 0 !important;
    width: var(--ghost-w, 240px) !important;
    height: var(--ghost-h, 40px) !important;
    margin: 0 !important;
    transform: translate(var(--ghost-x, 0px), var(--ghost-y, 0px));
    transition: none !important;
    z-index: 1200;
    pointer-events: none;
    opacity: .92;
    box-shadow: var(--shadow-lg);
    border-color: var(--primary);
}

/* 重排过程中让被挤开的框平滑滑到新位置，而不是瞬移 */
.links.reflowing .link { transition: left .16s ease, top .16s ease, width .16s ease, height .16s ease; }

.domain-placeholder {
    border: 2px dashed var(--primary);
    background: var(--primary-soft);
    border-radius: var(--radius);
    min-height: 120px;
    pointer-events: none;
}

/* ----------------------------- 缩放把手 -------------------------------- */

.rz {
    position: absolute;
    z-index: 8;
    touch-action: none;
}

.rz-n, .rz-s { left: 12px; right: 12px; height: 7px; cursor: ns-resize; }
.rz-n { top: -3px; }
.rz-s { bottom: -3px; }

.rz-e, .rz-w { top: 12px; bottom: 12px; width: 7px; cursor: ew-resize; }
.rz-e { right: -3px; }
.rz-w { left: -3px; }

.rz-ne, .rz-nw, .rz-se, .rz-sw { width: 14px; height: 14px; z-index: 9; }
.rz-ne { top: -4px; right: -4px; cursor: nesw-resize; }
.rz-nw { top: -4px; left: -4px; cursor: nwse-resize; }
.rz-se { bottom: -4px; right: -4px; cursor: nwse-resize; }
.rz-sw { bottom: -4px; left: -4px; cursor: nesw-resize; }

/*
 * 域自身的把手整体挪到域外沿：
 * 域内画布是 overflow:auto，网址框贴边时它自己的把手会伸到画布边缘，
 * 若域的把手仍压在内侧，两者会互相抢命中。挪到外面后各管各的，互不干扰。
 */
.domain > .rz { z-index: 12; }
.domain > .rz-n { top: -7px; }
.domain > .rz-s { bottom: -7px; }
.domain > .rz-e { right: -7px; }
.domain > .rz-w { left: -7px; }
.domain > .rz-ne { top: -7px; right: -7px; }
.domain > .rz-nw { top: -7px; left: -7px; }
.domain > .rz-se { bottom: -7px; right: -7px; }
.domain > .rz-sw { bottom: -7px; left: -7px; }

/* 右下角给一个可见的缩放暗示 */
body[data-mode="manage"][data-layout="free"] .rz-se::after {
    content: '';
    position: absolute;
    right: 4px;
    bottom: 4px;
    width: 9px;
    height: 9px;
    border-right: 2px solid var(--border-strong);
    border-bottom: 2px solid var(--border-strong);
    border-radius: 0 0 4px 0;
    opacity: .85;
}

body[data-mode="manage"][data-layout="free"] .domain:hover .rz-se::after,
body[data-mode="manage"][data-layout="free"] .link:hover .rz-se::after {
    border-color: var(--primary);
}

/* --------------------------- 缩放参考线（十字） --------------------------- *
 * 拉把手改变大小时，以「被拉动的那个点」为原点画横竖两条虚线贯穿视口，
 * 用来跟旁边的边框对个正。浮层在 body 上、position:fixed：
 *   - pointer-events:none —— 不吃点击，也不影响 elementFromPoint（准星下面是谁还是谁）；
 *   - 不遮句柄：z-index 低于弹窗（1000）。
 */
.resize-guides {
    position: fixed;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 950;
    pointer-events: none;
    opacity: 0;
    visibility: hidden;
}

.resize-guides.is-on { opacity: 1; visibility: visible; }

.rg-line {
    position: absolute;
    display: none;
    pointer-events: none;
}

/* 每条线单独开关：缩放只亮「被拉动那一点」的一横一竖，拖域亮域的四条边 */
.rg-line.is-on {
    display: block;
}

/* 竖线：left 由 JS 写成视口坐标；横向铺满视口 */
.rg-v,
.rg-v2 {
    top: 0;
    bottom: 0;
    width: 0;
    border-left: 1px dashed var(--primary);
    opacity: .85;
}

/* 横线：top 由 JS 写成视口坐标 */
.rg-h,
.rg-h2 {
    left: 0;
    right: 0;
    height: 0;
    border-top: 1px dashed var(--primary);
    opacity: .85;
}

/* 自定义主色的域，右下角把手也跟着变色 */
body[data-mode="manage"][data-layout="free"] .domain[style*="--dm-accent:"]:hover .rz-se::after {
    border-color: var(--dm-accent);
}

/* 运行模式下没有把手，用左侧色条体现自定义主色 */
body[data-mode="run"][data-layout="free"] .domain[style*="--dm-accent:"] {
    border-left: 3px solid color-mix(in srgb, var(--dm-accent) 80%, #ffffff);
}

body[data-layout="flow"] .rz { display: none !important; }

/* --------------------------- 域底部 / 空态 ------------------------------ */
/* 说明：「＋ 添加网址」已移入域标题栏右上角（.domain-actions），
   .domain-foot / .add-link 不再使用，故删除对应样式。 */

.domain-empty {
    color: var(--text-3);
    font-size: 12.5px;
    text-align: center;
    padding: 14px 8px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius-sm);
}

/* ------------------------------- 底部 ---------------------------------- */

/* ------------------- 右侧「管理工具」悬浮栏 ----------------------------
   管理模式下的整组管理按钮（新建域 / 站点设置 / 导入导出 / 接口调试 / 回收站）
   竖排在页面最右侧，只有按钮本身——没有外框、没有底色，不抢视觉。
   · 等宽按钮、上下排列；fixed 固定在视口右侧（不占看板横向空间），
     滚动页面时始终可见；
   · 域画板因此不再让位：管理模式与查看模式一样左右对称居中，
     域框左右边缘与顶栏内容区等距；
   · fixed 定位不参与域框高度 / 网格计算，域框排版完全不受影响。
   窄屏（文档流布局）下自动退回原来的底部横排，见文件末尾的 layout=flow 覆盖。 */
.board-footer {
    position: fixed;
    top: 72px;
    /* left 由 layoutRail() 动态设：域框右缘对齐顶栏退出登录按钮右缘，foot 紧跟域框右侧。 */
    left: 0;
    width: var(--rail-w);
    display: flex;
    flex-direction: column;
    gap: 8px;
    z-index: 20;
}

/* 栏内按钮：等宽 + 文案居中，长文案不折行 */
.board-footer .btn {
    width: 100%;
    padding: 7px 8px;
    font-size: 12.5px;
    justify-content: center;
}

/* 管理模式下域画板右侧让出按钮栏独立列（--rail-reserve），按钮栏 fixed 在这列里，
   不再压在域框上；查看模式域框全宽、无此栏。窄屏 compact 时 --rail-w 收缩，让位量跟着变小。 */
body[data-mode="manage"]:not([data-layout="flow"]) .board {
    margin-right: var(--rail-reserve);
}

/* 窄屏（compact-tools）时右侧栏收缩成小图标列：--rail-w 改为按钮框边长，
   域框右让位量同步收缩（--rail-reserve 自动跟随） */
body.compact-tools {
    --rail-w: var(--tool-btn-size, 40px);
}

/* 文档流布局（窄屏）退回「底部横排」：不再向右飘出，也不预留右侧空间。
   注意与上面那条同优先级，必须写在它后面才能盖住 margin-right。 */
body[data-layout="flow"] .board { margin-right: 0; }

body[data-layout="flow"] .board-footer {
    position: static;
    left: auto;
    width: auto;
    /* 网格里排到最后（所有域卡片之后）并占满整行 */
    order: 9999;
    grid-column: 1 / -1;
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: center;
    margin-top: 6px;
}

body[data-layout="flow"] .board-footer .btn { width: auto; }

/* 管理工具按钮图标容器：固定相对定位（回收站角标锚点）+ 字号可自定义（--tool-icon-size） */
.board-footer .btn .btn-ico,
.user-tab-align .btn-ico {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--tool-icon-size, 16px);
    line-height: 1;
}

/* 工具按钮图标用上传的图片时：跟着「图标字号」走，而不是把原图整张贴上去 */
.board-footer .btn .btn-ico img,
.user-tab-align .btn-ico img {
    width: var(--tool-icon-size, 16px);
    height: var(--tool-icon-size, 16px);
    object-fit: contain;
}

/* 回收站数量角标：安卓 App 图标式角标 —— 红底白字圆角小块 + 白色描边，
   悬在图标右上角（参考安卓桌面图标的通知角标设计） */
.trash-count {
    position: absolute;
    top: -7px;
    right: -9px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    border-radius: 8.5px;
    background: #ff3b30;
    color: #fff;
    font-size: 10.5px;
    font-weight: 700;
    line-height: 17px;
    text-align: center;
    box-sizing: border-box;
    border: 1.5px solid rgba(255, 255, 255, 0.95);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
    z-index: 2;
}

/* 窄屏（域框需要重排时由 JS 给 body 加 .compact-tools）：
   右侧管理工具栏只留图标、隐藏文字，按钮框同步收缩成小方块（--tool-btn-size），
   工具栏整体缩成一条窄列，给域框腾出横向空间 */
.btn-label { margin-left: 4px; }
body.compact-tools .board-footer .btn-label,
body.compact-tools .user-tab-align .btn-label { display: none; }
body.compact-tools .board-footer .btn {
    width: var(--tool-btn-size, 40px);
    height: var(--tool-btn-size, 40px);
    padding: 0;
    justify-content: center;
}
body.compact-tools .user-tab-align {
    width: var(--tool-btn-size, 40px);
    height: var(--tool-btn-size, 40px);
    padding: 0;
    justify-content: center;
}
/* 工具栏整体收缩成一条窄列；文档流布局（窄屏兜底）时保持底部横排，按钮各自收成小方块 */
body.compact-tools:not([data-layout="flow"]) .board-footer { width: var(--tool-btn-size, 40px); }

.empty-tip {
    text-align: center;
    color: var(--text-3);
    padding: 56px 20px;
    font-size: 14px;
}

/* 页脚：贴到浏览器最底部 */
.footer {
    flex: 0 0 auto;
    margin-top: auto;
    width: 100%;
    max-width: 1440px;
    margin-left: auto;
    margin-right: auto;
    padding: 16px 24px 14px;
    color: var(--text-3);
    font-size: 12px;
    text-align: center;
    border-top: 1px solid var(--border);
    /* 不透明度：页脚底色（默认 0 = 透明，维持原样）乘 --o-footer（0~1）。
       开了 Bing 背景图时，下面的 body[data-bg="on"] .footer 会覆盖成半透明白底保可读性。 */
    background: color-mix(in srgb, var(--surface) calc(var(--o-footer, 0) * 100%), transparent);
}

/* ------------------- 顶栏「使用统计」按钮（登录按钮右侧） ------------------- */

/* 固定在 header 里（不再悬浮 / 不可拖拽）；图标与底色可在「站点设置」自定义 */
/* 固定在 header 里（不再悬浮 / 不可拖拽）；图标与底色可在「站点设置」自定义。

   排版要点：它排在登录 / 退出登录按钮之后，但用「负 margin-right」抵消自己占的
   宽 + 间距（34 + 9 = 43px），于是它视觉上飘到顶栏内容区之外，
   而登录 / 退出登录按钮的右缘仍落在内容区右缘 —— 与下方 .hint 提示条右缘同线。

   飘出量做自适应：只飘「内容右缘到视口右缘的富余空间」这么多（留 8px 安全边距），
   屏幕不够宽时自动收敛到 0，退回正常流，绝不横向溢出。 */
.topbar-stats {
    flex: 0 0 auto;
    /* 自身宽 + 与前一按钮的间距（与 .topbar-right 的 gap 一致） */
    --stats-out: 43px;
    margin-right: calc(-1 * min(var(--stats-out),
        max(0px, (100vw - 1440px) / 2 + 16px)));
    width: 34px;
    height: 34px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    line-height: 1;
    /* 只要图标：无边框、无底色，颜色跟随主题文字色 */
    border: 0;
    background: none;
    border-radius: 10px;
    cursor: pointer;
    color: var(--text-2);
    transition: color .15s ease, transform .12s ease, filter .15s ease;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}

/* 里层图标：定时轮播动画加在外层按钮上、悬停动画加在这一层，
   同一个元素只能有一份 animation 声明，分两层才互不抢。
   .fab-ico 是统计按钮的历史类名，与 .ico-anim-inner 共用一套基础样式。 */
.fab-ico, .ico-anim-inner {
    display: inline-block;
    line-height: 1;
    /* 摆动类动画的支点略微下移，像挂着的牌子在晃 */
    transform-origin: 50% 62%;
}

.topbar-stats:hover {
    color: var(--primary);
    filter: drop-shadow(0 0 5px color-mix(in srgb, var(--primary) 45%, transparent));
}

.topbar-stats:active { transform: scale(.94); }

.topbar-stats:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   图标动画轮播：由 assets/app.js 定时给按钮（.ico-anim）加 class，7 种循环出现。
   使用统计 / 显示设置 / 天气 三个按钮共用，相位错开，同一时刻最多一个在动。
   只动 transform / filter，不占布局、不触发重排，也不影响按钮的可点击区域。
   -------------------------------------------------------------------------- */
@keyframes anim-pop {
    0% { transform: scale(1); }
    35% { transform: scale(1.45); }
    62% { transform: scale(.9); }
    100% { transform: scale(1); }
}
@keyframes anim-spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}
@keyframes anim-bounce {
    0%, 100% { transform: translateY(0); }
    25% { transform: translateY(-7px); }
    50% { transform: translateY(0); }
    75% { transform: translateY(-4px); }
}
@keyframes anim-flip {
    0% { transform: rotateY(0deg); }
    100% { transform: rotateY(360deg); }
}
@keyframes anim-swing {
    0%, 100% { transform: rotate(0deg); }
    20% { transform: rotate(16deg); }
    40% { transform: rotate(-14deg); }
    60% { transform: rotate(10deg); }
    80% { transform: rotate(-8deg); }
}
@keyframes anim-float {
    0%, 100% { transform: translateY(0) scale(1); }
    50% { transform: translateY(-6px) scale(1.14); }
}
@keyframes anim-glow {
    0%, 100% { transform: scale(1); filter: none; }
    50% { transform: scale(1.26); filter: drop-shadow(0 0 6px var(--primary)); }
}

.ico-anim.anim-pop    { animation: anim-pop .72s cubic-bezier(.34, 1.56, .64, 1); }
.ico-anim.anim-spin   { animation: anim-spin .9s cubic-bezier(.5, 0, .5, 1); }
.ico-anim.anim-bounce { animation: anim-bounce .8s ease-in-out; }
.ico-anim.anim-flip   { animation: anim-flip .9s ease-in-out; }
.ico-anim.anim-swing  { animation: anim-swing .9s ease-in-out; }
.ico-anim.anim-float  { animation: anim-float 1.1s ease-in-out; }
.ico-anim.anim-glow   { animation: anim-glow 1s ease-in-out; }

/* --------------------------------------------------------------------------
   悬停动画：鼠标停在图标上时持续摆动（1.4s 一轮、无限循环），移开立刻停。
   加在内层 .ico-anim-inner 上，和按钮上的轮播动画互不干扰。
   -------------------------------------------------------------------------- */
@keyframes anim-hover {
    0%, 100% { transform: rotate(0deg) translateY(0) scale(1.08); }
    25%      { transform: rotate(-13deg) translateY(-2px) scale(1.2); }
    50%      { transform: rotate(0deg) translateY(0) scale(1.08); }
    75%      { transform: rotate(13deg) translateY(-2px) scale(1.2); }
}

.ico-anim:hover .ico-anim-inner,
.ico-anim:focus-visible .ico-anim-inner {
    animation: anim-hover 1.4s ease-in-out infinite;
}

/* 尊重系统「减少动态效果」设置：动画整体关掉（含悬停），按钮仍完全可用 */
@media (prefers-reduced-motion: reduce) {
    .ico-anim.anim-pop, .ico-anim.anim-spin, .ico-anim.anim-bounce,
    .ico-anim.anim-flip, .ico-anim.anim-swing, .ico-anim.anim-float,
    .ico-anim.anim-glow { animation: none; }
    .ico-anim:hover .ico-anim-inner,
    .ico-anim:focus-visible .ico-anim-inner { animation: none; }
    .topbar-stats:hover { filter: none; }
    .fab-ico, .ico-anim-inner { transform: none; }
    /* 弹窗过渡的关闭见文件末尾的独立 media 块（必须排在 .modal 基础规则之后才能覆盖） */
}


@media (max-width: 640px) {
    .topbar-stats { width: 30px; height: 30px; font-size: 16px; }
}

/* 注：.brand-logo img 的样式已合并进前面的 .brand-logo 块（无边框 / 自适应 / 可自定义宽高） */

/* ------------------------- 页脚（行业标准三段式） ------------------------- */

.footer-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px 24px;
    flex-wrap: wrap;
    text-align: left;
}

.footer-info {
    flex: 1 1 240px;
    min-width: 0;
    color: var(--text-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.footer-copy {
    color: var(--text-3);
    white-space: nowrap;
}

@media (max-width: 640px) {
    .footer-inner { flex-direction: column; align-items: flex-start; }
    .footer-info { white-space: normal; }
}

/* ------------------------------- 弹窗 ---------------------------------- */

/*
 * 大小自适应策略：
 *   宽 = min(固定上限, 100vw - 32px)，窄窗口下自动收窄；
 *   高 = min(内容高度, 100vh - 32px)，超出时由 .modal-scroll 内部滚动。
 * 弹窗整体是 flex 纵向布局，头部固定、正文滚动，保存 / 取消 常驻右上角。
 */
/* 弹窗外层：全屏遮罩 + 居中容器。
   用 <dialog>.show()（非模态）打开，不进浏览器 top layer，
   避免触发 Bitwarden「页面在抢占顶层」的防干扰判定。 */
.modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 16px;
    /* 必须显式清掉 <dialog> 的 UA 默认盒模型，否则非模态下会露馅：
       UA 给的是 width/height: fit-content + margin: auto + background-color: canvas
       + border: 3px solid，于是卡片外会多出一圈「带底色的方框」（深色主题下就是黑灰方块）。 */
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    margin: 0;
    background: none;
    border: none;
    opacity: 1;
    transition: opacity .2s ease, display .2s ease allow-discrete;
}

.modal[open] { display: flex; }

/* 关闭过渡进行中（display allow-discrete 保持可见时）整体淡出。
   同时禁止命中：淡出的这 0.2s 里遮罩仍覆盖整个视口，
   不关掉 pointer-events 会吞掉这段时间内落在页面上的点击。 */
.modal:not([open]) { opacity: 0; pointer-events: none; }

/* 遮罩层：非模态 dialog 没有 ::backdrop，用 ::before 代替（z-index:-1 压在卡片下） */
.modal::before {
    content: '';
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, .48);
    backdrop-filter: blur(2px);
    z-index: -1;
}

/* 卡片本体：原 .modal 的卡片样式移到直接子元素（form / .modal-inner） */
.modal > form,
.modal > .modal-inner {
    border: none;
    border-radius: var(--radius);
    padding: 0;
    width: min(440px, calc(100vw - 32px));
    max-width: none;
    max-height: calc(100vh - 32px);
    overflow: hidden;
    box-shadow: var(--shadow-lg);
    color: var(--text);
    background: var(--surface);
    display: flex;
    flex-direction: column;
    opacity: 1;
    transform: translateY(0) scale(1);
    transition: opacity .2s ease, transform .2s ease;
}

/* 关闭态：卡片下移 + 缩小 + 透明 */
.modal:not([open]) > form,
.modal:not([open]) > .modal-inner {
    opacity: 0;
    transform: translateY(10px) scale(.97);
}

/* 打开起始态：从「下移 + 缩小 + 透明」过渡到正常，形成淡入上浮 */
@starting-style {
    .modal[open] > form,
    .modal[open] > .modal-inner {
        opacity: 0;
        transform: translateY(10px) scale(.97);
    }
}

.modal form { padding: 0; }
.modal .modal-inner { padding: 0; }

/* 头部：标题在左、操作按钮在右，横向不换行；内容过长时标题先省略 */
.modal-head {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--border);
    background: var(--surface-2);
}

.modal-title {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 15.5px;
    font-weight: 700;
    margin-bottom: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 右上角的按钮组：取消 / 保存 或 关闭 */
.modal-tools {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 8px;
}

.modal-tools .btn { padding: 6px 13px; font-size: 12.5px; }

/* 滚动区：弹窗高度不够时只滚这里，头部按钮始终可见。
   横向永远不滚（overflow-x: hidden）—— 表单是纵向流，
   行内元素都允许换行，任何情况下都不出现底部横向滚动条。 */
.modal-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
}

.modal-body {
    padding: 18px 16px 0;
    min-width: 0;
    max-width: 100%;
}

/* 表单行内的输入控件不允许把正文撑宽 */
.field,
.ts-field,
.color-field,
.emoji-field {
    min-width: 0;
    max-width: 100%;
}

.field input,
.field select,
.field textarea {
    max-width: 100%;
}

.modal-body > *:last-child { margin-bottom: 18px; }

/* 保存 / 取消 已移到右上角，底部不再需要按钮行；保留类名做兜底 */
.modal-footer {
    display: flex;
    justify-content: flex-end;
    gap: 9px;
    margin-top: 18px;
}

.field { margin-bottom: 13px; }

/* 并排字段行：相邻且 row 名相同的字段由 openForm 包进 .field-row，
   每个字段各占一半宽度（如「域名称 + 域类型」「图标 + 层级」） */
.field-row {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    margin-bottom: 13px;
}
.field-row > .field {
    flex: 1 1 0;
    min-width: 0;
    margin-bottom: 0;
}

.field label {
    display: block;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-2);
    margin-bottom: 5px;
}

.field input,
.field select,
.field textarea {
    width: 100%;
    padding: 9px 11px;
    border: 1px solid var(--border-strong);
    border-radius: 10px;
    font-size: 13.5px;
    font-family: inherit;
    color: var(--text);
    background: var(--surface);
    transition: border-color .15s, box-shadow .15s;
}

.field textarea { min-height: 66px; resize: vertical; line-height: 1.55; }

.field input::placeholder,
.field textarea::placeholder { color: #b3bccb; }

.field input:focus,
.field select:focus,
.field textarea:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, .14);
}

.field .tip { font-size: 11.5px; color: var(--text-3); margin-top: 4px; }

/* 下拉切换时把提示「闪」一下，让使用者注意到说明已随选择更新 */
.field .tip-flash {
    animation: tip-flash .9s ease-out;
    border-radius: 7px;
}
@keyframes tip-flash {
    0% { background: var(--primary-soft); box-shadow: 0 0 0 3px var(--primary-soft); color: var(--primary); }
    100% { background: transparent; box-shadow: none; color: var(--text-3); }
}

.confirm-text { font-size: 13.5px; color: var(--text-2); line-height: 1.7; white-space: pre-line; }

.modal-error {
    margin: 4px 16px 18px;
    padding: 8px 11px;
    border-radius: 9px;
    background: var(--danger-soft);
    border: 1px solid #f7cccc;
    color: var(--danger);
    font-size: 12.5px;
}

/* --------------------------- emoji 选择器 ------------------------------ */

.emoji-trigger {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 11px;
    border: 1px solid var(--border-strong);
    border-radius: 10px;
    background: var(--surface);
    cursor: pointer;
    text-align: left;
    transition: border-color .15s, box-shadow .15s;
}

.emoji-trigger:hover { border-color: var(--primary); }

.emoji-current {
    font-size: 19px;
    line-height: 1.2;
    width: 26px;
    text-align: center;
    flex: 0 0 auto;
}

.emoji-trigger-text { flex: 1 1 auto; font-size: 13px; color: var(--text-3); }

.emoji-caret { color: var(--text-3); font-size: 11px; }

/* 图标选择弹窗：比通用弹窗宽一点好放下整屏 emoji 网格（内联面板已废弃） */
/* 图标选择弹窗：分类不多、网格也不长，整个弹窗按内容自然撑开即可。
   绝对不要出滚动条——所以这里把内部所有滚动容器都关掉：
   .emoji-grid 原来的 overflow-y:auto 会被浏览器把 overflow-x 一起算成 auto，
   鼠标悬停放大某个格子时就冒出横向滚动条；.modal-scroll 同理。 */
.modal-emoji > form,
.modal-emoji > .modal-inner { width: min(720px, calc(100vw - 32px)); }
.modal-emoji .modal-scroll { overflow: visible; }
.modal-emoji .emoji-grid {
    /*
     * 图标库一个分类最多近 200 个，必须给高度上限并自己滚动。
     * overflow-x 要**显式**写 hidden：只写 overflow-y:auto 时浏览器会把横向也算成 auto，
     * 悬停放大格子就冒出一条横向滚动条（这个坑踩过一次，别再踩）。
     */
    max-height: min(52vh, 430px);
    overflow-y: auto;
    overflow-x: hidden;
    /* 留一圈内边距，悬停放大时不会被弹窗边缘切掉 */
    padding: 3px;
    grid-template-columns: repeat(10, 1fr);
}

/* 搜索行：输入 + 命中数量 */
.emoji-search-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 9px;
}

.emoji-search-row .emoji-search {
    flex: 1 1 auto;
    min-width: 0;
    padding: 6px 9px;
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    font-size: 13px;
    font-family: inherit;
    background: var(--surface);
    color: var(--text);
}

.emoji-search:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, .14);
}

.emoji-count { flex: 0 0 auto; font-size: 11.5px; color: var(--text-3); }

/* ------------------------------ 图标配色开关 -------------------------------
   「黑白 / 彩色」二选一。黑白 = 图标跟随当前文字颜色（默认，原来的行为）；
   彩色 = 品牌图标用官方品牌色（assets/brands.js 的 colors）、线性图标用主题蓝。
   选中结果写进图标值本身（ic:<id> / icc:<id>），所以这里纯粹是个切换按钮组。
   ------------------------------------------------------------------------- */
.emoji-tone-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 9px;
    flex-wrap: wrap;
}

.emoji-tone-label { font-size: 11.5px; font-weight: 600; color: var(--text-2); flex: 0 0 auto; }

.emoji-tone {
    display: inline-flex;
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    overflow: hidden;
    flex: 0 0 auto;
}

.emoji-tone-btn {
    padding: 3px 12px;
    border: 0;
    background: var(--surface);
    color: var(--text-2);
    font-size: 11.5px;
    font-weight: 600;
    cursor: pointer;
    transition: background .13s, color .13s;
}

.emoji-tone-btn + .emoji-tone-btn { border-left: 1px solid var(--border-strong); }
.emoji-tone-btn:hover { color: var(--primary); }

.emoji-tone-btn.is-active {
    background: var(--primary);
    color: #fff;
}

.emoji-tone-hint { font-size: 11px; color: var(--text-3); flex: 1 1 auto; min-width: 0; }

.emoji-empty {
    grid-column: 1 / -1;
    padding: 20px 4px;
    text-align: center;
    font-size: 12.5px;
    color: var(--text-3);
}

.emoji-tabs { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 9px; }

.emoji-tab {
    padding: 3px 10px;
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text-2);
    font-size: 11.5px;
    font-weight: 600;
    cursor: pointer;
    transition: all .13s;
}

.emoji-tab:hover { border-color: var(--primary); color: var(--primary); }

.emoji-tab.is-active {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
}

.emoji-grid {
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    gap: 4px;
    /* 不设 max-height / 不自建滚动容器：分组最多 24 个，天然就放得下 */
    padding: 3px;
}

.emoji-cell {
    /* 高度给到 44px：32px 的 emoji 上下各留 6px，悬停放大 1.08 也不会被切 */
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    /* emoji 的标准尺寸：32×32px（line-height 跟着走，免得行高把字形压小） */
    font-size: 32px;
    line-height: 32px;
    border: 1px solid transparent;
    border-radius: 8px;
    background: transparent;
    cursor: pointer;
    transition: background .12s, border-color .12s, transform .12s;
}

.emoji-cell:hover {
    background: var(--surface);
    border-color: var(--primary);
    transform: scale(1.08);
}

/* 线性图标格子：SVG 与 emoji 统一按 32×32px 渲染。
   不跟格子的 font-size 走（SVG 不吃 em），必须写死尺寸，否则 1544 个图标大小不一。
   32px + 悬停 scale(1.08)=34.6px，仍在 44px 格子里，不会被切。 */
.emoji-cell .nav-icon { width: 32px; height: 32px; }

/* 拟物彩色图标（图片形态：assets/winicons/*.svg）：同样统一按 32×32 渲染。
   <img> 不吃格子的 font-size，必须写死尺寸，否则会按 SVG 自带的 32px 固有尺寸乱跳。 */
.emoji-cell img {
    width: 32px;
    height: 32px;
    object-fit: contain;
    display: block;
    pointer-events: none;   /* 点击落在格子上（button），别让图片吞掉事件 */
}

.emoji-foot {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 9px;
    padding-top: 9px;
    border-top: 1px solid var(--border);
}

.emoji-foot span { font-size: 11.5px; color: var(--text-3); flex: 0 0 auto; }

.emoji-foot input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 6px 9px;
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    font-size: 13px;
    font-family: inherit;
    background: var(--surface);
    color: var(--text);
}

.emoji-foot input:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, .14);
}

/* ---------------------------- 图标选择 --------------------------------- */

.icon-field {
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: wrap;
}

.icon-preview {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface-2);
    overflow: hidden;
}

.icon-field input[type="text"] { flex: 1 1 150px; min-width: 130px; }

.icon-field .btn { flex: 0 0 auto; }

/* ------------------- 站点图标选择器（emoji + 图片 + 上传） ------------------- */

.siteicon-field {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.siteicon-row {
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: wrap;
}

.siteicon-preview {
    flex: 0 0 auto;
    width: 38px;
    height: 38px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 21px;
    line-height: 1;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface-2);
    overflow: hidden;
}

.siteicon-preview.is-image { padding: 0; }

.siteicon-preview img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.siteicon-row input[type="text"] { flex: 1 1 170px; min-width: 140px; }

.siteicon-row .btn { flex: 0 0 auto; }

/* ---------------------- 域外观：颜色 / 字体 / 预览 ---------------------- */

/* 颜色：预设色块 */
.color-field { display: flex; flex-direction: column; gap: 8px; }

.color-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.color-chip {
    width: 26px;
    height: 26px;
    padding: 0;
    border: 2px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    cursor: pointer;
    transition: transform .12s, border-color .12s, box-shadow .12s;
    font-size: 10px;
    font-weight: 600;
    color: var(--text-3);
    line-height: 1;
}

.color-chip:hover { transform: scale(1.1); border-color: var(--border-strong); }

.color-chip.is-reset {
    width: auto;
    min-width: 44px;
    padding: 0 8px;
    border-style: dashed;
    background: var(--surface-2);
}

.color-chip.is-active {
    border-color: var(--text);
    box-shadow: 0 0 0 2px rgba(37, 99, 235, .22);
}

.color-row {
    display: flex;
    align-items: center;
    gap: 7px;
}

/* .field input 的 width:100% 优先级更高，会把小色块撑满整行，
   把同行的颜色文本框 / 默认按钮挤出弹窗（横向溢出）——这里用更高优先级夺回宽度 */
.field input.color-picker {
    flex: 0 0 auto;
    width: 38px;
}

.color-row .btn { flex: 0 0 auto; }

.color-picker {
    flex: 0 0 auto;
    width: 38px;
    height: 34px;
    padding: 2px;
    border: 1px solid var(--border-strong);
    border-radius: 9px;
    background: var(--surface);
    cursor: pointer;
}

.color-text {
    flex: 1 1 auto;
    min-width: 0;
    padding: 8px 10px;
    border: 1px solid var(--border-strong);
    border-radius: 9px;
    font-size: 13px;
    font-family: Consolas, Monaco, monospace;
    color: var(--text);
    background: var(--surface);
}

.color-text:focus,
.color-picker:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, .14);
}

/* 文字样式：字号 + 字族 + 斜体 + 颜色 */
.ts-field { display: flex; flex-direction: column; gap: 8px; }

.ts-row {
    display: flex;
    align-items: center;
    gap: 7px;
    flex-wrap: wrap;
}

.ts-inline-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-3);
    flex: 0 0 auto;
    margin: 0;
}

.ts-size,
.ts-row input[type="number"] {
    width: 72px;
    flex: 0 0 auto;
    padding: 7px 9px;
    border: 1px solid var(--border-strong);
    border-radius: 9px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text);
    background: var(--surface);
}

.ts-unit { font-size: 12px; color: var(--text-3); flex: 0 0 auto; }

.ts-font {
    flex: 1 1 110px;
    min-width: 100px;
    padding: 7px 9px;
    border: 1px solid var(--border-strong);
    border-radius: 9px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text);
    background: var(--surface);
}

.ts-italic {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12.5px;
    color: var(--text-2);
    flex: 0 0 auto;
    cursor: pointer;
    margin: 0;
}

.ts-italic input { width: auto; margin: 0; cursor: pointer; }

/* 登录框「记住用户名和密码」勾选行。
   注意选择器权重：`.field label`（0,1,1）会按住 `.checkbox-line`（0,1,0），
   不把权重提到 `.field label.checkbox-line` 的话，这一行会被算成 display:block，
   flex + gap 失效 —— 复选框和后面的文字就贴在一起没有间距了。 */
.field-check { margin-top: 4px; }
.field label.checkbox-line {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-2);
    margin: 0;
    cursor: pointer;
}
.field label.checkbox-line span { font-weight: 500; margin: 0; }
.field label.checkbox-line input { width: 16px; height: 16px; margin: 0; flex: 0 0 auto; cursor: pointer; }

.ts-chips { padding-top: 1px; }

.ts-size:focus,
.ts-font:focus,
.ts-row input[type="number"]:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, .14);
}

/* 表单里的效果预览 */
.dm-preview {
    --dm-accent: var(--primary);
    --dm-title-size: 14px;
    --dm-note-size: 11px;
    margin-top: 2px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--dm-accent) 7%, #ffffff),
        var(--surface));
}

.dm-preview-head {
    display: flex;
    align-items: center;
    gap: 9px;
}

.dm-preview-icon {
    font-size: calc(var(--dm-icon-size, 42px) * 0.5);
    line-height: 1;
    width: var(--dm-icon-size, 42px);
    height: var(--dm-icon-size, 42px);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    background: color-mix(in srgb, var(--dm-accent) 12%, #ffffff);
    border: 1px solid color-mix(in srgb, var(--dm-accent) 30%, #ffffff);
    flex: 0 0 auto;
    overflow: hidden;
}

.dm-preview-title {
    font-size: var(--dm-title-size, 14px);
    font-weight: 700;
    color: var(--dm-title-color, var(--text));
    font-family: var(--dm-title-font, inherit);
    font-style: var(--dm-title-style, normal);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dm-preview-note {
    margin-top: 2px;
    font-size: var(--dm-note-size, 11px);
    color: var(--dm-note-color, var(--text-3));
    font-family: var(--dm-note-font, inherit);
    font-style: var(--dm-note-style, normal);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ------------------------------- Toast --------------------------------- */

.toast {
    position: fixed;
    left: 50%;
    bottom: 34px;
    transform: translateX(-50%) translateY(12px);
    background: #111827;
    color: #fff;
    font-size: 13px;
    padding: 10px 18px;
    border-radius: 11px;
    box-shadow: var(--shadow-lg);
    opacity: 0;
    transition: opacity .2s, transform .2s;
    z-index: 100;
    pointer-events: none;
}

.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

.toast.error { background: var(--danger); }

/* --------------------- 自定义悬停提示（现代 tooltip） --------------------- */
/*
 * 统一用 #navTip 浮层替代浏览器原生 title：
 *   毛玻璃气泡 + 指向元素的小箭头 + 带方向的弹出动效（缩放 + 从按钮那一侧滑入）。
 * 提示文字写在 data-tip 上；原生 title 会在首次悬停时自动迁移到 data-tip 并移除，
 * 因此既有 title 赋值无需改动，也不会出现「原生 + 自定义」双重提示。
 *
 * 可自定义（「帮助模块 → 提示框外观」，app.js 写内联变量）：
 *   --tip-bg   气泡底色（含箭头），留空用默认深色
 *   --tip-fg   文字颜色，留空用默认浅色
 *   --tip-line 气泡描边，留空用默认浅描边
 *   --tip-arrow / --tip-arrow-y  箭头相对气泡的位置（由 JS 按目标位置算）
 * 弹出位置四档：tip-top / tip-bottom / tip-left / tip-right。
 */
.nav-tip {
    position: fixed;
    z-index: 10000;
    max-width: 280px;
    padding: 8px 12px;
    background: var(--tip-bg, rgba(17, 24, 39, .96));
    color: var(--tip-fg, #f8fafc);
    font-size: 12.5px;
    line-height: 1.5;
    font-weight: 500;
    letter-spacing: .2px;
    border-radius: 10px;
    border: 1px solid var(--tip-line, rgba(255, 255, 255, .08));
    /* 阴影由 JS 按「每个按钮自己那一档」算好写进 --tip-shadow（无 / 弱 / 中 / 强，
       自定框底色时投影跟着底色走）；这条兜底值 = 中档，老配置不写 shadow 时观感不变 */
    box-shadow: var(--tip-shadow, 0 10px 28px rgba(15, 23, 42, .34), 0 2px 6px rgba(15, 23, 42, .18));
    backdrop-filter: blur(8px) saturate(150%);
    -webkit-backdrop-filter: blur(8px) saturate(150%);
    white-space: pre-line;
    pointer-events: none;
    opacity: 0;
    /* 默认（在按钮上方）：从下往上「顶」出来，缩放锚在底部（箭头那一侧） */
    transform: translateY(6px) scale(.94);
    transform-origin: 50% 100%;
    /* 回弹感的缓动曲线，比线性淡入更像「弹出」 */
    transition: opacity .15s ease, transform .22s cubic-bezier(.16, 1, .3, 1);
    will-change: transform, opacity;
}

/* 四个方向的起手姿态：从按钮那一侧滑入，缩放锚点也放在靠按钮那一侧 */
.nav-tip.tip-bottom { transform: translateY(-6px) scale(.94); transform-origin: 50% 0; }
.nav-tip.tip-left   { transform: translateX(7px)  scale(.94); transform-origin: 100% 50%; }
.nav-tip.tip-right  { transform: translateX(-7px) scale(.94); transform-origin: 0 50%; }

.nav-tip.show { opacity: 1; transform: translate(0, 0) scale(1); }

/* 指向目标元素的小箭头（旋转方块裁出三角感）。
   删掉「朝向气泡内部」的两条边，剩下的两条边在旋转后正好拼出指向目标的尖角。 */
.nav-tip::after {
    content: '';
    position: absolute;
    width: 8px;
    height: 8px;
    background: var(--tip-bg, rgba(17, 24, 39, .96));
    border: 1px solid var(--tip-line, rgba(255, 255, 255, .08));
}
.nav-tip.tip-top::after {
    left: var(--tip-arrow, 50%);
    bottom: -5px;
    transform: translateX(-50%) rotate(45deg);
    border-top: 0;
    border-left: 0;
}
.nav-tip.tip-bottom::after {
    left: var(--tip-arrow, 50%);
    top: -5px;
    transform: translateX(-50%) rotate(45deg);
    border-bottom: 0;
    border-right: 0;
}
.nav-tip.tip-left::after {
    top: var(--tip-arrow-y, 50%);
    right: -5px;
    transform: translateY(-50%) rotate(45deg);
    border-left: 0;
    border-bottom: 0;
}
.nav-tip.tip-right::after {
    top: var(--tip-arrow-y, 50%);
    left: -5px;
    transform: translateY(-50%) rotate(45deg);
    border-top: 0;
    border-right: 0;
}

@media (prefers-reduced-motion: reduce) {
    .nav-tip { transition: none; transform: none; }
    .nav-tip.show { transform: none; }
}

/* --------------------------- 登录状态 / 账号 --------------------------- */
/* 注：顶栏原来的「用户 chip」（头像 + 用户名 + 角色）已移除，相关样式一并删除 */

.form-tip {
    margin-bottom: 14px;
    padding: 9px 11px;
    border-radius: 9px;
    background: var(--primary-soft);
    border: 1px solid var(--primary-border);
    color: #1e40af;
    font-size: 12.5px;
    line-height: 1.6;
}

.modal-wide > form,
.modal-wide > .modal-inner { width: min(760px, calc(100vw - 32px)); }

.modal-inner { padding: 0; }

.text-3 { color: var(--text-3); }

.account-block {
    padding: 0 0 18px;
    margin-bottom: 18px;
    border-bottom: 1px solid var(--border);
}

/* 最后一块不再画分隔线，也不要自己抹掉底部间距——底部留白统一交给
   .modal-body > *:last-child 的 margin-bottom（否则「创建账号」按钮会贴着弹窗底边）。
   padding-bottom 也要留一点，按钮下方才不显得顶到边。 */
.account-block:last-child { border-bottom: none; padding-bottom: 0; }

.account-block h4 {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13.5px;
    font-weight: 700;
    margin-bottom: 11px;
}

.account-count {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-3);
    background: var(--surface-3);
    border-radius: 999px;
    padding: 1px 8px;
}

.account-note { font-size: 12.5px; color: var(--text-2); margin-bottom: 12px; }

.account-grid { display: grid; gap: 12px; }
.account-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.account-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.account-grid .field { margin-bottom: 0; }

.account-actions { margin-top: 14px; display: flex; justify-content: flex-end; }

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

.account-table th {
    text-align: left;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-2);
    padding: 8px 10px;
    border-bottom: 1px solid var(--border);
    background: var(--surface-2);
}

.account-table th:first-child { border-top-left-radius: 10px; }
.account-table th:last-child { border-top-right-radius: 10px; }

.account-table td {
    padding: 9px 10px;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}

.account-table tbody tr:last-child td { border-bottom: none; }

.account-table .col-time { color: var(--text-3); font-size: 12px; white-space: nowrap; }
.account-table .col-act { text-align: right; white-space: nowrap; }

.account-empty { text-align: center; color: var(--text-3); padding: 18px 0; }

.tag {
    display: inline-block;
    font-size: 11px;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--surface-3);
    color: var(--text-2);
}

.tag-admin { background: var(--primary-soft); color: var(--primary-dark); }
.tag-me { background: var(--success-soft); color: var(--success); }

/* ------------------------------- 响应式 -------------------------------- */

@media (max-width: 880px) {
    .wrap { padding-bottom: 24px; }
}

/* 中窄屏（含 645 / 886 这类出过畸形的宽度）：顶栏允许换行，
   品牌区独占整行（标题不再被右侧按钮挤成竖排），工具栏按钮整行换行铺在下面 */
@media (max-width: 960px) {
    .topbar-inner { flex-wrap: wrap; row-gap: 8px; }
    .brand { flex: 1 1 100%; }
    .topbar-right { flex: 1 1 100%; justify-content: flex-start; flex-wrap: wrap; }
}

@media (max-width: 640px) {
    .topbar-inner, .wrap, .footer { padding-left: 14px; padding-right: 14px; }
    .topbar-inner { flex-wrap: wrap; }
    .brand-text p { display: none; }
    .hint { font-size: 12px; }
    .account-grid-3, .account-grid-4 { grid-template-columns: 1fr; }
    /* 六列而非十列：32px 的 emoji / 线性图标在窄窗口下十列会被挤到贴边 */
    .emoji-grid,
    .modal-emoji .emoji-grid { grid-template-columns: repeat(6, 1fr); }
    .setting-grid { grid-template-columns: 1fr; }
    /* 并排的设置块在窄窗口里改成上下排列 */
    .settings-row { grid-template-columns: 1fr; }
    .api-params { grid-template-columns: 1fr; }

    /* 弹窗：小窗口下四周只留 10px，正文内边距同步收紧 */
    .modal > form,
    .modal > .modal-inner,
    .modal-wide > form,
    .modal-wide > .modal-inner {
        width: calc(100vw - 20px);
        max-height: calc(100vh - 20px);
    }
    .modal-head { padding: 11px 12px; }
    .modal-title { font-size: 14.5px; }
    .modal-tools .btn { padding: 5px 11px; font-size: 12px; }
    .modal-body { padding: 14px 12px 0; }
    .modal-error { margin: 4px 12px 14px; }
}

/* 极窄窗口（手机竖屏）：顶栏按钮换行铺满，避免挤压品牌区 */
@media (max-width: 420px) {
    .topbar-inner { padding-top: 9px; padding-bottom: 9px; }
    .topbar-right { flex-wrap: wrap; justify-content: flex-end; row-gap: 6px; }
    .brand-logo { width: 32px; height: 32px; font-size: 18px; }
    .brand-text h1 { font-size: 16px; }

    /* 浮动按钮在极窄窗口里统一退回内联，避免遮挡 */
    .link-actions {
        position: static;
        padding: 0;
        background: none;
        box-shadow: none;
        transform: none;
    }
    .link-actions .icon-btn { width: 22px; height: 22px; font-size: 12px; }
}

/* ==========================================================================
   Bing 每日一图背景
   背景层固定在视口最底层（z-index: -1），模糊 / 亮度由 JS 写到内联 filter 上。
   开启时把 body 自身的渐变底色去掉，否则会盖住图片。
   ========================================================================== */

html { background: var(--bg); }

/* 往外扩 26px：blur 会让边缘变透明，扩出去就看不到虚边了 */
.bg-layer {
    position: fixed;
    inset: -26px;
    z-index: -1;
    background-color: var(--bg);
    background-position: center center;
    background-size: cover;
    background-repeat: no-repeat;
    pointer-events: none;
    transition: filter .18s linear, opacity .45s ease;
}

body[data-bg="on"] { background: none; }

/* 开了背景图时，纯文字区块给一层半透明白底，保证可读性 */
body[data-bg="on"] .hint,
body[data-bg="on"] .empty-tip,
body[data-bg="on"] .footer { backdrop-filter: blur(2px); }

body[data-bg="on"] .hint { background: rgba(237, 243, 255, .94); }
body[data-bg="on"] .hint-warn { background: rgba(255, 246, 230, .94); }
body[data-bg="on"] .empty-tip { background: rgba(248, 250, 253, .92); }
/* 开了背景图：页脚底色同样听用户的 --o-footer（默认 0 = 不给底色）。
   这里**不能**写死一个半透明白底 —— 那条线的优先级比上面的 .footer 基础规则还高，
   会把滑块调出来的值整个盖掉，表现成「页脚不透明度怎么拉都没反应」。 */
body[data-bg="on"] .footer {
    background: color-mix(in srgb, var(--surface) calc(var(--o-footer, 0) * 100%), transparent);
}

/* ==========================================================================
   网址可达性徽标（类 tcping）
   贴在网址框右侧，竖排两行：上行「状态点 + 延时」，下行「丢包率」。
   徽标定宽 + 上下撑满，所以一行行网址排下去，徽标是齐的。

   外观：**只有文字**（+ 一个状态圆点）——不画边框、不铺底色，
   状态全靠文字颜色与圆点区分（绿＝可达 / 琥珀＝丢包 / 红＝不可达 / 灰＝检测中）。
   定宽 66px 与负边距保留：多行网址下来刻度一致、左右对齐，且上下贴齐网址框。
   ========================================================================== */

.link-probe {
    flex: 0 0 auto;
    align-self: stretch;          /* 撑满网址框的上下空间 */
    box-sizing: border-box;
    /* 负外边距抵消 .link 的 6px 上下内边距：让徽标的上下边正好贴齐网址框的边框，
       多行网址排下来徽标是「顶天立地」的，两行的字也就有充足空间，不会被裁。 */
    margin-top: -6px;
    margin-bottom: -6px;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    width: 66px;                  /* 定宽：多行网址时刻度一致、左右对齐 */
    padding: 2px 4px;
    border: 0;
    background: none;
    font-size: 11px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--text-3);
    white-space: nowrap;
    overflow: hidden;
    user-select: none;
    transition: color .15s;
}

/* 第一行：状态点 + 延时（行高给足，中文字形上下都不裁） */
.probe-line {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    max-width: 100%;
    font-size: 11px;
    line-height: 15px;
}

/* 第二行：丢包率（比第一行再小一号，保证「丢包 100%」这种最长文案也放得下） */
.probe-loss {
    font-size: 9.5px;
    font-weight: 600;
    line-height: 13px;
    opacity: .92;
    max-width: 100%;
    /* 正常情况一整个都放得下；真遇到超窄的网址框才退化成省略号 */
    overflow: hidden;
    text-overflow: ellipsis;
}

.probe-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--text-3);
    flex: 0 0 auto;
}

/* 可达：绿字 + 实心绿点（无边框无底色，靠颜色表达状态） */
.link-probe.is-ok {
    color: #0b7a44;
}
.link-probe.is-ok .probe-dot { background: var(--success); }

/* 线路质量中 / 差（丢包率高）：这一轮可能仍连得上，但要用警示色提醒 */
.link-probe.is-warn {
    color: #92600a;
}
.link-probe.is-warn .probe-dot { background: var(--warn); }

/* 「沿用上次数据」：本轮没连上但还不到判定阈值（连续 2 次失败才算不可达）。
   用成功色 + 空心圆点区分于真正的实时可达，既不吓人也不隐瞒。 */
.link-probe.is-stale {
    color: #0b7a44;
}
.link-probe.is-stale .probe-dot {
    background: transparent;
    border: 1.5px solid var(--success);
}

.link-probe.is-fail {
    color: var(--danger-dark);
}
.link-probe.is-fail .probe-dot { background: var(--danger); }

.link-probe.is-pending { color: var(--text-3); }
.link-probe.is-pending .probe-dot {
    background: var(--text-3);
    animation: probe-pulse 1s ease-in-out infinite;
}

/* 探测接口本身出错（服务端 4xx/5xx：data/ 不可写、PHP-FPM 未启动、超时…）：
   这不是「目标站不通」，所以不用红色，改成灰色空心点，
   tooltip 里能看到服务端返回的原文，鼠标一悬停就知道是环境问题还是网站问题。 */
.link-probe.is-api-error {
    color: var(--text-3);
}
.link-probe.is-api-error .probe-dot {
    background: transparent;
    border: 1.5px solid var(--text-3);
}

/* --------------------------------------------------------------------------
   延时 / 丢包「各自分色」：延时按 ms 分档（q-fast / q-mid / q-slow），
   丢包按丢包率分档（q-clean / q-mid / q-high）。两行独立着色，
   所以同一个徽标里能出现「绿延时 + 琥珀丢包」这种组合。
   这些类加在 .probe-text / .probe-loss 上，优先级高于徽标状态色（直接设 color），
   没传 levels 的状态行（已禁用 / 检测中 / 异常）不挂这些类，回落到徽标状态色。
   -------------------------------------------------------------------------- */
.probe-text.q-fast   { color: var(--success); }
.probe-text.q-mid    { color: var(--warn); }
.probe-text.q-slow   { color: var(--danger-dark); }

.probe-loss.q-clean  { color: var(--success); }
.probe-loss.q-mid    { color: var(--warn); }
.probe-loss.q-high   { color: var(--danger-dark); }

@keyframes probe-pulse {
    0%, 100% { opacity: .35; }
    50%      { opacity: 1; }
}

/* 窄屏文档流里徽标仍保持两行，只是更窄一点，别抢正文空间 */
/* 文档流布局下网址框是高度自适应的，徽标也照样抵消内边距贴到框边，
   只是字号收一点，窄屏不抢正文空间。 */
body[data-layout="flow"] .link {
    /* 给个下限，避免徽标两行的内容把网址框撑得比旁边高一个头 */
    min-height: 54px;
}
body[data-layout="flow"] .link-probe {
    font-size: 10px;
    width: 58px;
    padding: 3px 3px;
}
body[data-layout="flow"] .probe-line { font-size: 10px; line-height: 14px; }
body[data-layout="flow"] .probe-loss { font-size: 9px; line-height: 12px; }

/* ==========================================================================
   显示设置面板
   ========================================================================== */

.setting-block {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    padding: 14px;
    margin-bottom: 14px;
}

.setting-block > h4 {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-size: 13.5px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 6px;
}

.setting-note {
    font-size: 12px;
    color: var(--text-2);
    line-height: 1.65;
    margin-bottom: 10px;
}

.setting-note b { color: var(--text); }

.setting-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px 14px;
    margin-bottom: 10px;
}

/* 两个设置块并排（「网址可达性检测」+「天气城市」）：
   · 两块各自是完整的一张卡片，并排后高度按内容各自撑开；
   · 只有一块时（未登录看不到「天气城市」）自动占满整行，不会只画半张。
   .setting-block 自带 margin-bottom，进网格后由这一层统一控制间距。 */
.settings-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 14px;
    /* 两块卡片拉成等高：下沿对齐，看着才像一组 */
    align-items: stretch;
    margin-bottom: 14px;
}

.settings-row > .setting-block { margin-bottom: 0; }
.settings-row > .setting-block:only-child { grid-column: 1 / -1; }

.setting-field { min-width: 0; }

/* 独占一行的设置项（例如「背景更新方式」开关） */
.setting-field-wide { grid-column: 1 / -1; }

.setting-field .tip { font-size: 11.5px; color: var(--text-3); margin-top: 5px; line-height: 1.55; }

/* .setting-field 的第一个 label 走「块级小标题」样式，但开关本身就是个 label，
   别被那条规则改掉排版（display/font-size/margin 都要还原成 .switch 的）。 */
.setting-field > label.switch {
    display: inline-flex;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-2);
    margin-bottom: 0;
}

.setting-field > label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-2);
    margin-bottom: 4px;
}

.setting-field select,
.setting-field input[type="text"] {
    width: 100%;
    padding: 6px 9px;
    font-size: 12.5px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
}

.setting-range {
    display: flex;
    align-items: center;
    gap: 8px;
}

.setting-range input[type="range"] {
    flex: 1 1 auto;
    min-width: 0;
    accent-color: var(--primary);
}

.setting-range .range-val {
    flex: 0 0 auto;
    min-width: 48px;
    text-align: right;
    font-size: 12px;
    font-weight: 600;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.setting-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 4px;
}

/* 开关（原生 checkbox 外观重绘） */
.switch {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    cursor: pointer;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-2);
    flex: 0 0 auto;
}

.switch input { position: absolute; opacity: 0; width: 0; height: 0; }

.switch .switch-track {
    width: 38px;
    height: 21px;
    border-radius: 999px;
    background: var(--border-strong);
    position: relative;
    transition: background .16s;
    flex: 0 0 auto;
}

.switch .switch-track::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 17px;
    height: 17px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(15, 23, 42, .28);
    transition: transform .16s;
}

.switch input:checked + .switch-track { background: var(--primary); }
.switch input:checked + .switch-track::after { transform: translateX(17px); }
.switch input:focus-visible + .switch-track { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Bing 图片选择 */
.bg-picks {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 8px;
    margin-bottom: 12px;
}

.bg-picks-empty {
    grid-column: 1 / -1;
    font-size: 12px;
    color: var(--text-3);
    padding: 10px 0;
}

.bg-pick {
    position: relative;
    padding: 0;
    border: 2px solid var(--border);
    border-radius: 10px;
    background: var(--surface-3);
    aspect-ratio: 16 / 10;
    overflow: hidden;
    cursor: pointer;
    transition: border-color .15s, transform .15s;
}

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

.bg-pick:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.bg-pick.is-active { border-color: var(--primary); box-shadow: 0 0 0 2px var(--primary-soft); }

.bg-pick .bg-pick-tag {
    position: absolute;
    left: 5px;
    bottom: 5px;
    max-width: calc(100% - 10px);
    padding: 1px 6px;
    border-radius: 999px;
    background: rgba(15, 23, 42, .62);
    color: #fff;
    font-size: 10px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ==========================================================================
   接口调试面板
   ========================================================================== */

.modal-debug > form,
.modal-debug > .modal-inner { width: min(1080px, calc(100vw - 32px)); }

.debug-runtime {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    padding: 11px 13px;
    border: 1px solid var(--primary-border);
    border-radius: var(--radius-sm);
    background: var(--primary-soft);
    font-size: 12px;
    color: #1e40af;
    margin-bottom: 14px;
}

.debug-runtime b { color: #14306f; font-weight: 700; }

/* 部署自检：可写/不可写、容器标记、修复提示 */
.debug-runtime b.is-ok { color: #1b7f3b; }
.debug-runtime b.is-bad { color: #c62828; }
.debug-runtime .debug-tag {
    font-style: normal;
    font-size: 11px;
    padding: 0 5px;
    margin-left: 2px;
    border-radius: 4px;
    background: rgba(30, 64, 175, 0.12);
    color: #14306f;
}
.debug-runtime .debug-hint {
    flex-basis: 100%;
    color: #b3261e;
    background: #fdeceb;
    border: 1px solid #f6c9c5;
    border-radius: 6px;
    padding: 6px 9px;
    line-height: 1.5;
    word-break: break-all;
}

/* 分类 tab 条：按接口用途分页，一次只看一类 */
.debug-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    margin-bottom: 12px;
}

.debug-tab {
    font-size: 12.5px;
    line-height: 1;
    padding: 7px 12px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text-2);
    cursor: pointer;
    transition: background .15s, color .15s, border-color .15s;
}

.debug-tab:hover { border-color: var(--border-strong); color: var(--text); }

.debug-tab.is-active {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
    font-weight: 600;
}

/* 搜索时忽略分类：tab 条变灰、不可点 */
.debug-tabs.is-filtered .debug-tab { opacity: .5; pointer-events: none; }

.debug-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}

.debug-toolbar input[type="search"] {
    flex: 1 1 auto;
    min-width: 0;
    padding: 7px 11px;
    font-size: 12.5px;
    border: 1px solid var(--border);
    border-radius: 9px;
    background: var(--surface);
    color: var(--text);
}

.debug-count { font-size: 12px; color: var(--text-3); flex: 0 0 auto; }

.api-group-title {
    font-size: 12px;
    font-weight: 700;
    color: var(--text-3);
    letter-spacing: .04em;
    margin: 16px 0 8px;
    padding-bottom: 6px;
    border-bottom: 1px dashed var(--border);
}

.api-card {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    padding: 11px 12px;
    margin-bottom: 10px;
}

.api-card.is-write { border-left: 3px solid var(--warn); }
.api-card.is-danger { border-left: 3px solid var(--danger); }

.api-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 5px;
}

.api-action {
    font-family: Consolas, Monaco, "Courier New", monospace;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--text);
    background: var(--surface-3);
    border-radius: 6px;
    padding: 2px 7px;
}

.api-badge {
    font-size: 10.5px;
    font-weight: 700;
    padding: 1px 7px;
    border-radius: 999px;
    border: 1px solid var(--border);
    color: var(--text-2);
    background: var(--surface-2);
}

.api-badge.is-public { color: #0b7a44; border-color: #b7e2ca; background: var(--success-soft); }
.api-badge.is-login  { color: var(--primary-dark); border-color: var(--primary-border); background: var(--primary-soft); }
.api-badge.is-admin  { color: #8a5600; border-color: var(--warn-border); background: var(--warn-soft); }
.api-badge.is-danger { color: var(--danger-dark); border-color: #f3c2c2; background: var(--danger-soft); }

.api-desc { font-size: 12px; color: var(--text-2); line-height: 1.6; margin-bottom: 8px; }

.api-params {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px 10px;
    margin-bottom: 9px;
}

.api-params:empty { display: none; }

.api-param { min-width: 0; }
.api-param > span {
    display: block;
    font-size: 11px;
    font-weight: 600;
    color: var(--text-3);
    margin-bottom: 3px;
    font-family: Consolas, Monaco, "Courier New", monospace;
}
.api-param input,
.api-param textarea {
    width: 100%;
    padding: 5px 8px;
    font-size: 12px;
    border: 1px solid var(--border);
    border-radius: 7px;
    background: var(--surface-2);
    color: var(--text);
    font-family: Consolas, Monaco, "Courier New", monospace;
}
.api-param textarea { min-height: 56px; resize: vertical; }
.api-param .api-param-hint { font-size: 10.5px; color: var(--text-3); margin-top: 2px; }

.api-tools { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }

.api-result {
    margin: 9px 0 0;
    padding: 9px 11px;
    border-radius: 8px;
    background: #0f172a;
    color: #e2e8f0;
    font-family: Consolas, Monaco, "Courier New", monospace;
    font-size: 11.5px;
    line-height: 1.6;
    max-height: 300px;
    overflow: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.api-result .res-head { color: #93c5fd; font-weight: 700; }
.api-result.is-error .res-head { color: #fca5a5; }

.api-result[hidden] { display: none; }

/* ==========================================================================
   北京时间 + 本地天气（头部中间）
   ========================================================================== */

.nowbar {
    position: relative;
    display: flex;
    align-items: center;
    gap: 14px;
    margin-left: auto;          /* 把时间 / 天气推到标题与右侧按钮之间 */
    padding: 0 4px;
    min-width: 0;

    /* 时钟与天气是「两行」排版，两边共用同一套行高与行距，
       这样第一行（时间 / 温度）与第二行（日期 / 城市）都能各自水平对齐 */
    --nowbar-row1: 20px;        /* 上行：时间 / 天气温度 */
    --nowbar-row2: 15px;        /* 下行：日期 / 城市 */
    --nowbar-row-gap: 6px;      /* 上下两行之间的间距（原先偏挤，这里加大） */
}

.now-clock {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--nowbar-row-gap);
    white-space: nowrap;
}

.now-time {
    display: block;
    height: var(--nowbar-row1);
    line-height: var(--nowbar-row1);
    font-size: 17px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;   /* 等宽数字：秒跳动时不会左右抖 */
    letter-spacing: .4px;
    color: var(--text);
}

.now-date {
    display: block;
    height: var(--nowbar-row2);
    line-height: var(--nowbar-row2);
    font-size: 11px;
    color: var(--text-3);
}

/* 天气：与左侧时间同样的排版（上行大字 / 下行小字），无边框无背景 */
.now-weather {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--nowbar-row-gap);   /* 与时钟用同一个行距 */
    padding: 0;
    border: none;
    background: none;
    color: inherit;
    font: inherit;
    cursor: pointer;
    max-width: 260px;
    white-space: nowrap;
    transition: color .15s, opacity .15s;
}

.now-weather:hover { opacity: .78; }
.now-weather.is-error { color: var(--warn, #c2740a); }

/* 上行：与 .now-time 同高（--nowbar-row1），保证两者顶边 / 基线对齐 */
.wx-top {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    height: var(--nowbar-row1);
    line-height: var(--nowbar-row1);
}

.wx-icon { font-size: 15px; line-height: 1; }

.wx-temp {
    font-size: 17px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;   /* 与 .now-time 保持一致的视觉分量 */
    letter-spacing: .2px;
    color: var(--text);
}

/* 下行：与 .now-date 同高（--nowbar-row2） */
.wx-city {
    display: block;
    height: var(--nowbar-row2);
    line-height: var(--nowbar-row2);
    font-size: 11px;
    color: var(--text-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 170px;
}
.wx-caret { font-size: 8px; color: var(--text-3); }

/* 天气详情浮层 */
.wx-pop {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    width: 268px;
    padding: 12px 13px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    box-shadow: var(--shadow-md);
    z-index: 60;
}

.wx-pop-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 13px;
    font-weight: 700;
    margin-bottom: 9px;
}

.wx-refresh {
    border: 1px solid var(--border);
    background: var(--surface-2);
    border-radius: 7px;
    padding: 1px 7px;
    font-size: 12px;
    cursor: pointer;
    color: var(--text-2);
}
.wx-refresh:hover { background: var(--primary-soft); border-color: var(--primary-border); }

.wx-day {
    display: grid;
    grid-template-columns: 34px 1fr auto;
    align-items: center;
    gap: 8px;
    padding: 5px 0;
    font-size: 12px;
    border-top: 1px dashed var(--border);
}
.wx-day:first-child { border-top: 0; }
.wx-day .wx-day-name { color: var(--text-2); }
.wx-day .wx-day-icon { font-size: 14px; margin-right: 4px; }
.wx-day .wx-day-temp { font-variant-numeric: tabular-nums; color: var(--text); font-weight: 600; }

.wx-pop-foot {
    margin-top: 9px;
    padding-top: 7px;
    border-top: 1px solid var(--border);
    font-size: 11px;
    color: var(--text-3);
    line-height: 1.6;
}

/* ==========================================================================
   使用统计弹窗（由右侧悬浮按钮 #statsFab 唤起）
   要求：弹窗居中（.modal 用 flex 水平垂直居中，非模态 dialog 不进 top layer）、内容完整展示、
   任何情况下不出现上下或左右滚动条 —— 高度不够时压缩图表与行数而非滚动。
   ========================================================================== */

.modal-stats > form,
.modal-stats > .modal-inner { width: min(940px, calc(100vw - 32px)); }

/* 弹窗正文：固定不滚动，内容按可用高度自适应收缩 */
.modal-stats .modal-stats-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    padding: 14px 16px 16px;
    display: flex;
    flex-direction: column;
}

.stats-sub { font-size: 11.5px; font-weight: 400; color: var(--text-3); margin-left: 6px; }

.stats-updated { font-size: 11px; color: var(--text-3); }

.btn-xs { padding: 3px 9px; font-size: 11.5px; border-radius: 8px; }

/* --- KPI 磁贴 --- */
.stats-kpis {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
}

.kpi {
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: linear-gradient(180deg, var(--surface-2), var(--surface));
}

.kpi-label { font-size: 11.5px; color: var(--text-2); display: flex; align-items: center; gap: 5px; }
.kpi-value {
    font-size: 22px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.25;
    margin-top: 2px;
}
.kpi-value small { font-size: 12px; font-weight: 600; color: var(--text-3); margin-left: 3px; }
.kpi-sub { font-size: 11px; color: var(--text-3); margin-top: 1px; }

/* --- 卡片区 --- */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    margin-top: 12px;
}

.stats-card {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    padding: 11px 12px 12px;
    min-width: 0;
}

.stats-card-hours { grid-column: 1 / -1; }
.stats-card-visits { grid-column: 1 / -1; }

/* 最近访问列表：两列排布压低高度，弹窗里一行 = 时间 / IP / 浏览器 / 地理位置 */
.visit-list {
    margin-top: 8px;
    columns: 2;
    column-gap: 18px;
}

.visit-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 3px 0;
    font-size: 11.5px;
    border-bottom: 1px dashed color-mix(in srgb, var(--border) 60%, transparent);
    break-inside: avoid;
}

.visit-time {
    flex: 0 0 auto;
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
}

.visit-ip {
    flex: 0 0 auto;
    max-width: 130px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
    color: var(--text-2);
}

.visit-browser { flex: 0 0 auto; color: var(--text-3); }

.visit-geo {
    margin-left: auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-3);
}

/* 没查到地理位置的记录：淡一点，鼠标悬停有说明 */
.visit-geo.is-unknown { opacity: .55; }

.visit-empty {
    padding: 10px 0;
    font-size: 12px;
    color: var(--text-3);
    text-align: center;
}

@media (max-width: 700px) {
    .visit-list { columns: 1; }
}

/* --------------------------------------------------------------------------
   失效分析：把探测不可达 / 被禁用的网址列出来（占整行）
   -------------------------------------------------------------------------- */
.stats-card-fail { grid-column: 1 / -1; }

.fail-list {
    margin-top: 8px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 168px;
    overflow-y: auto;
}

.fail-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 4px 6px;
    border-radius: 7px;
    font-size: 11.5px;
    background: color-mix(in srgb, var(--danger, #dc2626) 7%, transparent);
    border: 1px solid color-mix(in srgb, var(--danger, #dc2626) 22%, transparent);
}

/* 已禁用（本地域连续 3 轮不可达）比普通不可达更重：实心红点 + 淡红底 */
.fail-row.is-disabled {
    background: color-mix(in srgb, var(--danger, #dc2626) 13%, transparent);
    border-color: color-mix(in srgb, var(--danger, #dc2626) 42%, transparent);
}

.fail-dot {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--danger, #dc2626);
    align-self: center;
}

.fail-main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: baseline;
    gap: 6px;
}

.fail-name {
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fail-host {
    color: var(--text-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.fail-domain {
    flex: 0 0 auto;
    max-width: 140px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-3);
}

/* 最后一次失效时间：比「原因」更弱一档，放在域名下、原因前 */
.fail-last {
    flex: 0 0 auto;
    max-width: 150px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
}

.fail-reason {
    flex: 0 0 auto;
    font-weight: 600;
    color: var(--danger, #dc2626);
}

.fail-more {
    margin: 4px 0 0;
    font-size: 11px;
    color: var(--text-3);
    text-align: center;
}

/* --------------------------------------------------------------------------
   回收站弹窗
   -------------------------------------------------------------------------- */
.modal-trash > form,
.modal-trash > .modal-inner { width: min(720px, calc(100vw - 32px)); }

.modal-trash .modal-trash-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 12px 16px 16px;
}

.trash-note { margin: 0 0 10px; font-size: 11.5px; color: var(--text-3); }
.trash-note:empty { display: none; }

.trash-list { display: flex; flex-direction: column; gap: 8px; }

.trash-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 11px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}

.trash-icon {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    border-radius: 7px;
    background: var(--surface);
    border: 1px solid var(--border);
}

.trash-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }

.trash-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.trash-tag {
    margin-left: 6px;
    padding: 0 5px;
    border-radius: 6px;
    font-size: 10px;
    font-weight: 600;
    vertical-align: 1px;
    color: var(--text-3);
    background: var(--surface);
    border: 1px solid var(--border);
}

.trash-meta {
    font-size: 11px;
    color: var(--text-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.trash-acts { flex: 0 0 auto; display: flex; gap: 6px; }

.trash-acts .trash-danger { color: var(--danger, #dc2626); }
.trash-acts .trash-danger:hover {
    color: #fff;
    background: var(--danger, #dc2626);
    border-color: var(--danger, #dc2626);
}

/* 回收站数量角标样式见上（.trash-count：安卓 App 图标式角标，锚定在 .btn-ico 右上角） */

/* --- 弹窗内紧凑化：保证一屏完整放下、不出现滚动条 --- */
.modal-stats .kpi { padding: 8px 11px; }
.modal-stats .kpi-value { font-size: 19px; }
/* 新增「失效分析」后卡片变多：KPI 常驻顶部，下面的图表区自己滚，
   弹窗本体仍然不出现滚动条（内容再高也不会把弹窗撑破） */
.modal-stats .stats-grid {
    margin-top: 10px;
    gap: 10px;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding-right: 2px;
}
.modal-stats .fail-list { max-height: 150px; }
.modal-stats .stats-card { padding: 10px 11px 11px; }
.modal-stats .hours-chart { height: 92px; }
.modal-stats .rank-bars { height: 104px; }
.modal-stats .pie-svg { width: 104px; height: 104px; }
.modal-stats .pie-wrap { min-height: 104px; }

/* 矮屏（笔记本小窗口）再压一档，弹窗始终完整呈现、始终居中 */
@media (max-height: 760px) {
    .modal-stats .hours-chart { height: 68px; }
    .modal-stats .kpi-value { font-size: 17px; }
    .modal-stats .rank-list { gap: 4px; }
    .modal-stats .rank-bars { height: 84px; }
    .modal-stats .pie-svg { width: 88px; height: 88px; }
    .modal-stats .pie-wrap { min-height: 88px; }
    .modal-stats .pie-legend { gap: 2px; }
}

/* 极窄屏（手机）：KPI 两列；内容实在放不下时才允许纵向滚动兜底 */
@media (max-width: 700px) {
    .modal-stats .stats-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .modal-stats .modal-stats-body { overflow-y: auto; }
}

/* 时间分布维度切换（日 / 月 / 年）：迷你分段控件 */
.dist-tabs {
    display: inline-flex;
    gap: 2px;
    margin-bottom: 10px;
    padding: 3px;
    border: 1px solid var(--border);
    border-radius: 9px;
    background: color-mix(in srgb, var(--surface-2, #f1f5f9) 60%, transparent);
}

.dist-tab {
    appearance: none;
    border: none;
    background: transparent;
    cursor: pointer;
    font: inherit;
    font-size: 12px;
    line-height: 1;
    color: var(--text-3);
    padding: 5px 14px;
    border-radius: 6px;
    transition: color .15s ease, background-color .15s ease, box-shadow .15s ease;
}

.dist-tab:hover { color: var(--text-2); }

.dist-tab.is-active {
    color: var(--primary);
    font-weight: 700;
    background: var(--surface);
    box-shadow: 0 1px 2px rgba(15, 23, 42, .08);
}

.stats-card-title {
    font-size: 12.5px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 9px;
    display: flex;
    align-items: baseline;
    gap: 7px;
}

.stats-card-sub { font-size: 11px; font-weight: 400; color: var(--text-3); }

/* --- 24 小时分布柱状图 --- */
.hours-chart {
    display: flex;
    align-items: flex-end;
    gap: 3px;
    height: 108px;
    padding-top: 6px;
}

.hour-col {
    flex: 1 1 0;
    min-width: 0;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    gap: 3px;
}

/* 柱子轨道：撑满剩余高度，柱子按百分比从底部往上长 */
.hour-track {
    flex: 1 1 auto;
    width: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    min-height: 0;
}

.hour-bar {
    display: block;
    width: 100%;
    max-width: 34px;
    border-radius: 3px 3px 0 0;
    background: linear-gradient(180deg, #7ea8f5, var(--primary));
    transition: height .3s ease;
}

.hour-col.is-empty .hour-bar { background: var(--surface-3); }
.hour-col.is-now .hour-bar { background: linear-gradient(180deg, #f7b955, #e08c0b); }
.hour-col.is-peak .hour-bar { background: linear-gradient(180deg, var(--accent), #0e7490); }

.hour-label {
    font-size: 10px;
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.hour-col.is-major .hour-label { color: var(--text-2); font-weight: 600; }

/* --- 排行榜 --- */
.rank-list { display: flex; flex-direction: column; gap: 6px; }

.rank-row {
    display: grid;
    grid-template-columns: 20px minmax(0, 1fr) minmax(40px, 38%) auto;
    align-items: center;
    gap: 8px;
    font-size: 12px;
}

.rank-no {
    width: 20px;
    height: 20px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    background: var(--surface-3);
    color: var(--text-2);
    font-size: 11px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.rank-row.is-top .rank-no { background: var(--primary); color: #fff; }

.rank-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
}

.rank-name .rank-icon { flex: 0 0 auto; }
.rank-name .rank-host { color: var(--text-3); font-size: 11px; }

.rank-row.is-gone .rank-name { color: var(--text-3); text-decoration: line-through; }

.rank-bar {
    height: 7px;
    border-radius: 999px;
    background: var(--surface-3);
    overflow: hidden;
}

.rank-bar i {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, #9dbcf8, var(--primary));
    transition: width .3s ease;
}

.rank-row.is-top .rank-bar i { background: linear-gradient(90deg, #67d9e8, var(--accent)); }

.rank-count {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--text-2);
    white-space: nowrap;
}

/* --- 域点击次数：纵向柱状图 --- */
.rank-chart { min-height: 96px; }

.rank-bars {
    display: flex;
    align-items: flex-end;
    gap: 6px;
    height: 118px;
    padding-top: 2px;
}

.rank-bar-col {
    flex: 1 1 0;
    min-width: 0;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
}

/* 柱体区吃掉剩余高度，数值与名称固定在上/下两端，柱子才对得齐 */
.rank-bar-track {
    flex: 1 1 auto;
    width: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    min-height: 0;
}

.rank-bar-track i {
    display: block;
    width: 62%;
    min-width: 12px;
    border-radius: 4px 4px 0 0;
    background: linear-gradient(180deg, #9dbcf8, var(--primary));
    transition: height .35s ease;
}

.rank-bar-col.is-top .rank-bar-track i { background: linear-gradient(180deg, #67d9e8, var(--accent)); }

.rank-bar-value {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-2);
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}

.rank-bar-col.is-top .rank-bar-value { color: var(--primary-dark); }

/* 标签只有纯文本域名：ellipsis 只在块级下有效，别加 display:flex（会让省略号失效） */
.rank-bar-label {
    max-width: 100%;
    font-size: 10.5px;
    color: var(--text-3);
    line-height: 1.2;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rank-bar-col.is-gone .rank-bar-label { text-decoration: line-through; }

/* --- 网址点击次数：饼状图 + 图例 --- */
.pie-wrap {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 116px;
}

.pie-svg { flex: 0 0 auto; display: block; }

.pie-slice { transition: opacity .15s ease; }
.pie-slice:hover { opacity: .82; }

.pie-legend {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.pie-legend-row {
    display: grid;
    grid-template-columns: 9px minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 6px;
    font-size: 11.5px;
    line-height: 1.35;
}

.pie-dot {
    width: 9px;
    height: 9px;
    border-radius: 3px;
    flex: 0 0 auto;
}

.pie-name {
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.pie-legend-row.is-gone .pie-name { color: var(--text-3); text-decoration: line-through; }

.pie-pct {
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.pie-count {
    font-weight: 700;
    color: var(--text-2);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

@media (max-width: 700px) {
    .pie-wrap { flex-direction: column; align-items: flex-start; }
    .rank-bars { height: 100px; }
}

.stats-empty {
    font-size: 12px;
    color: var(--text-3);
    padding: 14px 2px;
    text-align: center;
}

/* --- 窄屏适配 --- */
@media (max-width: 1100px) {
    .nowbar { gap: 10px; }
    .stats-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 880px) {
    .nowbar { margin-left: 0; order: 3; width: 100%; justify-content: space-between; }
    .now-clock { align-items: flex-start; }
    .stats-grid { grid-template-columns: minmax(0, 1fr); }
    .stats-card-hours { grid-column: auto; }
    .hour-col:nth-child(even) .hour-label { visibility: hidden; }
}

@media (max-width: 560px) {
    .stats-kpis { grid-template-columns: minmax(0, 1fr); }
    .rank-row { grid-template-columns: 20px minmax(0, 1fr) auto; }
    .rank-bar { display: none; }
    .wx-pop { width: min(268px, calc(100vw - 32px)); }
}

/* ----------------------------- 帮助模块 ----------------------------- */
.help-intro {
    font-size: 13px;
    color: var(--text-2);
    line-height: 1.6;
    margin: 0 0 14px;
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    background: var(--primary-soft);
    border: 1px solid var(--primary-border);
}
.help-empty { color: var(--text-3); padding: 16px 0; }
.help-row {
    display: grid;
    /* 第三列 = 该按钮自己的提示框外观（位置 / 框底色 / 文字色 / 恢复默认） */
    grid-template-columns: minmax(140px, .9fr) minmax(0, 1.2fr) auto;
    align-items: center;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px dashed var(--border);
}

/* ---- 提示框外观 ---- */
/* 顶部可折叠块 = 默认值（没单独设置的按钮用它）；每行右侧才是单按钮设置 */
.help-style {
    margin: 0 0 14px;
    padding: 12px 14px;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    border: 1px solid var(--border);
}
.help-style-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 700;
    color: var(--text);
    cursor: pointer;
    list-style: none;
}
.help-style-title::-webkit-details-marker { display: none; }
.help-style-title::before {
    content: '▸';
    font-size: 11px;
    color: var(--text-2);
    transition: transform .15s;
}
.help-style[open] > .help-style-title { margin-bottom: 10px; }
.help-style[open] > .help-style-title::before { transform: rotate(90deg); }
.help-style-sub { font-size: 12px; font-weight: 500; color: var(--text-3); }
.help-style-grid {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: 10px 14px;
}
.help-style-label { font-size: 12.5px; color: var(--text-2); white-space: nowrap; }
.help-place-group { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.help-place-btn {
    padding: 5px 12px;
    font-size: 12.5px;
    border-radius: 999px;
    border: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--text-2);
    cursor: pointer;
    transition: background .15s, color .15s, border-color .15s;
}
.help-place-btn:hover { border-color: var(--primary); color: var(--primary); }
.help-place-btn.is-active {
    background: var(--primary);
    border-color: var(--primary);
    color: #fff;
    font-weight: 600;
}
.help-color { display: inline-flex; align-items: center; gap: 8px; }
.help-color input[type="color"] {
    width: 40px;
    height: 28px;
    padding: 0 2px;
    border: 1px solid var(--border-strong);
    border-radius: 7px;
    background: var(--surface);
    cursor: pointer;
}
/* 每行右侧：这个按钮自己的一套外观 */
.help-appear {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    justify-content: flex-end;
}
.help-appear .help-color { gap: 6px; }
.help-appear input[type="color"] {
    width: 30px;
    height: 26px;
    padding: 0 1px;
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    background: var(--surface);
    cursor: pointer;
}
.help-appear-reset { white-space: nowrap; }
.help-mini {
    padding: 4px 9px;
    font-size: 12px;
    border-radius: 7px;
    border: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--text-2);
    cursor: pointer;
}
.help-mini:hover { border-color: var(--primary); color: var(--primary); }
.help-style-hint { font-size: 12px; color: var(--text-3); line-height: 1.6; margin: 10px 0 0; }
.help-place {
    padding: 6px 8px;
    font-size: 12.5px;
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
}
.help-enable { display: inline-flex; align-items: center; gap: 8px; min-width: 0; cursor: pointer; }
.help-enable input { width: 16px; height: 16px; margin: 0; flex: 0 0 auto; cursor: pointer; }
.help-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.help-text {
    width: 100%;
    padding: 7px 11px;
    border: 1px solid var(--border-strong);
    border-radius: 9px;
    font-size: 13px;
    background: var(--surface);
    color: var(--text);
}
.help-text:focus { outline: none; border-color: var(--primary); }
.help-appear .help-place { padding: 4px 6px; font-size: 12px; }
/* 阴影下拉：和位置下拉同一套外观（每行右侧多一格；窄屏时一起换行） */
.help-shadow {
    padding: 6px 8px;
    font-size: 12.5px;
    border: 1px solid var(--border-strong);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
}
.help-appear .help-shadow-row { padding: 4px 6px; font-size: 12px; }
.help-foot {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: flex-end;
    margin-top: 16px;
}

/* 窄屏：一行放不下「名称 | 文字 | 外观」三列，改成上下三行 */
@media (max-width: 680px) {
    .help-row { grid-template-columns: minmax(0, 1fr); gap: 8px; }
    .help-appear { justify-content: flex-start; }
}



/* =====================================================================
   线性（描边）图标 .nav-icon
   图标值写成 ic:<id>（如 ic:folder）时由 app.js 内联成 SVG。
   尺寸统一用 1em×1em —— 跟 emoji 一样由外层字号决定，所以域图标的
   --dm-icon-size、管理工具栏的 --tool-icon-size 那套变量照样生效。
   ===================================================================== */
.nav-icon {
    width: 1em;
    height: 1em;
    display: block;
    flex: 0 0 auto;
    /* 描边图标不吃文本基线：居中对齐时不会因基线留白显得偏上 */
    vertical-align: middle;
}

/* 域图标 / 域预览图标：方框 42px，图标占六成（和 emoji 的视觉大小对齐） */
.domain-icon .nav-icon,
.dm-preview-icon .nav-icon {
    width: calc(var(--dm-icon-size, 42px) * 0.56);
    height: calc(var(--dm-icon-size, 42px) * 0.56);
}

/* 网址框图标：24px 的框里放 20px */
.link-icon-emoji.is-svg .nav-icon { width: 20px; height: 20px; }

/* 管理工具栏 / 用户 Tab 上的按钮图标：跟上传图片一个尺寸变量 */
.board-footer .btn .btn-ico .nav-icon,
.user-tab-align .btn-ico .nav-icon {
    width: var(--tool-icon-size, 16px);
    height: var(--tool-icon-size, 16px);
}

/* 表单里的预览位（站点图标 / 网址图标 / 域编辑预览） */
.siteicon-preview .nav-icon,
.icon-preview .nav-icon,
.emoji-current .nav-icon { width: 20px; height: 20px; }

/* 回收站里的小图标 */
.trash-icon .nav-icon { width: 17px; height: 17px; }

/* 顶栏品牌 Logo 与统计按钮 */
.brand-logo .nav-icon { width: 26px; height: 26px; }
.fab-ico .nav-icon,
.ico-anim-inner .nav-icon { width: 1em; height: 1em; }

/* 拟物彩色图标放在顶栏图标按钮里时，也跟文字同高（否则会按固有尺寸 32px 撑破按钮） */
.fab-ico img,
.ico-anim-inner img { width: 1em; height: 1em; object-fit: contain; display: block; }

/* 线性图标在深色 / 浅色下都跟随文字颜色，不做额外着色 */
.nav-icon { color: inherit; }

/* =====================================================================
   减少动态效果：弹窗过渡的兜底关断
   必须放在 .modal 基础规则之后才能覆盖到它（前面的 media 块排得太早，会被后面的
   同优先级 .modal 规则赢回去，导致 reduced-motion 下过渡依旧是 .2s）。
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
    .modal { transition: opacity .01s linear, display .01s linear allow-discrete; }
    .modal::before { transition: opacity .01s linear; }
    .modal > form,
    .modal > .modal-inner {
        transition: opacity .01s linear, transform .01s linear;
    }
    /* 起止态拉平：不位移、不缩放，只做几乎瞬时的显隐 */
    .modal:not([open]) > form,
    .modal:not([open]) > .modal-inner { opacity: 1; transform: none; }
    @starting-style {
        .modal[open] > form,
        .modal[open] > .modal-inner { opacity: 1; transform: none; }
    }
}
