/* =============================================================
   艺格拼豆 · 基础样式与设计变量
   主题：蓝色系 · 支持浅色 / 深色（跟随系统 + 手动切换）
   ============================================================= */

/* ---------- 设计令牌：浅色（默认） ---------- */
:root {
  /* 背景与面 */
  --bg:            #F5F8FE;
  --bg-deep:       #EAEFFB;
  --surface:       #FFFFFF;
  --surface-2:     #EDF3FE;
  --surface-3:     #E1EAFB;
  --overlay:       rgba(10, 22, 45, .45);

  /* 文本 */
  --text:          #0F1B33;
  --text-2:        #5A6B8C;
  /* ⚠️ --text-3 用在小字上，且经常压在 --surface-2 / --surface-3 这类浅蓝底上：
     #62748F 压在 #E1EAFB 上只有 4.27:1（低于 WCAG AA 的 4.5），全站 60+ 处被判不达标。
     压深到 #556786 后：白底 5.7:1、#EDF3FE 上 5.1:1、#E1EAFB 上 4.7:1，全部达标。 */
  --text-3:        #556786;
  --text-invert:   #FFFFFF;
  /* P02 移动端排版角色令牌；按 2026-10-04 根目录 P01 基线核准，存量组件按后续计划迁移。 */
  --font-sans: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei",
               "Helvetica Neue", "Source Han Sans SC", "Noto Sans CJK SC", sans-serif;
  --type-display: 26px;
  --type-page-title: 22px;
  --type-section-title: 20px;
  --type-item-title: 16px;
  --type-body: 15px;
  --type-supporting: 13px;
  --line-display: 1.42;
  --line-page-title: 1.55;
  --line-section-title: 1.3;
  --line-item-title: 1.4;
  --line-body: 1.55;
  --line-supporting: 1.45;
  --tracking-display: -0.4px;
  --tracking-page-title: -0.3px;
  --font-weight-regular: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
  --font-weight-extrabold: 800;

  /* 浮层提示（半透明，不遮挡内容） */
  --toast-bg:      rgba(255, 255, 255, .84);
  --toast-fg:      #16233A;
  --toast-act-bg:  rgba(46, 107, 255, .14);

  /* 边框与分割 */
  --border:        #D9E4F7;
  --border-2:      #C3D3EE;

  /* 主色（蓝） */
  --primary:       #2E6BFF;
  --primary-strong:#1D4ED8;
  --primary-soft:  #E3EDFF;
  --primary-ghost: rgba(46, 107, 255, .10);
  --primary-grad:  linear-gradient(135deg, #3D7BFF 0%, #2E6BFF 55%, #1D5AE0 100%);

  /* 语义色 */
  --success:       #22C77B;
  --success-strong:#0B7A46;
  --success-soft:  #E4F8EE;
  --warning:       #F5A623;
  --warning-soft:  #FEF3E0;
  --warning-strong:#8A5A00;   /* 浅底上的警示「文字」色：--warning 直接当字用只有 1.9:1 */
  --danger:        #E8524D;
  --danger-strong: #B3261E;   /* 浅底上的危险「文字/小标签」色：--danger 直接当字用只有 3.28:1 */
  --danger-soft:   #FDEAE9;
  --info:          #7C6CE8;
  --info-soft:     #EEECFD;

  /* 画板专用 */
  --grid-1:        #B5D4F4;
  --grid-5:        #378ADD;
  --grid-10:       #185FA5;
  --board-bg:      #FBFCFD;
  --board-ruler:   #F3F4F6;
  --board-ruler-line: #D1D5DB;
  --board-blank:   #FFFFFF;

  /* P02 语义层级；旧阴影令牌供未迁移组件继续使用。 */
  --shadow-none: none;
  --shadow-subtle: var(--shadow-1);
  --shadow-overlay: var(--shadow-3);

  /* 阴影 */
  --shadow-1:      0 1px 2px rgba(16, 34, 71, .05), 0 2px 8px rgba(16, 34, 71, .05);
  --shadow-2:      0 4px 16px rgba(16, 34, 71, .09);
  --shadow-3:      0 12px 32px rgba(16, 34, 71, .14);
  --shadow-primary:0 6px 18px rgba(46, 107, 255, .28);

  /* 圆角 */
  --r-xs: 6px;
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 22px;
  --r-pill: 999px;
  /* P02 通用组件半径；旧 --r-xs 至 --r-xl 在页面迁移前保持兼容。 */
  --r-control: 12px;
  --r-button: 16px;
  --r-card: 20px;
  --r-featured: 22px;

  /* 控件高度四档：小 28 / 常规 34 / 中 38 / 触控热区 44（画板里的浮动按钮、工具栏都归到这一套） */
  --h-xs: 28px;
  --h-sm: 34px;
  --h-md: 38px;
  --h-lg: 44px;

  /* 间距 */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;
  --sp-10: 40px;
  --sp-12: 48px;
  --sp-16: 64px;

  /* 结构尺寸 */
  --nav-h: 52px;
  /* 页面（与顶栏/通告条内容）左右内边距：PC 端在 desktop.css 覆盖为 36px */
  --page-pad: 16px;
  /* 手机端底部导航：56 → 48（老板口径「占地方太多」，图标/文字同步等比缩小） */
  --tab-h: 48px;
  /* ⚠️ 只在「装到桌面/独立窗口」时才让出刘海与小白条：
     普通手机浏览器标签页里，有些浏览器（夸克/UC/部分安卓）会把
     env(safe-area-inset-top) 报成状态栏高度，于是顶部多出一条空白（老板反馈过）。 */
  --safe-b: 0px;
  --safe-t: 0px;
  --page-max: 520px;

  /* 动效曲线（老板给的三条）：
     --ease-out  先快后慢、末尾平稳 → 入场（弹窗、卡片、抽屉）
     --ease-in   先慢后快           → 离场（弹窗关闭、页面退出、toast 消失）
     --ease-mid  两头慢中间加速     → 位移 / 展开收起 / 页面切换
     --ease      保留原名（默认过渡用，与 --ease-mid 同值，避免老代码突变） */
  --ease: cubic-bezier(.4, 0, .2, 1);
  --ease-out: cubic-bezier(0, 0, .2, 1);
  --ease-in: cubic-bezier(.4, 0, 1, 1);
  --ease-mid: cubic-bezier(.4, 0, .2, 1);
  --dur: .22s;

  color-scheme: light;
}

/* 装到桌面 / 独立窗口（没有浏览器地址栏）时才让出刘海区与底部小白条；
   普通浏览器标签页里保持 0，否则顶栏上方会多出一条空白（老板反馈过）。 */
@media (display-mode: standalone), (display-mode: fullscreen), (display-mode: minimal-ui) {
  :root {
    --safe-b: env(safe-area-inset-bottom, 0px);
    --safe-t: env(safe-area-inset-top, 0px);
  }
}

/* ---------- 设计令牌：深色 ---------- */
:root[data-theme="dark"] {
  --bg:            #0B1220;
  --bg-deep:       #070D18;
  --surface:       #111C2E;
  --surface-2:     #16233A;
  --surface-3:     #1D2C46;
  --overlay:       rgba(2, 6, 14, .62);

  --text:          #E6EEFB;
  --text-2:        #94A6C4;
  --text-3:        #8798B8;   /* 深色底上的小字：原来的 #6B7D9C 在 --surface / --surface-2 上只有 4.1 / 3.77:1 */
  --text-invert:   #0B1220;

  /* 浮层提示：深色主题用深色半透明底 + 浅字 */
  --toast-bg:      rgba(23, 36, 58, .86);
  --toast-fg:      #EAF2FF;
  --toast-act-bg:  rgba(255, 255, 255, .16);

  --border:        #22344F;
  --border-2:      #2E4364;

  --primary:       #4D86FF;
  --primary-strong:#7AA8FF;
  --primary-soft:  #1B2C4D;
  --primary-ghost: rgba(77, 134, 255, .16);
  --primary-grad:  linear-gradient(135deg, #4D86FF 0%, #3B72F0 55%, #2C5CD6 100%);

  --success:       #35D98D;
  --success-strong:#35D98D;
  --success-soft:  #14311F;
  --warning:       #FFB742;
  --warning-soft:  #33260F;
  --warning-strong:#FFC97A;
  --danger:        #FF6B66;
  --danger-strong: #FF9B96;
  --danger-soft:   #38191A;
  --info:          #9A8CF5;
  --info-soft:     #241F45;

  --grid-1:        #2A4066;
  --grid-5:        #3E6DA8;
  --grid-10:       #6FA8E8;
  --board-bg:      #0F1B33;
  --board-ruler:   #1F2937;
  --board-ruler-line: #334155;
  --board-blank:   #16233A;

  --shadow-1:      0 1px 2px rgba(0, 0, 0, .3), 0 2px 8px rgba(0, 0, 0, .28);
  --shadow-2:      0 4px 16px rgba(0, 0, 0, .38);
  --shadow-3:      0 12px 32px rgba(0, 0, 0, .5);
  --shadow-primary:0 6px 18px rgba(45, 100, 220, .34);

  color-scheme: dark;
}

/* ---------- 重置 ---------- */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overscroll-behavior-y: none;
}

body {
  font-family: var(--font-sans);
  font-size: var(--type-body);
  line-height: var(--line-body);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--dur) var(--ease-mid), color var(--dur) var(--ease-mid);
}

