/* ============================================================
   顶部常驻搜索框（2026-10-23 第 83 轮 · 发哥第 4 条）
   ------------------------------------------------------------
   发哥原话：「搜索框要一直在顶部栏……不能一直限制宽度，而是类似很多网站的
             AI 对话框一样，内容达到一定的字数后，就会自动扩大搜索框的尺寸，
             还有动态的放大效果」。

   做法（对齐 ChatGPT / Linear / Raycast 一类"输入即扩展"的交互）：
     · 平时 240px，只占一条窄条；
     · 聚焦 → 380px（给"准备输入"一个明确反馈）；
     · 继续打字 → 由 JS 用**镜像文本**量出真实文字宽度，逐级扩到 620px；
     · 收起 → 回到 240px；
     · 宽度变化全部走 transition（0.24s），所以是"平滑长大"而不是跳变。

   🔴 为什么写在独立 CSS 而不是 Tailwind 原子类：
      宽度是 JS 算出来的**行内值**，需要 transition + 媒体查询覆盖，
      原子类没法优雅表达；而且这里不进 Vite 构建，改样式不用重新编译。
   ============================================================ */

.hs {
    position: relative;
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    width: 240px;
    margin: 0 12px;
    transition: width .24s cubic-bezier(.2, .8, .2, 1);
}

.hs-box {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    height: 34px;
    padding: 0 10px;
    border: 1px solid var(--border);
    background: var(--bg);
    transition: border-color .18s ease, background .18s ease, box-shadow .18s ease;
}

.hs.is-open .hs-box {
    border-color: var(--accent);
    background: var(--surface);
    box-shadow: 0 0 0 3px rgba(226, 35, 26, .12);
}

.hs-icon {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    color: var(--muted);
    transition: color .18s ease;
}
.hs.is-open .hs-icon { color: var(--accent); }

.hs-input {
    flex: 1 1 auto;
    min-width: 0;
    height: 100%;
    border: 0;
    outline: 0;
    background: transparent;
    color: var(--text);
    font-size: 14px;
    font-family: var(--font-sans);
}
.hs-input::placeholder { color: var(--subtle, var(--muted)); }   /* 第 157 轮：占位符走 subtle，别跟正文弱化文字同深 */

/* 量文字宽度用的镜像（不可见，不占位） */
.hs-mirror {
    position: absolute;
    left: -9999px;
    top: 0;
    white-space: pre;
    font-size: 14px;
    font-family: var(--font-sans);
    visibility: hidden;
    pointer-events: none;
}

.hs-kbd {
    flex: 0 0 auto;
    padding: 1px 5px;
    border: 1px solid var(--border);
    color: var(--muted);
    font-family: var(--font-mono);
    font-size: 12px;
    line-height: 1.5;
}
.hs.is-open .hs-kbd { display: none; }

.hs-clear {
    flex: 0 0 auto;
    border: 0;
    background: transparent;
    color: var(--muted);
    font-size: 14px;
    line-height: 1;
    cursor: pointer;
    padding: 0 2px;
}
.hs-clear:hover { color: var(--accent); }

/* ---------------- 下拉面板 ---------------- */
.hs-panel {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    width: 620px;
    max-width: calc(100vw - 24px);
    max-height: min(70vh, 560px);
    overflow-y: auto;
    border: 1px solid var(--border);
    background: var(--surface);
    box-shadow: 0 16px 48px rgba(0, 0, 0, .18);
    z-index: 60;
    animation: hs-in .16s ease-out;
}
@keyframes hs-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0); }
}

.hs-group { padding: 10px 12px; border-bottom: 1px solid var(--border); }
.hs-group:last-child { border-bottom: 0; }
.hs-group-title {
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 6px;
}

.hs-row {
    display: block;
    padding: 7px 8px;
    margin: 0 -8px;
    transition: background .14s ease;
}
.hs-row:hover { background: var(--accent-soft); }
.hs-row-title { font-size: 14px; color: var(--text); }
.hs-row:hover .hs-row-title { color: var(--accent); }
.hs-row-sub { margin-top: 2px; font-size: 12px; color: var(--muted); }
.hs-row-sub .mono { font-family: var(--font-mono); }

