/* 商店改版布局层（CMD_shop_ui_v2，2026-10-08，Mavis 实现 / Codex 设计终审）
   属主：本文件只服务 #shop。shop.js 在运行时注入 <link>（不碰 index.html，避免抢首页那一个并发位）。
   规矩：
     1. 只在手机（.mobile）下生效，电脑版布局一个字不动。
     2. 不改价格 / 掉落 / 物品效果 —— 这里只有排版、间距、危险样式。
     3. 触控下限 44px（锁 / 解雇 / 信息 / 页签），且彼此留间距。
     4. 固定栏一律带 safe-area + 内容 padding，不盖刷新按钮和最后一行商品。
*/

/* ============================ 1. 头部：紧凑页签（层数 / 两币 / 直切） ============================ */
/* 头部本来就 position:sticky（style.css:291），页签塞进去就自带吸顶，不用另算 z-index 和遮挡。 */
#shop .shop-head .sl-tabs { display: flex; align-items: stretch; gap: .4em; width: 100%; margin: 0 0 .35em; }
#shop .sl-tab {
    flex: 1 1 0; min-width: 0; min-height: 44px; display: flex; align-items: center; justify-content: center; gap: .3em;
    padding: .35em .4em; border-radius: .4em; cursor: pointer; appearance: none; -webkit-appearance: none;
    border: 1px solid var(--line); background: #15131f; color: var(--muted); font: inherit; font-weight: 700;
    touch-action: manipulation; overflow: hidden;
}
#shop .sl-tab .cur { width: 15px; height: 15px; flex: none; vertical-align: -2px; }
#shop .sl-tab b { font-size: 1.05em; font-variant-numeric: tabular-nums; color: var(--text); }
#shop .sl-tab small { font-size: .68em; font-weight: 600; white-space: nowrap; }
#shop .sl-tab.on { background: linear-gradient(#ffe066, #c99a00); border-color: #ffd100; color: #1a1200; }
#shop .sl-tab.on b, #shop .sl-tab.on small { color: #1a1200; }
#shop .sl-tab .cur { filter: brightness(1.15) saturate(1.1); }
/* 页签上的红点：有能买的东西才亮，0 券不去强迫空逛 */
#shop .sl-tab .dot { width: .5em; height: .5em; border-radius: 50%; background: #6be06b; box-shadow: 0 0 .4em #6be06b; flex: none; }
#shop .sl-tab.on .dot { background: #7a1010; box-shadow: none; }

/* 当前 Boss 短提示 + 展开；后续两层词缀默认折叠 */
#shop .sl-boss { display: flex; align-items: center; gap: .4em; flex-wrap: wrap; }
#shop .sl-boss .bn { color: #ff9a4a; font-weight: 800; }
#shop .sl-boss .bt { color: var(--muted); font-size: .82em; min-width: 0; }
#shop .sl-fold {
    min-height: 44px; display: inline-flex; align-items: center; gap: .3em; padding: .3em .7em; border-radius: .35em;
    border: 1px solid var(--line); background: #15131f; color: var(--muted); font: inherit; font-size: .82em; font-weight: 700;
    cursor: pointer; touch-action: manipulation; appearance: none; -webkit-appearance: none;
}
#shop .sl-fold.open { color: var(--gold); border-color: rgba(255,209,0,.45); }

/* 后续两层词缀：默认收起，展开才占地方（原来占货架上方一大块） */
#shop .affprev { margin: .4em 0 .2em; }
#shop .sl-affwrap .affprev { display: none; }
#shop .sl-affwrap.open .affprev { display: block; }

/* ============================ 2. 商品上方短阵容摘要 ============================ */
/* 只放「人数 / 真实缺口 / 临近组合」三件事。缺口走 run.roleNeeds()（= Run.ROLE_WANT 的真实规则），
   不在界面上硬编码 2 坦 2 奶，也不改组队规则。 */
#shop .sl-sum {
    display: flex; align-items: center; gap: .35em; flex-wrap: wrap; margin: 0 0 .55em;
    padding: .45em .55em; border-radius: .4em; border: 1px solid var(--line); background: #141220; font-size: .82em;
}
#shop .sl-sum .n { font-weight: 800; color: var(--gold); font-variant-numeric: tabular-nums; }
#shop .sl-sum .gap { color: #ffb454; font-weight: 700; }
#shop .sl-sum .combo { color: #8fe08f; font-weight: 700; }
#shop .sl-sum .link {
    margin-left: auto; min-height: 44px; display: inline-flex; align-items: center; padding: .3em .6em;
    border-radius: .35em; border: 1px solid var(--line); background: #1d1a2b; color: var(--text);
    font: inherit; font-size: .92em; font-weight: 700; cursor: pointer; touch-action: manipulation;
    appearance: none; -webkit-appearance: none;
}
#shop .sl-sum.ok { color: var(--muted); }