h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img { max-width: 100%; display: block; border: 0; }
button, input, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; }
a { color: var(--primary); text-decoration: none; }
hr { border: 0; border-top: 1px solid var(--border); margin: var(--sp-4) 0; }
[hidden] { display: none !important; }

/* 去掉点击时的灰色方块高亮（移动端体验） */
* { -webkit-tap-highlight-color: transparent; }
button, .tap { touch-action: manipulation; }

/* ---------- 布局 ---------- */
/* 手机端跟手返回：页面跟手右移时加一点左侧阴影，像真的把页面推出去 */
.app-main.swiping {
  transform: translateX(var(--swipe-x, 0px));
  box-shadow: -14px 0 30px rgba(15, 27, 51, .2);
  will-change: transform;
}
.app-main.swiping * { user-select: none; }

/* 滚动条：**一根长杠都不画了**（老板 09-20：右边那条长杠不美观），
   改成右下角跟手的小指示器（见 ui.js 的 bindScrollPin / .scroll-pin）。
   槽位固定仍然保留：内容长短不同的页面来回切时不会左右抖。 */
html {
  overflow-y: scroll;
  scrollbar-gutter: stable;
  scrollbar-width: none;          /* Firefox */
  overscroll-behavior-y: contain; /* 关掉浏览器自带的「下拉刷新」，改用站内下拉刷新 */
}
html::-webkit-scrollbar { width: 0; height: 0; }