.hs-spec { display: flex; gap: 6px; font-size: 14px; padding: 4px 0; }
.hs-spec-dot { flex: 0 0 auto; width: 4px; height: 4px; margin-top: 8px; border-radius: 50%; background: var(--accent); }
.hs-spec-dot.is-miss { background: var(--muted); }

.hs-empty { padding: 18px 14px 14px; text-align: center; }
.hs-empty-text { font-size: 14px; color: var(--muted); }
.hs-ask {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 10px;
    padding: 7px 14px;
    border: 1px solid var(--accent);
    background: var(--accent);
    /* 🔴 第 102 轮（发哥第 9 条）：「+ 发起提问，这四个字应该是白色的字体才对」
       红底上原来写的是 `color:#000`（黑字），对比度低且和全站红底按钮不一致。 */
    color: #fff;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
}
.hs-ask:hover { opacity: .9; }
.hs-ask-note { margin-top: 8px; font-size: 12px; color: var(--muted); }

.hs-foot {
    padding: 8px 12px;
    border-top: 1px solid var(--border);
    font-size: 12px;
    color: var(--muted);
    display: flex;
    justify-content: space-between;
    gap: 8px;
}

/* ---------------- 窄屏：收起成图标，点开占满一行 ---------------- */
@media (max-width: 767px) {
    .hs {
        width: 34px !important;
        margin: 0 4px;
    }
    .hs-input, .hs-kbd, .hs-clear { opacity: 0; pointer-events: none; }
    .hs.is-open {
        position: absolute;
        left: 8px;
        right: 8px;
        top: calc((var(--hub-nav-h, 64px) - 34px) / 2);
        width: auto !important;
        z-index: 70;
    }
    .hs.is-open .hs-input, .hs.is-open .hs-clear { opacity: 1; pointer-events: auto; }
    .hs-panel {
        position: fixed;
        left: 8px;
        right: 8px;
        top: calc(var(--hub-nav-h, 64px) + 4px);
        width: auto;
        max-width: none;
    }
}

/* Vue 挂载点在顶栏里不能占一个盒子，否则 flex 间距会多出一份 */
.hs-host { display: contents; }
@media (max-width: 767px) {
    .hs-host { position: static; }
}

/* ============================================================
   顶栏骨架（第 83 轮）
   ------------------------------------------------------------
   搜索框放在**右簇**里（`margin-left:auto` 让它整体贴右），所以搜索框变宽时
   是**向左长**，主题/语言/登录这些不会被推走、也不会跳动。
   展开时把中间的导航链接淡出，把空间让给搜索框（ChatGPT / Linear 同款做法）。
   ============================================================ */
.hub-nav {
    display: flex;
    align-items: center;
    gap: 20px;
    height: var(--hub-nav-h, 64px);   /* 第 84 轮：与 GitHub 一致的 64px */
}
.hub-brand { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.hub-links {
    display: flex;
    align-items: center;
    gap: 20px;
    font-size: 14px;
    transition: opacity .18s ease;
}
/* 🔴 第 100 轮（发哥第 4 条）：「切换白天黑夜的开关图标，高度应该和搜索框一样高」
   搜索框 `.hs` 是 34px —— 顶栏里的方形小控件统一走这个类，别再各写 px-2 py-1。 */
.hub-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 34px;
    min-width: 34px;
    padding: 0 8px;
    line-height: 1;
    cursor: pointer;
}
.hub-right {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 12px;
}

/* 用户区（登录 / 注册 / 头像）· 第 156 轮从 `.hub-right` 里拆出来：
   电脑端它紧贴搜索区右侧（视觉不变），手机端靠 `order` 挪到第二行导航条右侧。
   🔴 拆出来的原因：390px 宽时「logo + 搜索 + 用户名」三项挤在同一行，
      登录按钮必然被推出屏幕（只能靠 `overflow:hidden` 藏起来，那是自欺欺人）。 */
