/* kid.css —— 孩子视图：星罐 / 火箭轨道 / 卡片 / 贴纸墙 / 商店 / 券包 / 长按按钮 */

/* ---- 头部 ---- */
.kid-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 4px 4px;
  /* PWA 状态栏避让（v1.0.3 批次A §3）：top 方向在原 8px 上叠加安全区，其余方向不动 */
  padding-top: calc(8px + var(--sat));
}

.kid-title {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 36px;
  font-weight: 800;
  color: var(--accent-ink); /* 批次F ②：浅草地底改金棕（黄字对比不足） */
  text-shadow: 0 2px 0 rgba(255, 255, 255, .55);
}

.sound-btn {
  width: 72px;
  height: 72px;
  padding: 0;
  border-radius: 50%;
  font-size: 24px;
  background: rgba(255, 255, 255, .55); /* 批次F ② */
  color: var(--ink);
  border: 2px solid var(--card-line);
  box-shadow: none;
}

.sound-btn .s-icon svg { width: 36px; height: 36px; }
.sound-btn.muted { color: rgba(74, 54, 40, .45); opacity: .8; }

.sec-title {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 27px;
  font-weight: 800;
  color: var(--accent-ink); /* 批次F ② */
  margin: 30px 4px 16px;
  text-shadow: 0 0 3px rgba(255,255,255,.95), 0 0 7px rgba(255,255,255,.85), 0 1px 1px rgba(255,255,255,.9);  /* V200-G ①：草地直压金色标题加白晕（WCAG G18）*/
}

/* ---- 衣柜（批次F ③：星罐→大衣柜；id 钩子全部不变，仅视觉换皮） ---- */
.jar-section {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 26px;
  padding: 16px 0 6px;
  flex-wrap: wrap;
}

.jar-wrap {
  position: relative;
  width: 216px;
  height: 216px; /* V200-I² 勘误：wardrobe.png 实为 780×780（原注 512×512 过时），容器方盒 216 CSS px */
  filter: drop-shadow(0 12px 28px rgba(0, 0, 0, .38)) drop-shadow(0 0 16px rgba(255, 244, 200, .22));
  transition: filter .4s;
}

.jar-wrap.bounce { animation: jarBounce .42s cubic-bezier(.3, 1.7, .5, 1); }
.jar-wrap.dim { filter: drop-shadow(0 12px 28px rgba(0, 0, 0, .38)) drop-shadow(0 0 16px rgba(255, 244, 200, .22)) brightness(.82); }
.jar-wrap.full .jar-art { filter: drop-shadow(0 0 30px rgba(255, 201, 77, .75)); }

@keyframes jarBounce {
  0% { transform: scale(1); }
  45% { transform: scale(1.08); }
  100% { transform: scale(1); }
}

/* 衣柜容器图（原玻璃罐 SVG 已删；满 40 颗发光钩子保留） */
.jar-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
}

/* 蝴蝶结堆叠腔：对齐开放式货架的大开放格（V200-G ③）。
   V200-I² 勘误：现已为透明底、无阴影（原注「半透明深木色内衬+内阴影」过时）。 */
.jar-inner {
  position: absolute;
  left: 32px;
  right: 32px;
  bottom: 36px;
  height: 143px;      /* V200-G ③：对齐开放货架内部大格（实测 216盒:高142.9/底距36.6/开口宽152.9）*/
  overflow: hidden;
  border-radius: 0;
  background: transparent;   /* V200-G ②：去旧“关闭柜门”深木内衬（原 rgba(94,62,32,.20)）*/
  box-shadow: none;          /* 去内阴影 */
}

/* 罐内堆积物：像素蝴蝶结 <img>（批次F ③，原 SVG 星）。类名仍叫 .jar-star——
   startJarFloat('.jar-star') 选择器与漂浮实现零改动（kid.js 只换产出标签）。
   颜色多样性走内联 filter: hue-rotate（不放 transform 里——漂浮逐帧重写
   transform 会吞掉它），漂浮只写 transform，filter 每帧保留 */
.jar-star {
  position: absolute;
  display: block;
  image-rendering: pixelated;
  filter: drop-shadow(0 2px 3px rgba(120, 70, 0, .45)) drop-shadow(0 0 9px rgba(255, 214, 92, .7));
  transform-origin: 50% 50%;
  will-change: transform;
}
.jar-star.half {
  clip-path: inset(0 50% 0 0);
  opacity: .95;
}

.jar-num-wrap { text-align: center; min-width: 170px; }

/* 数字行：像素蝴蝶结 + 数字并排（批次F ③：数字区用蝴蝶结像素图） */
.jar-number-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}
.jar-number-bow {
  width: 44px;
  height: 44px;
  image-rendering: pixelated;
  filter: drop-shadow(0 2px 3px rgba(120, 70, 0, .35));
}

.jar-number {
  font-size: 68px;
  font-weight: 900;
  line-height: 1.1;
  color: var(--accent-ink); /* 批次F ②：浅底改金棕 */
  text-shadow: 0 0 4px rgba(255,255,255,.95), 0 0 9px rgba(255,255,255,.85), 0 2px 0 rgba(255,255,255,.6);  /* V200-G ①：压草地金色大字加白晕（大字需≥3.0）*/
  font-variant-numeric: tabular-nums;
}

.jar-number.num-tick { animation: tickPulse .15s ease; }

@keyframes tickPulse {
  50% { transform: scale(1.15); }
}

.jar-label { font-size: 22px; color: var(--ink-dim); text-shadow: 0 0 3px rgba(255,255,255,.95), 0 0 6px rgba(255,255,255,.8), 0 1px 1px rgba(255,255,255,.9); }   /* V200-G ①：草地直压文字加白晕（WCAG 2.1 SC1.4.3 / 技术 G18）*/

.pending-note {
  margin-top: 10px;
  font-size: 20px;
  color: #0A6E60; /* V200-G ①：深青 .原#0F8F7D（白底上2.67）→ #0A6E60（达4.5）*/
  background: rgba(255, 255, 255, .8);   /* V200-G ①：scrim .55→.8（底座更实）*/
  border-radius: var(--r-sm);
  padding: 8px 14px;
}

/* ---- 猫走路路线（v2.0 批次B：火箭轨道换皮；骨架 ID / 定位契约不变） ---- */
.rocket-section { padding: 4px 2px 0; }

.track-wrap {
  position: relative;
  height: 160px;
  margin: 6px 26px 0 10px;
}

/* 路线起点：像素小屋（猫从家门出发） */
.route-house {
  position: absolute;
  left: -6px;
  bottom: 54px;
  width: 60px;
  height: 60px;
  z-index: 1;   /* V200-G ④：抬到路面(.track-line auto)之上；🔴 不用 3——猫 .rocket z=2 会反被盖 */
}

.route-house img {
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
  filter: drop-shadow(0 3px 6px rgba(0, 0, 0, .35));
}

/* 批次F ⑥：直路→蜿蜒小路。.track-line 仍是 JS 丈量基准（offsetWidth）与
   fill 宽度基准，只是从「横条」变「曲线画布」：高度 14→76，底部 58→30，
   路中线 y=20/40 恰在猫脚线（rocket bottom 66 ≈ 30+76-38）。
   container-type:inline-size → 内层 .curve-fill 可用 100cqw 恒取整路宽。 */
.track-line {
  position: absolute;
  left: 62px;      /* V200-G ④：44→62（让出起点小屋右侧，防路面压屋顶）*/
  right: 64px;
  bottom: 30px;
  height: 76px;
  container-type: inline-size;
  pointer-events: none;
}

/* 路基本体：暖沙色宽带（vector-effect 让描边宽度不受 viewBox 非等比拉伸影响，
   任何屏宽下都是恒定 13px 圆头小路） */