/* -------------------------------------------------------------
   滚动条策略（老板 09-20 二次调整）
   两端都**不画原生滚动条**，改用右下角那个「上下箭头小胶囊」指示器：
   滑动时出现、跟着滑动比例走、停手 0.9 秒自动隐藏（ui.js bindScrollPin）。
   ------------------------------------------------------------- */
/* ⚠️ `*` 不匹配根元素本身，必须把 :root 单独列出来，否则 html 上那条 `scrollbar-width: thin`
   （更早、优先级更低，但只有 html 选择器命中）仍会生效，手机上照样看得见那根杠 */
:root, :root * { scrollbar-width: none; -ms-overflow-style: none; }
:root::-webkit-scrollbar,
:root *::-webkit-scrollbar { width: 0 !important; height: 0 !important; }

/* 跟手的小指示器：一小截胶囊 + 上下两个小箭头，只在滑动时出现 */
.scroll-pin {
  position: fixed; right: 8px; top: 0; z-index: 240;
  width: 13px; height: 42px; padding: 5px 0;
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--text) 30%, transparent);
  box-shadow: 0 1px 5px rgba(16, 34, 71, .18);
  display: flex; flex-direction: column; align-items: center; justify-content: space-between;
  opacity: 0; transform: scale(.86);
  pointer-events: none;
  transition: opacity .2s var(--ease-out), transform .2s var(--ease-out);
}
.scroll-pin.on { opacity: 1; transform: none; }
.scroll-pin i {
  display: block; width: 0; height: 0;
  border-left: 3.5px solid transparent; border-right: 3.5px solid transparent;
}
/* 箭头用页面底色：浅色主题＝深底浅箭头，深色主题自动反过来 */
.scroll-pin .sp-up { border-bottom: 4.5px solid var(--bg); }
.scroll-pin .sp-dn { border-top: 4.5px solid var(--bg); }
/* 手机上浏览器自带滚动条，我们这个小胶囊只在电脑端出现（老板口径） */
:root[data-device="mobile"] .scroll-pin { display: none; }

