/* ══════════════════════════════════════════════════════════════════════
   Fork: iOS 视口/键盘适配
   ──────────────────────────────────────────────────────────────────────
   ⚠️ 2026-10-08 大回退。此前我写了一套 JS 手动模拟 Chromium 的
   `interactive-widget=resizes-content`（visualViewport → --app-height →
   键盘态覆盖壳高），结果越来越糟：输入框弹得过高、点一下还乱跳。

   **真相是：iOS 根本不需要这套东西。** 一手证据来自上位参考实现
   （Ekko Studio 的 dist，用户确认其移动端「输入框跟着键盘走，一点问题
   都没有」）：
     · 它的 assets 里 `visualViewport` 只出现在 ts.worker 与 Monaco 编辑器
       内部，**应用层零键盘代码**；
     · `keyboardHeight` / `kb-height` / `interactive-widget` 命中数全为 0；
     · 它全部的做法就是 `:root{--vh:1vh}` + `@supports(height:100dvh){--vh:1dvh}`
       + 各组件 `height: calc(100 * var(--vh))`。
   因为 **`dvh` 本身就是「动态视口高」——键盘弹起时它会自动变小**，输入框
   自然被顶到键盘上方。用 JS 去「帮忙」反而是干扰。

   所以这里只保留两件事：
     1) 锁壳（`position:fixed`），让 iOS 没有可被强行滚动的轴；
     2) 高度交给 `dvh`（老浏览器回退 `--vh` 变量），**不写任何键盘 JS**。
   ══════════════════════════════════════════════════════════════════════ */

/* ── 1. 聚焦不缩放 ─────────────────────────────────────────────────────
   iOS 在可编辑元素 font-size < 16px 时会自动放大视口并滚动页面，表现为
   「一点输入框整页飞上去」。上游 body 字号 0.8125rem(13px)，输入区继承后
   必然低于阈值。只抬可编辑元素，不动其它排版。 */
input:not([type='checkbox']):not([type='radio']):not([type='range']),
textarea,
select,
[contenteditable='true'],
[contenteditable='plaintext-only'],
[data-slot='composer-rich-input'] {
  font-size: max(16px, 1rem) !important;
}

/* ── 2. 横向锁死 + 整壳 page-fixed 锁定（窄屏触摸设备）──────────────────
   横向：关掉 iOS 的 overscroll「橡皮筋」并兜一层 overflow-x。
   整壳锁定：上游只靠 height:100% + overflow:hidden，挡不住 iOS 键盘弹起时
   为「露出聚焦元素」而滚动 <body>。改成 position:fixed 钉死，页面没有可被
   滚动的轴 —— 这也是上位参考实现的做法。 */
html,
body {
  overflow-x: hidden !important;
  overscroll-behavior-x: none;
  overscroll-behavior-y: none;
  max-width: 100vw;
}

#root {
  overflow-x: hidden !important;
  max-width: 100vw;
}

@media (max-width: 767.98px) and (pointer: coarse) {
  html,
  body {
    position: fixed !important;
    top: 0 !important;
    left: 0 !important;
    width: 100% !important;
    overflow: hidden !important;
    overscroll-behavior: none;
  }
}

/* 纵向滚动容器：允许自身滚动，但不把滚动链传出去（避免带动整页） */
[data-slot='thread-viewport'],
[class*='overflow-y-auto'],
[class*='overflow-y-scroll'] {
  overscroll-behavior-y: contain;
}

/* ── 3. 高度模型：只认 dvh，不写键盘 JS ────────────────────────────────
   `dvh` = 动态视口高度，键盘弹起时浏览器自己会把它缩小，输入框随之被顶到
   键盘上方 —— 这就是「输入框跟着键盘走」的全部实现。
   `--vh` 变量是老浏览器（不支持 dvh）的回退，写法照抄上位参考实现。 */
:root {
  --vh: 1vh;
}

@supports (height: 100dvh) {
  :root {
    --vh: 1dvh;
  }
}

