/* =========================================================
   观岚 glance · 视觉系统
   ---------------------------------------------------------
   设计语言：Apple HIG 的「中性画布 + 白色材质 + 克制动效」。
   画布始终是中性灰，内容以白色材质纸片承载，层级只靠
   「阴影 + 圆角 + 留白」区分，不靠描边和色块堆叠。

   规范速查
   · 颜色     画布 --bg；材质 --surface；正文 --ink；次要 --muted
   · 圆角     --r-1 8 / --r-2 12 / --r-3 16 / --r-4 20 / --r-5 26 / pill
   · 阴影     --shadow-1 贴地 / -2 材质 / -3 浮层 / -4 模态
   · 字阶     44 / 34 / 26 / 20 / 17 / 15 / 13 / 11.5（逐级 -0.01em 字距）
   · 间距     4 的倍数，区块间 24 / 32 / 56
   · 动效     位移 ≤ 24px，160–620ms，缓动统一走 --ease-out / --ease-apple
   ========================================================= */

:root {
  /* 画布与材质 */
  --bg: #f5f5f7;
  --bg-blur: rgba(245, 245, 247, 0.72);
  --surface: #ffffff;
  --surface-2: #fbfbfd;
  --fill-1: rgba(118, 118, 128, 0.08);
  --fill-2: rgba(118, 118, 128, 0.12);
  --fill-3: rgba(118, 118, 128, 0.18);

  /* 文字 */
  --ink: #1d1d1f;
  --ink-2: #3a3a3c;
  --muted: #6e6e73;
  --muted-2: #86868b;
  --on-dark: #fbfbfd;

  /* 描边与分隔 */
  --line: rgba(0, 0, 0, 0.075);
  --line-2: rgba(0, 0, 0, 0.14);
  --line-3: rgba(0, 0, 0, 0.24);

  /* 语义色 */
  --danger: #d70015;
  --danger-bg: rgba(215, 0, 21, 0.06);
  --bubble-in: #e9e9eb;

  /* 圆角 */
  --r-1: 8px;
  --r-2: 12px;
  --r-3: 16px;
  --r-4: 20px;
  --r-5: 26px;
  --r-pill: 999px;

  /* 阴影 */
  --shadow-1: 0 0 0 0.5px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.04);
  --shadow-2: 0 0 0 0.5px rgba(0, 0, 0, 0.04), 0 2px 8px rgba(0, 0, 0, 0.05);
  --shadow-3: 0 0 0 0.5px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.08);
  --shadow-4: 0 0 0 0.5px rgba(0, 0, 0, 0.06), 0 24px 64px rgba(0, 0, 0, 0.13);

  /* 字体 */
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Segoe UI Variable Text", "Segoe UI", "PingFang SC", "HarmonyOS Sans SC", "MiSans", "Microsoft YaHei UI", "Microsoft YaHei", system-ui, sans-serif;
  --mono: "SF Mono", ui-monospace, "SFMono-Regular", "Cascadia Mono", "Cascadia Code", Consolas, "Liberation Mono", monospace;

  /* 动效 */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-apple: cubic-bezier(0.28, 0.8, 0.2, 1);
  --dur-1: 160ms;
  --dur-2: 260ms;
  --dur-3: 420ms;
  --dur-4: 620ms;

  /* 版心 */
  --shell-w: min(1180px, 100% - clamp(32px, 8vw, 96px));
  --topbar-h: 60px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* 锚点 / scrollIntoView 不要被吸顶导航压住 */
  scroll-padding-top: calc(var(--topbar-h) + 20px);
}

body {
  margin: 0;
  min-width: 320px;
  overflow-x: clip;
  min-height: 100vh;
  color: var(--ink);
  background: var(--bg);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  letter-spacing: 0.002em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "kern" 1;
}

[hidden] {
  display: none !important;
}

h1,
h2,
h3,
p,
pre {
  margin: 0;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button {
  padding: 0;
  cursor: pointer;
  background: none;
  border: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

img,
svg {
  display: block;
  max-width: 100%;
}

code,
pre {
  font-family: var(--mono);
}

::selection {
  color: #fff;
  background: var(--ink);
}

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ------------------------------ 工具类 ------------------------------ */

.skip-link {
  position: fixed;
  top: 10px;
  left: 10px;
  z-index: 60;
  padding: 10px 16px;
  color: #fff;
  font-size: 13px;
  background: var(--ink);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-3);
  transform: translateY(-180%);
  transition: transform var(--dur-2) var(--ease-out);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

/* 仅供读屏的文本：视觉上隐藏，仍保留在可访问性树里 */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  white-space: nowrap;
  border: 0;
  clip-path: inset(50%);
}

/* ------------------------------ 外壳 / 顶栏 ------------------------------ */

.shell {
  position: relative;
  display: flex;
  flex-direction: column;
  width: var(--shell-w);
  min-height: 100vh;
  margin: 0 auto;
}

/* 吸顶毛玻璃导航：本体仍按版心排布，材质由伪元素铺满整条视口 */
.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  flex: 0 0 auto;
  height: var(--topbar-h);
  background: transparent;
}

.topbar::before {
  position: absolute;
  inset: 0;
  margin-inline: calc(50% - 50vw);
  background: var(--bg-blur);
  border-bottom: 1px solid transparent;
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  content: "";
  transition: border-color var(--dur-2) var(--ease), background var(--dur-2) var(--ease);
}

.topbar.is-scrolled::before {
  border-bottom-color: rgba(0, 0, 0, 0.1);
}

.topbar__inner {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  height: 100%;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 4px 2px;
  border-radius: var(--r-2);
  transition: opacity var(--dur-1) var(--ease);
}

.brand:hover {
  opacity: 0.62;
}

.brand__mark {
  display: grid;
  width: 26px;
  height: 26px;
  color: var(--ink);
  place-items: center;
}

.brand__mark svg {
  width: 24px;
  height: 24px;
}

.brand__text {
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.01em;
}

.brand__text b {
  font-weight: 650;
  letter-spacing: 0.04em;
}

.topbar__user {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

/* 顶栏的安装包入口：一颗低调的胶囊，不抢品牌与账号的位置 */
.topbar__get {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 13px;
  color: var(--ink-2);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.01em;
  text-decoration: none;
  white-space: nowrap;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-1);
  transition: transform var(--dur-2) var(--ease-out), box-shadow var(--dur-2) var(--ease),
    border-color var(--dur-2) var(--ease);
}

.topbar__get svg {
  width: 15px;
  height: 15px;
}

.topbar__get:hover {
  border-color: var(--line-2);
  box-shadow: var(--shadow-2);
  transform: translateY(-1px);
}