#app { min-height: 100%; }

/* 并行淡入淡出的新旧页面叠放在同一网格单元，避免新页先排到旧页下方。 */
.route-stage { display: grid; grid-template-columns: minmax(0, 1fr); min-width: 0; }
.route-stage > * { grid-area: 1 / 1; }
.auth-bootstrap { display: flex; align-items: center; justify-content: center; gap: var(--sp-2); padding: var(--sp-16) var(--sp-4); color: var(--text-3); }
/* Grid 子项带左右 auto margin 时不会自动拉伸；显式撑满共享版心，再由各端 max-width 控制上限。 */
.route-stage > .page { width: 100%; }

.page {
  /* 页面顶部的品牌蓝网格由 ::before 承载，正文保持在其上方。 */
  position: relative; z-index: 1;
  /* ⚠️ 必须是 flow-root：否则首个子元素的 margin-top 会和 .page 发生外边距合并，
     把整个页面往下顶 16px —— 顶部渐隐就会「从卡片顶部才开始」而不是从导航栏下方开始 */
  display: flow-root;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: 0 var(--page-pad);
  /* 底部预留：Tab 栏 + 安全区 + 客服悬浮球不遮挡最后一行内容 */
  padding-bottom: calc(var(--tab-h) + var(--safe-b) + 76px);
}

/* 页面顶部淡蓝渐隐：往下淡出到屏幕的 1/3。
   z-index:-1 让它压在页面文字下面、又不被页面的背景盖住。 */
