/* Screen-specific styles: login, home, lottery (选号 / 我的彩票), settings, sheets. */

/* Only the root is locked: locking body too would turn it into a scroll container and unstick the top bar. */
html.is-locked { overflow: hidden; }
.noscript { padding: 48px 24px; text-align: center; color: var(--text-2); }
.stepper-btn[data-blocked="true"] { opacity: 0.32; box-shadow: none; }

/* ======================= Login ======================= */

.login {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background:
    radial-gradient(90% 50% at 50% 38%, rgba(255, 194, 51, 0.22) 0%, rgba(255, 194, 51, 0) 70%),
    linear-gradient(180deg, var(--hero-2) 0%, var(--hero-1) 100%);
}
.login-hero {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: calc(var(--safe-top) + 16px) var(--gutter) 56px;
  color: var(--hero-text);
  text-align: center;
}
.login-art { width: min(340px, 84vw, 40dvh); transition: width var(--dur-3) var(--ease-out); }
.login.is-password .login-hero { padding-bottom: 48px; }
.login.is-password .login-art { width: min(260px, 66vw, 27dvh); }
.login-art .hero-art { width: 100%; height: auto; overflow: visible; }
.login-title { margin-top: 6px; font-size: 28px; font-weight: 800; letter-spacing: 0.02em; }
.login-sub { margin-top: 4px; font-size: 15px; color: var(--hero-text-2); }
.login-panel {
  position: relative;
  margin-top: -30px;
  padding: 28px max(var(--gutter), var(--safe-right)) calc(var(--safe-bottom) + 16px) max(var(--gutter), var(--safe-left));
  background: var(--bg);
  border-radius: 32px 32px 0 0;
  box-shadow: 0 -14px 36px rgba(20, 6, 30, 0.20);
}
.login-panel > * { max-width: 460px; margin-left: auto; margin-right: auto; }
.login-choose { display: grid; gap: 8px; }
.login-form { display: grid; gap: 16px; }
.login-form .field + .field { margin-top: 0; }
.login-form .form-error { margin-top: -4px; }
.login-form-title { font-size: 15px; font-weight: 600; color: var(--text-2); text-align: center; }
/* Spec §44.5: why the password side opened (first login at this address, or Face ID did not get in). */
.login-hint { padding: 10px 14px; border-radius: var(--r-s); background: var(--accent-soft); color: var(--text-2); font-size: 14px; line-height: 1.5; text-align: center; }
.who { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; gap: 12px; }
.who-option {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 16px 8px 14px;
  border: 2px solid transparent;
  border-radius: 22px;
  background: var(--surface);
  box-shadow: var(--shadow-1);
  transition: border-color var(--dur-2), box-shadow var(--dur-2), transform var(--dur-1) var(--ease-out);
}
.who-option:active { transform: scale(0.97); }
.who-option[aria-checked="true"] { border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft), var(--shadow-1); }
.who-avatar { width: 64px; height: 64px; }
.who-avatar svg { width: 100%; height: 100%; }
.who-name { font-size: 16px; font-weight: 700; }
.who-check {
  position: absolute;
  top: 10px; right: 10px;
  width: 24px; height: 24px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--accent);
  color: #fff;
  transform: scale(0);
  transition: transform 300ms var(--ease-spring);
}
.who-check svg { width: 15px; height: 15px; stroke-width: 2.6; }
.who-option[aria-checked="true"] .who-check { transform: scale(1); }
.login-actions { display: grid; gap: 6px; margin-top: 2px; }
.login-foot { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 18px; font-size: 12px; color: var(--text-3); }
.login-foot svg { width: 15px; height: 15px; }

/* Floating decorations inside the hero art */
.hero-art .float-a, .hero-art .float-b, .hero-art .float-c, .hero-art .twinkle path {
  transform-box: fill-box;
  transform-origin: center;
}
.hero-art .float-a { animation: float 3.8s ease-in-out infinite alternate; }
.hero-art .float-b { animation: float 3.2s ease-in-out -1.4s infinite alternate; }
.hero-art .float-c { animation: float 4.4s ease-in-out -2s infinite alternate; }
.hero-art .twinkle path { animation: twinkle 2.6s ease-in-out infinite; }
.hero-art .twinkle path:nth-child(2) { animation-delay: -0.9s; }
.hero-art .twinkle path:nth-child(3) { animation-delay: -1.7s; }
.hero-art .twinkle path:nth-child(4) { animation-delay: -2.2s; }
@keyframes float { from { transform: translateY(-5px); } to { transform: translateY(5px); } }
@keyframes twinkle { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.35; transform: scale(0.6); } }

/* ======================= Home ======================= */

.page--home .hero { min-height: 172px; padding-bottom: 52px; }
.page--home .hero-title { font-size: 30px; max-width: calc(100% - 140px); }
.page--home .hero-sub { max-width: calc(100% - 140px); }
.hero > .home-duo {
  position: absolute;
  z-index: 0;
  right: max(4px, calc(var(--gutter) - 12px));
  bottom: 30px;
  width: 140px;
  pointer-events: none;
}
.home-duo svg { width: 100%; height: auto; overflow: visible; }

.avatar-btn {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  transition: transform var(--dur-1) var(--ease-out);
}
.avatar-btn:active { transform: scale(0.92); }
.avatar-img {
  width: 38px; height: 38px;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.9), 0 4px 12px rgba(10, 0, 20, 0.25);
}
.avatar-img svg { width: 100%; height: 100%; }

.banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 6px 14px 14px;
  margin-bottom: 14px;
}
.banner-icon {
  display: grid;
  place-items: center;
  width: 46px; height: 46px;
  border-radius: 15px;
  flex-shrink: 0;
  color: #fff;
  background: linear-gradient(135deg, #5CC78A, #2E9A5E);
  box-shadow: 0 6px 14px rgba(46, 154, 94, 0.30);
}
.banner-icon svg { width: 26px; height: 26px; }
.banner-text { flex: 1; min-width: 0; display: grid; gap: 1px; }
.banner-text strong { font-size: 16px; }
.banner-text span { font-size: 13px; color: var(--text-2); }
.banner .btn-sm { padding: 0 16px; flex-shrink: 0; }
.banner-close { color: var(--text-3); flex-shrink: 0; }
.banner-close svg { width: 18px; height: 18px; }
.banner.is-leaving { animation: banner-out 260ms var(--ease-out) forwards; }
@keyframes banner-out { to { opacity: 0; transform: translateY(-8px) scale(0.97); } }

.home-foot { margin-top: 36px; text-align: center; font-size: 12px; color: var(--text-3); letter-spacing: 0.04em; }

/* ======================= 选号 ======================= */

.hero-seg { margin-top: 16px; }

.draw-card { padding: 16px 18px; }
.draw-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 26px; margin-bottom: 12px; }
.draw-label { display: inline-flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 700; flex-shrink: 0; }
.draw-label svg { width: 18px; height: 18px; color: var(--pineapple-deep); }
.draw-meta { min-width: 0; font-size: 13px; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.draw-card .balls { gap: 5px; }
.draw-skeleton { display: flex; gap: 5px; }
.draw-skeleton .skeleton { width: 30px; height: 30px; border-radius: 50%; }
.draw-empty { display: flex; align-items: center; gap: 6px; min-height: 30px; font-size: 14px; color: var(--text-3); }
.draw-empty svg { width: 17px; height: 17px; }
.draw-card .divider { margin: 14px 0 12px; }
.draw-next { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.draw-next-main { display: grid; gap: 2px; min-width: 0; }
.draw-next-title { display: inline-flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 600; }
.draw-next-title svg { width: 17px; height: 17px; color: var(--accent); }
.draw-next-sub { padding-left: 23px; font-size: 12.5px; color: var(--text-3); }
.countdown {
  display: grid;
  justify-items: end;
  flex-shrink: 0;
  padding: 6px 12px;
  border-radius: 14px;
  background: var(--pineapple-soft);
  color: #7A4A00;
}
.countdown-label { font-size: 11px; font-weight: 600; opacity: 0.8; }
.countdown-value { font-size: 17px; font-weight: 800; line-height: 1.2; }
.countdown.is-urgent { background: var(--coral-soft); color: #C83A2B; animation: pulse 1.8s ease-in-out infinite; }
@keyframes pulse { 50% { transform: scale(1.04); } }
@media (prefers-color-scheme: dark) {
  .countdown { color: #FFD06A; }
  .countdown.is-urgent { color: #FF9A8C; }
}

/* 今日幸运 */
.swatches { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px 4px; }
.swatch {
  display: grid;
  justify-items: center;
  gap: 5px;
  min-height: 44px;
  padding: 2px 0;
  border: 0;
  background: none;
}
.swatch-dot {
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 28%, rgba(255, 255, 255, 0.55) 0%, rgba(255, 255, 255, 0) 46%),
    var(--swatch);
  box-shadow: inset 0 -2px 5px rgba(0, 0, 0, 0.16), 0 2px 6px rgba(42, 30, 53, 0.14);
  transition: transform 280ms var(--ease-spring), box-shadow var(--dur-2);
}
.swatch-dot svg { width: 20px; height: 20px; color: #fff; stroke-width: 2.6; opacity: 0; transform: scale(0.4); transition: opacity var(--dur-1), transform 280ms var(--ease-spring); }
.swatch:active .swatch-dot { transform: scale(0.9); }
.swatch[aria-pressed="true"] .swatch-dot {
  transform: scale(1.04);
  box-shadow: 0 0 0 3px var(--surface), 0 0 0 5.5px var(--swatch), 0 6px 14px rgba(42, 30, 53, 0.18);
}
.swatch[aria-pressed="true"] .swatch-dot svg { opacity: 1; transform: none; }
.swatch--white .swatch-dot { box-shadow: inset 0 0 0 1.5px var(--line-strong), 0 2px 6px rgba(42, 30, 53, 0.10); }
.swatch--white[aria-pressed="true"] .swatch-dot { box-shadow: inset 0 0 0 1.5px var(--line-strong), 0 0 0 3px var(--surface), 0 0 0 5.5px #CFC3B4; }
.swatch--white .swatch-dot svg, .swatch--yellow .swatch-dot svg { color: var(--ink); }
.swatch-name { font-size: 12px; font-weight: 500; color: var(--text-2); }
.swatch[aria-pressed="true"] .swatch-name { color: var(--text); font-weight: 700; }
.swatch.nope { animation: nope 400ms ease-in-out; }
@keyframes nope { 20%, 60% { transform: translateX(-4px); } 40%, 80% { transform: translateX(4px); } }
@media (prefers-color-scheme: dark) {
  .swatch--black .swatch-dot { box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.22); }
  .swatch--black[aria-pressed="true"] .swatch-dot { box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.22), 0 0 0 3px var(--surface), 0 0 0 5.5px rgba(255, 255, 255, 0.5); }
}

.tails {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 48px;
  margin-top: 14px;
  padding: 8px 12px 8px 14px;
  border-radius: 16px;
  background: var(--pineapple-soft);
}
.tails-label { font-size: 14px; font-weight: 600; color: #7A4A00; }
.tails-list { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; }
.tail-ball {
  display: grid;
  place-items: center;
  width: 30px; height: 30px;
  border-radius: 50%;
  font-size: 15px;
  font-weight: 800;
  color: #5A3500;
  background:
    radial-gradient(ellipse 42% 30% at 40% 20%, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0) 100%),
    radial-gradient(circle at 50% 35%, #FFE48A 0%, #FFC233 50%, #E39400 100%);
  box-shadow: inset 0 -2px 4px rgba(150, 80, 0, 0.2), 0 3px 8px -2px rgba(230, 150, 0, 0.6);
  animation: ball-pop 480ms var(--ease-spring) both;
}
.tails--empty { justify-content: flex-start; font-size: 13px; color: var(--text-2); background: var(--surface-3); }
@media (prefers-color-scheme: dark) { .tails-label { color: #FFD06A; } }

.lucky-pick {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 60px;
  margin-top: 12px;
  padding: 12px 10px 12px 12px;
  border: 0;
  border-radius: 16px;
  background: var(--surface-3);
  color: var(--text);
  text-align: left;
  transition: transform var(--dur-1) var(--ease-out);
}
.lucky-pick:active { transform: scale(0.98); }
.lucky-pick-main { flex: 1; min-width: 0; display: grid; gap: 6px; }
.lucky-pick-title { font-size: 15px; font-weight: 600; }
.lucky-numbers { display: grid; gap: 6px; }
.lucky-line { display: flex; align-items: flex-start; gap: 8px; }
.lucky-tag { flex-shrink: 0; margin-top: 3px; padding: 3px 6px; border-radius: 6px; font-size: 11px; font-weight: 700; line-height: 1.2; }
.lucky-tag--in { background: var(--pineapple-soft); color: #8A5600; }
.lucky-tag--out { background: var(--surface); color: var(--text-3); }
@media (prefers-color-scheme: dark) { .lucky-tag--in { color: #FFD06A; } }
.lucky-empty { font-size: 13px; color: var(--text-3); }
.balls--tight { gap: 4px; }
.balls--struck .ball::after {
  content: "";
  position: absolute;
  left: 4px; right: 4px;
  top: 50%;
  height: 1.5px;
  border-radius: 1px;
  background: currentColor;
  transform: rotate(-38deg);
}
.ball--xs .ball-star { top: -3px; right: -3px; width: 12px; height: 12px; }
.ball--xs .ball-star svg { width: 8px; height: 8px; }
.ball--sm .ball-star { width: 13px; height: 13px; }
.ball--sm .ball-star svg { width: 9px; height: 9px; }

/* 玩法 */
.play-card > .seg { margin-bottom: 4px; }
.play-controls { display: grid; }
.play-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 62px; padding: 6px 0; }
.play-row + .play-row { box-shadow: inset 0 1px 0 var(--line); } /* a border would make rows 2..n 1px taller */
.play-row-label { display: flex; align-items: center; gap: 10px; min-width: 0; }
.zone-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; background: var(--ball-red); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ball-red) 18%, transparent); }
.zone-dot--blue { background: var(--ball-blue); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ball-blue) 18%, transparent); }
.play-row-text { display: grid; min-width: 0; }
.play-row-title { font-size: 16px; font-weight: 600; }
.play-row-sub { font-size: 12.5px; color: var(--text-3); }
.quick-picks { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; padding: 0 0 10px; }
.play-note { display: flex; align-items: center; gap: 6px; padding: 8px 0 2px; font-size: 12.5px; color: var(--text-3); }
.play-note svg { width: 16px; height: 16px; }
.play-controls .divider { margin: 8px 0 2px; }
.play-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 60px;
  margin-top: 12px;
  padding: 10px 16px;
  border-radius: 18px;
  background: linear-gradient(135deg, var(--accent-soft) 0%, var(--pineapple-soft) 100%);
}
.play-summary-label { font-size: 14px; font-weight: 600; color: var(--text-2); }
.play-summary-value { font-size: 16px; color: var(--text-2); white-space: nowrap; }
.play-summary-value strong { font-size: 24px; font-weight: 800; color: var(--text); }
.play-summary.is-error { justify-content: flex-start; background: var(--danger-soft); color: var(--danger); font-size: 14px; font-weight: 600; }
.play-summary.is-error svg { width: 20px; height: 20px; }

/* CTA */
.cta-wrap { margin-top: 20px; }
.btn-cta { overflow: hidden; overflow: clip; isolation: isolate; }
.btn-cta svg { width: 24px; height: 24px; }
.btn-cta::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(105deg, rgba(255, 255, 255, 0) 35%, rgba(255, 255, 255, 0.5) 50%, rgba(255, 255, 255, 0) 65%);
  transform: translateX(-120%);
  animation: sheen 4s ease-in-out 1.5s infinite;
}
@keyframes sheen { 0%, 62% { transform: translateX(-120%); } 88%, 100% { transform: translateX(120%); } }
.btn-cta:disabled { opacity: 0.55; }
.btn-cta.is-shaking { animation: shake 480ms ease-in-out 2; opacity: 1; }
.btn-cta.is-shaking svg { animation: spin 700ms linear infinite; }
@keyframes shake {
  0%, 100% { transform: rotate(0deg); }
  20% { transform: rotate(-2.5deg) scale(1.02); }
  40% { transform: rotate(2.5deg) scale(1.02); }
  60% { transform: rotate(-1.5deg); }
  80% { transform: rotate(1.5deg); }
}

/* Lottery machine */
.machine { position: relative; width: 160px; height: 170px; margin: 12px auto 4px; animation: machine-in 320ms var(--ease-spring) both; }
.machine-svg { width: 160px; height: 170px; overflow: visible; }
.machine-balls { position: absolute; left: 14px; top: 8px; width: 132px; height: 132px; border-radius: 50%; overflow: hidden; overflow: clip; }
.mini-ball {
  --c: var(--ball-red); --cl: var(--ball-red-light); --cd: var(--ball-red-dark);
  position: absolute;
  left: 50%; top: 50%;
  width: 18px; height: 18px;
  margin: -9px 0 0 -9px;
  border-radius: 50%;
  background:
    radial-gradient(ellipse 45% 32% at 40% 22%, rgba(255, 255, 255, 0.85) 0%, rgba(255, 255, 255, 0) 100%),
    radial-gradient(circle at 50% 35%, var(--cl) 0%, var(--c) 50%, var(--cd) 100%);
  box-shadow: inset 0 -2px 3px rgba(0, 0, 0, 0.18);
}
.mini-ball--blue { --c: var(--ball-blue); --cl: var(--ball-blue-light); --cd: var(--ball-blue-dark); }
.mini-ball--gold { --c: #FFC233; --cl: #FFE48A; --cd: #D98A00; }
.machine-winner { left: 80px; top: 128px; width: 22px; height: 22px; margin: 0 0 0 -11px; opacity: 0; }
.machine.is-dropping .machine-winner { animation: winner-drop 380ms var(--ease-out) forwards; }
.machine.is-done { animation: machine-out 220ms var(--ease-out) forwards; }
@keyframes machine-in { from { opacity: 0; transform: scale(0.85); } }
@keyframes machine-out { to { opacity: 0; transform: scale(0.9); } }
@keyframes winner-drop { from { opacity: 1; transform: translateY(-24px) scale(0.6); } to { opacity: 1; transform: translateY(18px) scale(1.25); } }

/* Results */
.results { margin-top: 20px; scroll-margin-top: calc(var(--safe-top) + 72px); }
.results:empty { margin-top: 0; }
.results-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 10px 12px; margin: 6px 4px 12px; }
.results-title { display: grid; gap: 6px; }
.results-title h2 { font-size: 21px; font-weight: 800; }
.results-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.results-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.gen-list { display: grid; gap: 12px; }
.gen-card {
  position: relative;
  overflow: hidden;
  overflow: clip;
  padding: 14px 16px 8px 18px;
  border-radius: var(--r-l);
  background: var(--surface);
  box-shadow: var(--shadow-2);
}
.gen-card::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 5px;
  background: linear-gradient(180deg, var(--pineapple) 0%, var(--coral) 100%);
}
.gen-card.enter { animation: card-in 520ms var(--ease-spring) both; animation-delay: var(--card-delay, 0ms); }
.gen-card .ball.pop { animation-delay: calc(var(--card-delay, 0ms) + 120ms + var(--i, 0) * 50ms); }
@keyframes card-in { from { opacity: 0; transform: translateY(18px) scale(0.97); } }
.gen-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.gen-index {
  display: inline-grid;
  place-items: center;
  min-width: 26px;
  height: 26px;
  padding: 0 7px;
  border-radius: 9px;
  background: var(--surface-3);
  color: var(--text-2);
  font-size: 14px;
  font-weight: 800;
}
.gen-index--icon { background: var(--pineapple-soft); color: var(--pineapple-deep); }
.gen-index--icon svg { width: 16px; height: 16px; }
.gen-meta { font-size: 13px; font-weight: 600; color: var(--text-3); }
.gen-balls { padding: 2px 0 12px; }
.gen-balls .ball { --size: clamp(33px, 9.3vw, 42px); }
.gen-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; padding-top: 8px; border-top: 1px solid var(--line); }
.gen-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 0;
  min-height: 44px;
  padding: 0 2px;
  border: 0;
  border-radius: 14px;
  background: none;
  color: var(--text-2);
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
  transition: background-color var(--dur-2), transform var(--dur-1);
}
.gen-action svg { width: 18px; height: 18px; }
.gen-action:active { background: var(--surface-3); transform: scale(0.96); }

