/* ============================================================================
 * layout.css —— 页面骨架：导航、页容器、工具条、帖子栅格、安全区。
 *
 * ## 桌面与移动是两套形态，不是同一套的缩放（诉求：电脑端布局重新设计）
 *
 * 之前电脑端只是把手机那套放大：一条悬浮胶囊顶栏 + 一列内容 + 1200px 收窄。
 * 结果在 1920 屏上左右各空 350px，三个去处在屏幕最上边缘（鼠标每次都要甩
 * 一趟），阳光指数与灵感两张信息卡横躺在列表上方——进广场先滚过一屏才看见
 * 作品。用户的原话是「不方便操作」。
 *
 * 现在两套形态各按自己的输入设备来：
 *
 *   compact（手机 / 窄窗）  顶部无栏、底部固定五宫格、单列、卡片两列
 *   wide（鼠标 / 宽窗）     左侧常驻侧栏 + 主栏 + 右信息栏，卡片 auto-fill
 *
 * 侧栏而不是顶栏，是因为鼠标的成本在于距离：侧栏里三个去处永远在同一个
 * 位置，且纵向排列比横向排列更容易扩展（将来加「订单」「钱包」不必挤宽度）。
 * 右信息栏而不是内容上方，是因为信息卡是「瞥一眼」的内容，不该占用作品流的
 * 首屏。宽度不够放右栏时（<1400px）它自动落回列表上方，这一档就退化成两栏。
 *
 * ## 导航契约（诉求 #4 的修复点）
 *
 * 迁移前顶栏与底栏各有一套判断，互不相干：
 *   - `.navbar { display: none !important }` 在 `@media (max-width: 768px),
 *     (pointer: coarse) and (max-width: 1024px)` 内（style.css 4897、5221）。
 *   - `.mobile-bottom-nav { display: flex !important }` 在同一块内（5224），
 *     但块外 5277 行还有一条 `.mobile-bottom-nav { display: none !important }`：
 *     同特异性、同 `!important`、写在后面 —— 底栏在任何屏宽下都不显示。
 *
 * 所以「有些手机型号下方没有功能按钮」不限于某些机型：底栏本就被全局关掉，
 * 而 ≤768px 以及 769–1024px 的触摸屏（安卓大屏机、平板、开了「请求桌面版
 * 网站」的手机）顶栏也被关掉 —— 那一档两个导航都没有。
 *
 * 本层把两者绑成互补开关：每个改动导航可见性的块都同时写两条，一显一隐，
 * **并且同时写 body 的避让**（侧栏靠 padding-left、底栏靠 padding-bottom）。
 *   默认（桌面）      → 侧栏显示、底栏隐藏、body 让出 --sidebar-width
 *   @media 移动断点   → 侧栏隐藏、底栏显示、body 让出底栏高度（带
 *                      :not([data-layout="wide"]) 守卫）
 *   html[data-layout] → JS 判定，compact / wide，见文件末尾
 * JS 未执行时媒体查询兜底，仍然只有一个导航；JS 判定 wide 时守卫让媒体查询
 * 让位，不会把宽屏桌面顶成移动版。判定逻辑在 js/core/device.js。
 *
 * `assertNavigable()` 会在两个导航都不可见时强制回到 compact，它认的是
 * `.navbar` 这个类名 —— 所以侧栏保留原类名，改的是形态不是身份。
 *
 * ## 三栏用 grid 而不是 flex，且右栏写在 DOM 前面
 *
 * `.page-rail` 在 HTML 里排在 `.page-main` 之前，靠 grid 的显式行列号挪到
 * 右侧。这样单列时（窄屏、或 <1400px）信息卡自然落在作品流上方 —— 和迁移前
 * 的阅读顺序一致，读屏与键盘 Tab 的顺序也不会被视觉换位打乱。用 flex 的
 * `order` 也能换位，但 order 不改变焦点顺序，视觉在右、Tab 在前，反而更乱。
 *
 * ## 与迁移前的数值差异
 *
 * 归入令牌刻度：下拉圆角 12→20、底栏文字 10px→0.72rem、nav-link 0.95→1rem、
 * .square-container 内边距 15/20/20→24/32/32（桌面）、其窄屏上内边距 10→12px。
 *
 * 有意修改：底栏 z-index 10000 → --z-bottom-nav 1010（旧值压在弹窗 2000 与
 * 通知 3000 之上，手机上点开帖子详情底栏浮在遮罩上面）；底栏去掉
 * backdrop-filter（底色 0.98 不透明，模糊看不见，只白付一次 GPU 合成）；
 * 灵感卡图标由蓝紫渐变（#3b82f6→#8b5cf6，上一版冷色主题残留）改为
 * info→success 两个令牌色，与整站暖橙/海青的配色收在一起（诉求 #5）。
 *
 * 删除的死代码（诉求 #6）：`.navbar.scrolled`、`.nav-toggle` / `.bar` /
 * `.auth-buttons`、`.mobile-only-publish`（历次迁移已删，见 git 历史）；
 * 本次追加 `.search-box` 一族（模板与 JS 零引用）、`.square-header`（同）、
 * `#categoryFilter` 的整片 `!important` 皮肤（该 `<select>` 是
 * `display: none` 的取值容器，屏幕上由 `.custom-select-trigger` 代替它出现）、
 * `@media (max-width: 900px)` 里收窄 `.nav-publish` 的那一块（侧栏是纵向的，
 * 横向挤不着）。
 * ========================================================================== */

