/* ═══════════════════════════════════════════════════════════════════════════
   layout.css —— 页面骨架 + 响应式重排
   ───────────────────────────────────────────────────────────────────────────
   【双端口径】
     · 手机竖屏 / 窄屏（< 900px）：**纵向重排** —— 顶栏 / 对手条 / 对手场 /
       中线 / 己方场 / 己方条 / 手牌 / 操作栏，从上到下；战场段与手牌**横向滚动**。
       目标：竖屏下不缩字、不挤扁，所有可点区域 ≥ 44px。
     · 桌面 / 平板横屏（≥ 900px）：**牌桌形态** —— 双方各占半场、状态信息移到左右两侧，
       中间是战场，底部是手牌带。

   【为什么不用 cqw 等比缩放】见 tokens.css 顶部注释。
   【高度单位】用 dvh（动态视口高）而不是 vh：移动浏览器地址栏收起/展开时，
     vh 会跳，dvh 不会。带 vh 兜底给老浏览器。
   ═══════════════════════════════════════════════════════════════════════════ */

/* ══ 应用外壳 ═══════════════════════════════════════════════════════════ */
.app {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
    width: 100%;
    overflow: hidden;
    /* 刘海屏 / 手势条安全区 */
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
}

/* ══ 页头（上下两栏）═══════════════════════════════════════════════════
   ★ 用户口径：「bsgo 和按钮栏可以分成两栏吗」→ 采用上下两栏。
   上行 = 品牌 + 联机状态；下行 = 三个导航项。
   以后往下行加按钮，**上行纹丝不动**，永远不会挤到 BSGO。
   ⚠️ 背景从原来的深紫（#2e1c52→#1d1236）换成暖黑 —— 由设计稿导出：
      深紫底 + 砖红选中块是两个高饱和色正面撞，再加霓虹光晕，观感廉价。 */
.topbar {
    flex: none;
    display: flex;
    flex-direction: column;
    padding: 0 var(--gutter);
    background: rgba(21, 19, 18, .90);
    border-bottom: 1px solid rgba(217, 187, 135, .16);
    padding-top: env(safe-area-inset-top);     /* 刘海屏：别让内容顶到状态栏 */
}
.topbar__row {
    display: flex;
    align-items: center;
    /* ⚠️ 左右内边距由 .topbar 统一给，这里不能再加一份（会变成双倍留白） */
}
/* 上行：品牌在左，状态在右 */
.topbar__row--brand { height: var(--topbar-h1, 34px); justify-content: space-between; gap: var(--sp-4); }
/* 下行：导航居中 —— 用户在设计稿里选的「居中」 */
.topbar__row--nav { height: var(--topbar-h2, 38px); justify-content: center; }

/* 手机：**折回单行** —— 竖屏吃不起两栏的 72px。
   只留品牌 + 一条矮导航，页面切换仍以底部 tab 为主。 */
@media (max-width: 899px) {
    .topbar { flex-direction: row; align-items: center; height: 44px; padding-top: env(safe-area-inset-top); }
    .topbar__row { display: contents; }
    .topbar__row--nav .topnav { display: none; }
}

.topbar__back { flex: none; }
.topbar__title {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    font-size: var(--fs-sm);
    font-weight: 700;
    letter-spacing: .06em;
}
/* 品牌：**BSGO**（Battle Spirits Gate Open）+ 菱形标记。
   结构是 `<svg.mark><b>BSGO</b><i>BATTLE SPIRITS GATE OPEN</i>` ——
   全称在窄屏会挤掉导航，所以窄屏只留 BSGO。 */
.topbar__brand {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 9px;
    padding: 0 2px;
}
/* 菱形标记：外菱形描金、内菱形填红 —— 全站唯一的图形识别符 */
.topbar__mark { flex: none; width: 15px; height: 15px; }
.topbar__mark .o { fill: none; stroke: var(--c-gold); stroke-width: 1.2; }
.topbar__mark .i { fill: var(--c-red); }
.topbar__brand b {
    font-family: var(--font-num);
    font-size: 18px;
    font-weight: 900;
    letter-spacing: .06em;
    color: var(--c-text);
}
.topbar__brand i {
    font-style: normal;
    font-family: var(--font-num);
    font-size: 10px;
    letter-spacing: .40em;              /* 用户在设计稿里把字距拉到 0.40em */
    color: var(--c-gold);
    opacity: .78;
}
@media (max-width: 899px) { .topbar__brand i { display: none; } }
.topbar__act { flex: none; display: flex; gap: var(--sp-2); }

/* 当前屏名的胶囊：**手机上才有用**（手机隐藏了顶栏横向导航，得有个东西告诉用户在哪）
   桌面上 `.topnav` 已经把"当前在哪一屏"用高亮表达过了，再显示一次就是重复。 */
.topbar__title { flex: none; display: flex; }
@media (min-width: 900px) { .topbar__title { display: none; } }

