/* 全局基础。最外层这一串容器统一用 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;
  /* 不带空格的一长串（英文名下划线连写、链接、外卖名、数字）放不下时在哪儿都能断行，不顶出屏幕（4.c158-10）。
     只在一个词整行都放不下时才断，平常的排版不变；中文本来就能在字与字之间断，不受影响。
     一行到底带省略号的（white-space: nowrap）照旧是省略号。
     用 break-word 不用 anywhere：anywhere 会让「按内容定宽」的盒子也算成能缩到一个字宽，
     主屏 2x1 时钟的「08:53」就被拆成两行顶出卡片（wgfit 抓到）；break-word 不改盒子怎么定宽 */
  overflow-wrap: break-word;
}

#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); }
/* 日期、时间输入框（4.826，用户：记账最下面的时间，框太长了）。iOS 按里面的文字给它定了最小宽度，
   宽度写 100% 也照样撑出容器，窄屏上超出页面右边。去掉系统外观、允许缩到容器宽度，文字靠左；
   去掉外观之后空着时会塌成一条，高度对齐普通输入框 */
input[type="date"], input[type="datetime-local"], input[type="time"], input[type="month"] {
  -webkit-appearance: none; appearance: none;
  display: block; min-width: 0; max-width: 100%;
  min-height: calc(1.5em + var(--sp-2) * 2 + 2px);
  text-align: left;
}
input[type="date"]::-webkit-date-and-time-value,
input[type="datetime-local"]::-webkit-date-and-time-value,
input[type="time"]::-webkit-date-and-time-value,
input[type="month"]::-webkit-date-and-time-value { text-align: left; margin: 0; }
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; }
/* 浏览器全屏时也没有地址栏，「底部边距」不抬（4.712，system/look.js 的 noAddressBar 管另外两种） */
:root[data-browser-full] .root { padding-bottom: 0; }
/* 触屏设备上正在输入（system/viewport.js 挂 data-kb）：屏幕键盘盖住了 Home 横条那一截，
   底部不再留它，输入框贴着键盘（4.393） */
:root[data-kb] .root { --safe-bottom: 0px; }
/* 「返回方式」选了底部横条（4.714）：横条不再在 .root 最下面另占一排，浮在底部安全区上，和系统的 Home 横条一样。
   用户截图：多选栏、录音栏下面空一截露出壁纸 —— 页面底栏已经让过一次安全区，横条又在它下面占了一排 22px。
   底部安全区至少留出横条那么高（没有 Home 横条的设备、浏览器全屏），各层底栏的底色一直铺到屏幕底，横条画在它上面。
   正在输入时（data-kb）照旧清零，横条收起 */
:root[data-nav="bar"]:not([data-kb]) .root { --safe-bottom: max(env(safe-area-inset-bottom, 0px), 22px); }
:root[data-nav="bar"][data-browser-full]:not([data-kb]) .root { --safe-bottom: 22px; }
/* 自己画的那条状态栏至少和真的一样高。安卓全屏时浏览器报的顶部安全区就是
   系统状态栏（摄像头那一行）的高度，常见 40 多像素；只画 26 的话，时间和电量
   挤在那一行的上半截，下面的页面顶到摄像头上 */
:root[data-browser-full] .statusbar { height: max(var(--statusbar-h), var(--cutout-top)); }

/* 不全屏（设置 - 外观 - 全屏显示，system/fullscreen.js 的 applyWindowed）。
   手机上：内容从系统状态栏下面开始，那一条由 .root 统一让出来、垫一块底色，
   壁纸也从它下面开始。不再交给各层自己让（--top-inset 清零）。
   高度照旧是 100vh，只是顶上让一条，这一串容器的规矩不变（CLAUDE.md 第 1 条）。 */
:root[data-windowed] .root { padding-top: var(--safe-top); --top-inset: 0px; }
:root[data-windowed] .root::before {
  content: ''; position: absolute; left: 0; right: 0; top: 0; z-index: 60;
  height: var(--safe-top); background: var(--bg); pointer-events: none;
}
:root[data-windowed="dark"] .root::before { background: var(--status-band); }
:root[data-windowed] .wallpaper { top: var(--safe-top); }
/* 电脑、平板的宽屏：手机宽度居中。不画机身、刘海、投影（CLAUDE.md 第 3 条），只有两条细边。
   transform 让里面 position: fixed 的东西（壁纸、底部浮层）以这一栏为准，不铺到两侧留白上 */
@media (min-width: 600px) {
  :root[data-windowed] body { background: var(--surface-3); }
  :root[data-windowed] .root {
    max-width: 430px; margin: 0 auto; transform: translateZ(0);
    border-left: 1px solid var(--border); border-right: 1px solid var(--border);
  }
}
/* 自己定了窗口大小（外观里「全屏显示」关掉之后的宽度与高度）：中间那一块按设定的大小居中，
   超出屏幕就收到屏幕以内。外壳那一串（html、body、#app）仍然是 100vh，
   只有 .root 这一块变小 —— 它底下露出来的是有意留的底色，不是 iOS 填的那条白边。
   窗口不贴屏幕边，刘海与 Home Indicator 由 #app 让开，里面的安全区清零 */
:root[data-winsize] body { background: var(--surface-3); }
:root[data-winsize] #app {
  display: flex; align-items: center; justify-content: center;
  padding: env(safe-area-inset-top, 0px) 0 env(safe-area-inset-bottom, 0px);
}
:root[data-winsize] .root {
  width: var(--win-w); max-width: 100%;
  height: var(--win-h); max-height: 100%;
  margin: 0; transform: translateZ(0);
  border: 1px solid var(--border);
  padding-top: 0; --safe-top: 0px; --safe-bottom: 0px; --top-inset: 0px;
}
:root[data-winsize] .root::before { display: none; }
/* 填得比屏幕大、收到铺满的那一边不画细边，否则贴着屏幕边露一条浅线（4.572，system/fullscreen.js 的 fitEdges） */
:root[data-winsize][data-win-fill-x] .root { border-left-width: 0; border-right-width: 0; }
:root[data-winsize][data-win-fill-y] .root { border-top-width: 0; border-bottom-width: 0; }
:root[data-winsize] .wallpaper { top: 0; }

.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); }
}