.topbar__get:active {
  transform: translateY(0) scale(0.985);
}

@media (max-width: 560px) {
  .topbar__get span {
    display: none;
  }

  .topbar__get {
    padding: 7px;
    border-radius: 50%;
  }
}

.who {
  max-width: 34vw;
  overflow: hidden;
  color: var(--muted);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.avatar {
  display: grid;
  width: 28px;
  height: 28px;
  color: var(--on-dark);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  background: linear-gradient(180deg, #3a3a3c, #1d1d1f);
  border-radius: 50%;
  box-shadow: var(--shadow-1);
  place-items: center;
}

/* ------------------------------ 启动页 ------------------------------ */

.boot {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 22px;
  padding: 24px;
  text-align: center;
  background: var(--bg);
  transition: opacity 260ms var(--ease);
}

.boot__mark svg {
  width: 54px;
  height: 27px;
  color: var(--ink);
}

.boot__text {
  max-width: 32em;
  color: var(--muted);
  font-size: 13.5px;
  letter-spacing: 0.01em;
}

/* 细线进度条：只表达「正在进行」，不预报进度 */
.boot::after {
  width: 108px;
  height: 2px;
  overflow: hidden;
  background: var(--fill-2);
  border-radius: var(--r-pill);
  content: "";
  animation: boot-track 1.9s var(--ease) infinite;
}

.boot.is-error::after {
  display: none;
}

.boot.is-error .boot__mark svg {
  color: var(--danger);
}

.boot.is-error .boot__text {
  color: var(--danger);
  font-size: 13.5px;
  line-height: 1.75;
}

.boot.is-error .btn {
  margin-top: 4px;
}

.boot.is-leaving {
  opacity: 0;
  pointer-events: none;
}

/* ------------------------------ 登录页 ------------------------------ */

.auth {
  position: relative;
  z-index: 2;
  display: grid;
  flex: 1 1 auto;
  grid-template-columns: minmax(0, 1fr) minmax(0, 404px);
  gap: clamp(32px, 6vw, 88px);
  align-items: center;
  padding: clamp(32px, 7vh, 88px) 0 clamp(40px, 8vh, 96px);
}

.auth__intro {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 22px;
  min-width: 0;
}

.card {
  position: relative;
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 30px;
  background: var(--surface);
  border-radius: var(--r-5);
  box-shadow: var(--shadow-4);
}

.card__title {
  font-size: 26px;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.24;
}

/* 分段控件：灰底轨道 + 白色浮起的选中块 */
.tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px;
  padding: 3px;
  background: var(--fill-1);
  border-radius: var(--r-2);
}

.tabs__btn {
  position: relative;
  padding: 8px 0;
  color: var(--muted);
  font-size: 13.5px;
  font-weight: 500;
  white-space: nowrap;
  border-radius: var(--r-1);
  transition: color var(--dur-1) var(--ease), background var(--dur-2) var(--ease-out),
    box-shadow var(--dur-2) var(--ease-out);
}

.tabs__btn:hover {
  color: var(--ink-2);
}

.tabs__btn.is-active {
  color: var(--ink);
  font-weight: 600;
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08), 0 0 0 0.5px rgba(0, 0, 0, 0.04);
}

/* ------------------------------ 表单 ------------------------------ */

.form {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.field label {
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.01em;
}

.field > input,
.input > input,
.field > select {
  width: 100%;
  height: 48px;
  padding: 0 15px;
  color: var(--ink);
  font-size: 15px;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--r-2);
  outline: none;
  appearance: none;
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-2) var(--ease-out),
    background var(--dur-1) var(--ease);
}

.field > select {
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.75 6 6.75 11 1.75' fill='none' stroke='%236e6e73' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 15px center;
  background-size: 11px 7px;
  padding-right: 40px;
}

.field > input::placeholder,
.input > input::placeholder,
.field > textarea::placeholder {
  color: var(--muted-2);
}

.field > input:hover,
.input > input:hover,
.field > select:hover,
.field > textarea:hover {
  border-color: var(--line-3);
}

.field > input:focus,
.input > input:focus,
.field > select:focus,
.field > textarea:focus {
  border-color: var(--ink);
  box-shadow: 0 0 0 4px rgba(29, 29, 31, 0.07);
}

.field > input[aria-invalid="true"],
.input > input[aria-invalid="true"] {
  border-color: var(--danger);
  box-shadow: 0 0 0 4px rgba(215, 0, 21, 0.08);
}

/* 数字 / 口令类输入用等宽数字，避免跳动 */
input[type="tel"] {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

.input {
  position: relative;
  display: block;
}

.input > input {
  padding-right: 46px;
}

/* Edge 会在密码框右侧自带一个「显示密码」眼睛，和下面的按钮重复，隐藏掉 */
input[type="password"]::-ms-reveal,
input[type="password"]::-ms-clear {
  display: none;
}

.input[data-prefix] > input {
  padding-left: 54px;
}

.input[data-prefix="WIFI"] > input {
  padding-left: 64px;
}

.input[data-prefix]::before {
  position: absolute;
  top: 50%;
  left: 15px;
  color: var(--muted-2);
  font-family: var(--mono);
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.1em;
  content: attr(data-prefix);
  transform: translateY(-50%);
  pointer-events: none;
}

.reveal {
  position: absolute;
  top: 50%;
  right: 6px;
  display: grid;
  width: 34px;
  height: 34px;
  color: var(--muted-2);
  border-radius: var(--r-1);
  place-items: center;
  transform: translateY(-50%);
  transition: color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}

.reveal:hover {
  color: var(--ink);
  background: var(--fill-1);
}

.reveal svg {
  width: 17px;
  height: 17px;
}

.i-eye-off {
  display: none;
}

.reveal[aria-pressed="true"] .i-eye {
  display: none;
}

.reveal[aria-pressed="true"] .i-eye-off {
  display: block;
}

.error {
  padding: 10px 14px;
  color: var(--danger);
  font-size: 12.5px;
  line-height: 1.6;
  background: var(--danger-bg);
  border-radius: var(--r-2);
}

/* ------------------------------ 按钮 ------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 20px;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  transform: translateY(0);
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
    border-color var(--dur-1) var(--ease), opacity var(--dur-1) var(--ease),
    transform var(--dur-2) var(--ease-out), box-shadow var(--dur-2) var(--ease-out);
}

.btn:disabled {
  cursor: wait;
  opacity: 0.55;
}

.btn--primary {
  color: var(--on-dark);
  background: var(--ink);
  border-color: var(--ink);
  box-shadow: var(--shadow-1);
}

.btn--primary:hover:not(:disabled) {
  background: #333336;
  box-shadow: 0 6px 18px rgba(29, 29, 31, 0.18);
}

.btn--outline {
  color: var(--ink);
  background: var(--surface);
  border-color: var(--line-2);
}

.btn--outline:hover:not(:disabled) {
  border-color: var(--line-3);
  box-shadow: var(--shadow-1);
}

.btn--ghost {
  color: var(--ink-2);
  background: transparent;
}

.btn--ghost:hover:not(:disabled) {
  color: var(--ink);
  background: var(--fill-1);
}

.btn--sm {
  min-height: 34px;
  padding: 0 14px;
  font-size: 13px;
}

.btn--block {
  width: 100%;
}

/* 按压反馈：所有按钮统一回弹，这是苹果交互最容易被感知的一处 */
.btn:active:not(:disabled) {
  transform: scale(0.972);
  transition-duration: 90ms;
}

.spinner {
  display: none;
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  opacity: 0.85;
  animation: spin 720ms linear infinite;
}

.btn.is-loading .spinner {
  display: block;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* ------------------------------ 工作台骨架 ------------------------------ */

.app {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 28px;
  padding: 40px 0 72px;
}

.app__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
}

.app__head h1 {
  /* 标题不参与压缩：否则窄屏下会被页签挤到一列一字（「对」/「话」竖排）。 */
  flex: 0 0 auto;
  font-size: clamp(1.75rem, 2.4vw, 2.125rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.12;
}

/* 页签：比登录页的分段控件更宽，选中态同样是浮起的白块。
   这里是五个页面（设备/对话/文件/天气/配置），列数必须跟 HTML 对齐，
   否则第五个会掉到第二行，把页头撑成两层。 */
.tabs--page {
  grid-template-columns: repeat(5, 1fr);
  width: min(500px, 100%);
  flex: 0 0 auto;
}

.workspace {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 404px);
  grid-template-areas:
    "form result";
  gap: 20px;
  /* 左右两张卡片取同一高度：左边表单短时把「生成/清空」推到底部，
     和右边二维码卡片的底边对齐，页面看起来才是齐的。 */
  align-items: stretch;
}

.workspace > #qr-form {
  grid-area: form;
  height: 100%;
}