/* 回合指示：手机只显示阶段，桌面显示完整 */
.turn {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    padding: 4px var(--sp-3);
    border-radius: 0;                 /* 直角（原 999px 药丸形） */
    border: 1px solid var(--c-line-red);
    background: rgba(255, 43, 78, .12);
    font-size: var(--fs-xs);
    font-weight: 700;
    white-space: nowrap;
}
.turn--foe {
    border-color: var(--c-line);
    background: rgba(162, 77, 255, .14);
}
.turn__dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: var(--c-red);
    box-shadow: 0 0 8px var(--c-red);
}
.turn--foe .turn__dot { background: var(--c-purple); box-shadow: 0 0 8px var(--c-purple); }

/* ══ 战场主区 ═══════════════════════════════════════════════════════════ */
.board {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 0;
    position: relative;
}

/* 中线：一条带光的分隔 */
.midline {
    flex: none;
    height: 2px;
    margin: 2px var(--sp-3);
    background: linear-gradient(90deg, transparent, rgba(162, 77, 255, .55), rgba(255, 43, 78, .55), transparent);
    box-shadow: 0 0 12px rgba(162, 77, 255, .4);
    position: relative;
}
.midline::after {
    content: 'BATTLE';
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    padding: 0 10px;
    font-family: var(--font-num);
    font-size: var(--fs-2xs);
    font-weight: 800;
    letter-spacing: .3em;
    color: var(--c-faint);
    background: var(--c-bg);
}

/* ══ 一侧（玩家半场）═══════════════════════════════════════════════════ */
.side {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    position: relative;
}
/* 对手侧整体翻转（卡面朝对手），但**文字与按钮不翻** —— 只翻战场段 */
.side--foe .lanes { transform: rotate(180deg); }
.side--foe .lanes > * { transform: rotate(180deg); }

/* ── 状态条：手机是横向一条，桌面变成左右两列 ───────────────────────── */
.side__status {
    flex: none;
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-3);
    background: linear-gradient(90deg, rgba(26, 19, 48, .6), transparent 70%);
    border-block: 1px solid var(--c-line-soft);
}
.side--foe .side__status { background: linear-gradient(270deg, rgba(26, 19, 48, .6), transparent 70%); }

/* 头像 + 生命 */
.vital {
    flex: none;
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}
.vital__face {
    width: 34px; height: 34px;
    border-radius: 0;                 /* 方形头像（原圆形）：全界面统一直角 */
    border: 1px solid var(--c-line-red);
    background: var(--grad-red);
    display: grid;
    place-items: center;
    font-size: var(--fs-xs);
    font-weight: 900;
    color: #fff;
    flex: none;
}
.side--foe .vital__face { border-color: var(--c-line); background: var(--grad-purple); }

.vital__life {
    display: flex;
    align-items: baseline;
    gap: 3px;
    font-family: var(--font-num);
}
.vital__life b { font-size: var(--fs-lg); line-height: 1; }
.vital__life i { font-style: normal; font-size: var(--fs-2xs); color: var(--c-faint); }

/* 资源计数（手牌 / 卡组 / 废弃 / 预备） */
.res { display: flex; align-items: center; gap: var(--sp-2); margin-left: auto; }
.res__item {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 3px 7px;
    border-radius: var(--radius-sm);
    background: rgba(255, 255, 255, .05);
    border: 1px solid var(--c-line-soft);
    font-family: var(--font-num);
    font-size: var(--fs-xs);
    min-height: 28px;
}
.res__ico { width: 9px; height: 9px; border-radius: 2px; flex: none; }
.res__ico--deck  { background: var(--c-purple); }
.res__ico--hand  { background: var(--c-blue); }
.res__ico--trash { background: var(--c-white); opacity: .7; }
.res__ico--core  { background: var(--c-yellow); border-radius: 50%; }

/* ── 战场段区 ──────────────────────────────────────────────────────── */
.lanes {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
}
.lane {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    min-height: var(--card-h-sm);
    padding: 3px;
    border-radius: var(--radius-sm);
    /* 段的底纹：随属性色变化（--lane-c 由内联样式给） */
    background: linear-gradient(90deg, color-mix(in srgb, var(--lane-c, var(--c-purple)) 12%, transparent), transparent 74%);
    border: 1px dashed color-mix(in srgb, var(--lane-c, var(--c-purple)) 30%, transparent);
}
.lane__cards { display: flex; gap: var(--sp-2); }

/* ══ 手牌带 + 底栏 ═════════════════════════════════════════════════════ */
.handbar {
    flex: none;
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding: var(--sp-2) var(--sp-3);
    padding-bottom: calc(var(--sp-2) + env(safe-area-inset-bottom));
    background: linear-gradient(180deg, rgba(10, 8, 16, .5), rgba(26, 19, 48, .85));
    border-top: 1px solid var(--c-line);
}
.handbar__cards {
    display: flex;
    gap: var(--sp-2);
    padding: 2px;
    min-height: calc(var(--card-h) + 4px);
    align-items: flex-end;
}
.handbar__foot {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
}
.handbar__foot .btn { flex: 1; }
.handbar__hint {
    flex: 1;
    min-width: 0;
    font-size: var(--fs-2xs);
    color: var(--c-faint);
    text-align: center;
}