/* ======================= Sheets (lottery) ======================= */

.sheet-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.sheet-lead { font-size: 15px; color: var(--text-2); }
.sheet-section-title { display: flex; align-items: center; gap: 6px; margin: 20px 2px 10px; font-size: 15px; font-weight: 700; }
.sheet-section-title svg { width: 18px; height: 18px; color: var(--accent); }
.sheet-note { display: flex; align-items: flex-start; gap: 6px; margin-top: 12px; font-size: 12.5px; line-height: 1.5; color: var(--text-3); }
.sheet-note svg { width: 16px; height: 16px; margin-top: 1px; }

.legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  padding: 10px 12px;
  border-radius: 16px;
  background: var(--surface-3);
}
.legend-item { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; }
.legend-swatch { position: relative; display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; }
.legend-swatch svg { width: 12px; height: 12px; }
.legend-swatch[data-state="include"] {
  color: #fff;
  background: radial-gradient(circle at 50% 35%, var(--ball-red-light) 0%, var(--ball-red) 50%, var(--ball-red-dark) 100%);
}
.legend-swatch[data-state="exclude"] { box-shadow: inset 0 0 0 1.5px var(--text-3); }
.legend-swatch[data-state="exclude"]::after {
  content: "";
  position: absolute;
  left: 4px; right: 4px;
  top: 50%;
  height: 1.5px;
  background: var(--text-3);
  transform: rotate(-40deg);
}
.legend-tip { width: 100%; font-size: 12px; color: var(--text-3); }

.zone-section { margin-top: 18px; }
.zone-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.zone-head h3 { flex: 1; font-size: 16px; font-weight: 700; }
.zone-counter { font-size: 13px; font-weight: 600; color: var(--text-3); }
.zone-counter.is-full { color: var(--positive); }
.zone-hint { margin: -4px 0 10px; font-size: 12.5px; color: var(--text-3); }

.num-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px 5px; }
/* A digit game's position (排列5, spec §32.7): 0–9 as two rows of five, cells as in the other pads. */
.num-grid--digits { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.zone-section--digits { margin-top: 14px; }
.num-cell {
  --c: var(--ball-red); --cl: var(--ball-red-light); --cd: var(--ball-red-dark);
  position: relative;
  justify-self: center;
  display: grid;
  place-items: center;
  width: 100%;
  max-width: 50px;
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--text);
  font-family: var(--font-rounded);
  font-size: 17px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  transition: transform var(--dur-1) var(--ease-out), background-color var(--dur-2), color var(--dur-2);
}
/* Tap target reaches into half of each grid gap: a 39.6px cell at 375px width (7 columns) still gets a
   44.6 × 45.6px target, and neighbouring targets meet without overlapping. (::after is the state mark.) */
.num-cell::before { content: ""; position: absolute; inset: -3px -2.5px; }
.num-grid--blue .num-cell { --c: var(--ball-blue); --cl: var(--ball-blue-light); --cd: var(--ball-blue-dark); }
.num-cell:active { transform: scale(0.88); }
.num-cell[data-state="include"], .num-cell[data-state="selected"] {
  color: #fff;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
  background:
    radial-gradient(ellipse 42% 30% at 40% 20%, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0) 100%),
    radial-gradient(circle at 50% 35%, var(--cl) 0%, var(--c) 48%, var(--cd) 100%);
  box-shadow: inset 0 -3px 6px rgba(0, 0, 0, 0.16), 0 5px 10px -4px var(--c);
  animation: cell-pop 320ms var(--ease-spring);
}
.num-cell[data-state="exclude"] { background: transparent; color: var(--text-3); box-shadow: inset 0 0 0 1.5px var(--line-strong); }
.num-cell[data-state="exclude"]::after {
  content: "";
  position: absolute;
  left: 24%; right: 24%;
  top: 50%;
  height: 2px;
  border-radius: 1px;
  background: var(--text-3);
  transform: rotate(-40deg);
}
.num-cell-star {
  position: absolute;
  top: -2px; right: -2px;
  display: none;
  place-items: center;
  width: 17px; height: 17px;
  border-radius: 50%;
  background: var(--pineapple);
  color: #5A3500;
  box-shadow: 0 0 0 2px var(--bg-elevated);
}
.num-cell-star svg { width: 11px; height: 11px; }
.num-cell[data-state="include"] .num-cell-star { display: grid; }
/* A 组选单式 digit chosen twice (a pair, 排列3 / 福彩3D): the ball with a ×2 mark; three times (a recognized 豹子
   row, which 组选 cannot buy): ×3. */