.workspace > #qr-form .actions {
  margin-top: auto;
}

.workspace > #result-panel {
  grid-area: result;
  position: sticky;
  top: calc(var(--topbar-h) + 20px);
  align-self: start;
}

/* 手机客户端卡片：只在 App 壳里出现，独占一整行（不挤占表单与二维码的位置）。 */
.workspace > #client-panel {
  grid-column: 1 / -1;
}

/* 页面级纸片：白材质 + 大圆角 + 贴地阴影，全靠阴影分层，不画描边 */
.panel {
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 26px;
  background: var(--surface);
  border-radius: var(--r-4);
  box-shadow: var(--shadow-2);
}

/* 多张纸片并排的页面（文件页）：左写右看，窄屏自动叠成一列 */
.page--stack {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 20px;
  align-items: start;
}

/* 天气页只有一张卡片：不沿用文件页的两栏，否则桌面右半边会空着。 */
#page-weather {
  grid-template-columns: minmax(0, 1fr);
}

/* 天气抬头：温度是主角（和眼镜端 26px 的版式一致），现象与城市在右侧 */
.weather__head {
  display: flex;
  align-items: center;
  gap: 20px;
  margin: 4px 0 20px;
}

.weather__temp {
  margin: 0;
  font-size: 64px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.weather__side {
  min-width: 0;
}

.weather__text {
  margin: 0 0 6px;
  font-size: 20px;
  font-weight: 580;
}

.weather__advice {
  margin: 18px 0 0;
  padding: 12px 14px;
  border-radius: var(--r-2);
  background: color-mix(in srgb, currentColor 7%, transparent);
  font-size: 14px;
  line-height: 1.5;
}

/* ---------- 出行 / 穿衣推荐 ----------
   一级是两块预览卡片，二级是同一批数据的完整清单（`.tipgroup` + `.tiplist--full`）。
   卡片用 --surface-2 而不是再套一层白纸片：白纸上再放白纸片，边界只能靠阴影，
   在浅色主题里会糊成一块。 */

.tipcards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
  margin-top: 22px;
}

.tipcard {
  padding: 16px 18px;
  border-radius: var(--r-3);
  background: var(--surface-2);
  box-shadow: var(--shadow-1);
}

.tipcard__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.tipcard__title {
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.tipcard__outfit {
  margin: 0 0 6px;
  font-size: 17px;
  font-weight: 580;
  letter-spacing: -0.01em;
}

/* 标题列固定宽度：几行的"带伞 / 防晒"竖着对齐，正文才不会参差。
   和眼镜端"标题一列 + 正文一列"是同一个版式 —— 两边看的是同一份数据。 */
.tiplist {
  margin: 0;
  padding: 0;
  list-style: none;
}

.tiplist:empty {
  display: none;
}

.tiplist__item {
  display: flex;
  gap: 12px;
  padding: 5px 0;
  font-size: 14px;
  line-height: 1.55;
}

.tiplist__title {
  flex: 0 0 64px;
  color: var(--muted);
}

.tiplist__body {
  min-width: 0;
  color: var(--ink-2);
}

.tiplist--full .tiplist__item {
  padding: 8px 0;
  font-size: 15px;
}

.tiplist--full .tiplist__title {
  flex-basis: 76px;
  color: var(--ink);
  font-weight: 580;
}

.tipgroup {
  margin-top: 24px;
}

.tipgroup__title {
  margin-bottom: 8px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
}

.tipgroup__lead {
  margin: 0 0 6px;
  font-size: 20px;
  font-weight: 580;
  letter-spacing: -0.01em;
}

/* 一级整块包在 #weather-main 里（为了能整块被二级替掉），所以 .panel 的
   纵向 gap 传不下来 —— 这里复制一份，别让标题、读数、预报挤成一片。 */
#weather-main,
#weather-detail {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* 二级是"整块换掉"而不是弹窗：给一点位移，让人知道层级变了 */
#weather-detail {
  animation: weather-detail-in 220ms var(--ease-out) both;
}

@keyframes weather-detail-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  #weather-detail {
    animation: none;
  }
}

.panel__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.panel__head > div {
  min-width: 0;
}

.panel__head .status {
  margin-top: 4px;
  text-align: left;
}

.panel__title {
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.3;
}

.panel__sub {
  margin-top: 4px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}