/* ══ 横屏手机 / 矮屏：压缩上下留白 ════════════════════════════════════ */
@media (max-height: 520px) and (orientation: landscape) {
    :root { --topbar-h1: 30px; --topbar-h2: 34px; --card-w: 58px; --card-h: 85px; }
    .side__status { padding: 2px var(--sp-2); }
}

/* ══ 桌面 / 平板横屏（≥ 900px）：牌桌形态 ═══════════════════════════════ */
@media (min-width: 900px) {
    .board { padding: 0 var(--sp-5); }

    /* 桌面把"状态条"变成贴在左右的窄列，让战场占满中间 */
    .side { flex-direction: row; align-items: stretch; }
    .side--foe { flex-direction: row-reverse; }

    .side__status {
        flex: none;
        width: 210px;
        flex-direction: column;
        align-items: stretch;
        justify-content: flex-start;
        gap: var(--sp-3);
        padding: var(--sp-4);
        background: linear-gradient(180deg, rgba(26, 19, 48, .5), transparent);
        border-block: 0;
        border-inline: 1px solid var(--c-line-soft);
    }
    .side--foe .side__status { background: linear-gradient(0deg, rgba(26, 19, 48, .5), transparent); }
    .res { margin-left: 0; flex-wrap: wrap; }

    .lanes { gap: var(--sp-3); }
    .lane { padding: var(--sp-2) var(--sp-3); }

    /* 桌面上手牌居中成扇形排布 */
    .handbar { padding: var(--sp-3) var(--sp-5); }
    .handbar__cards { justify-content: center; }
    .handbar__foot { justify-content: center; }
    .handbar__foot .btn { flex: none; min-width: 132px; }
    .handbar__hint { flex: none; order: -1; }
}

/* ══ 大桌面：左右状态列再宽一点，战场更舒展 ═══════════════════════════ */
@media (min-width: 1400px) {
    .board { padding: 0 var(--sp-7); }
    .side__status { width: 250px; }
}

/* ═══════════════════════════════════════════════════════════════════════
   入口页（Hero）
   ═══════════════════════════════════════════════════════════════════════ */
.home,
.lobby {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

.hero {
    position: relative;
    flex: none;
    min-height: 700px;              /* 用户导出：700px（桌面档会覆盖成 66vh 以外的这个值） */
    display: flex;
    flex-direction: column;
    justify-content: center;
    isolation: isolate;
    overflow: hidden;
    /* ★ 头图整块是**纯展示**，点不动（2026-10-18 用户口径：「头的部分应该是点不动的」）。
       · pointer-events:none —— 不接收任何鼠标事件：不会出现 I 型光标、点不中、
         也吃不到「选中文字」；滚轮会落到底下的 .lobby 上，滚动正常。
       · user-select:none  —— 双保险：拖选也选不中标题那几个大字。
       ⚠️ 将来如果要在头图里放按钮，必须改成按元素关，别把这条留在 .hero 上。 */
    pointer-events: none;
    user-select: none;
}
/* 衬底：同一张图放大 + 高斯模糊，填补右侧清晰图之外的空当
   ⚠️ hero.png 是 620×743 的竖版，宽屏铺满会被横向拉一倍 ⇒ 靠它 + 右侧原图两层解决 */
.hero__blur {
    position: absolute;
    inset: -40px;
    z-index: -3;
    background: url("../assets/hero.png") center 22% / cover no-repeat;
    filter: blur(26px) saturate(115%) brightness(.4);
}
.hero__img {
    position: absolute;
    top: 0;
    /* ★ 水平居中放在中线上（用户口径：图本来就该摆在中线）。
       原来用 `right: 26%` —— 那是**固定比例**，可图宽被 hero 高锁死在 584px，
       所以屏越宽、左边空得越多，中心越往右漂：
         1280 偏右 15px · 1440 偏右 54px · 1920 偏右 169px
       ⇒ left:50% + translateX(-50%) 才是真正不漂的居中。 */
    left: 50%;
    transform: translateX(-50%);
    z-index: -2;
    width: auto;                    /* ★ 关键：不定宽，图就绝不会被拉伸 */
    height: 100%;
    max-width: 70%;
    object-fit: contain;
    object-position: center center;
    /* ★ 两端羽化（2026-10-17 用户口径：「主图左边羽化右边不羽化有点奇怪」）。
       原来只有左边缘渐隐（`transparent 0, #000 34%`）、右边缘是**硬切** ——
       图在屏上是居中的（left:50% + translateX(-50%)，1440 屏约 470~970px），
       那条右侧直线正好和背后的模糊衬底 `.hero__blur` 撞出一条分界。
       ⚠️ 两侧**刻意不等宽**：
         · 左 32% 宽羽化 —— 那片要跟左侧文字区的压暗层（`.hero__veil`）融合；
         · 右 14% 窄羽化 —— 右侧是角色本体，羽化太宽会把人削掉一块。
       改这两个数之前先想清楚"哪边是留白、哪边是主体"。 */
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 32%, #000 86%, transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 32%, #000 86%, transparent 100%);
}
/* 压暗层：**只为文字可读性服务**，不再负责"融合图片边缘"（那交给图片自己的 mask）。
   ⚠️ 原来横向是 `var(--c-bg) 30% → .86 44% → .12 68%`，过渡带 30%~68% 正好横跨
      图片边界，看起来就是在图上"斜切"了一道，边缘糊成斜带。
      ⇒ 现在 46% 处就完全透明，保证它绝不侵入图片范围。 */
.hero__veil {
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        linear-gradient(90deg, rgba(12, 11, 10, .94) 0%, rgba(12, 11, 10, .72) 30%, transparent 46%),
        linear-gradient(180deg, rgba(12, 11, 10, .45) 0%, transparent 22%, transparent 80%, var(--c-bg) 100%);
}
.hero__inner {
    /* ★ 显式把文字层抬到主视觉图之上（2026-10-17）——
       不再依赖"负 z-index 排在非定位内容之下"这条**隐式**层叠规则
       （图是 `z-index:-2`，而本层原本只是静态块级元素）。 */
    position: relative;
    z-index: 1;
    padding: var(--sp-6) var(--gutter);
    max-width: 46ch;                /* 限宽：右边留出头给主视觉图，别压上去 */
    display: flex;
    flex-direction: column;
    gap: var(--sp-4);
}
.hero__kicker {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-2);
    font-family: var(--font-num);
    font-size: var(--fs-2xs);
    font-weight: 700;
    letter-spacing: var(--tracking-widest);
    color: var(--c-gold);
}
/* ★ 标题用**衬线**（学参考站的 --font-display:"Noto Serif TC"）——
   同一句话，衬线给的"出版物质感"是无衬线给不了的。 */