.curve-base,
.curve-fill {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.curve-base .road-bed {
  fill: none;
  stroke: rgba(216, 186, 138, .95);
  stroke-width: 13px;
  stroke-linecap: round;
}
/* 路中沙砾虚线（替代原 ::after 沙点） */
.curve-base .road-mid {
  fill: none;
  stroke: rgba(255, 240, 200, .6);
  stroke-width: 2.5px;
  stroke-dasharray: 5 9;
  stroke-linecap: round;
}

/* 🔴 契约不变：JS 只写 width:%（0~100），本层是左锚定裁切窗——
   宽度增长 = 沿曲线从家到公园逐段点亮。overflow:hidden 裁切右侧。 */
.track-fill {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 0%;
  overflow: hidden;
  transition: width 1.2s cubic-bezier(.3, 1.4, .4, 1);
}
.curve-fill {
  /* 兜底：不支持 cqw 的旧浏览器按自身百分比（曲线会被压扁，功能不损） */
  width: 100%;
  width: 100cqw;  /* 恒等于 .track-line 全宽：fill 变窄时曲线不压缩，只被裁掉 */
}
.curve-fill path {
  fill: none;
  stroke: #FFB23E;
  stroke-width: 13px;
  stroke-linecap: round;
  filter: drop-shadow(0 0 6px rgba(255, 178, 62, .8));
}

/* 足迹石改沿曲线落位：5 块石头 x=10/30/50/70/90%，上/下石 top 交错
   （y=14→26.6px、y=26→49.4px，减半个石头高 18px = 8.6/31.4px 取整） */
.ticks {
  position: absolute;
  left: 62px;      /* V200-G ④：与 .track-line 同步 44→62 */
  right: 64px;
  bottom: 30px;
  height: 76px;
  pointer-events: none;
}

.tick {
  position: absolute;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  font-size: 20px;
  color: var(--ink-dim);
  width: 64px;
  text-shadow: 0 0 3px rgba(255,255,255,.95), 0 0 6px rgba(255,255,255,.8), 0 1px 1px rgba(255,255,255,.9);  /* V200-G ①：周一~周五直压草地加白晕 */
}
.tick:nth-child(1) { left: 10%; top: 9px; }
.tick:nth-child(2) { left: 30%; top: 31px; }
.tick:nth-child(3) { left: 50%; top: 9px; }
.tick:nth-child(4) { left: 70%; top: 31px; }
.tick:nth-child(5) { left: 90%; top: 9px; }

/* 脚印石（替换原 .dot 星体）：未点亮 stone_off 灰石 / 点亮 stone_on 暖石 */
.tick .stone {
  width: 36px;
  height: 36px;
  image-rendering: pixelated;
}

.tick.today { color: var(--accent-ink); font-weight: 800; }
.tick.today .stone {
  filter: drop-shadow(0 0 8px rgba(255, 201, 77, .8));
}

/* 路线终点：像素游乐园（沿用 #planet 容器与 glow / arrive 庆祝钩子） */
.planet {
  position: absolute;
  right: -12px;
  bottom: 54px;
  width: 68px;
  height: 102px;
  transition: filter .6s;
  z-index: 1;
}

.planet .park-img {
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
}

.planet.glow { filter: drop-shadow(0 0 20px rgba(255, 201, 77, .9)); animation: planetPulse 1.6s ease-in-out infinite alternate; }
.planet.arrive { animation: planetBurst .9s cubic-bezier(.34, 1.56, .64, 1); }

@keyframes planetPulse {
  from { filter: drop-shadow(0 0 10px rgba(255, 201, 77, .5)); }
  to { filter: drop-shadow(0 0 26px rgba(255, 201, 77, 1)); }
}

@keyframes planetBurst {
  0% { transform: scale(1); }
  40% { transform: scale(1.5); filter: drop-shadow(0 0 40px rgba(255, 201, 77, 1)); }
  100% { transform: scale(1); }
}

/* 批次E 色系联动：尾巴蝴蝶结默认粉（与 bows.js COLOR_HEX.pink 一致）。
   🔴 必须定义在 :root——bows.js 写 document.documentElement（:root）级变量，
   若定义在 .rocket 元素级会遮蔽继承链导致外部写入永不生效 */
:root { --cat-bow-color: #FF9AC8; }

/* 走路的猫（沿用 #rocket 容器：kid.js renderRocket 读写 offsetWidth / style.left，契约冻结） */
.rocket {
  position: absolute;
  left: 0%;
  bottom: 66px;
  width: 74px;
  height: 74px;
  /* margin-left 与 .track-line 的 left 对齐：JS 写的 style.left 从 wrap 左缘起算，
     margin 把起点平移到小屋右侧——renderRocket 逻辑零改动（视觉偏移不进契约） */
  margin-left: 62px;   /* V200-G ④：与 .track-line 的 left 同步 44→62 */
  transform: translateX(-50%);
  transition: left 1.2s cubic-bezier(.3, 1.4, .4, 1);
  filter: drop-shadow(0 4px 10px rgba(0, 0, 0, .5));
  z-index: 2;
}

.cat-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: pixelated;   /* 像素画硬边渲染 */
  /* 🔴 批次F ⑤：素材猫原生朝左（头左尾右，朝家的方向反了）→ 镜像朝右（朝公园）。
     catFrameA/B 只动 opacity 不含 transform，此处基类 transform 无冲突；
     减动效冻结帧1 时镜像同样保留（朝向是布局属性，非动效）。 */
  transform: scaleX(-1);
}

/* 批次E 色系联动消费端：尾巴蝴蝶结叠加层（index.html 内联 SVG，直角像素风）。
   批次F ⑤ 镜像后锚点同步左右翻转：素材原尾部在 ~80%（右），镜像后尾在左 →
   20%/28%（100%−80%，垂直位置不变）；宽 26% 不变，完整盖住 PNG 原粉结。
   fill 用 var(--cat-bow-color)（:root 级）， bows.js 佩戴/加载即变色。
   纯颜色变化无动画，天然满足减动效（铁律⑥）。 */
.cat-bow {
  position: absolute;
  left: 20%;
  top: 28%;
  width: 26%;
  transform: translate(-50%, -50%);
  shape-rendering: crispEdges;   /* SVG 直角硬边，匹配像素风 */
  pointer-events: none;          /* 不挡猫的点击区 */
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .35));
  z-index: 2;                    /* 盖在两帧 cat-frame 之上 */
}

/* 批次A 已重制匹配双帧（同朝向朝右 + 两帧均含金冠/尾结 + 统一 bbox 锚定）：
   两帧以 opacity 离散交替播放真正的行走循环；减动效下退化为静态站姿。 */

/* 帧1 / 帧2 各显示 340ms（≥300ms），steps 离散切换，无淡入淡出 */
.cat-frame[data-frame="1"] { animation: catFrameA 680ms steps(1, end) infinite; }
.cat-frame[data-frame="2"] { animation: catFrameB 680ms steps(1, end) infinite; }
@keyframes catFrameA {
  0%, 49.99% { opacity: 1; }
  50%, 100% { opacity: 0; }
}
@keyframes catFrameB {
  0%, 49.99% { opacity: 0; }
  50%, 100% { opacity: 1; }
}

.track-caption {
  text-align: center;
  font-size: 21px;
  color: var(--ink-dim);
  margin-top: 8px;
  text-shadow: 0 0 3px rgba(255,255,255,.95), 0 0 6px rgba(255,255,255,.8), 0 1px 1px rgba(255,255,255,.9);  /* V200-G ①：草地直压文字加白晕 */
}

/* ---- 今日卡片 ---- */
.card-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
}

@media (max-width: 560px) {
  .card-grid { grid-template-columns: 1fr; }
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 214px;
  padding: 30px 18px 24px;
  border-radius: var(--r-lg);
  /* 批次F ②：浅底暖白卡（原深底玻璃卡翻亮）
     V200-G ①（真机可读性）：草地降密后仍须保证正文对比度。
     🔴 注意：主卡背景是**本处硬编码渐变**，不是死变量 var(--card)（全前端零消费者）。
     故可读性只提高本处不透明度即可（.82/.6 → .94/.86）。 */
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(255, 255, 255, .95), rgba(255, 255, 255, 0) 62%),
    linear-gradient(168deg, rgba(255, 255, 255, .94), rgba(255, 251, 236, .86));
  border: 1.5px solid rgba(122, 88, 44, .22);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .8) inset,
    0 10px 26px rgba(58, 40, 16, .22),
    0 2px 6px rgba(58, 40, 16, .14);
  color: var(--ink);
  font-weight: 700;
  overflow: hidden;
  transition: transform .3s cubic-bezier(.34, 1.56, .64, 1), border-color .3s, box-shadow .3s;
}

.card:active { transform: scale(1.03); }
.card.pulse { animation: cardPulse .3s ease; }

@keyframes cardPulse {
  0% { transform: scale(1); }
  40% { transform: scale(1.06); }
  100% { transform: scale(1); }
}

.card .c-icon { width: 64px; height: 64px; color: var(--yellow); }
.card .c-icon svg { width: 100%; height: 100%; }
.card .c-title { font-size: 26px; font-weight: 800; letter-spacing: .5px; line-height: 1.25; }
.card .c-sub {
  font-size: 20px;
  color: rgba(74, 54, 40, .78); /* 批次F ② */
  font-weight: 500;
  text-align: center;
  line-height: 1.5;
  max-width: 92%;
}

.card .c-delta {
  margin-top: 6px;
  padding: 6px 20px;
  border-radius: var(--r-sm);
  font-size: 22px;
  font-weight: 800;
  color: #3a2800;
  background: linear-gradient(180deg, var(--yellow), var(--yellow-deep));
  box-shadow: var(--glow);
}

.card.best {
  border-color: rgba(197, 138, 32, .62);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, .8) inset,
    0 10px 26px rgba(58, 40, 16, .22),
    0 0 24px rgba(255, 201, 77, .4);
  /* 🔴 缎带占顶部 ~30px，必须让出空间，否则压住图标 */
  padding-top: 46px;
}

/* 「最值钱」：顶部居中缎带，压住卡边上沿；不再与完成星标同角冲突 */
.card .c-best-badge {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  padding: 3px 18px 4px;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: .5px;
  color: #4a2400;
  background: linear-gradient(180deg, #FFC77A, #FF8A3D);
  border-radius: 0 0 14px 14px;
  box-shadow: 0 3px 10px rgba(255, 138, 61, .42);
  white-space: nowrap;
}

/* 已得：整卡半透明 + 大金星盖章 + 轻微下移 */
.card.done {
  /* 🔴 原 opacity .5 让字变灰发脏；改为保留对比、只降饱和 + 换底（批次F ② 浅底化） */
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(88, 201, 107, .28), rgba(255, 255, 255, 0) 62%),
    linear-gradient(168deg, rgba(88, 201, 107, .2), rgba(255, 251, 236, .55));
  border-color: rgba(47, 158, 77, .55);
  transform: translateY(4px) scale(.985);
  pointer-events: none;
  cursor: default;
}

.card.done .c-title { color: rgba(74, 54, 40, .92); }
.card.done .c-sub { color: rgba(74, 54, 40, .72); }
.card.done .c-delta {
  background: rgba(47, 158, 77, .22);
  color: #1E6E38;
  box-shadow: none;
}
.card.done .c-icon { opacity: .55; filter: saturate(.5); }

.card .c-stamp {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(47, 158, 77, .2);
  border: 1.5px solid rgba(47, 158, 77, .55);
  color: #2F9E4D;
  box-shadow: 0 2px 8px rgba(58, 40, 16, .18);
  /* 🔴 v1.0.1 P1-4：修复编辑事故——两条声明曾被挤出块外（悬空 + 孤立右括号） */
  transform: rotate(14deg);
  filter: drop-shadow(0 0 10px rgba(255, 201, 77, .8));
}
.card .c-stamp svg { width: 20px; height: 20px; }

/* ---- 长按浮层 ---- */
#press-overlay { z-index: 60; }

.press-head {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 30px;
  font-weight: 800;
  color: #FFF7E6; /* 批次F ②：浮层仍是深色遮罩，压住页面主题变量改回亮字 */
}

.press-head .c-icon { width: 54px; height: 54px; color: var(--yellow); }
.press-head .c-icon svg { width: 100%; height: 100%; }
.press-head .c-delta {
  padding: 4px 18px;
  font-size: 24px;
  border-radius: var(--r-sm);
  color: #3a2800;
  background: var(--yellow);
}