.group {
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.group + .group {
  padding-top: 22px;
  border-top: 1px solid var(--line);
}

/* 分组标题走苹果的「小节标题」：小字号、灰、正体，不用大写等宽 */
.group__title {
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.actions {
  display: flex;
  gap: 10px;
  align-items: center;
}

.actions--wrap {
  flex-wrap: wrap;
}

/* 主按钮不再吃掉整行：成组出现时保持「一主一次」的轻重差 */
.actions .btn--primary {
  flex: 0 1 auto;
  min-width: 152px;
}

/* ------------------------------ 设备页 ------------------------------ */

.device {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 44px);
  align-items: center;
}

/* 产品图直接坐在纸片上：图片自带白底，不再套第二层底衬 */
.device__shot {
  display: grid;
  place-items: center;
}

.device__shot img {
  width: 100%;
  height: auto;
  border-radius: var(--r-2);
  object-fit: contain;
  mix-blend-mode: multiply;
}

/* 信息区按「分组列表」排：键左值右，行间一条发丝线 */
.device__info {
  display: flex;
  flex-direction: column;
}

.device__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  min-height: 54px;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
}

.device__row:first-child {
  padding-top: 0;
}

.device__row:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.device__key {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0.01em;
}

.device__key label {
  cursor: text;
}

.device__val {
  display: flex;
  min-width: 0;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  font-size: 14.5px;
  text-align: right;
}

.device__val b {
  font-weight: 560;
  letter-spacing: -0.005em;
  overflow-wrap: anywhere;
}

.device__val--input {
  display: block;
  flex: 0 1 220px;
}

/* 设备名：填色胶囊输入，聚焦才浮出描边，读起来像「可直接改的值」 */
.device__val--input input {
  width: 100%;
  height: 38px;
  padding: 0 13px;
  color: var(--ink);
  font-size: 14.5px;
  font-weight: 560;
  text-align: right;
  background: var(--fill-1);
  border: 1px solid transparent;
  border-radius: var(--r-2);
  outline: none;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
    box-shadow var(--dur-2) var(--ease-out);
}

.device__val--input input::placeholder {
  color: var(--muted-2);
  font-weight: 400;
}

.device__val--input input:hover {
  background: var(--fill-2);
}

.device__val--input input:focus {
  background: var(--surface);
  border-color: var(--ink);
  box-shadow: 0 0 0 4px rgba(29, 29, 31, 0.07);
}

.battery {
  position: relative;
  display: block;
  width: 40px;
  height: 18px;
  padding: 2px;
  border: 1.5px solid var(--ink-2);
  border-radius: 5px;
  opacity: 0.9;
}

.battery::after {
  position: absolute;
  top: 50%;
  right: -4px;
  width: 2.5px;
  height: 7px;
  background: var(--ink-2);
  border-radius: 0 2px 2px 0;
  content: "";
  transform: translateY(-50%);
}

.battery__fill {
  display: block;
  height: 100%;
  background: var(--ink);
  border-radius: 2px;
  transition: width 420ms var(--ease-out), background 300ms var(--ease);
}

.device__hint {
  color: var(--muted);
  font-size: 12.5px;
}

/* 登录页底部的 App 下载入口：不抢主按钮的视觉，但必须一眼能看见 */
.auth__download {
  margin-top: 28px;
  padding-top: 20px;
  border-top: 1px solid var(--line, rgba(0, 0, 0, 0.08));
}

.auth__download .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  text-decoration: none;
}

.auth__download-note {
  margin: 10px 0 0;
  text-align: center;
}

/* 设备页改成单列：信息卡在上、已配对设备卡在下（不沿用文件页的左右分栏） */
#page-device {
  grid-template-columns: minmax(0, 1fr);
}

.devicelist {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}

.devicelist__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-top: 1px solid var(--line-2);
}

.devicelist__item:first-child {
  padding-top: 0;
  border-top: 0;
}

.devicelist__item:last-child {
  padding-bottom: 0;
}

.devicelist__main {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.devicelist__name {
  font-size: 15px;
  font-weight: 600;
}

.devicelist__meta {
  color: var(--muted);
  font-size: 12.5px;
}

.devicelist__empty {
  color: var(--muted);
  font-size: 13.5px;
}

/* 配对码：等宽 + 拉开字距，用户要照着念、照着敲 */
.pairing {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px;
  background: var(--surface-2, #f5f4f1);
  border-radius: var(--r-3);
}

.pairing__title {
  margin: 0;
  color: var(--muted);
  font-size: 12.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.pairing__code {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: clamp(26px, 4vw, 34px);
  font-weight: 600;
  letter-spacing: 0.18em;
}

.pairing__hint {
  margin: 0;
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.6;
}

.pairing .actions {
  margin-top: 4px;
}

/* ------------------------- 配对弹层（二维码 + 配对码同屏） -------------------------
   生成凭据后自动弹出：左侧二维码、右侧 8 位码。
   动效两拍 —— 背板先压暗，面板上浮；面板落定后二维码（90ms）与码（170ms）
   依次淡入上移，眼睛先看到"有码了"，再分别落在扫码与输入两条路上。 */

.pairmodal {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(16px, 4vw, 40px);
}

.pairmodal__scrim {
  position: absolute;
  inset: 0;
  background: rgba(18, 18, 20, 0.38);
  -webkit-backdrop-filter: saturate(140%) blur(6px);
  backdrop-filter: saturate(140%) blur(6px);
  opacity: 0;
  transition: opacity var(--dur-3) var(--ease);
}

.pairmodal__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 20px;
  width: min(820px, 100%);
  max-height: calc(100vh - 2 * clamp(16px, 4vw, 40px));
  padding: clamp(22px, 3.4vw, 32px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface);
  border-radius: var(--r-5);
  box-shadow: var(--shadow-4);
  opacity: 0;
  transform: translateY(22px) scale(0.975);
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
}

.pairmodal.is-open .pairmodal__scrim {
  opacity: 1;
}

.pairmodal.is-open .pairmodal__panel {
  opacity: 1;
  transform: none;
}

.pairmodal__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.pairmodal__heading {
  min-width: 0;
}

.pairmodal__title {
  margin: 0;
  font-size: 24px;
  font-weight: 650;
  letter-spacing: -0.02em;
  line-height: 1.25;
}

.pairmodal__lead {
  margin: 6px 0 0;
  color: var(--muted);
  font-size: 13.5px;
  line-height: 1.6;
}

.pairmodal__close {
  display: grid;
  flex: none;
  width: 32px;
  height: 32px;
  padding: 0;
  color: var(--muted);
  cursor: pointer;
  background: var(--fill-1);
  border: 0;
  border-radius: 50%;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
    transform var(--dur-1) var(--ease);
  place-items: center;
}

.pairmodal__close svg {
  width: 18px;
  height: 18px;
}

.pairmodal__close:hover {
  color: var(--ink);
  background: var(--fill-2);
}

.pairmodal__close:active {
  transform: scale(0.94);
}

.pairmodal__body {
  display: grid;
  grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
  gap: clamp(18px, 3vw, 28px);
  align-items: start;
}

.pairmodal__qr {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0;
}

.pairmodal__qr-img {
  display: grid;
  padding: 16px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-4);
  box-shadow: var(--shadow-1);
  place-items: center;
}

.pairmodal__qr-img img {
  display: block;
  width: 100%;
  max-width: 288px;
  height: auto;
}

.pairmodal__qr figcaption {
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.55;
  text-align: center;
}

.pairmodal .pairing {
  align-self: center;
  padding: clamp(18px, 2.6vw, 24px);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-4);
}