.hero__title {
    margin: 0;
    /* ── 一行显示 + 盒子跟着文字走 ──────────────────────────────────────
       ★ 这两条是配套的，缺一不可：
         ① `white-space: nowrap` —— 一行（用户口径）；
         ② `width: max-content` + `align-self: flex-start`
            —— **让元素盒子跟着文字长**（原来是 flex item 被 stretch 成 278px）。
       ⚠️ ②绝对不能省。这个标题用的是 `background-clip: text` + `color: transparent`，
          **背景只铺在元素自己的盒子里**：文字一旦溢出盒子，那部分既没有背景填充、
          也没有字色 ⇒ **根本不会画出来**。
          实测（1440 视口）：盒子 278px、文字 543px ⇒ 用户看到的就是
          「Gate Op」之后凭空断掉，看起来像被主视觉图遮住了 —— 其实什么都没画。
         排查过程见 `_work/_sub/_tmp-hero-diag.js`（用 CDP 量的几何 + 命中测试）。 */
    white-space: nowrap;
    width: max-content;
    align-self: flex-start;
    font-family: var(--font-display);
    font-size: var(--fs-3xl);
    line-height: 1.06;
    font-weight: 700;
    letter-spacing: .01em;
    background: linear-gradient(100deg, #ffffff 6%, var(--c-gold) 62%, #b9954f 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    /* ★ 标题要**压在主视觉图上**（用户口径），所以得有阴影把它从图的亮部里托出来。
       ⚠️ 但这里**绝对不能用 `text-shadow`** —— 它和 `background-clip:text` 打架：
          Chrome 会把 text-shadow 画在**裁剪后的渐变之上**，整行字像蒙了一层灰。
          用户看到的现象就是「『Gate Open, 界放』被遮住了」，根因就在这条上。
       ⇒ 用 `filter: drop-shadow()`：它作用在元素的**最终渲染结果**上，
          阴影老老实实待在文字下面。两条叠着用 ——
          第一条紧贴文字（起描边作用，压亮部靠它），第二条柔散（起体积感）。 */
    filter: drop-shadow(0 0 2px rgba(0, 0, 0, .9)) drop-shadow(0 3px 14px rgba(0, 0, 0, .75));
}
.hero__sub {
    margin: 0;
    max-width: 46ch;
    color: var(--c-dim);
    font-size: var(--fs-sm);
}
/* 主视觉的动作按钮：整屏唯一的实心红按钮（核心动作 —— 进对战大厅）。
   原来的 `.hero__actions` 是同排两个按钮，"建立房间 / 已有房号加入"
   属于大厅内部的二级动作，放在首页抢了主按钮的位置。 */
.hero__cta {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 42px;
    padding: 0 22px;
    cursor: pointer;
    font-family: inherit;
    font-size: var(--fs-sm);
    font-weight: 700;
    letter-spacing: .04em;
    color: #fff;
    background: linear-gradient(135deg, #d8453a, #8e2b23);
    border: 1px solid rgba(240, 130, 115, .85);
    box-shadow: 0 0 16px rgba(207, 58, 48, .3);
    transition: box-shadow var(--dur-short), transform .08s;
}
.hero__cta:hover { box-shadow: 0 0 22px rgba(207, 58, 48, .46); }
.hero__cta:active { transform: translateY(1px); }

/* ═══════════════════════════════════════════════════════════════════════
   （已撤除）六色 X 卡插画 · 环绕主视觉两侧 —— 2026-10-18
   ───────────────────────────────────────────────────────────────────────
   这条线做了三件事：BS74 六色霸王 X 卡的插画裁切、左右两列环绕主视觉、
   一套可调的 CSS 变量（宽/压进/亮度/倾角/偏移/模糊/羽化）。
   用户看过真实效果后判为「不太符合我的想法」，要求先撤掉 ⇒ DOM 与 CSS 均已移除。

   材料都还在，要恢复时按顺序取：
     · 卡图裁切件    webui/assets/hero-cards/（六张 508×342）
     · 生成脚本      _work/ui-preview/gen-hero-cards.py
     · 调参面板      _work/ui-preview/hero-tuner.js（拷回 js/ 再在 index.html 挂一行）
     · 完整 CSS      _work/backup/layout.css.with-hero-cards
     · 合成参考图    _work/ui-preview/hero-flat-1440.png / hero-wide-1920x1080.png
   ═══════════════════════════════════════════════════════════════════════ */
/* 首页的功能入口卡 */
/* ── 大厅页的身子（主视觉之下）────────────────────────────────────── */
.lobby__body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-5);
    padding: var(--sp-5) 0 var(--sp-6);
}
.lobby__panel {
    margin: 0 var(--gutter);
    padding: var(--sp-5);
    border: 1px solid var(--c-line);
    background: linear-gradient(160deg, rgba(45, 42, 39, .42), rgba(12, 11, 10, .42));
    /* 斜切：本设计的"破直角"手段（见 tokens.css 形状口径）*/
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%);
}
.lobby__h {
    margin: 0 0 var(--sp-3);
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    font-weight: 700;
    letter-spacing: .02em;
}
.lobby__p { margin: 0 0 var(--sp-3); color: var(--c-dim); font-size: var(--fs-sm); }
.lobby__note {
    margin: 0;
    padding-top: var(--sp-3);
    border-top: 1px solid var(--c-line-soft);
    color: var(--c-faint);
    font-size: var(--fs-xs);
    line-height: 1.8;
}
.lobby__note code { font-family: var(--font-num, monospace); color: var(--c-gold); }
.lobby__note strong { color: var(--c-red-soft); }