.press-stage {
  position: relative;
  width: 224px;
  height: 224px;
}

.press-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.press-ring circle { fill: none; stroke-width: 13; }

.ring-bg { stroke: rgba(255, 255, 255, .14); }

.ring-fill {
  stroke: var(--teal);
  stroke-linecap: round;
  stroke-dasharray: 628.32;
  stroke-dashoffset: 628.32;
  filter: drop-shadow(0 0 8px rgba(77, 216, 192, .8));
}

.ring-fill.rebound { transition: stroke-dashoffset .3s cubic-bezier(.34, 1.4, .64, 1); }

.press-btn {
  position: absolute;
  inset: 22px;
  border-radius: 50%;
  font-size: 30px;
  padding: 0;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  outline: none;
}

.press-btn.holding { transform: scale(1.05); }

.press-hint { font-size: 21px; color: rgba(255, 247, 230, .78); } /* 深色遮罩上保持亮字 */

/* ---- 贴纸墙 ---- */
.sticker-card, .ticket-card {
  border-radius: var(--r-lg);
  background: var(--card-bg);
  border: 2px solid var(--card-line);
  padding: 24px 22px;
  box-shadow: 0 8px 24px rgba(58, 40, 16, .22);
}

.sticker-card .sec-title, .ticket-card .sec-title { margin: 0 0 16px; }

.sticker-row {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  min-height: 72px;
  align-items: center;
  margin-bottom: 16px;
}

.sticker {
  width: 62px;
  height: 62px;
  color: #0b3d1c;
}

.sticker.yellow { color: #6b4a00; }
.sticker.empty {
  width: 62px;
  height: 62px;
  border-radius: 50%;
  border: 3px dashed rgba(122, 88, 44, .4); /* 批次F ② */
}

.sticker.pop { animation: stickerPop .42s cubic-bezier(.34, 1.7, .5, 1); }

@keyframes stickerPop {
  0% { transform: scale(1.4) rotate(-14deg); opacity: 0; }
  60% { transform: scale(.94) rotate(4deg); opacity: 1; }
  100% { transform: scale(1) rotate(0); }
}

.sticker-goal p { font-size: 21px; margin-bottom: 12px; }
.sticker-goal b { color: var(--accent-ink); font-size: 25px; } /* 批次F ② */

.green-progress {
  height: 24px;
  border-radius: 14px;
  background: rgba(255, 255, 255, .55); /* 批次F ② */
  overflow: hidden;
}

.green-fill {
  height: 100%;
  width: 0%;
  border-radius: 14px;
  background: linear-gradient(90deg, #58C96B, #4DD8C0);
  transition: width .8s cubic-bezier(.34, 1.3, .5, 1);
}

.green-progress-label { font-size: 20px; color: var(--ink-dim); margin: 10px 0 18px; }

/* ---- 周末门票 ---- */
.ticket-result { text-align: center; }

.ticket-result .t-icon { width: 84px; height: 84px; margin: 0 auto 10px; color: var(--yellow); }
.ticket-result .t-icon svg { width: 100%; height: 100%; }
.ticket-result .t-big { font-size: 28px; font-weight: 800; color: var(--accent-ink); } /* 批次F ② */
.ticket-result .t-sub { font-size: 22px; color: var(--ink-dim); margin-top: 6px; }

/* ---- 商店 ---- */
.shop-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
}

@media (max-width: 560px) {
  .shop-grid { grid-template-columns: 1fr; }
}

.shop-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  min-height: 190px;
  padding: 22px 16px 20px;
  border-radius: var(--r-lg);
  background: var(--card-bg);
  border: 2px solid var(--card-line);
  box-shadow: 0 8px 24px rgba(58, 40, 16, .22);
  transition: transform .3s cubic-bezier(.34, 1.56, .64, 1), filter .3s;
}

.shop-card .c-icon { width: 58px; height: 58px; color: var(--orange); }
.shop-card .c-icon svg { width: 100%; height: 100%; }
.shop-card .c-title { font-size: 24px; font-weight: 800; text-align: center; }
.shop-card .c-sub { font-size: 20px; color: var(--ink-dim); text-align: center; }

.shop-card .price {
  font-size: 22px;
  font-weight: 800;
  color: var(--accent-ink); /* 批次F ② */
}

.shop-card.locked { filter: grayscale(.6) brightness(.96); }
.shop-card.locked .c-icon { color: rgba(74, 54, 40, .42); }
.shop-card.locked .price { color: rgba(74, 54, 40, .72); }
.shop-card .need-more { font-size: 20px; color: var(--orange); font-weight: 700; padding: 10px 18px; }

/* ---- 券包 ---- */
.voucher-strip {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  padding: 6px 2px 16px;
  -webkit-overflow-scrolling: touch;
}

.vou-card {
  flex: 0 0 auto;
  width: 240px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 22px 16px;
  border-radius: var(--r-lg);
  background: linear-gradient(170deg, rgba(255, 201, 77, .2), rgba(255, 138, 61, .1));
  border: 2px dashed rgba(255, 201, 77, .55);
  text-align: center;
}

.vou-card .c-icon { width: 52px; height: 52px; color: var(--yellow); }
.vou-card .c-icon svg { width: 100%; height: 100%; }
.vou-card .v-name { font-size: 23px; font-weight: 800; }
.vou-card .v-stars { font-size: 20px; color: var(--accent-ink); } /* 批次F ② */
.vou-card .v-date { font-size: 20px; color: var(--ink-dim); }
.vou-card .v-status {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 20px;
  font-weight: 700;
  color: #0F8F7D; /* 批次F ②：浅底加深青 */
}