/* ── 页面外壳 ─────────────────────────────────────────────────────────────
 * `.app-shell` 是门闩：index.html 没有导航，不加这个类就不吃这份避让。
 *
 * 桌面只让左边，不让上边 —— 顶部没有栏了，纵向留白交给各页容器自己的
 * padding，这样「容器上边距」只有一个来源。
 */
body.app-shell {
    padding-left: var(--sidebar-width);
}

/* ── 侧栏 ─────────────────────────────────────────────────────────────────
 * 类名仍是 `.navbar`：js/core/device.js 的 assertNavigable() 靠它判断
 * 「桌面导航是否可见」，改名会让那道兜底失效。
 */
.navbar {
    display: flex;
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: var(--z-sticky);
    width: var(--sidebar-width);
    border-right: 1px solid var(--color-border);
    background: var(--glass-bg);
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
    color: var(--color-text);
}

/* overflow-y 是为了矮窗口（笔记本外接竖屏、浏览器缩放到 200%）：内容顶不下
 * 时侧栏自己滚，而不是把「个人中心」挤出屏幕外。 */
.nav-container {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-5);
    margin: 0;
    padding: var(--space-5) var(--space-3) calc(var(--space-4) + var(--safe-bottom));
    width: 100%;
    max-width: none;
    height: 100%;
    overflow-y: auto;
}

.nav-logo {
    display: flex;
    align-items: center;
    padding: 0 var(--space-2);
    font-size: var(--font-size-xl);
    font-weight: 900;
}

.nav-logo span {
    background: var(--gradient-brand);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

.nav-logo i {
    margin-right: var(--space-2);
    color: var(--color-brand-soft);
}

.nav-menu {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

/* 整行可点，不只是文字：纵向菜单里 232px 宽的一整条比一个词的命中面积大得多。 */
.nav-link {
    display: flex;
    position: relative;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-bold);
    text-decoration: none;
    transition: background var(--transition-fast), color var(--transition-fast);
}

/* 定宽图标槽：三个图标字形宽度不同（罗盘宽、人像窄），不定宽文字就参差。 */
.nav-link i {
    width: 20px;
    font-size: 1.05rem;
    text-align: center;
}

.nav-link:hover {
    background: var(--color-brand-tint);
    color: var(--color-brand);
}

.nav-link.active {
    background: var(--color-brand-wash);
    color: var(--color-brand);
}

/* 顶栏时代这是一条从左往右展开的 2px 下划线；纵向菜单里改成左侧竖条。
 * 同一个伪元素换方向，而不是新加一个元素。 */
.nav-link::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 0;
    width: 3px;
    height: 0;
    border-radius: var(--radius-full);
    background: var(--color-brand);
    transform: translateY(-50%);
    transition: height var(--transition-fast);
}

.nav-link:hover::after,
.nav-link.active::after {
    height: 60%;
}

.nav-link:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* 未读红点。js/common.js 给**两个**导航里的 [data-nav="chat"] 都塞一个，
 * 所以这里要给两种形态各写一次落位：侧栏推到行尾，底栏叠在图标右上角。 */
.nav-badge {
    margin-left: auto;
    padding: 2px 7px;
    border-radius: var(--radius-full);
    background: var(--color-danger);
    color: var(--color-on-brand);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-bold);
    line-height: 1.5;
}

/* ── 侧栏用户区 ───────────────────────────────────────────────────────── */

/* margin-top: auto 把用户区推到侧栏底部。用它而不是
 * `.nav-container { justify-content: space-between }`：中间若再加一组菜单，
 * space-between 会把三段均分，而这里要的是「其余靠上、用户区贴底」。 */
.user-menu {
    display: flex;
    position: relative;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
    margin-top: auto;
}

/* 桌面端发布入口。取代原来右下角的 .fab-container 悬浮胶囊——那颗按钮的
 * 渐变是蓝紫（style.css 165 行），后面又被 1775 行改成琥珀橙，两套颜色都
 * 不是品牌渐变；展开的菜单是深蓝玻璃（rgba(15,23,42,0.6)）落在暖橙页面上。
 * 整块规则靠 15 个 !important 硬顶，无法被组件层调整。
 *
 * 收进导航片段后跟着 .navbar 一起走：侧栏只在 wide 布局显示，底栏只在
 * compact 显示，于是「每种布局恰好一个发布入口」成为结构性事实，而不是靠
 * 两处 display 规则手工维持。 */
.nav-publish {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    width: 100%;
    border: none;
    border-radius: var(--radius-full);
    background: var(--gradient-brand);
    box-shadow: var(--shadow-brand);
    color: var(--color-on-brand);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    font-family: inherit;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    transition: transform var(--transition-base), box-shadow var(--transition-base);
}

.nav-publish:hover {
    box-shadow: var(--shadow-brand-strong);
    transform: translateY(-2px);
}

.nav-publish:active {
    transform: translateY(0);
}

.nav-publish:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

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

    .nav-publish:hover {
        transform: none;
    }
}