.home__nav {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sp-4);
    padding: var(--sp-5);
}
.navcard {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    padding: var(--sp-4);
    min-height: 76px;
    text-align: left;
    border-radius: var(--radius);
    border: 1px solid var(--c-line);
    background: linear-gradient(120deg, rgba(36, 26, 66, .55), rgba(12, 9, 18, .55));
    transition: border-color .16s, transform .08s, background .16s;
}
.navcard:hover { border-color: rgba(162, 77, 255, .55); background: linear-gradient(120deg, rgba(52, 36, 96, .7), rgba(12, 9, 18, .6)); }
.navcard:active { transform: translateY(1px); }
.navcard__ico {
    flex: none;
    width: 44px; height: 44px;
    border-radius: 0;                 /* 直角（原 12px） */
    display: grid;
    place-items: center;
    font-size: 20px;
    background: var(--grad-red);
    box-shadow: var(--glow-red);
}
.navcard--b .navcard__ico { background: var(--grad-purple); box-shadow: var(--glow-purple); }
.navcard__txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.navcard__t { display: block; font-size: var(--fs-md); font-weight: 700; }
.navcard__d { display: block; font-size: var(--fs-xs); color: var(--c-dim); }

.home__foot {
    padding: var(--sp-4) var(--sp-5) calc(var(--sp-5) + env(safe-area-inset-bottom));
    font-size: var(--fs-2xs);
    color: var(--c-faint);
    text-align: center;
    border-top: 1px solid var(--c-line-soft);
}

@media (min-width: 900px) {
    .hero { min-height: 66vh; }
    .hero__inner { padding: var(--sp-7) var(--gutter); max-width: 52ch; }
    /* ★ 字号固定 68px（用户口径：「『Gate Open, 界放』可以压在图上」）。
       上一版我把它改成 `min(68px, 5.5vw)`，理由是"别伸进主视觉图" ——
       那条顾虑被用户否掉了：**压在图上正是想要的效果**，不该为留白缩字号。
       压上去还读得清，靠的是 `.hero__title` 上的 `filter: drop-shadow()`
       （**不是** text-shadow，那玩意会和 background-clip:text 打架）。 */
    .hero__title { font-size: 68px; }
    .home__nav { grid-template-columns: repeat(3, 1fr); max-width: 1180px; width: 100%; margin: 0 auto; padding: var(--sp-6) var(--sp-7); }
    .navcard { flex-direction: column; align-items: flex-start; min-height: 150px; }
}
/* 窄屏：**头图改成铺满的暗背景**，不再用桌面那套"右侧原比例"。
   之前这里是 `display: none` —— 结果手机首屏只剩一团模糊暗色，
   看起来就像"图片没加载出来"。现在放回来：cover 铺满 + 顶部压暗保可读性。 */