.page::before { content: none; }
:root[data-page="home"] .page::before,
:root[data-page="drawings"] .page::before,
:root[data-page="beadLibrary"] .page::before,
:root[data-page="templates"] .page::before,
:root[data-page="mine"] .page::before,
:root[data-page="settings"] .page::before,
:root[data-page="help"] .page::before,
:root[data-page="ai"] .page::before,
:root[data-page="about"] .page::before,
:root[data-page="feedback"] .page::before,
:root[data-page="legal"] .page::before {
  content: '';
  /* 桌面端保留内容列内的呼吸边距；触屏端在下方覆盖为满宽。 */
  position: absolute; left: 10px; right: 10px; top: 0;
  height: 33vh; z-index: -1; pointer-events: none;
  /* 拼豆网格从页首向内容区渐隐；低透明度也让不支持 mask 的浏览器保持克制。 */
  background:
    repeating-linear-gradient(0deg, transparent 0 17px, color-mix(in srgb, var(--primary) 3.5%, transparent) 17px 18px),
    repeating-linear-gradient(90deg, transparent 0 17px, color-mix(in srgb, var(--primary) 3.5%, transparent) 17px 18px),
    linear-gradient(180deg,
      color-mix(in srgb, var(--primary) 12%, transparent) 0%,
      color-mix(in srgb, var(--primary) 7%, transparent) 36%,
      color-mix(in srgb, var(--primary) 2%, transparent) 70%,
      transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, var(--text) 0%, var(--text) 24%, transparent 100%);
  mask-image: linear-gradient(180deg, var(--text) 0%, var(--text) 24%, transparent 100%);
}
/* 底部导航端让网格底色抵达屏幕两侧，正文边距仍由 .page 的 padding 控制。 */
:root[data-device="mobile"] .page::before { left: 0; right: 0; }
:root[data-theme="dark"][data-page="home"] .page::before,
:root[data-theme="dark"][data-page="drawings"] .page::before,
:root[data-theme="dark"][data-page="beadLibrary"] .page::before,
:root[data-theme="dark"][data-page="templates"] .page::before,
:root[data-theme="dark"][data-page="mine"] .page::before,
:root[data-theme="dark"][data-page="settings"] .page::before,
:root[data-theme="dark"][data-page="help"] .page::before,
:root[data-theme="dark"][data-page="ai"] .page::before,
:root[data-theme="dark"][data-page="about"] .page::before,
:root[data-theme="dark"][data-page="feedback"] .page::before {
  background:
    repeating-linear-gradient(0deg, transparent 0 17px, color-mix(in srgb, var(--primary) 4%, transparent) 17px 18px),
    repeating-linear-gradient(90deg, transparent 0 17px, color-mix(in srgb, var(--primary) 4%, transparent) 17px 18px),
    linear-gradient(180deg,
      color-mix(in srgb, var(--primary) 14%, transparent) 0%,
      color-mix(in srgb, var(--primary) 8%, transparent) 45%,
      color-mix(in srgb, var(--primary) 2%, transparent) 72%,
      transparent 100%);
}
/* 内容子页统一叠加一层轻柔蓝色渐变；全屏工作区继续使用自己的画布底色。 */
:root[data-page="templates"] .page::after,
:root[data-page="palette"] .page::after,
:root[data-page="exports"] .page::after,
:root[data-page="beadUsageRecords"] .page::after,
:root[data-page="beadCheck"] .page::after,
:root[data-page="settings"] .page::after,
:root[data-page="help"] .page::after,
:root[data-page="ai"] .page::after,
:root[data-page="about"] .page::after,
:root[data-page="feedback"] .page::after,
:root[data-page="legal"] .page::after {
  content: '';
  position: absolute; top: 0; left: 10px; right: 10px;
  height: min(58vh, 540px); z-index: -1; pointer-events: none;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--primary) 8%, transparent) 0%,
    color-mix(in srgb, var(--primary) 4%, transparent) 44%,
    transparent 100%);
}
/* 手机端内容区延伸至视口两侧，正文仍受 .page 内边距约束。 */
:root[data-device="mobile"] .page::after { left: 0; right: 0; }

/* 首页效果展示属于首屏叙事的一部分：沿用共享网格，只把渐隐范围延至展示卡底部。 */
:root[data-page="home"] .page::before { height: 620px; }

/* 电脑端：居中卡片式容器，两侧留白 */
:root[data-device="pc"] .page { max-width: 1100px; padding-bottom: var(--sp-8); }