.vou-card.fulfilled { opacity: .62; border-style: solid; border-color: rgba(77, 216, 192, .5); }
.vou-card.fulfilled .v-status { color: #0F8F7D; }
.vou-card.expired { opacity: .5; filter: grayscale(.8); border-color: rgba(122, 88, 44, .3); }
.vou-card.expired .v-status { color: var(--ink-dim); }

.vou-empty { font-size: 21px; color: var(--ink-dim); padding: 20px; text-shadow: 0 0 3px rgba(255,255,255,.95), 0 0 6px rgba(255,255,255,.8); }  /* V200-G ①：草地直压加白晕 */

/* ---- 兑换确认弹窗（三数字） ---- */
.redeem-math {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 20px;
  margin: 18px 0 8px;
}

.redeem-math .m-label { font-size: 21px; color: var(--ink-dim); display: block; }
.redeem-math .m-need { font-size: 44px; font-weight: 900; color: #C2611B; } /* 批次F ②：浅底加深 */
.redeem-math .m-minus { font-size: 32px; font-weight: 900; color: #D63A3A; }
.redeem-math .m-have { font-size: 44px; font-weight: 900; color: #0F8F7D; }

.redeem-left { font-size: 23px; color: var(--accent-ink); font-weight: 700; margin-bottom: 4px; }

/* ---- 券结果弹窗 ---- */
.vou-result .c-icon { width: 74px; height: 74px; margin: 0 auto 8px; color: var(--yellow); }
.vou-result .c-icon svg { width: 100%; height: 100%; }
.vou-result .v-name { font-size: 30px; font-weight: 800; }
.vou-result .v-meta { font-size: 21px; color: var(--ink-dim); margin-top: 8px; }
.vou-result .v-wait { display: flex; align-items: center; justify-content: center; gap: 10px; font-size: 21px; color: #0F8F7D; margin-top: 14px; }

/* ---- 弹窗内竖排按钮列表（习惯 / 贴纸选择） ---- */
.habit-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-top: 6px;
}

.habit-list .btn { width: 100%; justify-content: flex-start; padding-left: 26px; }

/* ---- 小齿轮 ---- */
#btn-gear {
  position: fixed;
  right: 16px;
  bottom: 16px;
  width: 64px;
  height: 64px;
  min-height: 64px;
  padding: 0;
  border-radius: 50%;
  /* 批次F ②：草地浅底上的磨砂白圆片（原深底玻璃翻亮；图标本身浅蓝系，压暗保对比） */
  background: rgba(255, 255, 255, .58);
  border: 1.5px solid rgba(122, 88, 44, .35);
  color: rgba(74, 54, 40, .8);
  box-shadow: 0 4px 16px rgba(58, 40, 16, .25);
  z-index: 30;
  display: grid;
  place-items: center;
  transition: background .2s, transform .2s, border-color .2s;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

#btn-gear:hover {
  background: rgba(255, 255, 255, .78);
  border-color: rgba(197, 138, 32, .6);
  color: #4A3628;
}

#btn-gear:active { transform: scale(.94); }
#btn-gear svg { width: 30px; height: 30px; filter: brightness(.78) saturate(.92); }

/* ================= 窄屏适配（≤480px 手机竖屏） =================
   🔴 修复：星罐段 216(jar) + 170(num) + 26(gap) + 36(padding) = 448px
      超过 iPhone 390~430px 视口 → 右侧内容被裁切。
   策略：窄屏时罐体与数字改为纵向堆叠。
   v1.0.3 §2.2 P0-4：星径基准 30→40（×1.333）后，堆叠档位按 128×168 罐腔标定，
      窄屏不再缩小罐体（缩小编腔会出瓶口）——纵向堆叠 + 整罐 216×256 保持不变。 */
@media (max-width: 480px) {
  .view { padding: 14px 12px 110px; }

  .jar-section {
    flex-direction: column;
    gap: 10px;
    padding: 8px 0 2px;
  }
  .jar-num-wrap { min-width: 0; }
  .jar-number { font-size: 54px; }
  .jar-unit { font-size: 20px; }

  .sec-title { font-size: 23px; margin: 22px 2px 12px; }

  /* 猫走路路线：等比缩小（房子/石头/公园/猫），留出猫半径避免飞出容器。
     批次F ⑥：曲线版——line 26+64，路中线 y=20/40 → 距底 58px = 猫脚(bottom 58)，
     石头 top：上石 y14→22.4-15=7px / 下石 y26→41.6-15=27px */
  .track-wrap { height: 134px; margin: 4px 14px 0 6px; }
  .track-line { left: 52px; right: 52px; bottom: 26px; height: 64px; }   /* V200-G ④移动端：36→52（房右缘44+8）*/
  .route-house { width: 48px; height: 48px; left: -4px; bottom: 46px; }
  .planet { width: 56px; height: 84px; right: -8px; bottom: 46px; }
  .rocket { width: 58px; height: 58px; margin-left: 52px; bottom: 58px; }  /* V200-G ④移动端：36→52 同步 */
  .tick .stone { width: 30px; height: 30px; }
  .ticks { left: 52px; right: 52px; bottom: 26px; height: 64px; }         /* V200-G ④移动端：36→52 同步 */
  .tick:nth-child(1), .tick:nth-child(3), .tick:nth-child(5) { top: 7px; }
  .tick:nth-child(2), .tick:nth-child(4) { top: 27px; }
  .track-caption { font-size: 20px; }

  .card { min-height: 190px; padding: 18px 12px 16px; }
}

/* 超窄屏（≤360px，老设备）：罐体同样保持 216×256（见 ≤480 注释） */
@media (max-width: 360px) {
  .jar-number { font-size: 46px; }
  .sec-title { font-size: 21px; }
}

/* ================= 离线提示条（孩子友好 + 家长线索） ================= */
.offline-hint {
  position: fixed;
  left: 50%;
  bottom: 92px;
  transform: translateX(-50%);
  z-index: 40;
  width: min(92vw, 520px);
  padding: 16px 18px 14px;
  border-radius: 22px;
  background: linear-gradient(170deg, rgba(40, 46, 78, .96), rgba(26, 31, 58, .96));
  border: 1.5px solid rgba(255, 201, 77, .38);
  box-shadow: 0 12px 34px rgba(0, 0, 0, .5), 0 0 22px rgba(255, 201, 77, .18);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  text-align: center;
  animation: popIn .3s cubic-bezier(.34, 1.56, .64, 1);
}
.offline-hint[hidden] { display: none !important; }

.offline-hint .oh-kid {
  font-size: 21px;
  font-weight: 700;
  color: #FFE9A8;
  line-height: 1.5;
}
.offline-hint .oh-parent {
  margin-top: 8px;
  font-size: 20px;
  font-weight: 500;
  color: rgba(255, 247, 230, .62);
  line-height: 1.45;
  word-break: break-all;
}
.offline-hint .oh-retry {
  margin-top: 12px;
  min-height: 72px;
  padding: 0 34px;
  border-radius: 40px;           /* v1.0.3 §2.3 游戏风胶囊 */
  font-size: 24px;
  font-weight: 800;
  color: #3a2800;
  background: linear-gradient(180deg, var(--yellow), var(--yellow-deep));
  box-shadow:
    inset 0 3px 0 rgba(255, 255, 255, .42),
    0 8px 0 #8F5E0F,
    0 14px 26px rgba(0, 0, 0, .3);
}
.offline-hint .oh-retry:active { transform: scale(.96); }

/* 离线提示条内的 SVG 月亮：与文字同色同大小，避免 emoji 字体缺失 */
.offline-hint .oh-kid svg {
  width: 24px;
  height: 24px;
  vertical-align: -4px;
  margin-right: 4px;
  fill: #FFE9A8;
}

.offline-hint .oh-meta {
  margin-top: 8px;
  font-size: 18px;
  color: rgba(255, 247, 230, .42);
  line-height: 1.4;
  word-break: break-all;
}
.offline-hint .oh-actions {
  margin-top: 12px;
  display: flex;
  gap: 10px;
  justify-content: center;
  flex-wrap: wrap;
}
.offline-hint .oh-retry,
.offline-hint .oh-refresh {
  min-height: 72px;
  padding: 0 28px;
  border-radius: 40px;
  font-size: 24px;
  font-weight: 800;
}
.offline-hint .oh-refresh {
  color: #FFE9A8;
  background: rgba(255, 255, 255, .1);
  border: 1.5px solid rgba(255, 201, 77, .45);
  box-shadow: none;
}
.offline-hint .oh-refresh:active { transform: scale(.96); }

/* ================= Header 日期 ================= */
.kh-left { display: flex; flex-direction: column; gap: 2px; }
/* v2.1 主题抽象：主标题（通用系统名）下方一行当前主题名。
   🔴 只做视觉，文案由 theme.js 从 rules.theme 渲染；字号≥20px 守儿童可用性下限。 */
.kid-subtitle {
  font-size: 21px;
  font-weight: 700;
  color: rgba(74, 54, 40, .82);
  text-shadow: 0 0 3px rgba(255, 255, 255, .95), 0 0 6px rgba(255, 255, 255, .8);
  letter-spacing: .4px;
  padding-left: 4px;
  margin-top: 2px;
}

.kid-date {
  font-size: 20px;
  font-weight: 600;
  color: rgba(74, 54, 40, .82); /* 批次F ②；V200-G ① .62→.82 提 alpha */
  text-shadow: 0 0 3px rgba(255,255,255,.95), 0 0 6px rgba(255,255,255,.8);  /* V200-G ①：草地直压加白晕 */
  letter-spacing: .4px;
  padding-left: 4px;
}

/* ================= 我的纪录 ================= */
.stats-card {
  /* 批次F ②：浅底暖白卡 */
  background:
    radial-gradient(120% 80% at 50% 0%, rgba(255, 255, 255, .95), rgba(255, 255, 255, 0) 62%),
    linear-gradient(168deg, rgba(255, 255, 255, .94), rgba(255, 251, 236, .86));
  border: 1.5px solid rgba(122, 88, 44, .22);
  border-radius: var(--r-lg);
  padding: 22px 20px 20px;
  box-shadow: 0 10px 26px rgba(58, 40, 16, .2);
}

.stats-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}
.stat-tile {
  text-align: center;
  padding: 12px 6px;
  border-radius: 18px;
  background: rgba(255, 255, 255, .5);
  border: 1px solid rgba(122, 88, 44, .16);
}
.stat-tile .st-num {
  font-size: 30px;
  font-weight: 900;
  line-height: 1.1;
  color: var(--accent-ink); /* 批次F ② */
  font-variant-numeric: tabular-nums;
}
.stat-tile .st-label {
  margin-top: 4px;
  font-size: 20px;
  font-weight: 600;
  color: rgba(74, 54, 40, .72);
}
.stat-tile.green .st-num { color: #2F9E4D; }
.stat-tile.teal .st-num { color: #0F8F7D; }
.stat-tile.orange .st-num { color: #C2611B; }

.stats-chart-title {
  font-size: 21px;
  font-weight: 700;
  color: rgba(74, 54, 40, .78);
  margin-bottom: 10px;
}
.stats-chart {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 130px;
  padding-top: 8px;
  border-bottom: 1.5px dashed rgba(122, 88, 44, .3);
  position: relative;
  margin-bottom: 30px;
}
.sc-bar-wrap {
  flex: 1;
  height: 100%;
  display: flex;
  align-items: flex-end;
  position: relative;
}
.sc-bar {
  position: relative;   /* 数值标签贴柱顶定位用（v1.0.1 合并重复定义） */
  width: 100%;
  border-radius: 6px 6px 3px 3px;
  background: linear-gradient(180deg, var(--yellow), var(--yellow-deep));
  min-height: 3px;
  transition: height .5s cubic-bezier(.34, 1.4, .64, 1);
  box-shadow: 0 2px 8px rgba(255, 201, 77, .28);
}
/* 零值柱：底部小矮块表示「这天没有」，不占满整列 */
.sc-bar.zero {
  background: rgba(122, 88, 44, .18);
  border-radius: 3px;
  box-shadow: none;
}
.sc-bar.hit { background: linear-gradient(180deg, #58C96B, #2F9E4D); box-shadow: 0 2px 8px rgba(88, 201, 107, .35); }
.sc-goal-line {
  position: absolute;
  left: 0; right: 0;
  border-top: 1.5px dashed rgba(15, 143, 125, .55);
  pointer-events: none;
}
.sc-x {
  position: absolute;
  bottom: -24px;
  left: 0; right: 0;
  text-align: center;
  font-size: 18px;
  color: rgba(74, 54, 40, .72);
}

.stats-chart-legend {
  display: flex;
  gap: 20px;
  font-size: 19px;
  color: rgba(74, 54, 40, .72);
  margin-top: 4px;
}
.stats-chart-legend span { display: inline-flex; align-items: center; gap: 6px; }
.lg-star { width: 12px; height: 12px; border-radius: 3px; background: var(--yellow); display: inline-block; }
.lg-line { width: 20px; height: 0; border-top: 1.5px dashed var(--teal); display: inline-block; }

/* ================= 我的成就（v1.0.1：5 系列 + 进度条） ================= */
.achv-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}
.achv-series {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px 16px 14px;
  border-radius: 22px;
  background: rgba(255, 255, 255, .86);   /* 批次F ②；V200-I②：.5→.86 直压草地须达 AA */
  border: 1.5px solid rgba(122, 88, 44, .18);
  transition: border-color .2s, background .2s, box-shadow .2s;
}
.achv-series .a-head {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.achv-series .a-emoji {
  font-size: 30px;
  line-height: 1;
  flex: none;
  filter: grayscale(.75) opacity(.6);
  transition: filter .3s;
}
.achv-series .a-name {
  font-size: 21px;
  font-weight: 800;
  color: rgba(74, 54, 40, .72);
  line-height: 1.3;
}
.achv-series .a-max {
  margin-left: auto;
  font-size: 20px;                 /* V200-I⁴ P1-1：17→20 满足 base.css 20px 红线 */
  font-weight: 700;
  color: #1F7837;                  /* V200-I⁴ P0-1：.on 卡上 #2F9E4D 仅 3.04；改深绿 ≥4.9 */
  white-space: nowrap;
}
.achv-series .a-bar {
  height: 16px;
  border-radius: 10px;
  background: rgba(255, 255, 255, .6);
  overflow: hidden;
}
.achv-series .a-bar-fill {
  height: 100%;
  width: 0%;
  border-radius: 10px;
  background: linear-gradient(90deg, var(--teal), var(--yellow));
  box-shadow: 0 0 10px rgba(255, 201, 77, .45);
  transition: width .8s cubic-bezier(.34, 1.3, .5, 1);
}
.achv-series .a-next {
  font-size: 20px;                 /* V200-I⁴ P1-1：18→20 满足 20px 红线 */
  color: rgba(74, 54, 40, .72);
}
.achv-series .a-desc {
  font-size: 20px;                 /* V200-I⁴ P1-1：18→20 满足 20px 红线 */
  color: rgba(74, 54, 40, .72);
  line-height: 1.4;
}
/* 当前级已解锁：图标点亮 + 暖色描边 */
.achv-series.on {
  /* V200-I² P0：解锁态须达 AA——原半透明渐变压草地时 a-next/desc 仅 2.95~3.06；
     改不透明浅暖底（两端 a-name 6.57/6.94、a-next 4.55/4.69，均 ≥4.5）。 */
  background: linear-gradient(160deg, #FCF1CE, #FEF7E4);
  border-color: rgba(197, 138, 32, .58);
  box-shadow: 0 6px 20px rgba(197, 138, 32, .22);
}
.achv-series.on .a-emoji { filter: none; }
.achv-series.on .a-name { color: #7A4A00; }
.achv-series.on .a-next { color: rgba(74, 54, 40, .78); }  /* V200-I⁴ P1-2：.72 余量仅 0.08→.78 */
/* 终极成就：虚线神秘框，解锁后实线发光 */
.achv-series.ultimate { border-style: dashed; }
.achv-series.ultimate.on {
  border-style: solid;
  border-color: rgba(47, 158, 77, .62);
  /* V200-I² P0：同 .on——改不透明浅绿底（两端 a-next 4.59/4.70）。 */
  background: linear-gradient(160deg, #E6F6E4, #EFF9EC);
  box-shadow: 0 6px 22px rgba(47, 158, 77, .25);
}

/* 纪录触顶提示（P1-3：/api/stats truncated 时显示） */
.stats-hint {
  margin-top: 8px;
  font-size: 18px;
  color: rgba(74, 54, 40, .72);
}

@media (max-width: 480px) {
  .stats-row { grid-template-columns: repeat(3, 1fr); gap: 8px; }
  .stat-tile .st-num { font-size: 26px; }
  .stat-tile .st-label { font-size: 18px; }
  .achv-grid { grid-template-columns: 1fr; }
  .stats-chart { height: 110px; }
  .sc-x { font-size: 16px; }
}

/* 零值柱与数值标签样式已并入上方 .sc-bar / .sc-bar.zero 主定义（v1.0.1 合并重复） */
.sc-val {
  position: absolute;
  top: -19px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 17px;
  font-weight: 800;
  color: var(--accent-ink); /* 批次F ② */
  white-space: nowrap;
}

/* 贴纸墙说明：孩子能读懂的一句话 */
.sticker-intro {
  font-size: 20px;
  line-height: 1.55;
  color: rgba(74, 54, 40, .78); /* 批次F ② */
  font-weight: 500;
  margin-bottom: 14px;
  padding: 0 2px;
}


/* ================= 成就图标（内联 SVG，替代 emoji）================= */
.achv-series .a-head {
  display: flex;
  align-items: center;
  gap: 10px;
}
.achv-series .a-ico {
  width: 34px;
  height: 34px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 11px;
  background: rgba(255, 255, 255, .55);
  color: rgba(74, 54, 40, .45);
  transition: background .25s, color .25s;
}
.achv-series .a-ico svg { width: 21px; height: 21px; }
.achv-series.on .a-ico {
  background: linear-gradient(180deg, #FFD75E, #F0A828);
  color: #4a2400;
  box-shadow: 0 3px 12px rgba(255, 201, 77, .35);
}
.achv-series .a-name {
  font-size: 22px;
  font-weight: 800;
  color: rgba(74, 54, 40, .72);
  line-height: 1.3;
}
.achv-series.on .a-name { color: #7A4A00; }
.achv-series .a-max {
  margin-left: auto;
  font-size: 20px;                 /* V200-I⁴ P1-1：18→20 满足 20px 红线 */
  font-weight: 700;
  color: #1F7837;                  /* V200-I⁴ P0-1：同深绿 */
  white-space: nowrap;
}
.achv-series .a-bar {
  margin-top: 10px;
  height: 10px;
  border-radius: 6px;
  background: rgba(255, 255, 255, .6);
  overflow: hidden;
}
.achv-series .a-bar-fill {
  height: 100%;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--teal), var(--yellow));
  transition: width .5s cubic-bezier(.34, 1.4, .64, 1);
}
.achv-series .a-next {
  margin-top: 8px;
  font-size: 20px;
  font-weight: 600;
  color: rgba(74, 54, 40, .72);
}
.achv-series .a-desc {
  margin-top: 8px;
  font-size: 20px;                 /* V200-I⁴ P1-1：19→20 满足 20px 红线 */
  line-height: 1.5;
  color: rgba(74, 54, 40, .72);
}
.achv-series.ultimate {
  grid-column: 1 / -1;
  /* V200-I⁴ P0-2：锁定态原半透明底压草地 a-next 仅 3.01；改不透明浅底 #F3F6E6。 */
  background: #F3F6E6;
  border-color: rgba(197, 138, 32, .38);
}


/* ═══════════════════════════════════════════════════════════════
 * v1.0.2 记录器模式（recorder）——以下全部为追加样式，不改动上方任何规则
 * ═══════════════════════════════════════════════════════════════ */

/* ---- 模式显隐：挂 html[data-mode]（head 内联脚本 0 延迟写入，防 FOUC） ---- */
html[data-mode="recorder"] [data-rule-only] { display: none !important; }
html[data-mode="rule"] [data-recorder-only] { display: none !important; }

/* ---- 路线节点「已点亮」态（当天拿到综合星 → 点亮石头；暖金光晕） ---- */
.tick.lit { color: var(--accent-ink); font-weight: 800; } /* 批次F ②：浅底改金棕 */
.tick.lit .stone {
  filter: drop-shadow(0 0 14px rgba(255, 201, 77, .95)) drop-shadow(0 0 4px rgba(255, 255, 255, .85));
}

/* ---- 加星按钮（星罐下方，长按 1.5s） ---- */
#star-btn-zone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 6px 16px 4px;
}
.star-add-btn {
  min-height: 78px;              /* 触摸区 ≥72px */
  min-width: min(100%, 320px);
  padding: 18px 36px;
  border: none;
  border-radius: 40px;           /* v1.0.3 §2.3 游戏风胶囊 */
  font-size: 27px;
  font-weight: 800;
  color: #4a2400;
  background: linear-gradient(180deg, #FFE08A, #F0A828);
  /* v1.0.3 §2.3 3D 立体：内高光 + 硬阴影底座 + 贴地投影 + 外发光 */
  box-shadow:
    inset 0 3px 0 rgba(255, 255, 255, .5),
    0 8px 0 #B3761C,
    0 16px 30px rgba(240, 168, 40, .32),
    0 0 22px rgba(255, 201, 77, .38);
  cursor: pointer;
  transition: transform .2s ease, box-shadow .2s ease;
}
/* 呼吸灯由 .btn-breathe 挂载（index.html class）；按压停呼吸、下沉 4px */
.star-add-btn:active { transform: translateY(4px) scale(.97); }
.star-add-btn.pulse { animation: starBtnPulse .32s ease; }
@keyframes starBtnPulse {
  0% { transform: scale(1); }
  40% { transform: scale(1.05); }
  100% { transform: scale(1); }
}
/* 软提示（松塔 P2-1）：小字、无动画、无音效——绝不做提示条/弹窗（批次F ② 浅底化） */
.star-hint {
  font-size: 20px;
  color: rgba(74, 54, 40, .82);   /* V200-G ① .58→.82 提 alpha */
  line-height: 1.4;
  text-shadow: 0 0 3px rgba(255,255,255,.95), 0 0 6px rgba(255,255,255,.8), 0 1px 1px rgba(255,255,255,.9);  /* V200-G ①：白晕 */
}

/* ---- 今天获得的星星（时间列表） ---- */
#today-stars { padding: 10px 16px 4px; }
.today-stars-title {
  font-size: 24px;
  font-weight: 800;
  color: var(--ink, #FFF7E6);
  margin: 0 0 10px;
  text-shadow: 0 0 3px rgba(255,255,255,.95), 0 0 7px rgba(255,255,255,.85);  /* V200-G ①：草地直压标题加白晕 */
}
.today-stars-title #today-count { color: var(--accent-ink); font-size: 28px; } /* 批次F ② */
.today-stars-title .tsp { font-size: 20px; font-weight: 600; color: rgba(74, 54, 40, .82); text-shadow: 0 0 3px rgba(255,255,255,.95), 0 0 6px rgba(255,255,255,.8); } /* V200-G ①：.62→.82+白晕 */
.star-time-list {
  list-style: none;
  margin: 0;
  padding: 4px;
  max-height: 320px;             /* 超出滚动 */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  border-radius: 18px;
  background: rgba(255, 255, 255, .55); /* 批次F ② */
}
.stl-row {
  display: flex;
  align-items: center;
  gap: 18px;
  min-height: 72px;              /* 行触摸区 ≥72px */
  padding: 0 18px;
}
.stl-row + .stl-row { border-top: 1px solid rgba(122, 88, 44, .14); }
.stl-time {
  font-size: 25px;               /* 时间字号 ≥24px */
  font-weight: 700;
  color: rgba(74, 54, 40, .88);  /* 批次F ② */
  font-variant-numeric: tabular-nums;
}
.stl-star { width: 30px; height: 30px; color: var(--yellow); }
.stl-star svg { width: 100%; height: 100%; }
.stl-star img { width: 100%; height: 100%; object-fit: contain; image-rendering: pixelated; } /* V200-I² P1-2：货币图标改像素蝴蝶结 */

/* ---- 券包：兑换入口（记录器模式唯一兑换路径，券包空且余额够时出现） ---- */
.redeem-inline {
  width: 100%;
  min-height: 78px;
  font-size: 25px;
  font-weight: 800;
  border-radius: 40px;
}

/* ---- 撕票券（单张大券） ---- */
.tear-ticket {
  position: relative;
  width: min(100%, 360px);
  height: 190px;
  margin: 0 auto;
  user-select: none;
  -webkit-user-select: none;
  /* 🔴 v2.4.3：圆角与阴影收到【整张券】上，不再挂到两个半张上。
     原先两半各带阴影，视觉上像「已经撕开的两张」，与「点开应是一整张」矛盾。 */
  border-radius: 20px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .4);
  will-change: transform;
  /* 注意：touch-action:none 只在撕票 overlay 内启用（下方 .tear-overlay .tear-ticket），
     券包里的券不锁——否则整张券变成页面滚动死区 */
}
/* ============================================================================
   🔴 v2.4.5 撕票结构（Jeff 14:16 明确纠正，这是最终形态）
   ----------------------------------------------------------------------------
   问题回顾：v2.4.3/v2.4.4 都把券事先拆成上下两半再拼起来。
     即便像素对齐、clip 无缝，用户仍能看到「中间有分割、像两张券拼接」——
     因为两半各自有独立圆角与边缘。**根本错误是"撕开前就拆"**。

   本版正确的两层模型：
     ① 撕开前 → .tt-flat 单层：一整张完整图 + 整卡圆角 + 整卡阴影，
        中间只有一条【横向虚线】作为撕开提示。此时 .tt-upper/.tt-lower 完全隐藏。
     ② 滑动之后 → JS 给 .tear-ticket 加 .tearing 类：
        .tt-flat 隐藏、两半显形，随后才开始分离动画。

   两半裁切刻意【重叠 0.4%】，抵消亚像素舍入，避免分离过程中出现发丝缝。
   ============================================================================ */

/* ── 撕开前：完整一张卡 ── */
.tt-flat {
  position: absolute;
  inset: 0;
  z-index: 1;                    /* 完整券在最底层；虚线 3 / 裂口 4 在它上面 */
  background: linear-gradient(165deg, #FFF3D0 0%, #FFE08A 55%, #F5C860 100%);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: center center;
  border-radius: 20px;
  overflow: hidden;
}
.tt-flat .tt-face { position: absolute; inset: 0; }

/* ── 撕开后才出现的两半：默认隐藏 ── */
.tt-half {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;                  /* 半张 = 整券大小，靠 clip 只露一半 */
  overflow: hidden;
  background: linear-gradient(165deg, #FFF3D0 0%, #FFE08A 55%, #F5C860 100%);
  opacity: 0;                    /* 🔴 默认不可见：撕开前只有 .tt-flat */
  pointer-events: none;
  will-change: transform;
  z-index: 2;
}
.tear-ticket.tearing .tt-flat { opacity: 0; }
.tear-ticket.tearing .tt-half { opacity: 1; }

/* 上下各露一半，重叠 0.4% 消除发丝缝 */
.tt-upper {
  clip-path: inset(0 0 49.6% 0);
  border-radius: 20px 20px 0 0;
}
.tt-lower {
  clip-path: inset(49.6% 0 0 0);
  border-radius: 0 0 20px 20px;
}
.tt-inner {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.tt-top {
  position: absolute;
  top: 18px;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.tt-badge {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 34px;               /* 券标题 ≥32px */
  font-weight: 900;
  letter-spacing: .18em;
  color: #7a4a00;
}
.tt-badge svg { width: 34px; height: 34px; color: #E8A32F; }
.tt-sub { font-size: 21px; font-weight: 600; color: rgba(122, 74, 0, .8); }
.tt-bottom {
  position: absolute;
  bottom: 16px;
  left: 0;
  right: 0;
  text-align: center;
  font-size: 20px;
  font-weight: 600;
  color: rgba(122, 74, 0, .55);
  letter-spacing: .1em;
}
/* 齿孔：高度 2px（🔴 是高度不是宽度），水平铺满，垂直居中；ASCII 图仅示意位置 */
.tt-perf {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 2px;
  transform: translateY(-50%);
  background: repeating-linear-gradient(90deg,
    rgba(11, 16, 38, .0) 0 3px,
    rgba(11, 16, 38, .55) 3px 5px);
  pointer-events: none;
  z-index: 3;
}
/* 撕开时的白色裂口（宽度由 JS 按 dx*0.15 设置） */
/* 撕开时的白色裂口：🔴 v2.4.3 由竖向改为横向（撕口横向）
 *   宽度铺满两侧 18%~82%，厚度（height）由 JS 按拖动距离增长 */
.tt-crack {
  position: absolute;
  left: 18%;
  right: 18%;
  top: 50%;
  height: 0;
  transform: translateY(-50%);
  background: linear-gradient(90deg, rgba(255, 255, 255, .6), rgba(255, 255, 255, .95), rgba(255, 255, 255, .6));
  box-shadow: 0 0 12px rgba(255, 255, 255, .9);
  border-radius: 3px;
  pointer-events: none;
  z-index: 4;
}

/* ---- 撕票全屏层 ---- */
.tear-overlay {
  position: fixed;
  inset: 0;
  z-index: 61;                   /* press=60 之上、toast=99 之下 */
  display: grid;
  place-items: center;
  background: rgba(4, 7, 20, .62);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  touch-action: none;            /* 🔴 锁在 overlay 上，手指下拉不带body滚（§五②c） */
  user-select: none;
  -webkit-user-select: none;
  opacity: 1;
  transition: opacity .6s ease;
}
.tear-overlay.fade { opacity: 0; }
.tear-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: min(92vw, 400px);
}
.tear-tip {
  font-size: 22px;
  font-weight: 700;
  color: rgba(255, 247, 230, .9);
  animation: tearTipPulse 1.5s ease-in-out infinite;
}
@keyframes tearTipPulse {
  0%, 100% { opacity: .55; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.04); }
}
/* ① 点击券 → 放大到屏幕中央：scale 1 → 1.06，300ms（宽度在 transform 前测量）
   🔴 touch-action:none 只在撕票 overlay 内启用（§五②d），券包里的券不锁滚动 */
.tear-overlay .tear-ticket { transform: scale(1); transition: transform .3s cubic-bezier(.34, 1.3, .64, 1); touch-action: none; }
.tear-overlay .tear-ticket.zoomed { transform: scale(1.06); }
.tear-close {
  margin-top: 6px;
  min-height: 72px;
  min-width: 72px;
  padding: 0 26px;
  border: 1px solid rgba(255, 255, 255, .3);
  border-radius: 18px;
  background: rgba(255, 255, 255, .08);
  color: rgba(255, 247, 230, .8);
  font-size: 24px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.tear-close svg { width: 24px; height: 24px; }

/* ---- 已用券折叠区 ---- */
#used-zone { padding: 2px 16px 20px; }
.used-toggle {
  min-height: 72px;
  width: 100%;
  padding: 0 20px;
  border: none;
  border-radius: 16px;
  background: rgba(255, 255, 255, .55); /* 批次F ② */
  color: rgba(74, 54, 40, .78);
  font-size: 24px;
  font-weight: 700;
  text-align: left;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}
.used-toggle::before {
  content: '▸';
  font-size: 20px;
  transition: transform .25s ease;
}
#used-zone.open .used-toggle::before { transform: rotate(90deg); }
.used-list { padding: 6px 4px 0; }
.used-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 14px;
  min-height: 72px;
  padding: 8px 14px;
  border-radius: 14px;
  background: rgba(255, 255, 255, .86); /* 批次F ②；V200-I②：.5→.86 + 去行级 opacity（原 .85 把文字压到 2.92）*/
}
.used-row + .used-row { margin-top: 6px; }
.used-row .u-ico { width: 26px; height: 26px; color: rgba(74, 54, 40, .5); flex: none; }
.used-row .u-ico svg { width: 100%; height: 100%; }
.used-row .u-name { font-size: 22px; font-weight: 700; color: rgba(74, 54, 40, .88); }
.used-row .u-date {
  font-size: 20px;
  color: rgba(74, 54, 40, .72);
  font-variant-numeric: tabular-nums;
}
.used-row .u-note {
  margin-left: auto;
  font-size: 20px;
  color: rgba(74, 54, 40, .72);
}

@media (max-width: 480px) {
  .tear-ticket { height: 175px; }
  .tt-badge { font-size: 32px; }
  .star-add-btn { font-size: 26px; }
}

/* ---- 罐内漂浮（L1-A）遵守系统减动效偏好 ---- */
@media (prefers-reduced-motion: reduce) {
  .tear-tip { animation: none; }
  /* v1.0.3 批次B P1-3：存量无限/一次性动画统一停（C8）；
     v2.0 批次B：猫颠步停 → 静态站姿（不位移，仅保留 scaleX 朝向） */
  .planet.glow,
  .cat-frame,
  .jar-wrap.bounce,
  .jar-number.num-tick,
  .card.pulse,
  .sticker.pop { animation: none !important; }
  /* 减动效：双帧静止，只留帧1（否则两帧 opacity:1 重叠） */
  .cat-frame[data-frame="1"] { opacity: 1 !important; }
  .cat-frame[data-frame="2"] { opacity: 0 !important; }
}

/* ---- 控制台「撤销综合星」联动确认弹窗（v1.0.2 松塔 P0-1，console.js 渲染在 kid 页） ---- */
.rvk-text {
  font-size: 22px;
  line-height: 1.6;
  color: rgba(74, 54, 40, .88); /* 批次F ②：弹窗已浅底化 */
  margin: 4px 0;
}
.rvk-text b { color: var(--accent-ink); font-size: 25px; }
.rvk-actions { flex-wrap: wrap; gap: 10px; }
.rvk-actions .btn { flex: 1 1 100%; min-height: 72px; font-size: 24px; }

/* ============================================================================
   v2.3 券面版式（Jeff 12:15 定）
   ----------------------------------------------------------------------------
   券面只有三层：大数字 → 自定义券名 → 轻滑撕开
   🔴 不印单位、不印币名、不印主题图标 —— 跨主题零耦合，
      换任何主题券面都成立（数字孩子一眼就懂）。
   ============================================================================ */
.tt-big {
  font-size: 62px;
  font-weight: 900;
  line-height: 1;
  letter-spacing: -2px;
  font-variant-numeric: tabular-nums;
  color: #7a4a00;                       /* 默认金色系；各 .vstyle-* 覆盖 */
  text-shadow: 0 2px 0 rgba(255, 255, 255, .9), 0 0 14px rgba(255, 255, 255, .75);
}
.tt-name {
  margin-top: 8px;
  font-size: 20px;
  font-weight: 800;
  letter-spacing: 2px;
  color: rgba(122, 74, 0, .88);
}
/* 券包内小尺寸：数字等比缩小，仍保证醒目 */
.voucher-grid .tt-big { font-size: 44px; letter-spacing: -1.5px; }
.voucher-grid .tt-name { font-size: 16px; letter-spacing: 1.5px; margin-top: 5px; }

/* ============================================================================
   v2.2 券样式目录（13 种 · 设计卡 V220_MULTI_VOUCHER_DESIGN_CARD.md）
   ----------------------------------------------------------------------------
   🔴 铁律：结构冻结。下列变体只覆盖「配色/纹理/光晕」，绝不改
      .tt-half / .tt-inner / .tt-top / .tt-badge / .tt-perf / .tt-crack
      的定位与尺寸 —— 撕票手势的几何契约（宽度 50%、inner 200%、齿孔居中）
      依赖这些值，改一个就会撕歪。
   🔴 样式挂在 .tear-ticket 上（.vstyle-xxx），由 kid.js 按 item.style 写入。
   🔴 新增样式必须三处同步：
      后端 config.py VOUCHER_STYLES + 本文件 .vstyle-* + 控制台下拉（自动读目录）。
   ============================================================================ */

/* ---- 纯色族：覆盖 .tt-half 底色 + 文字色（保证对比度 ≥4.5:1） ---- */
.vstyle-red .tt-half { background: linear-gradient(165deg, #FFE4E4 0%, #FFB3B3 55%, #E87A7A 100%); }
.vstyle-red .tt-badge { color: #7E1F1F; }
.vstyle-red .tt-badge svg { color: #C94A4A; }
.vstyle-red .tt-sub, .vstyle-red .tt-bottom { color: rgba(126, 31, 31, .8); }
.vstyle-red .tt-big { color: #7E1F1F; }
.vstyle-red .tt-name { color: rgba(126, 31, 31, .8); }

.vstyle-orange .tt-half { background: linear-gradient(165deg, #FFEEDC 0%, #FFCB9A 55%, #F09A4D 100%); }
.vstyle-orange .tt-badge { color: #7A3E00; }
.vstyle-orange .tt-badge svg { color: #D97118; }
.vstyle-orange .tt-sub, .vstyle-orange .tt-bottom { color: rgba(122, 62, 0, .8); }
.vstyle-orange .tt-big { color: #7A3E00; }
.vstyle-orange .tt-name { color: rgba(122, 62, 0, .8); }

.vstyle-green .tt-half { background: linear-gradient(165deg, #E4F8E4 0%, #AEE5AE 55%, #6FC46F 100%); }
.vstyle-green .tt-badge { color: #1B5A1B; }
.vstyle-green .tt-badge svg { color: #3E943E; }
.vstyle-green .tt-sub, .vstyle-green .tt-bottom { color: rgba(27, 90, 27, .8); }
.vstyle-green .tt-big { color: #1B5A1B; }
.vstyle-green .tt-name { color: rgba(27, 90, 27, .8); }

.vstyle-teal .tt-half { background: linear-gradient(165deg, #DDF6F3 0%, #9DE4DC 55%, #59C4B7 100%); }
.vstyle-teal .tt-badge { color: #0D5249; }
.vstyle-teal .tt-badge svg { color: #2A8F83; }
.vstyle-teal .tt-sub, .vstyle-teal .tt-bottom { color: rgba(13, 82, 73, .8); }
.vstyle-teal .tt-big { color: #0D5249; }
.vstyle-teal .tt-name { color: rgba(13, 82, 73, .8); }

.vstyle-blue .tt-half { background: linear-gradient(165deg, #E3EEFF 0%, #B6D1FF 55%, #7DA9ED 100%); }
.vstyle-blue .tt-badge { color: #14396E; }
.vstyle-blue .tt-badge svg { color: #3A6DBF; }
.vstyle-blue .tt-sub, .vstyle-blue .tt-bottom { color: rgba(20, 57, 110, .8); }
.vstyle-blue .tt-big { color: #14396E; }
.vstyle-blue .tt-name { color: rgba(20, 57, 110, .8); }

.vstyle-purple .tt-half { background: linear-gradient(165deg, #F0E6FF 0%, #CDB3FF 55%, #A483E8 100%); }
.vstyle-purple .tt-badge { color: #3D1E70; }
.vstyle-purple .tt-badge svg { color: #6F45B8; }
.vstyle-purple .tt-sub, .vstyle-purple .tt-bottom { color: rgba(61, 30, 112, .8); }
.vstyle-purple .tt-big { color: #3D1E70; }
.vstyle-purple .tt-name { color: rgba(61, 30, 112, .8); }

.vstyle-pink .tt-half { background: linear-gradient(165deg, #FFE8F4 0%, #FFBEE0 55%, #F58CC4 100%); }
.vstyle-pink .tt-badge { color: #7A1E52; }
.vstyle-pink .tt-badge svg { color: #CE4E93; }
.vstyle-pink .tt-sub, .vstyle-pink .tt-bottom { color: rgba(122, 30, 82, .8); }
.vstyle-pink .tt-big { color: #7A1E52; }
.vstyle-pink .tt-name { color: rgba(122, 30, 82, .8); }

/* ---- 金属族：多段渐变模拟金属反光 + 细高光条（静态，不用动画省电） ---- */
.vstyle-metallic_gold .tt-half {
  background:
    linear-gradient(105deg, rgba(255,255,255,.55) 0%, rgba(255,255,255,0) 28%,
                    rgba(255,255,255,.35) 42%, rgba(255,255,255,0) 60%),
    linear-gradient(165deg, #FFF6D8 0%, #F5D46A 30%, #D9A521 52%, #F7E08E 70%, #C08F12 100%);
  box-shadow: 0 10px 30px rgba(120, 80, 0, .45), inset 0 1px 0 rgba(255,255,255,.75);
}
.vstyle-metallic_gold .tt-badge { color: #6B4700; text-shadow: 0 1px 0 rgba(255,255,255,.6); }
.vstyle-metallic_gold .tt-big { color: #6B4700; text-shadow: 0 1px 0 rgba(255,255,255,.6), 0 0 12px rgba(255,245,200,.7); }
.vstyle-metallic_gold .tt-name { color: rgba(107, 71, 0, .82); }
.vstyle-metallic_gold .tt-sub, .vstyle-metallic_gold .tt-bottom { color: rgba(107, 71, 0, .82); }

.vstyle-metallic_silver .tt-half {
  background:
    linear-gradient(105deg, rgba(255,255,255,.7) 0%, rgba(255,255,255,0) 26%,
                    rgba(255,255,255,.45) 40%, rgba(255,255,255,0) 58%),
    linear-gradient(165deg, #F7F9FC 0%, #D6DCE6 30%, #A9B3C2 52%, #E2E8F0 70%, #8C96A6 100%);
  box-shadow: 0 10px 30px rgba(60, 70, 90, .35), inset 0 1px 0 rgba(255,255,255,.85);
}
.vstyle-metallic_silver .tt-badge { color: #38414F; text-shadow: 0 1px 0 rgba(255,255,255,.7); }
.vstyle-metallic_silver .tt-big { color: #38414F; text-shadow: 0 1px 0 rgba(255,255,255,.7), 0 0 12px rgba(240,245,255,.7); }
.vstyle-metallic_silver .tt-name { color: rgba(56, 65, 79, .8); }
.vstyle-metallic_silver .tt-sub, .vstyle-metallic_silver .tt-bottom { color: rgba(56, 65, 79, .8); }

/* ---- 闪光族 ---- */
/* 闪光券：浅底 + 多枚白色小光斑（radial-gradient 平铺，纯 CSS 实现，无图片） */
.vstyle-sparkle .tt-half {
  background:
    radial-gradient(circle at 18% 22%, rgba(255,255,255,.95) 0 3px, rgba(255,255,255,0) 4px),
    radial-gradient(circle at 72% 34%, rgba(255,255,255,.9) 0 2.5px, rgba(255,255,255,0) 3.5px),
    radial-gradient(circle at 40% 68%, rgba(255,255,255,.85) 0 2px, rgba(255,255,255,0) 3px),
    radial-gradient(circle at 86% 76%, rgba(255,255,255,.9) 0 3px, rgba(255,255,255,0) 4px),
    radial-gradient(circle at 58% 12%, rgba(255,255,255,.8) 0 2px, rgba(255,255,255,0) 3px),
    linear-gradient(165deg, #FFF8E0 0%, #FFE9A8 50%, #F5D179 100%);
  box-shadow: 0 10px 30px rgba(150, 110, 20, .4), 0 0 18px rgba(255, 226, 130, .75);
}
.vstyle-sparkle .tt-badge { color: #6E4A00; }
.vstyle-sparkle .tt-badge svg { color: #D9A521; }
.vstyle-sparkle .tt-sub, .vstyle-sparkle .tt-bottom { color: rgba(110, 74, 0, .82); }
.vstyle-sparkle .tt-big { color: #6E4A00; }
.vstyle-sparkle .tt-name { color: rgba(110, 74, 0, .82); }

/* 彩虹券：七色斜向渐变（低频分段，避免花到看不清字）+ 白描边 */
.vstyle-rainbow .tt-half {
  background: linear-gradient(150deg,
    #FF9AA2 0%, #FFB07C 16%, #FFE07A 32%, #A8E6A1 48%,
    #8ED9F0 64%, #A9B4F5 80%, #D9A8F0 100%);
  box-shadow: 0 10px 30px rgba(90, 60, 120, .38), 0 0 16px rgba(255, 255, 255, .6);
}
.vstyle-rainbow .tt-badge { color: #3A2A5E; text-shadow: 0 1px 2px rgba(255,255,255,.85); }
.vstyle-rainbow .tt-big { color: #3A2A5E; text-shadow: 0 1px 2px rgba(255,255,255,.85); }
.vstyle-rainbow .tt-name { color: rgba(58, 42, 94, .82); }
.vstyle-rainbow .tt-sub, .vstyle-rainbow .tt-bottom { color: rgba(58, 42, 94, .82); }

/* 星空券：深夜底 + 星点（浅色字，是唯一深底券） */
.vstyle-starry .tt-half {
  background:
    radial-gradient(circle at 14% 26%, rgba(255,255,255,.95) 0 1.8px, rgba(255,255,255,0) 2.6px),
    radial-gradient(circle at 34% 62%, rgba(255,255,255,.75) 0 1.4px, rgba(255,255,255,0) 2.2px),
    radial-gradient(circle at 62% 20%, rgba(255,255,255,.9) 0 2px, rgba(255,255,255,0) 3px),
    radial-gradient(circle at 80% 54%, rgba(255,255,255,.8) 0 1.6px, rgba(255,255,255,0) 2.4px),
    radial-gradient(circle at 48% 84%, rgba(255,255,255,.7) 0 1.5px, rgba(255,255,255,0) 2.2px),
    linear-gradient(165deg, #2B2B6E 0%, #1C1C4E 55%, #101034 100%);
  box-shadow: 0 10px 32px rgba(10, 10, 40, .55), 0 0 20px rgba(120, 140, 255, .35);
}
.vstyle-starry .tt-badge { color: #FFF3C4; text-shadow: 0 0 10px rgba(255, 235, 150, .9); }
.vstyle-starry .tt-big { color: #FFF3C4; text-shadow: 0 0 12px rgba(255,235,150,.9); }
.vstyle-starry .tt-name { color: rgba(255, 243, 196, .85); }
.vstyle-starry .tt-sub, .vstyle-starry .tt-bottom { color: rgba(255, 243, 196, .85); }
/* 深底券的齿孔调亮，否则黑点看不见 */
.vstyle-starry .tt-perf {
  background: repeating-linear-gradient(90deg,
    rgba(255, 255, 255, 0) 0 3px,
    rgba(255, 255, 255, .55) 3px 5px);
}

/* ---- 券包多张并排（v2.2：原先只显示第一张，其余退化为一句「还有 N 张」） ---- */
.voucher-grid {
  /* 🔴 必须显式撑满：父容器 .voucher-strip 是 display:flex，
     grid 作为 flex 子项默认 flex-shrink:1 → 会被压到内容最小宽度，
     券面文字因此竖排堆叠（v2.2 首次实现踩的坑）。 */
  flex: 1 0 100%;
  width: 100%;
  min-width: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 4px 2px 16px;
}
@media (max-width: 420px) {
  /* 窄屏单列，保证券面文字不被压扁到不可读 */
  .voucher-grid { grid-template-columns: 1fr; }
}
/* 券包内的小尺寸券：整体缩到 58%，撕开时回到全尺寸（.tear-stage 内不受影响） */
.voucher-grid .tear-ticket {
  width: 100%;
  /* 🔴 v2.4：用 aspect-ratio 而不是固定 height —— 固定 148px 在宽 352px 时
     会把 1.92:1 的券压成 2.38:1（肉眼可见上下挤扁）。 */
  aspect-ratio: 1.92 / 1;
  height: auto;
  transform: none;
}
.voucher-grid .tt-badge { font-size: 26px; }
.voucher-grid .tt-badge svg { width: 26px; height: 26px; }
.voucher-grid .tt-sub { font-size: 18px; }
.voucher-grid .tt-bottom { font-size: 17px; bottom: 12px; }
.voucher-grid .tt-top { top: 14px; gap: 6px; }

/* 券卡片外壳：点击区 + 券名标签（券包内每张券独立可点） */
.voucher-cell {
  display: flex;
  flex-direction: column;
  gap: 8px;
  cursor: pointer;
  min-width: 0;          /* 🔴 允许收缩，防长券名撑破格子 */
  overflow: hidden;
  -webkit-tap-highlight-color: transparent;
}
.voucher-cell:active { transform: scale(.98); }
.voucher-cell .vc-name {
  text-align: center;
  font-size: 20px;
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ============================================================================
   v2.4 PNG 券面（Jeff 13:02 定案：券面统一用生成图，不再 CSS 纯色块）
   ----------------------------------------------------------------------------
   🔴 关键：.tt-half 各持完整券面 → background-size:200% 100%
      左半 background-position:left center；右半 right center
      合起来 = 完整一张图；撕票手势（左半左移/右半右移）零改动。
   🔴 字色由 item.tone 决定（生成时自动测中心亮度）：
      tone-light = 深底券 → 浅字；tone-dark = 浅底券 → 深字
   ============================================================================ */
/* 🔴 v2.4.5：.tt-flat 与两半都持【同一张完整图】（100% 100%），像素同源同缩放。
 *   撕开前看 .tt-flat（完整一张），撕开时切到两半（各自 clip 露一半）。 */
.art-ticket .tt-flat,
.art-ticket .tt-half {
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: center center;
  background-color: transparent;
  box-shadow: none;
}

/* tone-light：深色券面 → 浅色字（带深色描边保证可读） */
.art-ticket.tone-light .tt-big {
  color: #FFFAEB;
  text-shadow: 0 2px 6px rgba(0, 0, 0, .85), 0 0 16px rgba(0, 0, 0, .55);
}
.art-ticket.tone-light .tt-name {
  color: rgba(255, 250, 235, .96);
  text-shadow: 0 1px 4px rgba(0, 0, 0, .9);
}
.art-ticket.tone-light .tt-bottom {
  color: rgba(255, 250, 235, .85);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .85);
}

/* tone-dark：浅色券面 → 深色字（带白色柔光保证可读） */
.art-ticket.tone-dark .tt-big {
  color: #23301C;
  text-shadow: 0 2px 4px rgba(255, 255, 255, .95), 0 0 14px rgba(255, 255, 255, .8);
}
.art-ticket.tone-dark .tt-name {
  color: rgba(35, 48, 28, .92);
  text-shadow: 0 1px 3px rgba(255, 255, 255, .95);
}
.art-ticket.tone-dark .tt-bottom {
  color: rgba(35, 48, 28, .8);
  text-shadow: 0 1px 2px rgba(255, 255, 255, .9);
}

/* 券包内小图：直接用同一张 PNG（254~640px 宽，2x 屏够清晰） */
/* v2.4.4：券包内 PNG 券阴影统一由外层 .tear-ticket 承担（半张已改为整券尺寸+clip，不自带阴影） */
.voucher-grid .tear-ticket { box-shadow: 0 4px 14px rgba(0, 0, 0, .28); }
.voucher-grid .art-ticket .tt-half { box-shadow: none; }

/* v2.4 商店卡片缩略图（用券的 PNG 直接预览） */
.shop-card .sc-thumb {
  width: 100%;
  aspect-ratio: 1.92 / 1;
  /* 🔴 cover 会裁掉券的四边（券框被切掉一半），必须 contain 完整显示 */
  object-fit: contain;
  background: rgba(0, 0, 0, .06);
  border-radius: 10px;
  margin-bottom: 10px;
  display: block;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .22);
}

/* ============================================================================
   v2.4.1 商店缩略图叠加层（数字 + 券名）
   —— 只放空白券壳，孩子看不出这张值多少 → 必须叠上与真实券面一致的「大数字 + 券名」
   ============================================================================ */
.shop-card .sc-thumb-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 1.92 / 1;
  margin-bottom: 10px;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .22);
}
.shop-card .sc-thumb-wrap .sc-thumb {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  margin: 0;
  border-radius: 0;
  box-shadow: none;
}
.shop-card .sc-thumb-face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  pointer-events: none;
}
.shop-card .sc-thumb-num {
  font-size: 40px;
  font-weight: 900;
  line-height: 1;
  letter-spacing: -1.2px;
  font-variant-numeric: tabular-nums;
}
.shop-card .sc-thumb-name {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 1.5px;
}
/* 字色与真实券面同一套规则 */
.shop-card .sc-thumb-wrap.tone-light .sc-thumb-num {
  color: #FFFAEB; text-shadow: 0 2px 6px rgba(0,0,0,.85), 0 0 14px rgba(0,0,0,.5);
}
.shop-card .sc-thumb-wrap.tone-light .sc-thumb-name {
  color: rgba(255,250,235,.96); text-shadow: 0 1px 4px rgba(0,0,0,.9);
}
.shop-card .sc-thumb-wrap.tone-dark .sc-thumb-num {
  color: #23301C; text-shadow: 0 2px 4px rgba(255,255,255,.95), 0 0 12px rgba(255,255,255,.8);
}
.shop-card .sc-thumb-wrap.tone-dark .sc-thumb-name {
  color: rgba(35,48,28,.92); text-shadow: 0 1px 3px rgba(255,255,255,.95);
}

/* ============================================================
   v3.2 首页底部水印（© Jeff Xu）
   🔴 克制：极淡、极小、不拦截点击，只在页面最底部
   ============================================================ */
.kid-watermark {
  margin: 28px 0 18px;
  text-align: center;
  font-size: 12px;
  letter-spacing: 0.4px;
  color: rgba(255, 255, 255, 0.42);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
  pointer-events: none;
  user-select: none;
}

/* 浅底主题兜底（当前无，留口子） */
@media (prefers-color-scheme: light) {
  .kid-watermark { color: rgba(74, 54, 40, 0.38); text-shadow: none; }
}