@media (max-width: 899px) {
    .hero__img {
        display: block;
        width: 100%;
        height: 100%;
        left: 0;
        /* ⚠️ 桌面那两条必须在这里**显式撤掉**，否则窄屏头图会歪：
           · `transform: translateX(-50%)` 是配 `left:50%` 的居中手法，
             窄屏把 left 改成 0 之后它还留着 ⇒ 整张图再左移半幅（只看得见右半边）
           · `max-width:70%` 同上，铺满的意图被它卡成 70% 宽
           两者叠加的症状就是「头图缩在左边一小块，右边一大片空」。 */
        transform: none;
        max-width: none;
        object-fit: cover;
        object-position: 50% 18%;      /* 焦点偏上：留出角色头部，别只截到腿 */
        -webkit-mask-image: none;      /* 铺满时不需要边缘渐隐 */
        mask-image: none;
    }
    .hero__veil {
        background:
            linear-gradient(180deg, rgba(12, 11, 10, .58) 0%, rgba(12, 11, 10, .72) 40%, rgba(12, 11, 10, .93) 78%, var(--c-bg) 100%);
    }
    /* ★ 高度按 38vh：52vh 时「页头 44 + hero 438」= 482px，
       首屏 57% 被主视觉吃掉，三个功能入口卡全被推到折叠以下。
       38vh 在 390×844 上约 321px，首屏能看到入口。 */
    .hero { min-height: 38vh; justify-content: flex-end; }
    .hero__inner {
        max-width: none;
        padding: var(--sp-5) var(--gutter) var(--sp-6);
        gap: var(--sp-3);
    }
    .hero__title { font-size: var(--fs-2xl); }   /* 26px，原 38px 在 390 上偏大 */
    .hero__cta { height: 46px; padding: 0 20px; }  /* 触控目标 ≥44px */
}

/* ═══════════════════════════════════════════════════════════════════════
   主区 / 顶栏导航 / 手机底部 tab / 启动画面 / 占位屏
   ═══════════════════════════════════════════════════════════════════════ */