.stack   { display: flex; flex-direction: column; gap: var(--sp-3); }
.stack-4 { display: flex; flex-direction: column; gap: var(--sp-4); }
.row     { display: flex; align-items: center; gap: var(--sp-2); }
.row-3   { display: flex; align-items: center; gap: var(--sp-3); }
.between { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.grow    { flex: 1 1 auto; min-width: 0; }
.center  { display: flex; align-items: center; justify-content: center; }

/* ---------- 文本 ---------- */
.t-title   { font-size: 19px; font-weight: 700; letter-spacing: -.2px; }
.t-sub     { font-size: 13px; color: var(--text-2); }
.t-hint    { font-size: 12px; color: var(--text-3); }
.t-strong  { font-weight: 600; }
.t-mono    { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }
.t-ellipsis{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.t-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.t-link    { color: var(--primary); font-weight: 500; }
/* 蓝色小字链接（如「忘记密码？」） */
.link-blue {
  color: var(--primary);
  font-size: 12.5px;
  font-weight: 500;
  text-decoration: none;
}
.link-blue:active { opacity: .7; }
.link-blue[disabled] { opacity: .45; pointer-events: none; }
.t-danger  { color: var(--danger); }
.t-success { color: var(--success); }
.t-warning { color: var(--warning-strong); }
.t-center  { text-align: center; }

.section-title {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: 15px; font-weight: 700;
  margin: var(--sp-6) 0 var(--sp-3);
}
.section-title::before {
  content: ""; width: 3px; height: 15px; border-radius: 2px;
  background: var(--primary);
}


/* 局部过渡：切页签/切品牌时只给「变化的那块内容」做一次淡入上移，标题与页头不动，
   用户一眼能看出是哪里变了（老板给的「文字局部过渡」） */
@keyframes swap-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.swap-in { animation: swap-in .22s var(--ease-out) both; }
/* 列表逐条错峰（最多 8 条，再多不叠加，避免太慢） */
.swap-in > * { animation: swap-in .24s var(--ease-out) both; }
.swap-in > *:nth-child(1) { animation-delay: .02s; }
.swap-in > *:nth-child(2) { animation-delay: .05s; }
.swap-in > *:nth-child(3) { animation-delay: .08s; }
.swap-in > *:nth-child(4) { animation-delay: .11s; }
.swap-in > *:nth-child(5) { animation-delay: .14s; }
.swap-in > *:nth-child(6) { animation-delay: .17s; }
.swap-in > *:nth-child(7) { animation-delay: .2s; }
.swap-in > *:nth-child(n+8) { animation-delay: .22s; }

/* ---------- 卡片 ---------- */
.card {
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--border) 76%, transparent);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-1);
}
.card-pad { padding: var(--sp-4); }
.card-flat { box-shadow: none; }

/* ---------- 按钮 ---------- */
button:focus-visible, a:focus-visible {
  outline: 2px solid var(--primary-strong);
  outline-offset: 2px;
}

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 44px; padding: 0 var(--sp-4);
  border-radius: var(--r-button);
  font-size: 15px; font-weight: 600;
  border: 1px solid transparent;
  transition: transform .14s var(--ease-mid), opacity .16s var(--ease-mid),
    background-color .16s var(--ease-mid), border-color .16s var(--ease-mid),
    box-shadow .16s var(--ease-mid), color .16s var(--ease-mid), filter .16s var(--ease-mid);
  user-select: none; white-space: nowrap;
}
.btn:active:not(:disabled):not([aria-disabled="true"]):not(.is-disabled) { transform: scale(.985); }
.btn:focus-visible { outline: 2px solid var(--primary-strong); outline-offset: 2px; }
.btn:disabled, .btn[aria-disabled="true"], .btn.is-disabled {
  opacity: .48; pointer-events: none; cursor: not-allowed;
  transform: none; box-shadow: none; filter: none;
}
.btn[aria-busy="true"] { cursor: progress; }
.btn[aria-busy="true"]::after {
  content: ''; flex: none; width: 13px; height: 13px;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  animation: p13-button-spin .8s linear infinite;
}
.btn[aria-busy="true"]:disabled { opacity: .74; }
@keyframes p13-button-spin { to { transform: rotate(1turn); } }

@media (hover: hover) and (pointer: fine) {
  .btn:not(:disabled):not([aria-disabled="true"]):not(.is-disabled):not([aria-busy="true"]):hover {
    filter: brightness(1.025);
  }
}