.hub-user {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 0 0 auto;
}

/* Vue 只负责给 <html> 挂这个类，避免依赖 :has() */
/* 展开时把导航链接**真正收起来**（不只是透明）：
   透明但仍然占位的话，搜索框会长到 620 却被挤掉 —— 实测 1200 容器下会溢出。
   用 max-width 收缩 + overflow:hidden，既能腾空间又有过渡。 */
.hub-links {
    overflow: hidden;
    transition: opacity .18s ease, max-width .26s cubic-bezier(.2, .8, .2, 1);
    max-width: 460px;
}
html.hs-open .hub-links {
    opacity: 0;
    max-width: 0;
    pointer-events: none;
}

/* ============================================================
   手机端顶栏（第 156 轮 · 发哥：断点只考虑电脑和手机）
   ------------------------------------------------------------
   原来这一档只有 `display: none` 把导航整组藏掉 —— 手机上**没有导航入口**，
   只能靠搜索或直接敲地址。现在改成「顶栏第一行 + 可横向滑动的导航条」：
     · 第一行：logo + 搜索 + 主题/账号（原样）
     · 第二行：5 个导航项，超出部分横向滑动（隐藏滚动条，露出半个词提示可滑）
   🔴 不动模板、不加 JS：纯 CSS 让 `.hub-links` 换行成第二行。
   🔴 `html.hs-open` 时导航**不塌陷**（它在第二行，跟搜索抢空间的是第一行）。
   ============================================================ */
