/* ═══════════════════════════════════════════════════════════
   牛马低价出行 · 样式
   三模块各自主题：目的地雷达 / 价格日历 / 周末出走
   浅色底 + 深色字，动效随模块换色
   ═══════════════════════════════════════════════════════════ */

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

:root {
  --bg: #f3f6fb;
  --surface: #ffffff;
  --surface-2: #f7f9fc;
  --surface-3: #eef2f9;
  --line: #e3e9f3;
  --line-2: #d5deec;
  --text: #0d1728;
  --text-2: #556783;
  --text-3: #8b9ab3;

  --a1: #06b6d4;
  --a2: #2563eb;
  --a3: #22d3ee;
  --glow: 6, 182, 212;

  --ok: #059669;
  --warn: #d97706;
  --err: #dc2626;

  --r: 16px;
  --r-sm: 10px;
  --sh-1: 0 1px 2px rgba(13, 23, 40, .04), 0 6px 18px -12px rgba(13, 23, 40, .16);
  --sh-2: 0 2px 6px rgba(13, 23, 40, .06), 0 18px 40px -18px rgba(13, 23, 40, .22);
  --ease: cubic-bezier(.22, .68, .36, 1);
  --font: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Segoe UI', Roboto, sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
}

/* ── 三套模块主题色 ─────────────────────────── */
body[data-module="radar"]    { --a1: #06b6d4; --a2: #2563eb; --a3: #22d3ee; --glow: 6, 182, 212; }
body[data-module="calendar"] { --a1: #8b5cf6; --a2: #4f46e5; --a3: #a78bfa; --glow: 139, 92, 246; }
body[data-module="weekend"]  { --a1: #f97316; --a2: #ef4444; --a3: #fbbf24; --glow: 249, 115, 22; }

html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font);
  color: var(--text);
  background: var(--bg);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  transition: background .6s var(--ease);
}

h1, h2, h3, p { margin: 0; }
button, select, input { font-family: inherit; font-size: inherit; color: inherit; }
button { cursor: pointer; border: none; background: none; }
code { font-family: var(--mono); font-size: .88em; background: var(--surface-3); padding: 1px 5px; border-radius: 5px; }

.wrap { width: min(1200px, calc(100% - 40px)); margin: 0 auto; }

/* ═══════════ 背景极光 ═══════════ */
.aurora { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.aurora .orb {
  position: absolute; border-radius: 50%; filter: blur(70px);
  opacity: .5; transition: background 1s var(--ease);
}
.aurora .o1 { width: 46vw; height: 46vw; left: -12vw; top: -14vw; background: radial-gradient(circle, var(--a1), transparent 68%); animation: drift1 26s ease-in-out infinite; }
.aurora .o2 { width: 40vw; height: 40vw; right: -10vw; top: 4vw; background: radial-gradient(circle, var(--a2), transparent 68%); animation: drift2 32s ease-in-out infinite; }
.aurora .o3 { width: 34vw; height: 34vw; left: 34vw; bottom: -16vw; background: radial-gradient(circle, var(--a3), transparent 68%); animation: drift3 38s ease-in-out infinite; }
.aurora .mesh {
  position: absolute; inset: 0;
  background-image: linear-gradient(rgba(13,23,40,.028) 1px, transparent 1px), linear-gradient(90deg, rgba(13,23,40,.028) 1px, transparent 1px);
  background-size: 46px 46px;
  mask-image: radial-gradient(ellipse 90% 60% at 50% 0%, #000 25%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 90% 60% at 50% 0%, #000 25%, transparent 78%);
}
@keyframes drift1 { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(6vw, 5vw) scale(1.14); } }
@keyframes drift2 { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(-7vw, 7vw) scale(1.1); } }
@keyframes drift3 { 0%,100% { transform: translate(0,0) scale(1); } 50% { transform: translate(5vw, -6vw) scale(1.16); } }

/* ═══════════ 顶栏 ═══════════ */
.topbar { position: relative; z-index: 3; padding: 22px 0 6px; }
.topbar-in { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
.brand { display: flex; align-items: center; gap: 13px; }
.brand-mark {
  width: 46px; height: 46px; display: grid; place-items: center; border-radius: 14px; color: #fff;
  background: linear-gradient(135deg, var(--a1), var(--a2));
  box-shadow: 0 10px 24px -10px rgba(var(--glow), .8);
  transition: background .6s var(--ease);
}
.brand-mark svg { width: 25px; height: 25px; }
.brand-txt h1 { font-size: 21px; font-weight: 700; letter-spacing: -.3px; }
.brand-sub { font-size: 12.5px; color: var(--text-2); margin-top: 2px; }

.top-right { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.loc-btn {
  display: inline-flex; align-items: center; gap: 7px; padding: 8px 13px; border-radius: 999px;
  background: rgba(255,255,255,.78); border: 1px solid var(--line); color: var(--text-2);
  font-size: 12.5px; backdrop-filter: blur(10px); transition: all .25s var(--ease);
}
.loc-btn:hover { border-color: rgba(var(--glow), .55); color: var(--text); box-shadow: 0 6px 18px -10px rgba(var(--glow), .9); transform: translateY(-1px); }
.loc-btn .pin { width: 15px; height: 15px; color: var(--a1); display: grid; place-items: center; }
.loc-btn .pin svg { width: 15px; height: 15px; }

/* ── 帮助按钮：引导只自动弹一次，之后靠它随时重开 ── */
.help-btn {
  width: 32px; height: 32px; flex: none; display: grid; place-items: center;
  border-radius: 50%; background: rgba(255,255,255,.78); border: 1px solid var(--line);
  color: var(--text-2); font-size: 15px; line-height: 1; font-weight: 600;
  backdrop-filter: blur(10px); transition: all .25s var(--ease);
}
.help-btn:hover { border-color: rgba(var(--glow), .55); color: var(--a2); transform: translateY(-1px); }

/* ── 分步引导（coach mark） ── */
.tour { position: fixed; inset: 0; z-index: 95; }
.tour[hidden] { display: none; }

/* 四块遮罩围出高亮洞：洞以外照常挡点击，洞内不挡，所以用户能直接点目标 */
.t-veil { position: fixed; background: rgba(15,23,42,.52); transition: all .28s var(--ease); }
.t-ring {
  position: fixed; border-radius: 10px; pointer-events: none;
  box-shadow: 0 0 0 2px var(--a1), 0 0 0 6px rgba(var(--glow), .28);
  transition: all .28s var(--ease);
}

.t-bubble {
  position: fixed; width: min(330px, calc(100vw - 24px));
  background: var(--surface); border: 1px solid var(--line); border-radius: 13px;
  padding: 13px 15px 12px; box-shadow: 0 18px 44px -16px rgba(15,23,42,.55);
  transition: top .28s var(--ease), left .28s var(--ease);
}
.t-bubble[hidden] { display: none; }
.t-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.t-step { font-size: 11px; font-family: var(--mono); color: var(--text-3); }
.t-x {
  border: 0; background: none; color: var(--text-3); font-size: 11.5px;
  padding: 2px 4px; cursor: pointer; border-radius: 6px; transition: color .2s var(--ease);
}
.t-x:hover { color: var(--text); }
.t-title { margin-top: 7px; font-size: 13.5px; font-weight: 650; }
.t-text { margin-top: 4px; font-size: 12.5px; color: var(--text-2); line-height: 1.65; }
.t-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 11px; }
.t-hint { font-size: 11.5px; color: var(--a2); }
.t-next {
  padding: 7px 15px; border-radius: 9px; border: 0; cursor: pointer;
  background: linear-gradient(135deg, var(--a1), var(--a2)); color: #fff;
  font-size: 12.5px; font-weight: 650; transition: transform .2s var(--ease), opacity .2s var(--ease);
}
.t-next:hover { transform: translateY(-1px); }
.t-next[disabled] { opacity: .45; cursor: default; transform: none; }

/* 开场卡 */
.t-intro {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(430px, calc(100vw - 32px)); background: var(--surface);
  border: 1px solid var(--line); border-radius: 16px; padding: 20px 22px 18px;
  box-shadow: 0 24px 60px -20px rgba(15,23,42,.5);
}
.t-intro[hidden] { display: none; }
.t-intro h2 { margin: 0; font-size: 15.5px; font-weight: 700; letter-spacing: -.2px; }
.t-intro p { margin: 8px 0 0; font-size: 12.5px; color: var(--text-2); line-height: 1.7; }
.t-intro-note {
  margin-top: 13px; padding: 10px 12px; border-radius: 10px;
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: 12px; color: var(--text-2); line-height: 1.7;
}
.t-intro-note code {
  font-family: var(--mono); font-size: 11.5px; padding: 1px 5px; border-radius: 5px;
  background: rgba(var(--glow), .12); color: var(--a2);
}
.t-intro-note b { font-weight: 650; color: var(--text); }
.t-start {
  margin-top: 15px; width: 100%; padding: 11px; border-radius: 10px; border: 0; cursor: pointer;
  background: linear-gradient(135deg, var(--a1), var(--a2)); color: #fff;
  font-size: 13.5px; font-weight: 650; transition: transform .2s var(--ease);
}
.t-start:hover { transform: translateY(-1px); }

.status {
  display: inline-flex; align-items: center; gap: 7px; padding: 8px 13px; border-radius: 999px;
  background: rgba(255,255,255,.78); border: 1px solid var(--line); font-size: 12.5px; color: var(--text-2);
  backdrop-filter: blur(10px);
}
.status .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text-3); }
.status.ok .dot { background: var(--ok); box-shadow: 0 0 0 0 rgba(5,150,105,.55); animation: pulseDot 2.2s infinite; }
.status.err .dot { background: var(--err); }
@keyframes pulseDot { 0% { box-shadow: 0 0 0 0 rgba(5,150,105,.5); } 70% { box-shadow: 0 0 0 7px rgba(5,150,105,0); } 100% { box-shadow: 0 0 0 0 rgba(5,150,105,0); } }