/* ============================ 3. 金币竖屏 2 列紧凑卡 ============================ */
/* 竖屏 2 列紧凑卡：原来手机是 3 列且每张卡把长机制全铺开。这里竖屏固定 2 列，卡内只留
   图标 / 名称 / 职责或部位 / 主要收益 / 买下+价格 / 锁状态，其余移详情弹层。
   ⚠ 必须限定 .portrait：横屏走的是完整卡（不是 .compact），套 2 列会把卡挤窄、
   按钮文字被切（实测 844×390 有 4 个按钮 scrollWidth > clientWidth）。 */
#shop .offer { min-width: 0; }   /* 长名字 + 小字副名不许把网格撑出横向溢出 */
#shop .offer h4 { min-width: 0; overflow-wrap: anywhere; }
#shop .offer h4 small { overflow-wrap: anywhere; }
#shop .offer.compact { padding: 1.15em .45em .45em; gap: .25em; }
#shop .offer.compact .gicon { width: 2.6em; height: 2.6em; }
#shop .offer.compact .portrait { width: 3em; height: 3.9em; }
#shop .offer.compact h4 { font-size: .92em; line-height: 1.25; }
#shop .offer.compact .q { font-size: .66em; left: .4em; top: .35em; }
/* 职责 / 补位 / 护甲三个小标签：原来是一行 nowrap，2 列窄卡（≈181px）装不下会横向溢出 8px
   （实测 scrollWidth 374 vs clientWidth 367）。让它换行，不改标签内容和顺序。 */
#shop .offer .chips { flex-wrap: wrap; row-gap: .2em; min-width: 0; }
#shop .offer.compact .main { margin: 0; font-size: .78em; line-height: 1.4; color: #e8e2d0; }
#shop .offer.compact .main em { display: block; font-style: normal; color: var(--muted); font-size: .92em; }
/* 锁状态：明确写「已锁定 / 锁定」，不再是右上角一个看不出状态的字 */
/* 锁：固定 44×44 最小触控块。窄卡里原来只有 30px 宽（高 44），宽度不达触控下限 ——
   合同 §7「锁/解雇/信息等 44px 触控间距」。顺带这一条也是卡片那 8px 内部溢出的来源，
   锁定宽之后要重新量（见 测试结果.json 的 worstCardOverflow）。 */
#shop .offer.compact button.lock {
    position: static; width: auto; flex: 0 0 auto; min-width: 44px; min-height: 44px; margin: 0; padding: 0 .5em;
    font-size: .8em; font-weight: 700; border-radius: .35em; border: 1px solid var(--line);
    background: #1d1a2b; color: var(--muted);
    display: inline-flex; align-items: center; justify-content: center; touch-action: manipulation; white-space: nowrap;
}
/* 竖屏紧凑卡：这条透明热区在紧凑卡上是多余的，留着反而吃掉整张卡（2026-10-09 修 §5.1 竖屏购买键 0/6）。
   style.css:1447 的 `.mobile .offer button.lock::after{content:'';position:absolute;inset:-14px -8px}`
   是一条撑到 44px 的透明热区，它靠「锁键自己是 absolute」（style.css:764 的卡片右上角小徽章）才有
   正确的包含块。上面把锁键排进 .buyrow 时改成了 position:static —— 绝对定位的 ::after 于是失去包含块，
   改挂到 position:relative 的 .offer 上，一块几乎盖住整张卡的透明盒子记在 .lock 名下，
   同卡的购买键被整片吞掉（实测 390×844：买键 121×44，整张卡里属于它的像素 = 0，中心点命中的是 BUTTON.lock）。
   紧凑卡的锁键自己就 ≥44×44（上一行的 min-width/min-height），不需要再撑一层，所以直接让这条 ::after 别生成。
   为什么不给它换个 inset 而不是 display:none：那样必须把锁键改成 position:relative 才能重新当包含块，
   而 style.css:764 那条 .mobile .offer button.lock 还留着 right:.35em / top:.3em（本来是给绝对定位徽章用的）——
   一旦变成 relative，这两个偏移立刻生效，锁键会被挪 3px（实测 360×640 offsetLeft 116→113、offsetTop 120→123）。
   保持 static、只摘掉多余的热区：锁键一个像素都不动（offset 前后一致），购买键 6/6 恢复可点。 */