.pairmodal .pairing__code {
  font-size: clamp(28px, 5vw, 38px);
  letter-spacing: 0.16em;
  overflow-wrap: anywhere;
}

.pairmodal__foot {
  margin: 0;
  color: var(--muted-2);
  font-size: 12.5px;
  line-height: 1.6;
}

/* 配对码没签出来的降级形态：只有二维码，居中放大 */
.pairmodal--qr-only .pairmodal__body {
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
}

/* 入场第二拍：内容块依次浮起（只在弹层里，静态页面上的 .pairing 不受影响） */
.pairmodal__qr,
.pairmodal .pairing {
  opacity: 0;
}

.pairmodal.is-open .pairmodal__qr {
  animation: pair-rise var(--dur-3) var(--ease-out) 90ms both;
}

.pairmodal.is-open .pairing {
  animation: pair-rise var(--dur-3) var(--ease-out) 170ms both;
}

@keyframes pair-rise {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.99);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* 弹层开着时锁住底下的页面滚动：否则滚轮会带着弹层一起滑走 */
body.modal-open {
  overflow: hidden;
}

@media (max-width: 720px) {
  .pairmodal {
    align-items: flex-end;
    padding: 12px;
  }

  .pairmodal__panel {
    max-height: calc(100vh - 24px);
    padding: 22px 20px 20px;
    border-radius: var(--r-5) var(--r-5) var(--r-4) var(--r-4);
    transform: translateY(28px);
  }

  .pairmodal__body {
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
  }

  .pairmodal__qr {
    align-items: center;
  }

  .pairmodal__qr-img {
    width: 100%;
    max-width: 300px;
  }

  .pairmodal__qr figcaption {
    text-align: center;
  }

  .pairmodal__title {
    font-size: 21px;
  }
}

/* ------------------------- 文本域（对话 / 备忘共用） ------------------------- */

textarea {
  font: inherit;
  color: inherit;
}

.field > textarea {
  width: 100%;
  min-height: 168px;
  padding: 14px 16px;
  font-size: 14.5px;
  line-height: 1.65;
  resize: vertical;
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-radius: var(--r-3);
  outline: none;
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-2) var(--ease-out);
}

/* ------------------------------ 对话页 ------------------------------ */

/* 消息区在发送栏上方：滚动只发生在消息区内部，最新一条贴着发送栏 */
.thread {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: min(50vh, 460px);
  padding: 4px 6px 20px 2px;
  overflow-y: auto;
  overscroll-behavior: contain;
  border-bottom: 1px solid var(--line);
  scrollbar-width: thin;
}

.thread:empty {
  display: none;
}

/* 对话页占满可用高度：整块纸片固定在视口内，消息区自己滚，输入区永远贴底。
   用 height 而不是 min-height：消息再多也只能让中间那块框滚动，不能把面板
   越撑越高、把输入框挤到屏幕下方。 */
#page-chat {
  height: min(680px, calc(100vh - 250px));
  height: min(680px, calc(100dvh - 250px));
  max-height: min(680px, calc(100dvh - 250px));
  min-height: 0;
  overflow: hidden;
}

/* 对话内容单独一个内嵌框：和发送栏之间有明确边界，滚动的也只有它 */
#page-chat .thread {
  flex: 1 1 0;
  min-height: 0;
  max-height: none;
  padding: 16px;
  background: var(--fill-1);
  border: 1px solid var(--line);
  border-radius: var(--r-3);
}

#page-chat .composer {
  flex: 0 0 auto;
}

.composer {
  margin-top: auto;
}

/* 输入区做成一体化的灰色圆角容器：文字、附件、动作都收在同一个「盒子」里，
   聚焦时整块变白并浮起，比给 textarea 单独描边更接近苹果的输入体验 */
.composer__box {
  display: flex;
  flex-direction: column;
  padding: 6px;
  background: var(--fill-1);
  border: 1px solid transparent;
  border-radius: var(--r-4);
  transition: background var(--dur-2) var(--ease-out), border-color var(--dur-1) var(--ease),
    box-shadow var(--dur-2) var(--ease-out);
}

.composer__box:focus-within {
  background: var(--surface-2);
  border-color: var(--line-2);
  box-shadow: var(--shadow-2);
}

.field--bare > textarea {
  min-height: 104px;
  padding: 12px 12px 4px;
  background: transparent;
  border: 0;
  border-radius: var(--r-3);
  resize: none;
}

.field--bare > textarea:hover,
.field--bare > textarea:focus {
  border-color: transparent;
  box-shadow: none;
}

.composer__box .chat__attach {
  padding: 8px 10px 2px;
}

.composer__box .error {
  margin: 6px 8px 0;
}

.actions--composer {
  justify-content: flex-end;
  margin-top: 6px;
  padding: 8px 4px 2px;
  border-top: 1px solid var(--line);
}

.actions--composer .btn--primary {
  flex: 0 0 auto;
  min-width: 92px;
}

/* 一条消息都没有时输入区沉到纸片底部，避免头部悬空 */
.thread:empty + .composer {
  margin-top: auto;
}

.bubble {
  max-width: min(80%, 560px);
  padding: 11px 16px;
  font-size: 14.5px;
  line-height: 1.65;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
  background: var(--bubble-in);
  border-radius: var(--r-4);
}

/* 气泡朝向的一角收紧成小圆角，是 iMessage 的经典细节 */
.bubble--ai {
  align-self: flex-start;
  border-bottom-left-radius: 6px;
}

.bubble--me {
  align-self: flex-end;
  color: var(--on-dark);
  background: var(--ink);
  border-bottom-right-radius: 6px;
}

.bubble__imgs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 8px;
}

.bubble__imgs img {
  width: 104px;
  height: 104px;
  object-fit: cover;
  background: var(--surface);
  border-radius: var(--r-2);
}

.bubble--me .bubble__imgs img {
  opacity: 0.96;
}