.main {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* ── 顶栏品牌 ──────────────────────────────────────────────────────────
   样式已合并到上方「顶栏」一节的 `.topbar__brand`（同一条规则写两遍会互相覆盖，
   且"后面那条赢"—— 留两份只会让以后改的人改错地方）。 */

/* ── 桌面横向导航（手机折回单行时隐藏，页面切换交给底部 tab）──────── */
.topnav { display: none; }
@media (min-width: 900px) {
    .topnav { display: flex; align-items: center; gap: 3px; }
    .topnav__i {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        height: 30px;
        padding: 0 23px;                    /* 用户在设计稿里调的值 */
        color: var(--c-dim);
        font-size: 15px;
        font-weight: 600;
        border: 0;
        background: none;
        position: relative;
    }
    .topnav__i:hover { color: var(--c-text); background: rgba(239, 233, 223, .06); }
    /* ★ 用户口径（设计稿导出）：选中态**只留一条 2px 红线**。
       原来是「整块变红 + var(--glow-red) 霓虹光晕」——
       红块压在深紫底上是两个高饱和色对撞，光晕再叠一层，观感廉价。
       现在底是暖黑，一条红线既安静、位置感又一样清楚。 */
    .topnav__i.is-on { color: var(--c-text); }
    .topnav__i.is-on::after {
        content: '';
        position: absolute;
        left: 10px;
        right: 10px;
        bottom: -1px;
        height: 2px;
        background: var(--c-red);
    }
    /* 2026-10-20：调试中 / 暂时封锁的入口（时轮、卡组编辑）——
       灰显 + 不可点感。真正的拦截在 store.js 的 LOCKED_ROUTES。 */
    .topnav__i.is-locked { opacity: .42; cursor: not-allowed; }
    .topnav__i.is-locked:hover { color: var(--c-dim); background: none; }
    .topnav__i.is-locked::before {
        content: '🔒';
        font-size: 11px;
        margin-right: -2px;
        filter: grayscale(1);
        opacity: .8;
    }
}

/* ── 手机底部 tab：单手可达、触控面积 ≥56px ──────────────────────── */
.tabbar {
    flex: none;
    display: flex;
    align-items: stretch;
    border-top: 1px solid var(--c-line-purple);
    background: linear-gradient(0deg, #241542, #1a1030);
    padding-bottom: env(safe-area-inset-bottom);
}
.tabbar__i {
    flex: 1;
    min-height: 56px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    color: var(--c-faint);
    font-size: var(--fs-2xs);
    font-weight: 600;
    transition: color .14s, background .14s;
}
.tabbar__i.is-on { color: #fff; background: linear-gradient(0deg, rgba(207, 58, 48, .42), transparent 70%); }
.tabbar__i.is-on::before {
    content: '';
    position: absolute;
    top: 0;
    width: 34px;
    height: 2px;
    background: var(--c-red);
    box-shadow: 0 0 10px var(--c-red);
}
.tabbar__i { position: relative; }
@media (min-width: 900px) { .tabbar { display: none; } }

/* ══ 全站页脚声明（非官方项目）══════════════════════════════════════════
   用户口径：「网页最下面还需要声明是非官方项目」——
   声明本身必须留（合规），但**不要做成一条横栏**：
   原来那版有底色 + 上边框 + 居中排列，横贯整屏像多出的一条 UI，用户口径
   「**底栏去了吧好丑**」⇒ 撤掉背景和边框，只留一行很淡的小字，
   视觉上退到"页脚说明"该有的位置。 */
.sitefoot {
    flex: none;
    display: flex;
    flex-wrap: wrap;                 /* 手机上自动换行 */
    align-items: center;
    justify-content: center;
    gap: 3px 10px;
    padding: 6px var(--gutter) 9px;
    font-size: 10px;
    line-height: 1.4;
    letter-spacing: .02em;
    color: rgba(239, 233, 223, .26);
    text-align: center;
    background: none;
    border: 0;
}
.sitefoot__dot { color: rgba(239, 233, 223, .14); }
@media (max-width: 899px) {
    .sitefoot { padding: 5px var(--sp-4); gap: 2px 8px; }
    .sitefoot__dot { display: none; }     /* 换行后分隔点没意义 */
}

/* ── 启动画面（卡库 5 MB，读盘期间别让用户看白屏）────────────────── */
.boot {
    height: 100dvh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-4);
}
.boot__mark {
    font-family: var(--font-num);
    font-size: 56px;
    font-weight: 900;
    letter-spacing: .1em;
    background: linear-gradient(96deg, var(--c-red-soft), var(--c-purple-soft));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    animation: bootpulse 1.4s ease-in-out infinite;
}
@keyframes bootpulse { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }
.boot__text { font-size: var(--fs-sm); color: var(--c-dim); letter-spacing: .2em; }

/* ── 未实现屏的占位 ──────────────────────────────────────────────── */
.todo {
    flex: 1;
    min-height: 0;
    display: grid;
    place-items: center;
    padding: var(--sp-5);
}
.todo__box {
    max-width: 520px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-3);
    text-align: center;
    padding: var(--sp-6) var(--sp-5);
    border: 1px solid var(--c-line);
    background: linear-gradient(160deg, rgba(36, 26, 66, .45), rgba(10, 8, 16, .5));
    /* 斜切：本设计的"破直角"手段（见 tokens.css 的形状口径）*/
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%);
}
.todo__ico {
    width: 56px; height: 56px;
    display: grid; place-items: center;
    background: var(--grad-purple);
    color: #fff;
    box-shadow: var(--glow-purple);
}
.todo__t { margin: 0; font-size: var(--fs-xl); font-weight: 800; }
.todo__d { margin: 0; color: var(--c-dim); font-size: var(--fs-sm); }
.todo__note { margin: 0; color: var(--c-faint); font-size: var(--fs-xs); line-height: 1.7; }
/* 「敬请期待」上方那行等宽小字（2026-10-18 占位屏改版时加的） */
.todo__k {
    font-family: var(--font-num);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .30em;
    color: var(--c-gold);
    opacity: .8;
}

/* ── 通用图标 ────────────────────────────────────────────────────── */
.ico { display: block; flex: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   对战大厅 · 房间列表 ｜ 建立房间（两栏）
   ───────────────────────────────────────────────────────────────────────────
   参照同类站 bs.quensonwai.com 的版式；参数由用户在设计稿里用滑条调定：
     房间列表 : 建立房间 = 1.75 : 1  ·  房间行内边距 15px
     窄屏单栏、**列表在上**（order: 2 → setup 排到列表之后）
   ⚠️ 本区块在文件**末尾**：旧的大厅样式（.home__nav / .navcard /
      .lobby__panel）还在上面，靠文档顺序被这里覆盖。确认无引用后可以单独清。
   ═══════════════════════════════════════════════════════════════════════════ */

.lobby__wrap { padding: var(--sp-6) var(--gutter) var(--sp-8); }
.lobby__tag {
    font-family: var(--font-num);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .16em;
    color: var(--c-gold);
}
.lobby__title {
    margin: 6px 0 0;
    font-family: var(--font-display);
    font-size: var(--fs-xl);
    font-weight: 700;
}
.lobby__hint { margin: 6px 0 0; font-size: var(--fs-xs); color: var(--c-faint); line-height: 1.7; }

.lobby__grid {
    display: grid;
    gap: var(--sp-5);
    align-items: start;
    margin-top: var(--sp-4);
    grid-template-columns: minmax(0, 1.75fr) minmax(320px, 1fr);
}
@media (max-width: 899px) {
    .lobby__grid { grid-template-columns: 1fr; gap: var(--sp-4); }
    .lobby__setup { order: 2; }        /* 用户口径：窄屏房间列表在上 */
}

.lobby__panel2 {
    border: 1px solid var(--c-line);
    background: rgba(21, 19, 18, .55);
}
.lobby__phead {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: var(--sp-4) var(--sp-5);
    border-bottom: 1px solid var(--c-line-soft);
}
.lobby__cnt {
    margin-left: auto;
    font-family: var(--font-num);
    font-size: 11px;
    letter-spacing: .05em;
    color: var(--c-faint);
}
.lobby__pbody { padding: var(--sp-5); }
.lobby__pfoot {
    padding: var(--sp-4) var(--sp-5);
    border-top: 1px solid var(--c-line-soft);
    font-size: var(--fs-xs);
    color: var(--c-faint);
    line-height: 1.7;
}

/* 筛选 chip */
.chips { display: inline-flex; gap: 6px; }
.chip {
    height: 28px;
    padding: 0 12px;
    cursor: pointer;
    font-family: inherit;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--c-dim);
    background: none;
    border: 1px solid var(--c-line);
}
.chip:hover { color: var(--c-text); }
.chip.is-on { color: var(--c-text); border-color: var(--c-red); background: rgba(207, 58, 48, .14); }