html,
body,
#root {
  /* ⚠️ 壳高【不能】依赖 --vh 变量。原来只写 `calc(100 * var(--vh))`，那是单点故障：
     任何引擎里 --vh 未定义或「计算时无效」（standalone 首次布局、旧 WebKit 的 dvh
     边界情况），height 就会取 unset → 壳高 0 → 整页只剩预涂的主题底色。现象正是
     「装到主屏的 PWA 打开是白屏/黑屏，什么都没渲染」。而且注意：var() 替换失败时
     浏览器【不会】回退到前一条 height 声明，所以双声明也救不了它 —— 必须绕开变量。
     直接对高度做双声明（100vh 人人都有，100dvh 支持的引擎覆盖）。
     --vh 仅保留给诊断浮层（fork-mobile.js 的 ?kbdiag=1）读取，不再参与布局。 */
  height: 100vh;
  height: 100dvh;
  box-sizing: border-box;
}

/* ── 5. 安全区（刘海屏 / home indicator）───────────────────────────────
   ⚠️ 2026-10-08 重写。上一版把 padding 加在 html/body 上 + 用
   `@media (display-mode: standalone)` 包裹 —— **两个错**：
     ① `html` 的 padding 对 `position:fixed` 的后代**完全无效**（fixed 元素
        相对视口定位，不看祖先 padding）。而这个应用的 titlebar
        (`[data-titlebar-cluster]`, 'fixed z-70') 和 composer 都是 fixed/absolute
        → 它们直接顶进状态栏和 home indicator，元素落在系统手势区里**点不动**。
        症状就是「加到主屏后上下顶满、上下元素点不了」。
     ② 不需要 `display-mode` 媒体查询：`env(safe-area-inset-*)` 在非
        standalone 环境**本来就解析为 0**，浏览器标签页里是天然无副作用的。
   所以：把安全区加到**真正贴边的那些元素上**，让它们自己让出系统栏。
   这跟上位参考实现（Ekko Studio）一致 —— 它也是逐组件加 safe-area
   （`.chat-header{padding:calc(16px + env(safe-area-inset-top)) ...}`），
   而不是给根节点加 padding。 */

/* 顶栏工具群（fixed）：整体下移状态栏高度。用 transform 而非改 top，
   因为它的 top 是 JS 按 --titlebar-* 算出来的，直接改会打架。 */
[data-titlebar-cluster] {
  transform: translateY(env(safe-area-inset-top, 0px));
}

/* 顶部/底部的固定背景层同样让位，否则会露出系统栏底色的接缝 */
[data-slot='composer-root'] {
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

/* 主内容区（非 fixed 的正常流）用 padding 兜底，保证滚动内容不被遮挡 */
#root {
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
}

/* 注：底部的 safe-area 只在 composer-root 上处理（见上）。这里不再给 body
   重复加 padding-bottom —— body 是 position:fixed，重复加会让「壳高」与
   「输入区让位」叠两层，反而把内容挤窄。 */

/* ── 6. titlebar 触摸目标放大（粗指针，不限宽度）─────────────────────────
   ROADMAP 自认缺口：titlebar 图标按钮仅 24px（--titlebar-control-size），
   远低于 44px 触摸指引；相邻按钮 24px 间距，直接放到 44px 会互相重叠导致
   点串。做法：视觉按钮放大到 34px（仍留间隙），再用伪元素把命中区向上下
   扩展到 44px —— 纵向无竞争控件，安全；横向不加宽，不会与邻键重叠。

   ⚠️ 条件只按「粗指针」、不再 AND「窄屏」：iPad 是宽屏触摸设备，原先
   (max-width: 767.98px and pointer: coarse) 把它整条排除在外，于是 iPad 上
   titlebar 一直是 24px 的鼠标尺寸。桌面鼠标是 pointer: fine，不受影响。 */
@media (pointer: coarse) {
  :root {
    --titlebar-control-size: 34px;
  }

  /* 按钮本体：撑高到与变量一致（上游按钮高度是 24px 硬编码，不吃变量） */
  [data-titlebar-cluster] button,
  [data-titlebar-cluster] a {
    position: relative;
    min-height: var(--titlebar-control-size);
    min-width: var(--titlebar-control-size);
  }

  /* 命中区：纵向扩展到 44px，横向不变 —— 不与邻键重叠 */
  [data-titlebar-cluster] button::after,
  [data-titlebar-cluster] a::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 44px;
    transform: translateY(-50%);
  }
}