/* 流式回复：正文由增量逐段写入，末尾跟一根光标表示仍在生成；
   结束时 JS 移除 .bubble--streaming，光标随之消失 */
.bubble--streaming .bubble__caret {
  display: inline-block;
  width: 2px;
  height: 1em;
  margin-left: 2px;
  vertical-align: -0.16em;
  background: currentColor;
  border-radius: 1px;
  opacity: 0.7;
  animation: caret-blink 1.1s steps(1, end) infinite;
}

/* 这一轮 agent 实际做了什么（记了备忘 / 规划了路线 / 查了备忘）。
   只是让"它真的做了"可见 —— 不是按钮，没有 hover，也不可点：
   真要看结果，跳转与页面本身已经负责了。 */
.bubble__acts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 9px;
  white-space: normal;
}

.act-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px;
  font-size: 12px;
  line-height: 1.7;
  letter-spacing: 0;
  color: var(--muted);
  background: var(--surface);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-1);
}

.chat__attach {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.chat__attach:empty {
  display: none;
}

.chat__thumb {
  position: relative;
  width: 76px;
  height: 76px;
  padding: 0;
  overflow: hidden;
  background: var(--fill-1);
  border-radius: var(--r-2);
  transition: transform var(--dur-2) var(--ease-out);
}

.chat__thumb:hover {
  transform: scale(1.03);
}

.chat__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.chat__thumb::after {
  position: absolute;
  top: 5px;
  right: 8px;
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  content: "×";
}

/* ------------------------------ 结果 ------------------------------ */

.panel--result {
  min-height: 320px;
}

.status {
  color: var(--muted);
  font-size: 12px;
  letter-spacing: 0.01em;
  line-height: 1.55;
  text-align: left;
}

/* 结果纸片的角标贴着右上角 */
.panel--result > .status {
  text-align: right;
}

.status::before {
  display: inline-block;
  width: 5px;
  height: 5px;
  margin-right: 6px;
  background: currentColor;
  border-radius: 50%;
  content: "";
  opacity: 0.45;
  vertical-align: middle;
}

.status.is-busy::before {
  background: var(--ink);
  animation: pulse 900ms ease-in-out infinite;
}

.status.is-error {
  color: var(--danger);
}

@keyframes pulse {
  0%,
  100% {
    opacity: 0.25;
  }
  50% {
    opacity: 1;
  }
}

.empty {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 18px;
  align-items: center;
  justify-content: center;
  min-height: 260px;
  padding: 12px;
  text-align: center;
}

.empty__mark {
  color: var(--ink);
  opacity: 0.16;
}

.empty__mark svg {
  width: 56px;
  height: 56px;
}

.empty__hint {
  max-width: 20em;
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.6;
}

.result {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* 二维码底座：纯白 + 发丝描边，保证静默区不被阴影压灰 */
.result__qr {
  display: grid;
  padding: 18px;
  margin-bottom: 6px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-4);
  box-shadow: var(--shadow-1);
  place-items: center;
}

.result__qr img {
  width: 100%;
  /* 加密后数据帧变长（QR v18 左右），码更密，展示尺寸相应放大一档，
     保证每模块仍有约 3.4px，扫码端更容易识别。 */
  max-width: 336px;
  height: auto;
}

.result h3 {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

.meta {
  color: var(--muted);
  font-size: 13px;
  overflow-wrap: anywhere;
}

.meta b {
  color: var(--ink-2);
  font-weight: 600;
}

.meta .sep {
  margin: 0 6px;
  opacity: 0.6;
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 2px;
}

.tags span {
  max-width: 100%;
  overflow: hidden;
  padding: 3px 8px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.01em;
  text-overflow: ellipsis;
  white-space: nowrap;
  background: var(--fill-1);
  border-radius: 6px;
}

/* 校验和较长，允许换行完整显示 */
.tags span:last-child {
  white-space: normal;
  overflow-wrap: anywhere;
}

.frame {
  margin-top: 6px;
  border-top: 1px solid var(--line);
}

.frame summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 13px 0;
  color: var(--muted);
  font-size: 13px;
  cursor: pointer;
  list-style: none;
  transition: color var(--dur-1) var(--ease);
}

.frame summary::-webkit-details-marker {
  display: none;
}

.frame summary::after {
  font-size: 16px;
  line-height: 1;
  content: "+";
  transition: transform var(--dur-2) var(--ease-out);
}

.frame[open] summary::after {
  content: "−";
}

.frame summary:hover {
  color: var(--ink);
}

.frame__body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-bottom: 4px;
  animation: rise-in var(--dur-2) var(--ease-out) both;
}

.frame__mark code {
  color: var(--muted-2);
  font-size: 10px;
  overflow-wrap: anywhere;
}