.btn-primary { background: var(--primary-grad); color: #fff; box-shadow: var(--shadow-primary); }
.btn-soft {
  /* 次要按钮：浅蓝实底（不要做成透明描边 —— 老板要求「比主按钮浅一点，但要有颜色」） */
  background: color-mix(in srgb, var(--primary) 14%, var(--surface));
  color: var(--primary-strong);
  border-color: color-mix(in srgb, var(--primary) 22%, transparent);
}
.btn-ghost   { background: transparent; border-color: var(--border-2); color: var(--text); }
.btn-plain   { background: var(--surface-2); color: var(--text); }
.btn-danger  { background: var(--danger-strong); color: #fff; }
:root[data-theme="dark"] .btn-danger { background: var(--danger); color: var(--bg); }
.btn-block   { width: 100%; }
.btn-sm      { height: 34px; padding: 0 var(--sp-3); font-size: 13px; border-radius: var(--r-control); }
.btn-lg      { height: 50px; font-size: 16px; border-radius: var(--r-button); }
.btn-icon    { width: 40px; height: 40px; padding: 0; border-radius: var(--r-md); }

.btn-row { display: flex; gap: var(--sp-3); }
.btn-row > .btn { flex: 1; }

/* ---------- 徽标 / 标签 ---------- */
.tag {
  display: inline-flex; align-items: center; gap: 4px;
  height: 22px; padding: 0 8px;
  font-size: 11px; font-weight: 600;
  border-radius: var(--r-xs);
  background: var(--surface-3); color: var(--text-2);
  white-space: nowrap;    /* 「客服回信」这种四字标签不能被挤成两行 */
}
.tag-primary { background: var(--primary-soft); color: var(--primary-strong); }
/* 软底标签的文字统一压深一档：原来直接用语义色，在白底软色上只有 ≈2:1，几乎看不清 */
.tag-success { background: var(--success-soft); color: #0B7A46; }
.tag-warning { background: var(--warning-soft); color: var(--warning-strong); }
.tag-danger  { background: var(--danger-soft);  color: #C0392B; }
.tag-info    { background: var(--info-soft);    color: #5344C7; }

.dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* 角标提示（未读数字） */
.badge {
  /* 原来是 top:-4px / right:-6px，44px 的按钮里直接被顶到顶栏边缘上，看着像贴边裁掉了；
     改成收进按钮右上角，仍压在铃铛的右上角上，但不再顶边 */
  position: absolute; top: 4px; right: 4px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: var(--r-pill);
  background: #D63A34; color: #fff;   /* 比 --danger 深一档：白字小红点也要达到可读对比度 */
  font-size: 11px; font-weight: 700; line-height: 16px; text-align: center;
  box-shadow: 0 0 0 2px var(--surface);
}

/* ---------- 表单 ---------- */
.field { display: flex; flex-direction: column; gap: 6px; }
.field-label { font-size: 13px; font-weight: 600; color: var(--text-2); }
/* 表单错误提示（如反馈命中违禁词）：贴在输入框正下方，红字 */
.field-err { margin: 6px 0 0; font-size: 12px; font-weight: 600; color: var(--danger-strong); line-height: 1.6; }
/* 常驻的输入提示（如反馈字数）：够字了变绿，用户不用点提交才知道规则 */
.field-hint { margin: 6px 0 0; font-size: 12px; color: var(--text-3); line-height: 1.6; }
.field-hint.ok { color: var(--success-strong); font-weight: 600; }

.input, .textarea, .select {
  width: 100%; height: 46px; padding: 0 var(--sp-3);
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--r-md);
  font-size: 16px;                     /* ≥16px：避免 iOS 聚焦时自动放大 */
  color: var(--text);
  outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.textarea { height: auto; min-height: 96px; padding: 10px var(--sp-3); resize: vertical; line-height: 1.6; }
.input:focus, .textarea:focus, .select:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-ghost);
}
.input::placeholder, .textarea::placeholder { color: var(--text-3); }
.input.is-success, .textarea.is-success, .select.is-success { border-color: var(--success-strong); }
.input.is-success:focus, .textarea.is-success:focus, .select.is-success:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--success) 18%, transparent);
}
.input.is-error, .textarea.is-error, .select.is-error,
.input[aria-invalid="true"], .textarea[aria-invalid="true"], .select[aria-invalid="true"] {
  border-color: var(--danger-strong);
}
.input.is-error:focus, .textarea.is-error:focus, .select.is-error:focus,
.input[aria-invalid="true"]:focus, .textarea[aria-invalid="true"]:focus, .select[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 18%, transparent);
}

/* 滑动条（网格线间隔等） */
.slider {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 4px; border-radius: 2px;
  background: var(--surface-3); outline: none;
}
.slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 22px; height: 22px; border-radius: 50%;
  background: #fff; border: 3px solid var(--primary);
  box-shadow: var(--shadow-1); cursor: pointer;
}
.slider::-moz-range-thumb {
  width: 22px; height: 22px; border-radius: 50%;
  background: #fff; border: 3px solid var(--primary); cursor: pointer;
}

