/* ============================================================
   天眼技术社区 - 交互增强与响应式收尾（第三阶段）
   加载顺序：main.css → ui.css
   因为排在 main.css 之后，同优先级规则天然覆盖前者。
   ⚠ 纪律（本项目历史踩坑）：媒体查询不提升优先级，
     若在本文件「基础区」直接改已有类（.card/.feed-item/.btn），
     会反过来盖掉 main.css 末尾响应式收尾里的窄屏规则。
     因此：新增类写基础区；改动已有类一律写入本文件末尾的媒体查询区。
   ============================================================ */

/* ---------- 补充令牌（仅新增，不覆盖既有变量） ---------- */
:root {
    --sk-bg: #EFF1F4;
    --sk-shine: rgba(255, 255, 255, .68);
    --ripple: rgba(37, 162, 242, .26);
    --ripple-on-dark: rgba(255, 255, 255, .40);
    --mask: rgba(0, 0, 0, .90);
    --tap: 44px;              /* 触控热区最小尺寸 */
    --progress-h: 3px;
}
html[data-theme="dark"] {
    --sk-bg: #24272D;
    --sk-shine: rgba(255, 255, 255, .07);
    --ripple: rgba(63, 176, 245, .30);
    --mask: rgba(0, 0, 0, .94);
}

/* ============================================================
   1. 骨架屏 Skeleton
   ============================================================ */
.sk {
    position: relative; overflow: hidden;
    background: var(--sk-bg); border-radius: var(--r-xs);
}
.sk::after {
    content: ''; position: absolute; top: 0; bottom: 0; width: 42%;
    background: linear-gradient(90deg, transparent, var(--sk-shine), transparent);
    animation: skShimmer 1.35s var(--ease) infinite;
}
@keyframes skShimmer {
    0%   { left: -42%; }
    100% { left: 100%; }
}
.sk-item {
    display: flex; gap: 14px; padding: 20px;
    border-bottom: 1px solid var(--border-2);
}
.sk-item:last-child { border-bottom: none; }
.sk-body { flex: 1; min-width: 0; }
.sk-line { height: 14px; margin-bottom: 10px; }
.sk-line.w40 { width: 40%; }
.sk-line.w60 { width: 60%; }
.sk-line.w90 { width: 90%; }
.sk-line.t-lg { height: 18px; margin-bottom: 14px; }
.sk-cover { width: 132px; height: 88px; flex: 0 0 auto; border-radius: var(--r-md); }
.sk-meta { display: flex; gap: 12px; margin-top: 4px; }
.sk-meta .sk { height: 12px; width: 56px; }

/* ============================================================
   2. 加载更多 / 无限滚动
   ============================================================ */
.lm-wrap { padding: 18px 0 26px; text-align: center; }
.lm-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    min-width: 190px; padding: 11px 26px;
    border: 1px solid var(--border); border-radius: var(--r-full);
    background: var(--bg-1); color: var(--text-2); font-size: 14px;
    box-shadow: var(--sh-1); transition: all .2s var(--ease);
}
.lm-btn:hover { color: var(--primary); border-color: var(--primary); box-shadow: var(--sh-2); }
.lm-btn[disabled] { opacity: .62; cursor: default; }
.lm-btn[disabled]:hover { color: var(--text-2); border-color: var(--border); box-shadow: var(--sh-1); }
/* 旋转指示器 */
.lm-spin {
    width: 15px; height: 15px; flex: 0 0 auto;
    border: 2px solid var(--border); border-top-color: var(--primary);
    border-radius: 50%; animation: lmSpin .7s linear infinite;
}
@keyframes lmSpin { to { transform: rotate(360deg); } }
.lm-done {
    display: inline-flex; align-items: center; gap: 6px;
    color: var(--text-3); font-size: 13px; padding: 10px 0;
}
.lm-done::before,
.lm-done::after {
    content: ''; width: 26px; height: 1px; background: var(--border);
}
.lm-fail {
    display: flex; flex-direction: column; align-items: center; gap: 8px;
    color: var(--text-3); font-size: 13px;
}
.lm-retry {
    color: var(--primary); border: 1px solid var(--primary); background: transparent;
    padding: 5px 16px; border-radius: var(--r-full); font-size: 13px;
    transition: all .18s var(--ease);
}
.lm-retry:hover { background: var(--primary-050); }
/* 新追加内容的入场动画 */
.lm-new { animation: lmIn .34s var(--ease) both; }
@keyframes lmIn {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
}