.user-info {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    color: var(--color-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    cursor: pointer;
    transition: background var(--transition-base);
}

.user-info:hover {
    background: var(--color-brand-tint);
}

.user-avatar {
    width: 34px;
    height: 34px;
    border: 2px solid rgba(255, 255, 255, 0.8);
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

/* 侧栏只有 232px，长昵称会把头像挤出去，所以截断而不是换行。 */
.user-name {
    overflow: hidden;
    color: var(--color-text);
    font-weight: var(--font-weight-bold);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 用户区贴在侧栏底部，所以菜单往上开。 */
.user-dropdown {
    position: absolute;
    bottom: 100%;
    left: 0;
    z-index: var(--z-dropdown);
    margin-bottom: var(--space-3);
    min-width: 100%;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
    box-shadow: var(--glass-shadow);
    color: var(--color-text);
    overflow: hidden;
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
    transition: opacity var(--transition-base), transform var(--transition-base),
                visibility var(--transition-base);
}

.user-dropdown.show {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.user-dropdown a {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    color: var(--color-text-muted);
    text-decoration: none;
    transition: background var(--transition-base), color var(--transition-base);
}

.user-dropdown a:hover {
    background: var(--color-brand-wash);
    color: var(--color-brand);
}

.user-dropdown a i {
    width: 20px;
    color: var(--color-brand);
    text-align: center;
}

/* ── 底栏 ─────────────────────────────────────────────────────────────────
 * 高度含安全区，内边距把内容顶出 iPhone 底部横条。
 */
.mobile-bottom-nav {
    display: none;
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: var(--z-bottom-nav);
    align-items: center;
    justify-content: space-around;
    height: calc(var(--bottom-nav-height) + var(--safe-bottom));
    padding-bottom: var(--safe-bottom);
    border-top: 1px solid rgba(251, 146, 60, 0.15);
    /* 不透明。原来是 rgba(255,255,255,0.98)，而这条底栏没有 backdrop-filter：
       那 2% 换不来毛玻璃，只让身后滚过的卡片文字和头像在四个标签上留一层
       淡淡的鬼影——底栏是常驻元素，任何一点脏都会一直在。 */
    background: var(--color-surface-solid);
    box-shadow: 0 -4px 15px rgba(124, 45, 18, 0.04);
}

.mobile-nav-item {
    display: flex;
    position: relative;
    flex: 1;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    text-decoration: none;
    opacity: 0.75;
    transition: color var(--transition-fast), opacity var(--transition-fast);
}

.mobile-nav-item i {
    font-size: 18px;
}

.mobile-nav-item:hover,
.mobile-nav-item.active {
    color: var(--color-brand);
    font-weight: var(--font-weight-bold);
    opacity: 1;
}

.mobile-nav-item:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* 底栏里没有行尾可推，红点改叠在图标右上角。 */
.mobile-nav-item .nav-badge {
    position: absolute;
    top: 1px;
    left: 54%;
    margin-left: 0;
    padding: 1px 5px;
}

/* 发布项的加号用品牌渐变，与侧栏 logo 同一处理。 */
.mobile-nav-item.publish-item i {
    background: var(--gradient-brand);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    font-size: 22px;
}

/* ── 三栏外壳 ─────────────────────────────────────────────────────────────
 * 默认单列（也是 <1400px 与 compact 的形态）。右栏在 DOM 里排在主栏之前，
 * 宽屏三栏时靠 grid-column 归位；单列时用 order 把它压到作品流之后，
 * 见下面 compact 档 —— 补充信息不该顶在页标题上方。
 */
.page-columns {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    align-items: start;
}

/* min-width: 0 是 grid 项装 auto-fill 栅格时的必需项：不写它，子栅格的
 * 最小内容宽度会把这一列顶宽，整页出现横向滚动条。 */
.page-main {
    min-width: 0;
}

/* 右栏启用阈值对齐令牌 --bp-wide（@media 里用不了 var()）。
 * 守卫用 :not([data-layout="compact"]) 而不是 [data-layout="wide"]：
 * JS 没跑时（首屏脚本被拦、浏览器禁用 JS）宽屏也该拿到三栏。 */
@media (min-width: 1400px) {
    html:not([data-layout="compact"]) .page-columns {
        grid-template-columns: minmax(0, 1fr) var(--rail-width);
        gap: var(--space-6);
    }

    html:not([data-layout="compact"]) .page-main {
        grid-row: 1;
        grid-column: 1;
    }

    html:not([data-layout="compact"]) .page-rail {
        grid-row: 1;
        grid-column: 2;
        position: sticky;
        top: var(--space-4);
    }
}

/* ── 页容器与帖子栅格 ─────────────────────────────────────────────────────
 * 广场与个人中心共用同一组栅格声明（诉求 #1）。迁移前两者列数看似一致，但
 * profile.html 的容器带行内 `style="grid-template-columns: repeat(auto-fill,
 * minmax(250px, 1fr))"`，全靠 style.css 的 `!important` 压住；本层不写
 * `!important`，所以那段行内样式已从模板删除。
 */
.square-container {
    margin: 0 auto;
    padding: var(--space-5) var(--space-6) var(--space-6);
    max-width: var(--content-max-width-wide);
}

/* align-items: stretch（而不是 start）：同一行的卡片被拉到等高。
 * 组件层已经把图片、标题、描述、标签、底条全部锁成定高，正常情况下卡片
 * 本就一样高；stretch 是兜底——将来某张卡片多出一行内容时，整行跟着长，
 * 而不是让那一张单独凸出来。 */
.square-content,
#profile-posts-container {
    display: grid;
    align-items: stretch;
}

/* 固定列数改成 auto-fill：主栏宽度现在有四种（有无右栏 × 窗口宽度），写死
 * 4 列的话 1920 屏上每张卡片被拉到 360px 宽、1400 屏上又挤到 250px。
 * auto-fill 让「一张卡片多宽」成为常量，列数交给可用宽度决定。 */
.square-content {
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: var(--space-5);
}

/* 个人中心（发布 / 点赞 / 收藏三个 Tab）的卡片换成 .post-card--mini 的紧凑
 * 尺寸——参考小红书：个人主页是「我的东西的索引」，一屏能看见多少条比每条
 * 看得多清楚更要紧；广场是浏览场景，卡片留大的。
 *
 * 结构仍是广场那一套（同一个 renderPostCard），只是尺寸缩了一档，所以
 * 「个人中心与广场排列一致」（诉求 #1）没有被破坏——变的是密度，不是形式。 */
#profile-posts-container {
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    gap: var(--space-4);
}

/* ── 页头 ─────────────────────────────────────────────────────────────────
 * 广场原来没有页头，桌面上进页面第一眼是一条光秃秃的工具条——没有标题，
 * 不知道这是哪儿、能干什么。手机上这样合理（屏幕小，寸土寸金，底栏已经写着
 * 「广场」），桌面上不合理：1560px 宽的内容区，最上面一行只有筛选控件。
 *
 * 标题与工具条分成两块而不是塞进同一行：工具条要吸顶，页头不该跟着吸——
 * 滚到第 200 张卡片时还挂着一行大标题只是占地方。
 */
.page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.page-title {
    color: var(--color-text);
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
}

.page-subtitle {
    margin-top: var(--space-1);
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

/* 右侧的实时计数由 js/square.js 填。空着时不占位，否则首屏会先亮出一块
   写着「共 0 条」的灰字，数据回来再跳成真数。 */
.page-header-meta {
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
}

.page-header-meta:empty {
    display: none;
}

/* ── 广场工具条 ───────────────────────────────────────────────────────────
 * Tab 与搜索筛选原来是上下两行，各占一条 30px 外边距，桌面上白掉近 120px
 * 首屏高度。收成一行并吸顶：长列表滚到第 200 张卡片时还能直接换 Tab / 改
 * 关键词，不必滚回顶部。
 */
.square-toolbar {
    display: flex;
    position: sticky;
    top: var(--space-3);
    z-index: var(--z-sticky);
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
    padding: var(--space-3);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    /* 比 --glass-bg（0.45 白）浓且偏暖：吸顶条底下滚过的是卡片，0.45 白会
     * 把卡片糊成一片灰。这里取 --color-bg 的同色高透明版，滚动时读起来像
     * 页面底色本身浮了上来。 */
    background: rgba(255, 251, 235, 0.86);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: var(--glass-shadow);
}

/* 胶囊分段控件，取代原来那条 2px 下划线：下划线在吸顶条里和条底的边框
 * 撞在一起，两条平行横线分不清哪条是选中态。 */
.square-tabs {
    display: flex;
    flex-shrink: 0;
    gap: var(--space-1);
    padding: var(--space-1);
    border-radius: var(--radius-full);
    background: var(--color-brand-tint);
}

.square-tabs .tab-btn {
    padding: var(--space-2) var(--space-4);
    border: none;
    border-radius: var(--radius-full);
    background: none;
    color: var(--color-text-muted);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
    font-family: inherit;
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.square-tabs .tab-btn:hover {
    color: var(--color-brand);
}

.square-tabs .tab-btn.active {
    background: var(--color-surface-solid);
    box-shadow: var(--shadow-sm);
    color: var(--color-brand);
}

.square-tabs .tab-btn:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* ── 筛选胶囊 ─────────────────────────────────────────────────────────────
 * 搜索框、地区、风格、按钮原来是四个各自带边框和圆角的控件并排，中间夹三段
 * 12px 空隙——同一排四种长相、四圈边框，这就是「搜索栏不美观」的来源。
 *
 * 现在边框只画最外面一圈，内部用 1px 竖线分段：整条读起来是一个控件，
 * 视线从「搜什么」到「在哪」到「什么风格」到「搜」是一条直线。
 *
 * flex-basis 460px：低于这个宽度四段挤到看不出边界，此时整块换行到 Tab 下面。
 * align-items: stretch 让四段等高——各段自己撑高度的话，按钮会比输入框高 4px。
 */
.search-filter {
    display: flex;
    flex: 1 1 460px;
    align-items: stretch;
    gap: 0;
    padding: var(--space-1);
    min-width: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    background: var(--color-surface-solid);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

/* 焦点落在任意一段时整条高亮。让各段自己画聚焦环的话，胶囊上会同时出现
   两圈橙光（段内输入框的 + 外圈的）。 */
.search-filter:focus-within {
    border-color: var(--color-brand);
    box-shadow: var(--focus-ring);
}

.search-input-wrapper {
    display: flex;
    flex: 1;
    align-items: center;
    min-width: 0;
}

.search-filter .input-group {
    display: flex;
    flex: 1;
    align-items: center;
    min-width: 0;
}

/* 段内输入框不再自带边框、底色和圆角——那圈边框由胶囊统一画。
 * 迁移前它的外观来自模板的 style 属性（深蓝底 + 近白字，上一版冷色主题的
 * 残留）与 style.css 第 821 起 6 条 `!important` 的对抗，两边都已删除。 */
.search-filter input[type="text"] {
    padding: 0 var(--space-3);
    padding-left: calc(var(--space-4) + var(--space-5));
    width: 100%;
    border: none;
    background: none;
    color: var(--color-text);
    font-size: var(--font-size-sm);
    font-family: inherit;
    outline: none;
}

.search-filter input[type="text"]::placeholder {
    color: var(--color-text-muted);
    opacity: 0.7;
}

/* 分段竖线。做成 flex 项而不是给相邻段加 border-left：段的圆角、hover 底色
   都会把 border 压出一个缺口。 */
.filter-divider {
    flex: 0 0 1px;
    align-self: stretch;
    margin: var(--space-2) 0;
    background: var(--color-border);
}

/* 提交按钮收进胶囊右端。min-height 从 .btn 的 44px 降到 40px：那 44px 是
   触摸目标下限，而这颗按钮只在 wide 布局（鼠标）里长这样——compact 档下面
   会把它改回 44px。 */
.search-filter .btn {
    flex: 0 0 auto;
    padding: 0 var(--space-5);
    min-height: 40px;
    border-radius: var(--radius-full);
    font-size: var(--font-size-sm);
}

/* ── 风格筛选器 ───────────────────────────────────────────────────────────
 * 一个 <div> 伪装的 <select>（真的那个 `#categoryFilter` 是 display:none 的
 * 取值容器，供 js 读写）。搬过来是因为它和上面两个输入框并排站在同一条
 * 工具条里，而它原来在 style.css 里是 20px 胶囊 + 1.5px 边、旁边两个是
 * 12px 圆角 + 1px 边 —— 同一排三个控件三种长相（诉求 #5）。
 *
 * 顺带摘掉 20 个 `!important`：它们压的是自己上一版，站内没有竞争者。
 */
.custom-select-wrapper {
    display: flex;
    position: relative;
    flex: 0 0 132px;
    font-size: var(--font-size-sm);
    user-select: none;
    cursor: pointer;
}

/* 和地区触发器一样不画边框、不铺底色：它是胶囊里的一段，不是独立控件。
   hover / 展开时只换文字颜色——换底色会在胶囊中间凭空多出一块方形色板。 */
.custom-select-trigger {
    display: flex;
    flex: 1;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: 0 var(--space-3);
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    font-weight: var(--font-weight-bold);
    white-space: nowrap;
    transition: color var(--transition-fast), background var(--transition-fast);
}

.custom-select-trigger:hover,
.custom-select-wrapper.open .custom-select-trigger,
.custom-select-wrapper.has-value .custom-select-trigger {
    color: var(--color-brand);
}

.custom-select-trigger span {
    overflow: hidden;
    text-overflow: ellipsis;
}

.custom-select-trigger i {
    color: var(--color-brand);
    font-size: var(--font-size-xs);
    transition: transform var(--transition-base);
}

.custom-select-wrapper.open .custom-select-trigger i {
    transform: rotate(180deg);
}

.custom-select-options {
    position: absolute;
    top: calc(100% + var(--space-3));
    right: 0;
    left: auto;
    z-index: var(--z-dropdown);
    min-width: 180px;
    max-height: 250px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface-solid);
    box-shadow: var(--shadow-lg);
    overflow-y: auto;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-10px);
    transition: opacity var(--transition-base), transform var(--transition-base),
                visibility var(--transition-base);
}

.custom-select-wrapper.open .custom-select-options {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

.custom-option {
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--color-border);
    color: var(--color-text);
    transition: background var(--transition-fast), color var(--transition-fast);
}

.custom-option:last-child {
    border-bottom: none;
}

.custom-option:hover {
    background: var(--color-brand-tint);
    color: var(--color-brand);
}

.custom-option.active {
    background: var(--gradient-brand);
    color: var(--color-on-brand);
    font-weight: var(--font-weight-bold);
}

/* ── 信息卡（阳光指数 / 灵感） ────────────────────────────────────────────
 * auto-fit 一条规则覆盖两种桌面形态：落在 300px 右栏里就是竖排一列，落在
 * 主栏上方（<1400px）就是并排两列。不必为两种位置各写一个断点。
 */
.sunlight-inspiration-widget {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: var(--space-4);
}

.widget-card {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-5);
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    background: var(--glass-bg);
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
    box-shadow: var(--glass-shadow);
    transition: transform var(--transition-base), box-shadow var(--transition-base);
}

.widget-card:hover {
    box-shadow: var(--shadow-lg);
    transform: translateY(-2px);
}

.widget-card h4 {
    margin-bottom: var(--space-1);
    color: var(--color-text);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-bold);
}

.widget-card p {
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    line-height: var(--line-height-tight);
}

.widget-icon {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    color: var(--color-on-brand);
    font-size: var(--font-size-lg);
}

/* pulse-sun 的 @keyframes 仍在 style.css：它只服务这一个图标，跟着元素走。 */
.sun-index-card .widget-icon {
    background: linear-gradient(135deg, var(--color-accent), var(--color-danger));
    animation: pulse-sun 2s infinite;
}

.inspiration-card .widget-icon {
    background: linear-gradient(135deg, var(--color-info), var(--color-success));
}

@media (prefers-reduced-motion: reduce) {
    .sun-index-card .widget-icon {
        animation: none;
    }

    .widget-card {
        transition: none;
    }

    .widget-card:hover {
        transform: none;
    }
}

/* ── 公告浮层 ─────────────────────────────────────────────────────────────
 * 迁移前是 `left: 50%` 对整个视口居中，桌面上有一半压在侧栏底下。改成对
 * 「侧栏右侧那块内容区」居中：fixed 元素的百分比按视口算，所以偏移量正好
 * 是侧栏宽度的一半。
 */
.announcement-container {
    position: fixed;
    top: calc(var(--space-4) + var(--safe-top));
    left: calc(50% + var(--sidebar-width) / 2);
    z-index: var(--z-sticky);
    width: min(600px, calc(100% - var(--sidebar-width) - var(--space-6)));
    transform: translateX(-50%);
    /* 没有公告时这块是个空盒子，不拦点击。 */
    pointer-events: none;
    transition: opacity var(--transition-base);
}

.announcement-container.show {
    pointer-events: auto;
}

/* ── 消息中心 ─────────────────────────────────────────────────────────────
 * 聊天页本来就是两栏（会话列表 + 对话区），桌面上只需要跟着侧栏让位、并放宽
 * 到与其他页一致的容器宽度。
 *
 * --border-color 留在这里：`.chat-dashboard-card` 的若干后代读它，值与迁移前
 * 逐字相同。它不是设计令牌（令牌在 tokens.css），只是这一页的局部变量。
 */
.chat-dashboard-container {
    --border-color: rgba(255, 255, 255, 0.08);
    margin: 0 auto;
    padding: var(--space-4) var(--space-5) var(--space-5);
    max-width: var(--content-max-width);
    height: 85vh;
    box-sizing: border-box;
}

/* ── 个人中心 ─────────────────────────────────────────────────────────────
 * 迁移前是一根 650px 的单列：桌面上左右各空 500px，而表单本身挤在中间，
 * 「发布 / 点赞 / 收藏」三个列表更是只能排两三张卡片。
 *
 * 改成 GitHub 式两栏：左边身份卡（头像、昵称、关注数、操作按钮）吸顶不动，
 * 右边是 Tab 与内容。容器自己变成透明栅格，玻璃质感下移到两块面板上——
 * 所以 style.css 里把 `.profile-container` 列进玻璃组的那两处已删除。
 */
.profile-container {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-5);
    margin: 0 auto;
    padding: var(--space-5) var(--space-6) var(--space-6);
    max-width: var(--content-max-width);
}