/* 开关 */
.switch {
  position: relative; flex: none;
  width: 46px; height: 27px; border-radius: var(--r-pill);
  background: var(--surface-3);
  transition: background-color .18s var(--ease-mid);
}
.switch::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 21px; height: 21px; border-radius: 50%;
  background: #fff; box-shadow: var(--shadow-1);
  transition: transform .2s var(--ease-mid);
}
.switch.on { background: var(--primary); }
.switch.on::after { transform: translateX(19px); }

/* 左右滑动式二选一切换（画布 ⇄ 底图、本地 ⇄ 云端） */
.seg {
  position: relative; display: inline-flex;
  background: var(--surface-3); border-radius: var(--r-pill);
  padding: 3px;
}
.seg-slider {
  position: absolute; top: 3px; left: 3px;
  height: calc(100% - 6px);
  border-radius: var(--r-pill);
  background: var(--surface);
  box-shadow: var(--shadow-1);
  transition: transform .28s var(--ease-mid), width .28s var(--ease-mid);
  pointer-events: none;
}
.seg-item {
  position: relative; z-index: 1;
  padding: 0 14px; height: 30px;
  display: inline-flex; align-items: center;
  font-size: 13px; font-weight: 600; color: var(--text-2);
  transition: color .18s;
}
.seg-item.on { color: var(--primary-strong); }

/* ---------- 分割与占位 ---------- */
.divider { height: 1px; background: var(--border); }
.spacer-8 { height: 8px; } .spacer-16 { height: 16px; } .spacer-24 { height: 24px; }

.empty {
  padding: var(--sp-8) var(--sp-4);
  text-align: center; color: var(--text-3);
}
.empty-icon { font-size: 40px; opacity: .5; }

/* ---------- 骨架屏 ---------- */
.skeleton {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 37%, var(--surface-2) 63%);
  background-size: 400% 100%;
  animation: skeleton 1.3s ease infinite;
  border-radius: var(--r-sm);
}
@keyframes skeleton { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ---------- 通用动画 ---------- */
@keyframes fade-in   { from { opacity: 0 } to { opacity: 1 } }
/* 首屏外壳快速淡入；首页快捷入口与主要功能按组沿同一曲线轻上移。 */
.page-enter { animation: fade-in var(--dur) var(--ease-out) both; }
.home-enter { animation: page-enter var(--dur) var(--ease-out) both; }
.home-enter--quick { animation-delay: .06s; }
.home-enter--features { animation-delay: .12s; }
@keyframes page-enter { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes slide-up  { from { transform: translateY(14px); opacity: 0 } to { transform: none; opacity: 1 } }
@keyframes slide-down{ from { transform: translateY(-10px); opacity: 0 } to { transform: none; opacity: 1 } }
@keyframes pop-in    { from { transform: scale(.94); opacity: 0 } to { transform: none; opacity: 1 } }
/* 轻提示入场：只做「自上而下 8px + 淡入」。
   ⚠️ 这里原来带着 translate(-50%)（那是给 .toast-wrap 自己居中的），
   但 .toast 是 wrap 里的 flex 子项、不再需要横移 —— 结果第 4 条提示（新进场那条）
   会被整体左移半个身位，看起来「错位」。 */
@keyframes toast-in  { from { transform: translateY(-8px); opacity: 0 } to { transform: none; opacity: 1 } }

.fade-enter-active { transition: opacity .2s var(--ease-out); }
.fade-leave-active { transition: opacity .16s var(--ease-in); }
.fade-enter-from, .fade-leave-to { opacity: 0; }

/* 页面切换：入场用缓出、离场用缓入（走掉更干脆） */
.vs-enter-active { transition: opacity .22s var(--ease-out), transform .22s var(--ease-out); }
.vs-leave-active { transition: opacity .18s var(--ease-in), transform .18s var(--ease-in); }
.vs-enter-from { opacity: 0; transform: translateY(8px); }
.vs-leave-to   { opacity: 0; transform: translateY(-6px); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