/* 房间行：整行可点，热区够大（手机上别做小按钮） */
.rooms { display: flex; flex-direction: column; }
.room {
    display: grid;
    gap: 2px 12px;
    align-items: center;
    width: 100%;
    grid-template-columns: 1fr auto;
    grid-template-areas: "name meta" "sub meta";
    padding: 15px var(--sp-5);          /* 用户导出值 */
    text-align: left;
    cursor: pointer;
    background: none;
    border: 0;
    border-bottom: 1px solid var(--c-line-soft);
    color: inherit;
    font-family: inherit;
    transition: background var(--dur-micro);
}
.room:last-child { border-bottom: 0; }
.room:hover { background: rgba(217, 187, 135, .05); }
.room__name {
    grid-area: name;
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--fs-md);
    font-weight: 600;
}
.room__sub {
    grid-area: sub;
    font-size: var(--fs-xs);
    color: var(--c-faint);
}
.room__meta { grid-area: meta; display: flex; align-items: center; gap: 8px; }
.room__lock { font-size: 11px; }
/* 空位用两个小方块表示：一眼扫出谁还缺人，比读 "1/2" 快 */
.seats { display: inline-flex; gap: 3px; }
.seat { width: 7px; height: 7px; border: 1px solid var(--c-line-strong); }
.seat.is-on { background: var(--c-green); border-color: var(--c-green); }

.tag {
    font-family: var(--font-num);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .08em;
    padding: 4px 7px;
    border: 1px solid var(--c-line);
    color: var(--c-dim);
}
.tag--wait { color: var(--c-green); border-color: rgba(47, 208, 122, .45); }

.rooms__empty {
    padding: var(--sp-7) var(--sp-5);
    text-align: center;
    color: var(--c-faint);
    font-size: var(--fs-sm);
    line-height: 1.8;
}

/* 建立房间表单 */
.field { margin-bottom: var(--sp-4); }
.field > label { display: block; font-size: var(--fs-xs); color: var(--c-dim); margin-bottom: 6px; }
.input {
    box-sizing: border-box;
    width: 100%;
    height: 38px;
    padding: 0 12px;
    background: #100e0d;
    color: var(--c-text);
    font-family: inherit;
    font-size: var(--fs-sm);
    border: 1px solid var(--c-line);
    outline: none;
}
.input:focus { border-color: var(--c-gold); }
.check { display: flex; align-items: flex-start; gap: 8px; margin-bottom: 10px; cursor: pointer; }
.check input { margin: 2px 0 0; accent-color: var(--c-red); }
.check__t { font-size: var(--fs-sm); }
.check__d { display: block; font-size: var(--fs-xs); color: var(--c-faint); margin-top: 2px; }

.seg { display: flex; }
.seg button {
    flex: 1;
    height: 32px;
    cursor: pointer;
    font-family: inherit;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--c-dim);
    background: none;
    border: 1px solid var(--c-line);
    margin-left: -1px;
}
.seg button:first-child { margin-left: 0; }
.seg button.is-on {
    color: var(--c-text);
    background: rgba(207, 58, 48, .16);
    border-color: var(--c-red);
    position: relative;
    z-index: 1;
}

.btn { width: 100%; height: 42px; cursor: pointer; font-family: inherit; font-size: var(--fs-sm); font-weight: 700; letter-spacing: .04em; border: 1px solid transparent; }
.btn--primary {
    color: #fff;
    background: linear-gradient(135deg, #d8453a, #8e2b23);
    border-color: rgba(240, 130, 115, .85);
    box-shadow: 0 0 16px rgba(207, 58, 48, .28);
}
.btn--ghost { color: var(--c-gold); background: rgba(239, 233, 223, .04); border-color: var(--c-line); }

.joinrow {
    display: flex;
    gap: 8px;
    margin-top: var(--sp-4);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--c-line-soft);
}
.joinrow .input { flex: 1; width: auto; font-family: var(--font-num); letter-spacing: .08em; }
.joinrow .btn { width: auto; padding: 0 20px; flex: none; }