/* ═══════════ 模块切换器 ═══════════ */
main { position: relative; z-index: 2; padding-bottom: 40px; }

.mods {
  position: relative; display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
  margin: 18px 0 16px; padding: 7px; border-radius: 20px;
  background: rgba(255,255,255,.72); border: 1px solid var(--line);
  backdrop-filter: blur(14px); box-shadow: var(--sh-1);
}
.mod-pill {
  position: absolute; top: 7px; left: 7px; height: calc(100% - 14px); border-radius: 14px; z-index: 0;
  background: linear-gradient(135deg, rgba(var(--glow), .14), rgba(var(--glow), .05));
  border: 1px solid rgba(var(--glow), .38);
  box-shadow: 0 8px 22px -14px rgba(var(--glow), 1), inset 0 0 0 1px rgba(255,255,255,.5);
  transition: transform .48s var(--ease), width .48s var(--ease), background .6s var(--ease), border-color .6s var(--ease);
}
.mod {
  position: relative; z-index: 1; display: flex; align-items: center; gap: 12px; text-align: left;
  padding: 13px 15px; border-radius: 14px; color: var(--text-2);
  transition: color .3s var(--ease), transform .3s var(--ease);
}
.mod:hover { transform: translateY(-1px); color: var(--text); }
.mod.active { color: var(--text); }
.m-ico {
  width: 38px; height: 38px; flex: 0 0 38px; display: grid; place-items: center; border-radius: 11px;
  background: var(--surface-3); color: var(--text-3); transition: all .35s var(--ease);
}
.m-ico svg { width: 20px; height: 20px; }
.mod.active .m-ico {
  background: linear-gradient(135deg, var(--a1), var(--a2)); color: #fff;
  box-shadow: 0 8px 20px -9px rgba(var(--glow), .95);
}
.m-txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.m-txt b { font-size: 14.5px; font-weight: 650; letter-spacing: -.2px; }
.m-txt em { font-style: normal; font-size: 11.5px; color: var(--text-3); line-height: 1.35; }
.mod.active .m-txt em { color: var(--text-2); }
.m-idx {
  margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--text-3);
  opacity: .55; transition: all .35s var(--ease);
}
.mod.active .m-idx { color: var(--a1); opacity: 1; }

/* ═══════════ 面板与入场动效 ═══════════ */
.panel { display: flex; flex-direction: column; gap: 14px; }
.panel.enter > * { animation: panelIn .52s var(--ease) both; }
.panel.enter > *:nth-child(1) { animation-delay: .02s; }
.panel.enter > *:nth-child(2) { animation-delay: .08s; }
.panel.enter > *:nth-child(3) { animation-delay: .14s; }
.panel.enter > *:nth-child(4) { animation-delay: .2s; }
/* ⚠️ 结束关键帧里绝对不要写 filter / transform（哪怕写 none 的等价值，如 blur(0)）。
   animation-fill-mode: both 会把结束态一直挂在元素上，而 filter 只要不是 none
   就会给这张卡片造出一个堆叠上下文 —— 卡片内下拉层的 z-index 会被彻底封死，
   直接表现为「输入框的候选弹窗被下面那张卡片盖住」。省略即回落到元素自身的值（none）。 */