/* ============================================================
   3. 图片灯箱 Lightbox
   ============================================================ */
/* 可放大的内容图：JS 自动打标，给出放大镜光标作为可点击暗示 */
.lb-zoomable { cursor: zoom-in; }

.lb-mask {
    position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 10000;
    display: flex; align-items: center; justify-content: center;
    background: var(--mask); opacity: 0; visibility: hidden;
    transition: opacity .22s var(--ease), visibility .22s;
    -webkit-tap-highlight-color: transparent;
}
.lb-mask.show { opacity: 1; visibility: visible; }
.lb-stage {
    position: relative; display: flex; align-items: center; justify-content: center;
    width: 100%; height: 100%; padding: 56px 16px 64px;
}
.lb-img {
    max-width: 100%; max-height: 100%; object-fit: contain;
    border-radius: var(--r-sm); box-shadow: 0 12px 48px rgba(0, 0, 0, .5);
    transform: scale(.96); opacity: 0;
    transition: transform .24s var(--ease), opacity .24s var(--ease);
}
.lb-mask.show .lb-img { transform: none; opacity: 1; }
.lb-loading { color: rgba(255, 255, 255, .8); font-size: 13px; }
.lb-close, .lb-nav {
    position: absolute; z-index: 2; display: flex; align-items: center; justify-content: center;
    width: var(--tap); height: var(--tap); border: none; border-radius: 50%;
    background: rgba(255, 255, 255, .12); color: #fff; cursor: pointer;
    transition: background .18s var(--ease), transform .18s var(--ease);
    -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
}
.lb-close:hover, .lb-nav:hover { background: rgba(255, 255, 255, .26); }
.lb-close:active, .lb-nav:active { transform: scale(.92); }
.lb-close { top: 12px; right: 14px; }
.lb-prev { left: 14px; top: 50%; margin-top: -22px; }
.lb-next { right: 14px; top: 50%; margin-top: -22px; }
.lb-nav[disabled] { opacity: .28; cursor: default; }
.lb-nav[disabled]:hover { background: rgba(255, 255, 255, .12); }
.lb-bar {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
    display: flex; align-items: center; justify-content: center; gap: 12px;
    padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
    color: rgba(255, 255, 255, .78); font-size: 13px;
    background: linear-gradient(transparent, rgba(0, 0, 0, .55));
}
.lb-counter { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.lb-caption {
    flex: 1 1 auto; min-width: 0; text-align: center;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lb-hidden { display: none !important; }
/* 灯箱打开时锁定滚动（JS 给 body 加类，避免 iOS 背景穿透滚动） */
body.lb-open { overflow: hidden; }

/* ============================================================
   4. 表单即时校验
   ============================================================ */
.fv-wrap { position: relative; }
.fv-msg {
    display: none; align-items: center; gap: 4px;
    margin-top: 5px; font-size: 12px; line-height: 1.5;
}
.fv-msg.show { display: flex; }
.fv-msg.err { color: var(--danger); }
.fv-msg.ok  { color: var(--success); }
.fv-msg .fv-ico { flex: 0 0 auto; font-style: normal; }
/* 无效态：仅改边框与底色，不动尺寸，避免布局跳动 */
.is-invalid {
    border-color: var(--danger) !important;
    background-color: var(--danger-bg) !important;
}
.is-invalid:focus { box-shadow: 0 0 0 3px rgba(227, 77, 89, .14) !important; }
.is-valid { border-color: var(--success) !important; }
/* 表单级汇总提示 */
.fv-summary {
    display: none; margin-bottom: 12px; padding: 10px 14px;
    background: var(--danger-bg); border: 1px solid var(--danger);
    border-radius: var(--r-sm); color: var(--danger); font-size: 13px;
}
.fv-summary.show { display: block; }

/* ============================================================
   5. 微动效：涟漪 / 按压反馈
   ============================================================ */
.ripple-host { position: relative; overflow: hidden; }
.ripple {
    position: absolute; border-radius: 50%; pointer-events: none;
    background: var(--ripple); transform: scale(0); opacity: .9;
    animation: rippleOut .58s var(--ease) forwards;
}
.btn-primary .ripple, .btn.primary .ripple,
.lb-close .ripple, .lb-nav .ripple, .fab-write .ripple {
    background: var(--ripple-on-dark);
}
@keyframes rippleOut { to { transform: scale(2.5); opacity: 0; } }

/* 数字变化时的轻弹（点赞/收藏计数） */
.num-pop { animation: numPop .38s var(--ease); }
@keyframes numPop {
    0%   { transform: scale(1); }
    38%  { transform: scale(1.28); color: var(--primary); }
    100% { transform: scale(1); }
}

/* 移动端按压反馈：触屏没有 hover，用 :active 补足即时响应 */
.tap-fx { transition: transform .12s var(--ease), opacity .12s var(--ease); }
.tap-fx:active { transform: scale(.97); opacity: .82; }

/* ============================================================
   6. Toast 增强（ui.js 重写 window.toast 使用这些类）
   ============================================================ */
#toast-box .toast-item {
    display: flex; align-items: center; gap: 9px;
    max-width: 88vw; padding: 11px 20px;
    background: var(--bg-1); color: var(--text-1);
    border: 1px solid var(--border); border-left: 3px solid var(--primary);
    border-radius: var(--r-md); font-size: 14px; line-height: 1.5;
    box-shadow: var(--sh-3); animation: toastIn .26s var(--ease);
    word-break: break-word;
}
#toast-box .toast-item.success { border-left-color: var(--success); }
#toast-box .toast-item.error   { border-left-color: var(--danger); }
#toast-box .toast-item.warn    { border-left-color: var(--warning); }
#toast-box .toast-ico {
    flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
    width: 18px; height: 18px; border-radius: 50%;
    background: var(--primary); color: #fff; font-size: 12px; font-style: normal;
    line-height: 1; font-weight: 700;
}
#toast-box .toast-item.success .toast-ico { background: var(--success); }
#toast-box .toast-item.error   .toast-ico { background: var(--danger); }
#toast-box .toast-item.warn    .toast-ico { background: var(--warning); }
#toast-box .toast-item.out { animation: toastOut .24s var(--ease) forwards; }
@keyframes toastIn  { from { opacity: 0; transform: translateY(-10px) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes toastOut { to   { opacity: 0; transform: translateY(-8px)  scale(.97); } }

/* ============================================================
   7. 阅读进度条（文章/帖子详情页）
   ============================================================ */
.read-progress {
    position: fixed; top: 0; left: 0; z-index: 1200;
    height: var(--progress-h); width: 0;
    background: var(--grad-primary);
    box-shadow: 0 0 8px rgba(37, 162, 242, .5);
    transition: width .12s linear;
    pointer-events: none;
}

/* ============================================================
   8. 空状态 / 图片兜底 / 表格滚动
   ============================================================ */
.empty .e-action { margin-top: 14px; }
.empty .e-icon { font-size: 40px; line-height: 1; margin-bottom: 10px; opacity: .75; }

/* 图片加载失败：保留占位框，避免出现破图图标并撑破布局 */
img.img-failed {
    min-width: 40px; min-height: 40px;
    background: var(--bg-3) !important;
    border: 1px dashed var(--border);
    object-fit: contain;
}
img.img-failed.avatar-sm, img.img-failed.fi-avatar { border: none; border-radius: 50%; }

/* 表格横向滚动容器（JS 自动包裹，窄屏表格不再撑破页面） */
.table-scroll {
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    margin-bottom: 12px; border-radius: var(--r-sm);
}
.table-scroll > table { min-width: 520px; }

/* ============================================================
   9. 无障碍：键盘焦点环 / 跳转链接
   ============================================================ */
.skip-link {
    position: absolute; left: -9999px; top: 0; z-index: 1300;
    padding: 10px 18px; background: var(--primary); color: #fff;
    border-radius: 0 0 var(--r-sm) 0; font-size: 14px;
}
.skip-link:focus { left: 0; }
/* 焦点环：只给「鼠标点击不匹配 :focus-visible」的元素。
   ⚠️ 2026-09-26 修订：原先把 input/textarea/select 也列进来，但可输入元素按浏览器规范
   「鼠标点击同样算 :focus-visible」（否则用户看不见光标在哪），于是点一下搜索框/登录框
   就会多出一圈 2px 橙红 outline，与组件自身的 border-color / :focus-within 反馈叠成
   双框线（搜索胶囊最明显：外橙边 + 内红框）。
   → 输入控件的焦点反馈一律交给组件类表达，已全站覆盖：
     .form-control / .input（main.css §表单）、.adm-input / .login-input / .mb-body input
     （admin.css）、.captcha-input、.comment-form|box|editor textarea、.v-field、
     .mng-form-row、.rp-form、.modal-box、.hs-pill:focus-within。
   → 新增输入控件时，请给它一个 border-color 变化的 :focus 样式。 */
a:focus-visible, button:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
    border-radius: var(--r-xs);
}
:focus:not(:focus-visible) { outline: none; }

/* ============================================================
   10. 响应式收尾（必须位于文件末尾）
   以下全部是媒体查询，用于覆盖 main.css 中的既有类。
   ============================================================ */

/* ---------- 全局防溢出兜底：flex/grid 子项允许收缩 ---------- */
/* 横向溢出 90% 源于 flex/grid 子项默认 min-width:auto 不肯收缩 */
@media (max-width: 1920px) {
    .layout-2col, .col-main, .col-side, .card, .feed-item, .feed-item .fi-body,
    .article-view, .article-detail, .panel, .panel-body, .user-item, .comment-item {
        min-width: 0;
    }
}

/* ---------- 长文本 / 长 URL 断行：防撑破卡片 ---------- */
@media (max-width: 1920px) {
    .fi-title, .rk-title, .res-title, .card-title, .av-title, .cm-content,
    .thread-title, .bi-content, .ui-name, .bc-cur, .dp-title, .ext-name {
        overflow-wrap: break-word;
        word-break: break-word;
    }
    pre, .md-code pre, code { max-width: 100%; overflow-x: auto; }
}

/* ---------- ≤1440px：栅格微调，保证侧栏不被挤 ---------- */
@media (max-width: 1440px) and (min-width: 1200px) {
    .layout-2col { gap: 16px; }
}

/* ---------- ≤1024px：平板 ---------- */
@media (max-width: 1024px) {
    .container { padding: 0 14px; }
    .feed-cover { width: 120px; height: 80px; }
    .sk-cover { width: 112px; height: 76px; }
    /* 分页在平板上更容易误触，放大间距 */
    .pagination { gap: 8px; }
}

/* ---------- ≤991px：侧栏下沉（main.css 已处理栅格，此处补细节） ---------- */
@media (max-width: 991px) {
    .col-side { margin-top: 16px; }
    .lm-btn { min-width: 160px; }
}

/* ---------- ≤768px：移动端触控热区 ≥44px ---------- */
@media (max-width: 768px) {
    /* 底部 tabbar：指甲可点中 */
    .mobile-tabbar a { min-height: 48px; justify-content: center; gap: 3px; }
    .mobile-tabbar a svg { width: 22px; height: 22px; }

    /* 分页按钮 */
    .page-link {
        display: inline-flex; align-items: center; justify-content: center;
        min-height: 40px; min-width: 40px; padding: 8px 15px;
    }
    .pagination { gap: 8px; padding: 18px 0; }

    /* 标签栏 / 分类栏 */
    .feed-tabs a, .cat-bar a {
        display: inline-flex; align-items: center;
        min-height: 40px; padding: 6px 12px;
    }

    /* 主按钮与表单控件 */
    .btn, .btn-primary, .btn-block, .btn-ghost,
    button[type="submit"], input[type="submit"] {
        min-height: var(--tap);
    }
    .form-control, .comment-form textarea, textarea, select { min-height: var(--tap); }

    /* 图标型按钮本体不改尺寸（会破坏视觉），用伪元素把热区撑到 44px */
    .theme-toggle, .back-top, .tb-caret {
        position: relative;
    }
    .theme-toggle::after, .back-top::after {
        content: ''; position: absolute; top: 50%; left: 50%;
        width: var(--tap); height: var(--tap);
        transform: translate(-50%, -50%);
    }
    /* 悬浮写作按钮本身 50px 已达标准，仅补安全区偏移 */
    .fab-write { width: 52px; height: 52px; }

    /* 加载更多按钮通栏更好点 */
    .lm-wrap { padding: 16px 0 22px; }
    .lm-btn { width: 100%; max-width: 320px; min-height: var(--tap); }

    /* 灯箱：导航键放大、图片留白收紧 */
    .lb-stage { padding: 52px 8px 62px; }
    .lb-close { top: 8px; right: 8px; }
    .lb-prev { left: 6px; }
    .lb-next { right: 6px; }
    .lb-caption { font-size: 12px; }

    /* Toast 靠近顶部，避免被 tabbar 遮挡 */
    #toast-box { top: 14px !important; }
}

/* ---------- ≤640px：小屏收敛 ---------- */
@media (max-width: 640px) {
    .container { padding: 0 12px; }
    .sk-item { padding: 14px; gap: 12px; }
    .sk-cover { display: none; }
    .lm-btn { font-size: 13px; }
    /* 信息流封面已在 main.css 隐藏，这里同步骨架屏 */
    .lb-bar { gap: 8px; font-size: 12px; }
    .empty .e-icon { font-size: 34px; }
}

/* ---------- ≤390px：超窄屏（iPhone SE 等） ---------- */
@media (max-width: 390px) {
    .container { padding: 0 10px; }
    .pagination { gap: 6px; }
    .page-link { min-width: 36px; padding: 8px 11px; font-size: 13px; }
    .lm-btn { padding: 10px 16px; }
}

/* ---------- 安全区适配（iPhone 刘海/横条）：有 env() 才生效 ---------- */
@supports (padding-bottom: env(safe-area-inset-bottom)) {
    @media (max-width: 768px) {
        /* main.css 里 body 是固定 56px，横条机型会盖住内容，补上 safe-area */
        body { padding-bottom: calc(56px + env(safe-area-inset-bottom)); }
        .back-top  { bottom: calc(142px + env(safe-area-inset-bottom)); }
        .fab-write { bottom: calc(78px + env(safe-area-inset-bottom)); }
        .lb-bar { padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
    }
}

/* ---------- 降低动效偏好：系统开启「减少动态效果」时关闭动画 ---------- */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
    .sk::after { display: none; }
    .lm-spin { animation: none; border-top-color: var(--primary); }
}

/* ---------- 打印：隐藏所有交互浮层 ---------- */
@media print {
    .topbar, .header, .footer, .mobile-tabbar, .back-top, .fab-write,
    .read-progress, .lb-mask, #toast-box, .lm-wrap, .suggest-box { display: none !important; }
}