@media (max-width: 767px) {
    /* 🔴 手机端用 **Grid 两行**，不用 flex-wrap：
       实测 flex-wrap + order 在这里会算错位置（logo 被排到视口外，截图三遍都消失）。
       Grid 的 grid-area 是显式坐标，不存在"谁被挤走"的可能：
           第 1 行 = logo | 搜索
           第 2 行 = 导航（可横滑） | 登录
       电脑端仍是 flex（这条只在 ≤767 生效，桌面布局一个像素都不动）。 */
    .hub-nav {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "brand search"
            "nav   user";
        height: auto;
        padding-top: 8px;
        padding-bottom: 6px;
        gap: 8px;
        align-items: center;
    }
    /* 🔴 用数字坐标（行 / 列）而不是命名区域：
       命名区域在"某个元素不是直接子元素"时会静默失效，元素被自动放置到新行。
       数字坐标是硬约束，错不了。 */
    .hub-nav > .hub-brand { grid-row: 1; grid-column: 1; }
    .hub-nav > .hub-right { grid-row: 1; grid-column: 2; margin-left: 0; }
    .hub-nav > .hub-links { grid-row: 2; grid-column: 1; min-width: 0; }
    .hub-nav > .hub-user  { grid-row: 2; grid-column: 2; justify-self: end; }
    /* logo 有内联 height:41px，必须 !important 才压得住。
       390px 宽下第一行要同时放：logo + 搜索 + 主题 + 语言 + 登录，
       不缩 logo 会直接把「注册」挤出屏幕（第 156 轮实测截图踩到）。 */
    .hub-brand img { height: 28px !important; }
    .hub-brand span { font-size: 14px !important; }

    .hub-links {
        order: 10;                        /* 第二行左侧：和「登录」同一行 */
        flex: 1 1 auto;                   /* 吃掉剩余宽度，超出横向滑动 */
        min-width: 0;
        max-width: 100%;
        display: flex;
        gap: 18px;
        margin-top: 8px;
        padding: 8px 0 7px;
        border-top: 1px solid var(--border);
        overflow-x: auto;
        overflow-y: hidden;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        opacity: 1;
        pointer-events: auto;
    }
    .hub-links::-webkit-scrollbar { display: none; }
    .hub-links > li { flex: 0 0 auto; }
    /* 搜索展开时别把第二行也塌掉（碰撞只发生在第一行） */
    html.hs-open .hub-links { opacity: 1; max-width: 100%; pointer-events: auto; }

    /* 🔴 `.hub-right` 用 `flex: 1 1 0`（基数为 0），不是 `auto`：
         `auto` 的基数是"内容宽度"，而内容里的搜索框由 JS 写成固定 px，
         基数一撑开，`margin-left: auto` 就把它整体推出屏幕右缘 ——
         表现是"搜索框很窄、但右边全是空白，登录按钮凭空消失"（本轮实测两遍）。
         基数 0 才会严格等于「容器宽 − logo 宽」。 */
    .hub-right { gap: 6px; flex: 1 1 0; min-width: 0; margin-left: 0; justify-content: flex-end; }
    /* 手机宽度只有 375~430：搜索框改成吃剩余空间，别再固定 240 */
    /* 🔴 必须 `!important`：`.hs` 的宽度由 HeaderSearch 组件在 JS 里按
         `--hs-w-min` / 视口算出来后写成**内联 style**，普通 CSS 压不住。
         🔴 `flex: 1 1 0` + `width: 0` 而不是 `auto`：`auto` 会按 placeholder 的
            文本长度撑开（占位文案很长），把 `.hub-right` 顶到下一行、语言下拉挤出屏幕。
            基数为 0 才是"只吃剩余空间、绝不撑开"。 */
    /* 🔴 `min-width: 0 !important` 是这条的关键：HeaderSearch 会按 `--hs-w-min`
         把最小宽写成**内联 style**（240px），只有 `!important` 能压过内联。
         不加这句，搜索框永远至少 240px，把「登录」顶出屏幕（本轮实测三遍）。 */
    .hub-right .hs { width: 0 !important; min-width: 0 !important; flex: 1 1 0; margin: 0 2px; }
    /* ============================================================
       390px 宽下第一行只能放三样：logo + 搜索 + 登录。
       ------------------------------------------------------------
       实测（390px，logo 缩到 28px 高后仍需 108px）：
         logo 108 + 搜索 + 主题 30 + 语言 62 + 登录 28 + 间距 24 = 252+搜索
       剩余只有 ~98px 给搜索 —— 输入框窄到不可用，且语言下拉必被挤到屏幕外。
       所以手机上收掉三个低频/装饰性控件（电脑端一个都不动）：
         · 主题切换：跟随系统 + 记住上次选择
         · 注册：登录页里有入口
         · 语言：URL 已带 /zh-CN，切换入口留给桌面（手机版待单独设计，见 docs 待办）
       ============================================================ */
    #theme-toggle,
    #lang-switcher { display: none !important; }

    /* 手机上 `hub-user` 整个收起，登录改由导航条第一项承担
       （grid 第 2 行右侧那一列在 390px 下会被导航挤成 0 宽，实测两遍）。
       注册入口在登录页里，手机端不再单独占位。 */
    .hub-nav > .hub-user { display: none !important; }
    /* 🔴 `!important` 是必须的：基础规则 `.hub-login-item{display:none}` 在文件更靠后
       （第 409 行），同特异性下后定义会赢 —— 不加就是"手机上登录永远不出现"，
       而且看起来像"模板没渲染"，极难查（本轮实测踩到）。 */
    .hub-login-item { display: block !important; order: -1; }
    .hub-login-item .nav-link { font-weight: 600; }
    :root { --hs-w-min: 140px; }
}

/* ============================================================
   首页 Hero 的搜索框 = **组件**，不是页面框架（第 83 轮）
   ------------------------------------------------------------
   页面容器统一成 1280 之后，首页那个 `w-full` 的搜索框会跟着拉到 1248px，
   既丑又难用（输入一个字要跨半个屏）。这里给它一个可读上限：
   **页面宽度仍然全站一致**，只是这个控件不像表格那样无限拉伸。
   ============================================================ */