.profile-side,
.profile-main {
    padding: var(--space-5);
    min-width: 0;
    border: 1px solid var(--glass-border);
    border-radius: var(--radius-lg);
    background: var(--glass-bg);
    backdrop-filter: blur(var(--glass-blur));
    -webkit-backdrop-filter: blur(var(--glass-blur));
    box-shadow: var(--glass-shadow);
    /* 显式取色，替代 style.css 那条 `.profile-container * { color: #1e293b }`
     * 通配后代刷色。那条把个人中心里所有没指定颜色的文字刷成冷灰蓝，而同一
     * 段文字在广场是暖棕——诉求 #5 的一处来源。删掉它之后，这里继承的就是
     * 全站正文色。 */
    color: var(--color-text);
}

.profile-side .profile-header-section {
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* 表单在 800px 宽的面板里铺满会让每个输入框长到一行读不完；680px 是一行
 * 中文大约 40 字的宽度。列表类 Tab 不受影响，它们自己是栅格。 */
.profile-main form {
    max-width: 680px;
}

@media (min-width: 1024px) {
    html:not([data-layout="compact"]) .profile-container {
        grid-template-columns: minmax(240px, 300px) minmax(0, 1fr);
        align-items: start;
    }

    html:not([data-layout="compact"]) .profile-side {
        position: sticky;
        top: var(--space-4);
    }
}

/* ── 移动布局 ─────────────────────────────────────────────────────────────
 * 断点条件与 style.css 原有的移动块逐字相同，改的只是「两个导航互补」。
 * 对应令牌 --bp-tablet 768px、--bp-desktop 1024px（@media 里用不了 var()）。
 */
@media (max-width: 768px), (pointer: coarse) and (max-width: 1024px) {
    /* 导航可见性与页面避让带 `:not([data-layout="wide"])` 守卫：JS 明确判定
       wide 时不被媒体查询顶翻。栅格列数与内边距不加守卫 —— 那些只跟视口宽度
       有关，和设备是什么无关。 */
    html:not([data-layout="wide"]) .navbar {
        display: none;
    }

    html:not([data-layout="wide"]) .mobile-bottom-nav {
        display: flex;
    }

    html:not([data-layout="wide"]) body.app-shell {
        padding-left: 0;
        padding-bottom: calc(
            var(--bottom-nav-height) + var(--space-1) + var(--safe-bottom)
        );
        overflow-x: hidden;
    }

    /* 公告浮层回到整个视口居中：这一档没有侧栏可避。 */
    html:not([data-layout="wide"]) .announcement-container {
        left: 50%;
        width: calc(100% - var(--space-5));
    }

    /* 单列时右栏挪到作品流之后。右栏在 DOM 里排在主栏前面（宽屏三栏靠
       grid-column 归位），塌成一列后它就顶在页标题上方 —— 打开广场先看到一张
       阳光指数卡，标题和作品被压到折叠线以下。补充信息该排在正文后面。 */
    .page-main {
        order: 0;
    }

    .page-rail {
        order: 1;
    }

    .square-container {
        padding: calc(var(--space-3) + var(--safe-top)) var(--space-2) var(--space-2);
    }

    .square-content,
    #profile-posts-container {
        grid-template-columns: repeat(2, 1fr);
        gap: var(--space-3);
    }

    /* 工具条在窄屏拆回两行、去掉玻璃底与吸顶：56px 的底栏已经占了一条，
       再吸一条顶就只剩不到半屏看作品。 */
    .square-toolbar {
        position: static;
        flex-direction: column;
        align-items: stretch;
        gap: var(--space-2);
        margin-bottom: var(--space-3);
        padding: 0;
        border: none;
        border-radius: 0;
        background: none;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        box-shadow: none;
    }

    .page-header {
        margin-bottom: var(--space-3);
    }

    .page-title {
        font-size: var(--font-size-lg);
    }

    /* 副标题在窄屏隐藏：底栏已经写着「广场」，这行字等于再说一遍，
       却要占掉小半张卡片的高度。 */
    .page-subtitle {
        display: none;
    }

    /* 胶囊在窄屏拆成独立字段，并且**两行都对齐**：第一行「搜索框 + 搜索按钮」，
       第二行「地区 + 风格」各占一半。
       原来是搜索框独占一行、第二行挤三个控件，宽度 185/98/60、高度 45/47/47/44
       ——四种宽度四种高度，这就是手机上这几块看起来乱的原因。现在只有两种宽度、
       一种高度，两行各自左右撑满。 */
    .search-filter {
        /* flex: 0 0 auto 是这一档的关键一行。上面的 .square-toolbar 是
           flex-direction: column，主轴变竖向后，wide 档那条 `flex: 1 1 460px`
           里的 460px 不再是宽度而是**高度**——胶囊被撑到 460px 高，它自己的
           两行再各分 230px，四个控件跟着一起长高，min-height: 44px 从来
           没成为约束。高度必须回到由内容决定。 */
        flex: 0 0 auto;
        flex-wrap: wrap;
        /* 两行按内容贴齐顶部，不瓜分容器余量（同一个坑的另一半）。 */
        align-content: flex-start;
        gap: var(--space-2);
        padding: 0;
        border: none;
        border-radius: 0;
        background: none;
    }

    .search-filter:focus-within {
        border-color: transparent;
        box-shadow: none;
    }

    .filter-divider {
        display: none;
    }

    /* 用 order 而不是改 DOM 顺序：按钮在 DOM 里排最后（桌面上它在胶囊右端），
       窄屏要它跟着搜索框留在第一行。 */
    .search-input-wrapper {
        order: 1;
        flex: 1 1 60%;
    }

    .search-filter .btn {
        order: 2;
        padding-right: var(--space-4);
        padding-left: var(--space-4);
    }

    /* 两个筛选器各占一半。basis 取 calc(50% - 半个间隙)，两个加起来正好一行,
       所以它们必然一起落到第二行，不会有一个跟着搜索框挤上去。 */
    .region-picker,
    .custom-select-wrapper {
        order: 3;
        flex: 1 1 calc(50% - var(--space-1));
        min-width: 0;
    }

    /* 省份名有两到七个字，固定宽度不是「太挤」就是「留一截空白」。 */
    .region-trigger {
        max-width: none;
    }

    /* 拆开之后每段自己把边框和底色拿回来——它们在 wide 档是被胶囊统一代管的。 */
    .search-filter input[type="text"],
    .search-filter .region-trigger,
    .search-filter .custom-select-trigger {
        border: 1px solid var(--color-border);
        border-radius: var(--radius-md);
        background: var(--color-surface);
    }

    /* 四段统一 44px：既是触摸目标下限，也让两行读起来是四个同款控件。
       wide 档为了压低胶囊高度把按钮降到过 40px，这里还回来。 */
    .search-filter input[type="text"],
    .search-filter .region-trigger,
    .search-filter .custom-select-trigger,
    .search-filter .btn {
        padding-top: 0;
        padding-bottom: 0;
        min-height: 44px;
    }

    /* iOS 的规则是「聚焦时字号小于 16px 就把整页放大」，而本站没锁缩放，
       放大后不会自己回去——点一下搜索框，整个界面就走形了。桌面档那个 sm
       字号在这里必须还原成 base.css 给输入框兜的 16px 下限。 */
    .search-filter input[type="text"] {
        font-size: max(16px, var(--font-size-md));
    }

    .search-filter input[type="text"]:focus {
        border-color: var(--color-brand);
        background: var(--color-surface-solid);
        box-shadow: var(--focus-ring);
    }

    .region-picker.open .region-trigger,
    .custom-select-wrapper.open .custom-select-trigger {
        border-color: var(--color-brand);
        background: var(--color-surface-solid);
    }

    /* ── 风格下拉改成底部弹层 ─────────────────────────────────────────────
     * 和地区面板同一处理（见 css/components.css 的 .region-panel）：两个筛选器
     * 并排站着，一个升起弹层、另一个掉下一张小卡片，会更像两个不相干的控件。
     */
    .custom-select-options {
        position: fixed;
        top: auto;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: var(--z-sheet);
        padding-bottom: calc(var(--space-2) + var(--safe-bottom));
        min-width: 0;
        max-height: 70vh;
        border-width: 1px 0 0;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
        transform: translateY(100%);
    }

    .custom-select-wrapper.open .custom-select-options {
        transform: translateY(0);
    }

    /* 顶上那道小横条是「这是可关掉的弹层」的通用信号，比再挤一个关闭按钮省地方。 */
    .custom-select-options::before {
        content: '';
        display: block;
        margin: var(--space-2) auto;
        width: 36px;
        height: 4px;
        border-radius: var(--radius-full);
        background: var(--color-border);
    }

    /* 压暗层挂在 wrapper 上而不是弹层里：弹层自己是层叠上下文，写在里面的
       伪元素只会盖住弹层自己的内容。 */
    .custom-select-wrapper.open::after {
        content: '';
        position: fixed;
        inset: 0;
        z-index: var(--z-sheet-backdrop);
        background: var(--color-scrim);
    }

    .custom-option {
        display: flex;
        align-items: center;
        min-height: 48px;
    }

    /* 信息卡改成横向 snap 滑块：窄屏上并排两张谁都读不清，竖排两张又要
       多滚一屏。 */
    .sunlight-inspiration-widget {
        display: flex;
        flex-wrap: nowrap;
        gap: var(--space-2);
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        scrollbar-width: none;
    }

    .sunlight-inspiration-widget::-webkit-scrollbar {
        display: none;
    }

    .sunlight-inspiration-widget .widget-card {
        flex: 0 0 calc(100% - var(--space-5));
        gap: var(--space-3);
        padding: var(--space-3) var(--space-4);
        border-radius: var(--radius-md);
        scroll-snap-align: center;
    }

    .sunlight-inspiration-widget .widget-icon {
        width: 38px;
        height: 38px;
        font-size: var(--font-size-md);
    }

    /* 两块面板在窄屏堆成一列，去掉内边距差与吸顶。 */
    .profile-container {
        gap: var(--space-3);
        padding: calc(var(--space-3) + var(--safe-top)) var(--space-2) var(--space-2);
    }

    .profile-side,
    .profile-main {
        padding: var(--space-4);
        border-radius: var(--radius-md);
    }

    .chat-dashboard-container {
        padding: var(--safe-top) 0 0;
        height: 100vh;
    }

    /* 手机上进入某个会话时收起底栏，把竖向空间让给消息列表。 */
    html:not([data-layout="wide"]) body.in-active-chat .mobile-bottom-nav {
        display: none;
    }

    html:not([data-layout="wide"]) body.in-active-chat.app-shell {
        padding-bottom: 0;
    }
}