@keyframes panelIn {
  from { opacity: 0; transform: translateY(14px) scale(.985); filter: blur(6px); }
  to   { opacity: 1; }
}

/* ═══════════ 卡片与表单 ═══════════ */
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: var(--sh-1); padding: 16px;
}
.wrap-bar { flex-wrap: wrap; }

.bar { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; }
.field { display: flex; flex-direction: column; gap: 6px; flex: 1 1 180px; min-width: 0; }
.field.narrow { flex: 0 0 108px; }
.fl { font-size: 11.5px; font-weight: 600; color: var(--text-3); letter-spacing: .3px; }
.field select {
  appearance: none; width: 100%; padding: 11px 34px 11px 13px; border-radius: var(--r-sm);
  border: 1px solid var(--line-2); background: var(--surface-2) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b9ab3' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 11px center / 15px;
  font-size: 14px; transition: all .22s var(--ease);
}
.field select:hover { border-color: var(--line-2); background-color: #fff; }
.field select:focus { outline: none; border-color: var(--a1); background-color: #fff; box-shadow: 0 0 0 3.5px rgba(var(--glow), .16); }
.actions { flex: 0 0 auto; flex-direction: row; align-items: flex-end; gap: 8px; }

/* ═══════════ 可输入城市选择器（combobox） ═══════════ */
.combo { position: relative; width: 100%; }
.combo.open .combo-input { border-color: var(--a1); background-color: #fff; }
.combo-input {
  width: 100%; padding: 11px 34px 11px 13px; border-radius: var(--r-sm);
  border: 1px solid var(--line-2); background: var(--surface-2);
  font-size: 14px; font-weight: 600; letter-spacing: -.2px;
  transition: all .22s var(--ease);
}
.combo-input::placeholder { font-weight: 400; color: var(--text-3); letter-spacing: 0; }
.combo-input:hover { background-color: #fff; }
.combo-input:focus { outline: none; border-color: var(--a1); background-color: #fff; box-shadow: 0 0 0 3.5px rgba(var(--glow), .16); }
.combo-input.bad { border-color: rgba(220, 38, 38, .55); box-shadow: 0 0 0 3.5px rgba(220, 38, 38, .1); }
.combo-value { display: none; }
.combo-clear {
  position: absolute; right: 9px; top: 50%; transform: translateY(-50%);
  width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
  background: var(--surface-3); color: var(--text-3); transition: all .2s var(--ease);
}
.combo-clear:hover { background: rgba(var(--glow), .16); color: var(--a2); }
.combo-clear svg { width: 11px; height: 11px; }
/* 候选层是挂在 <body> 下的浮层（portal，由 app.js 搬过去），不是卡片里的绝对定位块。
   用 position: fixed 以视口坐标定位 → 不属于任何卡片，因此不受任何祖先的堆叠上下文
   （动画的 filter/transform、backdrop-filter、main 的 z-index）或 overflow 裁切影响，
   天然压在整个页面之上。left / top / width / max-height 由 app.js 按输入框 rect 实时写入。
   ⚠️ 不要再把它挪回 .combo 里面 —— 那样 z-index 会被祖先的堆叠上下文封死，
      表现为「候选弹窗被下面那张结果卡片盖住」。 */
.combo-list {
  position: fixed; left: 0; top: 0; z-index: 9999;
  max-height: 308px; overflow-y: auto; overscroll-behavior: contain; padding: 6px;
  background: #fff; border: 1px solid var(--line-2); border-radius: 13px;
  box-shadow: 0 20px 44px -18px rgba(13, 23, 40, .34), 0 2px 6px rgba(13, 23, 40, .05);
  animation: comboIn .17s var(--ease) both;
}
.combo-list::-webkit-scrollbar { width: 9px; }
.combo-list::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 9px; border: 2px solid #fff; }
@keyframes comboIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
.combo-hint { padding: 5px 10px 6px; font-size: 10.5px; color: var(--text-3); letter-spacing: .3px; }
/* 分组标题：空输入时列表是「热门 / 国内 / 国际·地区」三段全量城市，需要分隔 */
.ci-group {
  position: sticky; top: -6px; z-index: 1;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin: 2px 0; padding: 5px 10px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .6px; color: var(--text-3);
  background: #fff; border-bottom: 1px solid var(--line);
}
.ci-group:first-child { margin-top: 0; }
.ci-group b { font-family: var(--mono); font-weight: 600; font-size: 10px; }
.ci-group + .ci { margin-top: 2px; }
.ci {
  display: flex; align-items: center; gap: 9px; padding: 8px 10px; border-radius: 9px;
  cursor: pointer; transition: background .14s var(--ease);
}
.ci:hover, .ci.on { background: rgba(var(--glow), .1); }
.ci.on { box-shadow: inset 0 0 0 1px rgba(var(--glow), .32); }
.ci-main { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 8px; }
.ci-name { font-size: 13.5px; font-weight: 650; letter-spacing: -.2px; }
.ci-sub { font-size: 11.5px; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ci-code { font-family: var(--mono); font-size: 11px; color: var(--text-3); background: var(--surface-3); padding: 2px 6px; border-radius: 5px; flex: 0 0 auto; }
.ci-cur { font-size: 10.5px; font-weight: 700; color: var(--a2); flex: 0 0 auto; white-space: nowrap; }
.ci-reg { font-size: 10.5px; font-weight: 600; padding: 2px 6px; border-radius: 5px; flex: 0 0 auto; white-space: nowrap; }
.ci-reg.dom { background: rgba(6, 182, 212, .13); color: #0e7490; }
.ci-reg.reg { background: rgba(249, 115, 22, .15); color: #c2410c; }
.ci-reg.intl { background: rgba(139, 92, 246, .13); color: #6d28d9; }
/* 「暂无数据」：城市码是对的，但携程侧查不到航班。提前标出来，别让用户白点一次。 */
.ci-nodata { font-size: 10.5px; font-weight: 600; padding: 2px 6px; border-radius: 5px; flex: 0 0 auto; white-space: nowrap; background: rgba(100, 116, 139, .14); color: #475569; }
.combo-empty { padding: 15px 12px; text-align: center; font-size: 12.5px; color: var(--text-3); line-height: 1.65; }
.combo-empty b { color: var(--text-2); }

.btn {
  padding: 11px 20px; border-radius: var(--r-sm); font-size: 13.5px; font-weight: 600;
  border: 1px solid transparent; display: inline-flex; align-items: center; gap: 7px;
  transition: all .24s var(--ease); white-space: nowrap;
}
.btn.primary {
  color: #fff; background: linear-gradient(135deg, var(--a1), var(--a2));
  box-shadow: 0 10px 24px -12px rgba(var(--glow), 1);
}
.btn.primary:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 16px 30px -12px rgba(var(--glow), 1); }
.btn.primary:active:not(:disabled) { transform: translateY(0); }
.btn.ghost { background: var(--surface-2); border-color: var(--line-2); color: var(--text-2); }
.btn.ghost:hover:not(:disabled) { background: #fff; color: var(--text); border-color: rgba(var(--glow), .5); }
.btn:disabled { opacity: .55; cursor: not-allowed; }

/* 分段控件 */
.seg { display: inline-flex; gap: 3px; padding: 4px; border-radius: 12px; background: var(--surface-3); }
.seg .sg {
  padding: 8px 14px; border-radius: 9px; font-size: 13px; color: var(--text-2);
  transition: all .26s var(--ease); display: flex; flex-direction: column; align-items: center; gap: 2px;
}
.seg .sg b { font-weight: 600; font-size: 13px; }
.seg .sg em { font-style: normal; font-size: 10.5px; color: var(--text-3); }
.seg .sg:hover { color: var(--text); }
.seg .sg.active {
  background: #fff; color: var(--text); box-shadow: 0 4px 12px -6px rgba(13,23,40,.3);
  outline: 1px solid rgba(var(--glow), .35);
}
.seg .sg.active em { color: var(--a1); }
.seg.big { width: 100%; }
.seg.big .sg { flex: 1; padding: 11px 14px; }

.swap {
  flex: 0 0 40px; width: 40px; height: 40px; display: grid; place-items: center; border-radius: 11px;
  border: 1px solid var(--line-2); background: var(--surface-2); color: var(--text-2);
  transition: all .3s var(--ease); align-self: flex-end; margin-bottom: 1px;
}
.swap svg { width: 18px; height: 18px; transition: transform .5s var(--ease); }
/* 按钮上的文字在桌面端不出现（那里是 40×40 的方形图标按钮），手机端才显示，
   因为触屏没有 hover 提示、纯图标不够明确。见响应式一节。 */
.swap-txt { display: none; }
.swap:hover { color: var(--a1); border-color: rgba(var(--glow), .5); transform: rotate(180deg); }

/* ═══════════ 雷达扫描动画 ═══════════ */
.radar-scan { display: flex; align-items: center; gap: 22px; background: linear-gradient(120deg, rgba(var(--glow), .06), var(--surface) 55%); }
.sweep { position: relative; width: 92px; height: 92px; flex: 0 0 92px; border-radius: 50%; background: radial-gradient(circle, rgba(var(--glow), .07), transparent 70%); }
.sweep .ring { position: absolute; inset: 0; border-radius: 50%; border: 1px solid rgba(var(--glow), .35); }
.sweep .r2 { inset: 16px; border-color: rgba(var(--glow), .28); }
.sweep .r3 { inset: 32px; border-color: rgba(var(--glow), .22); }
.sweep .beam {
  position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from 0deg, rgba(var(--glow), .5), rgba(var(--glow), .06) 78deg, transparent 92deg);
  animation: spin 1.5s linear infinite;
  mask-image: radial-gradient(circle, #000 92%, transparent 93%);
  -webkit-mask-image: radial-gradient(circle, #000 92%, transparent 93%);
}
.sweep .beam::after {
  content: ''; position: absolute; left: 50%; top: 50%; width: 46%; height: 2px; transform-origin: 0 50%;
  background: linear-gradient(90deg, rgba(var(--glow), 1), transparent); border-radius: 2px;
}
@keyframes spin { to { transform: rotate(360deg); } }
.sweep .blip { position: absolute; width: 6px; height: 6px; border-radius: 50%; background: var(--a1); }
.sweep .b1 { left: 26%; top: 30%; animation: blip 2.2s infinite; animation-delay: .1s; }
.sweep .b2 { right: 24%; bottom: 32%; animation: blip 2.2s infinite; animation-delay: .9s; }
.sweep .b3 { left: 48%; bottom: 18%; animation: blip 2.2s infinite; animation-delay: 1.5s; }
@keyframes blip { 0% { opacity: 0; box-shadow: 0 0 0 0 rgba(var(--glow), .65); } 25% { opacity: 1; } 100% { opacity: .2; box-shadow: 0 0 0 12px rgba(var(--glow), 0); } }

.scan-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.scan-txt b { font-size: 15px; }
.scan-txt em { font-style: normal; font-size: 12.5px; color: var(--text-2); }
.pbar { height: 6px; border-radius: 999px; background: var(--surface-3); overflow: hidden; margin-top: 3px; }
.pbar i { display: block; height: 100%; width: 0; border-radius: 999px; background: linear-gradient(90deg, var(--a1), var(--a2)); transition: width .4s var(--ease); }

/* ═══════════ 通用小节头 / 摘要 ═══════════ */
.sec-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.sec-head h2 { font-size: 15.5px; font-weight: 650; display: flex; align-items: center; gap: 8px; }
.sec-head h2::before { content: ''; width: 3px; height: 15px; border-radius: 3px; background: linear-gradient(var(--a1), var(--a2)); }
.pill { font-size: 11.5px; padding: 4px 10px; border-radius: 999px; background: rgba(var(--glow), .1); color: var(--a2); border: 1px solid rgba(var(--glow), .28); font-weight: 600; }
.muted { color: var(--text-3); }
.small { font-size: 12px; }

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); gap: 10px; }
.stat {
  padding: 13px 15px; border-radius: 13px; background: var(--surface-2); border: 1px solid var(--line);
  position: relative; overflow: hidden;
}
.stat::after { content: ''; position: absolute; right: -18px; top: -18px; width: 56px; height: 56px; border-radius: 50%; background: radial-gradient(circle, rgba(var(--glow), .16), transparent 70%); }
.stat .k { font-size: 11.5px; color: var(--text-3); display: block; margin-bottom: 5px; }
.stat .v { font-size: 19px; font-weight: 700; letter-spacing: -.4px; font-variant-numeric: tabular-nums; }
.stat .v.acc { color: var(--a2); }
.stat .s { font-size: 11.5px; color: var(--text-3); margin-top: 3px; }

/* ═══════════ 模块 1 · 目的地榜 ═══════════ */
.dest-list { display: flex; flex-direction: column; gap: 8px; }
.dest {
  display: grid; grid-template-columns: 44px 1fr 132px 108px; align-items: center; gap: 14px;
  padding: 13px 16px; border-radius: 13px; background: var(--surface); border: 1px solid var(--line);
  cursor: pointer; position: relative; overflow: hidden;
  animation: riseIn .5s var(--ease) both; animation-delay: calc(var(--i, 0) * 22ms);
  transition: transform .25s var(--ease), box-shadow .25s var(--ease), border-color .25s var(--ease);
}
.dest::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: linear-gradient(var(--a1), var(--a2)); transform: scaleY(0); transform-origin: center;
  transition: transform .3s var(--ease);
}
.dest:hover { transform: translateY(-2px); box-shadow: var(--sh-2); border-color: rgba(var(--glow), .42); }
.dest:hover::before { transform: scaleY(1); }
.dest .rk {
  width: 34px; height: 34px; display: grid; place-items: center; border-radius: 10px;
  font-family: var(--mono); font-size: 13px; font-weight: 700; color: var(--text-2);
  background: var(--surface-3);
}
.dest.top .rk { color: #fff; background: linear-gradient(135deg, var(--a1), var(--a2)); box-shadow: 0 6px 16px -8px rgba(var(--glow), 1); position: relative; overflow: hidden; }
.dest.top .rk::after { content: ''; position: absolute; top: -60%; left: -120%; width: 60%; height: 220%; background: linear-gradient(90deg, transparent, rgba(255,255,255,.75), transparent); transform: rotate(18deg); animation: shine 2.6s infinite; animation-delay: calc(var(--i, 0) * 160ms); }
@keyframes shine { 0% { left: -120%; } 55%, 100% { left: 160%; } }

.dest .dname { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dest .dname b { font-size: 15px; font-weight: 650; }
.dest .dname .apt { font-size: 11.5px; color: var(--text-3); }
.tag { font-size: 10.5px; padding: 2px 7px; border-radius: 6px; background: var(--surface-3); color: var(--text-2); font-weight: 600; white-space: nowrap; }
.tag.intl { background: rgba(139,92,246,.12); color: #6d28d9; }
.tag.reg { background: rgba(249,115,22,.14); color: #c2410c; }
.tag.low { background: rgba(5,150,105,.13); color: #047857; }
.dest .dsub { font-size: 12px; color: var(--text-3); margin-top: 4px; display: flex; gap: 10px; flex-wrap: wrap; }

.dest .dbar { position: relative; height: 7px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.dest .dbar i {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--a1), var(--a2));
  animation: barGrow .9s var(--ease) both; animation-delay: calc(var(--i, 0) * 22ms + 180ms);
}
@keyframes barGrow { from { width: 0; } }
.dest .dbarlab { font-size: 11px; color: var(--text-3); margin-top: 5px; text-align: right; }

.dest .dprice { text-align: right; }
.dest .dprice b { font-size: 21px; font-weight: 750; letter-spacing: -.7px; font-variant-numeric: tabular-nums; color: var(--text); }
.dest.top .dprice b { color: var(--a2); }
.dest .dprice em { display: block; font-style: normal; font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
@keyframes riseIn { from { opacity: 0; transform: translateY(12px) scale(.99); } to { opacity: 1; transform: none; } }

.failed-note { margin-top: 12px; font-size: 12px; color: var(--text-3); line-height: 1.7; }
.failed-note b { color: var(--text-2); }

/* ═══════════ 模块 2 · 价格日历 ═══════════ */
.cal-wrap { display: flex; flex-direction: column; gap: 16px; }
.month-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 9px; }
.month-head b { font-size: 14px; font-weight: 650; }
.month-head em { font-style: normal; font-size: 11.5px; color: var(--text-3); }
.grid7 { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.wd { text-align: center; font-size: 11px; color: var(--text-3); padding-bottom: 2px; font-weight: 600; }
.cell {
  position: relative; min-height: 62px; border-radius: 11px; padding: 7px 8px;
  background: var(--surface-2); border: 1px solid var(--line);
  display: flex; flex-direction: column; justify-content: space-between; gap: 4px;
  animation: popIn .42s var(--ease) both; animation-delay: calc(var(--i, 0) * 9ms);
  transition: transform .2s var(--ease), box-shadow .2s var(--ease), border-color .2s var(--ease);
}
@keyframes popIn { from { opacity: 0; transform: scale(.82); } to { opacity: 1; transform: none; } }
.cell .d { font-size: 11.5px; color: var(--text-3); font-weight: 600; font-variant-numeric: tabular-nums; }
.cell .p { font-size: 13px; font-weight: 700; letter-spacing: -.3px; font-variant-numeric: tabular-nums; }
/* 价格里的 ¥ 是独立元素（app.js 的 priceHtml），手机端会把它收起来。i 默认斜体，必须扳平 */
.cell .p .cur { font-style: normal; }
.cell.empty { background: repeating-linear-gradient(45deg, var(--surface-2), var(--surface-2) 5px, rgba(0,0,0,.014) 5px, rgba(0,0,0,.014) 10px); border-style: dashed; }
.cell.pad { visibility: hidden; animation: none; background: none; border: none; }
.cell.pad::after { content: none; }
.cell.past { background: transparent; border-color: transparent; animation: none; }
.cell.past .d { color: var(--text-3); opacity: .42; font-weight: 500; }
.cell.empty .d { color: var(--text-3); opacity: .6; }
.cell.empty .p { color: var(--text-3); font-size: 11px; font-weight: 500; }
.cell.can { cursor: pointer; }
.cell.can:hover { transform: translateY(-3px) scale(1.04); box-shadow: var(--sh-2); border-color: rgba(var(--glow), .5); z-index: 2; }
.cell.sel { outline: 2.5px solid var(--a1); outline-offset: -1px; box-shadow: 0 8px 20px -10px rgba(var(--glow), 1); }
.cell .dv { position: absolute; right: 7px; bottom: 6px; font-size: 9px; color: var(--a2); font-weight: 700; opacity: .85; }
.cell.t0 { background: linear-gradient(140deg, rgba(var(--glow), .24), rgba(var(--glow), .12)); border-color: rgba(var(--glow), .4); }
.cell.t0 .p { color: var(--a2); }
.cell.t1 { background: linear-gradient(140deg, rgba(var(--glow), .13), rgba(var(--glow), .06)); border-color: rgba(var(--glow), .26); }
.cell.t1 .p { color: var(--text); }
.cell.t2 { background: var(--surface-2); }
.cell.t3 { background: var(--surface-2); }
.cell.t3 .p { color: var(--text-2); }
.cell.best { box-shadow: 0 0 0 2px rgba(var(--glow), .55), 0 10px 22px -12px rgba(var(--glow), 1); animation: bestPulse 2.4s ease-in-out infinite; }
@keyframes bestPulse { 0%,100% { box-shadow: 0 0 0 2px rgba(var(--glow), .5), 0 10px 22px -12px rgba(var(--glow), .9); } 50% { box-shadow: 0 0 0 4px rgba(var(--glow), .22), 0 12px 26px -12px rgba(var(--glow), 1); } }

.legend { display: flex; align-items: center; gap: 8px; font-size: 11.5px; color: var(--text-3); flex-wrap: wrap; }
.legend .sw { width: 18px; height: 12px; border-radius: 4px; border: 1px solid var(--line); }

/* ═══════════ 航班列表（模块 2 下钻） ═══════════ */
.flights { display: flex; flex-direction: column; gap: 8px; }
.frow {
  display: flex; align-items: center; gap: 16px; padding: 13px 16px; border-radius: 13px;
  background: var(--surface); border: 1px solid var(--line);
  animation: riseIn .45s var(--ease) both; animation-delay: calc(var(--i, 0) * 26ms);
  transition: transform .22s var(--ease), box-shadow .22s var(--ease), border-color .22s var(--ease);
}
.frow:hover { transform: translateY(-2px); box-shadow: var(--sh-2); }
.frow.can-jump { cursor: pointer; }
.frow.can-jump:hover { border-color: rgba(var(--glow), .45); }
.frow:focus-visible { outline: 2.5px solid var(--a1); outline-offset: 2px; }
.frow .l { flex: 1; min-width: 0; }
.frow .al { font-size: 13.5px; font-weight: 600; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.frow .tm { display: flex; align-items: center; gap: 9px; margin-top: 8px; font-size: 16px; font-weight: 650; letter-spacing: -.3px; flex-wrap: wrap; font-variant-numeric: tabular-nums; }
.frow .tm .ap { font-size: 11.5px; font-weight: 500; color: var(--text-3); }
.frow .tm .dur { font-size: 11px; color: var(--text-3); font-weight: 500; }
.frow .tm .plus { font-size: 10px; color: var(--warn); font-style: normal; vertical-align: super; margin-left: 1px; }
.frow .legs { font-size: 11.5px; color: var(--text-3); margin-top: 7px; line-height: 1.65; }
.frow .meta { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; align-items: center; font-size: 11.5px; color: var(--text-3); }
.frow .r { text-align: right; flex: 0 0 auto; }
.frow .r b { font-size: 20px; font-weight: 750; letter-spacing: -.6px; font-variant-numeric: tabular-nums; }
.frow .r .fare { font-size: 11.5px; color: var(--text-3); margin-top: 3px; white-space: nowrap; }
.frow.cheap .r b { color: var(--a2); }
.frow .r .jump {
  display: inline-flex; align-items: center; gap: 4px; margin-top: 6px;
  font-size: 11.5px; font-weight: 650; color: var(--a2); opacity: .7;
  transition: all .22s var(--ease); white-space: nowrap;
}
.frow .r .jump svg { width: 11px; height: 11px; }
.frow.can-jump:hover .r .jump { opacity: 1; transform: translateX(2px); }
.frow .r .jump .ext { font-weight: 500; color: var(--text-3); }

/* 日历 → 航班 滚动落点与高亮 */
#cFlights { scroll-margin-top: 24px; }
.fly-flash { animation: flyFlash 1.7s var(--ease) both; }
@keyframes flyFlash {
  0%   { box-shadow: 0 0 0 0 rgba(var(--glow), 0); }
  16%  { box-shadow: 0 0 0 4px rgba(var(--glow), .3); }
  100% { box-shadow: 0 0 0 0 rgba(var(--glow), 0); }
}

/* ═══════════ 模块 3 · 周末榜 ═══════════ */
.trips { display: grid; grid-template-columns: repeat(auto-fill, minmax(272px, 1fr)); gap: 12px; }
.trip {
  position: relative; padding: 16px; border-radius: 15px; background: var(--surface); border: 1px solid var(--line);
  cursor: pointer; overflow: hidden;
  animation: riseIn .5s var(--ease) both; animation-delay: calc(var(--i, 0) * 30ms);
  transition: transform .26s var(--ease), box-shadow .26s var(--ease), border-color .26s var(--ease);
}
.trip::after {
  content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 0%), rgba(var(--glow), .13), transparent 42%);
  opacity: 0; transition: opacity .3s var(--ease);
}
.trip:hover::after { opacity: 1; }
.trip:hover { transform: translateY(-4px); box-shadow: var(--sh-2); border-color: rgba(var(--glow), .45); }
.trip .tr-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.trip .rk2 { font-family: var(--mono); font-size: 11px; font-weight: 700; color: var(--text-3); }
.trip.top1 { background: linear-gradient(150deg, rgba(var(--glow), .1), var(--surface) 46%); border-color: rgba(var(--glow), .42); }
.trip.top1 .rk2 { color: var(--a2); }
.trip .route { display: flex; align-items: center; gap: 9px; margin-top: 11px; font-size: 16.5px; font-weight: 700; letter-spacing: -.4px; flex-wrap: wrap; }
.trip .route .arrow { color: var(--a1); display: grid; place-items: center; }
.trip .route .arrow svg { width: 17px; height: 17px; }
.trip .dates { font-size: 12px; color: var(--text-2); margin-top: 9px; line-height: 1.6; }
.trip .dates b { color: var(--text); font-weight: 650; }
.trip .tr-bot { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; margin-top: 14px; padding-top: 13px; border-top: 1px dashed var(--line-2); }
.trip .price b { font-size: 24px; font-weight: 780; letter-spacing: -.9px; font-variant-numeric: tabular-nums; }
.trip.top1 .price b { color: var(--a2); }
.trip .price em { display: block; font-style: normal; font-size: 11px; color: var(--text-3); margin-top: 3px; }
.trip .price .fare2 { font-size: 10.5px; margin-top: 2px; white-space: nowrap; }
.trip .go { font-size: 12px; color: var(--a2); font-weight: 600; display: inline-flex; align-items: center; gap: 4px; opacity: .75; transition: all .25s var(--ease); }
.trip:hover .go { opacity: 1; transform: translateX(2px); }

/* ── 历史价格判断 ──
   便宜=红（涨/贵用绿，遵循 A 股约定在这里不适用：这里是「价格高低」不是「涨跌」，
   所以用直觉色：便宜显绿提示可下手，偏贵显橙提示再等等）。 */
.trip .hist {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  margin-top: 9px; padding: 6px 9px; border-radius: 8px;
  border: 1px solid var(--line-2); background: var(--surface-2);
}
.trip .hist .ht-tag { font-size: 11px; font-weight: 700; white-space: nowrap; }
.trip .hist .ht-sub { font-size: 10.5px; color: var(--text-3); }
.trip .hist.hist-low { background: rgba(5,150,105,.1); border-color: rgba(5,150,105,.28); }
.trip .hist.hist-low .ht-tag { color: #047857; }
.trip .hist.hist-high { background: rgba(249,115,22,.11); border-color: rgba(249,115,22,.3); }
.trip .hist.hist-high .ht-tag { color: #c2410c; }
.trip .hist.hist-flat { background: var(--surface-3); }
.trip .hist.hist-flat .ht-tag { color: var(--text-2); }

/* ═══════════ 骨架 / 提示 / 空态 ═══════════ */
.skel {
  height: 66px; border-radius: 13px; margin-bottom: 8px;
  background: linear-gradient(100deg, var(--surface-2) 28%, var(--surface-3) 46%, var(--surface-2) 64%);
  background-size: 260% 100%; animation: shimmer 1.35s linear infinite;
}
@keyframes shimmer { to { background-position: -160% 0; } }
.empty { padding: 30px 18px; text-align: center; color: var(--text-3); font-size: 13.5px; line-height: 1.75; }
.notice { display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; border-radius: 12px; font-size: 12.8px; line-height: 1.6; margin-bottom: 12px; }
.notice.err { background: rgba(220,38,38,.07); border: 1px solid rgba(220,38,38,.24); color: #b91c1c; }
.notice.warn { background: rgba(217,119,6,.08); border: 1px solid rgba(217,119,6,.26); color: #b45309; }
.notice .ic { width: 17px; height: 17px; flex: 0 0 17px; border-radius: 50%; display: grid; place-items: center; font-weight: 700; font-size: 11px; background: currentColor; color: #fff; margin-top: 1px; }
.spin { width: 13px; height: 13px; border-radius: 50%; border: 2px solid rgba(255,255,255,.35); border-top-color: #fff; animation: spin .7s linear infinite; display: inline-block; }

/* ═══════════ 说明 / 页脚 ═══════════ */
.method summary { cursor: pointer; font-size: 13.5px; font-weight: 600; color: var(--text-2); list-style: none; display: flex; align-items: center; gap: 8px; }
.method summary::-webkit-details-marker { display: none; }
.method summary::before { content: '?'; width: 18px; height: 18px; border-radius: 50%; background: var(--surface-3); color: var(--text-2); display: grid; place-items: center; font-size: 11px; font-weight: 700; }
.method ul { margin: 13px 0 0; padding-left: 20px; color: var(--text-2); font-size: 12.8px; line-height: 1.85; }
.method li { margin-bottom: 5px; }
.method b { color: var(--text); }

.foot { position: relative; z-index: 2; padding: 22px 0 34px; }
.foot .wrap { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; font-size: 12px; color: var(--text-3); }
.foot-dot { opacity: .5; }

/* ═══════════ 响应式 ═══════════
   查票多半在手机上，所以手机端是主场景，下面每个尺寸都按视口算过，不是拍脑袋调的。
   基准：iPhone 14/15 = 390px，Android 主流 = 360px（iPhone SE = 375px）。

   .wrap 在 ≤560px 时 = 100% − 24px → 390px 视口 = 366px；.card 左右各 12px → 内宽 342px
                                                                    360px 视口 → 内宽 312px

   日历是 7 列网格，最挤的地方：
     (内宽 − 6×gap) ÷ 7 = 每格宽 → 390px: (342−24)/7 = 45.4px   360px: (312−24)/7 = 41.1px
   每格左右各 4px padding → 文字可用 37.4px / 33.1px。
   最宽的价格串是「¥12,345」（7 个字形），13px 下约 51px、11px 下约 43px —— **都放不下**。
   所以手机端：① 格子里的 ¥ 收起来（.cell .p .cur，只在日历格子里收，别处照旧）；
              ② 价格降到 10.5px → 「12,345」约 32.5px，两种视口都装得下。
   完整价格仍保留在格子的 title 悬浮提示里，legend 也写了「含税总价」口径。 */

/* ── 触屏：先清掉 hover 位移 ──────────────────────────────
   触屏上 :hover 会在点完之后**粘住**（元素停在抬起 3px 的状态），看起来像卡住。
   这里用 @media (hover: none) 精确命中没有悬停能力的设备，改成按下缩放做反馈。 */
@media (hover: none) {
  .mod:hover, .loc-btn:hover, .swap:hover, .btn.ghost:hover:not(:disabled),
  .dest:hover, .trip:hover, .frow:hover, .cell.can:hover { transform: none; }
  .btn.primary:hover:not(:disabled) { transform: none; box-shadow: 0 10px 24px -12px rgba(var(--glow), 1); }
  .dest:hover { box-shadow: none; border-color: var(--line); }
  .dest:hover::before { transform: scaleY(0); }
  .trip:hover { box-shadow: none; border-color: var(--line); }
  .trip:hover::after { opacity: 0; }
  .frow.can-jump:hover { border-color: var(--line); }
  .cell.can:hover { box-shadow: none; border-color: var(--line); }
  .dest:active, .trip:active, .frow.can-jump:active, .cell.can:active { transform: scale(.985); }
}

/* ── 平板 / 窄窗口 ─────────────────────────────────────── */
@media (max-width: 900px) {
  /* 三段导航**保持三列**：竖排三段会白占 200px 高度，三列只占 64px。
     代价是放不下副标题，所以把描述与序号收起，只留图标 + 模块名。 */
  .mods { grid-template-columns: repeat(3, 1fr); gap: 8px; }
  .mod-pill { display: none; }
  .mod { padding: 11px 12px; gap: 10px; }
  .m-ico { width: 34px; height: 34px; flex: 0 0 34px; }
  .m-ico svg { width: 18px; height: 18px; }
  .m-txt em, .m-idx { display: none; }
  /* 滑动药丸没了，必须另有办法看出「当前是哪个模块」，否则三个 tab 只靠图标深浅区分 */
  .mod.active { background: rgba(var(--glow), .1); outline: 1px solid rgba(var(--glow), .34); }

  /* 目的地榜：收起价格条（它只是相对刻度的可视化），把宽度让给城市名与价格 */
  .dest { grid-template-columns: 38px 1fr auto; gap: 12px; }
  .dest .dbar, .dest .dbarlab { display: none; }

  .cell { min-height: 54px; padding: 6px; }
  .cell .p { font-size: 11.5px; }

  /* 交换按钮不再隐藏。手机上手工输城市恰恰最费劲，这个按钮在手机上最有用。 */
  .swap { display: grid; }

  /* 价格明细是 nowrap 的，在 561~900px 这段窄桌面/平板上会把航班卡挤变形，允许折行 */
  .frow .r .fare { white-space: normal; }
}

/* ── 手机 ──────────────────────────────────────────────── */
@media (max-width: 560px) {
  /* 刘海 / 挖孔屏：viewport-fit=cover 已开，这里补左右安全区，避免内容被圆角切掉 */
  body { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
  .wrap { width: calc(100% - 24px); }
  .card { padding: 12px; }

  /* 分步引导：手机上气泡贴边放，别顶到屏幕外 */
  .t-bubble { width: calc(100vw - 24px); padding: 12px 13px 11px; }
  .t-title { font-size: 13px; }
  .t-text { font-size: 12px; }
  .help-btn { width: 30px; height: 30px; font-size: 14px; }

  /* 背景极光是三个 34~46vw 的大色块在持续位移。模糊半径越大，每帧重绘越贵 ——
     手机上把半径压到 44px，观感几乎不变，滚动明显更跟手。 */
  .aurora .orb { filter: blur(44px); opacity: .42; }

  /* 顶栏收紧，省出首屏高度 */
  .topbar { padding: 14px 0 4px; }  .brand { gap: 10px; }
  .brand-mark { width: 40px; height: 40px; border-radius: 12px; }
  .brand-mark svg { width: 22px; height: 22px; }
  .brand-txt h1 { font-size: 19px; }
  .brand-sub { display: none; }
  .loc-btn, .status { padding: 7px 11px; font-size: 12px; }

  /* 导航：图标在上、模块名在下，三列等宽 */
  .mods { padding: 6px; gap: 6px; margin: 12px 0; border-radius: 16px; }
  .mod { flex-direction: column; align-items: center; text-align: center; gap: 6px; padding: 10px 6px; }
  .m-txt { align-items: center; }
  .m-txt b { font-size: 12.5px; }

  /* 表单控件一律独占一行，按钮撑满 —— 一行里挤三个控件在手机上会变成点击事故 */
  .bar { gap: 10px; }
  .field, .field.narrow { flex: 1 1 100%; }
  .actions { flex: 1 1 100%; }
  .actions .btn { flex: 1; justify-content: center; }
  .seg { width: 100%; }
  .seg .sg { flex: 1; min-height: 40px; justify-content: center; padding: 9px 10px; }
  .seg.big .sg { padding: 10px 6px; }
  .seg.big .sg em { font-size: 10px; }

  /* ⚠️ iOS Safari 会在聚焦 font-size < 16px 的输入框时**自动放大整个页面**，且失焦后不缩回。
     这是移动端最容易被忽略的一个坑，必须把表单控件顶到 16px。 */
  .combo-input, .field select { font-size: 16px; }
  .combo-input { padding: 12px 38px 12px 13px; }
  .combo-clear { width: 26px; height: 26px; right: 7px; }
  .combo-clear svg { width: 12px; height: 12px; }
  .ci { padding: 11px 12px; }   /* 候选行加高到约 40px，手指点得准 */

  /* 交换按钮独占一行：图标转 90° 指向上下，正好对应它上方/下方的两个输入框。
     ⚠️ 必须 display: flex —— 上一档给它的是 grid + place-items:center，
        加上文案后 svg 与文字会变成两个 grid item 上下堆叠，而不是并排。 */
  .swap { display: flex; align-items: center; justify-content: center; gap: 7px;
          flex: 0 0 100%; max-width: none; width: 100%; height: 44px; margin: 0; }
  .swap svg { transform: rotate(90deg); }
  .swap-txt { display: inline; font-size: 12px; }

  /* 摘要卡：两列，数字降一档 */
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .stat { padding: 11px 12px; border-radius: 12px; }
  .stat .v { font-size: 18px; }
  .stat .s { font-size: 11px; line-height: 1.5; }

  /* 目的地榜 */
  .dest { grid-template-columns: 32px 1fr auto; gap: 10px; padding: 12px 13px; }
  .dest .rk { width: 30px; height: 30px; font-size: 12px; }
  .dest .dname b { font-size: 14.5px; }
  .dest .dsub { font-size: 11.5px; gap: 8px; margin-top: 3px; }
  .dest .dprice b { font-size: 19px; }

  /* 日历：尺寸推导见本文件「响应式」一节的注释 */
  .grid7 { gap: 4px; }
  .cell { min-height: 48px; padding: 5px 4px; border-radius: 9px; }
  .cell .d { font-size: 10.5px; }
  .cell .p { font-size: 10.5px; letter-spacing: -.2px; }
  .cell .p .cur { display: none; }   /* 去掉 ¥ 才装得下 4~5 位数 */
  .cell .dv { right: 3px; top: 3px; bottom: auto; }   /* 「补」角标移右上，避免和价格撞 */
  .wd { font-size: 10.5px; }
  .month-head em { font-size: 11px; }
  .legend { font-size: 11px; }

  /* 航班卡：时间与价格改成上下排 */
  .frow { flex-direction: column; align-items: stretch; gap: 10px; padding: 12px 13px; }
  .frow .r { text-align: left; }
  .frow .r b { font-size: 19px; }
  .frow .tm { font-size: 15px; }

  /* 周末榜 */
  .trips { grid-template-columns: 1fr; }
  .trip { padding: 14px; }
  .trip .price b { font-size: 21px; }
  .trip .route { font-size: 15.5px; }

  /* 扫描动画：盘子缩小，文字占满 */
  .radar-scan { gap: 16px; }
  .sweep { width: 78px; height: 78px; flex: 0 0 78px; }
  .sweep .r2 { inset: 14px; }   /* 盘子缩到 78/92 后，内外圈按同比例收，否则最内圈只剩 14px */
  .sweep .r3 { inset: 27px; }
  .scan-txt b { font-size: 14px; }
  .scan-txt em { font-size: 12px; }

  .sec-head h2 { font-size: 14.5px; }
  .method summary { font-size: 13px; }
  .method ul { font-size: 12.5px; line-height: 1.8; padding-left: 18px; }

  /* 底部胶囊条会盖住内容，footer 也要留出安全区 */
  .foot { padding: 18px 0 calc(26px + env(safe-area-inset-bottom)); }
  .foot .wrap { font-size: 11.5px; }
}

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