/* Carta · 结构样式层：布局/组件/响应式。 */
  * { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

  /* ===== Global Button Tap Feedback ===== */
  @keyframes btnFlash { 0% { filter: brightness(1); } 50% { filter: brightness(1.25); } 100% { filter: brightness(1); } }
  @keyframes btnRipple {
    0% { box-shadow: 0 0 0 0 rgba(232,93,58,0.35); }
    100% { box-shadow: 0 0 0 10px rgba(232,93,58,0); }
  }
  button, .hub-link, [onclick], [role="button"] {
    transition: opacity .12s ease, background-color .12s ease, border-color .12s ease, color .12s ease, transform .12s ease, filter .12s ease, box-shadow .12s ease;
  }
  button:active, .hub-link:active, [onclick]:active, [role="button"]:active {
    opacity: 0.6;
  }
  /* 移动端触摸反馈：:active 在手机上不可靠，由 app.js 的 touch 监听加 .tapping 兜底 */
  .tapping { opacity: 0.55 !important; }
  /* 全屏遮罩弹窗：按住弹窗内任意处，容器（祖先）也会进入 :active，若不屏蔽会导致整个弹窗跟着变淡/缩。
     ① 容器自身 :active 不做任何反馈（不变淡/不缩/不变暗）；
     ② 弹窗内所有元素禁止缩放（防残留 transform 连带缩窗），内部按钮的「按住变淡」反馈保留。
     attr-mask 系列用类名覆盖，新增同类无需改这里；其余 overlay/modal 用 id 列举，新增时各补一行。 */
  .attr-mask:active,
  #siteDisabledOverlay:active, #pinOverlay:active, #successOverlay:active, #orderPinOverlay:active,
  #aboutModal:active, #transferOverlay:active, #seatsOverlay:active, #tableMenuOverlay:active,
  #tableFilterOverlay:active, #dishDescModal:active, #confirmModal:active, #promptModal:active,
  #allergenPickerOverlay:active, #allergenAdminOverlay:active, #tabPinOverlay:active, #smPickerOverlay:active, #entryPinOverlay:active {
    opacity: 1 !important; transform: none !important; filter: none !important;
  }
  /* v499：加 :not(.jelly-play) —— CSS 规范里【!important 声明优先级高于动画】，
     原规则会在按住时把果冻动画的 transform 清零，导致弹窗内按钮的果冻「看不见」（Jay 报）。
     排除正在播果冻的元素即可，其余「弹窗内禁止缩放」的原意完全保留。 */
  .attr-mask *:active:not(.jelly-play),
  #siteDisabledOverlay *:active:not(.jelly-play), #pinOverlay *:active:not(.jelly-play), #successOverlay *:active:not(.jelly-play), #orderPinOverlay *:active:not(.jelly-play),
  #aboutModal *:active:not(.jelly-play), #transferOverlay *:active:not(.jelly-play), #seatsOverlay *:active:not(.jelly-play), #tableMenuOverlay *:active:not(.jelly-play),
  #tableFilterOverlay *:active:not(.jelly-play), #dishDescModal *:active:not(.jelly-play), #confirmModal *:active:not(.jelly-play), #promptModal *:active:not(.jelly-play),
  #allergenPickerOverlay *:active:not(.jelly-play), #allergenAdminOverlay *:active:not(.jelly-play), #tabPinOverlay *:active:not(.jelly-play), #smPickerOverlay *:active:not(.jelly-play), #entryPinOverlay *:active:not(.jelly-play) {
    transform: none !important;
  }
  /* v401：纯挡冒泡容器（onclick 恰好 = event.stopPropagation() 的弹窗盒子/包裹层）按住不给任何反馈——
     它只拦点击、从不是真按钮。之前它匹配全局 [onclick]:active 与 .tapping 而变半透明（Jay 报「按住关于弹框变淡」）。
     用【精确串】匹配：event.stopPropagation();attrPickCount(…) 这类"挡冒泡+真动作"的按钮不是精确匹配，反馈照常保留。 */
  [onclick="event.stopPropagation()"]:active { opacity: 1 !important; transform: none !important; filter: none !important; }
  [onclick="event.stopPropagation()"].tapping { opacity: 1 !important; }
  /* v488：+/− 原来是「透明度压淡 + 0.35s 扩散阴影涟漪」＝ Jay 说的快闪。
     改为【按住变暗、松手恢复】：动作按钮无选中态，需要明确按压反馈。 */
  html, body { overscroll-behavior-y: none; }
  body {
    font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Noto Sans CJK SC', sans-serif;
    background: var(--bg);
    color: var(--text);
    min-height: 100dvh;
  }
  /* 🔒 v590 根治「底部多出一整屏空白」——顾客端文档滚动锁（由 setupCustomer 挂 .doc-lock）。
     病理：v361/v362/v380/v431 四代药全是【自愈型】——允许文档滚动器活着，等浏览器把滚动范围
     撑开后再掰回来，故永远存在一个「已经看见空白」的窗口期，治标不治本。
     🧹 v629：本锁成立后那四代自愈药在顾客端已整体删除（它们每次回前台要强制四次同步重排）。
     根修：把这个自由度直接删掉。按 CSS 规范，html 的 overflow 为 visible 时，body 的 overflow
     会被【传播到视口】→ 文档滚动范围硬钳为 0。浏览器还原过期 scrollY 也好、长锁屏后合成器带坏
     状态回来也好，都没有可撑开的范围 → 空白无处可生。
     ✅ 安全性已逐页核验：顾客端四页与全部弹层早在 v97/v118 起就是 position:fixed 定高内层滚动
        （#pageCustomerHome.active / .menu-layout / .myorders-scroll / .attr-mask 等 inset:0），
        文档滚动器纯属摆设 → 加锁零视觉变化、零行为变化（地址栏本来就不会收起，因为本来就没在滚）。
     🚨 绝不可挂到柜台/编辑端：#pageHome/#pageMenuEdit/#pageTranslate/#pageSettings/#pageComboEdit
        是真·文档流滚动页，锁死会让整页滚不动。故用类名按角色限定，不写进 body 基础规则。 */
  body.doc-lock { height: 100dvh; overflow: hidden; overscroll-behavior: none; }

  /* ===== NAV ===== */
  nav {
    position: fixed; top: 0; left: 0; right: 0; z-index: 100;
    height: var(--nav-h);
    background: var(--card);
    border-bottom: 1px solid var(--border);
    display: flex; align-items: center;
    padding: 0 12px;   /* v370：16 → 12，把 8px 还给店名（Jay：字号不动，把显示区拉长） */
    box-shadow: 0 1px 4px rgba(0,0,0,0.04);
  }
  /* v371：页头左侧容器（标题 + 店铺徽章绑在一起）。
     .kitchen-header h2 本身带 margin-right:auto——徽章若直接跟在 h2 后面会被推到最右、和按钮挤在一起。
     包一层「内容宽度」的 flex 容器并把 auto 外边距移到容器上，徽章才紧贴标题；其余 kitchen-header 一律不受影响。 */
  .hdr-l { display: flex; align-items: center; gap: 10px; margin-right: auto; min-width: 0; }
  .hdr-l h2 { margin-right: 0; }

  /* 🈯 v372 基准语言徽章 + 导入面板语言列声明。
     基准语言决定文本模板【第 1 列是哪种语言】。它错了不会报错——只会让整列译文静默串到别的语言上，
     等顾客看到西语菜名变成中文才发现（Jay）。所以它必须在两个地方都醒目：
     ① 编辑页头常驻徽章（导入面板是折叠的 <details>，不点开看不见，而"照模板直接导"恰恰最危险）
     ② 导入面板顶部的列顺序声明 + 警告。 */
  .base-tag {
    font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 999px;
    background: var(--green-light); color: var(--green);
    border: 1px solid color-mix(in srgb, var(--green) 35%, transparent);
    white-space: nowrap; flex: 0 0 auto;
  }
  .lang-spec {
    font-size: 12.5px; line-height: 1.75; margin: 10px 0;
    padding: 10px 12px; border-radius: 8px;
    background: var(--accent-light); border-left: 3px solid var(--accent); color: var(--text);
  }
  .lang-spec b { color: var(--accent); }
  .lang-spec .warn { display: block; margin-top: 6px; color: var(--text-sub); font-size: 11.5px; }

  /* 🏪 v371 店铺徽章：菜品/翻译/套餐三个编辑页的页头，恒显当前店铺名。
     超管常同时开五家店的标签页，进了编辑器却看不出这是谁家的菜单——改错一家就是真事故（Jay）。
     `.admin-only` 使其仅对 hub 可见（boot 对非 hub 角色统一隐藏），柜台/编辑端界面零变化。 */
  .store-tag {
    font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 999px;
    background: var(--accent-light); color: var(--accent);
    border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 220px;
    flex: 0 1 auto; min-width: 0;
  }
  nav .logo {
    font-size: 18px; font-weight: 700; color: var(--accent);
    margin-right: auto; display: flex; align-items: center; gap: 6px;   /* v370：8 → 6 */
    min-width: 0;                 /* v366：解锁收缩，否则 flex 子项默认 min-width:auto 会顶开导航栏 */
    flex: 1 1 auto;               /* v370：占满导航栏剩余宽度（顾客端标签区为空，全部归店名） */
  }
  /* v366 店名【绝不换行】：长店名一律单行 + 省略号。原来没有任何 nowrap/overflow 规则，
     店名一长就折行，把 56px 的导航栏撑成两行、顶掉下面的内容（Jay 报障）。 */
  nav .logo #navTitle {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
  }
  /* v366 店名图片（艺术字标）：与 logo 同一套等比缩放约束，任何比例都不变形、不超高 */
  nav .logo #navNameImg {
    max-height: 42px; max-width: 180px; width: auto; height: auto;
    display: none; object-fit: contain; flex-shrink: 0;
  }
  nav .logo svg { width: 24px; height: 24px; }
  /* v365 导航栏 logo：30px → 42px 高（导航栏 56px，上下各留 7px 呼吸），宽上限 90 → 120px。
     复杂 logo 在 30px 高度下细节糊成一团，而导航栏的垂直空间本来就是空着的。
     ⚠️ 同时修掉一个既有缺陷：原来写死 `height:30px` + `max-width:90px` —— 宽形 logo（横版字标）
     宽度被砍到 90px、高度却仍钉在 30px，图会被【横向压扁】。改用 max-height + max-width + 双 auto：
     替换元素按固有宽高比等比缩放至同时满足两个上限，不再变形。 */
  nav .logo #navLogo { max-height: 42px; max-width: 96px; width: auto; height: auto; display: block; object-fit: contain; flex-shrink: 0; } /* v370：宽上限 120 → 96，只影响【宽形字标】；方形 logo 渲染宽仅 42px，高度 42px 一分不减 */
  /* v139 规范②条款：.tabs 是 nav 的 flex 子项，默认 min-width:auto 拒绝收缩会把最右 tab 推出屏——解锁后内部规则才生效 */
  nav .tabs { display: flex; gap: 4px; flex: 0 1 auto; min-width: 0; }
  nav .tab {
    padding: 8px 16px; border-radius: 8px; font-size: 14px; font-weight: 500;
    border: none; background: none; color: var(--text-sub); cursor: pointer;
    transition: all .2s; touch-action: manipulation;
  }
  nav .tab.active { background: var(--accent); color: #fff; }
  nav .tab:not(.active):hover { background: var(--accent-light); color: var(--accent); }

  /* ===== PAGES ===== */
  .page { display: none; padding-top: calc(var(--nav-h) + 16px); padding-bottom: 140px; min-height: 100dvh; }
  .page.active { display: block; }
  /* 🧭 v516（Jay 报：手机/iPad 柜台端在【餐桌页】向下滑，顶部导航会跟着往下移一段再弹回）。
     真因：餐桌页是普通文档流页面（.page），滚动发生在 document 上；iOS 的文档级橡皮筋
     会把 position:fixed 的 nav 一起拖走 —— 正是 .menu-list 注释里点名的「当年导航漂移 bug」。
     html/body 虽已有 overscroll-behavior-y:none，但在 iOS 上挡不住这条（顾客端之所以没事，
     是因为那边滚动本就关在 .menu-list / .myorders-scroll 等定高容器里，body 根本不滚）。
     解法沿用 v97/v118 经 Jay 真机验收的方案（勿再改回文档滚动）：
     body 不滚 → 定高内层滚动区 + overscroll-behavior:contain，回弹关在容器内，导航纹丝不动。
     · min-height 必须归 0：.page 的 min-height:100dvh 会把这个 top/bottom 已定高的容器撑破出视口。
     · padding-top 收为 16px：位置已由 top:var(--nav-h) 决定，再叠 .page 那份就重复留白。
     · padding-bottom 沿用 .page 的 140px 不动，保住右下角悬浮按钮的避让空间。
     · 桌面端 .page:not(...) 的 max-width:600px + margin:auto 仍生效（fixed + left/right:0 下照样居中）。 */
  #pageTables.active {
    position: fixed; top: var(--nav-h); left: 0; right: 0; bottom: 0;
    min-height: 0; overflow-y: auto;
    overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
    padding-top: 16px;
  }

  /* 还有未完成订单时：员工端整页泛起暖色，全部完成自动退回中性（背景氛围提醒） */
  body { transition: background-color .5s ease; }
  body.has-pending { background-color: #FDECC8; }
  body.has-pending .page { background-color: #FDECC8; transition: background-color .5s ease; }
  body.has-pending .kitchen-header { background-color: #FDECC8; transition: background-color .5s ease; }

  /* ===== TEST HUB ===== */
  /* ===== 超管侧栏控制台 ===== */
  #pageHub { padding: 0; }
  .ac-wrap { display:flex; flex-direction:column; height:100vh; overflow:hidden; }
  .ac-top { position:sticky; top:0; z-index:40; display:flex; align-items:center; gap:12px; padding:12px 18px; background:var(--card); border-bottom:1px solid var(--border); }
  .ac-logo { display:flex; align-items:center; gap:9px; font-weight:800; font-size:15px; white-space:nowrap; }
  /* v367/v368：后台品牌标识 = 奇妙 logo（原为 ⚡ emoji 占位）。
     v368：去掉橙色底板与内边距——那个橙底是 App 图标（手机主屏）的需要，后台不需要；这里只要 logo 本身。
     深色后台上：灯泡的黄 + 灯座的白足以立住，无需底板。 */
  .ac-logo .z { width:30px; height:30px; background:none; padding:0; display:grid; place-items:center; flex:0 0 auto; }
  .ac-top .sp { flex:1; }
  .ac-pick { display:inline-flex; align-items:center; gap:6px; background:var(--bg); border:1px solid var(--border); border-radius:9px; padding:6px 10px; font-size:13px; font-weight:600; }
  .ac-pick select { font:inherit; font-weight:600; border:0; background:transparent; color:var(--text); cursor:pointer; outline:none; max-width:42vw; }
  .ac-chip { font-size:11.5px; font-weight:700; padding:4px 11px; border-radius:20px; white-space:nowrap; }
  .ac-chip.on { background:var(--green-light); color:var(--green); }
  .ac-chip.off { background:#FDECEC; color:#e53e3e; }
  .ac-l1 { display:grid; grid-template-columns:214px 1fr; flex:1; min-height:0; overflow:hidden; }
  .ac-rail { border-right:1px solid var(--border); padding:14px 12px; background:#FCFBF9; overflow-y:auto; }
  .ac-grp { display:flex; align-items:center; gap:6px; font-size:10px; font-weight:800; letter-spacing:.12em; color:var(--gc,var(--text-sub)); padding:14px 9px 6px; }
  .ac-grp::before { content:''; width:6px; height:6px; border-radius:50%; background:var(--gc,var(--text-sub)); flex:0 0 auto; }
  .ac-grp:first-child { padding-top:2px; }
  .ac-grp.danger-grp { margin-top:10px; padding-top:14px; border-top:1px solid var(--border); }
  .ac-nav { display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:10px; cursor:pointer; color:var(--text-sub); font-weight:600; font-size:13px; border:1px solid transparent; user-select:none; transition:background .14s ease, border-color .14s ease; }
  .ac-nav.primary { font-weight:700; }
  .ac-nav .ic { width:24px; height:24px; border-radius:7px; display:grid; place-items:center; font-size:13px; background:var(--surface); background:color-mix(in srgb, var(--ac,var(--accent)) 15%, transparent); border:1px solid var(--border); border-color:color-mix(in srgb, var(--ac,var(--accent)) 30%, transparent); flex:0 0 auto; }
  .ac-nav:hover { background:var(--surface); background:color-mix(in srgb, var(--ac,var(--accent)) 9%, transparent); color:var(--text); }
  .ac-nav.on { background:var(--card); color:var(--text); border-color:var(--ac,var(--accent)); box-shadow:var(--shadow); }
  .ac-nav.on .ic { background:var(--ac,var(--accent)); border-color:transparent; color:#fff; }
  .ac-content { padding:22px clamp(16px,2.4vw,28px); overflow-y:auto; }
  .ac-area { display:none; }
  .ac-area.on { display:block; }
  .ac-head { display:flex; align-items:center; gap:12px; margin-bottom:16px; }
  .ac-head .ic { width:42px; height:42px; border-radius:11px; display:grid; place-items:center; font-size:20px; flex:0 0 auto; }
  .ac-head h3 { font-size:17px; font-weight:700; margin:0; }
  .ac-head .d { font-size:12px; color:var(--text-sub); margin-top:2px; }
  .ac-panel { background:var(--card); border:1px solid var(--border); border-radius:var(--radius); padding:18px; box-shadow:var(--shadow); }
  .ac-panel.danger { border-color:#f3b6b6; background:#FFFBFB; }
  .ac-panel h3 { font-size:15px; margin-bottom:6px; }
  .ac-stats { display:grid; grid-template-columns:repeat(auto-fit,minmax(120px,1fr)); gap:12px; }
  .ac-stat { background:var(--card); border:1px solid var(--border); border-radius:13px; padding:14px 16px; box-shadow:var(--shadow); }
  .ac-stat .v { font-size:26px; font-weight:800; }
  .ac-stat .k { font-size:12px; color:var(--text-sub); margin-top:2px; }
  @media (max-width:720px) {
    .ac-wrap { height:auto; overflow:visible; }
    .ac-l1 { grid-template-columns:1fr; overflow:visible; }
    .ac-rail { display:flex; gap:6px; overflow-x:auto; border-right:0; border-bottom:1px solid var(--border); position:sticky; top:57px; z-index:30; padding:10px 12px; }
    .ac-grp { display:none; }
    .ac-nav { flex:0 0 auto; white-space:nowrap; }
  }


  .desc { font-size: 13px; color: var(--text-sub); margin-bottom: 14px; line-height: 1.5; }
  .link-row { display: flex; gap: 8px; flex-wrap: wrap; }
  .hub-link {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 9px 16px; border-radius: 8px; border: none;
    font-size: 13px; font-weight: 600; cursor: pointer;
    text-decoration: none; transition: all .15s; touch-action: manipulation;
  }
  .hub-link.orange { background: var(--accent); color: #fff; }
  .hub-link.dark { background: var(--text); color: #fff; }
  .hub-link.green { background: var(--green); color: #fff; }   /* v623：类名在 HTML 里用了很久，样式却一直不存在 → 「➕ 新增店铺」是个纯透明按钮 */
  .hub-link.outline { background: none; border: 1.5px solid var(--border); color: var(--text); }
  /* v623：面板底色上的「添加一项」按钮。不能用 .me-btn —— 它底色是 var(--card)，
     与面板同色 = 隐形（本条规则见 AI_NOTES「UI 铁律 5」）。这里比面板暗一档 + accent 描边。 */
  .add-row-btn { display:inline-flex; align-items:center; gap:6px; padding:8px 14px; border-radius:8px;
    background: var(--surface); border: 1.5px dashed var(--accent); color: var(--accent);
    font-size:12px; font-weight:700; font-family:inherit; cursor:pointer; touch-action:manipulation; }
  .hub-link.st-on  { background: #10B981 !important; border-color: #10B981 !important; color: #fff !important; }
  .hub-link.st-off { background: #EF4444 !important; border-color: #EF4444 !important; color: #fff !important; }

  /* ===== PIN OVERLAY ===== */
  .pin-overlay {
    position: fixed; inset: 0; z-index: 999;
    background: rgba(0,0,0,0.5); backdrop-filter: blur(8px);
    display: flex; align-items: center; justify-content: center;
  }
  .pin-box {
    background: var(--card); border-radius: 16px; padding: 32px; width: 320px;
    box-shadow: var(--shadow-lg); text-align: center;
  }
  .pin-box h3 { font-size: 18px; font-weight: 700; margin-bottom: 6px; }
  .pin-box p { font-size: 13px; color: var(--text-sub); margin-bottom: 20px; }
  .pin-input {
    width: 100%; padding: 14px; border: 2px solid var(--border); border-radius: 10px;
    font-size: 24px; font-family: inherit; text-align: center; letter-spacing: 8px;
    margin-bottom: 16px; transition: border-color .2s;
  }
  .pin-input:focus { outline: none; border-color: var(--accent); }
  .pin-input.error { border-color: #e53e3e; animation: shake .4s ease; }
  /* 🎫 v488 登录名额已满：副标题转红并放宽行距（这条文案是两行的长句，
     必须留在屏幕上而不是用 toast —— 店员回头再看时还得看得见原因）。 */
  .pin-box p.pin-err { color: #e53e3e; font-weight: 600; line-height: 1.5; }
  @keyframes shake { 20%,60% { transform: translateX(-6px); } 40%,80% { transform: translateX(6px); } }
  .pin-submit {
    width: 100%; padding: 14px; border-radius: 10px; border: none;
    background: var(--accent); color: #fff; font-size: 16px; font-weight: 700;
    cursor: pointer; touch-action: manipulation;
  }  @keyframes popIn { 0% { transform: scale(0); } 50% { transform: scale(1.2); } 100% { transform: scale(1); } }

  .cart-float {
    position: fixed; bottom: 76px; left: auto; right: 16px; z-index: 90;
    background: var(--text); color: #fff; border-radius: 16px;
    padding: 14px 18px; box-shadow: var(--shadow-lg);
    display: none; align-items: center; gap: 12px; animation: slideUp .3s ease;
    width: fit-content; max-width: calc(100vw - 32px);
  }
  .cart-float.show {
    display: flex;
    /* v400：给这条固定悬浮下单条一块独立稳定的合成层。手机快速甩动菜单、主线程一卡时，
       合成器会给没有自有图层的 fixed 元素贴上错误的滚动补偿 transform → 视觉上「向右上飞走消失」。
       仅 .show（购物车有货）时提层，隐藏时不留常驻图层，符合合成器减压纪律。 */
    transform: translateZ(0);
  }
  @keyframes slideUp { from { transform: translateY(30px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }  /* 单条「查看购物车」浮条：整条可点 → 打开购物车弹层 */
  .cart-bar-btn {
    flex: 1; display: flex; align-items: center; gap: 12px;
    background: none; border: 0; color: #fff; font: inherit; text-align: left;
    cursor: pointer; padding: 0; touch-action: manipulation; min-width: 0;
  }
  .cart-bar-btn:active, .cart-bar-btn.tapping { opacity: 1 !important; filter: brightness(.9); }
  .cb-info {
    flex: 1; min-width: 0; font-size: 14px; font-weight: 600; white-space: nowrap;
    display: flex; flex-direction: column; justify-content: center; gap: 1px; line-height: 1.2;
  }
  .cb-info .cb-line { white-space: nowrap; }
  .cb-cart {
    flex: 0 0 auto; background: rgba(255,255,255,0.14); color: #fff;
    font-size: 13px; font-weight: 700; padding: 8px 13px; border-radius: 10px;
    white-space: nowrap;
  }
  .cb-cart:active, .cb-cart.tapping { opacity: 1 !important; filter: brightness(.9); }
  .cb-order {
    flex: 0 0 auto; margin-left: 8px; border: 0; font-family: inherit;
    background: var(--accent); color: #fff; cursor: pointer; touch-action: manipulation;
    font-size: 14px; font-weight: 800; padding: 9px 18px; border-radius: 10px;
    white-space: nowrap; letter-spacing: .3px;
  }
  .cb-order:active, .cb-order.tapping { opacity: 1 !important; background: var(--accent-dark); }  /* ===== 点餐菜单布局 ===== */
  .menu-layout {
    display: flex; gap: 0; margin: 0; flex: 1;
    height: calc(100dvh - var(--nav-h) - 52px);
    position: fixed; top: var(--nav-h); left: 0; right: 0;
    bottom: 52px; /* customer bottom nav */
  }
  /* 分类栏 — 固定左侧，独立滚动但由代码控制 */
  .cat-bar {
    width: 88px; flex-shrink: 0; background: #F0EFEC;
    display: flex; flex-direction: column; gap: 2px;
    padding: 6px 0; overflow-y: auto;
    -ms-overflow-style: none; scrollbar-width: none;
  }
  .cat-bar::-webkit-scrollbar { display: none; }
  .cat-btn {
    padding: 14px 6px; border: none; background: none;
    font-size: 13px; font-weight: 500; color: var(--text-sub);
    cursor: pointer; text-align: center; transition: all .15s;
    border-left: 3px solid transparent; touch-action: manipulation;
    line-height: 1.3; white-space: normal; overflow-wrap: normal; min-width: 0;
    position: relative;
  }
  .cat-btn .cat-emoji { position: absolute; top: 2.5px; left: 2.5px; line-height: 1; pointer-events: none;
    font-size: 13px; /* v607：原由 .tw-emoji img 宽高 13px 控制，改用原生 emoji 后由字号控制 */ }
  .cat-btn .cat-text { display: block; }
  .cat-btn.active {
    background: var(--card); color: var(--accent);
    border-left-color: var(--accent);
  }
  /* v488：分类（含套餐分类 .cat-btn-combo）有 .active 选中外框 → 按压零反馈 */
  .cat-btn:active, .cat-btn.tapping { opacity: 1 !important; background: inherit; }

  /* 菜品列表 — 唯一滚动区域 */
  .menu-list {
    flex: 1; padding: 0 12px 160px 12px; overflow-y: auto;
    /* ★ v118 恢复 v97 真机验收方案（勿再改回 none！）：
       精炼规则 = html/body 与所有弹层 sheet 保持 none（挡文档级回弹=当年导航漂移 bug 的源头）；
       但「定高内层滚动区 + body 不滚」的三处（菜单列表/我的订单/顾客主页）用 contain——
       橡皮筋回弹关在容器内，导航与背景纹丝不动。Jay 真机验收通过（v97）。
       切语言后的滚动高度异常由 app.js 的 clamp 兜底（见「根治」注释处）。 */
    overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  }
  /* 订单历史页：与菜单页同款——滚动关在内部定高容器里，body 不滚，避免手机地址栏收起/全屏效果 */
  .myorders-scroll {
    position: fixed; top: var(--nav-h); left: 0; right: 0;
    height: calc(100dvh - var(--nav-h) - 52px);
    /* ★ v118：有界内层滚动区用 contain（回弹关在容器内），见 .menu-list 处的精炼规则 */
    overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  }
  .myorders-inner { max-width: 600px; margin: 0 auto; padding: 16px 16px calc(40px + env(safe-area-inset-bottom, 0px)); }
  .menu-cat-title {
    font-size: 16px; font-weight: 700; padding: 16px 4px 10px;
    color: var(--text); position: sticky; top: 0;
    background: var(--bg); z-index: 2;
  }
  .cat-closed-banner {
    margin: 0 4px 10px; padding: 8px 12px; border-radius: 8px;
    background: #FEF9C3; color: #92660A; border: 1px solid #FDE68A;
    font-size: 13px; font-weight: 700;
  }
  /* v607：Twemoji 已移除，改用系统原生 emoji（天然随字号缩放，无需额外规则） */
  /* 菜品卡片 */
  .dish-card {
    display: flex; gap: 12px; padding: 12px;
    background: var(--card); border-radius: var(--radius);
    box-shadow: var(--shadow); margin-bottom: 10px;
    align-items: center;
  }
  .dish-img {
    width: 80px; height: 80px; border-radius: 10px;
    background: #EEECEA; flex-shrink: 0; position: relative;
    display: flex; align-items: center; justify-content: center;
    font-size: 45px; /* v607：原 32px 容器 + .tw-emoji img 1.4em = 44.8px；改原生 emoji 后由此字号直接控制 */
    overflow: hidden;
  }
  .dish-img img { width: 100%; height: 100%; object-fit: cover; }
  /* v460：点单端点菜品图放大时同样去掉半透明白层——.dish-img 带 onclick，命中全局 [onclick]:active{opacity:.6} 与 .tapping{opacity:.55}，
     整张缩略图被压淡＝白闪。禁掉这张图的按压 opacity，丝滑进大图查看器（同 v459 落地图、v455 套餐行手法）。 */
  .dish-img:active, .dish-img.tapping { opacity: 1 !important; }
  .dish-info { flex: 1; min-width: 0; }
  .dish-name { font-size: 15px; font-weight: 600; margin-bottom: 3px; }
  .dish-desc { font-size: 12px; color: var(--text-sub); margin-bottom: 6px; line-height: 1.4;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .dish-desc.truncated { cursor: pointer; text-decoration: underline dotted; text-decoration-color: var(--border); text-underline-offset: 2px; }
  .dish-desc.truncated:active { opacity: .55; }
  .dish-bottom { display: flex; align-items: center; justify-content: space-between; }
  .dish-price { font-size: 15px; font-weight: 700; color: var(--accent); }
  .dish-num-tag { font-size: 11px; color: var(--text-sub); background: #F0EFEC;
    padding: 2px 6px; border-radius: 4px; margin-left: 6px; }
  .dishimg-emoji { font-size: 120px; line-height: 1; } /* v607：原由 .tw-emoji img 宽高 120px 控制 */
  /* 🚨 v524（Jay 报：点单端看大图，按左右箭头时按钮往下掉一个身位再弹回）。
     真因：本按钮原用 top:50% + transform:translateY(-50%) 做垂直居中，而 #dishImgMask 属于 .attr-mask，
     全局有 `.attr-mask *:active:not(.jelly-play){transform:none!important}`（防按压时缩放残留）——
     一按下去居中用的 translateY(-50%) 就被清空 → 按钮下坠半个身高(17px)；松手 transform 回来 → 弹回。
     修法不是加豁免（同等特异性还要跟源码顺序较劲），而是【让它根本不依赖 transform 居中】：
     按钮高度固定 34px，改用 margin-top:-17px，那条全局规则就再也伤不到它。
     果冻的 scale 动画不受影响（它走 animation，且 :not(.jelly-play) 本就排除）。 */
  .dishimg-nav { position: absolute; top: 50%; margin-top: -17px; width: 34px; height: 34px; border: 0; border-radius: 50%; background: rgba(255,255,255,.82); color: var(--text); font-size: 22px; line-height: 1; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 2; box-shadow: 0 2px 8px rgba(0,0,0,.18); -webkit-tap-highlight-color: transparent; padding: 0; }
  .di-panel { flex: 0 0 100%; height: 100%; }
  .dish-nomenu-tag { font-size: 10px; font-weight: 700; color: #1F2937;
    background: #FBBF24; border: 1px solid #D97706;
    padding: 1px 7px; border-radius: 7px; white-space: nowrap; }
  /* 加减控件 */
  .qty-ctrl {
    display: flex; align-items: center; gap: 0;
  }
  .qty-btn {
    width: 30px; height: 30px; border-radius: 50%; border: none;
    font-size: 18px; font-weight: 700; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    touch-action: manipulation; transition: all .12s;
  }
  .qty-minus {
    background: #EEECEA; color: var(--text-sub);
  }
  .qty-plus {
    background: var(--accent); color: #fff;
  }
  .qty-num {
    width: 32px; text-align: center; font-size: 16px; font-weight: 700;
  }
  .qty-ctrl.zero .qty-minus,
  .qty-ctrl.zero .qty-num { display: none; }
  .qty-ctrl.zero .qty-plus { width: 30px; height: 30px; }

  .success-overlay {
    position: fixed; inset: 0; z-index: 200;
    background: rgba(0,0,0,0.4);
    align-items: center; justify-content: center;
    pointer-events: none;
    /* 🩹 v427：隐藏态改 display:none —— 元素及子树【完全退出渲染/合成树】，根治 v381/v382 遗留的幽灵闪现：
       原 visibility:hidden 挡得住绘制，却挡不住 .success-box 的 transform 常驻一个 GPU 合成层，
       快速切底部导航、合成器抽风重排的瞬间被误画成「下单成功！」一闪。display:none 让那个层根本不存在。
       显示动画改 keyframe（display:none→flex 时 transition 不触发、animation 会），弹入/淡入效果照旧保留。 */
    display: none;
  }
  .success-overlay.show { display: flex; pointer-events: auto; backdrop-filter: blur(4px); animation: successFade .22s ease; }
  .success-box {
    background: var(--card); border-radius: 20px; padding: 40px; text-align: center;
    box-shadow: var(--shadow-lg);
    max-width: 300px; width: 90%;
  }
  .success-overlay.show .success-box { animation: successPop .32s cubic-bezier(.22,.61,.36,1); }
  @keyframes successFade { from { opacity: 0; } to { opacity: 1; } }
  @keyframes successPop { from { transform: scale(.9); opacity: .5; } to { transform: scale(1); opacity: 1; } }
  .success-box .check { font-size: 56px; margin-bottom: 12px; }
  .success-box h3 { font-size: 20px; font-weight: 700; margin-bottom: 6px; }
  .success-box p { font-size: 14px; color: var(--text-sub); }

  /* ===== 厨房页 — 双栏布局 ===== */
  /* 🧭 v517：工作端（厨房/出菜/寿司/柜台共用此页）与餐桌页同病——原本是文档流滚动，
     iOS 文档级橡皮筋会把 position:fixed 的 nav 一起拖走。沿用 v97/v118、v516 同一套方案：
     body 不滚 → 定高内层滚动区 + overscroll-behavior:contain。
     · 保留 flex 纵向布局不变（.kitchen-header 固定高、.kitchen-body flex:1 min-height:0 照旧）。
     · min-height 归 0：.page 的 min-height:100dvh 会把已由 top/bottom 定高的容器撑破出视口。
     · padding-top 收为 16px（位置已由 top 决定）；padding-bottom 沿用 .page 的 140px。
     · 订单内容超出时，溢出仍计入本容器 scrollHeight，照常可滚到底，不会被裁。 */
  #pageKitchen.active {
    display: flex; flex-direction: column;
    position: fixed; top: var(--nav-h); left: 0; right: 0; bottom: 0;
    min-height: 0; overflow-y: auto;
    overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
    padding-top: 16px;
  }

  /* 全屏模式 */
  :fullscreen nav, :-webkit-full-screen nav { display: none !important; }
  :fullscreen .page, :-webkit-full-screen .page { padding-top: 8px !important; }
  :fullscreen .orders-main, :-webkit-full-screen .orders-main {
    max-height: calc(100dvh - 80px) !important;
  }
  :fullscreen .stats-panel, :-webkit-full-screen .stats-panel {
    max-height: calc(100dvh - 80px) !important;
  }

  .kitchen-header {
    margin: 0 16px 12px; padding: 14px 16px; background: var(--card);
    border-radius: var(--radius); box-shadow: var(--shadow);
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap; flex-shrink: 0;
  }
  .kitchen-header h2 { font-size: 18px; font-weight: 700; margin-right: auto; }
  .kitchen-header .order-count {
    padding: 4px 12px; border-radius: 20px; font-size: 13px; font-weight: 600;
    background: var(--accent-light); color: var(--accent);
  }
  .sync-dot {
    width: 8px; height: 8px; border-radius: 50%; background: var(--green);
    display: inline-block; animation: pulse 2s infinite;
  }
  @keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .3; } }
  .kitchen-btn {
    padding: 8px 14px; border-radius: 8px; border: 1px solid var(--border);
    background: var(--card); font-size: 13px; color: var(--text-sub);
    cursor: pointer; touch-action: manipulation;
  }
  .kitchen-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); }
  /* v475 药丸切换按钮（外形：胶囊 + 标签）。v514 起内部标记改为免密同款滑块开关，见下方注释。 */
  .pill-toggle {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 7px 15px; min-height: 36px; box-sizing: border-box;
    border-radius: 999px; border: 1.5px solid var(--border);
    background: var(--surface); color: var(--text-sub);
    font-size: 13px; font-weight: 600; font-family: inherit; line-height: 1;
    cursor: pointer; touch-action: manipulation; white-space: nowrap;
    transition: background .16s ease, color .16s ease, border-color .16s ease;
  }
  /* v514（Jay）：通知 / 只看未完成 改用与「餐桌·免密」【完全同一套】滑块开关——
     直接复用 .ttbl-tgl + .ttbl-tgl-knob，不另造一套，两处控件语言从此一致
     （左灰=关、右绿=开，店员有现成肌肉记忆，不必读字判断状态）。
     .on 的表现同样对齐免密：边框与文字转绿、底色不变；原来「整颗药丸填实 accent」
     与绿色滑块会打架，故一并改掉。原 .pt-dot 圆点标记随之作废，已删。
     按压：本控件有选中态（.on）→ 按 Jay 两类规则属第①类，按压【零视觉变化】，
     不再 brightness——滑块自身的滑动已是足够反馈，再压暗反而多一层图层。 */
  .pill-toggle.on { border-color: #34C759; color: #15803D; }
  .pill-toggle.on .ttbl-tgl { background: #34C759; }
  .pill-toggle.on .ttbl-tgl-knob { left: 17px; }
  .pill-toggle:active, .pill-toggle.tapping { opacity: 1 !important; }

  /* ===== 餐桌卡片（精简版）===== */
  .ttbl-card { background: var(--card); border-radius: 12px; box-shadow: var(--shadow); padding: 9px 11px 10px; display: flex; flex-direction: column; }
  .ttbl-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 6px; }
  .ttbl-numwrap { min-width: 0; }
  .ttbl-num { font-size: 17px; font-weight: 800; line-height: 1.1; }
  .ttbl-badge { display: inline-block; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 6px; margin-top: 5px; white-space: nowrap; }
  .ttbl-badge.open { background: var(--green-light); color: var(--green); }
  .ttbl-badge.locked { background: #FEF9C3; color: #CA8A04; }
  .ttbl-badge.idle { background: #F0F0EC; color: var(--text-sub); }
  .ttbl-dots { display: inline-flex; align-items: center; gap: 4px; padding: 0 12px; height: 30px; border: none; background: none; font-size: 14px; font-weight: 600; line-height: 1; color: var(--text-sub); cursor: pointer; border-radius: 8px; touch-action: manipulation; flex-shrink: 0; white-space: nowrap; }
  .ttbl-dots:active { background: var(--bg); }  .ttbl-pw { text-align: center; font-size: 24px; font-weight: 800; letter-spacing: 4px; color: var(--accent); margin: 5px 0 8px; }
  /* v615 桌卡 GPS 标记：沿用 v355 呼叫按钮的定案 —— 文字包一层 position:relative 的 inline-block，
     图标 position:absolute 挂在文字块【左外侧】。绝对定位不参与布局 → 「GPS」三个字在整条 .ttbl-pw
     宽度内真正居中，图标只是贴着它浮动。原写法 '📍 GPS' 整串一起居中，emoji 把真正的文字顶偏了。
     图标自身 letter-spacing 归零：父级的 4px 字距是给密码数字的，套在 emoji 上只会再推开一点。 */
  .ttbl-gps { position: relative; display: inline-block; }
  .ttbl-gps-ico { position: absolute; right: 100%; margin-right: 6px; font-style: normal; letter-spacing: 0; }
  .ttbl-empty { text-align: center; font-size: 13px; color: var(--text-sub); padding: 12px 0 14px; }
  .ttbl-action { width: 100%; padding: 9px; border-radius: 10px; border: none; font-size: 14px; font-weight: 700; color: #fff; cursor: pointer; margin-top: auto; touch-action: manipulation; }
  .ttbl-row2 { display: flex; gap: 6px; margin-bottom: 6px; }
  .ttbl-nopin { flex: 1; min-width: 0; padding: 6px; border-radius: 8px; font-size: 12px; font-weight: 700; line-height: 1.25; text-align: center; cursor: pointer; touch-action: manipulation; -webkit-appearance: none; -webkit-tap-highlight-color: transparent; border: 1px solid var(--border); background: var(--card); color: var(--text-sub); }
  .ttbl-close { flex: 1; min-width: 0; padding: 6px; border-radius: 8px; font-size: 12px; font-weight: 700; line-height: 1.25; text-align: center; cursor: pointer; touch-action: manipulation; -webkit-appearance: none; -webkit-tap-highlight-color: transparent; border: 1px solid var(--border); background: var(--card); color: var(--text-sub); }
  /* v337：免密改「药丸开关」（toggle）。手机用户对药丸有现成肌肉记忆——左灰=关、右绿=开，
     不用读字就知道状态；而按钮式必须靠文案告诉你"现在是什么"，多一层脑内翻译。
     规格沿用菜品上下架的 .me-tgl（38×21 轨道 + 17px 圆钮 + .2s 滑动，开=#34C759），
     与后台既有开关视觉统一，店员认知可迁移。独立 class 避免与 .me-tgl 互相干扰。 */
  .ttbl-nopin {
    flex: 1; min-width: 0; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    padding: 5px 4px; border-radius: 8px; font-size: 11px; font-weight: 700; line-height: 1.2;
    cursor: pointer; touch-action: manipulation; -webkit-appearance: none; -webkit-tap-highlight-color: transparent;
    border: 1px solid var(--border); background: var(--card); color: var(--text-sub);
  }
  .ttbl-nopin.on { border-color: #34C759; color: #15803D; }   /* 开：边框/文字转绿，与药丸呼应 */
  .ttbl-tgl { width: 34px; height: 19px; border-radius: 10px; background: #c8c8c8; position: relative; transition: background .2s; flex-shrink: 0; }
  .ttbl-nopin.on .ttbl-tgl { background: #34C759; }
  .ttbl-tgl-knob { position: absolute; top: 2px; left: 2px; width: 15px; height: 15px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.35); transition: left .2s; }
  .ttbl-nopin.on .ttbl-tgl-knob { left: 17px; }
  .ttbl-action.flip { background: #6366f1; }
  .ttbl-action.open { background: var(--accent); }

  /* ===== 桌位「更多功能」弹层 ===== */
  .tmenu-sheet { position: relative; background: var(--card); border-radius: 18px; width: 100%; max-width: 360px; max-height: 85vh; overflow-y: auto; overscroll-behavior: none; padding: 8px 0 14px; box-shadow: var(--shadow-lg); border: 2px solid #1a1a1a; animation: tmenuFade .15s ease; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
  @keyframes tmenuFade { from { opacity: 0; } to { opacity: 1; } }
  .tmenu-title { text-align: center; font-size: 15px; font-weight: 700; padding: 12px 40px; }
  .tmenu-close { position: absolute; top: 8px; right: 8px; width: 32px; height: 32px; border: none; background: none; font-size: 17px; color: var(--text-sub); cursor: pointer; border-radius: 8px; line-height: 1; touch-action: manipulation; z-index: 2; -webkit-tap-highlight-color: transparent; -webkit-appearance: none; appearance: none; transition: background .1s; }
  .tmenu-close:active { background: var(--accent-light); }
  .tmenu-row { display: flex; align-items: center; gap: 14px; width: 100%; padding: 15px 24px; background: none; border: none; border-top: 1px solid var(--border); font-size: 15px; color: var(--text); cursor: pointer; text-align: left; touch-action: manipulation; font-family: inherit; -webkit-tap-highlight-color: transparent; -webkit-appearance: none; appearance: none; transition: background .1s; }
  .tmenu-row:active { background: var(--accent-light); }
  .tmenu-ico { font-size: 18px; width: 24px; text-align: center; flex-shrink: 0; }
  .tmenu-label { flex: 1; min-width: 0; }
  .tmenu-row.danger .tmenu-label, .tmenu-row.danger .tmenu-ico { color: #e53e3e; }
  .tmenu-seats { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
  .tmenu-seat-btn { width: 30px; height: 30px; border-radius: 8px; border: 1px solid var(--border); background: var(--card); font-size: 17px; font-weight: 700; color: var(--text); cursor: pointer; touch-action: manipulation; line-height: 1; -webkit-tap-highlight-color: transparent; -webkit-appearance: none; appearance: none; transition: background .1s, border-color .1s; }
  .tmenu-seat-btn:active { background: var(--accent-light); border-color: var(--accent); }
  .tmenu-seats .tmenu-seatval { min-width: 20px; text-align: center; font-weight: 700; }

  .kitchen-body {
    display: flex; gap: 12px; padding: 0 16px; flex: 1; min-height: 0;
  }

  /* 左侧统计栏 */
  .stats-panel {
    width: 220px; flex-shrink: 0;
    background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow);
    padding: 14px; overflow-y: auto; max-height: calc(100dvh - var(--nav-h) - 90px);
  }
  .stats-panel h3 { font-size: 14px; font-weight: 700; margin-bottom: 10px; color: var(--text-sub); }
  .stats-list-wrap { position: relative; }
  .stats-list {
    display: grid; grid-template-columns: 1fr 1fr; gap: 6px;
    grid-auto-rows: 46px; align-content: start;
    height: 514px; overflow-y: auto;
    -webkit-overflow-scrolling: touch; overscroll-behavior: none;
    scrollbar-width: thin; scrollbar-color: var(--accent) #EFEEE9;
  }
  .stats-list::-webkit-scrollbar { width: 6px; -webkit-appearance: none; }
  .stats-list::-webkit-scrollbar-track { background: #EFEEE9; border-radius: 3px; }
  .stats-list::-webkit-scrollbar-thumb { background: var(--accent); border-radius: 3px; }
  .stat-pill {
    display: flex; align-items: flex-start;
    padding: 6px 10px; border-radius: 8px;
    background: var(--accent-light); font-size: 12px;
    transition: opacity .15s; height: 46px; overflow: hidden;
  }
  .stat-pill.done { opacity: .35; background: var(--green-light); text-decoration: line-through; }
  .stat-pill .s-num { font-weight: 700; color: var(--accent); }
  .stat-pill.done .s-num { color: var(--green); }
  .stat-pill .s-qty { font-weight: 600; color: var(--text); }

  /* 右侧订单列表 */
  /* 🚨 v630 修「超过 6 桌桌卡相互重叠」（Jay 报 + 控制台实测定位）。
     病理三条缺一不可：① 本元素是 .kitchen-body 的 flex 子项，高度被**定死**（实测 494px）；
     ② 行轨道是隐式 auto，装不下时 grid 会把轨道按剩余空间【等分压缩】——实测 (494−3×12)/4 = 114.5px，
        与控制台 `grid-template-rows: 114.5px ×4` 完全一致；
     ③ 轨道本不该压到内容以下，但 `.order-card{overflow:hidden}` 使其自动最小尺寸变成 0 → 可无限压。
     叠加 align-items:start（卡片保持 164px 自然高，不随轨道缩）→ 卡片高出轨道 49.5px，直接压到下一张头上。
     阈值也对得上：4 桌=2 行 340px 尚可容下；6 桌=3 行 516px 起超出 → 开始重叠，桌越多压得越狠
     （正是 Jay 感知到的「间距渐变缩减」）。
     修法：把行轨道钉死为内容高度，超出改由本元素既有的 overflow-y:auto 滚动承担 ——
     间距从此恒为 gap 的 12px，与桌数无关。绝不能改成给 .order-card 写死 min-height：那是把
     一个会随卡片结构漂移的魔数埋进 CSS。 */
  .orders-main {
    flex: 1; overflow-y: auto; max-height: calc(100dvh - var(--nav-h) - 90px);
    display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
    grid-auto-rows: max-content;
    align-content: start; align-items: start;
  }

  .order-card {
    background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow);
    overflow: hidden; border-left: 4px solid var(--accent);
  }
  .order-card.all-done { border-left-color: var(--green); opacity: .5; }
  .order-card.all-done.bill-called, .order-card.all-done.svc-called { opacity: 1; } /* v428 bug1：呼叫中的桌即使菜已全完成也不淡化——置顶且激活可见 */
  .order-card.bill-called { border: 2.5px solid #22C55E; box-shadow: 0 0 0 3px rgba(34,197,94,0.24), var(--shadow); animation: billPulse 1.1s ease-in-out infinite; }
  .order-card.bill-called .order-table-tag { background: #22C55E; }
  @keyframes billPulse {
    0%, 100% { box-shadow: 0 0 0 3px rgba(34,197,94,0.24), var(--shadow); }
    50% { box-shadow: 0 0 0 7px rgba(34,197,94,0.48), var(--shadow); }
  }
  .bill-badge { font-size: 12px; font-weight: 800; color: #fff; background: #22C55E; padding: 3px 9px; border-radius: 6px; white-space: nowrap; }
  /* 🛎️ v351 呼叫服务：黄色外框 + 脉冲（与买单的绿色区分开）。徽章可点击消除。 */
  .order-card.svc-called { border: 2.5px solid #EAB308; box-shadow: 0 0 0 3px rgba(234,179,8,0.24), var(--shadow); animation: svcPulse 1.1s ease-in-out infinite; }
  .order-card.svc-called .order-table-tag { background: #EAB308; }
  @keyframes svcPulse {
    0%, 100% { box-shadow: 0 0 0 3px rgba(234,179,8,0.24), var(--shadow); }
    50% { box-shadow: 0 0 0 7px rgba(234,179,8,0.48), var(--shadow); }
  }
  .svc-badge { font-size: 12px; font-weight: 800; color: #fff; background: #EAB308; padding: 3px 9px; border-radius: 6px; white-space: nowrap; cursor: pointer; }
  .svc-badge:active, .bill-badge:active { opacity: 0.7; }
  .bill-badge { cursor: pointer; }
  /* 同时呼叫买单+服务时：买单（绿）优先显示外框，服务徽章仍在 —— 避免两套脉冲打架 */
  .order-card.bill-called.svc-called { border-color: #22C55E; animation: billPulse 1.1s ease-in-out infinite; }  @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }

  .order-head {
    padding: 8px 12px; display: flex; align-items: center; gap: 8px;
    border-bottom: 1px solid var(--border);
  }
  .order-table-tag {
    padding: 4px 10px; border-radius: 6px; font-size: 15px; font-weight: 700;
    background: var(--accent); color: #fff; min-width: 48px; text-align: center;
  }
  .order-card.all-done .order-table-tag { background: var(--green); }
  .order-time { font-size: 12px; color: var(--text-sub); }
  .order-first-time { font-size: 12px; color: var(--text-sub); font-weight: 600; white-space: nowrap; }
  .order-head-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }

  .order-body { padding: 12px 16px; }
  .order-items { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }

  /* 可点击的菜品 chip */
  .item-chip {
    position: relative; min-width: 0; min-height: 46px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
    text-align: center; padding: 4px 6px; border-radius: 6px;
    background: #F5F5F2; font-weight: 500;
    cursor: pointer; transition: background .15s, border-color .15s, opacity .15s;
    border: 2px solid transparent; user-select: none;
    touch-action: manipulation;
  }
  .item-chip:active { opacity: .75; }
  .item-chip .chip-num {
    font-weight: 700; color: var(--accent); font-size: var(--chip-font, 12px);
    line-height: 1.12; max-height: 2.4em; overflow: hidden; word-break: break-word;
  }
  .item-chip .chip-code {
    position: absolute; top: 2px; left: 3px;
    font-weight: 800; color: #fff; background: var(--text);
    font-size: 9px; padding: 0 4px; border-radius: 4px; line-height: 1.5;
  }
  .item-chip.done .chip-code { background: var(--text-sub); }
  .item-chip .chip-qty {
    position: absolute; top: 2px; right: 4px;
    color: var(--text-sub); font-size: 10px; font-weight: 600;
  }
  /* done state */
  .item-chip.done {
    background: #EEECEA; opacity: .45;
    text-decoration: line-through; text-decoration-color: var(--text-sub);
  }
  .item-chip.done .chip-num { color: var(--text-sub); }
  /* 套餐项标识：青色 Menu 徽章 + 青边底，员工一眼区分 */
  .item-chip .chip-menu {
    position: absolute; top: 2px; left: 2px;
    width: 15px; height: 15px; display: grid; place-items: center;
    font-weight: 900; color: #fff; background: #0E9F8E;
    font-size: 11px; border-radius: 4px; line-height: 1; box-shadow: 0 1px 2px rgba(0,0,0,.2);
  }
  .item-chip.combo { border-color: #0E9F8E; background: rgba(14,159,142,.10); }
  .item-chip.combo.done { border-color: rgba(14,159,142,.4); }
  .item-chip.done .chip-menu { background: var(--text-sub); }
  /* 顾客端·套餐选择卡片 */
  .cat-btn-combo { color: #0E9F8E; font-weight: 700; }
  .combo-sect { padding-top: 12px; }
  .ccombo-card { border: 1.5px solid #0E9F8E; border-radius: 14px; padding: 14px; background: var(--card); box-shadow: var(--shadow); }
  .ccombo-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
  .ccombo-title { font-size: 17px; font-weight: 800; color: var(--text); }
  .ccombo-price { font-size: 18px; font-weight: 800; color: #0E9F8E; white-space: nowrap; }  .ccombo-add { margin-top: 14px; width: 100%; padding: 11px; border: none; border-radius: 10px; background: #0E9F8E; color: #fff; font-size: 14px; font-weight: 700; font-family: inherit; cursor: pointer; touch-action: manipulation; }
  /* 套餐编辑器（档位式） */
  .sm-card { background:var(--card); border:1px solid var(--border); border-radius:12px; padding:14px; margin:0 0 14px; box-shadow:var(--shadow); }
  .sm-head { display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-bottom:12px; }
  .sm-name { flex:1; min-width:160px; padding:8px 10px; border:1.5px solid var(--border); border-radius:7px; font-size:15px; font-weight:700; font-family:inherit; }
  .sm-slots { display:flex; flex-direction:column; gap:10px; }
  .sm-slot { border:1px solid var(--border); border-radius:9px; padding:10px; background:var(--surface); }
  .sm-slot-head { display:flex; gap:8px; align-items:center; margin-bottom:6px; }
  .sm-slot-label { flex:1; min-width:120px; padding:6px 9px; border:1.5px solid var(--border); border-radius:6px; font-size:14px; font-weight:700; font-family:inherit; }
  .sm-chip-hint { font-size:11px; color:var(--text-sub); margin-bottom:7px; }
  .sm-chips { display:flex; flex-wrap:wrap; gap:6px; }
  .sm-chip { display:inline-flex; align-items:center; gap:5px; padding:6px 9px; border:1.5px solid var(--border); border-radius:8px; background:var(--card); color:var(--text); font-size:12px; font-family:inherit; cursor:pointer; }
  .sm-chip .n { font-size:10px; font-weight:800; color:var(--text-sub); }
  .sm-chip.on { border-color:#0E9F8E; background:rgba(14,159,142,.12); color:#0B7E70; font-weight:700; }
  .sm-chip.on .n { color:#0E9F8E; }
  .sm-addslot { margin-top:10px; width:100%; padding:9px; border:1.5px dashed var(--border); border-radius:8px; background:transparent; color:var(--text-sub); font-size:13px; font-family:inherit; cursor:pointer; }
  /* 顾客套餐卡片·档位小结 */
  .sm-mini { margin-top:8px; }
  .sm-mini-row { font-size:12px; color:var(--text-sub); padding:3px 0; border-top:1px dashed var(--border); }
  /* 套餐配色序号 + 供应/暂停态 */
  .sm-badge { flex:0 0 auto; display:inline-flex; align-items:center; color:#fff; font-size:11px; font-weight:800; padding:3px 9px; border-radius:7px; white-space:nowrap; }
  .sm-card.off { opacity:.72; }
  .sm-card.off .sm-name { color:var(--text-sub); }
  .sm-toggle.on { border-color:#0E9F8E; color:#0B7E70; background:rgba(14,159,142,.10); }
  .sm-toggle.off { border-color:#CA8A04; color:#92660A; background:rgba(202,138,4,.12); }
  .cat-btn-combo.off { opacity:.5; }
  .ccombo-card.off { opacity:.62; border-color:var(--border); }
  .ccombo-paused { font-size:11px; font-weight:700; color:var(--text-sub); background:var(--surface); border:1px solid var(--border); border-radius:6px; padding:1px 7px; margin-left:6px; vertical-align:2px; white-space:nowrap; }
  .ccombo-add:disabled { background:var(--surface); color:var(--text-sub); border:1px solid var(--border); cursor:not-allowed; }
  /* 🕒 v480 定时供应：顾客端提示 + 灰态标签变体 */
  .ccombo-paused.sched { color:var(--amber); border-color:var(--amber); background:var(--amber-light); }
  .ccombo-sched { margin-top:10px; font-size:12.5px; font-weight:650; color:var(--amber); background:var(--amber-light); border:1px solid var(--amber); border-radius:8px; padding:7px 10px; line-height:1.4; }
  /* 🕒 v480 定时供应：后台编辑器 */
  .sm-sched { margin-top:12px; padding:11px 12px; border-radius:10px; background:var(--amber-light); border:1px solid var(--amber); }
  .sm-sched-row { display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
  .sm-sched-lab { font-size:12.5px; font-weight:700; color:var(--amber); white-space:nowrap; }
  .sm-wd-group { display:inline-flex; gap:4px; }
  .sm-wd { width:30px; height:30px; border-radius:7px; border:1.5px solid var(--border); background:var(--card); color:var(--text-sub); font-size:13px; font-weight:700; font-family:inherit; cursor:pointer; padding:0; line-height:1; touch-action:manipulation; }
  .sm-wd.on { border-color:var(--amber); color:#fff; background:var(--amber); }
  .sm-sched-t { height:32px; border:1.5px solid var(--border); border-radius:7px; background:var(--input); color:var(--text); font-size:13px; font-family:inherit; padding:0 6px; }
  .sm-sched-dash { color:var(--amber); font-weight:700; }
  .sm-sched-note { margin-top:8px; font-size:11.5px; color:var(--text-sub); line-height:1.5; }
  /* 🍱 v484 套餐编辑器折叠改版 */
  .sm-caret { flex:0 0 auto; width:26px; height:26px; border:0; background:transparent; color:var(--text-sub); font-size:13px; cursor:pointer; padding:0; line-height:1; border-radius:6px; }
  .sm-caret:hover { background:var(--surface); color:var(--accent); }
  .sm-card-collapsed { cursor:pointer; }
  .sm-card-collapsed:hover { border-color:var(--accent); }
  .sm-head-sum { display:flex; align-items:center; gap:9px; flex-wrap:wrap; margin:0; }
  .sm-sum-name { font-size:14.5px; font-weight:750; color:var(--text); }
  .sm-sum-price { font-size:14px; font-weight:800; color:#0E9F8E; }
  .sm-sum-sched { font-size:11.5px; font-weight:650; color:var(--amber); background:var(--amber-light); border:1px solid var(--amber); border-radius:7px; padding:2px 7px; white-space:nowrap; }
  .sm-sum-meta { font-size:11.5px; color:var(--text-sub); }
  .sm-sum-state { margin-left:auto; font-size:11px; font-weight:700; white-space:nowrap; }
  .sm-sum-state.on { color:var(--green,#2D9F6F); }
  .sm-sum-state.off { color:var(--text-sub); }
  .sm-slot-actions { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:8px 0 6px; }
  .sm-pickbtn { font:inherit; font-size:12.5px; font-weight:650; border:1.5px dashed var(--accent); background:var(--accent-light); color:var(--accent); border-radius:8px; padding:7px 13px; cursor:pointer; white-space:nowrap; }
  .sm-pickbtn:hover { background:var(--accent); color:#fff; }
  .sm-chips-empty { font-size:12px; color:var(--text-sub); }
  /* 选菜弹窗（复用 .sh-head/.sh-body/.sh-foot 视觉） */
  .sm-pick-mask { position:fixed; inset:0; background:rgba(0,0,0,.45); display:none; align-items:flex-end; justify-content:center; z-index:9500; }
  .sm-pick-mask.show { display:flex; }
  .sm-pick-sheet { width:100%; max-width:560px; max-height:88dvh; background:var(--bg); border-radius:18px 18px 0 0; display:flex; flex-direction:column; overflow:hidden; box-shadow:var(--shadow-lg); }
  .sm-pick-sheet .sh-head { position:relative; padding:16px 52px 12px 18px; border-bottom:1px solid var(--border); }
  .sm-pick-sheet .sh-head h3 { margin:0; font-size:16px; }
  .sm-pick-sheet .sh-head .x { position:absolute; top:14px; right:14px; width:30px; height:30px; border:0; background:var(--surface); border-radius:50%; font-size:17px; color:var(--text-sub); cursor:pointer; }
  .sm-pick-sheet .sh-body { overflow-y:auto; -webkit-overflow-scrolling:touch; overscroll-behavior:none; padding:14px 18px; flex:1; min-height:0; }
  .sm-pick-sheet .sh-foot { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:12px 18px; border-top:1px solid var(--border); background:var(--card); }
  .sm-pick-cat { margin-bottom:14px; }
  .sm-pick-cat-name { font-size:12.5px; font-weight:750; color:var(--text-sub); margin-bottom:7px; }
  /* 套餐选餐弹窗 */
  #smPickerOverlay { display:none; position:fixed; inset:0; z-index:2100; background:rgba(0,0,0,0.5); backdrop-filter:blur(8px); align-items:flex-end; justify-content:center; }
  #smPickerOverlay.show { display:flex; }
  #smPickerBox { width:100%; max-width:560px; max-height:88vh; overflow-y:auto; background:var(--card); border-radius:18px 18px 0 0; padding:18px; -webkit-overflow-scrolling:touch; }
  @media(min-width:600px){ #smPickerOverlay{ align-items:center; } #smPickerBox{ border-radius:18px; } }
  .sm-pick-head { display:flex; justify-content:space-between; align-items:flex-start; gap:10px; margin-bottom:12px; }
  .sm-pick-title { font-size:18px; font-weight:800; color:var(--text); }
  .sm-pick-x { width:32px; height:32px; border:none; background:var(--surface); border-radius:50%; font-size:20px; color:var(--text-sub); cursor:pointer; flex:0 0 auto; }
  .sm-pick-slot { margin-bottom:14px; }
  /* v476：缺选档位定位闪烁——弹窗提示后滚到该档并脉冲高亮 */
  @keyframes smFlash { 0% { box-shadow:0 0 0 0 rgba(14,159,142,0); } 22% { box-shadow:0 0 0 3px rgba(14,159,142,.55); } 100% { box-shadow:0 0 0 0 rgba(14,159,142,0); } }
  .sm-pick-slot.sm-flash { animation:smFlash 1.3s ease-out 1; border-radius:10px; }
  /* v507：自动滚动落位提示框（与上面缺选闪烁分家——那个保持 1.3s 快脉冲不动）。
     Jay 定稿节奏：0.31s 升到最亮 → 整整维持 1.2s → 0.89s 淡出，总长 2.4s（12.9167%/62.9167% 由 0.31/2.4、1.51/2.4 精确换算）。
     峰值颜色 = 选中菜品的边框色 #0E9F8E【全不透明】（.sm-pick-opt.on 的 border-color），与选中态视觉严格一致；
     旧 smFlash 峰值只有 .55 透明度，故不复用。 */
  @keyframes smFlashHold { 0% { box-shadow:0 0 0 0 rgba(14,159,142,0); animation-timing-function:ease-out; } 12.9167% { box-shadow:0 0 0 3px rgba(14,159,142,1); animation-timing-function:linear; } 62.9167% { box-shadow:0 0 0 3px rgba(14,159,142,1); animation-timing-function:ease-out; } 100% { box-shadow:0 0 0 0 rgba(14,159,142,0); } }
  .sm-pick-slot.sm-flash-hold { animation:smFlashHold 2.4s 1; border-radius:10px; }
  .sm-pick-lab { font-size:14px; font-weight:700; color:var(--text); margin-bottom:8px; }
  /* v471 套餐多份点餐 */
  /* v508（Jay）：去掉包住「份数」标签+加减的灰底圆角框——同 v500 .cs-qty/.sm-qstep 的教训：
     果冻 scale(1.08) 在贴身框里弹就发闷、显得按钮嵌在框中。标签与两个独立按钮直接落在
     弹窗底色上（与 .sm-pick-lab 档位标题同一视觉层级，横向也对齐），形变有余地。 */
  .sm-pick-qty { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:2px 0; margin-bottom:12px; }
  .sm-pick-qty-lab { font-size:14px; font-weight:700; color:var(--text); }
  /* v500：同 .cs-qty —— 去掉共享外框与 overflow:hidden，拆成独立按钮，果冻才不被裁 */
  .sm-qstep { display:flex; align-items:center; gap:6px; background:transparent; border:0; border-radius:0; overflow:visible; }
  .sm-qstep button { width:42px; height:36px; border:1px solid var(--border); border-radius:9px; background:var(--card); color:#0E9F8E; font-size:23px; font-weight:800; line-height:1; padding:0; cursor:pointer; touch-action:manipulation; }
  .sm-qstep button:disabled { color:var(--text-sub); opacity:.4; cursor:not-allowed; }
  .sm-qstep .n { min-width:36px; text-align:center; font-size:16px; font-weight:800; color:var(--text); }
  .sm-pick-tabs { display:flex; flex-wrap:wrap; gap:7px; margin-bottom:14px; }
  .sm-pick-tab { padding:7px 12px; border:1.5px solid var(--border); border-radius:9px; background:var(--card); color:var(--text-sub); font-size:12.5px; font-weight:700; font-family:inherit; cursor:pointer; touch-action:manipulation; }
  .sm-pick-tab.done { color:#0E9F8E; border-color:#0E9F8E; }
  .sm-pick-tab.cur { background:#0E9F8E; color:#fff; border-color:#0E9F8E; }
  .sm-pick-copyall { width:100%; margin-top:2px; padding:9px; border:1.5px dashed #0E9F8E; border-radius:10px; background:transparent; color:#0E9F8E; font-size:13px; font-weight:700; font-family:inherit; cursor:pointer; touch-action:manipulation; transition:background .12s ease; }
  /* 🍱 v568 下一份键：实心主色主按钮（比复制键更主，是多份流程的主动作），压变暗、禁用置灰 */
  .sm-pick-next { width:100%; margin-top:2px; margin-bottom:6px; padding:11px; border:none; border-radius:10px; background:#0E9F8E; color:#fff; font-size:14px; font-weight:700; font-family:inherit; cursor:pointer; touch-action:manipulation; transition:filter .12s ease; }
  .sm-pick-next:active, .sm-pick-next.tapping { opacity:1 !important; filter:brightness(.92); }
  .sm-pick-next:disabled { background:var(--surface); color:var(--text-sub); border:1px solid var(--border); opacity:.55; cursor:not-allowed; }
  .sm-pick-next:disabled:active, .sm-pick-next:disabled.tapping { opacity:.55 !important; filter:none; }
  .sm-pick-copyall:active, .sm-pick-copyall.tapping { opacity:1 !important; filter:brightness(.94); }
  /* v510：当前份没选东西 / 没有空份可复制 → 禁用。虚线框与文字转灰，并单独兜住按压态，
     免得被上一行的 opacity:1 !important 顶掉而看起来仍可按（同 .cs-qty 禁用态写法）。 */
  .sm-pick-copyall:disabled { border-color:var(--border); color:var(--text-sub); opacity:.45; cursor:not-allowed; }
  .sm-pick-copyall:disabled:active, .sm-pick-copyall:disabled.tapping { opacity:.45 !important; filter:none; }
  .sm-pick-req { font-size:11px; font-weight:500; color:#0E9F8E; margin-left:6px; }
  .sm-pick-opt { display:flex; align-items:center; gap:10px; width:100%; padding:9px 12px; margin-bottom:7px; border:1.5px solid var(--border); border-radius:10px; background:var(--card); color:var(--text); font-size:14px; font-family:inherit; cursor:pointer; text-align:left; transition: background .16s ease, border-color .16s ease; }
  /* v455 修「套餐点选闪一下」：此行是 <button onclick>，命中全局 button:active{opacity:.6} 与 .tapping{opacity:.55}——
     整行（含缩略图+过敏原图标）被压暗再弹回＝"图片快速刷了一下"。含图行的按压反馈改用底色轻染，禁 opacity 变淡。
     （v454 已修异步解码闪，这是另一半根因。）.so 售罄行的常驻 .45 置灰不受影响（选择器优先级：下方规则只管按压态。） */
  .sm-pick-opt:active { opacity: 1 !important; }
  .sm-pick-opt.tapping { opacity: 1 !important; }
  .sm-pick-opt.on:active, .sm-pick-opt.on.tapping { background: rgba(14,159,142,.16); } /* 已选行按压：茶绿加深，不跳灰 */
  .sm-pick-opt.so:active, .sm-pick-opt.so.tapping { opacity: .45 !important; background: var(--card); } /* 售罄行禁反馈、保持置灰 */
  .sm-pick-opt.on { border-color:#0E9F8E; background:rgba(14,159,142,.08); }
  .sm-pick-opt.so { opacity:.45; cursor:not-allowed; }
  .sm-pick-thumb { width:42px; height:42px; border-radius:8px; background:#EEECEA; flex:0 0 auto; display:flex; align-items:center; justify-content:center; font-size:22px; overflow:hidden; transform:translateZ(0); }
  /* ↑ v456 translateZ(0)：iOS Safari 已知怪癖——border-radius+overflow:hidden 裁切的 <img> 在所在行每次 repaint（选中变底色/按压染色）都闪一帧。
     提升独立合成层后缩略图隔离于行 repaint，不再重合成。PC 无此怪癖故 PC 正常、手机闪——v454(解码)/v455(变淡)之外的第三半根因。
     盒内无 position:fixed 子元素，transform 安全（规范⑧）。 */
  .sm-pick-thumb img { width:100%; height:100%; object-fit:cover; }
  .sm-pick-name { flex:1; min-width:0; }
  .sm-pick-attr { display:block; font-size:12px; font-weight:500; color:#0E9F8E; margin-top:3px; }
  /* 🏷️ v375：套餐档位里的过敏原【恒定独占一行】。原来 ${al} 裸贴在菜名后、走 inline 自然折行——
     过敏原少时挤在名字后面、多时才折行，不一致（Jay 报障）。块级容器让它无论多少都自成一行。 */
  .sm-pick-al { display:block; margin-top:4px; line-height:1; transform:translateZ(0); } /* v456 提层防 iOS 行 repaint 连带闪 */
  .sm-pick-check2 { flex:0 0 auto; width:24px; height:24px; border-radius:50%; border:2px solid var(--border); display:flex; align-items:center; justify-content:center; font-size:14px; font-weight:800; color:transparent; transition: background .16s ease, border-color .16s ease; }
  .sm-pick-opt.on .sm-pick-check2 { background:#0E9F8E; border-color:#0E9F8E; color:#fff; }  /* 属性选择器需盖过套餐选餐弹窗(z-index 2100) */
  #dishPickMask { z-index:2200; }

  .order-body-wrap { position: relative; }
  .order-body {
    padding: 8px 12px; height: 114px; overflow-y: auto;
    -webkit-overflow-scrolling: touch; overscroll-behavior: none;
    scrollbar-width: thin; scrollbar-color: var(--accent) #EFEEE9;
  }
  .order-body::-webkit-scrollbar { width: 6px; -webkit-appearance: none; }
  .order-body::-webkit-scrollbar-track { background: #EFEEE9; border-radius: 3px; }
  .order-body::-webkit-scrollbar-thumb { background: var(--accent); border-radius: 3px; }
  .scroll-more {
    position: absolute; left: 0; right: 0; bottom: 0; height: 22px;
    display: none; align-items: flex-end; justify-content: center;
    font-size: 11px; line-height: 1; color: var(--accent); font-weight: 800;
    background: linear-gradient(to top, var(--card) 35%, transparent);
    pointer-events: none; padding-bottom: 2px;
  }
  .order-body-wrap.has-more .scroll-more,
  .stats-list-wrap.has-more .scroll-more { display: flex; }  .order-done-btn {
    padding: 5px 10px; border-radius: 8px; border: none; white-space: nowrap;
    background: var(--green); color: #fff; font-size: 11px; font-weight: 600;
    cursor: pointer; touch-action: manipulation;
  }  .no-orders {
    text-align: center; padding: 60px 20px; color: var(--text-sub);
    grid-column: 1 / -1;
  }
  .no-orders svg { width: 64px; height: 64px; margin-bottom: 12px; opacity: .3; }
  .no-orders p { font-size: 15px; line-height: 1.6; }

  /* ===== 菜品编辑器 ===== */
  /* 客户信息·档案表单（仅后台/hub 使用，深色由 .hub-dark input 规则接管） */
  .ci-grp {
    font-size: 12px; font-weight: 700; color: var(--text-sub);
    letter-spacing: .04em; margin: 18px 0 8px; padding-bottom: 5px;
    border-bottom: 1px solid var(--border);
  }
  .ci-grid {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 10px 14px;
  }
  .ci-f { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
  .ci-f.ci-wide { grid-column: 1 / -1; }
  .ci-f label { font-size: 12px; font-weight: 600; color: var(--text-sub); }
  .ci-f input, .ci-f select, .ci-f textarea {
    padding: 8px 10px; border: 1.5px solid var(--border); border-radius: 7px;
    font-size: 13px; font-family: inherit; width: 100%; box-sizing: border-box;
  }
  .ci-f textarea { resize: vertical; }  .cmb-price { width:120px; padding:8px 10px; border:1.5px solid var(--border); border-radius:7px; font-size:14px; font-weight:600; font-family:inherit; }
  .cmb-price:placeholder-shown { border-color:var(--accent); background:rgba(232,93,58,.07); }
  .cmb-price-wrap:has(.cmb-price:placeholder-shown) .cmb-eur { border-color:var(--accent); color:var(--accent); }
  .cmb-price-wrap { display:inline-flex; align-items:stretch; }
  .cmb-price-wrap .cmb-eur { display:grid; place-items:center; padding:0 10px; border:1.5px solid var(--border); border-right:none; border-radius:7px 0 0 7px; background:var(--surface); font-size:14px; font-weight:800; color:var(--text-sub); }
  .cmb-price-wrap .cmb-price { width:92px; border-radius:0 7px 7px 0; }  .me-cat {
    background: var(--card); border-radius: var(--radius); box-shadow: var(--shadow);
    margin-bottom: 14px; overflow: hidden;
  }
  /* v523 分类折叠：箭头 + 菜品数徽标。标题行本身可点（点输入框/按钮/手柄不触发，见 toggleMeCat）。
     .me-cat-head 有选中态（展开=.me-open）→ 按 Jay 两类规则属第①类：按压零视觉变化。 */
  .me-caret { flex-shrink:0; width:16px; text-align:center; color:var(--text-sub); font-size:12px; user-select:none; }
  .me-cat.me-open .me-caret { color:var(--accent); }
  .me-count { flex-shrink:0; min-width:22px; padding:1px 6px; border-radius:9px; background:var(--border); color:var(--text-sub); font-size:11px; font-weight:700; text-align:center; user-select:none; }
  .me-cat.me-open .me-count { background:var(--accent-light); color:var(--accent); }
  .me-cat-head:active, .me-cat-head.tapping { opacity:1 !important; }
  .me-cat-head {
    padding: 12px 16px; background: #F5F5F2; display: flex; align-items: center; gap: 10px;
    border-bottom: 1px solid var(--border);
    /* v625：按钮多时换行，而不是把分类名压成 0 宽（配合下面 input 的 min-width 保底） */
    flex-wrap: wrap;
  }
  .me-cat-head input {
    flex: 1; padding: 6px 10px; border: 2px solid var(--border); border-radius: 6px;
    font-size: 15px; font-weight: 600; font-family: inherit;
    /* v124 手机端修复：文本输入框固有最小宽度 ~170px，不加 min-width 会把「＋加菜/删除分类」挤出屏幕右缘。
       v625 修正 v124 的过头之处：min-width:0 让它可以被压到【完全看不见】——开启额外收费/Menu赠饮后
       分类名当场消失（Jay 截图实证）。改为 120px 保底，配合 .me-cat-head 的 flex-wrap：
       空间不够时按钮换行，分类名永远保得住。
       v626：120px 预留过多，还没挤就先换行了 —— 收到 80px（Jay 定：缩三分之一）。 */
    min-width: 80px;
  }
  .me-cat-head .me-btn { flex-shrink: 0; }
  .me-cat-head input:focus { outline: none; border-color: var(--accent); }
  .me-btn {
    padding: 6px 12px; border-radius: 6px; border: 1px solid var(--border);
    background: var(--card); font-size: 12px; cursor: pointer; touch-action: manipulation; white-space: nowrap;
  }
  /* 菜品上线开关（绿色胶囊 + 白钮） */
  .me-tgl { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; border: none; background: none; padding: 4px 2px; font-size: 11px; font-weight: 700; color: var(--text); touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
  .me-tgl-track { width: 38px; height: 21px; border-radius: 11px; background: #c8c8c8; position: relative; transition: background .2s; flex-shrink: 0; }
  .me-tgl-track.on { background: #34C759; }
  .me-tgl-knob { position: absolute; top: 2px; left: 2px; width: 17px; height: 17px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.35); transition: left .2s; }
  .me-tgl-track.on .me-tgl-knob { left: 19px; }
  .me-btn.red { color: #e53e3e; border-color: #fcc; }
  .me-btn.accent { background: var(--accent); color: #fff; border-color: var(--accent); }
  .me-items { padding: 8px; }
  .me-item {
    display: flex; gap: 8px; align-items: center; padding: 8px;
    border-bottom: 1px solid #F0F0EC; flex-wrap: wrap;
  }
  .me-item:last-child { border-bottom: none; }
  .me-item:nth-child(odd) { background: #F4F3EE; }
  .me-item:nth-child(even) { background: #FFFFFF; }
  .me-item input, .me-item select {
    padding: 6px 8px; border: 1.5px solid var(--border); border-radius: 6px;
    font-size: 13px; font-family: inherit;
  }
  .me-item input:focus { outline: none; border-color: var(--accent); }
  .me-field-num {
    width: 72px; text-align: center; font-weight: 700;
    -moz-appearance: textfield; appearance: textfield;
  }
  .me-field-num::-webkit-outer-spin-button,
  .me-field-num::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  .me-field-emoji { width: 44px; text-align: center; font-size: 18px; }
  .me-field-name { flex: 1; min-width: 100px; }
  .me-field-desc { flex: 2; min-width: 120px; }
  .me-field-price { width: 80px; }
  .me-field-limit {
    width: 72px; text-align: center; font-weight: 700;
    -moz-appearance: textfield; appearance: textfield;
    border-color: rgba(202,138,4,0.5); color: #CA8A04;
  }
  .me-field-limit::-webkit-outer-spin-button,
  .me-field-limit::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  .me-field-limit::placeholder { color: rgba(202,138,4,0.6); font-weight: 600; }
  /* v384 拖拽手柄：touch-action:none 是关键——按住手柄拖动时不触发页面滚动（其余区域照常滚） */
  .me-drag {
    flex-shrink: 0; align-self: center; cursor: grab; touch-action: none;
    -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent;
    color: var(--text-sub); font-size: 15px; line-height: 1; padding: 6px 5px; border-radius: 6px;
  }
  .me-drag:active { cursor: grabbing; }
  /* v527 长按武装态：给出"现在可以拖了"的明确视觉，配合震动。
     手柄本身保持 touch-action:none —— 它完全接管自己那一小块触摸区，
     配合长按门槛后，快速划动既不会重排、也不会误触发任何东西。 */
  .me-drag-armed { background: var(--accent-light); color: var(--accent); transform: scale(1.12); transition: transform .12s ease, background .12s ease; }
  .me-drag-cat { font-size: 16px; margin-right: -2px; }
  /* 拖拽中的行「抬起」态。放在 nth-child 斑马纹之后，class 选择器同权重靠后覆盖背景 */
  .me-item.me-dragging, .me-cat.me-dragging, .gcard.me-dragging, .optblock.me-dragging {
    position: relative; z-index: 30; box-shadow: 0 10px 26px rgba(0,0,0,.20);
  }
  .me-item.me-dragging { background: var(--accent-light); border-radius: 8px; }
  .me-cat.me-dragging { outline: 2px solid var(--accent); outline-offset: -1px; }
  /* v398 属性编辑器拖拽：组卡/选项块抬起态 + 手柄在头行/选项行内的对齐 */
  .gcard.me-dragging { outline: 2px solid var(--accent); outline-offset: -1px; }
  .optblock.me-dragging { background: var(--accent-light); border-radius: 8px; }
  .gcard .gtop .attr-drag, .oprow .attr-drag { align-self: center; margin-right: 2px; }
  /* v501 套餐卡 / 档位拖拽：沿用菜品编辑器的抬起语言（整块用描边、行内块用浅底） */
  /* v614 主页图片行。原 v613 把外观写成行内 style，而行内样式优先级高于任何类规则 →
     .me-dragging 的高亮永远盖不过它；且 .me-dragging 本身【没有通用规则】，
     全部被限定在 .me-item / .me-cat / .gcard / .optblock / .sm-card / .sm-slot 上，
     .li-row 一条都匹配不到 —— 两个原因叠加，v613 的拖拽全程零反馈。 */
  .li-row { display: flex; gap: 10px; align-items: flex-start; padding: 10px;
    background: var(--surface); border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; }
  .li-row.me-dragging { position: relative; z-index: 30; box-shadow: 0 10px 26px rgba(0,0,0,.20);
    background: var(--accent-light); outline: 2px solid var(--accent); outline-offset: -1px; }
  .sm-card.me-dragging, .sm-slot.me-dragging { position: relative; z-index: 30; box-shadow: 0 10px 26px rgba(0,0,0,.20); }
  .sm-card.me-dragging { outline: 2px solid var(--accent); outline-offset: -1px; }
  .sm-slot.me-dragging { background: var(--accent-light); }
  .sm-drag { margin-right: -4px; }
  /* 折叠态套餐卡是整行 onclick，会命中全局 [onclick]:active{opacity:.6} 与 .tapping{opacity:.55}——
     拖拽中再叠半透明就是"拖着一张灰卡"。拖拽期间锁死不透明；暂停态套餐保留它自己的 .72 以示停用。 */
  .sm-card.me-dragging:active, .sm-card.me-dragging.tapping { opacity: 1 !important; }
  .sm-card.off.me-dragging:active, .sm-card.off.me-dragging.tapping { opacity: .72 !important; }
  body.me-drag-lock, body.me-drag-lock * { cursor: grabbing !important; }
  body.me-drag-lock { -webkit-user-select: none; user-select: none; overflow-anchor: none; }

  /* ===== 设置页 ===== */
  .settings-section {
    margin: 0 16px 16px; padding: 20px; background: var(--card);
    border-radius: var(--radius); box-shadow: var(--shadow);
  }
  .settings-section h3 { font-size: 16px; font-weight: 600; margin-bottom: 12px; }
  .settings-section label { display: block; font-size: 14px; margin-bottom: 6px; color: var(--text-sub); }
  .settings-section input[type="number"],
  .settings-section input[type="text"] {
    width: 100%; padding: 10px 14px; border: 2px solid var(--border); border-radius: 8px;
    font-size: 15px; font-family: inherit; margin-bottom: 12px; transition: border-color .2s;
  }
  .settings-section input:focus { outline: none; border-color: var(--accent); }
  .settings-section .save-btn {
    padding: 10px 24px; border-radius: 8px; border: none;
    background: var(--accent); color: #fff; font-size: 14px; font-weight: 600;
    cursor: pointer; touch-action: manipulation;
  }
  .settings-section .tip { font-size: 12px; color: var(--text-sub); margin-top: 12px; line-height: 1.7; }

  .toast {
    position: fixed; top: 50%; left: 50%; transform: translate(-50%, calc(-50% - 20px));
    background: var(--text); color: #fff; padding: 12px 24px; border-radius: 10px;
    font-size: 14px; font-weight: 500; z-index: 3300; opacity: 0; visibility: hidden;
    /* v382：与 success-overlay 同款合成器卫生——隐藏时 visibility:hidden 退出合成树，
       常驻的 opacity:0 提示条也无从被合成器误画。visibility 延迟切换保留滑入淡出。 */
    transition: opacity .3s ease, transform .3s ease, visibility 0s .3s; pointer-events: none; box-shadow: var(--shadow-lg);
  }
  .toast.show { opacity: 1; visibility: visible; transform: translate(-50%, -50%); transition: opacity .3s ease, transform .3s ease, visibility 0s 0s; }

  /* ===== 手机端适配 ===== */

  /* ===== Customer Bottom Nav（精简·纯图标）===== */
  .customer-nav {
    position: fixed; bottom: 0; left: 0; right: 0; z-index: 95;
    height: 52px; background: var(--card);
    border-top: 1px solid var(--border);
    display: flex; align-items: center; box-shadow: 0 -2px 12px rgba(0,0,0,0.05);
  }
  .customer-nav-btn {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    height: 100%; border: none; background: none; color: var(--text-sub);
    font-size: 10px; font-weight: 600; line-height: 1; white-space: nowrap;
    cursor: pointer; touch-action: manipulation; transition: color .15s;
  }
  .customer-nav-btn.active { color: var(--accent); }
  .customer-nav-btn svg { width: 21px; height: 21px; flex: 0 0 auto; }
  .lang-opt {
    width: 100%; display: flex; align-items: center; justify-content: space-between;
    padding: 15px 16px; margin-bottom: 8px; border: 1.5px solid var(--border); border-radius: 12px;
    background: var(--card); color: var(--text); font-size: 16px; font-weight: 600;
    cursor: pointer; transition: border-color .15s, background .15s, color .15s;
  }
  .lang-opt:last-child { margin-bottom: 0; }
  .lang-opt.on { border-color: var(--accent); background: var(--accent-light); color: var(--accent); }
  .lang-opt-check { font-size: 17px; font-weight: 700; }

  /* ===== Customer Landing Page ===== */
  /* v328：主页图上下留白对称。原 `0 16px 80px` = 上0/下80——第一张图直接顶在 nav 底下，
     下方却空出一大块。顶部 0 是因为 #pageCustomerHome.active 用 position:fixed + padding:0
     覆盖了 .page 的 padding-top；底部 80px 则是「整页滚动」时代的遗留值——现在主页已是容器内
     定高滚动（bottom:52px 已避开底部导航），80px 纯属多余。四边统一 16px，与左右留白一致。 */
  .landing-page { padding: 16px; max-width: 500px; margin: 0 auto; }
  /* 主页也走内层定高滚动，获得弹性回弹（与菜单/订单页同款；body 不滚） */
  #pageCustomerHome.active {
    position: fixed; top: var(--nav-h); bottom: 52px; left: 0; right: 0;
    padding: 0; min-height: 0;
    /* ★ v118：有界内层滚动区用 contain（回弹关在容器内），见 .menu-list 处的精炼规则 */
    overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  }  .landing-images {
    display: flex; flex-direction: column; gap: 12px; margin-bottom: 24px;
  }
  /* v333：卡片四边留白 = 相框效果。此前图片按高度缩放后比卡片窄，卡片白底从「两侧」透出来，
     形成了半截画框；加 12px 内边距后上下也有白色衬底，四边成为完整相框。 */
  .landing-img-card {
    border-radius: var(--radius); overflow: hidden;
    box-shadow: var(--shadow); background: var(--card);
    padding: 12px;
  }
  .landing-img-card img {
    width: 100%; display: block; object-fit: cover;
    border-radius: 6px; /* v333：卡片有内边距后，图片自身也给小圆角，方角嵌圆角卡片会别扭 */
  }
  /* v459：点图进查看器时去掉半透明白层——卡片带 onclick，会命中全局 [onclick]:active{opacity:.6} 与 .tapping{opacity:.55}，
     整张卡片被压淡＝伤眼的白闪。此处禁掉该卡按压 opacity，丝滑进放大弹框（查看器本身已有 .2s 淡入）。 */
  .landing-img-card:active, .landing-img-card.tapping { opacity: 1 !important; }
  /* v329：第一张图整张装进可视区，上下留白真正等距。
     v328 只调了 padding，但图片本身比可视区还高——顶部是 16px 留白，底部却是图片被截断继续往下滚，
     所以观感始终「上宽下窄」。padding 再怎么调都没用：底部那个边界不是 padding，是滚动。
     限高 = 可视容器(100dvh - 顶部nav - 底部导航52px) - 上下 padding(32px)。
     等比缩放(height:auto)+居中(margin auto)，不裁切、不变形；图片够小则保持原样，不放大。 */
  .landing-images .landing-img-card:first-child img {
    /* v333：限高再减卡片上下内边距 24px —— 否则卡片总高 = 图高 + 24 会溢出可视区。
       实算(iPhone 844dvh)：844−56−52−32−24 = 680px 图高，卡片总高 680+24 = 704px，正好填满、不溢出。 */
    max-height: calc(100dvh - var(--nav-h) - 52px - 32px - 24px);
    width: auto; max-width: 100%; height: auto;
    margin: 0 auto; object-fit: contain;
  }
  .landing-img-card .caption {
    padding: 10px 14px; font-size: 13px; color: var(--text-sub); line-height: 1.5;
  }
  /* ═══ v457 主页落地图查看器 ═══ body 级独立浮层 */
  .lv-mask { position: fixed; inset: 0; z-index: 99999; background: rgba(0,0,0,.93); opacity: 0; transition: opacity .2s ease; overflow: hidden; touch-action: none; -webkit-tap-highlight-color: transparent; }
  .lv-mask.show { opacity: 1; }
  .lv-strip { display: flex; height: 100%; width: 100%; will-change: transform; }
  .lv-panel { flex: 0 0 100vw; width: 100vw; height: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; }
  .lv-img { max-width: 100%; max-height: 100%; object-fit: contain; will-change: transform; -webkit-user-select: none; user-select: none; -webkit-user-drag: none; display: block; }
  .lv-close { position: fixed; top: 14px; right: 16px; width: 38px; height: 38px; border: 0; border-radius: 50%; background: rgba(255,255,255,.92); color: #222; font-size: 19px; line-height: 1; display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 2; box-shadow: 0 2px 10px rgba(0,0,0,.3); -webkit-tap-highlight-color: transparent; padding: 0; }
  .lv-count { position: fixed; bottom: 16px; left: 0; right: 0; text-align: center; color: rgba(255,255,255,.8); font-size: 13px; font-weight: 600; pointer-events: none; z-index: 2; }
  .lv-cap { position: fixed; bottom: 40px; left: 0; right: 0; text-align: center; color: rgba(255,255,255,.92); font-size: 14px; line-height: 1.5; padding: 0 24px; pointer-events: none; z-index: 2; text-shadow: 0 1px 4px rgba(0,0,0,.6); }
  .landing-cta {
    width: 100%; padding: 16px; border-radius: 12px; border: none;
    background: var(--accent); color: #fff; font-size: 17px; font-weight: 700;
    cursor: pointer; touch-action: manipulation;
    box-shadow: 0 4px 16px rgba(232,93,58,0.3);
  }
  .landing-no-images {
    text-align: center; padding: 40px 20px; background: var(--card);
    border-radius: var(--radius); box-shadow: var(--shadow); margin-bottom: 24px;
  }
  .landing-no-images svg { width: 48px; height: 48px; color: var(--text-sub); opacity: .3; margin-bottom: 10px; }
  .landing-no-images p { font-size: 14px; color: var(--text-sub); line-height: 1.6; }

  /* ═══ v558 极简展示版：整条底部导航隐藏 + 主页图收回那 52px ═══
     仅当顾客端 display+minimal 时 <html> 挂 minimal-only。
     #pageCustomerHome.active 原 bottom:52px 是给底部导航留位——导航隐藏后必须收回，
     否则主页底部留一条 52px 死白（v328/v329 一直在打的"上宽下窄"病）。
     bottom / 首图限高改用 safe-area-inset-bottom 兜刘海屏 home indicator（无刘海时 =0，等价 bottom:0）。 */
  .minimal-only .customer-nav { display: none; }
  .minimal-only #pageCustomerHome.active { bottom: env(safe-area-inset-bottom, 0px); }
  .minimal-only .landing-images .landing-img-card:first-child img {
    max-height: calc(100dvh - var(--nav-h) - env(safe-area-inset-bottom, 0px) - 32px - 24px);
  }

  /* ===== 过敏原 ===== */
  .allergen-icons { display: inline-flex; align-items: center; gap: 5px; flex-wrap: wrap; }
  .dish-allergens { margin: 2px 0 6px; }  .allergen-ic {
    width: 22px; height: 22px; border-radius: 50%; background: var(--accent-light, #f0f4ff);
    display: inline-flex; align-items: center; justify-content: center; font-size: 13px; line-height: 1;
    flex-shrink: 0; overflow: hidden;
  }
  .allergen-ic img { width: 100%; height: 100%; object-fit: cover; }
  .allergen-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .allergen-pick {
    display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: 10px;
    border: 1.5px solid var(--border); background: var(--card); cursor: pointer; user-select: none;
    font-size: 13px; touch-action: manipulation; transition: all .12s;
  }
  .allergen-pick.on { border-color: var(--accent); background: var(--accent-light, #f0f4ff); color: var(--accent); font-weight: 600; }
  .allergen-pick .ic {
    width: 26px; height: 26px; border-radius: 50%; background: rgba(0,0,0,.04);
    display: flex; align-items: center; justify-content: center; font-size: 15px; flex-shrink: 0; overflow: hidden;
  }
  .allergen-pick .ic img { width: 100%; height: 100%; object-fit: cover; }
  .me-allergen-btn {
    width: 70px; padding: 6px; border: 1.5px solid var(--border); border-radius: 6px; font-size: 11px;
    background: var(--card); cursor: pointer; color: var(--text-sub); touch-action: manipulation; white-space: nowrap; overflow: hidden;
  }
  .me-allergen-btn.has { border-color: var(--accent); color: var(--accent); }
  .al-admin-row { display: flex; align-items: center; gap: 10px; padding: 8px; border: 1px solid var(--border); border-radius: 10px; margin-bottom: 8px; }
  .al-admin-icwrap { position: relative; width: 40px; height: 40px; flex-shrink: 0; }
  .al-admin-ic {
    width: 40px; height: 40px; border-radius: 8px; background: rgba(0,0,0,.04);
    display: flex; align-items: center; justify-content: center; font-size: 20px; overflow: hidden;
  }
  .al-admin-ic img { width: 100%; height: 100%; object-fit: cover; }

  /* ===== iOS Standalone (Add to Home Screen) ===== */
  @media (display-mode: standalone) {
    /* 顶栏总高 = 内容高 + 状态栏/刘海安全区；padding 把 logo+标签压到状态栏下方 */
    nav { height: calc(var(--nav-h) + env(safe-area-inset-top, 0px)); padding-top: env(safe-area-inset-top, 0px); }
    .customer-nav { padding-bottom: env(safe-area-inset-bottom, 0px); }
    /* 各页面内容相应补上顶部安全区，避免被加高后的顶栏遮住 */
    .page { padding-top: calc(var(--nav-h) + env(safe-area-inset-top, 0px) + 16px); }
    .menu-layout {
      top: calc(var(--nav-h) + env(safe-area-inset-top, 0px));
      height: calc(100dvh - var(--nav-h) - env(safe-area-inset-top, 0px) - 52px);
    }
    .myorders-scroll {
      top: calc(var(--nav-h) + env(safe-area-inset-top, 0px));
      height: calc(100dvh - var(--nav-h) - env(safe-area-inset-top, 0px) - 52px);
    }
    /* v516：餐桌页定高滚动区同样补顶部安全区（与上面 .menu-layout / .myorders-scroll 同款） */
    #pageTables.active { top: calc(var(--nav-h) + env(safe-area-inset-top, 0px)); }
    #pageKitchen.active { top: calc(var(--nav-h) + env(safe-area-inset-top, 0px)); }
    /* 顾客端右上角 © 按钮：下移到状态栏之下 */
    #custAboutBtn { top: env(safe-area-inset-top, 0px) !important; }
  }

  /* 🔍 v529（Jay：点搜索后误触发页面放大，且因禁了缩放回不去）。
     真因：iOS Safari 有一条铁律——聚焦【字号<16px】的输入框时，会自动放大整个页面把它顶上来；
     而 user-scalable=no 在 iOS 上被系统忽略（苹果为无障碍强制放开），放大后没有捏合手势就回不去。
     搜索框是 15px，正好踩线。根治不是"再禁一次缩放"（禁不掉），而是把顾客可触达的输入类元素
     统一抬到 ≥16px —— 只要聚焦时字号不小于 16，iOS 就没有放大的理由，问题从源头消失。
     只在触屏(pointer:coarse)生效，桌面端字号不动；只覆盖顾客端会聚焦的元素，后台编辑表单不受影响。 */
  @media (pointer: coarse) {
    #dishSearchInput,
    #pageOrder input, #pageOrder textarea, #pageOrder select,
    #pageCombos input, #pageCombos textarea, #pageCombos select,
    #pageCustomerHome input, #pageCustomerHome textarea, #pageCustomerHome select,
    #pageMyOrders input, #pageMyOrders textarea, #pageMyOrders select,
    .attr-sheet input, .attr-sheet textarea, .attr-sheet select,
    #entryPinOverlay input {
      font-size: 16px !important;
    }
  }

  /* ===== 手机端适配 (original) ===== */
  @media (max-width: 768px) {
    .kitchen-body { flex-direction: column; }
    .stats-panel {
      width: 100%; max-height: none; overflow-y: visible;
      margin-bottom: 12px;
    }
    .stats-list { grid-template-columns: 1fr 1fr; }
    .orders-main {
      max-height: none; overflow-y: visible;
      grid-template-columns: 1fr;
    }
    /* 菜单布局手机端 */
    .cat-bar {
      width: 76px; font-size: 12px;
    }
    .cat-btn { padding: 12px 4px; font-size: 12px; }
    .dish-img { width: 64px; height: 64px; font-size: 26px; }
    .dish-name { font-size: 14px; }
    .dish-price { font-size: 14px; }
    .menu-list { padding: 0 8px 160px 8px; }
    .dish-card { padding: 10px; gap: 10px; }
    /* v474：购物车浮条在内容列（分类栏右侧 76px 起）居中——原 right:16px 贴右、忽略侧栏宽而右偏。
       [76, vw] 居中 → 中心 (76+vw)/2，恰等于内容卡片中心，浮条正落卡片下方居中。 */
    .cart-float { left: 76px; right: 0; margin-left: auto; margin-right: auto; max-width: calc(100vw - 92px); }
  }

  @media (min-width: 769px) {
    .page:not(#pageKitchen):not(#pageOrder):not(#pageHub) { max-width: 600px; margin: 0 auto; }
    .cart-float { max-width: 560px; left: 0; right: 0; width: auto; margin: 0 auto; }
  }

/* ===================== 菜品属性编辑器（B1）===================== */
/* 原型用到、本主题缺失的变量 → 映射到现有变量 / 字面色（明暗主题均可读）*/
:root{
  --indigo: var(--accent); --indigo-light: var(--accent-light);
  --amber: #C77800; --amber-light: rgba(199,120,0,.14);
  --danger-bg: rgba(214,69,69,.10); --danger-border: rgba(214,69,69,.38);
  --border-d: var(--border); --input: var(--surface);
}
/* 菜单行的属性按钮（样式与过敏原按钮一致）*/
.me-attr-btn{padding:6px 9px;border:1.5px solid var(--border);border-radius:6px;font-size:11px;background:var(--card);cursor:pointer;color:var(--text-sub);touch-action:manipulation;white-space:nowrap;font-weight:600}
.me-attr-btn.has{border-color:#161616;color:#161616;background:#fff}

/* ═══ v625（UI 铁律 5）：菜品行按钮可见性 ═══
   菜品行是斑马纹（奇 --surface / 偶 --card），而 .me-btn / .me-allergen-btn / .me-attr-btn
   的底色恰好都是 var(--card) —— 偶数行按钮与行底【完全同色】，只剩一条淡边框。
   深色 #2A3340 撞 #2A3340、浅色 #FFFFFF 撞 #FFFFFF，两个主题都中招（Jay 截图实证）。
   改用与【两种行底都不同】的中性档；带修饰类的（.accent/.red/.has）保持各自配色不动。 */
.me-btn:not(.accent):not(.red),
.me-allergen-btn:not(.has),
.me-attr-btn:not(.has) { background: #E6E3DA; border-color: #D2CFC5; color: #3A3A38; }
.hub-dark .me-btn:not(.accent):not(.red),
.hub-dark .me-allergen-btn:not(.has),
.hub-dark .me-attr-btn:not(.has) { background: #3A4553; border-color: #4E5A69; color: #E6EAF0; }
/* 弹层 */
.attr-mask{position:fixed;inset:0;z-index:110;background:rgba(0,0,0,.62);display:none;align-items:flex-end;justify-content:center}
.attr-mask.show{display:flex}
@media(min-width:560px){.attr-mask{align-items:center}}
#colorMask{z-index:2300;align-items:center;padding:20px 16px}
#colorSheet{border-radius:18px;max-height:78vh}
.attr-sheet{width:100%;max-width:560px;max-height:92dvh;background:var(--bg);border-radius:18px 18px 0 0;display:flex;flex-direction:column;overflow:hidden;transform:translateY(24px);transition:transform .24s;box-shadow:var(--shadow-lg)}
@media(min-width:560px){.attr-sheet{border-radius:18px}}
.attr-mask.show .attr-sheet{transform:none}
#dishImgSheet{height:86dvh;max-height:86dvh}
.attr-sheet.small{max-width:420px}
.attr-sheet .sh-head{flex-shrink:0;padding:16px 18px 0;background:var(--card);border-radius:18px 18px 0 0;position:relative;border-bottom:1px solid var(--border)}
.attr-sheet .sh-head h3{font-size:17px;padding-right:34px;margin:0 0 2px}
.attr-sheet .sh-head .x{position:absolute;top:14px;right:14px;width:30px;height:30px;border:0;background:var(--surface);border-radius:50%;font-size:17px;color:var(--text-sub);cursor:pointer}
.attr-sheet .sh-tabs{display:flex;gap:4px;margin-top:12px}
.attr-sheet .sh-tabs button{font:inherit;font-size:13px;font-weight:650;border:0;background:transparent;color:var(--text-sub);padding:10px 14px;border-radius:9px 9px 0 0;cursor:pointer;border-bottom:2.5px solid transparent}
.attr-sheet .sh-tabs button.on{color:var(--accent);border-bottom-color:var(--accent)}
.attr-sheet .sh-body{overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:none;touch-action:pan-y;padding:16px 18px;flex:1;min-height:0}
.attr-sheet .sh-foot{flex-shrink:0;padding:13px 18px max(13px,env(safe-area-inset-bottom));border-top:1px solid var(--border);background:var(--card);display:flex;gap:10px;align-items:center}
.attr-done{margin-left:auto;background:var(--accent);color:#fff;border:0;border-radius:9px;padding:11px 24px;font-weight:700;font-size:14px;cursor:pointer}
/* 属性组卡片 */
.gcard{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:14px;margin-bottom:13px;box-shadow:var(--shadow)}
.gtop{display:flex;align-items:center;gap:9px;margin-bottom:12px;flex-wrap:wrap}
.attr-lab{display:block;font-size:11.5px;color:var(--text-sub);margin-bottom:4px;font-weight:600}
input.attr-f{width:100%;font:inherit;font-size:13px;background:var(--input);border:1px solid var(--border);border-radius:8px;padding:8px 10px;color:var(--text)}
.oprow{display:flex;gap:8px;align-items:center;margin-bottom:8px}
.oprow .on{flex:1}
.attr-del{width:32px;height:34px;flex:0 0 auto;border:1px solid var(--danger-border);background:var(--danger-bg);color:var(--accent-dark);border-radius:7px;cursor:pointer}
.miniadd{font:inherit;font-size:12.5px;font-weight:600;border:1.5px dashed var(--border-d);background:none;color:var(--accent);border-radius:8px;padding:8px 12px;cursor:pointer;margin-top:4px}
.miniadd:hover{background:var(--accent-light)}
.delg{margin-left:auto;font:inherit;font-size:12px;font-weight:600;border:1px solid var(--danger-border);background:none;color:var(--accent-dark);border-radius:7px;padding:6px 11px;cursor:pointer}
.addgrp{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}
.addgrp button{font:inherit;font-size:13px;font-weight:650;border:1.5px dashed var(--border-d);background:var(--card);color:var(--text);border-radius:9px;padding:11px 14px;cursor:pointer}
.addgrp button:hover{border-color:var(--accent);color:var(--accent)}
.attr-empty{text-align:center;padding:24px 16px;color:var(--text-sub);font-size:13px}
.attr-hint{font-size:12px;color:var(--text-sub);margin:10px 0 0;line-height:1.6}
.attr-hint code{background:var(--surface);padding:1px 5px;border-radius:4px}
/* 单选/多选 segmented + 必选 pill */
.seg{display:inline-flex;border:1.5px solid var(--border-d);border-radius:9px;overflow:hidden;background:var(--input)}
.seg button{font:inherit;font-size:12.5px;font-weight:650;border:0;background:none;color:var(--text-sub);padding:7px 14px;cursor:pointer;border-right:1px solid var(--border)}
.seg button:last-child{border-right:0}
.seg button.on{background:var(--accent);color:#fff}
.reqpill{display:inline-flex;align-items:center;gap:5px;font-size:12.5px;font-weight:650;color:var(--text-sub);border:1.5px solid var(--border-d);border-radius:9px;padding:6px 11px;cursor:pointer;user-select:none}
.reqpill.on{border-color:var(--accent);color:var(--accent);background:var(--accent-light)}
.reqpill input{width:15px;height:15px;accent-color:var(--accent);margin:0}
/* 选项块 + 溢价/数量 */
.optblock{border:1px solid var(--border);border-radius:9px;padding:9px;margin-bottom:9px;background:var(--surface)}
.optblock .oprow{margin-bottom:0}
.actrow{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.actbtn{font:inherit;font-size:12px;font-weight:600;border:1.5px dashed var(--border-d);background:none;color:var(--text-sub);border-radius:8px;padding:6px 11px;cursor:pointer}
.actbtn:hover{border-color:var(--accent);color:var(--accent);background:var(--accent-light)}
.actfield{display:inline-flex;align-items:center;gap:6px;background:var(--accent-light);border:1.5px solid var(--accent);border-radius:8px;padding:4px 6px 4px 9px}
.actfield .eur{font-size:13px;font-weight:800;color:var(--accent-dark)}
.actfield .qlab{font-size:11.5px;color:var(--text-sub);font-weight:600;white-space:nowrap}
.actoff{width:24px;height:24px;border:1px solid var(--danger-border);background:var(--input);color:var(--accent-dark);border-radius:6px;cursor:pointer;font-size:12px;line-height:1;flex:0 0 auto}
.qtyfield{background:var(--amber-light);border-color:var(--amber)}
.qtyfield .eur,.qtyfield .qlab{color:var(--amber)}
.qtyfield .actoff{border-color:var(--amber);color:var(--amber)}
/* 步进器 */
.stepper{display:inline-flex;align-items:center;border:1px solid var(--border);border-radius:8px;overflow:hidden;background:var(--input)}
.stepper button{width:36px;height:36px;border:0;background:transparent;color:var(--accent);font-size:20px;font-weight:700;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;touch-action:manipulation;-webkit-user-select:none;user-select:none}
.stepper button:hover,.stepper button:active{background:var(--accent-light)}
.stepper input{width:54px;height:36px;border:0;border-left:1px solid var(--border);border-right:1px solid var(--border);background:transparent;text-align:center;font-size:14px;font-weight:700;color:var(--text);-moz-appearance:textfield;appearance:textfield}
.stepper input:focus{outline:none}
.stepper input::-webkit-outer-spin-button,.stepper input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.qtyfield .stepper button{color:var(--amber)}
.qtyfield .stepper button:hover,.qtyfield .stepper button:active{background:var(--amber-light)}
/* 颜色按钮 + 选择器 */
.colorbtn{display:inline-flex;align-items:center;gap:6px}
.cdot{width:18px;height:18px;min-width:18px;max-width:18px;box-sizing:border-box;border-radius:50%;display:inline-block;flex:0 0 auto;box-shadow:0 0 0 1px rgba(0,0,0,.3) inset}
.cdot.empty{background:conic-gradient(from 0deg,hsl(0,90%,55%),hsl(45,90%,55%),hsl(90,80%,48%),hsl(140,75%,46%),hsl(180,80%,48%),hsl(220,85%,58%),hsl(265,80%,60%),hsl(310,85%,60%),hsl(360,90%,55%));box-shadow:0 0 0 1px rgba(0,0,0,.18) inset}
.cgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(40px,1fr));gap:9px;margin-bottom:14px}
.csw{aspect-ratio:1;border-radius:8px;border:0;cursor:pointer;box-shadow:0 0 0 1px rgba(0,0,0,.22) inset;transition:transform .1s;touch-action:manipulation;display:flex;align-items:center;justify-content:center;font:inherit;font-weight:800;font-size:14px}
.csw:hover{transform:scale(1.1)}
.csw.on{outline:3px solid #161616;outline-offset:2px;transform:scale(1.16);box-shadow:0 3px 12px rgba(0,0,0,.45);position:relative;z-index:2}
.clearcolor{width:100%;margin-top:4px;padding:11px;border:1.5px dashed var(--border-d);background:none;color:var(--text-sub);border-radius:9px;font:inherit;font-weight:600;cursor:pointer}
.clearcolor.on{border-color:var(--accent);color:var(--accent);background:var(--accent-light)}
/* 多语言翻译矩阵 */
.attr-mtx{background:var(--card);border:1px solid var(--border);border-radius:var(--radius);padding:4px;box-shadow:var(--shadow);overflow-x:auto}
table.attr-tt{width:100%;border-collapse:collapse;min-width:460px}
table.attr-tt th{font-size:11px;color:var(--text-sub);font-weight:700;text-align:left;padding:9px 8px;border-bottom:2px solid var(--border)}
table.attr-tt td{padding:5px 6px;border-bottom:1px solid var(--border)}
table.attr-tt .rk{font-size:12px;color:var(--text-sub);white-space:nowrap;max-width:120px}
table.attr-tt .rk.grp{font-weight:800;color:var(--text)}
table.attr-tt input{width:100%;min-width:84px;font:inherit;font-size:12.5px;border:1px solid var(--border);border-radius:6px;padding:6px 8px;background:var(--input);color:var(--text)}
table.attr-tt input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-light)}/* 卡片「＋ 选择」按钮 + 数量角标 */
.cz-pick-btn{position:relative;border:1.5px solid var(--accent);background:var(--accent);color:#fff;border-radius:11px;padding:8px 14px;font:inherit;font-size:13px;font-weight:700;cursor:pointer;white-space:nowrap;touch-action:manipulation}
.cz-pick-n{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;margin-left:6px;padding:0 4px;background:#fff;color:var(--accent);border-radius:9px;font-size:11px;font-weight:800;vertical-align:1px}
/* 可定制菜品：单个圆形「＋」，与普通菜的加号一致；角标浮在右上角 */
.cz-pick-plus{width:30px;height:30px;min-width:30px;padding:0;border-radius:50%;border:none;font-size:18px;line-height:1;display:inline-flex;align-items:center;justify-content:center;overflow:visible}
.cz-pick-plus .cz-pick-n{position:absolute;top:-6px;right:-6px;margin-left:0;min-width:17px;height:17px;padding:0 3px;border:1.5px solid var(--accent);border-radius:9px;font-size:10px;box-shadow:0 1px 3px rgba(0,0,0,.18);vertical-align:0}/* 选购弹层主体（容器复用 .attr-sheet / .sh-head / .sh-body）*/
.cz-hero{display:flex;align-items:center;gap:12px;padding:2px 0 14px}
.cz-emoji{font-size:34px;line-height:1;flex:0 0 auto}
.cz-hero h3{font-size:18px;margin:0}
.cz-desc{font-size:12.5px;color:var(--text-sub);margin-top:3px;line-height:1.4}
.cz-grp{margin-bottom:18px}
.cz-grp-head{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-bottom:9px}
.cz-grp-name{font-size:14.5px;font-weight:700}
.cz-badge{font-size:10.5px;font-weight:600;color:var(--text-sub);background:var(--surface);border:1px solid var(--border);border-radius:5px;padding:1px 6px}
.cz-badge.req{color:var(--accent);border-color:var(--accent);background:var(--accent-light)}
.cz-opts{display:flex;flex-wrap:wrap;gap:9px}
.cz-opt{display:inline-flex;align-items:center;gap:7px;border:1.5px solid var(--border);background:var(--card);border-radius:11px;padding:9px 13px;font:inherit;font-size:13.5px;font-weight:600;color:var(--text);cursor:pointer;touch-action:manipulation;transition:transform .08s}
/* 🚨 v486→v487 修「点选项一闪」（Jay 报；与 v455 套餐行 / v459 落地图 / v460 菜品图同一类病）：
   .cz-opt 等是带 onclick 的 <button>，命中全局 button:active{opacity:.6} 与 .tapping{opacity:.55}
   → 一点就被压到 55% 半透明再弹回 ＝ 肉眼「闪一下」。与 DOM 重建 / 图片解码无关。
   【v487 定稿】按压一律【零视觉变化】，写法对齐 .dish-img（v460 Jay 验收通过的手感基准）：只写 opacity:1。
   v486 曾用 filter:brightness() 想保留一点反馈 —— 那层压暗本身就是 Jay 说的「弱化版的闪」，已全部去掉。
   原则：选项的反馈来自【选中态外框/配色】本身，按压不该再叠加任何图层。 */
/* ——【第一类】有选中态（外框/配色）的元素 → 按压【零视觉变化】，反馈来自选中态本身 —— */
.cz-opt:active, .cz-opt.tapping { opacity: 1 !important; }
.sm-pick-tab:active, .sm-pick-tab.tapping { opacity: 1 !important; }
.sm-chip:active, .sm-chip.tapping { opacity: 1 !important; }
/* ——【第二类】无选中态的动作按钮 → 按住变暗、松手恢复（v488 Jay 定：没有外框就需要按压反馈）—— */
.cz-qstep button:active, .cz-qstep button.tapping { opacity: 1 !important; filter: brightness(.88); }
.sm-qstep button:active, .sm-qstep button.tapping { opacity: 1 !important; filter: brightness(.88); }
.cz-add:active, .cz-add.tapping { opacity: 1 !important; filter: brightness(.9); }
.sm-pick-x:active, .sm-pick-x.tapping { opacity: 1 !important; filter: brightness(.85); }
/* 审计补漏（v486）：这三个同样是带底色的可点大块，压淡即闪 —— .ccombo-add 是顾客端套餐「选择」按钮，
   .sm-wd/.sm-pickbtn 是 v484 新增的编辑器控件。 */
.ccombo-add:active, .ccombo-add.tapping { opacity: 1 !important; filter: brightness(.9); }   /* 动作按钮：变暗 */
.sm-wd:active, .sm-wd.tapping { opacity: 1 !important; }                                       /* 周几：有选中态 → 零反馈 */
.sm-pickbtn:active, .sm-pickbtn.tapping { opacity: 1 !important; filter: brightness(.94); }     /* 动作按钮：变暗 */
/* 点单页加减号（.qty-plus/.qty-minus/.qty-btn）：无选中态 → 按住变暗、松手恢复（替代原涟漪+压淡） */
.qty-btn:active, .qty-btn.tapping,
.qty-plus:active, .qty-plus.tapping,
.qty-minus:active, .qty-minus.tapping { opacity: 1 !important; filter: brightness(.86); }
/* 选购加号/按钮（cz-pick-*）同属动作按钮 */
.cz-pick-btn:active, .cz-pick-btn.tapping,
.cz-pick-plus:active, .cz-pick-plus.tapping { opacity: 1 !important; filter: brightness(.9); }
/* v533 柜台开台/改人数弹窗的人数快选键（原为行内样式的裸 <button>，v533 起有了选中态）：
   数字键只【选中】人数、不再直接提交，选中反馈＝橙色外框+底色；
   按【第一类】规则（同 .cz-opt/.sm-wd/.dish-img）按压零视觉变化，避免带底色被压淡再弹回的「一闪」。 */
.seat-quick { padding:14px 0; border-radius:8px; border:1.5px solid var(--border); background:var(--card); color:var(--text); font:inherit; font-size:18px; font-weight:700; cursor:pointer; touch-action:manipulation; }
.seat-quick.on { border-color:var(--accent); background:var(--accent-light); color:var(--accent); }
.seat-quick:active, .seat-quick.tapping { opacity: 1 !important; }
button.cz-opt{position:relative;justify-content:center;padding-left:26px;padding-right:26px}
.cz-opt.on{border-color:var(--green);color:var(--green)}.cz-oname{white-space:nowrap}
.cz-oprice{font-size:11.5px;font-weight:700;opacity:.85}
.cz-check{position:absolute;right:11px;top:50%;transform:translateY(-50%);visibility:hidden;font-weight:800;pointer-events:none}
/* v524 顺手堵同类隐患：这个勾是纯装饰标记，高度不定没法用 margin 居中，只能保留 transform；
   但只要它不接收指针事件，就永远不会自己进 :active，也就轮不到被 `.attr-mask *:active{transform:none}` 清掉。
   附带好处：点选项时右边缘不再被这个勾挡一下，命中更稳。 */
.cz-opt.on .cz-check{visibility:visible}
.cz-qstep{display:inline-flex;align-items:center;gap:2px;margin-left:2px}
.cz-qstep button{width:28px;height:28px;border:1px solid var(--border);background:var(--surface);color:var(--accent);border-radius:7px;font-size:16px;font-weight:700;cursor:pointer;line-height:1;touch-action:manipulation}
.cz-qstep button:disabled{opacity:.4;cursor:default}
.cz-qstep .qn{min-width:22px;text-align:center;font-size:14px;font-weight:700}
.cz-qstep.big button{width:36px;height:36px;font-size:19px}
.cz-qstep.big .qn{min-width:30px;font-size:16px}
/* 同色互斥子框 */
.cz-cluster{display:flex;flex-wrap:wrap;gap:8px;align-items:center;border:1.5px dashed var(--border);border-radius:11px;padding:8px 10px}.cz-empty{text-align:center;color:var(--text-sub);font-size:13px;padding:20px}
/* 弹层底部：合计 + 数量 + 加入 */
.cz-foot{flex-shrink:0;padding:12px 18px max(12px,env(safe-area-inset-bottom));border-top:1px solid var(--border);background:var(--card);display:flex;flex-direction:column;gap:10px}
.cz-foot-top{display:flex;align-items:center;justify-content:space-between;gap:12px}
.cz-total{font-size:13px;color:var(--text-sub)}
.cz-total b{font-size:19px;color:var(--text);margin-left:6px}
.cz-foot-btns{display:flex}
.cz-add{flex:1;background:var(--accent);color:#fff;border:0;border-radius:12px;padding:14px;font:inherit;font-size:15px;font-weight:800;cursor:pointer;touch-action:manipulation}
.cz-add.miss{background:var(--surface);color:var(--text-sub);cursor:not-allowed}
.cz-add:disabled{background:var(--surface);color:var(--text-sub);cursor:not-allowed}.cs-line{position:relative;display:flex;align-items:flex-start;gap:11px;padding:13px 28px 13px 0;border-bottom:1px solid var(--border)}
.cs-line:last-child{border-bottom:0}
.cs-emoji{width:42px;height:42px;border-radius:9px;display:flex;align-items:center;justify-content:center;font-size:24px;background:var(--surface);flex:0 0 auto;overflow:hidden}
.cs-emoji img{width:100%;height:100%;object-fit:cover}
.cs-main{flex:1;min-width:0}
.cs-name{font-size:14px;font-weight:700;color:var(--text);line-height:1.3}
.cs-name .dish-num-tag{font-weight:600}
.cs-price{font-size:15px;font-weight:800;color:var(--accent);white-space:nowrap;line-height:1;margin-top:6px}
.cs-side{display:flex;flex-direction:column;align-items:flex-end;gap:8px;flex:0 0 auto;max-width:52%;margin-top:2px}
.cs-sub{font-size:12px;color:var(--text-sub);line-height:1.35;word-break:break-word;text-align:right}
.cs-sub-edit{font-size:12px;color:var(--accent);line-height:1.35;word-break:break-word;text-align:right;background:none;border:0;font-family:inherit;font-weight:600;cursor:pointer;padding:0;touch-action:manipulation}
.cs-sub-edit:active,.cs-sub-edit.tapping{opacity:1 !important;filter:brightness(.8)}
.cs-sub-ic{opacity:.65;margin-left:1px}
/* v500：拆成两个【独立按钮】——原来共享外框且 overflow:hidden，果冻放大到 1.08 的部分被裁掉，
   动效发闷（Jay 报「嵌套在框里使果冻减弱」）。现在各按钮自带边框圆角、之间留 gap，形变有余地。 */
.cs-qty{display:inline-flex;align-items:center;gap:6px;overflow:visible}
.cs-qty button{width:30px;height:30px;border:1px solid var(--border);border-radius:8px;background:var(--surface);color:var(--accent);font-size:17px;font-weight:700;cursor:pointer;line-height:1;padding:0;touch-action:manipulation}
.cs-qty button:disabled{opacity:.35;cursor:default}
.cs-qty .qn{min-width:26px;height:30px;display:inline-flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;border:0;background:transparent}
.cs-del{position:absolute;top:12px;right:0;width:24px;height:24px;border:0;background:var(--surface);color:var(--text-sub);border-radius:7px;cursor:pointer;font-size:12px;line-height:1;touch-action:manipulation}
.cs-clear{flex:0 0 auto;margin-left:auto;border:1px solid var(--border);background:none;color:var(--text-sub);border-radius:9px;padding:8px 14px;font:inherit;font-size:13px;font-weight:600;cursor:pointer;touch-action:manipulation}
/* 🛒 v493 购物车按压反馈（Jay 报「购物车加减按钮快闪」）：这些是带 onclick 的 <button>，
   命中全局 button:active{opacity:.6} 与 .tapping{opacity:.55} → 压淡＝快闪。
   按 v488 定的两类规则，它们都是【无选中态的动作按钮】→ 按住变暗、松手恢复。
   加减按钮的 brightness(.86) 与菜单 +/−（.qty-plus/.qty-minus/.qty-btn）完全一致，手感统一。 */
.cs-qty button:active, .cs-qty button.tapping { opacity: 1 !important; filter: brightness(.86); }
.cs-del:active, .cs-del.tapping { opacity: 1 !important; filter: brightness(.86); }
.cs-clear:active, .cs-clear.tapping { opacity: 1 !important; filter: brightness(.92); }
/* disabled 的加减按钮保持原本的 .35 淡出，不被上面的 !important 顶掉 */
.cs-qty button:disabled:active, .cs-qty button:disabled.tapping { opacity: .35 !important; filter: none; }
/* 套餐多语言弹层 */
.smi-hint{font-size:12px;color:var(--text-sub);line-height:1.6;margin:0 0 14px}
.smi-group{border:1px solid var(--border);border-radius:12px;padding:12px 14px;margin-bottom:14px;background:var(--card)}
.smi-title{font-size:15px;font-weight:800;color:var(--text);margin-bottom:10px}
.smi-field{margin-bottom:12px}
.smi-field:last-child{margin-bottom:0}
.smi-label{font-size:12px;font-weight:700;color:var(--text-sub);margin-bottom:6px}
.smi-label b{color:var(--text);font-weight:700}
.smi-in{display:flex;align-items:center;gap:8px;margin-bottom:6px}
.smi-in:last-child{margin-bottom:0}
.smi-flag{flex:0 0 96px;font-size:12px;color:var(--text-sub);white-space:nowrap}
.smi-in input{flex:1;min-width:0;padding:8px 10px;border:1px solid var(--border);border-radius:8px;font-size:14px;font-family:inherit;background:var(--surface);color:var(--text)}
.smi-in input:focus{outline:none;border-color:var(--accent)}
.smi-io{margin-bottom:16px;border:1px solid var(--border);border-radius:10px;background:var(--surface);overflow:hidden}
.smi-io summary{cursor:pointer;font-size:13px;font-weight:700;color:var(--accent);padding:12px 14px;list-style:none;touch-action:manipulation}
.smi-io summary::-webkit-details-marker{display:none}
.smi-io-body{padding:0 14px 14px}
.smi-io-body p{font-size:12px;color:var(--text-sub);line-height:1.7;margin:0 0 10px}
.smi-io-body code{background:var(--card);padding:1px 6px;border-radius:4px;font-size:11px;font-family:ui-monospace,Menlo,Consolas,monospace}
.smi-io-btns{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.smi-io-btns button{flex:1;min-width:130px;padding:9px;border:1px solid var(--border);border-radius:8px;background:var(--card);font:inherit;font-size:12px;font-weight:600;color:var(--accent);cursor:pointer;touch-action:manipulation}
.smi-io textarea{width:100%;min-height:128px;padding:10px;border:1px solid var(--border);border-radius:8px;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px;line-height:1.5;background:var(--card);color:var(--text);resize:vertical;box-sizing:border-box;margin-bottom:8px}
.smi-io textarea:focus{outline:none;border-color:var(--accent)}
.smi-io-import{width:100%;padding:10px;border:0;border-radius:8px;background:var(--green,#0E9F8E);color:#fff;font:inherit;font-size:13px;font-weight:700;cursor:pointer;touch-action:manipulation}
/* 出菜端 chip 属性 notes */
.chip-notes{display:inline-block;max-width:100%;font-size:calc(var(--chip-font,15px) * .7);color:#92400E;background:#FEF3C7;border:1px solid #FDE68A;border-radius:5px;padding:1px 5px;font-weight:700;line-height:1.3;margin-top:3px;word-break:break-word}
.item-chip.done .chip-notes{opacity:.5}
/* 菜品搜索弹层 */
/* 搜索弹窗固定高度：输入时外框不随结果数量跳动 */
.ds-sheet{height:82vh;height:82dvh;max-height:82dvh}
@media(min-width:560px){.ds-sheet{height:min(640px,82dvh)}}
/* 搜索输入框（放大镜 + 清除） */
.ds-search-wrap{position:relative;display:flex;align-items:center}
.ds-search-ic{position:absolute;left:13px;width:18px;height:18px;color:var(--text-sub);pointer-events:none;flex:0 0 auto}
#dishSearchInput{width:100%;box-sizing:border-box;padding:12px 44px;border:2px solid var(--border);border-radius:12px;font-size:15px;font-family:inherit;background:var(--input);color:var(--text)}
#dishSearchInput:focus{outline:none;border-color:var(--accent)}
.ds-search-clear{position:absolute;right:8px;width:28px;height:28px;border:0;border-radius:50%;background:var(--surface);color:var(--text-sub);font-size:13px;display:flex;align-items:center;justify-content:center;cursor:pointer}
.ds-empty{text-align:center;color:var(--text-sub);font-size:14px;padding:44px 16px;line-height:1.6}
.ds-empty-ic{font-size:40px;margin-bottom:12px;opacity:.5}
.ds-result{display:flex;align-items:center;gap:12px;width:100%;text-align:left;padding:11px 6px;border:0;border-bottom:1px solid var(--border);background:none;font-family:inherit;cursor:pointer}
.ds-result:last-child{border-bottom:0}
/* v627（Jay 报「搜索菜品按住拖动会快速闪好几次」）：.ds-result 是 <button>，命中全局
   button:active{opacity:.6} 与 .tapping{opacity:.55}。按住拖动时浏览器在「滚动还是点击」之间
   反复判定，:active 被一加一撤 → 快速闪几下。可滚动列表里的按钮都有这个毛病，房子里既有解法
   一致（.cat-btn 分类条、.dish-img 菜品图）：屏蔽 opacity 反馈、零附加效果（v487 定的手感基准）。
   点中即跳转并关闭搜索面板，本来也不需要按压反馈。 */
.ds-result:active, .ds-result.tapping { opacity: 1 !important; }
.ds-emoji{flex:0 0 auto;width:46px;height:46px;border-radius:8px;background:var(--surface);display:flex;align-items:center;justify-content:center;font-size:24px;overflow:hidden}
.ds-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
.ds-name{font-size:14px;font-weight:700;color:var(--text);line-height:1.3}
.ds-num{font-size:11px;color:var(--text-sub);font-weight:600}
.ds-cat{font-size:12px;color:var(--text-sub)}
.ds-price{flex:0 0 auto;font-size:14px;font-weight:800;color:var(--accent);white-space:nowrap}
/* 搜索跳转后高亮 */
@keyframes dishFlash{0%,100%{box-shadow:0 0 0 0 rgba(232,93,58,0)}30%{box-shadow:0 0 0 3px var(--accent)}}
.dish-flash{animation:dishFlash 1.7s ease}

/* ═══ v124 手机端排查修复 ═══ */
/* 翻译页多语言表格：窄屏改为区域内横向滚动，保证每列可用且可达 */
#translateArea { overflow-x: auto; -webkit-overflow-scrolling: touch; }
#translateArea table { min-width: 560px; }
/* 过敏原选择卡片：长译名（如 Frutos de cáscara）省略号收尾，不撑破卡片 */
.allergen-pick span:not(.ic) { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ═══ v130 多语言按钮自适应（西语/加泰语文案比中文长2-4倍，不裁字是底线）═══ */
/* ① 标签类按钮：宽度随文字自适应，容不下则换行；保住触控高度下限，行距收紧防松散 */
.kitchen-btn, .me-btn, .me-attr-btn, .cz-add, .attr-done, .save-btn, .hub-link {
  white-space: normal;
  height: auto;
  min-height: 36px;
  line-height: 1.25;
  overflow-wrap: break-word;
}
/* ② 固定高度导航条里的 tab：不换行（会被条高裁切），改为横向滑动——每个 tab 完整容纳文字（安卓 tabs 标准模式）。店家四端与顾客端共用 #navTabs，一处通吃 */
/* v132 修正：横滑会把最右侧 tab（如西语 Ajustes）藏到屏外不可发现——改为均分+缩字，四个 tab 永远全部可见 */
#navTabs { overflow: hidden; }
#navTabs .tab { flex: 1 1 0; min-width: 0; white-space: nowrap; overflow: hidden; padding-left: 6px; padding-right: 6px; display: flex; align-items: center; justify-content: center; }
/* ③ 属性多语言表词条列：长基准名允许换行（表格已有 560px 横滚兜底，不会互相挤压） */
table.attr-tt .rk { white-space: normal; }

/* ═══ v131 员工端菜品块：长内容自适应加宽 + 数量角标永不被盖 ═══ */
/* 长菜名/长属性串（如 corto/descafeinado/leche de soja…）的 chip 占两列＝2倍宽；dense 回填空洞保持看板紧凑 */
.order-items { grid-auto-flow: dense; }
.item-chip.wide { grid-column: span 2; }
/* 数量角标（0/2、✓）加不透明底衬+微描边：长文字换行穿过时角标依然清晰可读 */
.item-chip .chip-qty {
  background: var(--card);
  padding: 0 4px;
  border-radius: 5px;
  box-shadow: 0 0 0 1px var(--border);
  z-index: 1;
}

/* ═══ v132 放大镜弹窗（大字模式）═══ */
.zoom-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 3000; display: flex; align-items: center; justify-content: center; padding: 18px; }
.zoom-box { position: relative; background: var(--card); border-radius: 16px; max-width: 620px; width: 100%; max-height: 82vh; overflow-y: auto; overscroll-behavior: none; padding: 20px 18px 16px; box-shadow: 0 18px 60px rgba(0,0,0,.35); }
.zoom-x { position: absolute; top: 10px; right: 10px; width: 38px; height: 38px; border: none; border-radius: 10px; background: var(--surface); color: var(--text); font-size: 19px; font-weight: 700; cursor: pointer; }
.zoom-title { font-size: 26px; font-weight: 800; margin-bottom: 12px; }
.zoom-item { padding: 12px 4px; border-bottom: 1px solid var(--border); }.zoom-line1 { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.zoom-num { font-size: 24px; font-weight: 800; color: var(--accent); }
.zoom-name { font-size: 22px; font-weight: 700; word-break: break-word; min-width: 0; }
.zoom-qty { margin-left: auto; font-size: 20px; font-weight: 700; color: var(--text-sub); white-space: nowrap; }
.zoom-notes { margin-top: 8px; font-size: 19px; line-height: 1.45; color: #92400E; background: #FEF3C7; border: 1px solid #FDE68A; border-radius: 8px; padding: 8px 10px; word-break: break-word; }
/* v133 菜品 chip 左上角放大按钮（每道菜一个）；code/M 徽章右移让位 */
.item-chip .chip-zoom { position: absolute; top: 1px; left: 1px; width: 21px; height: 21px; display: grid; place-items: center; font-size: 11px; border-radius: 6px; background: rgba(255,255,255,.75); cursor: pointer; z-index: 2; }
.item-chip .chip-code { left: 25px; }
.item-chip .chip-menu { left: 25px; }
/* v133 渐显渐隐（退场先透明再隐藏，掩掉 history.back 闪帧） */
.zoom-overlay { opacity: 0; transition: opacity .16s ease; }
.zoom-overlay.on { opacity: 1; }

/* v134：fitb 缩字按钮统一居中（缩字后文字在原框内绝对居中，不再"偏一边"） */
.fitb { text-align: center; }

/* v139：非中文店家界面导航 tab 字号 -1px（Pedidos/Ajustes 等拉丁长词），中文界面维持 14px 不变 */
body.lang-latin nav .tab { font-size: 13px; }

  /* 拖拽导入高亮（主页/Logo 面板的拖放区） */
  .drag-over { border-color: var(--accent) !important; background: var(--accent-light) !important; }

  /* 🍮 果冻点击动效（高级功能，仅 body.jelly-btn 即顾客点单端激活时）：所有按钮点击 Q 弹形变 */
  @keyframes jellyBtn {
    0%{transform:scale(1,1)}
    25%{transform:scale(.92,1.08)}
    45%{transform:scale(1.08,.92)}
    65%{transform:scale(.97,1.03)}
    85%{transform:scale(1.02,.98)}
    100%{transform:scale(1,1)}
  }
  body.jelly-btn .jelly-play { animation: jellyBtn .55s ease; }
  /* 🎈 v499 Logo 果冻：Logo 是 <img>，给 transform 原点居中 + 手型，点起来像个可互动的品牌标 */
  /* 🎈 Logo 果冻。touch-action:manipulation 关掉【双击缩放】——Jay 报连点两次会把页面放大，
     退出缩放后 iOS 视觉视口复位不干净、页面底部留一条空白。禁掉双击缩放即从源头消除。
     该属性【不受 jelly 开关影响】，始终生效：Logo 本就不该被双击放大。 */
  #navLogo { touch-action: manipulation; }
  body.jelly-btn #navLogo { cursor: pointer; transform-origin: center center; }

  /* 🙈 隐藏菜品价格：已改由 app.js 的 fmtMoney 中枢 + 单价/合计条件渲染实现，无需 CSS */

  /* 🍱 Menu 超支菜（超出含额度、需加价）：员工端红框 + 右上角加价标 */
  .item-chip.menu-over { border: 2px solid #EAB308 !important; box-shadow: 0 0 0 2px rgba(234,179,8,.18); }
  .item-chip.menu-over::before { content: '＋💰'; position: absolute; bottom: -7px; right: -6px; font-size: 10px; background: #EAB308; color: #fff; padding: 0 5px; border-radius: 8px; font-weight: 700; z-index: 3; line-height: 15px; }

  /* 🔄 服务模式分段切换器（counter 设置页：散点/自助/Menu 三选一） */
  .sm-seg-wrap { display: flex; gap: 6px; background: var(--surface); padding: 5px; border-radius: 12px; }
  .sm-seg { flex: 1; padding: 12px 8px; border: none; border-radius: 9px; background: transparent; color: var(--text-sub); font-size: 13.5px; font-weight: 700; cursor: pointer; transition: background .18s, color .18s, box-shadow .18s; font-family: inherit; white-space: nowrap; }
  .sm-seg.on { background: var(--accent); color: #fff; box-shadow: 0 2px 8px rgba(232,93,58,.3); }
  .sm-seg:not(.on):active { background: var(--card); }

  /* 💶 呼叫买单·钞票雨（纯装饰，不拦点击） */
  .money-rain { position: fixed; inset: 0; pointer-events: none; z-index: 9998; overflow: hidden; }
  .money-bill { position: absolute; top: -48px; animation: moneyFall linear forwards; will-change: transform, opacity; filter: drop-shadow(0 3px 4px rgba(0,0,0,.18)); }
  @keyframes moneyFall {
    0%   { transform: translateY(-48px) rotate(0deg);   opacity: 0; }
    8%   { opacity: 1; }
    75%  { opacity: 1; }
    100% { transform: translateY(98vh) rotate(380deg);  opacity: 0; }
  }

  /* ⭐ 套餐级别锁定：基础套餐下高级功能开关变灰不可用 */
  .hub-link.plan-locked { opacity: .5; border-color: var(--border) !important; color: var(--text-sub) !important; background: var(--card) !important; cursor: not-allowed; }

/* 🩹 v380 后台减压：标签页隐藏时暂停一切动画/过渡，降低导致 Chrome 手机端合成器卡死的持续 GPU 压力。前台一分不影响。 */
html.bg-paused * { animation-play-state: paused !important; transition: none !important; }

/* ═══ 🌐 v598 阻塞门语言条 ═══
   GPS 门 / 进桌密码门 / 未开台锁屏共用。默认 display:none，由 renderGateLangs() 决定是否 flex
   （单语言店整条不出现）。各语言按钮用自身语言命名，不参与 i18n —— 那正是它能被看懂的原因。 */
.gate-langs{display:none;flex-wrap:wrap;justify-content:center;gap:6px;margin-top:18px;padding-top:14px;border-top:1px solid var(--border);}
.gate-langs button{padding:7px 13px;border:1px solid var(--border);border-radius:999px;background:transparent;color:var(--text-sub);font-size:12px;font-weight:600;font-family:inherit;line-height:1.2;cursor:pointer;-webkit-tap-highlight-color:transparent;}
/* 有选中态的按钮：按压零视觉变化（Carta 按钮反馈两类规则之一） */
.gate-langs button:active{opacity:1!important;}
.gate-langs button.on{background:var(--accent);border-color:var(--accent);color:#fff;}