/* ── 7. 底部状态条：窄屏下的收缩与命中区 ────────────────────────────────
   实测（390×844 / iOS UA / 真 touch，2026-10-08）：
     · `[data-slot='statusbar']` 内右侧 chip 群溢出到 `right=416`（屏宽 390）
       → 最后一个 chip（"# backend v0…"）被裁掉一截。
     · 该条内 chip 的命中高度只有 20px（`h-5`）。

   根因（对上游源码）：上游 deliberately 用 `overflow-x-clip` + chip 内部
   `truncate` 处理过宽（statusbar-controls.tsx 有注释说明），但 **chip 自身
   是 `inline-flex` 且没有 `min-width: 0`** → flex 项无法收缩到内容宽度以下，
   truncate 拿不到机会，于是整块顶出边界。所以修的是「让 chip 真的能收缩」，
   与上游「截断而非滚动」的意图一致，不改信息架构。

   ⚠️ 不加 `overflow-x: auto`：上游明确否决滚动条方案；移动端横向可滑的
   信息条还会与整壳的触摸手势打架。 */
@media (max-width: 767.98px) and (pointer: coarse) {
  /* 缩小 chip 间距，先把横向预算还给标签 */
  [data-slot='statusbar'] > div {
    gap: 0.125rem;
  }

  /* 根因修复：chip 可收缩，truncate 才有机会生效 */
  [data-slot='statusbar'] > div > * {
    min-width: 0;
  }

  /* 顶栏那一套命中区手法复用到这里：纵向扩到 44px。
     ⚠️ 状态条内 chip 只有 20px 高，纵向扩到 44px 会与上方 composer 重叠。
     所以这里只扩到 32px（在条自身的可支配空间内），不追求 44px ——
     状态条是次要信息区，主控件的 44px 优先级更高，见下一条。 */
  [data-slot='statusbar'] button::after,
  [data-slot='statusbar'] a::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 32px;
    transform: translateY(-50%);
  }

  [data-slot='statusbar'] button,
  [data-slot='statusbar'] a {
    position: relative;
  }
}

/* ── 8. composer 行内控件：命中区 44px（第 2 步）─────────────────────────
   实测（390×844，/tmp/probe-composer.py）：输入行 7 个控件可见高只有
   20–26px，全部低于 44px 触摸指引 —— 而这一行是手机上用得最多的区域
   （+ 附加上下文 / 切模型 / 思考强度 / 麦克风 / 语音会话 / 引擎）。最窄的
   只有 14px（状态栈里的图标按钮）。

   为什么敢用「纵向 ::after 扩展」而不是抬高整行：
   实测几何给出了余量 —— 控件垂心约 y=792，扩到 44px 即 770→814，
   正好落在状态栈底边（771）与本行底边（814）之间；也就是说：
     · 向上侵入 1px（可忽略），不会碰到状态栈里的按钮（那行在 y≈734–740）
     · 向下正好到 composer 底边 814，不会碰到状态条（起点 814）
   横向完全不动 → 相邻控件之间没有重叠可能（这是 titlebar 与状态条已经在用的
   同一套手法，见 §6 / §7 的注释）。

   ⚠️ 只作用于 composer 内部；条件只按「粗指针」（iPad 是宽屏触摸设备，
   原先的窄屏条件会漏掉它），桌面鼠标 pointer: fine 不受影响。 */
@media (pointer: coarse) {
  [data-slot='composer-root'] button,
  [data-slot='composer-root'] a {
    position: relative;
  }

  [data-slot='composer-root'] button::after,
  [data-slot='composer-root'] a::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 44px;
    transform: translateY(-50%);
  }
}

/* ── 9. composer 状态栈的开合把手：命中区 44px ─────────────────────────────
   实测：`[data-slot='status-drawer-toggle']` 可见高 16px（`size="grip"` 的
   细条），远低于 44px 触摸指引，而它是输入区上方唯一的开合入口（点不中 =
   状态栈打不开）。
   它与 titlebar 同类：纵向无竞争控件（上方是消息流、下方是状态栈本体），
   所以复用同一手法纵向扩到 44px，横向不动。
   条件同 §6：只按粗指针，让 iPad 也拿到（详见 §6 的说明）。 */
