/* 会员中心（C 端）样式 —— 与后台 app.css 完全独立
   视觉基调：暖橙主色 + 大圆角卡片 + 轻投影，移动端优先。 */

:root {
  --brand: #f2541b;
  --brand-2: #ff7a3c;
  --brand-soft: #fff1e9;
  --ink: #16181d;
  --ink-2: #5e636d;
  --ink-3: #9aa0a9;
  --line: #ecebe6;
  --bg: #f6f5f2;
  --card: #ffffff;
  --ok: #12a45f;
  --ok-soft: #e6f7ee;
  --warn: #d13b2e;
  --warn-soft: #fdecea;
  --r-lg: 22px;
  --r-md: 16px;
  --r-sm: 12px;
  --shadow: 0 1px 2px rgba(23, 26, 32, .04), 0 8px 24px rgba(23, 26, 32, .05);
  --shadow-lift: 0 2px 6px rgba(23, 26, 32, .06), 0 16px 36px rgba(23, 26, 32, .09);
  --tab-h: 62px;
}

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

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB",
               "Microsoft YaHei", "Segoe UI", sans-serif;
  font-size: 15px;
  line-height: 1.55;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}

a { color: var(--brand); text-decoration: none; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.ic { width: 22px; height: 22px; display: block; fill: none; stroke: currentColor;
      stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

.mapp { max-width: 480px; margin: 0 auto; min-height: 100vh; position: relative;
        background: var(--bg); }

/* ===== 顶部渐变区 =====
   原来上下 20/56 的大块橙色 + 22px 标题 + 一行说明，
   手机上差不多吃掉 150px，一进站先看到一大片色块，什么都还没看到。
   现在收成一条：品牌 + 积分胶囊，下面一行小标题，高度砍一半。 */
.hero {
  position: relative;
  padding: 14px 16px 26px;
  background: linear-gradient(135deg, #ff8a4d 0%, #f2541b 55%, #db3f0e 100%);
  color: #fff;
  border-radius: 0 0 22px 22px;
  overflow: hidden;
}
.hero::after {
  content: "";
  position: absolute;
  width: 190px; height: 190px;
  right: -70px; top: -120px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .13);
}
.hero::before {
  content: "";
  position: absolute;
  width: 110px; height: 110px;
  left: -46px; bottom: -64px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .1);
}
.hero-top { position: relative; display: flex; align-items: center; justify-content: space-between; z-index: 1; }
.hero-brand { display: flex; align-items: center; gap: 8px; color: #fff; font-size: 15px;
              font-weight: 600; letter-spacing: .3px; }
.hero-brand:hover { text-decoration: none; }
.logo {
  width: 28px; height: 28px; border-radius: 9px;
  background: rgba(255, 255, 255, .22);
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 600;
  backdrop-filter: blur(4px);
}
.hero-pts {
  display: flex; align-items: center; gap: 5px;
  background: rgba(255, 255, 255, .2);
  border-radius: 999px;
  padding: 5px 12px;
  color: #fff; font-size: 12.5px;
  backdrop-filter: blur(6px);
}
.hero-pts:hover { text-decoration: none; background: rgba(255, 255, 255, .3); }
.hero-pts b { font-size: 14px; font-variant-numeric: tabular-nums; }
/* 积分前那个"共"字：点明这是账号总额（各设备之和），不是这一台的余额 */
.pts-k { font-style: normal; font-size: 11px; opacity: .85; }
.hero-sub { position: relative; z-index: 1; margin: 12px 0 0; font-size: 18px;
            font-weight: 600; letter-spacing: .2px; }
/* 原来这里还有一行"远程控制你的炽芯设备"，和标题说的是同一件事，删掉 */
.hero-note { display: none; }
/* 控制面板页专用：设备名和状态已经在下面的文字行里，顶部不再重复标题，
   只留品牌 + 积分这一条，压到 40 多像素高，别一进页面先吃半屏橙色。 */
.hero-mini { padding: 8px 14px 12px; border-radius: 0 0 16px 16px; }
.hero-mini + .mwrap { margin-top: 0; }
.hero-mini .hero-sub { display: none; }
.hero-mini .hero-brand { font-size: 14px; gap: 7px; }
.hero-mini .logo { width: 24px; height: 24px; border-radius: 8px; font-size: 12.5px; }
.hero-mini .hero-pts { padding: 4px 10px; font-size: 12px; }
.hero-mini .hero-pts b { font-size: 13px; }

/* ===== 内容区 ===== */
.mwrap { padding: 0 16px 32px; margin-top: -16px; position: relative; z-index: 2; }
.is-guest .mwrap { margin-top: 0; padding-top: 24px; }
.mfoot { text-align: center; font-size: 12px; color: var(--ink-3); padding: 8px 16px 88px; }
.is-guest .mfoot { padding-bottom: 32px; }

.mtitle { font-size: 19px; font-weight: 600; margin: 18px 4px 12px; letter-spacing: .2px; }

/* ===== 卡片 ===== */
.card {
  background: var(--card);
  border-radius: var(--r-lg);
  padding: 18px;
  margin-bottom: 14px;
  box-shadow: var(--shadow);
}
.card-flat { box-shadow: none; border: 1px solid var(--line); }
.card h2 {
  display: flex; align-items: center; gap: 8px;
  font-size: 15px; font-weight: 600; margin: 0 0 14px;
  letter-spacing: .2px;
}
.card h2 .ic { width: 18px; height: 18px; color: var(--brand); }
.card h3 {
  font-size: 13px; font-weight: 500; color: var(--ink-2);
  margin: 18px 0 10px;
}
.card h2 + h3 { margin-top: 4px; }
.mhint { font-size: 13px; color: var(--ink-2); margin: 8px 0; line-height: 1.65; }
.mhint-sm { font-size: 12px; color: var(--ink-3); margin: 6px 0 0; }

/* ===== 提示条 ===== */
.toast {
  display: flex; align-items: flex-start; gap: 8px;
  border-radius: var(--r-md);
  padding: 12px 14px;
  font-size: 13.5px;
  margin-bottom: 12px;
  animation: tin .22s ease-out;
}
.toast.ok { background: var(--ok-soft); color: #0c7a46; }
.toast.bad { background: var(--warn-soft); color: #b3301f; }
.toast::before {
  content: ""; flex: 0 0 auto; width: 6px; height: 6px; border-radius: 50%;
  margin-top: 7px; background: currentColor;
}
@keyframes tin { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

/* 页面内 JS 提示（防连点等）：浮在顶部，不进文档流，2.4 秒自己消失。
   单独一套动画：tin 用的是 translateY，会把水平居中的 translateX(-50%) 覆盖掉。 */
.toast.jstip {
  position: fixed; left: 50%; top: 18px; z-index: 999;
  margin: 0; max-width: min(92vw, 420px);
  transform: translateX(-50%);
  background: #2a2c31; color: #fff;
  box-shadow: var(--shadow-lift);
  animation: jin .2s ease-out;
}
.toast.jstip::before { background: #ffb08a; }
@keyframes jin {
  from { opacity: 0; transform: translate(-50%, -8px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}

/* 排队中的指令条数 + 撤销入口。设备离线时这块最有用。 */
.pendbar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 0 0 10px; padding: 9px 12px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: #fbfaf8; font-size: 12.5px; color: var(--ink-2);
}
.pendbar b { color: var(--brand); font-weight: 600; }
.pendbar form { margin: 0; flex: 0 0 auto; }
.pendbar button {
  border: 1px solid var(--line); border-radius: 999px; padding: 4px 12px;
  background: var(--card); color: var(--ink-2);
  font-family: inherit; font-size: 12.5px; cursor: pointer;
}
.pendbar button:active { background: #f2f0ec; }

/* ===== 设备卡（列表） ===== */
/* 一行 = 可点的卡片 + 独立的解绑按钮。
   卡片是 <a>，里面不能套 <form>，所以解绑只能放在它旁边。 */
.devrow { display: flex; align-items: stretch; gap: 8px; margin-bottom: 12px; }
.devrow .devcard { flex: 1 1 auto; margin-bottom: 0; min-width: 0; }
/* 解绑按钮以前会被挤成"解/绑"两行竖排，按钮不参与收缩、字不换行 */
.unb { display: flex; align-items: center; flex: 0 0 auto; }
.unb button {
  height: 100%; padding: 0 14px;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--card); color: var(--ink-3);
  font-size: 13px; font-family: inherit; cursor: pointer;
  white-space: nowrap;
  transition: color .16s ease, border-color .16s ease;
}
.unb button:hover { color: var(--warn); border-color: var(--warn-soft); }

.sechead { display: flex; align-items: center; justify-content: space-between; margin: 4px 2px 10px; }
.sechead h2 { font-size: 15px; font-weight: 600; margin: 0; }
.quota { font-size: 13px; color: var(--ink-3); }

.devcard {
  display: flex; align-items: center; gap: 14px;
  background: var(--card);
  border-radius: var(--r-lg);
  padding: 16px;
  margin-bottom: 12px;
  box-shadow: var(--shadow);
  color: inherit;
  transition: transform .16s ease, box-shadow .16s ease;
}
.devcard:active { transform: scale(.985); }
.devcard:hover { text-decoration: none; box-shadow: var(--shadow-lift); }
.devico {
  flex: 0 0 auto;
  width: 52px; height: 52px; border-radius: 18px;
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-soft); color: var(--brand);
  position: relative;
}
.devico .ic { width: 26px; height: 26px; }
.devico.round { border-radius: 50%; }
.devmain { flex: 1 1 auto; min-width: 0; }
.devname {
  display: flex; align-items: center; gap: 7px;
  font-size: 15.5px; font-weight: 600;
  margin-bottom: 3px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* 设备码一行、固件与最后通信一行。原来全挤一行，窄屏折行时行尾会吊着一个孤零零的
   "·"，看着像漏了半句话。分两行之后宽窄屏都稳定。 */
.devmeta { font-size: 12.5px; color: var(--ink-3); display: flex; flex-direction: column; gap: 1px; }
.devmeta .mono { color: var(--ink-2); }
/* 本机余额：和设备码/固件同一列，数字用品牌色拎出来 */
.devmeta .devpts { color: var(--ink-2); }
.devmeta .devpts b { color: var(--brand); font-variant-numeric: tabular-nums; }
.chev { flex: 0 0 auto; color: #c9ccd2; }
.chev .ic { width: 18px; height: 18px; }

.dot { width: 7px; height: 7px; border-radius: 50%; background: #c8ccd3; flex: 0 0 auto; }
.dot.on { background: var(--ok); box-shadow: 0 0 0 0 rgba(18, 164, 95, .5); animation: pulse 2.2s infinite; }
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(18, 164, 95, .45); }
  70%  { box-shadow: 0 0 0 7px rgba(18, 164, 95, 0); }
  100% { box-shadow: 0 0 0 0 rgba(18, 164, 95, 0); }
}

/* ===== 控制面板页：设备信息小卡片 =====
   以前这里是一块深色"假屏幕"卡（148px 圆屏 + 大阴影），把一整屏都占了。
   现在收成一张小卡：两行字交代"谁、在不在线、固件、最后通信"，比纯文字有边界感。 */
.devbar {
  margin: 14px 0 4px;
  padding: 13px 14px 12px;
  background: var(--card);
  border-radius: var(--r-md);
  box-shadow: var(--shadow);
}
.devbar-line { display: flex; align-items: center; gap: 8px; }
.devbar-name {
  min-width: 0; font-size: 18px; font-weight: 600; letter-spacing: .2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pill {
  flex: 0 0 auto;
  font-size: 11.5px; padding: 3px 9px; border-radius: 999px;
  background: #eceef1; color: var(--ink-2);
  display: inline-flex; align-items: center; gap: 5px;
}
.pill.on { background: var(--ok-soft); color: #0c7a46; }

/* 设备码一行、固件和最后通信一行。以前三项横排用竖线分隔，
   窄屏换行时那根竖线会跑到行首变成"| 最后通信"，很难看；
   改成固定两行，宽窄屏都不会错位。 */
.devbar-meta {
  display: flex; flex-direction: column; gap: 3px;
  margin-top: 5px; font-size: 12px; color: var(--ink-3);
}
/* 设备码等宽字体，抄给客服时不会把 0 和 O 看错。
   带杠的分组写法（D885-ACD5-7E40-019D）里全是天然的断行点，
   一行放不下时会在中间裂开，读起来像两组无关的码，所以整段不许断。 */
.devbar-code { font-family: ui-monospace, Menlo, Consolas, monospace; letter-spacing: .2px; white-space: nowrap; color: var(--ink-2); }
/* 本机余额：指令费就是从这台机器上扣的，数字给它品牌色 */
.devbar-pts { color: var(--brand); font-variant-numeric: tabular-nums; }
.devbar-off {
  margin: 9px 0 0; padding: 8px 11px;
  border-radius: var(--r-sm);
  background: var(--warn-soft); color: #b3301f;
  font-size: 12px; line-height: 1.55;
}
.devbar-find { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.devbar-find button {
  border: 0; border-radius: 999px; padding: 6px 13px;
  background: var(--brand-soft); color: var(--brand);
  font-family: inherit; font-size: 12.5px; cursor: pointer;
  transition: background .14s ease;
}
.devbar-find button:active { background: #ffe0cf; }
.devbar-find em { font-style: normal; font-size: 11.5px; color: var(--ink-3); }

/* 撤销排队中的指令。用中性描边而不是橙色——它和「闪灯找设备」不是一类操作，
   一个是日常动作，一个是纠错动作，视觉上要能分开。 */
.devbar-cancel { display: flex; align-items: center; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
.devbar-cancel button {
  border: 1px solid var(--line); border-radius: 999px; padding: 5px 13px;
  background: var(--card); color: var(--ink-2);
  font-family: inherit; font-size: 12.5px; cursor: pointer;
  transition: background .14s ease;
}
.devbar-cancel button:active { background: #f6f4f1; }
.devbar-cancel em { font-style: normal; font-size: 11.5px; color: var(--ink-3); }

/* 功能入口的小标题：只是一行小字，不再占一块色阶 */
.modcap {
  margin: 2px 2px 9px; font-size: 12px; font-weight: 500;
  color: var(--ink-3); letter-spacing: 1px;
}

/* ===== 九宫格快捷操作 ===== */
.qgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.qgrid > form { display: contents; }
.qtile {
  width: 100%;
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 15px 6px 12px;
  border: 0; border-radius: 18px;
  background: #faf9f7;
  color: var(--ink);
  font-family: inherit; font-size: 12.5px;
  cursor: pointer;
  transition: transform .14s ease, background .14s ease;
}
.qtile:active { transform: scale(.955); background: #f3f1ed; }
.qico {
  width: 42px; height: 42px; border-radius: 14px;
  display: flex; align-items: center; justify-content: center;
  background: #fff; color: var(--brand);
  box-shadow: 0 1px 3px rgba(23, 26, 32, .07);
}
.qico .ic { width: 21px; height: 21px; }
.qico.off { color: #8b9099; }
.qico.moon { color: #7a5af8; background: #f3f0ff; }
.qico.sun  { color: #f0a01b; background: #fff7e8; }
.qico.clock{ color: #0e8fbf; background: #eaf7fd; }
.qico.album{ color: #d6457a; background: #fdeef4; }
.qico.chat { color: #12a45f; background: #e9f8f0; }
.qtile .qpt { font-size: 10.5px; color: var(--ink-3); }
.qtile:disabled { opacity: .5; }

/* ===== 颜色圆点 ===== */
.swrow { display: flex; gap: 12px; flex-wrap: wrap; }
.swrow > form { display: contents; }
.sw {
  width: 44px; height: 44px; border-radius: 50%;
  border: 0; cursor: pointer;
  position: relative;
  box-shadow: 0 2px 8px rgba(23, 26, 32, .14);
  transition: transform .14s ease;
}
.sw:active { transform: scale(.9); }
.sw span { position: absolute; left: 50%; transform: translateX(-50%); bottom: -18px;
           font-size: 11px; color: var(--ink-3); white-space: nowrap; }
.sw-red    { background: linear-gradient(145deg, #ff6b5e, #d92b1c); }
.sw-green  { background: linear-gradient(145deg, #4ed08a, #17a05c); }
.sw-blue   { background: linear-gradient(145deg, #5aa9ff, #1f6fd0); }
.sw-rainbow{ background: conic-gradient(#ff5f57, #ffbd2e, #28c840, #4fc3f7, #b06bff, #ff5f57); }
.swrow { padding-bottom: 18px; }

/* ===== 色板网格（灯光固定颜色） =====
   一格一个色点 + 名字。用 3 列是因为 8 个预设色加流光正好排满三行，
   两列会把灯光页拉太长。 */
.cgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.cgrid > form { display: contents; }
.cbtn {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 4px 8px;
  background: #faf9f7; border: 0; border-radius: 14px;
  font-family: inherit; font-size: 12px; color: var(--ink-2);
  cursor: pointer; transition: background .14s ease, transform .14s ease;
}
.cbtn:active { transform: scale(.96); background: #f2f0ec; }
.cdot {
  width: 30px; height: 30px; border-radius: 50%; display: block;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08), 0 2px 6px rgba(23, 26, 32, .12);
}

/* ===== 自定义颜色 =====
   唤醒系统取色器，比让学生手输 #RRGGBB 靠谱（手机键盘上打十六进制太容易错）。 */
.colorrow { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.colorin {
  -webkit-appearance: none; appearance: none;
  width: 58px; height: 44px; padding: 0; border: 0; border-radius: 12px;
  background: none; cursor: pointer; overflow: hidden;
}
.colorin::-webkit-color-swatch-wrapper { padding: 0; }
.colorin::-webkit-color-swatch { border: 0; border-radius: 12px; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1); }
.colorin::-moz-color-swatch { border: 0; border-radius: 12px; }
.colorhint { font-size: 12.5px; color: var(--ink-3); }

/* ===== chips：一排小胶囊按钮（快捷时长 / 音量档位 / 热门城市） ===== */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chips > form { display: contents; }
.chip {
  border: 0; border-radius: 999px; padding: 7px 13px;
  background: #f3f1ed; color: var(--ink-2);
  font-family: inherit; font-size: 12.5px; cursor: pointer;
  transition: background .14s ease, color .14s ease;
}
.chip:active { background: var(--brand-soft); color: var(--brand); }

/* ===== 聊天主题预览 ===== */
.chatpick {
  width: 100%; border: 0; background: #faf9f7; border-radius: var(--r-md);
  padding: 12px; font-family: inherit; text-align: left; cursor: pointer; display: block;
}
.chatpick:active { background: #f2f0ec; }
.chatprev {
  display: flex; flex-direction: column; gap: 6px;
  padding: 12px; border-radius: 12px; min-height: 104px;
}
.chatprev.light { background: #f0efe9; }
.chatprev.dark  { background: #14161a; }
.bb {
  font-style: normal; font-size: 11.5px; line-height: 1.5;
  padding: 5px 9px; border-radius: 10px; max-width: 84%;
}
.chatprev.light .bb.l { background: #fff; color: #333; align-self: flex-start; }
.chatprev.light .bb.r { background: #95ec69; color: #1b3a14; align-self: flex-end; }
.chatprev.dark  .bb.l { background: #262a31; color: #d9dde3; align-self: flex-start; }
.chatprev.dark  .bb.r { background: #2e7d4f; color: #eaf7ee; align-self: flex-end; }
.chatname { display: flex; align-items: baseline; gap: 8px; margin-top: 10px; }
.chatname b { font-size: 14px; font-weight: 600; }
.chatname em { font-style: normal; font-size: 11.5px; color: var(--ink-3); }

/* ===== 说明块：浅橙底，交代"为什么这里做不了" ===== */
.tipbox {
  margin-top: 12px; padding: 10px 12px;
  background: var(--brand-soft); color: #8a3a12;
  border-radius: var(--r-sm); font-size: 12px; line-height: 1.65;
}

/* ===== 滑块 ===== */
.rngbox { display: flex; align-items: center; gap: 14px; }
.rng {
  -webkit-appearance: none; appearance: none;
  flex: 1 1 auto; min-width: 0;
  height: 8px; border-radius: 99px;
  background: linear-gradient(90deg, var(--brand-2) 0%, var(--brand) var(--p, 50%), #eeedea var(--p, 50%));
  outline: none;
}
.rng::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 26px; height: 26px; border-radius: 50%;
  background: #fff; border: 0;
  box-shadow: 0 2px 8px rgba(242, 84, 27, .35), 0 1px 3px rgba(0, 0, 0, .16);
  cursor: pointer;
}
.rng::-moz-range-thumb {
  width: 26px; height: 26px; border-radius: 50%; background: #fff; border: 0;
  box-shadow: 0 2px 8px rgba(242, 84, 27, .35);
}
.rngv {
  min-width: 46px; text-align: right;
  font-size: 17px; font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.rngv em { font-style: normal; font-size: 11px; color: var(--ink-3); font-weight: 400; margin-left: 2px; }
/* 灯关着时整条滑条禁用：别让用户拖了半天才发现白拖。
   灰掉比藏起来好——藏了他会以为页面坏了。 */
.rng:disabled { opacity: .4; cursor: not-allowed; }
.rng:disabled::-webkit-slider-thumb { box-shadow: none; cursor: not-allowed; }
.rng:disabled::-moz-range-thumb { box-shadow: none; cursor: not-allowed; }
.mhint-sm.bad { color: #b3301f; }

/* ===== 主题预览（时钟 / 显示内容）===== */
.pickgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.pickgrid > form { display: contents; }
.pick {
  border: 0; padding: 0; background: none; cursor: pointer;
  font-family: inherit; display: flex; flex-direction: column; align-items: center; gap: 7px;
  color: var(--ink-2); font-size: 12.5px;
}
.pick:active .pthumb { transform: scale(.95); }
.pthumb {
  width: 100%; aspect-ratio: 1 / 1; border-radius: 16px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; position: relative; overflow: hidden;
  transition: transform .14s ease;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .06);
}
.pthumb b { font-size: 15px; font-weight: 500; font-variant-numeric: tabular-nums; }
.pthumb i { font-style: normal; font-size: 9px; opacity: .55; }
.p-dark  { background: linear-gradient(150deg, #2a2d33, #121417); color: #fff; }
.p-light { background: linear-gradient(150deg, #fdfdfb, #eeeee8); color: #2b2f36; }
.p-chat  { background: linear-gradient(150deg, #e9f8f0, #d3f0e2); color: #0c7a46; }
.p-clock { background: linear-gradient(150deg, #eaf7fd, #cfeaf8); color: #0a6f96; }
.p-album { background: linear-gradient(150deg, #fdeef4, #f8d9e6); color: #a83262; }
.pick .pin { position: absolute; top: 6px; right: 6px; width: 14px; height: 14px;
             border-radius: 50%; background: var(--brand); display: none;
             box-shadow: 0 0 0 3px rgba(242, 84, 27, .18); }
.pick.on .pthumb { box-shadow: 0 0 0 2px var(--brand), 0 4px 12px rgba(242, 84, 27, .2); }
.pick.on .pin { display: block; }

/* ===== 列表行（指令记录 / 积分明细）===== */
.rows { display: flex; flex-direction: column; }
.row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 0;
  border-bottom: 1px solid #f4f2ee;
}
.row:last-child { border-bottom: 0; }
.row:first-child { padding-top: 0; }
.row-main { flex: 1 1 auto; min-width: 0; }
.row-t { font-size: 14px; }
.row-s { font-size: 11.5px; color: var(--ink-3); margin-top: 1px; }
.row-v { font-size: 14px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.row-v.plus { color: var(--ok); }
.row-v.minus { color: var(--warn); }
.st { font-size: 11.5px; padding: 3px 9px; border-radius: 999px; white-space: nowrap; }
.st.s0 { background: #f2f1ee; color: #8b9099; }
.st.s1 { background: #fff6e3; color: #a9741a; }
.st.s2 { background: var(--ok-soft); color: #0c7a46; }
.st.s3 { background: var(--warn-soft); color: #b3301f; }

/* ===== 表单 ===== */
label {
  display: block; font-size: 13.5px; font-weight: 500;
  color: var(--ink-2); margin: 18px 0 8px;
}
/* 选择器写成一网打尽的形式：以前按 name 一个个列，注册页的手机号是
   type="tel"，没被列进去，就退回浏览器默认样式，又小又灰。
   现在 [type=...] 全带上，没写 type 的也用 :not([type]) 兜住。 */
input:not([type]),
input[type="text"],
input[type="tel"],
input[type="password"],
input[type="number"],
input[type="email"] {
  width: 100%;
  padding: 16px 16px;
  border: 2px solid #f0ae91;
  border-radius: 16px;
  font-size: 16px;               /* 16px 是 iOS 的分界，小于它聚焦会自动放大页面 */
  font-family: inherit;
  color: var(--ink);
  background: #fffdfb;
  outline: none;
  transition: border-color .16s ease, background .16s ease, box-shadow .16s ease;
  -webkit-appearance: none;
  appearance: none;
}
input::placeholder { color: #b7bbc2; }
input:focus {
  border-color: var(--brand);
  background: #fff;
  box-shadow: 0 0 0 4px rgba(242, 84, 27, .12);
}

.btn {
  display: block; width: 100%;
  margin-top: 22px;
  padding: 16px;
  border: 0; border-radius: 16px;
  background: linear-gradient(135deg, var(--brand-2), var(--brand));
  color: #fff;
  font-size: 15.5px; font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(242, 84, 27, .28);
  transition: transform .14s ease, box-shadow .14s ease;
}
.btn:active { transform: scale(.98); box-shadow: 0 3px 10px rgba(242, 84, 27, .22); }
.btn-ghost {
  background: #fff; color: var(--ink-2);
  box-shadow: inset 0 0 0 1.5px var(--line);
}
.btn-ghost:active { box-shadow: inset 0 0 0 1.5px var(--line); }
.btn-sm {
  display: inline-block; width: auto;
  margin: 0; padding: 9px 15px;
  font-size: 13px; border-radius: 11px;
  box-shadow: none;
}
.btn-danger { background: none; color: var(--warn); box-shadow: none; font-weight: 500; }

.malt { font-size: 13px; color: var(--ink-3); text-align: center; margin: 18px 0 0; }

/* ===== 登录 / 注册（游客态）===== */
.guest-head { text-align: center; padding: 26px 0 20px; }
.guest-logo {
  width: 62px; height: 62px; border-radius: 20px; margin: 0 auto 14px;
  background: linear-gradient(135deg, var(--brand-2), var(--brand));
  color: #fff; font-size: 26px; font-weight: 600;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 26px rgba(242, 84, 27, .3);
}
.guest-head h1 { font-size: 22px; font-weight: 600; margin: 0 0 6px; }
.guest-head p { font-size: 13.5px; color: var(--ink-2); margin: 0; }

/* ===== 积分卡 ===== */
/* 积分卡：原来是一块黑色渐变 + 44px 白字，压在页面上很沉，
   像贴在橙色头部下面的一口黑井。现在改成浅橙描边白卡，
   数字用品牌橙，一眼能看清数额，也不抢头部的视觉重量。 */
.ptscard {
  background: linear-gradient(135deg, #fff7f2 0%, #ffffff 62%);
  border: 1px solid #ffe3d3;
  border-radius: var(--r-lg);
  padding: 15px 18px 14px;
  color: var(--ink);
  position: relative;
  overflow: hidden;
  box-shadow: var(--shadow);
}
.ptscard-top { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.ptscard-k { font-size: 13px; color: var(--ink-2); }
.ptscard-n {
  font-size: 28px; font-weight: 600; line-height: 1.1;
  letter-spacing: .2px; color: var(--brand);
  font-variant-numeric: tabular-nums;
}
.ptscard-n em { font-style: normal; font-size: 12.5px; font-weight: 400; color: var(--ink-3); margin-left: 4px; }
.ptscard-tip {
  font-size: 12px; color: var(--ink-3); margin: 8px 0 0; line-height: 1.6;
}

/* 账号页列表 */
.menu { display: flex; flex-direction: column; }
.menu-row {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid #f4f2ee;
  font-size: 14.5px; color: var(--ink);
}
.menu-row:last-child { border-bottom: 0; }
.menu-row .ic { width: 19px; height: 19px; color: var(--ink-3); }
.menu-row .r { margin-left: auto; color: var(--ink-3); font-size: 13px; }
/* 设备码带杠之后有 19 个字符，窄屏容易从杠那里断成两截，整段锁住宽度 */
.mono { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12.5px; letter-spacing: .3px; white-space: nowrap; }

/* ===== 底部导航 ===== */
.tabbar {
  position: fixed;
  left: 50%; bottom: 0;
  transform: translateX(-50%);
  width: 100%; max-width: 480px;
  height: calc(var(--tab-h) + env(safe-area-inset-bottom, 0px));
  padding-bottom: env(safe-area-inset-bottom, 0px);
  display: flex;
  background: rgba(255, 255, 255, .86);
  backdrop-filter: saturate(180%) blur(18px);
  -webkit-backdrop-filter: saturate(180%) blur(18px);
  border-top: 1px solid rgba(0, 0, 0, .05);
  z-index: 50;
}
.tabbar a {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  color: var(--ink-3); font-size: 11px;
}
.tabbar a:hover { text-decoration: none; }
.tabbar a .ic { width: 23px; height: 23px; }
.tabbar a.on { color: var(--brand); font-weight: 500; }

/* ===== 兜底 ===== */
.mempty { text-align: center; padding: 34px 16px; color: var(--ink-3); font-size: 13.5px; }
.mempty .ic { width: 34px; height: 34px; margin: 0 auto 10px; color: #cfd3d9; }

@media (min-width: 481px) {
  body { background: #eeede9; }
  .mapp { box-shadow: 0 0 60px rgba(0, 0, 0, .07); min-height: 100vh; }
  .tabbar { box-shadow: 0 -8px 30px rgba(0, 0, 0, .05); }
}

/* ===== 设备页新增：闹钟 / 喝水 / 天气城市 / 固件升级 =====
   表单元素全部自绘，避开 iOS 原生控件那套深浅不一的默认样式。 */

.fld { margin-bottom: 14px; }
.fld > label {
  display: block; font-size: 12.5px; color: var(--ink-2);
  margin-bottom: 7px; font-weight: 500;
}
.fldem { font-style: normal; color: var(--ink-3); font-weight: 400; }

.inp, .timein, .fld input[type="number"] {
  width: 100%; padding: 12px 14px;
  border: 1.5px solid #eae8e3; border-radius: 14px;
  font-size: 15px; font-family: inherit; color: var(--ink);
  background: #faf9f7; outline: none;
  -webkit-appearance: none; appearance: none;
}
.inp:focus, .timein:focus, .fld input[type="number"]:focus {
  border-color: var(--brand); background: #fff;
}
.timein { font-variant-numeric: tabular-nums; letter-spacing: .5px; }

/* 时间选择：两个下拉框拼成 HH:MM，点一下列出 00-23 点 / 00-59 分。
   - 不用 <input type="time">：Chrome 会塞「上午/下午」和时钟图标，手机上又弹滚轮。
   - 不用手打数字：用户反馈"不要让别人去输"，所以一律点选。
   手机上点开是系统原生滚轮，桌面上是下拉列表。 */
.timebox { display: flex; align-items: center; gap: 10px; }
.tpid {
  flex: 0 0 auto; width: 112px;
  /* 左右内边距相等，文字才能真的居中（右边留给箭头的空间靠 background-position 叠上去） */
  padding: 7px 22px;
  border: 1.5px solid #eae8e3; border-radius: 10px;
  font: inherit; font-size: 15px; font-weight: 500; line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--ink); background-color: #faf9f7; outline: none; cursor: pointer;
  text-align: center; text-align-last: center;
  -webkit-appearance: none; appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a8f98' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat;
  background-position: right 9px center;
  background-size: 13px;
}
.tpid:focus { border-color: var(--brand); background-color: #fff; }
.tsep { font-style: normal; font-size: 16px; font-weight: 600; color: var(--ink-3); }
.fld2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.unitrow { display: flex; align-items: center; gap: 10px; }
.unitrow em { font-style: normal; font-size: 13px; color: var(--ink-3); white-space: nowrap; }
.btn-block { margin-top: 14px; }
.stoprow { margin-top: 10px; }
.stoprow .btn { margin-top: 0; }
.btn:disabled { opacity: .45; box-shadow: none; cursor: not-allowed; }

/* ===== 喝水提醒页 =====
   分区顺序照小程序 pages/drink：头部开关 → 下次提醒 → 重复方式 → 间隔 →
   生效时段 → 星期。类名统一 dk- 前缀，避免和闹钟/灯光页的 .day .chip 打架。 */
.dk-head { display: flex; align-items: center; gap: 12px; }
.dk-head-t { flex: 1; min-width: 0; }
.dk-title {
  display: flex; align-items: center; gap: 6px;
  font-size: 16px; font-weight: 600; color: var(--ink);
}
.dk-title .ic { width: 18px; height: 18px; }
.dk-sub { margin: 4px 0 0; font-size: 12px; color: var(--ink-3); }

/* 开关：点一下直接提交，跟小程序那个 switch 一样，不用先改再保存 */
.dk-switch {
  position: relative; flex: none; width: 46px; height: 27px; padding: 0;
  border: none; border-radius: 999px; background: #dcd9d2;
  cursor: pointer; transition: background .18s;
  -webkit-appearance: none; appearance: none;
}
.dk-switch i {
  position: absolute; top: 3px; left: 3px; width: 21px; height: 21px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .22);
  transition: left .18s;
}
.dk-switch.on { background: var(--brand); }
.dk-switch.on i { left: 22px; }

/* 下次提醒：这张页面最该先回答的问题，所以给足对比度 */
.dk-note {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 12px; padding: 10px 12px;
  border-radius: 12px; background: var(--brand-soft);
  font-size: 13px; color: #8a3a12;
}
.dk-note-k { font-size: 12px; color: #b0603a; }
.dk-note b { font-size: 14px; font-weight: 600; color: #7a2f0a; }
.dk-note-src { margin-left: auto; font-style: normal; font-size: 11px; color: #b0603a; }
.dk-warn { margin-top: 8px; font-size: 12px; color: var(--warn); }

/* 小节标题 */
.dk-sec {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 18px 0 10px; font-size: 13px; font-weight: 600; color: var(--ink);
}
.dk-tag {
  font-style: normal; font-size: 11px; font-weight: 400;
  color: var(--brand); background: var(--brand-soft);
  padding: 2px 7px; border-radius: 6px;
}

/* 重复方式：三块，选中靠 :has() 即时反馈，不用等提交 */
.dk-modes { display: flex; gap: 8px; }
.dk-mode {
  position: relative; flex: 1; text-align: center; cursor: pointer;
  padding: 10px 6px; border: 1.5px solid #edebe4; border-radius: 12px; background: #fff;
}
.dk-mode input { position: absolute; opacity: 0; pointer-events: none; }
.dk-mn { display: block; font-size: 13px; font-weight: 600; color: #5f5e5a; }
.dk-md { display: block; margin-top: 3px; font-size: 11px; color: #a8a69d; }
.dk-mode:has(input:checked) { border-color: var(--brand); background: #faece7; }
.dk-mode:has(input:checked) .dk-mn { color: var(--brand); }

/* 常用间隔胶囊 */
.dk-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.dk-chip {
  padding: 6px 14px; cursor: pointer; font: inherit; font-size: 12px;
  border: 1.5px solid #edebe4; border-radius: 999px;
  background: #fff; color: #5f5e5a;
}
.dk-chip:hover { border-color: #d8d4cc; }
.dk-chip.on { border-color: var(--brand); background: #faece7; color: var(--brand); font-weight: 600; }

.dk-selfrow { display: flex; align-items: center; gap: 6px; margin-top: 10px; }
.dk-selfk { font-size: 12px; color: var(--ink-3); }
.dk-selfrow em { font-style: normal; font-size: 12px; color: var(--ink-3); }
.dk-inp {
  width: 56px; padding: 3px 6px; text-align: center;
  border: 1.5px solid #eae8e3; border-radius: 8px;
  font: inherit; font-size: 13px; line-height: 1.5; color: var(--ink); background: #faf9f7; outline: none;
  -webkit-appearance: none; appearance: none;
}
/* 收掉数字框上下那对箭头：鼠标移上去会突然占掉一半宽度，字被挤歪，
   而且这行本来就窄，用键盘上下键一样能改。 */
.dk-inp::-webkit-outer-spin-button,
.dk-inp::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.dk-inp { -moz-appearance: textfield; }
.dk-inp:focus { border-color: var(--brand); background: #fff; }

/* 生效时段：两组「小时 : 分钟」下拉，点选不手打 */
.dk-times { display: flex; flex-direction: column; gap: 8px; }
.dk-times.dim { opacity: .45; }
.dk-trow { display: flex; align-items: center; gap: 8px; }
.dk-tk { flex: none; width: 32px; font-size: 12px; color: var(--ink-3); }
.dk-sel { width: 100px; padding: 6px 24px 6px 8px; font-size: 14px; border-radius: 9px; }

/* 星期圆点 */
.dk-days { display: flex; gap: 6px; }
.dk-day {
  position: relative; flex: 1; aspect-ratio: 1 / 1;
  display: grid; place-items: center; cursor: pointer;
  border-radius: 50%; background: #f1efe8; color: #888780; font-size: 13px;
}
.dk-day input { position: absolute; opacity: 0; pointer-events: none; }
.dk-day:has(input:checked) { background: var(--brand); color: #fff; font-weight: 600; }

/* 关闭提醒：跟闹钟列表的"删除"同一套警示色 */
.dk-close { margin-top: 8px; }
.dk-del {
  width: 100%; padding: 8px 12px; cursor: pointer;
  border: 1.5px solid #f0cfcb; border-radius: 10px;
  background: var(--warn-soft); color: var(--warn);
  font: inherit; font-size: 13px; font-weight: 600;
}
.dk-del:hover { background: var(--warn); color: #fff; border-color: var(--warn); }

/* 二选一分段 */
.segrow { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.seg, .day { position: relative; }
.seg input, .day input { position: absolute; opacity: 0; pointer-events: none; }
.seg span {
  display: block; text-align: center; padding: 11px 8px;
  border-radius: 13px; background: #faf9f7;
  box-shadow: inset 0 0 0 1.5px #eae8e3;
  font-size: 14px; color: var(--ink-2);
  transition: background .15s ease, color .15s ease, box-shadow .15s ease;
}
.seg input:checked + span {
  background: var(--brand-soft); color: var(--brand); font-weight: 600;
  box-shadow: inset 0 0 0 1.5px rgba(242, 84, 27, .45);
}

/* 星期多选 */
.dayrow { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; }
.day span {
  display: flex; align-items: center; justify-content: center;
  height: 40px; border-radius: 12px;
  background: #faf9f7; box-shadow: inset 0 0 0 1.5px #eae8e3;
  font-size: 13.5px; color: var(--ink-2);
  transition: background .15s ease, color .15s ease;
}
.day input:checked + span {
  background: var(--brand); color: #fff; font-weight: 600;
  box-shadow: 0 4px 10px rgba(242, 84, 27, .25);
}

/* 开关 */
.chkrow {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 2px 14px; font-size: 14px;
}
.switch { position: relative; width: 48px; height: 28px; flex: 0 0 auto; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch i {
  position: absolute; inset: 0; border-radius: 999px;
  background: #e2e0db; transition: background .2s ease;
}
.switch i::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 22px; height: 22px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .18);
  transition: transform .2s ease;
}
.switch input:checked + i { background: var(--brand); }
.switch input:checked + i::after { transform: translateX(20px); }

/* 城市搜索结果 */
.cityres {
  margin-top: 8px; max-height: 264px; overflow-y: auto;
  border-radius: 14px; background: #faf9f7;
  box-shadow: inset 0 0 0 1.5px #eae8e3;
  -webkit-overflow-scrolling: touch;
}
.cityitem {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  width: 100%; padding: 11px 14px; border: 0; background: none;
  font-family: inherit; text-align: left; cursor: pointer;
}
.cityitem + .cityitem { box-shadow: inset 0 1px 0 #efede8; }
.cityitem:active { background: var(--brand-soft); }
.cityitem b { font-size: 14px; font-weight: 600; color: var(--ink); }
.cityitem em { font-style: normal; font-size: 11.5px; color: var(--ink-3); }
.cityempty { padding: 14px; font-size: 13px; color: var(--ink-3); text-align: center; }
.citypick {
  margin-top: 10px; padding: 10px 14px; border-radius: 12px;
  background: var(--brand-soft); font-size: 13px; color: var(--brand);
}
.citypick b { font-weight: 600; }

/* 天气城市页顶上的"当前城市"。
   设备从来不上报这个值，只能直连问它；问到了就明写出来，
   用户点完保存跳回来能立刻确认生效，不用再跑去盯设备屏幕。 */
.wxnow {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 16px; padding: 12px 14px;
  border-radius: 14px; background: #faf9f7;
  box-shadow: inset 0 0 0 1.5px #efece6;
}
.wxnow-k { font-size: 12px; color: var(--ink-3); }
.wxnow b { font-size: 17px; font-weight: 600; color: var(--ink); letter-spacing: .2px; }
.wxnow em {
  font-style: normal; font-size: 11px; color: var(--ink-3);
  padding: 2px 8px; border-radius: 999px; background: #f0eee9;
}
/* 设备离线时的说明：用中性底不是警告红——读不到只说明它没联网，
   不代表设置错了，用红字会让人以为出了问题。 */
.wxwarn {
  margin-bottom: 16px; padding: 11px 13px;
  border-radius: 13px; background: #faf9f7;
  box-shadow: inset 0 0 0 1.5px #efece6;
  font-size: 12px; line-height: 1.6; color: var(--ink-2);
}

/* 固件升级 */
.fwwrap {
  padding: 14px; border-radius: 14px; margin-bottom: 4px;
  background: linear-gradient(135deg, #fff6f1, #fff);
  box-shadow: inset 0 0 0 1.5px rgba(242, 84, 27, .14);
}
.fwnew { font-size: 14px; color: var(--ink-2); }
.fwnew b { color: var(--brand); font-size: 18px; margin-left: 2px; }
.fwcur { font-size: 12.5px; color: var(--ink-3); margin-top: 3px; }
/* 「设备自报」徽标：明确告诉用户这个版本号是当场问设备拿的，
   不是服务器里那条可能过时的记录。 */
.fwlive {
  font-style: normal; font-size: 10.5px; color: #0c7a46;
  padding: 1px 7px; border-radius: 999px; background: var(--ok-soft);
  margin: 0 3px;
}
.fwnote { font-size: 13px; color: var(--ink-2); margin: 10px 0 0; line-height: 1.6; }

/* ==========================================================================
   ===== 功能模块入口（设备概览页） =====
   以前所有功能竖着堆在一页，手机上要滚七八屏，想调音量得先划过灯光和闹钟。
   现在概览页只放出口：两列方格，一屏看完有什么功能，点进去只管一件事。
   ========================================================================== */

.mods { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.mod {
  display: flex; align-items: center; gap: 10px;
  background: var(--card);
  border-radius: 18px;
  padding: 12px 11px;
  min-height: 66px;
  color: var(--ink);
  box-shadow: var(--shadow);
  transition: transform .14s ease, box-shadow .14s ease;
}
.mod:hover { text-decoration: none; box-shadow: var(--shadow-lift); }
.mod:active { transform: scale(.985); }
.modico {
  flex: 0 0 auto;
  width: 38px; height: 38px; border-radius: 13px;
  display: flex; align-items: center; justify-content: center;
}
.modico .ic { width: 20px; height: 20px; }
/* 一个模块一个浅底色，靠颜色区分，不用读字也能找到 */
.c-lamp    { background: #fff0e2; color: #f2541b; }
.c-screen  { background: #e8f1ff; color: #2f6fd0; }
.c-sound   { background: #eaf7ee; color: #17935a; }
.c-alarm   { background: #fff3e0; color: #d98209; }
.c-drink   { background: #e7f6fb; color: #1286a8; }
.c-weather { background: #fff6df; color: #b8830a; }
.c-update  { background: #f0ecff; color: #6b4fd8; }
.c-log     { background: #f1f2f5; color: #5e636d; }
.c-theme   { background: #f3edff; color: #6b4fd8; }
.c-clock   { background: #e8f1ff; color: #2f6fd0; }
.c-album   { background: #fdeef4; color: #d6457a; }

.modtx { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.modtx b {
  font-size: 13.5px; font-weight: 600;
  display: flex; align-items: center; gap: 5px;
}
.modtx em {
  font-style: normal; font-size: 11px; color: var(--ink-3); line-height: 1.4;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.modgo { flex: 0 0 auto; width: 14px; height: 14px; color: #ccd0d6; stroke-width: 2.2; }
.moddot { width: 6px; height: 6px; border-radius: 50%; background: var(--warn); display: inline-block; }

/* 功能页顶部的返回条：胶囊形，和底部菜单的圆角语言一致 */
/* 功能页顶部：左边一个圆形返回键，中间模块名，右边挂设备名（知道自己在哪台机器上） */
.featbar { display: flex; align-items: center; gap: 10px; padding: 14px 2px 12px; }
.fback {
  flex: 0 0 auto;
  width: 32px; height: 32px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--card); color: var(--ink-2);
  box-shadow: var(--shadow);
}
.fback:hover { color: var(--brand); }
.fback .ic { width: 16px; height: 16px; transform: rotate(180deg); stroke-width: 2.2; }
.fname {
  flex: 1 1 auto; min-width: 0;
  font-size: 17px; font-weight: 600; letter-spacing: .2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fdev {
  flex: 0 0 auto; max-width: 40%;
  font-size: 11.5px; color: var(--ink-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* 功能页顶上的一行"上次下发"。
   设备状态读不回来，这一行是唯一的参照物：让用户知道刚才那一按确实排进去了。 */
.lastcmd {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  margin: -2px 0 12px; padding: 8px 11px;
  background: var(--brand-soft); border-radius: var(--r-sm);
  font-size: 12px; color: var(--ink-2); line-height: 1.45;
}
.lastcmd-k { color: var(--ink-3); flex: 0 0 auto; }
.lastcmd b { font-weight: 600; color: var(--ink); min-width: 0; }
.lastcmd-t {
  margin-left: auto; flex: 0 0 auto;
  font-size: 11.5px; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* 一行开关：照小程序的做法，灯 / 时钟 / 相册各只给一个开关。
   以前是"开灯 + 关灯 + 开小夜灯 + 关小夜灯"四个方块，用户得先判断该点哪个。 */
.pwr { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.pwr-l { display: flex; align-items: center; gap: 11px; min-width: 0; }
.pwr-ico {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 12px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--brand-soft); color: var(--brand);
}
.pwr-ico .ic { width: 19px; height: 19px; }
.pwr-tx { min-width: 0; }
.pwr-tx b { display: block; font-size: 15px; font-weight: 600; letter-spacing: .2px; }
.pwr-tx p { margin: 3px 0 0; font-size: 11.5px; color: var(--ink-3); line-height: 1.45; }
.swform { flex: 0 0 auto; margin: 0; }

/* 表盘库：圆形缩略图（YOC 是圆屏），点一下推到设备 */
.faces { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 12px; }
.faceform { margin: 0; }
.facebtn {
  display: flex; flex-direction: column; align-items: center; gap: 9px;
  width: 100%; padding: 0; border: 0; background: none;
  font-family: inherit; color: inherit; cursor: pointer;
}
/* 表盘预览：这里只放与屏幕形状无关的部分（尺寸、居中、阴影）。
 * 圆角交给下面两个变体各自决定 —— 方屏和圆屏的样式物理分开，
 * 以后调圆屏的圆角碰不到方屏，反之亦然。 */
.face {
  width: 100%; aspect-ratio: 1 / 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .07), 0 4px 14px rgba(20, 22, 27, .1);
  transition: transform .12s ease;
}

/* 方屏：moc（ST7789 240×240）、ssd-tvz / sdd-clock（ST7789P3 1.54" 240×240）。
 * 18% 圆角是照设备外壳的圆角，不是正方的直角，也不是圆。 */
.face--square { border-radius: 18%; }

/* 圆屏：只有 yoc（GC9A01 240×240）是圆的。 */
.face--round { border-radius: 50%; }
.f-w { font-size: 9.5px; letter-spacing: .2px; }
.f-t { font-size: 23px; font-weight: 300; letter-spacing: .5px; line-height: 1;
       font-variant-numeric: tabular-nums; }
.f-d { font-size: 8.5px; letter-spacing: .2px; }
.face-n { font-size: 12.5px; font-weight: 500; color: var(--ink-2); }
.facebtn:active .face { transform: scale(.97); }
/* 正在用的那款：加一圈品牌色 + 名字变亮，跟"点了没反应"区分开 */
.facebtn.on .face { box-shadow: 0 0 0 3px var(--brand), 0 4px 14px rgba(242, 84, 27, .22); }
.facebtn.on .face-n { color: var(--brand); }
.facebtn.on .face-n::after { content: " · 使用中"; font-weight: 400; font-size: 11px; }

/* ===== 相册直传（浏览器 → 设备局域网） =====
   服务器在公网够不到设备，只有用户自己的浏览器和设备在同一个 WiFi 里，
   所以这一包由浏览器直接发给 192.168.x.x，不经过后台。 */
.upl { margin-top: 4px; }
.upl .fld { margin-bottom: 8px; }
.upl .fld .inp {
  font-family: ui-monospace, Menlo, Consolas, monospace;
  letter-spacing: .3px;
}
.upl > .btn { margin-top: 12px; }
.upl-prev {
  display: flex; align-items: center; gap: 12px;
  margin-top: 12px; padding: 10px;
  background: #faf9f7; border-radius: var(--r-sm);
}
.upl-prev canvas {
  flex: 0 0 auto; width: 56px; height: 56px;
  border-radius: 10px; background: #000; display: block;
}
.upl-tx { min-width: 0; }
.upl-tx b { display: block; font-size: 13.5px; font-weight: 500; }
.upl-tx em { font-style: normal; font-size: 11.5px; color: var(--ink-3); }
.upl-st { margin: 10px 0 0; font-size: 12.5px; line-height: 1.6; }
.upl-st:empty { display: none; }
.upl-st.ok { color: #0c7a46; }
.upl-st.bad { color: #b3301f; }
.upl .btn[disabled] { opacity: .5; }

/* 隐私说明：这块要让人一眼看到，所以给淡绿底 + 锁图标，和普通灰字提示区分开 */
.privacy {
  display: flex; gap: 9px;
  margin-top: 12px; padding: 11px 12px;
  background: #eef7f1;
  border-radius: var(--r-sm);
}
.privacy .ic { flex: 0 0 auto; width: 15px; height: 15px; color: #0c7a46; margin-top: 2px; }
.privacy b { display: block; font-size: 13px; font-weight: 600; color: #0a5f38; }
.privacy p {
  margin: 3px 0 0; font-size: 12px; line-height: 1.6;
  color: #3c6b52;
}

/* 这次传过的图：横排缩略图，纯前端内存，刷新即空 */
.upl-sent { margin-top: 14px; }
.upl-sent-cap {
  margin: 0 0 8px; font-size: 11.5px; color: var(--ink-3); line-height: 1.5;
}
.upl-grid { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 2px; }
.upl-thumb { flex: 0 0 auto; text-align: center; }
.upl-thumb canvas {
  width: 56px; height: 56px; display: block;
  border-radius: 10px; background: #000;
  box-shadow: 0 1px 3px rgba(20, 22, 27, .12);
}
.upl-thumb em {
  display: block; margin-top: 3px;
  font-style: normal; font-size: 10.5px; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* 窄屏（小屏安卓）一列，否则两列里文字全被挤成省略号 */
@media (max-width: 344px) {
  .mods { grid-template-columns: minmax(0, 1fr); }
}

/* 设备列表顶部的配额提示：标题在橙色头里，这里只留一行小字。
   内容区是负边距压上橙色的，这行是纯文字，得往下让出橙色区域，否则糊在橙底上看不清。 */
.devquota { font-size: 12.5px; color: var(--ink-3); margin: 20px 2px 10px; text-align: right; }

/* ===== 添加设备入口 =====
   设备列表页只留这一行，点了才进 /m/bind 填码。
   虚线框是移动端"加号位"的通用语言，一眼看出这不是一台已有设备。 */
.adddev {
  display: flex; align-items: center; gap: 12px;
  margin-top: 14px;
  padding: 15px 14px;
  background: var(--card);
  border: 1.5px dashed #ecd0bf;
  border-radius: 18px;
  color: var(--ink);
  transition: border-color .14s ease, background .14s ease;
}
.adddev:hover { text-decoration: none; border-color: var(--brand); background: #fffaf6; }
.adddev:active { transform: scale(.99); }
.adddev-ico {
  flex: 0 0 auto;
  width: 38px; height: 38px; border-radius: 13px;
  background: #fff0e2; color: var(--brand);
  display: flex; align-items: center; justify-content: center;
}
.adddev-ico .ic { width: 20px; height: 20px; stroke-width: 2.4; }
.adddev-tx { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.adddev-tx b { font-size: 14px; font-weight: 600; }
.adddev-tx em {
  font-style: normal; font-size: 11.5px; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ==========================================================================
   PC 宽屏（2026-11-10）
   --------------------------------------------------------------------------
   原来整站 .mapp 死守 480px，PC 上就是一根竖条贴在屏幕中间 —— 用 1440 的
   显示器打开注册页，看起来像把手机页面塞进了浏览器。
   这里分两种情况：
   1) 游客态（登录 / 注册）：左半边铺品牌渐变，右半边放表单卡，撑满整屏。
   2) 已登录态：仍然是单列，但宽度放开到 720，至少不像手机了。
   手机上 .gside 是 display:none，一个像素都不占，移动端布局完全没变。
   ========================================================================== */

.gside { display: none; }

@media (min-width: 900px) {
  /* ---------- 游客态：左右两栏 ---------- */
  body.is-guest { background: #fbfaf8; }

  body.is-guest .mapp {
    display: grid;
    grid-template-columns: minmax(360px, 43%) minmax(0, 1fr);
    grid-template-rows: 1fr auto;
    max-width: none;
    min-height: 100vh;
    background: #fbfaf8;
    box-shadow: none;
  }

  body.is-guest .gside {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    grid-column: 1;
    grid-row: 1 / -1;
    padding: 56px 52px 40px;
    background: linear-gradient(155deg, #ff8f55 0%, #f2541b 50%, #c23505 100%);
    color: #fff;
    overflow: hidden;
  }
  /* 两团柔光，别让整块橙色太死 */
  body.is-guest .gside::before,
  body.is-guest .gside::after {
    content: "";
    position: absolute;
    border-radius: 50%;
    background: rgba(255, 255, 255, .10);
    pointer-events: none;
  }
  body.is-guest .gside::before { width: 300px; height: 300px; left: -130px; top: -150px; }
  body.is-guest .gside::after { width: 560px; height: 560px; right: -230px; bottom: -300px; }

  .gside-in, .gside-foot { position: relative; z-index: 2; }

  body.is-guest .gside-logo {
    display: flex; align-items: center; justify-content: center;
    width: 54px; height: 54px; margin-bottom: 26px;
    border-radius: 17px;
    background: rgba(255, 255, 255, .18);
    border: 1px solid rgba(255, 255, 255, .3);
    font-size: 24px; font-weight: 600; letter-spacing: 1px;
  }
  body.is-guest .gside h2 {
    margin: 0 0 16px;
    font-size: 30px; font-weight: 700; letter-spacing: -.4px;
  }
  body.is-guest .gside-lead {
    margin: 0 0 34px;
    font-size: 15.5px; line-height: 1.85;
    color: rgba(255, 255, 255, .84);
  }
  body.is-guest .gside-list {
    list-style: none;
    margin: 0; padding: 0;
    display: flex; flex-direction: column; gap: 15px;
  }
  body.is-guest .gside-list li {
    display: flex; align-items: center; gap: 12px;
    font-size: 14px;
    color: rgba(255, 255, 255, .93);
  }
  body.is-guest .gside-list .ic {
    flex: 0 0 auto;
    width: 34px; height: 34px; padding: 7px;
    border-radius: 11px;
    background: rgba(255, 255, 255, .16);
    stroke-width: 1.7;
  }
  body.is-guest .gside-foot {
    margin: 40px 0 0;
    font-size: 12.5px;
    letter-spacing: 1.6px;
    color: rgba(255, 255, 255, .74);
  }

  /* 右栏：表单垂直居中，宽度锁在 460 左右，读起来是舒服的行长 */
  body.is-guest .mwrap {
    grid-column: 2;
    grid-row: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    width: 100%;
    max-width: 468px;
    margin: 0 auto;
    padding: 40px 24px 20px;
  }
  body.is-guest .mfoot {
    grid-column: 2;
    grid-row: 2;
    padding: 0 24px 28px;
  }

  /* 头图与卡片：PC 上留白松一点，圆角收一点，别像放大的手机截图 */
  body.is-guest .guest-head { padding: 0 0 24px; }
  body.is-guest .guest-logo {
    width: 56px; height: 56px; border-radius: 18px;
    margin-bottom: 16px; font-size: 24px;
  }
  body.is-guest .guest-head h1 { font-size: 26px; letter-spacing: -.3px; }
  body.is-guest .guest-head p { font-size: 13.5px; }
  body.is-guest .card {
    padding: 30px 32px 26px;
    border-radius: 20px;
    box-shadow: 0 1px 2px rgba(23, 26, 32, .04), 0 20px 44px -30px rgba(23, 26, 32, .32);
  }
  body.is-guest label { margin: 16px 0 8px; font-size: 13px; }
  body.is-guest .card form > label:first-child { margin-top: 0; }
  /* 16px 字号是给 iOS 防聚焦放大的，PC 上没必要这么大 */
  body.is-guest input:not([type]),
  body.is-guest input[type="text"],
  body.is-guest input[type="tel"],
  body.is-guest input[type="password"],
  body.is-guest input[type="email"] {
    padding: 14px 16px;
    font-size: 15px;
    border-width: 1.5px;
    border-color: #f2dbcd;
    border-radius: 13px;
  }
  body.is-guest .btn {
    margin-top: 26px;
    padding: 15px;
    border-radius: 13px;
    transition: transform .14s ease, box-shadow .14s ease, filter .14s ease;
  }
  body.is-guest .btn:hover {
    filter: brightness(1.04);
    box-shadow: 0 12px 26px rgba(242, 84, 27, .34);
    transform: translateY(-1px);
  }
  body.is-guest .mhint-sm { font-size: 12.5px; }
  body.is-guest .malt { margin-top: 16px; font-size: 13px; }
  body.is-guest .malt a:hover { text-decoration: underline; }

  /* ---------- 已登录态：单列但放开宽度 ----------
     640 而不是 720：再宽下去，账号页那种"左边字段名、右边数值"的行
     会拉出 500px 的空当，看着散。 */
  body:not(.is-guest) .mapp { max-width: 640px; }
  body:not(.is-guest) .tabbar { max-width: 640px; }
}

/* ===== 登录态 PC 宽屏：左侧栏 + 右侧内容 =====
 * 原来 ≥900 只把 .mapp 放到 640，于是在 1440 的屏幕上是一个竖条居中：
 * 两侧一大片灰，底部导航只占中间一截，看着像把手机页面贴进了浏览器。
 *
 * 这里不改任何 HTML，只用 grid 把已有的三个兄弟节点重新摆位：
 *   .hero（品牌+积分+标题） → 左栏顶部
 *   .tabbar（三个导航）      → 左栏中部，横排改竖排
 *   .mwrap（全部页面内容）   → 右栏，独占宽度
 *   .mfoot                   → 右栏底部
 * 游客态（.is-guest）走的是另一套双栏，这里用 body:not(.is-guest) 全部隔离，互不影响。
 */
@media (min-width: 1024px) {
  body:not(.is-guest) .mapp {
    display: grid;
    grid-template-columns: 276px minmax(0, 1fr);
    grid-template-rows: auto auto 1fr auto;
    max-width: 1240px;
    min-height: 100vh;
    /* 左栏浅底色 + 一条 1px 分割线，用渐变画：grid 没法给"某一列"单独上色，
       而左右同色时左栏下半段会悬空，看着像内容没排满。 */
    background-image: linear-gradient(to right,
      #fbfaf8 0px, #fbfaf8 275px,
      #eae8e3 275px, #eae8e3 276px,
      #fff 276px);
    box-shadow: 0 0 70px rgba(23, 26, 32, .08);
  }

  /* ---------- 左栏顶部：品牌区改成整块竖区 ---------- */
  body:not(.is-guest) .hero {
    grid-column: 1; grid-row: 1;
    padding: 30px 24px 26px;
    border-radius: 0;
  }
  /* 手机上品牌和积分是一左一右，竖栏里改成上下两行 */
  body:not(.is-guest) .hero-top {
    flex-direction: column; align-items: flex-start; gap: 16px;
  }
  body:not(.is-guest) .hero-brand { font-size: 16px; gap: 10px; }
  body:not(.is-guest) .logo { width: 34px; height: 34px; border-radius: 11px; font-size: 16px; }
  body:not(.is-guest) .hero-sub { font-size: 20px; margin-top: 22px; }
  body:not(.is-guest) .hero-pts { padding: 7px 14px; font-size: 13px; }
  body:not(.is-guest) .hero-pts b { font-size: 15px; }
  /* 两个白色光斑按手机上的比例摆，换到 276 宽的竖块里会全跑到框外 */
  body:not(.is-guest) .hero::after { width: 280px; height: 280px; right: -130px; top: -120px; }
  body:not(.is-guest) .hero::before { width: 160px; height: 160px; left: -70px; bottom: -80px; }

  /* 控制面板页用的 hero-mini 也一并拉起来，否则左栏只有一条细橙边 */
  body:not(.is-guest) .hero-mini { padding: 26px 24px 22px; border-radius: 0; }
  body:not(.is-guest) .hero-mini .hero-brand { font-size: 16px; gap: 10px; }

  /* ---------- 左栏中部：底部导航 → 左侧竖排菜单 ---------- */
  body:not(.is-guest) .tabbar {
    position: static;
    transform: none;
    left: auto; bottom: auto;
    grid-column: 1; grid-row: 2;
    width: 100%; max-width: none;
    height: auto;
    padding: 14px 14px 0;
    flex-direction: column;
    gap: 3px;
    /* 手机上是毛玻璃浮层，竖排进侧栏后不需要这些 */
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-top: 0;
    box-shadow: none;
  }
  body:not(.is-guest) .tabbar a {
    flex: none;
    flex-direction: row;
    justify-content: flex-start;
    gap: 11px;
    padding: 12px 14px;
    border-radius: 12px;
    font-size: 14px;
    font-weight: 500;
  }
  body:not(.is-guest) .tabbar a:hover { background: rgba(242, 84, 27, .07); }
  body:not(.is-guest) .tabbar a.on { background: rgba(242, 84, 27, .10); }
  body:not(.is-guest) .tabbar a .ic { width: 20px; height: 20px; }

  /* ---------- 右栏：内容区 ---------- */
  body:not(.is-guest) .mwrap {
    grid-column: 2;
    grid-row: 1 / 4;          /* 从顶栏一直占到页脚上一行 */
    /* -16px 是手机上让内容压住 hero 圆角的，这里是并排两栏，必须归零 */
    margin-top: 0;
    max-width: 820px;         /* 内容自己再收一道，避免行长拉到上千像素 */
    padding: 34px 40px 24px;
  }
  body:not(.is-guest) .mfoot {
    grid-column: 2; grid-row: 4;
    /* 88px 是给手机那根固定底栏让位的，PC 上导航已经在左边了 */
    padding: 16px 40px 22px;
    border-top: 1px solid var(--line);
    text-align: left;
  }
}

/* 更大的屏（>=1280）左栏再宽一点，右侧卡片字号略调，避免空旷 */
@media (min-width: 1280px) {
  body.is-guest .mapp { grid-template-columns: minmax(420px, 46%) minmax(0, 1fr); }
  body.is-guest .gside { padding: 68px 64px 48px; }
  body.is-guest .gside h2 { font-size: 34px; }
  body.is-guest .gside-lead { font-size: 16.5px; }
}

/* ===== 闹钟列表 =====
   设备上报的真实闹钟，一行一条。开关和删除都在行尾，
   手机上单行高度足够点，不用进二级页面。
   关掉的那条整体降透明度 + 时间不加粗：一眼能分出哪些还会响。 */
.alist { display: flex; flex-direction: column; gap: 8px; margin-bottom: 4px; }
.aitem {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--card);
}
/* 已关闭的项不再整行打 0.5 透明——那会把「删除」一起淡化到看不见。
   改成只淡化文字，按钮保持原样。 */
.aitem.aoff { background: var(--bg); }
.atime {
  font-size: 17px; font-weight: 600; letter-spacing: .3px;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.aitem.aoff .atime { font-weight: 500; color: var(--ink-3); }
.aitem.aoff .ameta b, .aitem.aoff .ameta span { color: var(--ink-3); }
.ameta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ameta b {
  font-size: 12.5px; font-weight: 500; color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ameta span { font-size: 11.5px; color: var(--ink-3); }
.aops { display: flex; gap: 6px; flex: none; }
.aops form { display: contents; }
.achip {
  border: 1px solid var(--line); background: transparent; color: var(--ink-2);
  font: inherit; font-size: 11.5px; line-height: 1;
  padding: 7px 9px; border-radius: 8px; cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.achip:hover { background: var(--bg); }
.achip.on { border-color: var(--brand); color: var(--brand); background: var(--brand-soft); }
/* 删除必须一眼看见：原来用 --ink-3 (#9aa0a9) 配 --line 边框，
   白卡片上等于隐身，用户反馈「根本没有删除按钮」。 */
.achip.adel { color: var(--warn); border-color: rgba(209, 59, 46, .32); }
.achip.adel:hover { color: #fff; border-color: var(--warn); background: var(--warn); }

/* ===== 窄屏防溢出（≤389px） =====
   机器码固定 19 个字符（D885-ACD5-7E40-019D），等宽字体下约 148px。
   设备卡一行里还要放 图标(52) + 箭头(18) + 解绑按钮(约 56) 和四处间距：
   390px 屏留给机器码约 164px，放得下；360px 只剩约 134px，文字会直接画到卡片圆角外面
   —— 这就是"换台窄屏手机机器码就超出框"的原因。
   临界点是 375px 屏（约 149px，跟 148px 只差 1px），字体一换就溢出，所以阈值取 389：
   390 及以上不动，375 及以下把解绑按钮挪到卡片下面一行，整宽让给机器码。 */
@media (max-width: 389px) {
  .devrow { flex-wrap: wrap; }
  .devrow .devcard { flex: 1 1 100%; }
  .unb { width: 100%; justify-content: flex-end; margin-top: 6px; }
  .unb button { height: 32px; border-radius: 999px; }
}

/* 兜底：码更长、或系统字号调得很大时，宁可省略号，也不许画到框外 */
.devmeta .mono { overflow: hidden; text-overflow: ellipsis; }
.devbar-code { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