.num-cell[data-state="pair"],
.num-cell[data-state="triple"] {
  color: #fff;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
  background:
    radial-gradient(ellipse 42% 30% at 40% 20%, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0) 100%),
    radial-gradient(circle at 50% 35%, var(--cl) 0%, var(--c) 48%, var(--cd) 100%);
  box-shadow: inset 0 -3px 6px rgba(0, 0, 0, 0.16), 0 5px 10px -4px var(--c);
  animation: cell-pop 320ms var(--ease-spring);
}
.num-cell[data-state="pair"]::after,
.num-cell[data-state="triple"]::after {
  content: "×2";
  position: absolute;
  top: -4px; right: -6px;
  display: grid;
  place-items: center;
  min-width: 22px;
  height: 18px;
  padding: 0 4px;
  border-radius: var(--r-pill);
  background: var(--pineapple);
  color: #5A3500;
  font-size: 11px;
  font-weight: 800;
  text-shadow: none;
  box-shadow: 0 0 0 2px var(--bg-elevated);
}
.num-cell[data-state="triple"]::after { content: "×3"; }
@keyframes cell-pop { 40% { transform: scale(1.14); } }

.draw-options { display: grid; gap: 10px; }
.draw-option {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 66px;
  padding: 10px 14px;
  border: 2px solid var(--line);
  border-radius: 18px;
  background: var(--surface);
  color: var(--text);
  text-align: left;
  transition: border-color var(--dur-2), background-color var(--dur-2), transform var(--dur-1);
}
.draw-option:active { transform: scale(0.98); }
.draw-option[aria-checked="true"] { border-color: var(--accent); background: var(--accent-soft); }
.draw-option-radio {
  display: grid;
  place-items: center;
  width: 24px; height: 24px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 2px solid var(--line-strong);
  color: transparent;
  transition: background-color var(--dur-2), border-color var(--dur-2), color var(--dur-2);
}
.draw-option-radio svg { width: 14px; height: 14px; stroke-width: 3; }
.draw-option[aria-checked="true"] .draw-option-radio { background: var(--accent); border-color: var(--accent); color: #fff; }
.draw-option-main { flex: 1; min-width: 0; display: grid; gap: 2px; }
.draw-option-date { font-size: 16px; font-weight: 700; }
.draw-option-sub { font-size: 12.5px; color: var(--text-3); }
/* The tag row is reserved even when a row has no 当前 / 最近一期 chip, so every option is the same height. */
.draw-option-side { display: grid; grid-template-rows: auto 26px; justify-items: end; align-items: center; gap: 4px; flex-shrink: 0; }
.draw-option-issue { display: inline-flex; align-items: center; gap: 4px; font-size: 13px; font-weight: 600; color: var(--text-2); }

.manual-draw > .seg, .manual-draw > .game-picker { margin-bottom: 14px; }

/* ---------- Game selector (spec §32.7): 常用 segments + 「更多」 → a 4 × 2 grid ---------- */
.seg--games .seg-item { padding: 0 4px; gap: 4px; }
.seg--games .seg-item svg { width: 16px; height: 16px; }
.game-grid-sheet { display: grid; gap: 16px; padding-bottom: 6px; }
.game-grid-label { margin: 0 2px 8px; font-size: 13px; font-weight: 700; color: var(--text-3); }
.game-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: 1fr; gap: var(--gap); }
.game-cell {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 4px;
  min-width: 0;
  height: 100%;
  min-height: 68px;
  padding: 10px 4px;
  border: 1.5px solid transparent;
  border-radius: var(--r-s);
  background: var(--surface-3);
  color: var(--text);
  transition: transform var(--dur-1) var(--ease-out), background-color var(--dur-2), border-color var(--dur-2);
}
.game-cell:active:not(:disabled) { transform: scale(0.97); }
.game-cell-name, .game-cell-sub { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.game-cell-name { font-size: 15px; font-weight: 700; }
.game-cell-sub { font-size: 11.5px; font-weight: 600; color: var(--text-3); }
.game-cell.is-current { border-color: var(--accent); background: var(--accent-soft); }
.game-cell.is-current .game-cell-sub { color: var(--accent); }
.game-cell:disabled { background: transparent; box-shadow: inset 0 0 0 1.5px var(--line-strong); color: var(--text-3); cursor: default; }
.manual-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.manual-fields .field + .field { margin-top: 0; }

/* ======================= 我的彩票 ======================= */

.page--records .hero { padding-bottom: 48px; }
.stat-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; gap: 10px; margin-top: 16px; }
.stat-tile {
  display: grid;
  gap: 2px;
  align-content: start;
  min-width: 0;
  padding: 12px 14px;
  border-radius: 20px;
  container-type: inline-size;
  background: var(--hero-glass);
  border: 1px solid var(--hero-line);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
.stat-head { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--hero-text-2); }
.stat-head svg { width: 16px; height: 16px; }
/* Both tiles shrink together so ¥6,208,577 fits a 375px tile instead of being cut to ¥6,208,… */
.stat-value { font-size: 26px; font-size: min(26px, 16cqi); font-weight: 800; line-height: 1.2; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat-tile--win .stat-value { color: var(--pineapple); }
.stat-sub { min-height: 1.2em; font-size: 12px; color: var(--hero-text-2); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat-tiles { color: inherit; text-decoration: none; transition: transform var(--dur-1) var(--ease-out); }
.stat-tiles:active { transform: scale(0.98); }
.stat-head .stat-more { width: 15px; height: 15px; margin-left: auto; opacity: 0.7; }
.record-actions { display: flex; gap: 8px; margin-top: 12px; }
.scan-btn { flex: 1; min-width: 0; min-height: 56px; border-radius: 18px; font-size: 17px; }
.hero-action {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 2px;
  width: 58px;
  min-height: 56px;
  flex-shrink: 0;
  border: 1px solid var(--hero-line);
  border-radius: 18px;
  background: var(--hero-glass);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  transition: transform var(--dur-1) var(--ease-out), background-color var(--dur-2);
}
.hero-action svg { width: 22px; height: 22px; }
.hero-action:active { transform: scale(0.94); background: var(--hero-glass-strong); }
.sync-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: -4px 4px 10px; }
.sync-info { display: inline-flex; align-items: center; gap: 5px; min-width: 0; font-size: 12.5px; color: var(--text-3); }
.sync-info svg { width: 15px; height: 15px; }
.sync-info span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.refresh-btn { flex-shrink: 0; }
.refresh-btn:disabled { opacity: 0.7; }

.records-tabs { position: sticky; top: calc(var(--safe-top) + 64px); z-index: 20; margin-bottom: 14px; }
/* Once the hero has scrolled under the bar, a page-coloured band fills the 8px gap between the bar and the stuck
   tabs (down to their middle), so cards scrolling underneath do not show through. Before that the tabs float
   over the hero's bottom edge, which the band must not cover. */
.records-tabs::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: -8px; bottom: 50%;
  left: calc(-1 * var(--gutter)); right: calc(-1 * var(--gutter));
  background: var(--bg);
  pointer-events: none;
  visibility: hidden;
}
.page.is-past-hero .records-tabs::before { visibility: visible; }
.seg--card { padding: 4px; border-radius: 18px; background: var(--surface); box-shadow: var(--shadow-2); }
.seg--card .seg-thumb {
  top: 4px; bottom: 4px; left: 4px;
  width: calc((100% - 8px) / var(--n));
  border-radius: 14px;
  background: linear-gradient(135deg, #8A43B0 0%, var(--mangosteen) 100%);
  box-shadow: 0 4px 12px rgba(107, 47, 138, 0.30);
}
.seg--card .seg-item[aria-selected="true"] { color: #fff; }

.ticket-list { display: grid; gap: 12px; }
.ticket {
  position: relative;
  padding: 14px 16px 10px;
  border: 2px solid transparent;
  border-radius: var(--r-l);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  transition: opacity 280ms var(--ease-out), transform 280ms var(--ease-out);
}
.ticket.is-won {
  background:
    linear-gradient(var(--surface), var(--surface)) padding-box,
    linear-gradient(135deg, var(--pineapple) 0%, var(--coral) 100%) border-box;
}
.ticket.is-new-win { animation: win-glow 1.6s ease-in-out 3; }
@keyframes win-glow { 50% { box-shadow: 0 0 0 6px rgba(255, 194, 51, 0.35), var(--shadow-2); } }
.ticket.is-removing { opacity: 0; transform: scale(0.95); }
/* Opened from a win notification (spec §21): the ticket is ringed for a moment. */
.ticket.is-focus { box-shadow: 0 0 0 3px var(--accent), var(--shadow-2); animation: ticket-focus 1s var(--ease-out) 3; }
@keyframes ticket-focus { 50% { box-shadow: 0 0 0 7px var(--accent-soft), var(--shadow-2); } }
.ticket-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ticket-chips { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.ticket-cost { flex-shrink: 0; font-size: 17px; font-weight: 800; }
/* 赠票 (spec §35): 「赠票 · 价值 ¥20」 in the cost's place. */
.ticket-cost--gift { font-size: 14px; font-weight: 700; color: var(--accent); }
.ticket-sub { display: flex; align-items: center; gap: 5px; margin: 8px 0 12px; font-size: 13px; color: var(--text-3); }
.ticket-sub svg { width: 15px; height: 15px; flex-shrink: 0; }
.ticket-bets { display: grid; gap: 10px; }
.ticket-bet { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: start; gap: 8px; }
.ticket-bet.no-index { grid-template-columns: minmax(0, 1fr) auto; }
.ticket-bet-index {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: 20px; height: 20px;
  margin-top: 5px;
  border-radius: 6px;
  background: var(--surface-3);
  font-size: 12px;
  font-weight: 700;
  color: var(--text-3);
}
.ticket-drawn { display: flex; align-items: center; gap: 8px; margin-top: 12px; padding: 8px 10px; border-radius: 14px; background: var(--surface-3); }
.ticket-drawn-label { flex-shrink: 0; font-size: 12px; font-weight: 700; color: var(--text-3); }
.ticket-drawn .balls { gap: 4px; }
.ticket-tiers { margin-top: 8px; font-size: 12.5px; color: var(--text-2); font-variant-numeric: tabular-nums; text-wrap: pretty; }
.ticket-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--line); }
/* 多期票 (spec §30): 「已开 3/15 期」, what it won so far and a bar; a tap opens 每期结果. */
.ticket-progress {
  display: grid;
  gap: 8px;
  width: 100%;
  min-height: 56px;
  margin-top: 12px;
  padding: 10px 12px;
  border: 0;
  border-radius: 14px;
  background: var(--surface-3);
  color: var(--text);
  font: inherit;
  text-align: left;
  transition: transform var(--dur-1) var(--ease-out);
}
.ticket-progress:active { transform: scale(0.98); }
.ticket-progress-head { display: grid; grid-template-columns: auto minmax(0, 1fr) 18px; align-items: center; gap: 8px; }
.ticket-progress-head svg { width: 18px; height: 18px; color: var(--text-3); }
.ticket-progress-label { font-size: 14px; font-weight: 700; }
.ticket-progress-sum { justify-self: end; overflow: hidden; font-size: 13px; color: var(--text-2); text-overflow: ellipsis; white-space: nowrap; }
.ticket-progress.is-won .ticket-progress-sum { color: var(--coral); font-weight: 700; }
.ticket-progress-bar { display: block; height: 6px; border-radius: var(--r-pill); background: var(--line); overflow: hidden; overflow: clip; }
.ticket-progress-fill { display: block; height: 100%; border-radius: inherit; background: var(--accent); transform: scaleX(0); transform-origin: left center; transition: transform var(--dur-3) var(--ease-out); }
.ticket-progress.is-won .ticket-progress-fill { background: linear-gradient(90deg, var(--pineapple) 0%, var(--coral) 100%); }

/* 每期结果: every row the same size (place, issue and date, drawn numbers or when, a fixed result column). */
.draws-sheet { display: grid; gap: 10px; }
.draws-sheet-sum { font-size: 14px; font-weight: 700; color: var(--text); }
.period-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.period-row {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) 96px;
  align-items: center;
  gap: 8px;
  min-height: 70px;
  margin: 0;
  padding: 10px 10px 10px 8px;
  border: 2px solid transparent;
  border-radius: 16px;
  background: var(--surface-2);
}
.period-row--win {
  background:
    linear-gradient(var(--surface-2), var(--surface-2)) padding-box,
    linear-gradient(135deg, var(--pineapple) 0%, var(--coral) 100%) border-box;
}
.period-row-index { display: grid; place-items: center; width: 24px; height: 24px; border-radius: 8px; background: var(--surface-3); font-size: 12px; font-weight: 700; color: var(--text-3); }
.period-row-main { display: grid; gap: 6px; min-width: 0; }
.period-row-main > * { min-width: 0; }
.period-row-title { overflow: hidden; font-size: 13px; font-weight: 600; color: var(--text-2); text-overflow: ellipsis; white-space: nowrap; }
.period-row-balls { min-height: 24px; }
.period-row-balls .balls { flex-wrap: nowrap; gap: 3px; }
.period-row-balls .balls-sep { height: 18px; margin: 0 2px; }
/* 7 balls at 24px need 195px; a 375-wide phone gives the column 181px. */
@media (max-width: 400px) {
  .period-row-balls .ball--xs { --size: 21px; }
  .period-row-balls .balls { gap: 2px; }
}
.period-row-wait { display: flex; align-items: center; gap: 5px; min-height: 24px; font-size: 13px; color: var(--text-3); }
.period-row-wait svg { width: 15px; height: 15px; flex-shrink: 0; }
.period-row-tax { font-size: 12px; color: var(--text-2); }
.period-row-result { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; font-size: 13px; font-weight: 700; line-height: 1.35; text-align: right; }
.period-row-phrase { display: inline-block; max-width: 100%; }
.period-row-result--pending { color: var(--accent); }
.period-row-result--lose { color: var(--text-3); }
.period-row-result--win { color: var(--coral); }
.period-row-result--float { color: var(--warning-text); }
.ticket-actions { display: flex; gap: 6px; flex-shrink: 0; }
.ticket-actions .icon-btn svg { width: 20px; height: 20px; }
.result-badge {
  font-variant-numeric: tabular-nums;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  min-height: 32px;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.3;
  /* When it has to wrap, at a space or after 「，」, never inside 「以官方为准」 or an amount (review 2026-10-14). */
  word-break: keep-all;
  overflow-wrap: break-word;
}
.result-badge svg { width: 16px; height: 16px; flex-shrink: 0; }
.result-badge--pending { background: var(--accent-soft); color: var(--accent); }
.result-badge--lose { background: var(--surface-3); color: var(--text-3); }
.result-badge--win { color: #fff; background: linear-gradient(135deg, #FFB020 0%, #FF6B5A 100%); box-shadow: 0 4px 12px rgba(255, 107, 90, 0.35); }
.result-badge--float { border-radius: 14px; background: var(--warning-soft); color: #8A5600; }
@media (prefers-color-scheme: dark) { .result-badge--float { color: #FFD06A; } }
.empty-icon { display: grid; place-items: center; width: 64px; height: 64px; border-radius: 22px; background: var(--surface-3); color: var(--text-3); }
.empty-icon svg { width: 30px; height: 30px; }
/* Empty tab (spec §28): picture, title, one line. The drawing has ~15px of blank space at its top,
   so the top padding is the smaller one and the card looks evenly spaced. */
.records-empty { gap: 0; padding: 20px 20px 30px; }
.records-empty .empty-art { margin-bottom: 12px; }
.records-empty p { margin-top: 6px; line-height: 1.55; }
.records-empty-phrase { white-space: nowrap; }
/* 抓不到开奖号？手动录入 — rarely needed, so quiet: grey text, only the action slightly darker. */
.records-manual { display: flex; justify-content: center; margin-top: 10px; }
.records-manual .records-manual-btn { padding: 0 12px; color: var(--text-3); font-size: 13px; font-weight: 500; }
.records-manual-go { color: var(--text-2); font-weight: 600; text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; }
.records-manual + .disclaimer { margin-top: 10px; }

/* 识别任务 (spec §29.1): one card per photo on top of 待开奖. Every card is the same size whatever it
   says: the picture sets the height, the state takes at most two lines and the note under it two. */
.scan-jobs { display: grid; gap: 12px; }
.scan-job {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  align-items: center;
  gap: 6px;
  padding: 12px 10px 12px 12px;
  border: 2px solid transparent;
  border-radius: var(--r-l);
  background: var(--surface);
  box-shadow: var(--shadow-2);
  overflow: hidden;
  overflow: clip;
  transition: opacity 280ms var(--ease-out), transform 280ms var(--ease-out), border-color var(--dur-2);
}
.scan-job--warn { border-color: var(--warning-soft); }
.scan-job--danger { border-color: var(--danger-soft); }
.scan-job.is-removing { opacity: 0; transform: scale(0.95); }
.scan-job-main {
  display: grid;
  grid-template-columns: 60px minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 0;
  border: 0;
  border-radius: var(--r-s);
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
}
button.scan-job-main { grid-template-columns: 60px minmax(0, 1fr) 18px; transition: transform var(--dur-1) var(--ease-out); }
button.scan-job-main:active { transform: scale(0.98); }
.scan-job-thumb {
  position: relative;
  display: grid;
  place-items: center;
  width: 60px;
  height: 80px;
  border-radius: 12px;
  overflow: hidden;
  overflow: clip;
  background: var(--surface-3);
  color: var(--text-3);
}
.scan-job-thumb > svg { width: 24px; height: 24px; }
.scan-job-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.scan-job-img:not([src]), .scan-job-img.is-broken { display: none; }
.scan-job-thumb .scan-line { display: none; }
.scan-job.is-reading .scan-job-thumb .scan-line { display: block; }
.scan-job-text { display: grid; gap: 4px; min-width: 0; }
.scan-job-title { display: flex; align-items: flex-start; gap: 5px; min-width: 0; font-size: 15px; font-weight: 700; line-height: 1.3; }
.scan-job-icon { display: inline-grid; flex-shrink: 0; margin-top: 1px; }
.scan-job-icon svg { width: 17px; height: 17px; }
.scan-job-title-text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  min-width: 0;
  overflow: hidden;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.scan-job-sub {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--text-3);
}
/* A phrase moves to the next line whole; one longer than a line still wraps inside. */
.scan-job-phrase { display: inline-block; max-width: 100%; }
.scan-job--accent .scan-job-title { color: var(--accent); }
.scan-job--warn .scan-job-title { color: var(--warning-text); }
.scan-job--danger .scan-job-title { color: var(--danger); }
.scan-job-go { display: grid; place-items: center; color: var(--text-3); }
.scan-job-go svg { width: 18px; height: 18px; }
.scan-job-delete { color: var(--text-3); }
.scan-job-bar { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: var(--accent-soft); }
.scan-job-fill { display: block; height: 100%; background: var(--accent); transform: scaleX(0); transform-origin: left center; transition: transform var(--dur-2) var(--ease-out); }

/* ======================= 拍票 / 手动记一张 ======================= */

.entry { display: grid; gap: 14px; }
.entry .field + .field { margin-top: 0; }
.entry-photo {
  position: relative;
  display: block;
  width: 100%;
  height: 200px;
  padding: 0;
  border: 0;
  border-radius: 18px;
  overflow: hidden;
  overflow: clip;
  background: var(--surface-3);
}
.photo-canvas { display: block; width: 100%; height: 100%; object-fit: contain; }
.entry-photo-zoom {
  position: absolute;
  right: 10px; bottom: 10px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 6px 12px;
  border-radius: var(--r-pill);
  background: rgba(20, 8, 28, 0.62);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.entry-photo-zoom svg { width: 16px; height: 16px; }
.entry-notices { display: grid; gap: 6px; }
.entry-notice { display: flex; align-items: flex-start; gap: 8px; padding: 10px 12px; border-radius: 14px; font-size: 13.5px; line-height: 1.45; }
.entry-notice svg { width: 18px; height: 18px; flex-shrink: 0; margin-top: 1px; }
.entry-notice--ok { background: var(--positive-soft); color: var(--positive); font-weight: 600; }
.entry-notice--warn { background: var(--warning-soft); color: #8A5600; }
.entry-notice--error { background: var(--danger-soft); color: var(--danger); }
@media (prefers-color-scheme: dark) { .entry-notice--warn { color: #FFD06A; } }
.entry-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.entry .sheet-section-title { margin: 6px 2px -4px; }
.entry-count { margin-left: auto; font-size: 13px; font-weight: 600; color: var(--text-3); }
.entry-bets { display: grid; gap: 10px; }
.entry-bet {
  display: grid;
  gap: 8px;
  width: 100%;
  padding: 12px 14px;
  border: 2px solid var(--line);
  border-radius: 18px;
  background: var(--surface);
  color: var(--text);
  text-align: left;
  transition: border-color var(--dur-2), transform var(--dur-1);
}
.entry-bet:active { transform: scale(0.99); }
.entry-bet.is-invalid { border-color: var(--danger); background: color-mix(in srgb, var(--danger-soft) 45%, var(--surface)); }
.entry-bet.is-empty { border-style: dashed; }
.entry-bet-placeholder { display: inline-flex; align-items: center; gap: 6px; min-height: 30px; font-size: 14px; font-weight: 600; color: var(--accent); }
.entry-bet-placeholder svg { width: 18px; height: 18px; }
.entry-bet-error { display: flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; color: var(--danger); }
.entry-bet-error svg { width: 16px; height: 16px; flex-shrink: 0; }
.entry-rows { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
/* 期数 (spec §30): a row like 追加, a two-digit box on the right. */
.entry-draws .play-row-title { color: var(--text); }
/* 44px tall (the toggle row's size): both rows stay at the play-row's 62px. */
.entry-draws-input { flex-shrink: 0; width: 76px; min-height: 44px; height: 44px; padding: 0 8px; border-radius: var(--r-s); text-align: center; font-size: 18px; font-weight: 700; }
.input-wrap--prefix .input { padding-left: 38px; padding-right: 16px; font-size: 20px; font-weight: 700; }
.input-prefix { position: absolute; left: 16px; font-size: 18px; font-weight: 700; color: var(--text-3); pointer-events: none; }
/* The amount's check, and the draw date's (spec §35: 「这张票太旧了…」): one look. */
.entry-cost-hint, .entry-date-hint { font-variant-numeric: tabular-nums; display: flex; align-items: flex-start; gap: 6px; padding: 0 4px; font-size: 13px; line-height: 1.45; color: var(--text-3); }
.entry-cost-hint svg, .entry-date-hint svg { width: 16px; height: 16px; flex-shrink: 0; margin-top: 1px; }
.entry-cost-hint.is-ok { color: var(--positive); font-weight: 600; }
.entry-cost-hint.is-error, .entry-date-hint.is-error { color: var(--danger); font-weight: 600; }

.bet-editor > .seg { margin-bottom: 12px; }
/* 玩法 (spec §32.7): one row, or 「直选 | 组选」 and that kind's forms for 排列3 / 福彩3D. */
.bet-editor-plays { display: grid; gap: 8px; margin-bottom: 12px; }
.legend--compact { margin-bottom: 4px; }
.legend-swatch--pick { background: radial-gradient(circle at 50% 35%, var(--ball-red-light) 0%, var(--ball-red) 50%, var(--ball-red-dark) 100%); }
.bet-editor-mult { margin-top: 14px; border-top: 1px solid var(--line); }
.bet-editor-status { display: flex; align-items: center; gap: 6px; min-height: 40px; margin-top: 6px; padding: 8px 12px; border-radius: 14px; background: var(--surface-3); font-size: 14px; font-weight: 600; color: var(--text-2); }
.bet-editor-status svg { width: 18px; height: 18px; flex-shrink: 0; }
.bet-editor-status.is-ok { background: var(--positive-soft); color: var(--positive); }
.bet-editor-status.is-error { background: var(--danger-soft); color: var(--danger); }

.scan-wait { display: grid; justify-items: center; gap: 12px; padding-top: 4px; text-align: center; }
.scan-photo { position: relative; width: min(260px, 100%); border-radius: 20px; overflow: hidden; overflow: clip; box-shadow: var(--shadow-2); background: var(--surface-3); }
.scan-photo .photo-canvas { height: auto; max-height: 300px; object-fit: contain; }
.scan-line {
  position: absolute;
  left: 0; right: 0;
  top: 0;
  height: 3px;
  background: linear-gradient(90deg, rgba(255, 194, 51, 0), var(--pineapple) 30%, var(--coral) 70%, rgba(255, 107, 90, 0));
  box-shadow: 0 0 16px 4px rgba(255, 194, 51, 0.55);
  animation: scan-sweep 1.8s ease-in-out infinite alternate;
}
@keyframes scan-sweep { from { top: 0; } to { top: calc(100% - 3px); } }
.scan-text { display: inline-flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 600; }
.scan-text svg { width: 20px; height: 20px; color: var(--accent); }
.scan-elapsed { font-size: 13px; color: var(--text-3); }
/* 正在上传照片 45% → 正在认票面上的号码… (spec §26.3): one line, digits that do not shift it. */
.scan-status { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* The save button while the photo goes up with it: the label shows the percent over a filling bar. */
.btn.has-progress { overflow: hidden; }
.btn.has-progress > :not(.btn-progress):not(.spinner) { position: relative; font-variant-numeric: tabular-nums; }
.btn.is-busy.has-progress > :not(.spinner) { opacity: 1; }
.btn.is-busy.has-progress .spinner { display: none; }
.btn-progress {
  position: absolute;
  inset: 0;
  background: var(--hero-glass-strong);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-2) var(--ease-out);
  pointer-events: none;
}

.viewer { position: fixed; inset: 0; z-index: 160; background: rgba(8, 2, 12, 0.94); animation: fade-in 180ms both; }
.viewer.is-leaving { animation: fade-out 180ms both; }
.viewer-scroll { position: absolute; inset: 0; overflow: auto; display: grid; place-items: center; padding: calc(var(--safe-top) + 60px) 8px calc(var(--safe-bottom) + 20px); }
.viewer-canvas { display: block; max-width: 100%; height: auto; border-radius: 10px; }
.viewer-close { position: absolute; top: calc(var(--safe-top) + 10px); right: 14px; }
/* While a viewer's picture comes, and when it does not (spec §34; ui/viewer.js): ticket photos and the
   hero picture. The spinner waits 150 ms (§13), so a picture that is already here does not flash it. */
.viewer-wait { display: grid; justify-items: center; gap: 12px; color: var(--hero-text-2); font-size: 15px; animation: fade-in var(--dur-1) var(--ease-out) 150ms both; }
.viewer-wait .spinner { width: 32px; height: 32px; border-width: 3px; color: var(--hero-text); }
.viewer-error { display: grid; justify-items: center; gap: 8px; max-width: 280px; text-align: center; color: var(--hero-text); }
.viewer-error-icon { display: grid; place-items: center; color: var(--hero-text-2); }
.viewer-error-icon svg { width: 40px; height: 40px; }
.viewer-error-title { font-size: 18px; font-weight: 700; }
.viewer-error-text { margin: 0; font-size: 15px; line-height: 1.5; color: var(--hero-text-2); }
.viewer-retry { margin-top: 8px; }

/* ======================= 账本 ======================= */

.ledger-range { min-height: 1.4em; }
.page--ledger .hero-seg { margin-top: 12px; }
.page--ledger .seg-item { font-size: 14px; }
.ledger { transition: opacity var(--dur-2); }
.ledger.is-loading { opacity: 0.55; }
/* First load with nothing cached: the real cards with shimmering values (same heights, no jump). */
.ledger.is-skeleton { opacity: 1; }
.skeleton-value { display: inline-block; vertical-align: middle; width: 4.2em; max-width: 100%; height: 0.8em; border-radius: 6px; }
.figure-value .skeleton-value { width: 3.6em; }
.skeleton-block { display: block; height: 84px; margin: 6px 0; }
.skeleton-chart { display: block; height: 240px; }
.figures { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; gap: var(--gap); }
.figure {
  display: grid;
  gap: 4px;
  min-width: 0;
  padding: var(--card-pad);
  border-radius: var(--r-l);
  container-type: inline-size;
  background: var(--surface);
  box-shadow: var(--shadow-2);
}
.figure-label { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 600; color: var(--text-2); }
.figure-label svg { width: 18px; height: 18px; }
.figure--cost .figure-label svg { color: var(--chart-cost); }
.figure--prize .figure-label svg { color: var(--chart-prize); }
/* Sized by the card so ¥6,208,577 fits a 375px half card; 花了 and 中了 always share one size. A longer amount
   (ledger.js sets the longest one's length, --figure-chars / --net-chars) makes it smaller: money is never cut with
   「…」 (review 2026-10-14: ¥15,126,… on a 7星彩 一等奖). */
.figure-value { font-family: var(--font-rounded); font-variant-numeric: tabular-nums; font-size: 28px; font-size: min(28px, 17cqi, 165cqi / var(--figure-chars, 1)); font-weight: 800; line-height: 1.15; letter-spacing: -0.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.figure--net { grid-column: 1 / -1; grid-template-columns: 1fr auto; align-items: center; }
.figure--net .figure-label { grid-column: 1 / -1; }
.figure--net .figure-value { font-size: 34px; font-size: min(34px, 11cqi, 135cqi / var(--net-chars, 1)); }
.figure-note { justify-self: end; padding: 4px 12px; border-radius: var(--r-pill); font-size: 13px; font-weight: 700; background: var(--surface-3); color: var(--text-2); }
.figure--gain .figure-value { color: var(--gain); }
.figure--gain .figure-label svg { color: var(--gain); }
.figure--gain .figure-note { background: var(--positive-soft); color: color-mix(in srgb, var(--positive) 85%, var(--text)); }
.figure--loss .figure-value { color: var(--loss); }
.figure--loss .figure-label svg { color: var(--loss); }
.figure--loss .figure-note { background: var(--danger-soft); color: color-mix(in srgb, var(--danger) 85%, var(--text)); }

/* 6-col track: 3 per row (span 2); a last row of 2 splits in halves (span 3), of 1 spans the row — no empty slot. */
.mini-stats { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); grid-auto-rows: 1fr; gap: 14px 8px; margin-top: var(--gap); padding: 16px 12px; }
.mini-stat { grid-column: span 2; display: grid; align-content: start; justify-items: center; gap: 2px; text-align: center; min-width: 0; }
.mini-stat:nth-child(3n + 1):nth-last-child(2), .mini-stat:nth-child(3n + 1):nth-last-child(2) + .mini-stat { grid-column: span 3; }
.mini-stat:nth-child(3n + 1):last-child { grid-column: 1 / -1; }
.mini-stat-value { font-size: 22px; font-weight: 800; line-height: 1.2; }
.mini-stat-label { max-width: 100%; font-size: 12px; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.ledger-chart, .ledger-days { margin-top: var(--gap); }
.month-chart { display: grid; gap: 8px; }
.chart-top { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 8px; }
.chart-readout { font-variant-numeric: tabular-nums; display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; min-height: 24px; font-size: 13px; color: var(--text-2); }
.chart-readout-month { font-weight: 700; color: var(--text); }
.chart-readout-item { display: inline-flex; align-items: center; gap: 5px; }
.chart-readout-item strong { font-size: 15px; color: var(--text); }
.chart-legend { display: flex; gap: 12px; font-size: 12px; color: var(--text-2); }
.legend-key { display: inline-flex; align-items: center; gap: 5px; }
.legend-swatch-bar { width: 8px; height: 12px; border-radius: 3px 3px 0 0; background: var(--chart-cost); }
.legend-swatch-bar--prize { background: var(--chart-prize); }
.line-key { display: inline-block; width: 12px; height: 3px; border-radius: 2px; background: var(--chart-cost); }
.line-key--prize { background: var(--chart-prize); }
.chart-scroll { overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.chart-scroll::-webkit-scrollbar { display: none; }
.chart-svg { display: block; }
.chart-grid { stroke: var(--chart-grid); stroke-width: 1; }
.chart-axis { stroke: var(--line-strong); stroke-width: 1; }
.chart-tick, .chart-xlabel { fill: var(--text-3); font-size: 11px; font-family: var(--font); }
.chart-year { fill: var(--text-3); font-size: 10px; font-family: var(--font); opacity: 0.8; }
.chart-group { cursor: pointer; outline: none; }
.chart-hit { fill: transparent; }
.chart-wash { fill: transparent; transition: fill var(--dur-2); }
.chart-group.is-selected .chart-wash { fill: var(--surface-3); }
.chart-group:focus-visible .chart-wash { stroke: var(--focus); stroke-width: 2; }
.chart-group.is-selected .chart-xlabel { fill: var(--text); font-weight: 700; }
.chart-xlabel.is-minor { visibility: hidden; }
.chart-bar--cost { fill: var(--chart-cost); }
.chart-bar--prize { fill: var(--chart-prize); }

.ledger-table { margin-top: 12px; border-top: 1px solid var(--line); }
.ledger-table summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-2);
  cursor: pointer;
  list-style: none;
}
.ledger-table summary::-webkit-details-marker { display: none; }
.ledger-table summary svg { width: 18px; height: 18px; transition: transform var(--dur-2); }
.ledger-table[open] summary svg { transform: rotate(180deg); }
.ledger-table table { width: 100%; border-collapse: collapse; font-size: 14px; }
.ledger-table th, .ledger-table td { padding: 8px 4px; text-align: right; border-bottom: 1px solid var(--line); font-variant-numeric: tabular-nums; }
.ledger-table th:first-child { text-align: left; font-weight: 500; }
.ledger-table thead th { font-size: 12px; font-weight: 600; color: var(--text-3); }

.day-list { display: grid; }
.day-row { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 2px 10px; padding: 10px 0; border-bottom: 1px solid var(--line); }
.day-row:last-child { border-bottom: 0; }
.day-date { font-weight: 600; }
.day-count { font-size: 13px; color: var(--text-3); justify-self: end; }
.day-money { grid-column: 1 / -1; display: flex; gap: 16px; font-size: 14px; color: var(--text-2); }
.day-cost, .day-prize { display: inline-flex; align-items: center; gap: 6px; }
.day-empty { padding: 8px 0; }

.game-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 1fr; align-items: stretch; gap: var(--gap); margin-top: var(--gap); }
.game-card { display: grid; align-content: start; gap: 10px; min-width: 0; padding: var(--card-pad); }
.game-card .chip { justify-self: start; }
.game-card-list { display: grid; gap: 6px; margin: 0; }
.game-card-list div { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; column-gap: 8px; min-width: 0; }
.game-card-list dt { flex-shrink: 0; font-size: 13px; color: var(--text-3); }
/* An amount too long for the row goes under its label, right-aligned, never cut (review 2026-10-14); the cards of a
   row stay the same height (.game-cards grid-auto-rows). */
.game-card-list dd { min-width: 0; margin: 0 0 0 auto; font-weight: 700; white-space: nowrap; }
.ledger-foot { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 26px; font-size: 13px; color: var(--text-3); }
.ledger-foot svg { width: 16px; height: 16px; color: var(--coral); }

/* ======================= Settings ======================= */

.page--settings .page-body { margin-top: 0; padding-top: 4px; }
.profile { display: flex; align-items: center; gap: 14px; margin-top: 12px; }
.profile-avatar {
  width: 64px; height: 64px;
  flex-shrink: 0;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.9), 0 8px 20px rgba(10, 0, 20, 0.28);
}
.profile-avatar svg { width: 100%; height: 100%; }
.profile-text { display: grid; gap: 2px; min-width: 0; }
.profile-name { font-size: 22px; font-weight: 800; }
.profile-sub { font-size: 13px; color: var(--hero-text-2); }
.section-foot { margin: 8px 8px 0; font-size: 12.5px; line-height: 1.55; color: var(--text-3); }
.row--add .row-title { color: var(--positive); font-weight: 600; }
/* 休市日历: every row has the same columns (icon · text · tag · link slot), so tags and links line up
   and rows without a source keep the same height and tag position. */
.cal-tag { width: 40px; justify-content: center; }
.cal-link { flex-shrink: 0; width: 44px; height: 44px; margin-right: -8px; }
.cal-link svg { width: 18px; height: 18px; }
.cal-checked { min-height: 1.55em; }
.row:disabled { opacity: 0.55; }
.skeleton-line { display: block; width: 60%; height: 16px; border-radius: 8px; }
.passkey-sheet { display: grid; justify-items: center; gap: 14px; padding-top: 6px; text-align: center; }
.passkey-sheet .field { width: 100%; text-align: left; }
.passkey-hero {
  display: grid;
  place-items: center;
  width: 76px; height: 76px;
  border-radius: 26px;
  color: #fff;
  background: linear-gradient(135deg, #5CC78A, #2E9A5E);
  box-shadow: 0 12px 26px rgba(46, 154, 94, 0.35);
}
.passkey-hero svg { width: 42px; height: 42px; }
.about-card { display: flex; align-items: center; gap: 14px; }
.about-art { width: 86px; flex-shrink: 0; }
.about-art svg { width: 100%; height: auto; overflow: visible; }
.about-text { display: grid; gap: 2px; }
.about-text strong { font-size: 17px; }
.about-text span { font-size: 14px; color: var(--text-2); }
.about-text .about-version { font-size: 12.5px; color: var(--text-3); }

/* ======================= Small screens ======================= */

@media (max-width: 374px) {
  .hero-title { font-size: 28px; }
  .stat-value { font-size: 22px; }
  .gen-action { font-size: 13px; gap: 3px; }
  .gen-action svg { width: 16px; height: 16px; }
}

/* ---------- 快乐8 (spec §32 phase 3b) ---------- */
/* 「这一注」: 选一…选十 as two rows of five equal buttons (§12), the form switch under them. */
.keno-play-section { margin-bottom: 14px; }
.keno-play-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); grid-auto-rows: 1fr; gap: 8px; }
.keno-play {
  min-width: 0;
  min-height: 44px;
  padding: 0 4px;
  border: 0;
  border-radius: var(--r-s);
  background: var(--surface-3);
  color: var(--text);
  font-size: 15px;
  font-weight: 700;
  white-space: nowrap;
  transition: transform var(--dur-1) var(--ease-out), background-color var(--dur-2), color var(--dur-2);
}
.keno-play:active { transform: scale(0.95); }
.keno-play.is-selected { background: var(--game-kl8); color: var(--game-kl8-on); box-shadow: var(--shadow-1); }
.keno-forms > .seg { margin-bottom: 4px; }
/* The 20 drawn numbers: two rows of ten equal cells (four rows of five in 每期结果's narrow column); cells shrink on a
   phone and stay ball-sized on an iPad instead of spreading over the card. */
.balls.balls--keno-draw { display: grid; grid-template-columns: repeat(10, minmax(0, 32px)); justify-content: start; justify-items: center; gap: 4px 2px; }
.period-row-balls .balls.balls--keno-draw { grid-template-columns: repeat(5, minmax(0, 32px)); }
.ticket-drawn--stack { flex-direction: column; align-items: stretch; gap: 6px; }
