/* 全局基础。最外层这一串容器统一用 100vh,不许混 100% / dvh,见 CLAUDE.md */

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0;
  padding: 0;
  height: 100vh;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  font-family: var(--font);
  font-size: var(--fs-15);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

#app { height: 100vh; }

button, input, textarea, select {
  font: inherit;
  color: inherit;
  margin: 0;
}

button { background: none; border: none; padding: 0; cursor: pointer; }

input, textarea {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-3);
  outline: none;
  width: 100%;
}
input:focus, textarea:focus { border-color: var(--accent); }
textarea { resize: vertical; line-height: 1.6; }

img { max-width: 100%; display: block; }
svg { display: block; flex: none; }

/* ---- 外壳。和 html / body / #app 一样是 100vh，一个都不能换成别的写法。
       只要有一层用了 100% 或量出来的像素值，它就只撑到 WebKit 认为的可视区，
       撑不到屏幕底部，底下那条会被 iOS 拿页面底色填掉。见 CLAUDE.md ---- */
.root {
  height: 100vh;
  /* 高度仍然是整屏。上下两头各让出一点，让内容避开刘海和地址栏，
     壁纸是 fixed 的，照样铺到屏幕边。
     顶部这条必须写在 .root 上：状态栏在触摸设备上是隐藏的，
     写在 .statusbar 里的话一隐藏，内容就钻到系统状态栏底下去了。 */
  padding-top: var(--safe-top);
  padding-bottom: var(--bottom-lift);
  display: flex;
  flex-direction: column;
  background: var(--bg);
  position: relative;
  overflow: hidden;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --top-inset: 0px;
  /* 浏览器报的顶部安全区原值，下面清零 --safe-top 之后状态栏还要用它 */
  --cutout-top: env(safe-area-inset-top, 0px);
}
/* 网页自己不画状态栏的时候（iOS、手机浏览器），顶上刘海那一条不在 .root 上统一让，
   交给里面各层自己让（--top-inset，见 shell.css）：这样 app 页面的顶栏底色
   能一直铺到屏幕顶边、垫在系统状态栏底下，只有顶栏里的字和按钮落在安全区以下。
   统一让的话，那一条永远是 .root 的底色，和顶栏颜色接不上。
   画了状态栏的（安卓安装包）照旧由 .root 让，状态栏本身就在那一条下面。 */
.root:not(:has(> .statusbar)) { padding-top: 0; --top-inset: var(--safe-top); }
/* 浏览器标签页里的全屏（system/fullscreen.js）：系统状态栏和导航条都藏起来了，
   网页自己画状态栏，从屏幕顶边开始，上下都不再让。
   不照 env() 让：安卓 Chrome 全屏时从顶上划一下，系统状态栏会临时滑出来，
   它报上来的安全区跟着变成状态栏的高度，状态栏收回去之后却不改回来 ——
   顶上就一直空着一条状态栏那么高的空白。挖孔摄像头那一行正好是自己画的状态栏，
   和真机的状态栏同一个位置。 */
:root[data-browser-full] .root { --safe-top: 0px; --safe-bottom: 0px; }
/* 自己画的那条状态栏至少和真的一样高。安卓全屏时浏览器报的顶部安全区就是
   系统状态栏（摄像头那一行）的高度，常见 40 多像素；只画 26 的话，时间和电量
   挤在那一行的上半截，下面的页面顶到摄像头上 */
:root[data-browser-full] .statusbar { height: max(var(--statusbar-h), var(--cutout-top)); }

.scroll {
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
.scroll::-webkit-scrollbar { width: 0; height: 0; }

.ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.press { transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease); }
.press:active { opacity: .6; transform: scale(.97); }

@keyframes spin { to { transform: rotate(360deg); } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes slide-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes slide-in { from { transform: translateX(100%); } to { transform: translateX(0); } }
@keyframes jiggle {
  0%, 100% { transform: rotate(-.7deg); }
  50%      { transform: rotate(.7deg); }
}