.search-hero {
    max-width: 760px;
    margin-left: auto;
    margin-right: auto;
}

/* ============================================================
   窄屏顶栏适配（2026-10-24 第 85 轮 · 发哥 1080 视口截图）
   ------------------------------------------------------------
   现象：1080 宽时「产品手册 / 提问与回答 …」被折成两行（每个链接自己换行）。
   原因：顶栏是 flex，链接文字允许折行；且搜索框固定 240px 抢了太多空间。

   治法：
     ① 链接**永不折行**（`white-space:nowrap`）；
     ② ≤1200 收紧间距、字号 13px、搜索框基准宽降到 180（`--hs-w-min` 由 JS 读取）；
     ③ 搜索展开时的最大宽由 JS 按视口算，不再死写 620。
   ============================================================ */
.hub-links li { white-space: nowrap; }
/* 手机专用登录项（第 156 轮）：电脑端由顶栏右侧 `.hub-user` 承担，这里隐藏 */
.hub-login-item { display: none; }

:root { --hs-w-min: 240px; }

@media (max-width: 1279px) {
    :root { --hs-w-min: 180px; }
    /* 🔴 768~1279（笔记本半屏/小窗口）：导航原来 `overflow: hidden`，
       宽度不够时会**默默只留第一项**，看起来像"导航项丢了"。
       改成横向可滑 —— 能放几项放几项，剩下的滑出来。 */
    .hub-links { gap: 12px; overflow-x: auto; max-width: 360px; scrollbar-width: none; }
    .hub-links::-webkit-scrollbar { display: none; }
    .hub-links .nav-link { font-size: 14px; }
    .hub-nav { gap: 12px; }
    .hub-right { gap: 8px; }
    .hs { margin: 0 6px; }
}

/* ============================================================
   首页搜索（第 101 轮 · 发哥第 5 / 7 / 8 条）
   ------------------------------------------------------------
   ① 搜索框改**两行**（textarea），右侧圆形箭头按钮（↑，AI 聊天那种）
   ② 提示词改用**打字机效果**（`.sh-ph` 覆盖层），聚焦即消失
   ③ 结果统一成 `.sr-card`（每组一个标题 `.sr-title`，鼠标移上去一律红框）
   ============================================================ */

.sh-box {
    position: relative;
    border: 1px solid var(--border);
    background: var(--surface);
    transition: border-color .15s ease;
}
.sh-box.is-focus { border-color: var(--accent); }

.sh-ta {
    display: block;
    width: 100%;
    /* 🔴 第 102 轮（发哥第 1 条）：「首页搜索框的内容应该是居左，不应该是居中」
       —— textarea **会继承** 祖先的 `text-align`（首页 hero 容器是 `text-center`，
       所以光标和输入的文字都跑中间去了）。这里显式 left，不依赖外层。 */
    text-align: left;
    min-height: 76px;          /* 两行：行高 1.6 × 14px ≈ 22.4 × 2 + 上下内边距 */
    padding: 12px 56px 12px 14px;
    border: 0;
    background: transparent;
    color: var(--text);
    font-family: inherit;
    font-size: 14px;
    line-height: 1.6;
    resize: none;              /* 两行固定，别让用户拖成半个屏 */
    outline: none;
}
.sh-ta::placeholder { color: transparent; }   /* 提示词由 .sh-ph 画，不用原生 placeholder */

/* 打字机提示词：绝对定位覆盖在输入区左上，pointer-events:none 不挡点击 */
.sh-ph {
    position: absolute;
    left: 15px;
    top: 13px;
    right: 56px;
    text-align: left;          /* 同上：提示词也继承 text-center，必须显式左对齐 */
    font-size: 14px;
    line-height: 1.6;
    color: var(--muted);
    pointer-events: none;
    white-space: pre-wrap;
    word-break: break-word;
}
/* 光标：一条细竖线，随打字闪烁 */
.sh-caret {
    display: inline-block;
    width: 1px;
    height: 15px;
    margin-left: 2px;
    vertical-align: -2px;
    background: var(--muted);
    animation: sh-blink 1s steps(2, start) infinite;
}
@keyframes sh-blink { to { visibility: hidden; } }