#shop .offer.compact button.lock::after { display: none; }
#shop .offer.compact button.lock.on { border-color: var(--gold); color: var(--gold); background: #2a2410; }
#shop .offer .buyrow { display: flex; align-items: stretch; gap: .3em; margin-top: .3em; width: 100%; max-width: 100%; }
#shop .offer .buyrow > button[data-act="buy"] { flex: 1 1 0; min-width: 0; min-height: 44px; }
/* 卖光 / 买不起：写清楚差多少，不让玩家猜 */
#shop .offer .why { font-size: .72em; color: #ff8a7a; }
#shop .offer .why.short { color: #ffb454; }
#shop .offer button:disabled { opacity: .5; }
/* 详情入口（长机制 / 组合技 / 教学都收进这里） */
#shop .sl-more {
    min-height: 44px; display: flex; align-items: center; justify-content: center; width: 100%;
    margin-top: .3em; padding: 0 .4em; border-radius: .35em; border: 1px dashed rgba(255,209,0,.4);
    background: rgba(255,209,0,.07); color: #ffe9a8; font: inherit; font-size: .8em; font-weight: 700;
    cursor: pointer; touch-action: manipulation; appearance: none; -webkit-appearance: none;
}

/* ============================ 4. 羁绊：默认已激活 / 临近，全部可查 ============================ */
#shop .bonds .bond.zero { display: none; }
#shop .bonds .bond { margin: .2em 0; }
#shop .sl-bondmore {
    min-height: 44px; display: flex; align-items: center; justify-content: center; width: 100%; margin: .3em 0 0;
    border-radius: .35em; border: 1px solid var(--line); background: #1d1a2b; color: var(--muted);
    font: inherit; font-size: .8em; font-weight: 700; cursor: pointer; touch-action: manipulation;
    appearance: none; -webkit-appearance: none;
}
#shop .bonds .sl-allbonds { margin-top: .3em; }
#shop .bonds .sl-allbonds .bond { display: flex; }
#shop .bonds .sl-allbonds .bond.zero { display: flex; opacity: .75; }

/* ============================ 5. 刷新：紧邻货架 + 上涨可见 + 买不起写差额 ============================ */
#shop .market-foot { flex-wrap: wrap; gap: .4em .6em; }
#shop .market-foot .refresh { min-height: 44px; }
#shop .market-foot .note { font-size: .76em; color: var(--muted); line-height: 1.35; }
#shop .market-foot .note .up { color: #ffb454; font-weight: 700; }
#shop .market-foot .note .short { color: #ff8a7a; font-weight: 700; }

/* ============================ 6. 生命分流：独立危险样式 + 一次确认 ============================ */
/* 事实核对（run.js:1175）：hpTax 只乘在主角一人的 maxHp 上，整局有效 —— 所以文案写「只扣你」，不写全队。 */
#shop .offer.prize.altar { border-color: #ff4d6d; background: linear-gradient(180deg, rgba(255,77,109,.16), #17121c 65%); }
#shop .offer.prize.altar .q { color: #ff8095; }
#shop .offer.prize.altar h4 { color: #ffb3c0; }
#shop .offer.prize.altar .sl-danger { margin: .25em 0; font-size: .76em; line-height: 1.4; color: #ffd0d8; }
#shop .offer.prize.altar .sl-danger b { color: #ff8095; }
#shop .offer.prize.altar .sl-danger .hp { font-variant-numeric: tabular-nums; font-weight: 800; color: #fff; }
#shop .offer.prize.altar .sl-danger .arrow { color: #ff8095; font-weight: 800; padding: 0 .15em; }
#shop .offer.prize.altar button[data-act="prize"] { border-color: #ff4d6d; background: #3a1220; color: #ffb3c0; }
#shop .offer.prize.altar button[data-act="prize"]:hover:not(:disabled) { background: #57192c; }
/* 已用掉的生命分流：留在状态条里，写清楚是「你 / 本局」 */
#shop .status .hptax { color: #ff8095; font-weight: 700; }