@media (pointer: coarse) {
  /* `!important` 是必须的：app.css 里有一条基座规则把按钮压成
     position:relative（在流内），此处无 !important 时级联输给它 ——
     于是 h-4 的把手按钮撑出一行 ~19px 的行盒，把输入框表面从状态栈
     下方顶开（真机表现为「后台任务卡片与输入框之间的空隙」，
     2026-10-09 再现器已复现并验证修复）。 */
  [data-slot='status-drawer-toggle'] {
    position: absolute !important;
  }

  [data-slot='status-drawer-toggle']::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    width: 44px;
    height: 44px;
    transform: translate(-50%, -50%);
  }
}

/* ══════════════════════════════════════════════════════════════════════
   §10 覆盖层卡片（设置 / 指令中心 / 智能体等）：手机几何
   ──────────────────────────────────────────────────────────────────────
   上游 OverlayView 用「桌面窗控让位」四边等距（--titlebar-height + 0.625rem
   ≈ 44px 一边）把卡片悬在窗口中央。手机上：
     · 顶部 44px < 状态栏/灵动岛（~59pt）→ 卡片顶行（关闭 × 与操作按钮）
       钻进系统死区，**点不到**；
     · 底部同样留 44px + 视口其下的系统带 → 下方一大片空，白丢展示面积。
   手机没有桌面窗控可让：顶部改为清状态栏（保留 titlebar 项作桌面窄窗兜底），
   底部只留薄呼吸（即使环境报告了 safe-bottom，视口本身通常已让开系统区，
   这里再减去 1.5rem 上限）。桌面（非窄触摸）不受影响 —— 媒体条件同 §6/§7。 */
@media (max-width: 767.98px) and (pointer: coarse) {
  [data-overlay-surface] {
    padding-top: max(calc(var(--titlebar-height) + 0.625rem), calc(env(safe-area-inset-top) + 1rem), 4.5rem) !important;
    padding-right: max(0.5rem, env(safe-area-inset-right)) !important;
    padding-bottom: max(0.5rem, calc(env(safe-area-inset-bottom) - 1.5rem)) !important;
    padding-left: max(0.5rem, env(safe-area-inset-left)) !important;
  }
}

/* ══════════════════════════════════════════════════════════════════════
   §11 composer 贴上底部状态条
   ──────────────────────────────────────────────────────────────────────
   实测（420×912 / 真机截图 2026-10-09）：输入框底到状态条顶悬空 ~70pt，
   来自三层叠加：上游 inline `margin-bottom: env(safe-bottom)`（34）+ 本节
   §5 的 `padding-bottom: env(safe-bottom)`（34）+ dock 壳底垫 0.625rem。
   状态条在场时由它承担底部语义 —— 三层清零、留 4px 薄缝；状态条被隐藏时
   维持原让位（规则不生效）。 */
@media (max-width: 767.98px) and (pointer: coarse) {
  body:has([data-slot='statusbar']) [data-slot='composer-root'] {
    margin-bottom: 0 !important; /* 抵消上游 inline env() margin */
    padding-bottom: 0;           /* 抵消 §5 的 env() padding */
  }

  body:has([data-slot='statusbar']) [data-slot='composer-dock'] {
    padding-bottom: 0.25rem;     /* 原 0.625rem 壳底垫 → 薄贴 */
  }
}

/* ══════════════════════════════════════════════════════════════════════
   §12 浮动 HUD（命令面板 / 会话切换器）：手机上清状态栏
   ──────────────────────────────────────────────────────────────────────
   两者的窄屏定位 = `top: calc(var(--titlebar-height,34px) + 0.375rem)`，
   portal 到 body 后 --titlebar-height 取 fallback → 顶部 ≈ 40pt，
   **钻进状态栏区**（真机反馈：点开搜索面板"撑到顶"）。
   手机改为：安全区 + 硬下限 4.5rem（不依赖 env() 是否生效 —— 真机疑似
   env(safe-area-inset-top) 解析为 0，安全区项不可信）。硬下限按 110%
   档位 ≈ 79pt，清过状态栏并留出药丸骑线空间；100% 档 ≈ 72pt。
   仅窄屏 + 粗指针生效，桌面不受影响。 */
@media (max-width: 767.98px) and (pointer: coarse) {
  [data-slot='command-palette'],
  [data-slot='session-switcher'] {
    top: max(calc(env(safe-area-inset-top) + 0.5rem), 4.5rem) !important;
  }
}