/* 右侧发送按钮：圆角方块 + 箭头（不再用 "GO" 文字） */
.sh-go {
    position: absolute;
    right: 8px;
    bottom: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 30px;
    border: 1px solid var(--accent);
    border-radius: var(--admin-r-sm);   /* 第 155 轮：8px 属越档，归到控件档（6px） */
    background: var(--accent);
    color: #fff;
    cursor: pointer;
    transition: opacity .15s ease;
}
.sh-go:hover { opacity: .88; }
.sh-go:active { transform: translateY(1px); }
.sh-go svg { display: block; }

/* 结果分组：标题 + 一叠同款卡片 */
.sr-group { margin-top: 18px; text-align: left; }
.sr-title {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    color: var(--muted);
    margin-bottom: 8px;
}
.sr-card {
    display: block;
    border: 1px solid var(--border);
    background: var(--surface);
    padding: 12px 14px;
    text-decoration: none;
    color: inherit;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.sr-card + .sr-card { margin-top: 8px; }
/* 🔴 所有答案卡片（提问与回答 / 固件市场 / 论坛 / 手册）**同一套 hover** */
.sr-card:hover,
.sr-card:focus-visible {
    border-color: var(--accent);
    box-shadow: 0 0 0 1px var(--accent) inset;
    outline: none;
}
.sr-card-h {
    font-size: 14px;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    border-radius: 0 !important;   /* 第 152 轮：贴边裁字容器一律直角（admin.css 基线 6px 会削字形四角） */
}
.sr-card:hover .sr-card-h { color: var(--accent); }
.sr-card-b {
    margin-top: 4px;
    font-size: 14px;
    line-height: 1.6;
    color: var(--muted);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    border-radius: 0 !important;   /* 第 152 轮：贴边裁字容器一律直角 */
}
.sr-card-m {
    margin-top: 6px;
    font-size: 12px;
    color: var(--accent);
}

/* ============================================================
   手机端搜索框宽度（第 156 轮 · 收尾修正）
   ------------------------------------------------------------
   🔴 必须放在文件**最后**：
      `:root { --hs-w-min: 240px }` 与 `.hs { width: 240px }` 在文件中部，
      `@media` 块写在它们之前时，同特异性下会被覆盖（本条踩过一次）。
      `--hs-w-min` 还会被 HeaderSearch 读去写成 `style="width:180px"` 内联，
      所以宽度与最小宽都必须 `!important` 才压得住。
   ============================================================ */
@media (max-width: 767px) {
    :root { --hs-w-min: 120px; }
    /* 固定 150px，不用 flex 分配：
       390 − 边距40 − logo约128 − 登录28 − 间距 ≈ 150，
       写死比"分配剩余"更可预测（headless 与真机的 vw 计算有过出入）。 */
    .hub-nav .hub-right .hs {
        width: 150px !important;
        min-width: 150px !important;
        max-width: 150px !important;
        flex: 0 0 150px !important;
        margin: 0 2px !important;
    }
    /* 组件内部的盒子跟着外层走，别自己撑出固定宽 */
    .hub-nav .hub-right .hs .hs-box { width: 100% !important; min-width: 0 !important; }
    /* 🔴 必须是 `!important` + 放在文件最后：
         `@media (max-width:1279px)` 在文件中部还有一条 `.hub-right { gap: 8px }`，
         同特异性下后定义会吃掉整组声明（实测：`margin-left:auto` 一直生效，
         搜索框被推到屏幕右缘、登录被裁掉）。这里把所有布局属性一次钉死。 */
    .hub-nav .hub-right {
        flex: 1 1 0 !important;
        margin-left: 0 !important;
        min-width: 0 !important;
        justify-content: flex-end !important;
        gap: 6px !important;
    }
}