/* 确认层：只有「永久本局代价」才过一次；金币 / 券正常购买不弹 */
#shop .gsheet .sl-confirm { padding: .9em; }
#shop .gsheet .sl-confirm h4 { margin: 0 0 .3em; font-size: 1.05em; color: #ffb3c0; }
#shop .gsheet .sl-confirm p { margin: 0 0 .5em; font-size: .85em; line-height: 1.45; color: var(--text); }
#shop .gsheet .sl-confirm .sl-hp { font-variant-numeric: tabular-nums; font-weight: 800; }
#shop .gsheet .sl-confirm .acts { display: flex; gap: .5em; margin-top: .6em; }
#shop .gsheet .sl-confirm button {
    flex: 1 1 0; min-height: 44px; border-radius: .4em; font: inherit; font-weight: 800; font-size: .95em;
    border: 1px solid var(--line); background: #1d1a2b; color: var(--text); cursor: pointer; touch-action: manipulation;
}
#shop .gsheet .sl-confirm button.danger { border-color: #ff4d6d; background: #57192c; color: #ffd0d8; }

/* ============================ 7. 奖券预览：装给谁 / 旧装去哪 / 套装进度 ============================ */
/* 数据全部来自 run.previewGear 的真实预演（run.js:692），不编 DPS 百分比。 */
#shop .offer.prize .sl-pv { margin: .25em 0 0; font-size: .74em; line-height: 1.4; color: var(--muted); }
#shop .offer.prize .sl-pv .to { color: #ffe9a8; font-weight: 700; }
#shop .offer.prize .sl-pv .set { color: var(--gold); font-weight: 700; }
#shop .offer.prize .sl-pv .old { color: #cfc6b4; }

/* ============================ 8. 底部固定主按钮（两页都能开始） ============================ */
/* 原来手机版「开始下一层」只在第 2 页，金币页买完要点两次才走。这里两页常驻。
   固定栏不吃商品区：.panel.shop 加 padding-bottom，最后一行商品和刷新按钮都不会被盖。 */
/* ⚠ bottom:0 必须写。少写这一句，fixed 元素会退回「静态位置」（#shop 是滚动容器，
   它是最后一个子节点 → 静态位置就在内容末尾，滚动到顶时正好压在**屏幕顶部**），
   于是点页签会点到「开始下一层」直接开波。实测踩过：elementFromPoint(页签中心) 返回 BUTTON.go。 */
#shop .sl-foot {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 6; display: none;
    padding: .45em max(1em, env(safe-area-inset-right)) calc(.45em + env(safe-area-inset-bottom, 0px)) max(1em, env(safe-area-inset-left));
    background: linear-gradient(180deg, rgba(10,8,16,.6), var(--panel-solid) 40%);
    border-top: 1px solid var(--line); pointer-events: none;
}
#shop .sl-foot > * { pointer-events: auto; }
#shop .sl-foot button.go {
    width: 100%; min-height: 48px; display: flex; align-items: center; justify-content: center; gap: .4em;
    padding: .5em .8em; border-radius: .45em; border: 1px solid #ffd100; color: #1a1200; font-weight: 800;
    background: linear-gradient(#ffe066, #c99a00); font: inherit; font-size: 1.02em; cursor: pointer; touch-action: manipulation;
}
#shop .sl-foot button.go:disabled { opacity: .45; cursor: default; }
#shop .sl-foot .lb { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; text-align: left; }
#shop .sl-foot .lb small { font-weight: 600; font-size: .7em; opacity: .85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#shop .sl-foot kbd { display: none; }

/* 天赋三选一没选完：原有的流程阻断保留，固定栏跟着禁用，不绕过 onStart 条件 */
#shop .sl-foot.blocked button.go { background: #2a2438; border-color: var(--line); color: var(--muted); }
#shop .sl-foot .why { color: #ffb454; font-size: .72em; text-align: center; margin-top: .2em; font-weight: 700; }

/* ============================ 9. 详情底部弹层（长机制 / 组合技 / 教学） ============================ */
#shop .gsheet .sl-detail { padding: .9em; max-height: 70vh; overflow-y: auto; -webkit-overflow-scrolling: touch; }
#shop .gsheet .sl-detail h4 { margin: 0 0 .3em; font-size: 1.05em; }
#shop .gsheet .sl-detail .sec { margin: .45em 0 0; font-size: .82em; line-height: 1.5; color: var(--text); }
#shop .gsheet .sl-detail .sec em { display: block; font-style: normal; color: var(--muted); font-size: .94em; }
#shop .gsheet .sl-detail .close {
    width: 100%; min-height: 44px; margin-top: .7em; border-radius: .4em; border: 1px solid var(--line);
    background: #1d1a2b; color: var(--text); font: inherit; font-weight: 700; cursor: pointer; touch-action: manipulation;
}