/* ── JS 判定优先 ──────────────────────────────────────────────────────────
 * 取值 compact / wide（不是 mobile / desktop）：判的是「界面该紧凑还是宽松」，
 * 不是「这是什么机器」—— 桌面浏览器把窗口拉窄也该走 compact。
 *
 * 这一组不带媒体查询，所以横屏大屏手机（视口 1080）和开了「请求桌面版网站」
 * 的手机（视口 980）也吃得到 —— 这两档正是上面媒体查询漏掉的、诉求 #4 的
 * 主场景。可见性与避让必须同时给：只切导航不改 padding，侧栏会压住内容、
 * 底栏会压住页脚。
 */
html[data-layout="compact"] .navbar {
    display: none;
}

html[data-layout="compact"] .mobile-bottom-nav {
    display: flex;
}

html[data-layout="compact"] body.app-shell {
    padding-left: 0;
    padding-bottom: calc(
        var(--bottom-nav-height) + var(--space-1) + var(--safe-bottom)
    );
    overflow-x: hidden;
}

html[data-layout="compact"] .announcement-container {
    left: 50%;
    width: calc(100% - var(--space-5));
}

html[data-layout="compact"] body.in-active-chat .mobile-bottom-nav {
    display: none;
}

html[data-layout="compact"] body.in-active-chat.app-shell {
    padding-bottom: 0;
}

/* wide 一侧的媒体块已被 :not() 守卫排除，这里只是把默认值显式写成一对，
 * 让「改了一边忘了另一边」在评审时看得见。 */
html[data-layout="wide"] .navbar {
    display: flex;
}

html[data-layout="wide"] .mobile-bottom-nav {
    display: none;
}

html[data-layout="wide"] body.app-shell {
    padding-left: var(--sidebar-width);
}