.frame pre {
  max-height: 168px;
  overflow: auto;
  padding: 12px 14px;
  color: var(--ink-2);
  font-size: 11px;
  line-height: 1.7;
  background: var(--fill-1);
  border-radius: var(--r-2);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.copy-helper {
  position: fixed;
  top: 0;
  left: -9999px;
  opacity: 0;
}

.warn {
  color: var(--muted-2);
  font-size: 11.5px;
  line-height: 1.55;
  letter-spacing: 0.005em;
}

/* ------------------------------ 滚动条 ------------------------------
   Windows 的默认滚动条又宽又亮，压过界面本身；这里收成一条细灰线。 */

.thread::-webkit-scrollbar,
.frame pre::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

.thread::-webkit-scrollbar-track,
.frame pre::-webkit-scrollbar-track {
  background: transparent;
}

.thread::-webkit-scrollbar-thumb,
.frame pre::-webkit-scrollbar-thumb {
  background: var(--fill-3);
  background-clip: content-box;
  border: 3px solid transparent;
  border-radius: var(--r-pill);
}

.thread::-webkit-scrollbar-thumb:hover,
.frame pre::-webkit-scrollbar-thumb:hover {
  background: rgba(118, 118, 128, 0.32);
  background-clip: content-box;
}

/* ------------------------------ 提示条 ------------------------------ */

.toasts {
  position: fixed;
  right: 20px;
  bottom: calc(20px + env(safe-area-inset-bottom, 0px));
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  pointer-events: none;
}

.toast {
  max-width: min(360px, calc(100vw - 40px));
  padding: 11px 16px;
  color: #fff;
  font-size: 13px;
  line-height: 1.5;
  background: rgba(29, 29, 31, 0.9);
  border-radius: var(--r-3);
  box-shadow: var(--shadow-3);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  animation: toast-in var(--dur-3) var(--ease-out);
}

.toast.is-leaving {
  opacity: 0;
  transform: translateY(8px) scale(0.98);
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}

.toast--action {
  display: flex;
  align-items: center;
  gap: 12px;
  pointer-events: auto;
}

.toast__action {
  flex: none;
  padding: 3px 10px;
  color: #fff;
  font-size: 12px;
  line-height: 1.6;
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 999px;
  cursor: pointer;
  transition: background var(--dur-2) var(--ease);
}

.toast__action:hover {
  background: rgba(255, 255, 255, 0.28);
}

@keyframes toast-in {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.noscript {
  position: fixed;
  right: 16px;
  bottom: 16px;
  left: 16px;
  padding: 12px 16px;
  color: #fff;
  font-size: 13px;
  text-align: center;
  background: var(--ink);
  border-radius: var(--r-3);
}

/* =========================================================
   主视觉 · 手绘墨线单片镜
   主视觉是 static/img/hero-glasses.jpg（784×786），底色已按通道
   缩放到画布色 #f5f5f7，与页面无缝相接，因此不需要遮罩或边框。
   标语「匆匆，只为更好的遇见」直接画在镜片内，不再叠加文字层；
   h1 用 .sr-only 保留语义与朗读，视觉上由图片承载。
   .lens 用 aspect-ratio 锁住比例，宽度同时受 34rem 与 72vh 约束，
   避免高瘦屏下图片顶出视口。
   ========================================================= */

.lens {
  position: relative;
  width: 100%;
  max-width: min(100%, 34rem, 72vh);
  margin-inline: auto;
  aspect-ratio: 784 / 786;
  will-change: transform;
}

.lens__photo {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
  animation: rise-in 900ms var(--ease-out) both;
}

/* ------------------------------ 文件页（= 眼镜端备忘录） ------------------------------ */

.memo-hint {
  margin-top: -4px;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
}

.memo-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* 有内容时才画上面那条发丝线，空列表不留孤线 */
.memo-list:not(:empty) {
  border-top: 1px solid var(--line);
}

.memo-item {
  padding: 15px 2px;
  border-bottom: 1px solid var(--line);
  transition: background var(--dur-1) var(--ease);
}

.memo-item:last-child {
  border-bottom: 0;
}

.memo-item__head {
  display: flex;
  align-items: baseline;
  gap: 14px;
}

.memo-item__time {
  flex: 0 0 auto;
  min-width: 88px;
  color: var(--muted);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

.memo-item__title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  font-size: 15px;
  font-weight: 560;
  letter-spacing: -0.005em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.memo-item__meta {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
}

.memo-item__del {
  flex: 0 0 auto;
  align-self: center;
  padding: 4px 12px;
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  line-height: 1.5;
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
    background var(--dur-1) var(--ease), transform var(--dur-2) var(--ease-out);
}

.memo-item__del:hover,
.memo-item__del:focus-visible {
  color: var(--danger);
  background: var(--danger-bg);
  border-color: rgba(215, 0, 21, 0.28);
}

.memo-item__del:active {
  transform: scale(0.95);
}

.memo-item__preview {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  margin: 6px 0 0 102px;
  color: var(--muted);
  font-size: 13.5px;
  line-height: 1.6;
}

/* =========================================================
   动效
   位移 ≤ 24px，时长 160–620ms，统一 --ease-out / --ease-apple。
   入场一律「淡入 + 轻微上浮」，不用弹跳，避免廉价感。
   ========================================================= */

@keyframes view-in {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.992);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes page-in {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.996);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes rise-in {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.99);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes bubble-in {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes float-soft {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-6px);
  }
}

@keyframes boot-breathe {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.42;
  }
}

@keyframes boot-track {
  0% {
    transform: scaleX(0.1) translateX(0);
    opacity: 0.4;
  }
  50% {
    transform: scaleX(1) translateX(0);
    opacity: 1;
  }
  100% {
    transform: scaleX(0.1) translateX(0);
    opacity: 0.4;
  }
}

/* 流式回复末尾的光标：还在生成时闪动，收到结束事件后随气泡一起消失 */
@keyframes caret-blink {
  0%,
  49% {
    opacity: 0.75;
  }
  50%,
  100% {
    opacity: 0.15;
  }
}

/* 视图整体进入（登录页 / 工作台），[hidden] 移除时动画重新播放 */
#auth-view,
#app-view {
  animation: view-in var(--dur-4) var(--ease-out) both;
}

/* 页面 / 表单切换：设备·对话·文件·配置 与 登录·注册 */
[data-page-panel],
[data-auth-panel] {
  animation: page-in var(--dur-2) var(--ease-out) both;
}

/* 结果区显现：二维码连同文字轻快浮起 */
.result {
  animation: rise-in var(--dur-3) var(--ease-out) both;
}

/* 对话气泡逐条进入 */
.bubble {
  animation: bubble-in 300ms var(--ease-apple) both;
}

/* 空状态：极轻的悬浮呼吸，6s 一轮 */
.empty__mark {
  animation: float-soft 6s ease-in-out infinite;
}

/* 启动页标识呼吸 */
.boot__mark svg {
  animation: boot-breathe 1.8s ease-in-out infinite;
}

/* 页签：激活态轻微回弹 */
.tabs__btn.is-active {
  animation: tab-pop 260ms var(--ease-apple);
}

@keyframes tab-pop {
  from {
    transform: scale(0.96);
  }
  to {
    transform: scale(1);
  }
}

/* 卡片可点区域：轻抬 */
.device__shot img,
.result__qr {
  transition: transform var(--dur-3) var(--ease-out);
}

.device__shot:hover img {
  transform: scale(1.012);
}

/* ------------------------- 滚动进入（由 JS 挂 .rv / .is-in） -------------------------
   只有 JS 支持且用户没有要求减少动效时才会被加上 .rv，
   所以脚本失效、禁用 JS 时内容一定完整可见。 */

.rv {
  opacity: 0;
  transform: translateY(24px);
}

.rv.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 700ms var(--ease-out), transform 700ms var(--ease-out);
  transition-delay: calc(var(--rv-i, 0) * 70ms);
}

/* ------------------------------ 减少动态效果 ------------------------------ */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .toast {
    animation: none;
  }

  .btn:active:not(:disabled),
  .btn:hover:not(:disabled),
  .memo-item__del:active,
  .chat__thumb:hover {
    transform: none;
  }

  /* 滚动进入直接可见，不留空白 */
  .rv {
    opacity: 1;
    transform: none;
  }

  /* 功能性动画豁免：加载指示仍需可见地表达进行中状态 */
  .spinner,
  .status.is-busy::before {
    animation-duration: 900ms !important;
    animation-iteration-count: infinite !important;
  }

  /* 流式光标同理：不闪动，但始终可见 */
  .bubble--streaming .bubble__caret {
    animation: none;
    opacity: 0.7;
  }
}