/* ============================ 10. 触控间距：锁 / 解雇 / 信息 ============================ */
/* 横屏走的是完整卡（非 .compact），锁按钮用的是 style.css 里那条 .mobile 规则：
   position:absolute; padding:.2em .6em → 实测只有 30×28px。
   合同 §7 要求锁/解雇/信息 ≥44px。style.css 不能碰，所以在这里覆盖（属主边界内）。
   宽度取 44px 就够：实测「锁定」两字实际占 17.6px，44px 盒子的 content box 有 26px。
   （别拿 scrollWidth 当依据 —— <button> 的 scrollWidth 恒定虚高 8px，见测试里的 KNOWN_ARTIFACT。） */
.mobile #shop .offer button.lock { min-width: 44px; min-height: 44px; padding: 0 .5em; font-weight: 700; white-space: nowrap; }
#shop .roster li .fire { min-height: 44px; min-width: 44px; padding: .2em .6em; touch-action: manipulation; }
#shop .offer .give { min-height: 44px; touch-action: manipulation; }
#shop .offer .give b { padding-left: .2em; }
#shop .roster .needs .rolebar span { line-height: 2; }
/* 相邻可点元素之间留出间距，避免误触（不靠缩放，字号一律不小于 11px） */
#shop .offer.compact .buyrow { gap: .35em; }
#shop .pg-prize .prizes { gap: .5em; }
#shop .pg-prize .offer { min-width: 0; }
#shop .pg-prize .offer h4, #shop .pg-prize .offer .desc { overflow-wrap: anywhere; }

/* 底部提示条别压在固定栏上 */
#shop .gtoast { bottom: calc(5.5em + env(safe-area-inset-bottom, 0px)); }

/* ============================ 11. 横屏：左商品 / 右队伍，两区可滚 ============================ */
/* 横屏不切竖屏那套 2 列紧凑卡和固定底栏的挤压；保持左右分栏 + 共享稳定头尾。 */
#shop .shop-body { align-items: start; }
#shop .shop-body .market, #shop .shop-body .roster { min-width: 0; }

/* ============================ 12. 手机端生效范围 ============================ */
/* 下面这些是「只在手机」的部分。电脑版（无 .mobile）整份文件不产生任何布局变化。 */
#shop .sl-sum, #shop .sl-foot, #shop .shop-head .sl-tabs { display: none; }

.mobile #shop .sl-tabs { display: flex; }
.mobile #shop .sl-sum { display: flex; }
.mobile #shop .sl-foot { display: block; }
/* 固定底栏要占的位置：内容 padding-bottom 预留 + safe-area，刷新按钮和末行商品不被盖 */
.mobile #shop .panel.shop { padding-bottom: calc(5.6em + env(safe-area-inset-bottom, 0px)); }
/* 竖屏：页签头更紧凑一点，两行封顶 */
.mobile.portrait #shop .sl-tabs { gap: .3em; }
.mobile.portrait #shop .sl-tab { min-height: 44px; padding: .3em .3em; }
.mobile.portrait #shop .sl-tab small { font-size: .64em; }
/* 竖屏：金币货架 2 列紧凑卡；奖券摊 3 列（4 列太窄，字和触控不能靠缩放） */
.mobile.portrait #shop .pg-gold .offers { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5em; }
.mobile.portrait #shop .pg-prize .prizes { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* 竖屏紧凑卡的「买下」按钮里那个 <kbd>数字是电脑版快捷键（手机没有物理键盘），
   它带 white-space:nowrap，在 181px 的窄卡里把按钮内容顶宽 8px，卡片横向溢出。
   手机端不显示它 —— 不是隐藏功能，是去掉一个在触屏上没意义的装饰。 */
#shop .offer.compact kbd { display: none; }

/* 顶部短反馈不能同时受底部footer避让约束，否则被拉成整屏。 */
#shop .gtoast.top, .mobile #shop .gtoast.top { bottom: auto !important; height: auto; max-height: min(96px, 18vh); overflow: hidden; }