/* ------------------------------ 响应式 ------------------------------ */

@media (max-width: 1080px) {
  .auth {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(24px, 5vh, 40px);
    padding: 24px 0 48px;
  }

  .auth__intro {
    gap: 16px;
  }

  .lens {
    max-width: min(100%, 27rem, 46vh);
  }

  .card {
    width: 100%;
    max-width: 440px;
    margin-inline: auto;
    padding: 26px;
  }

  /* 单列后收一下阅读宽度：键值行拉到整屏宽会显得空 */
  .device {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
    max-width: 620px;
    margin-inline: auto;
  }

  .device__shot {
    max-width: 100%;
    margin-inline: auto;
  }
}

@media (max-width: 940px) {
  .workspace {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "form"
      "result";
    max-width: 760px;
    width: 100%;
    margin-inline: auto;
  }

  .workspace > #result-panel {
    position: static;
    top: auto;
  }

  .page--stack {
    grid-template-columns: minmax(0, 1fr);
    max-width: 760px;
    width: 100%;
    margin-inline: auto;
  }
}

@media (max-width: 700px) {
  :root {
    --shell-w: calc(100% - 32px);
    --topbar-h: 56px;
  }

  /* 登录页在手机上压缩留白：主视觉 + 表单尽量一屏装下 */
  .auth {
    gap: 20px;
    align-content: start;
    padding: 8px 0 36px;
  }

  .lens {
    max-width: min(100%, 18.5rem, 36vh);
  }

  .app {
    gap: 22px;
    padding: 26px 0 52px;
  }

  #page-chat {
    height: calc(100vh - 210px);
    height: calc(100dvh - 210px);
    max-height: calc(100dvh - 210px);
  }

  /* 页头改为上下两行：大标题独占一行，页签铺满下一行 */
  .app__head {
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
  }

  .tabs--page {
    width: 100%;
  }

  .who {
    display: none;
  }

  .brand__text {
    font-size: 13.5px;
  }

  .card,
  .panel {
    padding: 20px;
    border-radius: var(--r-3);
  }

  .card {
    border-radius: var(--r-4);
  }

  .card__title {
    font-size: 23px;
  }

  .actions .btn {
    flex: 1 1 0;
    min-width: 0;
  }

  .toasts {
    right: 12px;
    bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    left: 12px;
    align-items: stretch;
  }

  .toast {
    max-width: none;
  }

  /* 设备信息在窄屏改为上下两行，数值不再右贴边 */
  .device__row {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    min-height: 0;
    padding: 14px 0;
  }

  .device__val {
    justify-content: flex-start;
    font-size: 15px;
    text-align: left;
  }

  .device__val--input {
    flex: 1 1 auto;
  }

  .device__val--input input {
    text-align: left;
  }

  .thread {
    max-height: 44vh;
  }

  .bubble {
    max-width: 88%;
  }

  /* 输入区动作：次要按钮靠左成组，发送贴右，不要三颗平均铺满 */
  .actions--composer {
    justify-content: flex-start;
  }

  .actions--composer .btn {
    flex: 0 0 auto;
  }

  .actions--composer .btn--primary {
    margin-left: auto;
  }
}

@media (max-width: 640px) {
  .memo-item__preview {
    margin-left: 0;
  }

  .memo-item__head {
    flex-wrap: wrap;
    gap: 6px 12px;
  }

  .memo-item__time {
    min-width: 0;
  }
}

@media (max-width: 420px) {
  .app__head h1 {
    font-size: 1.6rem;
  }

  .tabs__btn {
    font-size: 13px;
  }

  .panel,
  .card {
    padding: 18px;
  }
}

/* 触屏设备没有 hover：去掉悬停位移，只保留按压反馈 */
@media (hover: none) {
  .device__shot:hover img {
    transform: none;
  }

  .chat__thumb:hover {
    transform: none;
  }
}

/* ------------------------------ 导航页 ------------------------------ */

/* 导航只有一张卡片：占满内容列，别在桌面右半边留一块空白 */
#page-nav {
  grid-template-columns: minmax(0, 1fr);
  max-width: 920px;
  width: 100%;
}

.nav__form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 0.7fr);
  gap: 14px;
  align-items: end;
  margin: 18px 0 14px;
}

.nav__form .field {
  margin: 0;
}

.field--narrow {
  position: relative;
}

.field--narrow input {
  padding-right: 48px;
}

.field__suffix {
  position: absolute;
  right: 14px;
  bottom: 12px;
  color: var(--muted-2);
  font-size: 13px;
  pointer-events: none;
}

.nav__hero {
  display: flex;
  align-items: center;
  gap: 22px;
  padding: 18px 4px 10px;
}

.nav__arrow {
  flex: 0 0 112px;
  width: 112px;
  height: 112px;
  display: grid;
  place-items: center;
  font-size: 88px;
  line-height: 1;
  border-radius: 50%;
  background: var(--fill-1);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.nav__main {
  min-width: 0;
}

.nav__dist {
  margin: 0;
  font-size: 40px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.nav__inst {
  margin: 2px 0 0;
  font-size: 30px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.nav__road {
  margin: 6px 0 0;
  font-size: 17px;
  color: var(--ink-2);
}

.nav__next {
  margin: 4px 0 0;
  font-size: 14px;
  color: var(--muted);
}

.nav__bar {
  height: 8px;
  margin: 14px 0 6px;
  border-radius: 999px;
  background: var(--fill-2);
  overflow: hidden;
}

.nav__bar-fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: inherit;
  background: var(--ink);
  transition: width 600ms var(--ease-out, ease);
}

.nav__controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 18px 0 6px;
}

.nav__steps {
  margin-top: 16px;
  border-top: 1px solid var(--line);
  padding-top: 12px;
}

.nav__steps summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 14px;
}

.nav__steps ol {
  margin: 12px 0 0;
  padding-left: 20px;
  display: grid;
  gap: 6px;
}

.nav__steps li {
  font-size: 14px;
  color: var(--ink-2);
}

.nav__steps li b {
  color: var(--ink);
  font-weight: 600;
}

.nav__steps li span {
  color: var(--muted-2);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 720px) {
  .nav__form {
    grid-template-columns: 1fr;
  }

  .nav__hero {
    gap: 14px;
  }

  .nav__arrow {
    flex-basis: 84px;
    width: 84px;
    height: 84px;
    font-size: 64px;
  }

  .nav__dist {
    font-size: 30px;
  }

  .nav__inst {
    font-size: 24px;
  }
}
