/* BuyToken public site.
   Light "paper" surface, hairline borders, one deep-green accent, generous
   vertical rhythm. Everything is plain CSS on purpose — no build step, so the
   page ships inside the relay binary as-is. */

:root {
  --ink: #1f1f1f;
  --ink-2: #5f6368;
  --ink-3: #9aa0a6;

  --green: #047857;
  --green-d: #065f46;
  --green-l: #34d399;
  --tint: #f6faf7;
  --tint-2: #ecfdf3;

  --line: #eaecef;
  --line-2: #e5e7eb;
  --line-3: #dadce0;

  --panel: #0f1115;
  --panel-2: #1a1d23;

  --wrap: none;
  --pad: clamp(14px, 1.25vw, 20px);

  /* Right-edge fade for the horizontal chip strips phones fall back to. */
  --strip-fade: linear-gradient(to right, #000 0, #000 calc(100% - 22px), transparent 100%);

  --r-sm: 10px;
  --r: 16px;
  --r-lg: 24px;

  --sh-card: 0 8px 30px rgba(15, 23, 42, .06);
  --sh-hero: 0 20px 60px rgba(15, 23, 42, .08);

  --font: -apple-system, system-ui, BlinkMacSystemFont, "PingFang SC",
    "Helvetica Neue", "Segoe UI", "Microsoft YaHei", sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: #fff;
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Short public pages should still finish at the bottom of the viewport instead
   of leaving their footer floating halfway up a tall monitor. */
body > main,
body > .app { flex: 1 0 auto; }
body > .foot { margin-top: auto; }

a { color: inherit; text-decoration: none; }

h1, h2, h3 { margin: 0; font-weight: 600; }

p { margin: 0; }

code {
  font-family: var(--mono);
  font-size: .92em;
}

/* Horizontal longhands, not the `padding` shorthand: these container classes
   get composed with others that set vertical padding (e.g. `wrap-wide hdr-in`),
   and a shorthand would silently zero that out depending on source order. */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding-left: var(--pad);
  padding-right: var(--pad);
}

/* ---------- header ---------- */

.hdr {
  position: sticky;
  top: 0;
  z-index: 30;
  background: rgba(255, 255, 255, .9);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}

.hdr-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  min-height: 70px; /* floor, so the bar keeps its shape whatever it holds */
  padding-top: 14px;
  padding-bottom: 14px;
}

.brand { display: flex; align-items: center; gap: 10px; }

.brand-lockup {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
}

.brand-domain {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--green-d);
  line-height: 1.2;
}

.brand-mark {
  display: grid;
  place-items: center;
  width: 148px;
  height: 34px;
  flex: 0 0 auto;
}

.brand-logo {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
  object-position: left center;
}

.brand-name {
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -.005em;
}

.nav {
  display: none;
  align-items: center;
  gap: 32px;
  font-size: 14px;
  color: var(--ink-2);
}

.nav a { transition: color .15s ease; }
.nav a:hover { color: var(--ink); }

.hdr-cta { display: flex; align-items: center; gap: 12px; }

/* Header account balance. Sits left of the language switch, where the QQ group
   pop-over used to be. The label shows on wider screens and collapses to the
   wallet glyph plus the amount on a phone, so the account block and 退出 keep
   their room. Colours follow the wallet page: under ¥5 is low, below zero is
   overdrawn. */
.hdr-bal {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.hdr-bal-ico {
  width: 16px;
  height: 16px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.hdr-bal-label { color: var(--ink-2); }
.hdr-bal-amt { font-weight: 600; color: var(--green-d); }
.hdr-bal-low .hdr-bal-amt { color: #b45309; }
.hdr-bal-neg .hdr-bal-amt { color: #e5484d; }
/* Only on a narrow phone does the label go: the wallet glyph beside the amount
   still says what the number is. */
@media (max-width: 520px) {
  .hdr-bal-label { display: none; }
  .hdr-bal { padding-left: 10px; padding-right: 10px; }
}
.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--ink-3);
  font-size: 13px;
  white-space: nowrap;
}

.lang-switch a { color: var(--ink-2); }
.lang-switch a:hover,
.lang-switch a[aria-current="true"] { color: var(--green); font-weight: 600; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: 999px;
  padding: 9px 20px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

.btn:focus-visible {
  outline: 2px solid rgba(4, 120, 87, .35);
  outline-offset: 2px;
}

.btn-solid { background: var(--green); color: #fff; }
.btn-solid:hover { background: var(--green-d); }

.btn-ghost {
  border: 1px solid var(--line-3);
  color: var(--green);
  background: #fff;
}
.btn-ghost:hover { background: var(--tint); border-color: #c7d9d0; }

.btn-lg { padding: 12px 26px; }

/* ---------- shared section furniture ---------- */

.sec {
  border-top: 1px solid var(--line);
  padding: 88px 0;
  /* keep anchor targets clear of the sticky header */
  scroll-margin-top: 64px;
}

.sec-head {
  display: grid;
  gap: 20px;
  margin-bottom: 44px;
}

.eyebrow {
  font-size: 14px;
  font-weight: 500;
  color: var(--green);
  margin-bottom: 12px;
}

.sec-head h2 {
  font-size: clamp(27px, 3.4vw, 40px);
  line-height: 1.2;
  letter-spacing: -.01em;
}

.sec-note {
  font-size: 15px;
  line-height: 1.75;
  color: var(--ink-2);
  max-width: 460px;
}

.sec-note code {
  background: var(--tint-2);
  color: var(--green-d);
  padding: 2px 6px;
  border-radius: 6px;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  align-self: flex-start;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: #fff;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-2);
  box-shadow: 0 1px 2px rgba(15, 23, 42, .04);
}

.pill-g { background: var(--tint-2); border-color: #c6f0da; color: var(--green-d); }

.dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--green);
}

.ico {
  width: 22px;
  height: 22px;
  /* Icons live next to text that wraps on a phone; without this they get
     squashed off their viewBox ratio instead of holding their size. */
  flex: none;
  fill: none;
  stroke: var(--green);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------- hero ---------- */

/* Launch strip above the hero. Amber rather than the brand green so it reads as
   news instead of another call to action, and compact enough on a phone that it
   does not push the ¥ gift chip out of the first screen. */
.deal-strip {
  display: flex;
  /* The callout is operator copy and can be a whole sentence, not just a
     「4 折」 chip. Wrapping lets a long one drop to its own row instead of
     crushing the title into a one-word column and widening the page. */
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 20px 0 0;
  padding: 14px 20px;
  border: 1px solid #f0c98a;
  border-left: 5px solid #d97706;
  border-radius: 14px;
  background: linear-gradient(90deg, #fff8ec, #fffdf8);
  text-decoration: none;
  color: var(--ink);
  transition: transform .15s ease, box-shadow .15s ease;
}

.deal-strip:hover {
  transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(217, 119, 6, .18);
  color: var(--ink);
}

.deal-flag {
  flex: none;
  padding: 3px 9px;
  border-radius: 999px;
  background: #d97706;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
}

.deal-main {
  display: flex;
  /* Grows into the row but claims at least 14em before the callout may sit
     beside it; below that the callout wraps under it. */
  flex: 1 1 14em;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 12px;
  min-width: 0;
}

.deal-title {
  font-size: clamp(17px, 2.1vw, 23px);
  font-weight: 700;
  letter-spacing: -.01em;
}

.deal-note { font-size: 13px; color: var(--ink-2); }

.deal-off {
  flex: 0 1 auto;
  min-width: 0;
  /* Beside the title it never takes more than ~half the row; a longer
     callout wraps inside the chip. Alone on its own row it may use it all. */
  max-width: 48%;
  padding: 6px 14px;
  /* Half the one-line height: a pill on one line, a rounded box on two. */
  border-radius: 18px;
  background: #d97706;
  color: #fff;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.deal-arw { flex: none; font-size: 17px; font-weight: 700; color: #d97706; }

@media (max-width: 900px) {
  /* Too narrow for the title and a sentence-long callout side by side: the
     callout takes the row under the title, and the → follows it. */
  .deal-off { max-width: 100%; }
}

@media (max-width: 620px) {
  .deal-strip { gap: 8px 9px; padding: 12px 14px; border-radius: 12px; }
  /* Narrower floor on a phone so a short 「官方 4 折」 still shares the row
     at 360px; anything much longer goes to the row below. */
  .deal-main { flex-basis: 7em; }
  .deal-title { font-size: 16px; line-height: 1.45; }
  /* The note is the first thing to go: the headline and the 折 are what make
     this worth a row of the first screen. */
  .deal-note { display: none; }
  .deal-off { padding: 5px 11px; border-radius: 14px; font-size: 13px; }
  .deal-arw { display: none; }
}

.hero {
  display: grid;
  grid-template-columns: 1fr;
  gap: 48px;
  padding: 72px 0 88px;
}

.hero-copy { display: flex; flex-direction: column; }

.hero h1 {
  margin-top: 24px;
  max-width: 640px;
  font-size: clamp(31px, 4.6vw, 50px);
  line-height: 1.16;
  letter-spacing: -.02em;
}

.hero h1 .g { color: var(--green); }

.lead {
  margin-top: 24px;
  max-width: 560px;
  font-size: 15px;
  line-height: 1.85;
  color: var(--ink-2);
}

.mini-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  margin-top: 32px;
}

.mini {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: rgba(255, 255, 255, .8);
  padding: 16px;
  transition: transform .15s ease, border-color .15s ease, box-shadow .15s ease;
}

.mini:hover {
  transform: translateY(-1px);
  border-color: #d2e7dc;
  box-shadow: 0 6px 20px rgba(15, 23, 42, .05);
}

.mini h3 { margin-top: 10px; font-size: 14px; }

.mini p {
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.6;
  color: var(--ink-2);
}

.ticks {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  margin: 28px 0 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
  color: var(--ink-2);
}

.ticks li { display: flex; align-items: center; gap: 7px; }

.ticks li::before {
  content: "";
  width: 14px;
  height: 14px;
  flex: none;
  border-radius: 999px;
  background: var(--tint-2);
  /* check mark */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.6 6.2 4.8 8.4 9.4 3.8' fill='none' stroke='%23047857' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-size: 12px 12px;
  background-position: center;
  background-repeat: no-repeat;
}

/* first-screen invoice banner, links to the invoice section */

.hero-inv {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 12px;
  margin-top: 20px;
  border: 1px solid #fecaca;
  border-radius: var(--r);
  background: #fef2f2;
  padding: 14px 18px;
  color: #b91c1c;
  transition: border-color .15s ease, box-shadow .15s ease;
}

.hero-inv:hover {
  border-color: rgba(185, 28, 28, .45);
  box-shadow: var(--sh-card);
}

.hero-inv .ico { width: 20px; height: 20px; flex: none; stroke: #dc2626; }

.hero-inv-t { font-size: 15px; font-weight: 600; white-space: nowrap; }

.hero-inv-d {
  flex: 1;
  min-width: 200px;
  font-size: 13px;
  color: var(--ink-2);
}

.hero-inv-arw { flex: none; font-size: 15px; transition: transform .15s ease; }

.hero-inv:hover .hero-inv-arw { transform: translateX(3px); }

/* ---------- hero card ---------- */

/* The hero's default second column. A campaign replaces it while one runs;
   with neither, the copy stretches the full width and the right half of the
   first screen is empty. */
.hero-card {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-self: start;
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  background: #fff;
  padding: 28px;
  box-shadow: var(--sh-hero);
}

.glow {
  position: absolute;
  top: -120px;
  right: -100px;
  width: 280px;
  height: 280px;
  border-radius: 999px;
  background: radial-gradient(circle, rgba(4, 120, 87, .12), transparent 68%);
  pointer-events: none;
}

.card-title {
  position: relative;
  margin-top: 18px;
  font-size: 22px;
  letter-spacing: -.02em;
}

.card-sub {
  position: relative;
  margin-top: 8px;
  font-size: 13px;
  line-height: 1.65;
  color: var(--ink-2);
}

.kv {
  position: relative;
  margin: 20px 0 0;
  display: grid;
  gap: 10px;
}

.kv > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.kv dt { font-size: 12px; color: var(--ink-3); }

.kv dd {
  margin: 0;
  min-width: 0;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink);
  overflow-wrap: anywhere;
}

.card-link {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 22px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
  font-size: 14px;
  font-weight: 500;
  color: var(--green);
}

.card-link:hover { color: var(--green-d); }
.card-link .arw { transition: transform .15s ease; }
.card-link:hover .arw { transform: translateX(3px); }

/* ---------- hero ad slot ---------- */

/* Artwork is desktop-only. On a phone the 3:2 poster used to lead the hero
   (order: -1) and pushed 注册立得 ¥1 below the fold; the compact chip next
   to the gift is the campaign on that width. */
.hero-ad {
  display: none;
}

/* Solid, not outlined: on a phone this chip is the whole campaign, so it has
   to read as loudly as the ¥1 gift it sits under rather than as a quiet tag. */
.hero-ad-compact {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  max-width: 100%;
  padding: 10px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #ea580c, #b45309);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .01em;
  text-decoration: none;
  box-shadow: 0 6px 18px rgba(234, 88, 12, .34);
  transition: transform .15s ease, box-shadow .15s ease;
  /* Two lines on a phone, and CJK breaks between any two characters: without
     this the wrap lands mid-word and leaves 方 6 折 dangling. Breaks are then
     only allowed at the spaces, and the discount itself is spelled with
     non-breaking ones. */
  word-break: keep-all;
}

.hero-ad-compact:hover {
  transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(234, 88, 12, .42);
  color: #fff;
}

.hero-ad-new {
  flex: none;
  padding: 2px 7px;
  border-radius: 6px;
  background: #fff;
  color: #b45309;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .06em;
}

.hero-ad-link {
  display: block;
  overflow: hidden;
  border-radius: var(--r-lg);
  box-shadow: var(--sh-hero);
  transition: transform .15s ease, box-shadow .15s ease;
}

.hero-ad-link:hover {
  transform: translateY(-2px);
  box-shadow: 0 26px 70px rgba(15, 23, 42, .14);
}

.hero-ad-link img {
  display: block;
  width: 100%;
  height: auto;
}

.code {
  position: relative;
  margin-top: 20px;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--panel);
}

.code-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-bottom: 1px solid rgba(255, 255, 255, .08);
}

.code-name {
  font-family: var(--mono);
  font-size: 11px;
  color: #8a8f98;
}

.copy {
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 999px;
  background: transparent;
  color: #c9cdd4;
  font-family: inherit;
  font-size: 11px;
  padding: 3px 11px;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}

.copy:hover { background: rgba(255, 255, 255, .08); color: #fff; }
.copy.ok { background: var(--green-l); border-color: var(--green-l); color: #06281c; }

.code pre {
  margin: 0;
  padding: 16px;
  overflow-x: auto;
  font-family: var(--mono);
  font-size: 12px;
  line-height: 1.85;
  color: #e8e8ec;
}

.code .cm { color: #6b7280; }
.code .kw { color: #7dd3fc; }
.code .st { color: var(--green-l); }

/* ---------- feature grid ---------- */

.grid-3 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}

.vendor-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
  padding: 8px 0 28px;
}
.vendor-card {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  padding: 22px 24px;
}
.vendor-card h2 {
  margin: 0;
  font-size: 18px;
  font-weight: 650;
  letter-spacing: -.02em;
}
.vendor-card p {
  margin: 8px 0 0;
  color: var(--ink-3);
  font-size: 13px;
}

.card {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  padding: 24px;
  transition: border-color .15s ease, box-shadow .15s ease;
}

.card:hover {
  border-color: rgba(4, 120, 87, .3);
  box-shadow: var(--sh-card);
}

.card h3 { margin-top: 14px; font-size: 18px; }

.card p {
  margin-top: 8px;
  font-size: 14px;
  line-height: 1.75;
  color: var(--ink-2);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 28px;
}

.chips-label {
  font-size: 13px;
  color: var(--ink-3);
  margin-right: 4px;
}

.chip {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 12px;
  color: var(--ink-2);
  background: var(--tint);
}

/* ---------- invoice ---------- */

.inv-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
  margin-bottom: 16px;
}

.inv-card {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  padding: 24px;
  transition: border-color .15s ease, box-shadow .15s ease;
}

.inv-card:hover {
  border-color: rgba(4, 120, 87, .3);
  box-shadow: var(--sh-card);
}

.inv-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.inv-head h3 { font-size: 18px; }

.inv-head .tag {
  margin-left: auto;
  border-radius: 999px;
  background: var(--tint-2);
  color: var(--green-d);
  font-size: 12px;
  font-weight: 500;
  padding: 3px 10px;
}

.inv-card > p {
  margin-top: 10px;
  font-size: 14px;
  line-height: 1.75;
  color: var(--ink-2);
}

.inv-list {
  margin: 14px 0 0;
  padding: 14px 0 0;
  list-style: none;
  display: grid;
  gap: 8px;
  font-size: 13px;
  color: var(--ink-2);
  border-top: 1px dashed var(--line);
}

.inv-list li { display: flex; align-items: center; gap: 7px; }

.inv-list li::before {
  content: "";
  width: 14px;
  height: 14px;
  flex: none;
  border-radius: 999px;
  background: var(--tint-2);
  /* check mark */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.6 6.2 4.8 8.4 9.4 3.8' fill='none' stroke='%23047857' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* ---------- contact page ---------- */

.contact-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
}

.contact-card {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  padding: 32px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
}

.contact-ico { width: 28px; height: 28px; flex: none; }

.contact-label { font-size: 13px; color: var(--ink-3); }

.contact-num {
  display: flex;
  align-items: center;
  gap: 12px;
}

.contact-num code {
  font-family: var(--mono);
  font-size: 28px;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--ink);
}

.contact-num .key-btn { font-size: 12px; padding: 5px 14px; }

.contact-hint { font-size: 13px; color: var(--ink-2); }

.contact-qr {
  width: min(240px, 100%);
  height: auto;
  display: block;
  border-radius: 18px;
}

/* Join button inside a centred contact card: the card's own gap is tuned for
   text rows, so the button needs its own breathing room above it. */
.contact-cta { margin-top: 6px; }

/* Home page QQ community block. Horizontal on desktop so the join button sits
   on the same line as the number, stacked below 620px. */
.qq-card {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  padding: 28px 32px;
  display: flex;
  align-items: center;
  gap: 20px;
}

.qq-ico { width: 28px; height: 28px; flex: none; }

.qq-qr {
  width: 176px;
  flex: none;
  margin: 0;
  text-align: center;
}

.qq-qr img {
  width: 176px;
  height: 176px;
  display: block;
  border-radius: 14px;
}

.qq-qr figcaption {
  margin-top: 7px;
  font-size: 12px;
  color: var(--ink-3);
}

.qq-body { flex: 1; min-width: 0; }

.qq-label { font-size: 13px; color: var(--ink-3); }

.qq-num {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 4px;
}

.qq-num code {
  font-family: var(--mono);
  font-size: 26px;
  font-weight: 600;
  letter-spacing: .02em;
  color: var(--ink);
}

.qq-num .key-btn { font-size: 12px; padding: 5px 14px; }

.qq-hint { margin-top: 8px; font-size: 13px; color: var(--ink-2); }

.qq-join { flex: none; }

@media (max-width: 620px) {
  .qq-card { flex-direction: column; align-items: center; padding: 24px; text-align: center; }
  .qq-body { width: 100%; }
  .qq-num { justify-content: center; }
  .qq-num code { font-size: 22px; }
  .qq-join { width: 100%; justify-content: center; }
}

.contact-list {
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 10px;
  font-size: 14px;
  line-height: 1.7;
  color: var(--ink-2);
}

/* ---------- tables ---------- */

.tbl-card {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  overflow: hidden;
}

.tbl-card + .tbl-card { margin-top: 16px; }

.tbl-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 18px 24px;
  border-bottom: 1px solid var(--line);
  background: var(--tint);
}

.tbl-head h3 { font-size: 16px; }

.tag {
  font-size: 12px;
  color: var(--ink-2);
}

.tbl-scroll { overflow-x: auto; }

.tbl {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

.tbl th,
.tbl td {
  padding: 13px 24px;
  text-align: left;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

.tbl thead th {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-3);
  background: #fff;
}

.tbl tbody tr:last-child th,
.tbl tbody tr:last-child td { border-bottom: none; }

.tbl tbody tr { transition: background-color .12s ease; }
.tbl tbody tr:hover { background: var(--tint); }

.tbl .r { text-align: right; }
.tbl .muted { color: var(--ink-2); font-weight: 400; }

.tbl .num {
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}

.tbl code { color: var(--ink); }

.tbl-kv th {
  width: 128px;
  font-weight: 500;
  color: var(--ink);
  vertical-align: top;
}

.tbl-kv td { white-space: normal; line-height: 1.7; }

.badge {
  display: inline-block;
  margin-left: 6px;
  border-radius: 999px;
  background: var(--tint-2);
  color: var(--green-d);
  font-size: 11px;
  font-weight: 500;
  padding: 1px 8px;
  vertical-align: 1px;
}

.peak-p {
  font-size: 11px;
  font-weight: 400;
  color: #b25a1b;
  line-height: 1.4;
}

.tbl-price td.note {
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}

.tbl-price td.note-discount {
  color: var(--green-d);
  font-weight: 500;
}

/* ---------- home pricing teaser ---------- */

/* The band under the hero: live headline prices so a first-time visitor —
   especially on a phone — sees what models cost without opening /pricing. */
.pt {
  display: flex;
  align-items: center;
  gap: 22px;
  padding: 16px 20px;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: #fff;
  transition: border-color .15s ease, box-shadow .15s ease;
}

.pt:hover { border-color: var(--green-l); box-shadow: 0 8px 24px rgba(15, 76, 92, .08); }

.pt-head { flex: 0 0 auto; }

.pt-label {
  display: block;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -.01em;
}

.pt-unit {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--ink-3);
}

.pt-items {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}

.pt-item {
  border: 1px solid var(--line-2);
  border-radius: 12px;
  padding: 8px 12px;
  min-width: 0;
}

.pt-item code {
  display: block;
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pt-price {
  display: block;
  margin-top: 2px;
  font-size: 15px;
  font-weight: 650;
  color: var(--green-d);
  white-space: nowrap;
}

.pt-sep { color: var(--ink-3); font-weight: 400; margin: 0 2px; }

.pt-more {
  flex: 0 0 auto;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--green-d);
  white-space: nowrap;
}

.pt-more .arw { margin-left: 4px; }

@media (max-width: 899.98px) {
  .pt { flex-direction: column; align-items: stretch; gap: 12px; }
  .pt-head { display: flex; align-items: baseline; justify-content: space-between; }
  .pt-items { grid-template-columns: 1fr 1fr; }
  .pt-more { text-align: center; padding-top: 2px; }
}

/* ---------- steps ---------- */

.steps {
  display: grid;
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: step;
}

.steps li {
  display: flex;
  gap: 18px;
  /* Same reason as `.doc-body section > *`: a grid item's automatic minimum is
     min-content, so an unwrappable code sample inside a step would widen the
     whole page instead of scrolling inside its own block. */
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  padding: 22px 24px;
  transition: border-color .15s ease, box-shadow .15s ease;
}

.steps li:hover {
  border-color: rgba(4, 120, 87, .3);
  box-shadow: var(--sh-card);
}

.step-n {
  display: grid;
  place-items: center;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: var(--tint-2);
  color: var(--green-d);
  font-size: 13px;
  font-weight: 600;
}

.steps h3 { font-size: 17px; }

.steps p {
  margin-top: 6px;
  font-size: 14px;
  line-height: 1.75;
  color: var(--ink-2);
}

/* ---------- faq ---------- */

.faq { display: grid; gap: 10px; }

.faq details {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  transition: border-color .15s ease;
}

.faq details[open] { border-color: #d2e7dc; }
.faq details:hover { border-color: #d2e7dc; }

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 24px;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  list-style: none;
}

.faq summary::-webkit-details-marker { display: none; }

.chev {
  flex: none;
  width: 9px;
  height: 9px;
  border-right: 1.6px solid var(--ink-3);
  border-bottom: 1.6px solid var(--ink-3);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .18s ease;
}

.faq details[open] .chev { transform: rotate(-135deg) translate(-2px, -2px); }

.faq p {
  padding: 0 24px 20px;
  font-size: 14px;
  line-height: 1.8;
  color: var(--ink-2);
}

/* ---------- closing cta ---------- */

.sec-cta { padding-bottom: 96px; }

.cta {
  display: grid;
  gap: 28px;
  border: 1px solid #d7ebe2;
  border-radius: var(--r-lg);
  background: linear-gradient(135deg, var(--tint-2), var(--tint) 70%);
  padding: 40px;
}

.cta-h {
  font-size: clamp(24px, 3vw, 32px);
  letter-spacing: -.015em;
  line-height: 1.25;
}

.cta-p {
  margin-top: 12px;
  max-width: 520px;
  font-size: 15px;
  line-height: 1.75;
  color: var(--ink-2);
}

.cta-btns { display: flex; flex-wrap: wrap; gap: 12px; }

.cta-act { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; }

.cta-gift {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 9px 18px;
  border-radius: 999px;
  background: var(--green);
  color: #fff;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .01em;
  box-shadow: 0 6px 18px rgba(22, 163, 74, .38);
}

.cta-gift b { font-size: 20px; font-weight: 700; }

/* hero 第一屏的营销胶囊：注册礼金（绿）+ 首充折扣（橙），可直接点击。 */
.hero-ctas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 22px 0 0;
}

.hero-gift,
.hero-deal {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 12px 24px;
  border-radius: 999px;
  color: #fff;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: .01em;
  text-decoration: none;
  transition: transform .15s ease, box-shadow .15s ease;
}

.hero-gift {
  background: var(--green);
  box-shadow: 0 6px 18px rgba(22, 163, 74, .38);
}

.hero-gift:hover {
  transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(22, 163, 74, .45);
  color: #fff;
}

.hero-deal {
  background: #d97706;
  box-shadow: 0 6px 18px rgba(217, 119, 6, .35);
}

.hero-deal:hover {
  transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(217, 119, 6, .45);
  color: #fff;
}

.hero-gift b,
.hero-deal b { font-size: 24px; font-weight: 700; }

.hero-gift-arw { font-weight: 700; }

/* The strip already supplies the space above the headline, so the hero drops
   most of its own top padding rather than opening a gap under the strip. */
.deal-strip + .hero { padding-top: 34px; }

@media (max-width: 620px) {
  /* Full-width so the gift is unmissable on the first screen instead of a
     small pill competing with the headline. */
  .hero-gift,
  .hero-deal {
    width: 100%;
    justify-content: center;
    padding: 13px 18px;
  }
  .hero-gift b,
  .hero-deal b { font-size: 22px; }
  .deal-strip + .hero { padding-top: 24px; }
}

/* 钱包页首充提示与实付价 */
.topup-deal {
  margin-bottom: 14px;
  padding: 10px 16px;
  border: 1px solid #fcd9a8;
  border-radius: var(--r-md, 10px);
  background: #fff7ed;
  color: #9a5b0b;
  font-size: 14px;
  line-height: 1.6;
}

.topup-deal b { color: #d97706; }

.topup-sub .topup-pay { color: #d97706; font-weight: 600; }
/* First-top-up offer: a banner above the amount picker and a flag on every
   discounted amount. It exists only while the account can still use the offer. */
.first-offer {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 18px;
  padding: 14px 18px;
  border: 1px solid #f3c26b;
  border-radius: 14px;
  background: linear-gradient(110deg, #fff7d6 0%, #fde68a 100%);
  color: #7a4a05;
  box-shadow: 0 6px 18px rgba(217, 119, 6, .14);
}
.first-offer-badge {
  flex: none;
  padding: 5px 13px;
  border-radius: 999px;
  background: #b45309;
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .02em;
  white-space: nowrap;
}
.first-offer-body { min-width: 0; }
.first-offer-t { display: block; font-size: 17px; font-weight: 700; color: #7a3f00; }
.first-offer-t b { font-size: 24px; color: #b45309; font-variant-numeric: tabular-nums; }
.first-offer-d { display: block; margin-top: 2px; font-size: 13px; line-height: 1.6; }
.topup-flag {
  margin-top: 2px;
  padding: 1px 8px;
  border-radius: 999px;
  background: #fff1cf;
  color: #b45309;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.6;
}
@media (max-width: 560px) {
  .first-offer { flex-direction: column; align-items: flex-start; gap: 8px; }
}

.topup-paid { font-size: 12px; }

/* ---------- footer ---------- */

.foot {
  border-top: 1px solid var(--line);
  padding: 32px 0 40px;
  font-size: 13px;
  color: var(--ink-2);
}

.foot-in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
}

.foot-copy { color: var(--ink-2); }
.foot-nav { display: flex; flex-wrap: wrap; gap: 20px; }
.foot-nav a:hover { color: var(--ink); }
.foot-icp { color: var(--ink-3); }
.foot-icp:hover { color: var(--ink-2); }

/* ============================================================
   Console
   Same tokens as the marketing pages, different furniture:
   sidebar shell, stat cards, dense tables, forms.
   ============================================================ */

/* Same max-width as .wrap: the console used to run 1400px while public pages
   ran 1280px, so the header's logo visibly jumped when crossing between them. */
.wrap-wide {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding-left: var(--pad);
  padding-right: var(--pad);
}

.brand-tag {
  border: 1px solid var(--line-2);
  border-radius: 999px;
  padding: 2px 9px;
  font-size: 11px;
  color: var(--ink-2);
}

/* The rename note sits next to the wordmark on the public header and auth
   pages, where a returning GimmitkAPI user is deciding whether they landed
   on the right site. It has to read at a glance, so it gets the brand
   gradient and white text rather than the muted tag treatment. */
.brand-note {
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 12px;
  font-weight: 600;
  color: #fff;
  background: linear-gradient(135deg, #0f4c5c, #14b8a6);
}

.inline-form { display: inline-flex; }

.acct { display: flex; align-items: center; gap: 9px; }

.acct-name { font-size: 14px; color: var(--ink-2); }

.avatar {
  display: grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: var(--tint-2);
  color: var(--green-d);
  font-size: 13px;
  font-weight: 600;
}

.avatar-sm {
  width: 20px;
  height: 20px;
  margin-right: 7px;
  font-size: 11px;
  background: rgba(255, 255, 255, .22);
  color: #fff;
}

/* ---------- shell ---------- */

.app {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  /* keeps .wrap-wide's gutter: a bare `0` here would let the sidebar's
     negative margin escape the viewport on mobile */
  padding: 28px var(--pad) 72px;
  align-items: start;
}

.side { display: flex; flex-direction: column; gap: 16px; }

.side nav { display: grid; gap: 2px; }

/* Group QR under the nav, shown in the open so it can be scanned straight off
   the screen. */
.side-qr {
  margin: 4px 0 0;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: #fff;
  text-align: center;
}
.side-qr img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 8px;
}
.side-qr figcaption { display: grid; gap: 2px; margin-top: 10px; }
.side-qr strong { font-size: 13px; color: var(--ink); }
.side-qr span { font-size: 12px; color: var(--ink-2); }
.side-qr code {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .01em;
  color: var(--ink-3);
}
.side-qr .side-qr-join { margin-top: 8px; }

.side-item {
  display: flex;
  align-items: center;
  gap: 11px;
  border-radius: var(--r-sm);
  padding: 9px 12px;
  font-size: 14px;
  color: var(--ink-2);
  transition: background-color .12s ease, color .12s ease;
}

.side-item:hover { background: var(--tint); color: var(--ink); }

.side-badge {
  display: inline-flex;
  align-items: center;
  min-height: 16px;
  padding: 1px 5px;
  border-radius: 999px;
  background: #e5484d;
  color: #fff;
  font-size: 9px;
  font-style: normal;
  font-weight: 750;
  line-height: 1;
  letter-spacing: .04em;
  box-shadow: 0 2px 6px rgba(229, 72, 77, .24);
}

.side-item.on {
  background: var(--tint-2);
  color: var(--green-d);
  font-weight: 500;
}

/* A badged console feature is a deliberate discovery point, not another
   same-weight menu row. Keep it static and high-contrast so HOT is noticeable
   without a distracting idle animation. */
.side-item-featured {
  position: relative;
  margin: 5px 0 7px;
  border: 1px solid #b9e5d0;
  background: linear-gradient(135deg, #ecfdf3 0%, #f4fbf7 62%, #fff5f5 100%);
  color: #086343;
  font-weight: 700;
  box-shadow: 0 8px 20px rgba(16, 122, 83, .12);
  transition: transform .14s ease, border-color .14s ease, box-shadow .14s ease, background-color .14s ease;
}

.side-item-featured:hover {
  border-color: #7fd3ac;
  background: linear-gradient(135deg, #def8e9 0%, #eefaf4 62%, #fff0f0 100%);
  color: #064e36;
  box-shadow: 0 10px 24px rgba(16, 122, 83, .17);
  transform: translateY(-1px);
}

.side-item-featured .side-ico {
  width: 32px;
  height: 32px;
  padding: 7px;
  border-radius: 10px;
  background: var(--green);
  color: #fff;
  opacity: 1;
  box-shadow: 0 4px 10px rgba(16, 122, 83, .22);
}

.side-item-featured .side-badge {
  min-height: 18px;
  margin-left: auto;
  padding: 2px 6px;
  box-shadow: 0 3px 8px rgba(229, 72, 77, .3);
}

.side-item-featured.on {
  border-color: #67c99c;
  background: linear-gradient(135deg, #d9f7e6 0%, #ebf9f2 65%, #ffeded 100%);
  color: #064e36;
  box-shadow: 0 10px 24px rgba(16, 122, 83, .16);
}

.side-ico {
  width: 17px;
  height: 17px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .8;
}

.app-main { min-width: 0; }

.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: 28px;
}

.page-h {
  font-size: clamp(24px, 3vw, 32px);
  letter-spacing: -.015em;
  line-height: 1.25;
  margin-top: 10px;
}

/* Invoicing reminder beside a page heading. Red because it asks the user to do
   something (contact support), not just to know something — but a tinted pill
   rather than a full alert box, so it does not outshout the balance figure the
   page exists to show. */
.head-title-row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 10px;
}

/* The row owns the gap above the heading; a second margin on the h1 would
   double it and push the pill off the heading's baseline. */
.head-title-row .page-h { margin-top: 0; }

.head-invoice {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 5px 11px 5px 5px;
  border: 1px solid #f5c9c9;
  border-radius: 999px;
  background: #fef4f4;
  color: #a33a3a;
  font-size: 13px;
  line-height: 1.35;
}


.head-invoice a {
  color: #a33a3a;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 2px;
  font-variant-numeric: tabular-nums;
}

.head-invoice a:hover { color: #7d2b2b; }

.head-invoice-copy {
  border: 1px solid #e7b4b4;
  border-radius: 999px;
  background: #fff;
  color: #a33a3a;
  font-family: inherit;
  font-size: 11px;
  line-height: 1;
  padding: 4px 9px;
  cursor: pointer;
}

.head-invoice-copy:hover { background: #fbe4e4; }
.head-invoice-copy.ok { background: #e5484d; border-color: #e5484d; color: #fff; }

/* ---------- stat cards ---------- */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px;
  margin-bottom: 32px;
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 8px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  padding: 20px 22px;
}

.stat-warn { border-color: #f5d9a8; background: #fffbf2; }

.stat-label { font-size: 13px; color: var(--ink-2); }

.stat-value {
  font-size: 30px;
  font-weight: 600;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.stat-warn .stat-value { color: #b45309; }

.stat-note { font-size: 12px; color: var(--ink-3); }

/* ---------- content blocks ---------- */

.block { margin-bottom: 32px; }

.block-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.block-head h2 { font-size: 17px; }

.block-note { font-size: 12px; color: var(--ink-3); }
.block-note code { color: var(--ink-2); }

.block-link { font-size: 13px; color: var(--green); }
.block-link:hover { color: var(--green-d); }

/* minmax(0,…) rather than 1fr: the track's auto minimum would otherwise be the
   table's min-content, widening the column instead of letting .tbl-scroll scroll */
.cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: 32px; }

.empty {
  border: 1px dashed var(--line-3);
  border-radius: var(--r);
  padding: 28px;
  text-align: center;
  font-size: 14px;
  color: var(--ink-3);
  background: var(--tint);
}

/* ---------- api keys ---------- */

.keys {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 14px;
}

.key {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  padding: 18px 20px;
}

.key-off { opacity: .6; }

.key-top {
  display: flex;
  align-items: center;
  gap: 10px 14px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.key-id {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  min-width: 0;
}

.key-name { font-size: 15px; font-weight: 500; }

.badge-off { background: #f1f3f5; color: var(--ink-2); }
.badge-warn { background: #fef3c7; color: #92400e; }

.key-val {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--tint);
  padding: 8px 10px;
}

.key-text {
  flex: 1;
  min-width: 0;
  font-size: 12px;
  overflow-wrap: anywhere;
  color: var(--ink);
}

.key-btn {
  flex: none;
  border: 1px solid var(--line-3);
  border-radius: 999px;
  background: #fff;
  color: var(--ink-2);
  font-family: inherit;
  font-size: 11px;
  padding: 3px 11px;
  cursor: pointer;
  transition: background-color .12s ease, color .12s ease, border-color .12s ease;
}

.key-btn:hover { color: var(--green-d); border-color: #c7d9d0; background: var(--tint-2); }
.key-btn.ok { background: var(--green); border-color: var(--green); color: #fff; }

.key-btn-danger:hover { color: #a33a3a; border-color: #e8c4c4; background: #fef4f4; }

/* Per-image pricing cell on the pricing table: one inline tier list instead
   of four per-token columns. */
.tbl-price td.img-tier { white-space: nowrap; font-size: 13px; }
.tbl-price td.img-tier .sep { color: var(--ink-3); margin: 0 6px; }

.key-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin-top: 12px;
  font-size: 12px;
  color: var(--ink-3);
}

.key-meta code { color: var(--ink-2); }

/* A per-key cap is invisible until it bites, so the two states that actually
   break requests get colour rather than another grey line of metadata. */
.key-meta .key-bad { color: #b42318; font-weight: 500; }
.key-meta .key-warn { color: #b45309; font-weight: 500; }

.key-alert {
  margin: 10px 0 0;
  padding: 9px 12px;
  border: 1px solid #f5d9a8;
  border-radius: var(--r-sm);
  background: #fffbf2;
  font-size: 12.5px;
  line-height: 1.7;
  color: #92400e;
}

/* ---------- usage bars ---------- */

.bars { display: grid; gap: 16px; }

.bar-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
}

.bar-val { font-variant-numeric: tabular-nums; font-weight: 500; }

.bar-track {
  height: 6px;
  margin-top: 7px;
  border-radius: 999px;
  background: #eef1f0;
  overflow: hidden;
}

.bar-fill {
  height: 100%;
  border-radius: 999px;
  background: var(--green);
}

.bar-foot { margin-top: 6px; font-size: 12px; color: var(--ink-3); }

.tbl-tight th, .tbl-tight td { padding: 10px 16px; }
.nowrap { white-space: nowrap; }

/* ---------- alerts ---------- */

.alert {
  border-radius: var(--r-sm);
  padding: 12px 16px;
  font-size: 14px;
  margin-bottom: 20px;
}

.alert-bad {
  border: 1px solid #f3c7c7;
  background: #fef4f4;
  color: #a33a3a;
}

.alert-good {
  border: 1px solid #c3e0d1;
  background: var(--tint-2);
  color: var(--green-d);
}

.hint {
  margin-bottom: 20px;
  font-size: 13px;
  line-height: 1.8;
  color: var(--ink-3);
}

.panel {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  padding: 22px;
}

.block-top { margin-top: 8px; }

/* ---------- keys page ---------- */

.keys-wide { grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); }

.key-new {
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(4, 120, 87, .08);
}

/* Card actions sit with the name they act on, in the same pill style as
   显示/复制 — they're secondary to the key itself and shouldn't outweigh it. */
.key-acts {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
  margin-left: auto;
}

/* Opened on demand by the 重命名 button; rendered open when JS is off. */
.key-rename {
  display: flex;
  gap: 6px;
  margin-bottom: 12px;
}

.key-rename .input { flex: 1; min-width: 0; }

/* A class selector outranks the UA stylesheet's [hidden], so restate it. */
.key-rename[hidden] { display: none; }

.btn-sm { padding: 6px 12px; font-size: 13px; }

.btn-danger { color: #a33a3a; }
.btn-danger:hover { color: #8b2f2f; border-color: #e8c4c4; background: #fef4f4; }

.input-sm { padding: 7px 11px; font-size: 13px; }

.row-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: #fff;
  padding: 20px 22px;
}

.row-form .field { flex: 1; min-width: 180px; }

/* Key management borrows the overview dashboard: same topline, same panel
   chrome, restrained rectangular controls, and consistently aligned columns. */
.app[data-page="keys"] { padding-bottom: 24px; }
.keys-head { align-items: center; margin-bottom: 16px; }
.keys-topline { margin-bottom: 12px; }
.keys-topline .dash-greeting { font-size: 23px; }
.keys-endpoint {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 48px;
  margin-bottom: 16px;
  border: 1px solid #e5e7eb;
  border-radius: 12px;
  background: #fff;
  padding: 8px 14px;
}
.keys-endpoint-title {
  color: #5f6368;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.keys-endpoint code {
  overflow: hidden;
  min-width: 0;
  color: #165dff;
  font-size: 13.5px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.keys-endpoint .key-btn {
  flex: none;
  border: 1px solid #d7e0ea;
  border-radius: 6px;
  background: #fff;
  color: #2563eb;
}
.keys-endpoint .key-btn:hover { border-color: #b9c7dc; background: #f5f8ff; }
@media (max-width: 640px) {
  /* Tighter gaps and a slightly smaller code face keep the default
     https://api.<domain> on one line at 360–412px; a longer URL still wraps
     instead of overflowing. */
  .keys-endpoint { gap: 8px; padding: 8px 10px; }
  .keys-endpoint code { font-size: 12.5px; white-space: normal; overflow-wrap: anywhere; }
}
@media (max-width: 380px) {
  .keys-endpoint code { font-size: 12px; }
}
.keys-topline-note {
  overflow: hidden;
  color: #8b9095;
  font-size: 13px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 899.98px) {
  .keys-topline-note { display: none; }
  .keys-panel .dash-panel-head { flex-direction: row; align-items: center; }
}
.key-create-open { min-width: 96px; }
.key-modal {
  width: min(480px, calc(100vw - 32px));
  border: 0;
  border-radius: 15px;
  padding: 0;
  background: #fff;
  color: var(--ink);
  box-shadow: 0 24px 64px rgba(15, 23, 42, .22);
}
.key-modal::backdrop { background: rgba(15, 23, 42, .44); backdrop-filter: blur(2px); }
.key-modal-head {
  display: flex;
  min-height: 76px;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid #eceef0;
  padding: 0 22px;
}
.key-modal-head h2 { margin-top: 2px; font-size: 18px; }
.key-modal-head .eyebrow { margin: 0; }
.key-modal-close {
  display: grid;
  width: 34px;
  height: 34px;
  place-items: center;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: #7a7f84;
  font-size: 24px;
  cursor: pointer;
}
.key-modal-close:hover { background: #f3f4f6; color: #1f2328; }
.key-modal-body { display: grid; gap: 16px; padding: 22px; }
.key-modal-body .field { display: grid; gap: 7px; }
.key-modal-body .block-note { margin: 0; color: #7a7f84; font-size: 12px; }
.key-modal-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  border-top: 1px solid #eceef0;
  padding: 14px 22px;
  background: #fafbfc;
}

.keys-panel {
  display: block;
  border: 1px solid #e5e7eb;
  border-radius: 15px;
  background: #fff;
  overflow: hidden;
}
.keys-panel .dash-panel-head small { color: #8b9095; font-size: 11px; font-weight: 400; }
.keys-toolbar {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) 150px 150px auto auto;
  align-items: center;
  gap: 9px;
  min-height: 64px;
  border-bottom: 1px solid #eceef0;
  padding: 12px 15px;
}
.keys-toolbar .input { width: 100%; background-color: #fff; }
.keys-reset { padding: 7px 5px; color: #7a7f84; font-size: 13px; }
.keys-reset:hover { color: #2563eb; }
.keys-table-wrap { min-width: 0; background: #fff; overflow: visible; }
.keys-table { width: 100%; max-width: 100%; table-layout: fixed; border: 0; font-size: 12px; }
.keys-table th {
  height: 43px;
  padding: 0 12px;
  background: #fff;
  color: #777d83;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .02em;
  text-align: left;
}
.keys-table td { height: 72px; padding: 11px 12px; vertical-align: middle; }
.keys-table tbody tr:hover { background: #fafbfc; }
/* Tabular figures keep dates, counts, and amounts on a shared vertical rhythm,
   the same way the overview cards line their numbers up. */
.key-date, .key-expiry, .quota-line, .usage-link, .keys-table td:nth-child(5) {
  font-variant-numeric: tabular-nums;
}
.keys-table th:nth-child(1) { width: 16%; }
.keys-table th:nth-child(2) { width: 30%; }
.keys-table th:nth-child(3) { width: 14%; }
.keys-table th:nth-child(4) { width: 18%; }
.keys-table th:nth-child(5) { width: 12%; }
.keys-table th:nth-child(6) { width: 150px; }
.keys-table .key-name {
  display: block;
  overflow: hidden;
  margin-bottom: 7px;
  color: #31353a;
  font-size: 13px;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.key-meta-line { display: flex; min-width: 0; align-items: center; gap: 9px; color: #7a7f84; font-size: 11px; }
.key-status { display: inline-flex; align-items: center; gap: 5px; color: #238636; }
.key-status::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.key-status.is-off { color: #9a5b56; }
.key-group { overflow: hidden; min-width: 0; text-overflow: ellipsis; white-space: nowrap; }
.keys-table .key-val {
  min-width: 0;
  gap: 4px;
  overflow: hidden;
  border-color: #e4e7ea;
  border-radius: 7px;
  padding: 6px 7px 6px 9px;
  background: #f8f9fa;
}
.keys-table .key-text { overflow: hidden; color: #4b5563; white-space: nowrap; text-overflow: ellipsis; }
.keys-panel .key-btn {
  border-color: transparent;
  border-radius: 5px;
  padding: 4px 7px;
  background: transparent;
  color: #66707a;
  font-size: 11px;
}
.keys-panel .key-btn:hover { border-color: #d9dcdf; background: #fff; color: #2563eb; }
.key-date, .key-expiry, .quota-line { display: block; white-space: nowrap; }
.key-expiry, .quota-line { overflow: hidden; margin-top: 5px; color: #8b9095; font-size: 11px; text-overflow: ellipsis; }
.usage-link { color: #2563eb; font-weight: 600; white-space: nowrap; }
.key-actions { display: flex; max-width: 100%; min-width: 0; align-items: center; gap: 2px; }
.key-actions .key-btn-danger { color: #9a5b56; }
.key-editor { position: relative; }
.key-editor > summary { list-style: none; }
.key-editor > summary::-webkit-details-marker { display: none; }
.key-editor:not([open]) > .key-edit-form { display: none; }
.key-edit-form {
  position: fixed;
  z-index: 30;
  right: 24px;
  top: 96px;
  width: min(520px, calc(100vw - 32px));
  max-height: calc(100dvh - 120px);
  overflow-y: auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  padding: 16px;
  /* Keep the top-right corner free for .key-edit-close: this panel covers the
     编辑 summary it was opened from, so the close button is not a duplicate. */
  padding-right: 52px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: #fff;
  box-shadow: 0 20px 55px rgba(15, 23, 42, .20);
}
.key-edit-form label { display: grid; gap: 5px; color: var(--ink-2); }
.key-edit-form label:has(> input[type="checkbox"]) { display: flex; align-items: center; }
.key-edit-form .edit-wide { grid-column: 1 / -1; }
.key-edit-form textarea { resize: vertical; }
.key-edit-close { position: absolute; top: 8px; right: 8px; }

/* Ordered counter list on the key forms. The number is the priority. */
.kg { display: grid; gap: 8px; min-width: 0; }
.kg-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; counter-reset: kg; }
.kg-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  min-height: 28px;
  padding: 0 4px 0 6px;
  border: 1px solid #dfe5e2;
  border-radius: 999px;
  background: #f7faf8;
  color: var(--ink-2);
  font-size: 12px;
  counter-increment: kg;
}
.kg-chip::before {
  content: counter(kg);
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #1f6f54;
  color: #fff;
  font-size: 10.5px;
  font-weight: 600;
}
.kg-name { overflow: hidden; min-width: 0; text-overflow: ellipsis; white-space: nowrap; }
.kg-x {
  display: inline-grid;
  place-items: center;
  width: 20px;
  height: 20px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: #8a9290;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
}
.kg-x:hover, .kg-x:focus-visible { background: #e9eeec; color: #b42318; }
.kg-add { justify-self: start; width: auto; min-width: 160px; }
.kg-empty { margin: 0; color: #b42318; font-size: 12px; }
.kg-overlap { margin: 0; color: #8a5a00; font-size: 12px; line-height: 1.5; }
.kg-field { display: grid; gap: 5px; color: var(--ink-2); }
.key-group-multi { color: #1f6f54; }

.usage-estimated {
  margin-left: 5px;
  color: #b45309;
  font-size: 9px;
  font-weight: 500;
}

@media (max-width: 1279px) {
  .keys-toolbar { grid-template-columns: minmax(220px, 1fr) 140px 140px auto auto; }
  .keys-table-wrap { border: 0; background: transparent; }
  .keys-table { display: block; min-width: 0; }
  .keys-table thead { display: none; }
  .keys-table tbody { display: grid; gap: 12px; }
  .keys-table tr {
    position: relative;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px 14px;
    padding: 16px;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: #fff;
  }
  .keys-table td {
    display: block;
    width: auto !important;
    padding: 0;
    border: 0;
    text-align: left !important;
    min-width: 0;
  }
  .keys-table td::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 4px;
    color: var(--ink-3);
    font-size: 10px;
    text-transform: uppercase;
  }
  .keys-table td:nth-child(1),
  .keys-table td:nth-child(2),
  .keys-table td:last-child { grid-column: 1 / -1; }
  .keys-table .key-val { min-width: 0; max-width: none; }
  .key-actions { min-width: 0; }
  .key-edit-form { inset: 10vh 16px auto; max-height: 80vh; grid-template-columns: 1fr; }
  .key-edit-form .edit-wide { grid-column: auto; }
}

@media (max-width: 760px) {
  .keys-toolbar { grid-template-columns: 1fr 1fr; }
  .keys-toolbar .input[type="search"] { grid-column: 1 / -1; }
  .keys-toolbar .btn { width: 100%; }
  .keys-reset { text-align: center; }
}

@media (max-width: 520px) {
  .keys-head { align-items: flex-end; }
  .keys-panel { border: 0; border-radius: 0; background: transparent; overflow: visible; }
  .keys-toolbar { border: 1px solid #e5e7eb; border-radius: 12px; background: #fff; }
  .keys-table tbody { margin-top: 10px; }
  .key-modal-foot .btn { flex: 1; }
}

select.input {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%236b7280' stroke-width='1.4' d='M3 4.5 6 7.5 9 4.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 12px;
  padding-right: 30px;
  cursor: pointer;
}

/* ---------- logs page ---------- */

/* The usage log reproduces New API's own usage-log page, which the users know
   from the legacy console. Colours, sizes and radii below were read off that
   page rendered in Chrome (New API web/, default theme) rather than guessed,
   and are scoped to this page: the rest of the console keeps BuyToken's. */
.logs-page {
  --lg-fg: #0a0a0a;
  --lg-muted: #606060;
  --lg-faint: rgba(96, 96, 96, .6);
  --lg-fainter: rgba(96, 96, 96, .4);
  --lg-line: #e8e8e8;
  --lg-hover: #f5f5f5;
  --lg-primary: var(--green);
  --lg-primary-d: var(--green-d);
  --lg-ok: #009767;
  --lg-warn: #cd8900;
  --lg-bad: #e40014;
  --lg-info: #0084cc;
  min-width: 0;
  color: var(--lg-fg);
  /* New API asks for "Public Sans", sans-serif, but its bundle registers the
     face as "Public Sans Variable", so what the browser actually draws is the
     generic sans-serif: Helvetica on macOS, Arial on Windows. That narrower
     face is what lets its eight columns fit; SF at the same 13px runs ~15%
     wider and clipped token and model names. */
  font-family: Helvetica, Arial, "PingFang SC", "Microsoft YaHei", sans-serif;
}
.app[data-page="logs"] { padding-bottom: 16px; }

/* One filter card above the table: the range button and text filters on the
   first row, totals and actions on the second. The range is typed rather than
   picked from fixed windows, so "what happened between these two hours" is
   answerable without repeating totals already on the dashboard. */
.logs-head {
  position: relative;
  z-index: 5;
  margin-bottom: 12px;
  padding: 12px;
  border: 1px solid var(--lg-line);
  border-radius: 16px;
  background: rgba(255, 255, 255, .5);
}

.logs-filter { display: block; }
/* Every field is New API's 32px rounded input. */
.lf-field {
  display: flex;
  align-items: center;
  width: 100%;
  min-width: 0;
  height: 32px;
  margin: 0;
  padding: 4px 10px;
  border: 1px solid var(--lg-line);
  border-radius: 16px;
  background: transparent;
  box-shadow: none;
  color: var(--lg-fg);
  font: inherit;
  font-size: 14px;
  line-height: 20px;
  outline: none;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.lf-field::placeholder { color: var(--lg-muted); opacity: 1; }
.lf-field:focus-visible {
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(4, 120, 87, .16);
}

.lf-icon {
  width: 16px;
  height: 16px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  color: var(--lg-muted);
}

/* The range is a button that opens the two time fields, like New API's
   compact range picker. A <details> keeps it working without script; site.js
   only closes it on an outside click and fills in the quick ranges. */
.lf-range { position: relative; min-width: 0; }
.lf-range-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lf-range-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 30;
  width: min(520px, calc(100vw - 32px));
  padding: 12px;
  border: 1px solid var(--lg-line);
  border-radius: 16px;
  background: #fff;
  box-shadow: 0 12px 32px rgba(15, 23, 42, .12);
}
.lf-range-fields {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: end;
  gap: 8px;
}
.lf-range-field { display: grid; gap: 6px; min-width: 0; }
.lf-range-field > span { color: var(--lg-muted); font-size: 12px; line-height: 16px; }
.lf-range-field .lf-field { font-variant-numeric: tabular-nums; }
.lf-dash { padding-bottom: 7px; color: var(--lg-muted); font-size: 12px; }
.lf-quick {
  flex: 1 1 0;
  height: 28px;
  padding: 0 8px;
  border: 1px solid var(--lg-line);
  border-radius: 12.8px;
  background: #fff;
  color: var(--lg-fg);
  font: inherit;
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
}
.lf-quick:hover { background: var(--lg-hover); }
/* The date-time picker behind the two range fields. The browser's own
   datetime-local popup has no way to say "done", so the fields are a hidden
   input plus this button and picker, which end in 取消 / 确认. */
.lf-dt-trigger { display: flex; align-items: center; width: 100%; text-align: left; cursor: pointer; font-variant-numeric: tabular-nums; }
.dt-pop {
  position: absolute;
  z-index: 40;
  width: 292px;
  padding: 12px;
  border: 1px solid var(--lg-line);
  border-radius: 14px;
  background: #fff;
  box-shadow: 0 14px 36px rgba(15, 23, 42, .18);
  color: var(--lg-fg);
  font-size: 13px;
}
.dt-pop[hidden] { display: none; }
.dt-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.dt-title { font-size: 14px; font-weight: 600; }
.dt-nav {
  width: 28px; height: 28px; padding: 0;
  border: 1px solid var(--lg-line); border-radius: 8px;
  background: #fff; color: var(--lg-fg); font: inherit; font-size: 16px; line-height: 1; cursor: pointer;
}
.dt-nav:hover { background: var(--lg-hover); }
.dt-week, .dt-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; }
.dt-week span { padding: 4px 0; color: var(--lg-muted); font-size: 12px; }
.dt-day {
  height: 32px; padding: 0;
  border: 0; border-radius: 8px;
  background: transparent; color: var(--lg-fg); font: inherit; cursor: pointer;
}
.dt-day:hover { background: var(--lg-hover); }
.dt-day.is-other { color: var(--lg-muted); opacity: .55; }
.dt-day.is-today { box-shadow: inset 0 0 0 1px var(--lg-primary); }
.dt-day.is-selected { background: var(--lg-primary); color: #fff; opacity: 1; box-shadow: none; }
.dt-time { display: flex; align-items: center; gap: 6px; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--lg-line); }
.dt-time-label { margin-right: auto; color: var(--lg-muted); font-size: 12px; }
.dt-time select {
  height: 30px; padding: 0 8px;
  border: 1px solid var(--lg-line); border-radius: 8px;
  background: #fff; color: var(--lg-fg); font: inherit; font-variant-numeric: tabular-nums;
}
.dt-foot { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
.dt-spacer { flex: 1; }
.dt-link { padding: 0; border: 0; background: none; color: var(--lg-primary-d); font: inherit; cursor: pointer; }
.dt-link:hover { text-decoration: underline; }

.lf-combo-icon,
.lf-select-icon {
  position: absolute;
  top: 50%;
  right: 10px;
  transform: translateY(-50%);
  pointer-events: none;
}

.lf-actions {
  display: flex;
  margin-left: auto;
  justify-content: flex-end;
  gap: 8px;
}
.lf-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 32px;
  padding: 0 10px;
  border: 1px solid var(--lg-line);
  border-radius: 16px;
  background: #fff;
  color: var(--lg-fg);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .12s ease, color .12s ease;
}
.lf-btn:hover { background: var(--lg-hover); color: var(--lg-fg); }
.lf-btn-primary { border-color: transparent; background: var(--lg-primary); color: #fff; }
.lf-btn-primary:hover { background: var(--lg-primary-d); color: #fff; }

/* ---------- usage log header: stats cards + toolbar ---------- */
.logs-page {
  --lf-h: 32px;                       /* 控件高度，与 .lf-btn / 分页保持一致 */
  --lf-note: #6b7177;                 /* 次要文字：白底 4.9:1，tint 底 4.7:1 */
  --lf-soft: #f0f0f0;                 /* 行内分隔线，比 --lg-line 更轻 */
  --lf-cap: #fafafa;                  /* 标签格底色，与表头 #fbfbfb 同一档 */
  --lf-set-line: #b8e3cd;             /* 「已选中」描边 */
  --lf-ring: 0 0 0 3px rgba(4, 120, 87, .16);
  --lf-focus: 2px solid rgba(4, 120, 87, .6);
}

.lh-sr {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- 标题行：与「令牌管理」同一套 .dash-topline ---------- */
.logs-topline { margin-bottom: 12px; }
.logs-topline .dash-greeting { font-size: 23px; }

/* ---------- 统计卡 ---------- */
.logs-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 12px;
}
.lstat {
  min-width: 0;
  padding: 14px 16px;
  border: 1px solid var(--lg-line);
  border-radius: 16px;
  background: #fff;
}
.lstat-label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: var(--lg-muted);
  font-size: 13px;
  font-weight: 500;
  line-height: 24px;
}
.lstat-ico {
  display: grid;
  place-items: center;
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: 8px;
  background: var(--tint-2);
  color: var(--green);
}
.lstat-ico svg {
  width: 14px; height: 14px;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.lstat-main {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 32px;
  margin-top: 6px;
}
.lstat-value {
  margin: 0;
  color: var(--lg-fg);
  font-size: 28px;
  font-weight: 700;
  line-height: 32px;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.lstat-value .cur {
  margin-right: 2px;
  font-size: .64em;
  font-weight: 600;
  letter-spacing: 0;
  vertical-align: .2em;
}
.lstat-foot,
.lstat-split {
  margin: 4px 0 0;
  min-height: 16px;
  color: var(--lf-note);
  font-size: 12px;
  line-height: 16px;
}

/* 总消费：全页唯一的强调色卡 —— 绿字 + 实心绿图标格 + 微绿底 */
.lstat-cost { border-color: #cfe6da; background: var(--tint); }
.lstat-cost .lstat-ico { background: var(--green); color: #fff; }
.lstat-cost .lstat-value { color: var(--green); }

/* 总 Token：数字右侧一条占比条，下面一行三段数字（输入 + 输出 + 缓存命中 = 总数） */
.lstat-meter {
  display: flex;
  flex: 1 1 auto;
  gap: 2px;
  min-width: 48px;
  height: 8px;
  margin: 0;
}
.lstat-meter i {
  display: block;
  flex: 1 1 0;                         /* flex-grow 内联为各段 token 数，服务端直接输出 */
  min-width: 4px;                      /* 0.45M 这种极小段也留一道可见的细线 */
  border-radius: 4px;
}
.lstat-split {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 14px;
}
.lstat-split span { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.lstat-split b { color: var(--lg-fg); font-weight: 600; font-variant-numeric: tabular-nums; }
.lstat .d { width: 8px; height: 8px; flex: none; border-radius: 50%; }
.c-in { background: var(--green); }
.c-out { background: var(--green-l); }
.c-cache { background: #a9d9c1; }

/* 空数据：数字退成灰，占比条换成一条空轨道 */
.lstat.is-empty .lstat-value { color: #8b9095; }
.lstat.is-empty .lstat-split b { color: var(--lf-note); font-weight: 500; }   /* 12px 小字要 ≥4.5:1 */
.lstat.is-empty .lstat-meter i { background: #eceeef; }
.lstat.is-empty .lstat-meter i:not(:first-child) { display: none; }
.lstat.is-empty .d { background: #d5d9dc; }
.lstat-cost.is-empty { background: #fff; border-color: var(--lg-line); }
.lstat-cost.is-empty .lstat-ico { background: var(--lf-cap); color: #8b9095; }
.lstat-cost.is-empty .lstat-value { color: #8b9095; }

/* 加载中（数据由异步请求补上时）：骨架块占住和真数据同样的高度，不跳 */
.sk {
  display: block;
  border-radius: 6px;
  background: linear-gradient(90deg, #f1f2f3 0%, #e6e8ea 45%, #f1f2f3 90%);
  background-size: 220% 100%;
  animation: lstat-shimmer 1.4s linear infinite;
}
.sk-value { width: 112px; height: 24px; }
.sk-meter { flex: 1 1 auto; min-width: 48px; height: 8px; border-radius: 4px; }
.sk-foot { width: 100%; max-width: 168px; height: 10px; margin: 3px 0; }
.sk-foot.sm { max-width: 88px; }
@keyframes lstat-shimmer { to { background-position: -220% 0; } }
@media (prefers-reduced-motion: reduce) { .sk { animation: none; } }

/* ---------- 工具栏：一张卡，两行，每行以「标签格 | 控件」开头 ---------- */
.logs-head { padding: 12px 16px; background: #fff; }   /* 左右 16px = 统计卡内边距，控件左缘与卡片文字左缘对齐 */
.lf-row { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 12px; min-width: 0; }
.lf-row + .lf-row { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--lf-soft); }

/* 标签格 + 控件格 的胶囊；时间条和三个下拉共用 */
.lf-group {
  display: flex;
  align-items: stretch;
  min-width: 0;
  height: var(--lf-h);
  border: 1px solid var(--lg-line);
  border-radius: 16px;
  background: #fff;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.lf-group:hover,
.lf-group.is-hover { border-color: #d2d6d9; }
.lf-cap {
  display: flex;
  align-items: center;
  flex: none;
  gap: 6px;
  padding: 0 10px 0 12px;
  border-right: 1px solid var(--lg-line);
  border-radius: 15px 0 0 15px;
  background: var(--lf-cap);
  color: var(--lg-muted);
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  cursor: default;
}
.lf-cap .lf-icon { width: 14px; height: 14px; }

/* 分段时间条 */
.lf-seg { display: flex; align-items: center; gap: 2px; padding: 0 3px; }
.lf-seg-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  height: 24px;
  margin: 0;
  padding: 0 10px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--lg-muted);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  line-height: 24px;
  white-space: nowrap;
  list-style: none;
  cursor: pointer;
  transition: background-color .12s ease, color .12s ease, box-shadow .12s ease;
}
.lf-seg-btn:hover,
.lf-seg-btn.is-hover { background: var(--lg-hover); color: var(--lg-fg); }
.lf-seg-btn:focus-visible,
.lf-seg-btn.is-focus { outline: var(--lf-focus); outline-offset: 1px; }
.lf-seg-btn.on {
  background: var(--tint-2);
  color: var(--green-d);
  font-weight: 600;
  box-shadow: inset 0 0 0 1px var(--lf-set-line);
}
.lf-seg .lf-range { position: static; display: block; }
.lf-seg .lf-range-trigger::-webkit-details-marker { display: none; }
.lf-seg .lf-range-trigger::marker { content: ""; }
.logs-head .lf-range[open] > .lf-range-trigger,
.logs-head .lf-range-trigger.is-open {
  background: #fff;
  color: var(--green-d);
  box-shadow: inset 0 0 0 1px var(--green), 0 0 0 3px rgba(4, 120, 87, .14);
}
.logs-head .lf-range[open] > .lf-range-trigger.on,
.logs-head .lf-range-trigger.is-open.on {
  background: var(--tint-2);
}
.lf-seg .lf-icon { width: 14px; height: 14px; color: currentColor; transition: transform .15s ease; }
.lf-range[open] .lf-range-chev { transform: rotate(180deg); }

/* 当前范围的真实起止时间 —— 近 24 小时是滚动的，所以必须写出来 */
.lf-span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  color: var(--lf-note);
  font-size: 12.5px;
  line-height: 16px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.lf-span .lf-icon { width: 14px; height: 14px; color: #8b9095; }
.lf-span .lf-range-text { overflow: visible; }

/* 展开面板：8 个预设（最近 / 日历两组）+ 自定义起止 + 应用 */
.lf-range-pop {
  top: calc(100% + 8px);
  left: 0;
  width: min(468px, 100%);
  padding: 14px;
  border-radius: 16px;
  box-shadow: 0 16px 40px rgba(15, 23, 42, .14), 0 2px 6px rgba(15, 23, 42, .05);
}
.lf-pop-head { display: none; }
.lf-pop-sec { display: grid; grid-template-columns: 36px minmax(0, 1fr); align-items: center; gap: 10px; }
.lf-pop-sec + .lf-pop-sec { margin-top: 8px; }
.lf-pop-cap { color: var(--lf-note); font-size: 12px; line-height: 16px; }
.lf-pop-chips { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.lf-quick {
  flex: none;
  height: var(--lf-h);
  padding: 0 4px;
  border: 1px solid var(--lg-line);
  border-radius: 16px;
  background: #fff;
  color: var(--lg-fg);
  font-size: 13px;
  font-weight: 500;
  transition: background-color .12s ease, border-color .12s ease;
}
.lf-quick:hover,
.lf-quick.is-hover { background: var(--lg-hover); border-color: #d2d6d9; }
.lf-quick:focus-visible { outline: var(--lf-focus); outline-offset: 1px; }
.lf-quick.on {
  border-color: var(--lf-set-line);
  background: var(--tint-2);
  color: var(--green-d);
  font-weight: 600;
}
.lf-pop-custom {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--lf-soft);
}
.lf-pop-custom > .lf-pop-cap { display: block; margin-bottom: 8px; }
.lf-range-fields {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 14px minmax(0, 1fr) auto;
  align-items: end;
  gap: 8px;
}
.lf-range-field > span { color: var(--lf-note); font-size: 12px; line-height: 16px; }
.lf-range-fields .lf-dash { padding: 0; line-height: var(--lf-h); text-align: center; color: #8b9095; }
.lf-range-fields .lf-dt-trigger {
  gap: 6px;
  padding: 0 10px;
  border-radius: 16px;
  font-size: 13px;
  background: #fff;
}
.lf-range-fields .lf-dt-trigger:hover { border-color: #d2d6d9; }
.lf-range-fields .lf-dt-trigger:focus-visible,
.lf-range-fields .lf-dt-trigger.is-focus { border-color: var(--green); box-shadow: var(--lf-ring); }
.lf-range-fields .lf-dt-trigger .lf-icon { margin-left: auto; width: 14px; height: 14px; }

/* ---------- 下拉：标签格 + 原生 <select> ---------- */
.lf-sel { flex: 1 1 190px; }   /* 窄到放不下时，按钮换到下一行靠右，下拉不再被挤成 "cc…" */
.lf-sel-ctl { position: relative; display: flex; flex: 1 1 auto; min-width: 0; }
.lf-sel select {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  height: 100%;
  margin: 0;
  padding: 0 32px 0 12px;
  border: 0;
  border-radius: 0 15px 15px 0;
  background: transparent;
  color: var(--lg-muted);
  font: inherit;
  font-size: 14px;
  font-weight: 400;
  line-height: 20px;
  text-overflow: ellipsis;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  outline: none;
}
.lf-sel .lf-combo-icon { right: 11px; width: 14px; height: 14px; }
.lf-sel:focus-within,
.lf-sel.is-focus { border-color: var(--green); box-shadow: var(--lf-ring); }

/* 已选中：描边、标签格、值全部转绿，一眼看出「现在带着条件」 */
.lf-sel.is-set,
.lf-sel:has(option:checked:not([value=""])) { border-color: var(--lf-set-line); }
.lf-sel.is-set .lf-cap,
.lf-sel:has(option:checked:not([value=""])) .lf-cap {
  border-right-color: var(--lf-set-line);
  background: var(--tint-2);
  color: var(--green-d);
}
.lf-sel.is-set select,
.lf-sel:has(option:checked:not([value=""])) select { color: var(--green-d); font-weight: 600; }
.lf-sel.is-set .lf-combo-icon,
.lf-sel:has(option:checked:not([value=""])) .lf-combo-icon { color: var(--green-d); }
.lf-sel.is-set:focus-within,
.lf-sel:has(option:checked:not([value=""])):focus-within { border-color: var(--green); }

/* ---------- 按钮：32px 胶囊，查询用站点绿 ---------- */
.logs-head .lf-actions { flex: none; margin-left: auto; gap: 8px; }
.logs-head .lf-btn {
  gap: 6px;
  padding: 0 14px;
  height: var(--lf-h);
  text-decoration: none;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}
.logs-head .lf-btn .lf-icon { width: 14px; height: 14px; color: currentColor; }
.logs-head .lf-btn:focus-visible,
.logs-head .lf-btn.is-focus { outline: var(--lf-focus); outline-offset: 2px; }
.logs-head .lf-btn-primary { background: var(--green); padding: 0 18px; }
.logs-head .lf-btn-primary:hover,
.logs-head .lf-btn-primary.is-hover { background: var(--green-d); }
/* 重置：没有条件时是灰的、不可点；带着条件时变成可用态 */
.logs-head .lf-reset { color: var(--green-d); border-color: var(--lf-set-line); }
.logs-head .lf-reset:hover,
.logs-head .lf-reset.is-hover { background: var(--tint-2); color: var(--green-d); }
.logs-head .lf-reset[aria-disabled="true"] {
  border-color: var(--lf-soft);
  background: var(--lf-cap);
  color: #a3a8ad;
  cursor: default;
  pointer-events: none;
}

/* ---------- 手机（沿用站点 logs 页的 700px 断点） ---------- */
@media (max-width: 700px) {
  .logs-page { --lf-h: 40px; }              /* 触控目标 */

  .logs-stats { grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 8px; }
  .lstat { padding: 12px 14px; }
  .lstat-req { order: 1; }
  .lstat-cost { order: 2; }
  .lstat-tok { order: 3; grid-column: 1 / -1; }
  .lstat-value { font-size: 24px; line-height: 28px; }
  .lstat-main { min-height: 28px; margin-top: 4px; }

  .logs-head { padding: 12px 14px; }
  .lf-row { flex-wrap: wrap; gap: 8px; }
  .lf-row + .lf-row { margin-top: 12px; padding-top: 12px; }

  /* 标签格变成控件上方的小标题，控件独占整行宽度 */
  .lf-group { flex-direction: column; height: auto; border: 0; border-radius: 0; background: none; box-shadow: none !important; }
  .lf-group:hover { border-color: transparent; }
  .lf-cap { padding: 0 0 4px; border: 0; border-radius: 0; background: none !important; font-size: 12px; line-height: 16px; color: var(--lf-note) !important; }
  /* 手机：「时间范围」标签和起止时间同一行，分段条整行在下 */
  .lf-row-time { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px 8px; align-items: center; }
  .lf-time { display: contents; }
  .lf-time > .lf-cap { grid-column: 1; grid-row: 1; padding: 0; }
  .lf-time > .lf-seg { grid-column: 1 / -1; grid-row: 2; }
  .lf-row-time > .lf-span { grid-column: 2; grid-row: 1; justify-self: end; width: auto; }
  .lf-seg {
    height: var(--lf-h); padding: 0 4px; gap: 2px;
    border: 1px solid var(--lg-line); border-radius: 20px; background: #fff;
  }
  .lf-seg-btn { flex: 1 1 auto; height: 32px; padding: 0 4px; border-radius: 16px; line-height: 32px; font-size: 13px; }
  .lf-seg .lf-range { flex: 1 1 auto; }
  .lf-seg .lf-range-trigger { width: 100%; }
  .lf-span { font-size: 12px; }

  .lf-row-filters { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 8px; }
  .lf-sel { flex: none; min-width: 0; }
  .lf-sel-ctl { height: var(--lf-h); border: 1px solid var(--lg-line); border-radius: 20px; background: #fff; }
  .lf-sel select { border-radius: 20px; font-size: 16px; padding-left: 14px; }   /* 16px：iOS 聚焦不缩放 */
  .lf-sel:focus-within,
  .lf-sel.is-focus { border-color: transparent; box-shadow: none; }
  .lf-sel:focus-within .lf-sel-ctl,
  .lf-sel.is-focus .lf-sel-ctl { border-color: var(--green); box-shadow: var(--lf-ring); }
  .lf-sel.is-set,
  .lf-sel:has(option:checked:not([value=""])) { border-color: transparent; }
  .lf-sel.is-set .lf-sel-ctl,
  .lf-sel:has(option:checked:not([value=""])) .lf-sel-ctl { border-color: var(--lf-set-line); background: var(--tint-2); }
  .lf-sel.is-set .lf-cap,
  .lf-sel:has(option:checked:not([value=""])) .lf-cap { color: var(--green-d) !important; }
  .lf-sel.is-set:focus-within .lf-sel-ctl,
  .lf-sel:has(option:checked:not([value=""])):focus-within .lf-sel-ctl { border-color: var(--green); }
  .lf-sel .lf-combo-icon { right: 14px; }
  .logs-head .lf-actions { display: flex; align-self: end; }
  .logs-head .lf-actions .lf-btn { flex: 1 1 0; justify-content: center; border-radius: 20px; padding: 0 8px; }

  /* 展开面板：手机上做成底部抽屉（纯 CSS，fixed + ::before 遮罩），
     不会再被折叠线以下的内容顶到屏幕外；点遮罩 / × / Esc 关闭（site.js 已有 closeDetailsPopovers，
     遮罩点击只需多认一个 details 自身作为 target，见 NOTES） */
  /* 抽屉打开时，把工具栏的层叠上下文抬到顶栏(30)之上，遮罩才会盖住顶栏；
     只在打开时抬，否则滚动时工具栏会盖到粘性顶栏上面 */
  .logs-head:has(.lf-range[open]) { z-index: 35; }
  .lf-range[open]::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 29;
    background: rgba(15, 23, 42, .4);
  }
  .lf-range-pop {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 31;
    width: auto;
    max-height: min(86dvh, 560px);
    overflow: auto;
    padding: 8px 16px calc(16px + env(safe-area-inset-bottom, 0px));
    border: 0;
    border-radius: 20px 20px 0 0;
    box-shadow: 0 -12px 40px rgba(15, 23, 42, .22);
  }
  .lf-range-pop::before {
    content: "";
    display: block;
    width: 36px;
    height: 4px;
    margin: 0 auto 8px;
    border-radius: 2px;
    background: #d6d9dc;
  }
  .lf-pop-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
  .lf-pop-head strong { font-size: 16px; font-weight: 600; }
  .lf-pop-close {
    display: grid; place-items: center;
    width: 32px; height: 32px; padding: 0;
    border: 0; border-radius: 50%;
    background: var(--lg-hover); color: var(--lg-muted);
    font: inherit; font-size: 20px; line-height: 1; cursor: pointer;
  }
  .lf-pop-close:focus-visible { outline: var(--lf-focus); outline-offset: 2px; }
  .lf-pop-sec { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .lf-pop-chips { gap: 8px; }
  .lf-quick { height: 36px; border-radius: 18px; font-size: 13px; }
  .lf-pop-custom { margin-top: 16px; padding-top: 14px; }
  .lf-range-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .lf-range-fields .lf-dash { display: none; }
  .lf-range-fields .lf-dt-trigger { height: var(--lf-h); border-radius: 20px; padding: 0 12px; font-size: 14px; }
  .lf-range-fields .lf-btn { grid-column: 1 / -1; width: 100%; height: var(--lf-h); border-radius: 20px; justify-content: center; margin-top: 4px; }
}

/* Single-key scope (?token_id=): the key drop-down is replaced by a read-only chip. */
.lf-scope { cursor: default; border-color: var(--lf-set-line); }
.lf-scope .lf-cap { border-right-color: var(--lf-set-line); background: var(--tint-2); color: var(--green-d); }
.lf-scope-val { display: flex; align-items: center; padding: 0 14px 0 12px; color: var(--green-d); font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums; }

.seg {
  display: inline-flex;
  border: 1px solid var(--line-3);
  border-radius: var(--r-sm);
  background: #fff;
  overflow: hidden;
}

.seg-btn {
  display: block;
  border: 0;
  border-right: 1px solid var(--line-3);
  background: #fff;
  color: var(--ink-2);
  font-family: inherit;
  font-size: 13px;
  line-height: 1.3;
  padding: 7px 14px;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .12s ease, color .12s ease;
}

.seg-btn:last-child { border-right: 0; }
.seg-btn:hover { background: var(--tint); color: var(--ink); }
.seg-btn.on { background: var(--green); color: #fff; }

.cache-hit {
  color: var(--green-d);
  font-weight: 500;
}

/* The page itself stays still: rows scroll inside this card, while the column
   labels stay pinned at its top and the pager sits right under it. */
.logs-frame {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Content-sized but allowed to shrink: a short page ends the card at its last
   row with the pager right under it, as in New API; a long one fills the
   frame and scrolls. */
.logs-scroll {
  flex: 0 1 auto;
  min-width: 0;
  min-height: 0;
  overflow: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--lg-line);
  border-radius: 16px;
  background: #fff;
  transition: opacity .14s ease;
}

/* New API keeps the pager mounted while it loads another page. Only the rows
   soften briefly, so controls do not vanish or jump around during the request. */
.logs-frame.is-loading .logs-scroll { opacity: .48; }
.logs-frame.is-loading .logs-pager { cursor: progress; }
.logs-frame.is-loading .pager-total::after {
  content: "";
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-left: 8px;
  border: 2px solid #d4e9fa;
  border-top-color: var(--lg-primary);
  border-radius: 50%;
  vertical-align: -2px;
  animation: log-page-spin .65s linear infinite;
}

.logs-page-error {
  flex-basis: 100%;
  color: #b45309;
  font-size: 12px;
  text-align: right;
}

@keyframes log-page-spin { to { transform: rotate(360deg); } }

/* The frame has to end exactly at the viewport bottom, or the pager sits just
   below the fold: you scroll to click it, the click loads a new page at scroll
   top, and the bar appears to vanish until you scroll again. Sizing the frame
   as `100dvh - 196px` guessed the distance from the viewport top down to the
   frame, and the guess was 27px short — 75px once the filter row wrapped to two
   lines. Nothing here may assume that distance: the body takes the viewport
   height and each link in the chain hands the remainder down, so the frame
   ends where the padding does no matter how tall the header or filters grow. */
@media (min-width: 900px) {
  body:has(.app[data-page="logs"]) {
    height: 100dvh;
    /* auto rather than hidden: below the min-height floor the frame stops
       shrinking, and then the page still has to be able to scroll to the pager */
    overflow: auto;
  }

  /* `body > .app` ships flex: 1 0 auto; a shrink factor of 0 would let a
     hundred rows push the pager back off the bottom edge. */
  body:has(.app[data-page="logs"]) > .app { flex: 1 1 auto; min-height: 0; }

  /* Every other console page wants align-items: start. This grid row has to
     stretch instead, or the main column is only as tall as its content and the
     frame inherits no height to fill. */
  .app[data-page="logs"] { align-items: stretch; }
  .app[data-page="logs"] > .side { align-self: start; }

  .logs-page { display: flex; flex-direction: column; min-height: 0; }
  .logs-frame { flex: 1 1 auto; min-height: 300px; }
}

/* ---------- log table ---------- */

/* New API's table: a 40px header on a faint grey band, 60px rows, 13px medium
   text throughout, every cell vertically centred. Eight columns stay at a
   readable width; a narrower window scrolls the table sideways inside
   .logs-scroll instead of squeezing a column or folding rows into cards.
   `separate` rather than the shared `collapse` so the sticky header keeps its
   bottom rule while the rows scroll under it. */
.tbl.tbl-logs {
  table-layout: fixed;
  width: 100%;
  min-width: 1100px;
  border-collapse: separate;
  border-spacing: 0;
  color: var(--lg-fg);
  font-size: 13px;
  line-height: 1.43;
  font-variant-numeric: tabular-nums;
}

.tbl.tbl-logs th,
.tbl.tbl-logs td {
  padding: 8px;
  border-bottom: 1px solid var(--lg-line);
  text-align: left;
  white-space: nowrap;
  vertical-align: middle;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tbl.tbl-logs thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  height: 40px;
  padding: 0 8px;
  background: #fbfbfb;
  color: var(--lg-fg);
  font-size: 13px;
  font-weight: 500;
}

.tbl-logs .col-ts { width: 14%; }
.tbl-logs .col-key { width: 16%; }
.tbl-logs .col-model { width: 17%; }
.tbl-logs .col-stream { width: 7%; }
.tbl-logs .col-tokens { width: 13%; }
.tbl-logs .col-cost { width: 10%; }
.tbl-logs .col-lat { width: 10%; }
.tbl-logs .col-detail { width: 13%; }
/* English formulas ("Per image ¥0.11 / image", "multiplier 0.6 × ¥4.5")
   run longer than the Chinese. The time and cost columns have slack to give;
   token and model names do not. */
html[lang="en"] .tbl-logs .col-ts { width: 13%; }
html[lang="en"] .tbl-logs .col-cost { width: 9%; }
html[lang="en"] .tbl-logs .col-detail { width: 15%; }

.tbl.tbl-logs td { height: 60px; font-weight: 500; }
.tbl.tbl-logs tbody tr:last-child td { border-bottom: 0; }
.tbl.tbl-logs tbody tr:hover { background: none; }
.tbl.tbl-logs tbody tr:hover > td { background: #fafafa; }
/* New API tints error rows rose; ours are the unbilled / cut-short ones. */
.tbl.tbl-logs .log-row.is-abnormal > td { background: rgba(255, 241, 242, .45); }
.tbl.tbl-logs .log-row.is-abnormal:hover > td { background: rgba(255, 228, 230, .5); }

/* Two-line cells stack block children; the second line is quieter. */
.log-time { display: block; line-height: 17px; font-variant-numeric: tabular-nums; }
.log-sub {
  display: block;
  margin-top: 2px;
  overflow: hidden;
  color: var(--lg-faint);
  font-size: 13px;
  line-height: 16px;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.log-kind { margin-top: 0; }
.log-kind-tag {
  display: inline-flex;
  height: 20px;
  align-items: center;
  color: var(--lg-ok);
  font-size: 12px;
  font-weight: 500;
}
.log-kind-tag.is-warn { color: var(--lg-warn); }
/* A client cancel is not a fault: grey, no row tint. */
.log-kind-tag.is-neutral { color: var(--lg-muted); }

/* Token and model chips: New API's outlined 24px badge with an icon. */
.log-chip {
  display: inline-flex;
  max-width: 100%;
  height: 24px;
  align-items: center;
  gap: 6px;
  padding: 0 8px;
  border: 1px solid rgba(232, 232, 232, .6);
  border-radius: 12.8px;
  background: rgba(245, 245, 245, .3);
  color: var(--lg-fg);
  font-size: 13px;
  font-weight: 500;
  line-height: 13px;
  vertical-align: middle;
}
.log-chip-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 18px; }
.log-chip-icon {
  width: 14px;
  height: 14px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.log-model-icon { display: block; width: 18px; height: 18px; flex: none; }

.log-group-line { margin-top: 4px; line-height: 15px; }
.log-group-name { font-weight: 500; }
.log-ratio { margin-left: 3px; color: var(--lg-faint); font-variant-numeric: tabular-nums; }

/* Group and unknown-vendor model names take New API's hashed text colour
   (stringToColor → textColorMap); tagHue reproduces the hash. */
.log-hue-amber, .log-hue-orange, .log-hue-yellow { color: var(--lg-warn); }
.log-hue-blue, .log-hue-indigo { color: #4ca9ff; }
.log-hue-cyan, .log-hue-teal { color: #00a3aa; }
.log-hue-green { color: var(--lg-ok); }
.log-hue-grey { color: var(--lg-muted); }
.log-hue-light-blue { color: var(--lg-info); }
.log-hue-lime { color: #9095e8; }
.log-hue-pink { color: #20b46b; }
.log-hue-purple, .log-hue-violet { color: #d068d8; }
.log-hue-red { color: var(--lg-bad); }

.log-stream-label { display: block; color: var(--lg-muted); font-weight: 500; line-height: 16px; }
.log-stream-label.is-stream { color: var(--lg-info); }
.log-tps { padding: 0 2px; }

.log-token-pair { display: block; line-height: 17px; }
.log-cache > span { margin-left: 4px; }
.log-cache > span:first-child { margin-left: 0; }

.log-cost-badge {
  display: inline-flex;
  height: 24px;
  align-items: center;
  padding: 0 8px;
  border: 1px solid rgba(232, 232, 232, .8);
  border-radius: 12.8px;
  background: rgba(245, 245, 245, .6);
  color: var(--lg-fg);
  font-size: 13px;
  font-weight: 500;
  line-height: 13px;
  font-variant-numeric: tabular-nums;
}
.cost-zero { color: var(--lg-muted); font-weight: 500; }

/* Latency: a 4px bar beside the labels, split in two for a stream (first
   token on top, total below), each half coloured by how slow it was. */
.log-timing { display: flex; align-items: stretch; gap: 8px; }
.log-timing-bar {
  display: flex;
  width: 4px;
  min-height: 32px;
  flex: none;
  flex-direction: column;
  overflow: hidden;
  border-radius: 99px;
  background: rgba(161, 161, 161, .8);
}
.log-timing-bar > span { flex: 1; }
.log-timing-bar .lat-fast { background: rgba(0, 151, 103, .9); }
.log-timing-bar .lat-mid { background: rgba(205, 137, 0, .8); }
.log-timing-bar .lat-slow { background: rgba(228, 0, 20, .8); }
.log-timing-lines {
  display: flex;
  min-height: 32px;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  line-height: 16px;
}
.log-lat-line { display: flex; align-items: baseline; gap: 6px; }
.log-lat-k { color: var(--lg-muted); }
.log-lat-line .lat-fast { color: var(--lg-ok); }
.log-lat-line .lat-mid { color: var(--lg-warn); }
.log-lat-line .lat-slow { color: var(--lg-bad); }

/* Details: the formula's first term, then "+N" for the rest (cache, peak),
   the way New API previews its billing segments. The whole line is in the
   tooltip and the dialog. */
.log-detail-btn {
  display: inline-flex;
  max-width: 100%;
  min-width: 0;
  align-items: baseline;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--lg-fg);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  line-height: 18px;
  text-align: left;
  cursor: pointer;
}
.log-detail-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.log-detail-btn:hover .log-detail-text { text-decoration: underline; text-underline-offset: 2px; }
.log-detail-btn.is-warn { color: var(--lg-warn); }
.log-detail-more { flex: none; margin-left: 2px; color: var(--lg-fainter); }
.log-detail-btn:focus-visible {
  border-radius: 4px;
  outline: 2px solid rgba(62, 164, 236, .45);
  outline-offset: 2px;
}

/* Prefix, not a badge: a rare estimate flag should not widen the column for
   every row. Cache is a first-class numeric field, matching New API. */
.tok-est { margin-right: 1px; color: var(--lg-muted); font-weight: 400; cursor: help; }

.note-bad { color: #b45309; }

.log-bill-modal {
  width: min(560px, calc(100vw - 32px));
  max-height: min(86vh, 820px);
  border: 0;
  border-radius: 16px;
  padding: 0;
  background: #f6f7f8;
  color: var(--ink);
  box-shadow: 0 24px 64px rgba(15, 23, 42, .22);
}
.log-bill-modal::backdrop { background: rgba(15, 23, 42, .44); }
.log-bill-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px;
  background: #fff;
  border-bottom: 1px solid #eceef0;
}
.log-bill-model {
  margin: 0;
  color: #727a82;
  font-size: 12px;
  font-family: var(--mono);
}
.log-bill-head h2 { margin: 2px 0 0; font-size: 16px; }
.log-bill-body {
  display: grid;
  gap: 12px;
  max-height: calc(86vh - 74px);
  overflow: auto;
  padding: 14px;
}
.log-bill-card {
  padding: 4px 14px 8px;
  border: 1px solid #eceef0;
  border-radius: 12px;
  background: #fff;
}
.log-bill-card h3 {
  margin: 12px 0 2px;
  font-size: 13px;
}
.log-bill-card dl { margin: 0; }
.log-bill-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 0;
  border-bottom: 1px solid #f2f3f5;
  font-size: 13px;
}
.log-bill-row:last-child { border-bottom: 0; }
.log-bill-row dt { color: #727a82; }
.log-bill-row dd {
  margin: 0;
  color: #1f2328;
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.log-bill-row.is-strong dd { font-weight: 600; }
.log-bill-surcharge {
  margin: 0 0 10px;
  padding: 8px 10px;
  border: 1px solid #fcd34d;
  border-radius: 8px;
  background: #fffbeb;
  color: #78350f;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
}
.log-bill-surcharge.is-quiet {
  border-color: #dbe7fb;
  background: #f3f7ff;
  color: #1e3a8a;
}
.log-bill-note {
  margin: 4px 2px 8px;
  color: #727a82;
  font-size: 12px;
  line-height: 1.6;
}

/* ---------- label tags ---------- */

/* One pill for every categorical value, coloured by hashing the name. The hue
   assignment reproduces the legacy console's, so a model or group keeps the
   colour the users already associate with it. */
.ntag {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--line);
  color: var(--ink-2);
  font-size: 11.5px;
  line-height: 1.7;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;
}

.ntag + .ntag { margin-left: 3px; }
.ntag-mono { font-family: var(--mono); font-size: 11.5px; }

/* Latency reads as a bare number behind a coloured bar: it is a measurement,
   not a category, so it does not get a pill of its own. */
.ntag-plain {
  padding: 1px 0 1px 7px;
  border-left: 3px solid var(--line-3);
  border-radius: 0;
  background: none;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.lat-fast { border-left-color: var(--green-l); }
.lat-mid { border-left-color: #f0a92a; }
.lat-slow { border-left-color: #e05656; }

/* The bar grades total duration; time to first token is graded on its own
   scale, so it carries the colour as text instead of a second bar. */
.lat-frt { color: var(--ink-3); }
.lat-frt.t-mid { color: #b5730f; }
.lat-frt.t-slow { color: #c0392b; }

.ntag-amber { background: #fff1db; color: #8f5100; }
.ntag-blue { background: #e6f1fe; color: #0b4fbf; }
.ntag-cyan { background: #dff4f7; color: #00707f; }
.ntag-green { background: #e4f7ec; color: #0a7a46; }
.ntag-grey { background: #f0f1f3; color: #575d66; }
.ntag-indigo { background: #e9ebfb; color: #303ba8; }
.ntag-light-blue { background: #e1f3fd; color: #00648f; }
.ntag-lime { background: #eef7da; color: #4f7a00; }
.ntag-orange { background: #ffeee0; color: #9c4a00; }
.ntag-pink { background: #fde9f3; color: #a82269; }
.ntag-purple { background: #f2e9fc; color: #6329b8; }
.ntag-red { background: #fde9e9; color: #b01b1b; }
.ntag-teal { background: #def4f1; color: #007566; }
.ntag-violet { background: #eee8fc; color: #5227c4; }
.ntag-yellow { background: #fff6d9; color: #7e6000; }

/* Exact timestamps in log tables: date above, time below, so full precision
   fits without widening the column. */
.ts { line-height: 1.35; }
.ts-d { display: block; font-size: 11.5px; color: var(--ink-3); }
.ts-t { display: block; font-variant-numeric: tabular-nums; color: var(--ink-2); }

/* New API's pager, right under the table card: total, page size, then
   « ‹ pages › » as 32px round buttons with the current page filled. */
.logs-pager {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 8px 12px;
  margin: 0;
  padding: 12px 0 0;
}

.pager-total {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  color: rgba(96, 96, 96, .8);
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
}
.pager-total b { color: var(--lg-fg); font-weight: 500; font-variant-numeric: tabular-nums; }

.pager-size {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: rgba(96, 96, 96, .8);
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
}
.lf-select {
  width: 70px;
  padding: 0 28px 0 10px;
  -webkit-appearance: none;
  appearance: none;
  background: #fff;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.pager-size .lf-select-icon { right: 8px; }

.pages { display: inline-flex; align-items: center; gap: 8px; }

.page-btn {
  display: inline-flex;
  width: 32px;
  height: 32px;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid var(--lg-line);
  border-radius: 16px;
  background: #fff;
  color: var(--lg-muted);
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  transition: background-color .12s ease, color .12s ease;
}
a.page-btn:hover { background: var(--lg-hover); color: var(--lg-fg); }
.page-btn.on { border-color: transparent; background: var(--lg-primary); color: #fff; font-weight: 600; }
/* Rendered as a span, not a link, so the row keeps its shape at either end. */
.page-btn.off { color: rgba(96, 96, 96, .5); cursor: default; }
.page-btn svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.page-gap { padding: 0 2px; color: rgba(96, 96, 96, .6); font-size: 14px; }

@media (max-width: 899.98px) {
  .app[data-page="logs"] { padding-bottom: 40px; }
}

@media (max-width: 700px) {
  .dt-pop { width: auto; left: 0; right: 0; }
  .logs-pager { justify-content: flex-start; }
  .pages { gap: 4px; }
  /* « and » go first, as on New API's narrow pager; ‹ › stay. */
  .pages > .page-arrow:first-child,
  .pages > .page-arrow:last-child { display: none; }
}

/* ---------- wallet page ---------- */

/* Stripe settles in USD while the wallet stays CNY-denominated; keep that
   conversion rule visible beside the balance. */
.rate-note {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin: 0 0 22px;
  padding: 12px 16px;
  border: 1px solid #cfe7dc;
  border-radius: var(--r-sm);
  background: #f2fbf7;
  color: #14614a;
  font-size: 13px;
  line-height: 1.7;
}

.rate-eq {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--green-d);
}

.rate-txt { flex: 1; min-width: 240px; }
.rate-note b { color: var(--green-d); }

.pay-pick { margin-bottom: 22px; }

.pay-pick-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}

.pay-pick-step {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
}

.pay-pick-t { font-size: 14px; font-weight: 600; color: var(--ink); }
.pay-pick-note { font-size: 12px; color: var(--ink-3); }

/* Both methods are equal choices, so they get card-sized weight rather than the
   pair of 13px pills this used to be — nobody noticed a card option was there. */
.pay-choice {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

/* WeChat, Alipay and Stripe side by side. The card body wraps, so three fit. */
.pay-choice.pay-choice-3 { grid-template-columns: repeat(3, 1fr); }

@media (max-width: 700px) {
  .pay-choice,
  .pay-choice.pay-choice-3 { grid-template-columns: 1fr; }
}

.pay-choice-card {
  /* Each method carries its own accent so the two cards stay distinguishable
     when one is selected; a shared green made them read as one control. */
  --pm: var(--green);
  --pm-glow: rgba(4, 120, 87, .10);
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 14px 46px 14px 16px;
  border: 1px solid var(--line-3);
  border-radius: var(--r-sm);
  background: #fff;
  text-align: left;
  cursor: pointer;
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}

.pay-choice-card[data-method="alipay"] {
  --pm: #1677ff;
  --pm-glow: rgba(22, 119, 255, .14);
}

.pay-choice-card[data-method="stripe"] {
  --pm: #635bff;
  --pm-glow: rgba(99, 91, 255, .14);
}

.pay-choice-card:hover { border-color: var(--pm); transform: translateY(-1px); }

.pay-choice-card.is-on {
  border-color: var(--pm);
  box-shadow: inset 0 0 0 1px var(--pm), 0 6px 18px var(--pm-glow);
}

/* With one method configured there is nothing to choose, so the card drops the
   radio affordances and reads as a statement of what checkout will do. */
.pay-choice-card.is-solo {
  padding-right: 16px;
  cursor: default;
}

.pay-choice-card.is-solo:hover { border-color: var(--line-3); transform: none; }
.pay-choice-card.is-solo .pay-choice-tick { display: none; }

.pay-choice-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 10px;
}

.mark-wechat { background: #e6f7ed; color: #07c160; }
.mark-card { background: #ecebfd; color: #635bff; }
/* The mark is a filled blue square with the 支 cut out, so it carries its own colour. */
.mark-alipay { background: transparent; color: #1677ff; }
[data-pay-for][hidden] { display: none; }

.pay-choice-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

.pay-choice-t {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
}

.pay-choice-d { font-size: 12px; line-height: 1.6; color: var(--ink-3); }
.pay-choice-d b { color: var(--ink-2); font-weight: 600; }

/* Which cards actually work is the first question this option raises, so the
   networks are named on the option itself rather than in the fine print. */
.pay-brands {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 9px;
}

.pay-brand {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 26px;
  padding: 0 8px;
  border: 1px solid var(--line-2);
  border-radius: 6px;
  background: #fff;
}

.pay-brand-ico { display: block; flex: none; width: 25px; height: 15px; }

.pay-brand-wm {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--ink-2);
  white-space: nowrap;
}

/* Visa is distributed as a wordmark, so the styled text is the mark. */
.brand-visa {
  font-size: 14px;
  font-style: italic;
  font-weight: 800;
  letter-spacing: -.01em;
  color: #1434cb;
}

/* Alipay's mark is its blue wordmark; the Chinese name is what users look for. */
.brand-alipay {
  font-size: 11.5px;
  font-weight: 700;
  color: #1677ff;
}

.pay-choice-tick {
  position: absolute;
  top: 50%;
  right: 16px;
  width: 18px;
  height: 18px;
  border: 1px solid var(--line-3);
  border-radius: 50%;
  background: #fff;
  transform: translateY(-50%);
}

.pay-choice-card.is-on .pay-choice-tick {
  border-color: var(--pm);
  background: var(--pm);
}

.pay-choice-card.is-on .pay-choice-tick::after {
  content: "";
  position: absolute;
  left: 5px;
  top: 2px;
  width: 5px;
  height: 9px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* Three fixed columns so the six tiers read as 3 + 3. Sizing the tracks by
   min-width instead packed five into a wide panel and orphaned the sixth on a
   row of its own. */
.topup-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-bottom: 16px;
}

/* Three 150px-plus cards don't fit a phone; two rows of three become three
   rows of two. */
@media (max-width: 560px) {
  .topup-grid { grid-template-columns: repeat(2, 1fr); }
}

.topup-grid form { margin: 0; }

.topup-opt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 100%;
  padding: 18px 12px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: #fff;
  color: inherit;
  cursor: pointer;
  transition: border-color .15s ease, transform .15s ease;
}

.topup-opt:hover {
  border-color: var(--green);
  transform: translateY(-1px);
}

.topup-amt {
  font-size: 22px;
  font-weight: 600;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}

.topup-sub {
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* Stripe Checkout rejects anything under $0.50 after conversion, so obviously
   tiny admin test amounts go flat instead of failing after a request. */
.topup-note {
  font-size: 11px;
  line-height: 1.4;
  color: var(--ink-3);
}

.topup-opt:disabled { cursor: not-allowed; opacity: .45; }
.topup-opt:disabled:hover { border-color: var(--line); transform: none; }

/* The 1-fen admin button sits in the same grid as the real amounts; dashed and
   muted so it reads as a tool rather than an offer. */
.topup-test {
  border-style: dashed;
  border-color: var(--line-3);
}

.topup-test .topup-amt { color: var(--ink-2); }

/* Sized to the QR rather than to the column: a checkout stretched across a
   1200px console reads as a broken embed. */
.pay-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 420px;
  margin: 0 auto;
}

/* The checkout is a third-party page, so its height is fixed here rather than
   negotiated — a cross-origin frame can't report its own content size. */
.pay-frame {
  width: 100%;
  max-width: 340px;
  height: 420px;
  border: 0;
}

.pay-tip { margin-top: 12px; text-align: center; }

.pay-done {
  padding: 48px 24px;
  text-align: center;
}

.pay-done-t {
  font-size: 20px;
  font-weight: 600;
  color: var(--green);
  margin-bottom: 8px;
}

.pay-done-d {
  font-size: 14px;
  color: var(--ink-3);
}

/* Picking an amount opens this straight away and swaps in the QR when the
   provider answers, so the wait happens over the amount grid instead of on a
   page that has nothing else on it. */
.pay-modal {
  width: min(420px, calc(100vw - 32px));
  border: 0;
  border-radius: 15px;
  padding: 0;
  background: #fff;
  color: var(--ink);
  box-shadow: 0 24px 64px rgba(15, 23, 42, .22);
}

.pay-modal::backdrop { background: rgba(15, 23, 42, .44); backdrop-filter: blur(2px); }

.pay-modal-body { padding: 18px 22px 22px; }

.pay-modal-sub {
  margin: 0 0 14px;
  text-align: center;
  font-size: 13px;
  color: var(--ink-2);
  min-height: 20px;
}

/* Fixed to the frame's height so swapping between spinner, QR and receipt
   doesn't resize the dialog under the pointer. */
.pay-modal-stage {
  display: grid;
  place-items: center;
  min-height: 420px;
}

.pay-modal-load {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--ink-3);
}

.pay-spin {
  width: 20px;
  height: 20px;
  border: 2px solid var(--line-2);
  border-top-color: var(--green);
  border-radius: 50%;
  animation: pay-spin .7s linear infinite;
}

@keyframes pay-spin { to { transform: rotate(360deg); } }

.pay-modal-err {
  margin: 0;
  max-width: 280px;
  text-align: center;
  font-size: 13px;
  line-height: 1.7;
  color: #a33a3a;
}

/* Class selectors outrank the UA stylesheet's [hidden], so restate it for the
   stage's three swappable states. */
.pay-modal [hidden] { display: none; }

.pay-modal-tip { margin: 14px 0 0; text-align: center; }

@media (max-width: 480px) {
  .pay-modal-stage { min-height: 380px; }
}

/* ---------- settings page ---------- */

.field-hint {
  font-size: 12px;
  line-height: 1.7;
  color: var(--ink-3);
}

.deflist { display: grid; gap: 1px; background: var(--line); }

.deflist > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  background: #fff;
  padding: 10px 0;
}

.deflist dt { font-size: 13px; color: var(--ink-2); }

.deflist dd {
  font-size: 13px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.deflist + .field-hint { margin-top: 16px; }
/* Live invite-code hint on the sign-up form. */
.field-hint.aff-ok { color: var(--green); }
.field-hint.aff-warn { color: #b45309; }

/* ---------- auth page ---------- */

body.plain { background: var(--tint); }

.auth {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  padding: 40px 20px;
}

.auth-brand { justify-content: center; }
.auth > .lang-switch { justify-content: center; margin-top: -24px; }

.auth-card {
  width: 100%;
  max-width: 400px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  background: #fff;
  padding: 32px;
  box-shadow: var(--sh-hero);
}

.auth-h { font-size: 22px; letter-spacing: -.02em; }

.auth-sub {
  margin-top: 8px;
  margin-bottom: 24px;
  font-size: 13px;
  line-height: 1.7;
  color: var(--ink-2);
}

.form { display: grid; gap: 16px; }

.oauth-entry { display: grid; gap: 10px; margin-bottom: 18px; }
.oauth-entry .auth-divider { margin-top: 6px; }

/* The OAuth actions (Google, GitHub) are form controls, not one of the site's pill CTAs. Keep
   its geometry and interaction local so shared buttons remain untouched. */
.btn-google,
.btn-github {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 48px;
  border: 1px solid #d6ddda;
  border-radius: 12px;
  background: #fff;
  color: var(--ink);
  padding: 0 48px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.005em;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(15, 76, 92, .05);
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease;
}

.btn-google:hover,
.btn-github:hover {
  border-color: #b6c5bf;
  background: #fbfcfc;
  box-shadow: 0 3px 10px rgba(15, 76, 92, .08);
}

.btn-google:active,
.btn-github:active {
  background: var(--tint);
  box-shadow: 0 1px 2px rgba(15, 76, 92, .04);
}

.btn-google:focus-visible,
.btn-github:focus-visible {
  outline: none;
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(4, 120, 87, .1);
}

.google-mark {
  position: absolute;
  left: 16px;
  width: 18px;
  height: 18px;
}

.google-mark svg { display: block; width: 100%; height: 100%; }
.google-label { overflow: hidden; text-overflow: ellipsis; }

/* The masked address on the link-account page: shown, not editable. */
.bind-email {
  min-height: 44px;
  display: flex;
  align-items: center;
  padding: 0 14px;
  border: 1px solid var(--line-2);
  border-radius: 12px;
  background: var(--tint);
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  word-break: break-all;
}
.auth-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
  color: var(--ink-3);
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: .01em;
}

.auth-divider span { padding: 0 2px; white-space: nowrap; }

.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--line-2));
}

.auth-divider::after { transform: scaleX(-1); }

/* Submit buttons size to their label; the auth page opts back into full
   width with .btn-block. */
.form > .btn { justify-self: start; }
.form > .btn-block { justify-self: stretch; }

.field { display: grid; gap: 7px; }

.field-code { display: flex; gap: 8px; }
.field-code .input { flex: 1; min-width: 0; }
.field-code .btn { flex-shrink: 0; white-space: nowrap; }

/* 阿里云验证码是弹窗模式，占位元素本身不占高；无痕验证时完全不可见 */
.captcha-slot { margin: 0; }

.field-edit { font-size: 12px; font-weight: 400; margin-left: 6px; }
.input[readonly] { background: var(--tint); color: var(--ink-2); }

.field-label { font-size: 13px; color: var(--ink-2); }

.input {
  width: 100%;
  border: 1px solid var(--line-3);
  border-radius: var(--r-sm);
  background: #fff;
  padding: 11px 13px;
  font-family: inherit;
  font-size: 15px;
  color: var(--ink);
  outline: none;
  transition: border-color .12s ease, box-shadow .12s ease;
}

.input:focus {
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(4, 120, 87, .1);
}

.btn-block { width: 100%; padding: 12px; margin-top: 4px; }

/* Keep the two sign-in actions in one visual system without changing shared
   auth buttons on registration, password reset, or account pages. */
.auth-sign-in .form > .btn-block {
  min-height: 48px;
  border: 1px solid var(--green);
}

/* ---------- attributed signup landing ---------- */

/* The campaign strip is shared with the home page, where it spans the content
   width. On the auth page it has to track the card instead: 400px normally,
   and the wider two-column grid on an attributed visit. */
.signup-deal {
  width: 100%;
  max-width: 400px;
  margin: 0;
}

.auth-source .signup-deal { max-width: 980px; }

@media (max-width: 800px) {
  .auth-source .signup-deal { max-width: 520px; }
}

/* The ordinary /sign-up card stays exactly as-is. These rules only activate
   when utm_source/source turns the page into an acquisition landing surface. */
.auth-source {
  justify-content: flex-start;
  gap: 16px;
  padding-top: 28px;
  padding-bottom: 32px;
}

.auth-source > .lang-switch { margin-top: -16px; }

.signup-hvoy-title,
.signup-lead-gift,
.signup-lead-grid {
  width: min(100%, 980px);
}

.signup-hvoy-title {
  margin: 0;
  font-size: 28px;
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -.03em;
}

.signup-lead-gift {
  display: flex;
  align-items: center;
  gap: 18px;
  border: 1px solid rgba(4, 120, 87, .2);
  border-radius: var(--r-lg);
  background: linear-gradient(115deg, var(--green), #066b52);
  color: #fff;
  padding: 16px 22px;
  box-shadow: 0 10px 30px rgba(4, 120, 87, .16);
}

.signup-gift-amount {
  flex: 0 0 auto;
  min-width: 84px;
  font-size: 36px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.04em;
  font-variant-numeric: tabular-nums;
}

.signup-gift-copy { display: grid; gap: 3px; }
.signup-gift-copy strong { font-size: 17px; letter-spacing: -.01em; }
.signup-gift-copy small { color: rgba(255, 255, 255, .82); font-size: 12px; line-height: 1.5; }

.signup-lead-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(360px, .75fr);
  grid-template-areas: "story form";
  gap: 18px;
  align-items: start;
}

@media (max-width: 800px) {
  .auth-source { padding-top: 24px; }

  .signup-hvoy-title,
  .signup-lead-gift,
  .signup-lead-grid { max-width: 520px; }

  .signup-lead-grid {
    grid-template-columns: 1fr;
    grid-template-areas:
      "story"
      "form";
  }

  .signup-lead-form { position: static; }
}

@media (max-width: 520px) {
  .auth-source { padding-inline: 14px; }

  .signup-lead-gift {
    gap: 12px;
    padding: 14px 16px;
  }

  .signup-gift-amount { min-width: 67px; font-size: 29px; }
  .signup-gift-copy strong { font-size: 15px; }

}

.auth-sign-in .form > .btn-block {
  border-radius: 12px;
  padding: 0 16px;
  margin-top: 2px;
  font-family: inherit;
  font-size: 14px;
  line-height: 1.2;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
}

.auth-sign-in .form > .btn-block:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(4, 120, 87, .14);
}

.auth-foot {
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
  font-size: 13px;
  color: var(--ink-3);
  text-align: center;
}

/* The footer's action links (注册 / 找回密码) are the page's secondary
   conversions — plain muted links read as decoration, so give them weight,
   brand color, and an underline. */
.auth-act { display: block; }
.auth-act + .auth-act { margin-top: 10px; }
.auth-link {
  color: var(--green);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: var(--green-l);
  text-underline-offset: 3px;
}
.auth-link:hover { color: var(--green-d); text-decoration-color: var(--green-d); }

.auth-alt { font-size: 13px; color: var(--ink-3); }
.auth-alt a { color: var(--ink-2); }
.auth-alt a:hover { color: var(--ink); }
.auth-alt .sep { margin: 0 8px; }

/* ---------- error page ---------- */

.err { padding: 100px 0 120px; text-align: center; }

.err-code {
  font-size: 13px;
  font-weight: 500;
  color: var(--green);
  letter-spacing: .08em;
}

.err-h {
  margin-top: 12px;
  font-size: clamp(26px, 4vw, 38px);
  letter-spacing: -.02em;
}

.err-p {
  margin: 14px auto 28px;
  max-width: 440px;
  font-size: 15px;
  line-height: 1.8;
  color: var(--ink-2);
}

.err .cta-btns { justify-content: center; }

/* ---------- responsive ---------- */

@media (max-width: 899.98px) {
  :root { --pad: 14px; }

  .sec { padding: 60px 0; }
  .sec-head { margin-bottom: 32px; }
  /* Tighter than the desktop 48px: with the ad leading the hero, the default
     gap pushed the headline itself off a phone's first screen. */
  .hero { padding: 32px 0 60px; gap: 26px; }
  .hero-card { padding: 20px; }
  /* The signup credit is the primary phone CTA. Keep it before the campaign
     even if future template edits or translations make the row wrap. */
  .hero-gift { order: 0; }

  /* Full width rather than a pill: the announcement is longer than a 390px
     line, and a wrapped 999px capsule reads as a layout accident. As its own
     row it also cannot squeeze the gift off the first screen. */
  .hero-ad-compact {
    order: 1;
    width: 100%;
    border-radius: 14px;
    padding: 12px 14px;
    font-size: 13px;
    line-height: 1.45;
  }

  .hero-ad-compact .hero-gift-arw { margin-left: auto; padding-left: 8px; }
  .cta { padding: 28px 24px; }
  .only-lg { display: none; }
  .tbl th, .tbl td { padding: 12px 16px; }
  .tbl-head { padding: 16px; }
  .faq summary { padding: 16px 18px; }
  .faq p { padding: 0 18px 16px; }
  .steps li { padding: 18px; }

  /* The sidebar becomes a scrollable chip strip — a stacked seven-row nav
     would push the actual page content below the fold. */
  .side {
    margin: 0 calc(var(--pad) * -1);
    padding: 0 var(--pad);
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    /* A chip cut flat by the viewport edge reads as a broken layout; fading it
       is what tells a touch user the strip keeps going. */
    -webkit-mask-image: var(--strip-fade);
    mask-image: var(--strip-fade);
  }

  .side::-webkit-scrollbar { display: none; }

  .side nav {
    grid-auto-flow: column;
    grid-auto-columns: max-content;
    gap: 7px;
  }

  .side-item {
    border: 1px solid var(--line-2);
    border-radius: 999px;
    padding: 9px 14px;
    font-size: 13px;
    white-space: nowrap;
  }

  .side-item.on { border-color: transparent; }
  .side-item-featured { margin: 0; box-shadow: 0 4px 12px rgba(16, 122, 83, .13); }
  .side-item-featured:hover { transform: none; }
  .side-item-featured .side-badge { min-height: 16px; padding: 1px 5px; }
  .side-ico { display: none; }
  .side-qr { display: none; }

  .page-head { margin-bottom: 22px; }
  /* Phones get the reminder as one unbroken line: the copy button is a
     convenience for a number that is right there, so it is the first thing to
     go rather than letting the pill wrap to two rows. */
  .head-invoice { padding-right: 10px; }
  .head-invoice-copy { display: none; }
  .stat { padding: 16px 18px; }
  .stat-value { font-size: 26px; }
  .app { padding-top: 22px; gap: 24px; }

  /* The public nav has no hamburger menu; hiding it below the desktop
     breakpoint left phone users with no way to reach pricing/docs/contact.
     Wrap the header and lay the links out as a scrollable chip strip, the
     same pattern the console sidebar already uses on narrow screens. */
  .hdr-in { flex-wrap: wrap; row-gap: 10px; }

  .hdr .nav {
    display: flex;
    order: 3;
    width: calc(100% + (var(--pad) * 2));
    gap: 8px;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    margin: 0 calc(var(--pad) * -1);
    padding: 0 var(--pad) 2px;
    -webkit-mask-image: var(--strip-fade);
    mask-image: var(--strip-fade);
  }

  .hdr .nav::-webkit-scrollbar { display: none; }

  .hdr .nav a {
    border: 1px solid var(--line-2);
    border-radius: 999px;
    padding: 8px 14px;
    font-size: 13px;
    white-space: nowrap;
  }

  /* 13x20 of glyph is not a touch target: pad the hit area out to the row
     height and pull the box back so the header keeps its measured height. */
  .lang-switch a {
    padding: 10px 3px;
    margin: -10px 0;
  }

  .code-name { font-size: 12px; }
  .copy { padding: 8px 14px; font-size: 12px; }

  /* `code { font-size: .92em }` compounds inside the block and lands the
     shell samples near 10px on a phone. */
  .code pre { font-size: 12.5px; }
  .code pre code { font-size: 1em; }
}

@media (max-width: 520px) {
  /* On a phone the rename note goes away — the domain under the logo already
     tells a returning user which site they're on, and the header needs the
     room. The secondary login action is available on the signup page, so the
     header can privilege the primary CTA without overflowing a 390px phone. */
  .hdr .brand { gap: 7px; }
  .hdr .brand-mark { width: 118px; height: 28px; }
  .hdr .brand-note { display: none; }
  /* Not zero: at gap 0 the language switch sits flush against the primary
     pill and the two read as one broken control. */
  .hdr-cta { gap: 9px; }
  .hdr-cta .btn { padding: 8px 14px; }
  /* Direct children only. The console's sign-out button is a ghost button
     nested in a form, and hiding it left phone users with no way out. */
  .hdr-cta > .btn-ghost { display: none; }
  /* The console no longer lists the setup guide in its rail, so on a phone
     this top-bar button is the only way to it; keep it, just smaller. */
  .hdr-cta > .btn-ghost.hdr-docs { display: inline-flex; padding: 8px 10px; font-size: 13px; }
  /* The balance stays visible even when direct ghost links are hidden. */
  .hdr-cta .hdr-bal { display: inline-flex; padding: 7px 9px; }
  /* space-between does nothing once the strip overflows, and spreads the chips
     unevenly when it doesn't — keep one rhythm at every width. */
  .hdr .nav { gap: 7px; }
  .hdr .nav a { padding: 8px 10px; font-size: 12.5px; }
}

/* Below this the logo plus the CTA row no longer fit on one line, and the
   header spills onto a third row. The language separator is decorative, so
   it is the first thing to give up. */
@media (max-width: 360px) {
  .lang-switch { gap: 8px; }
  .lang-switch span[aria-hidden] { display: none; }
  .hdr-cta { gap: 8px; }
  .hdr-cta .btn { padding: 8px 12px; }
}

/* ---------- docs & pricing pages ---------- */

.page-hero {
  padding: 56px 0 8px;
  max-width: 760px;
}

.page-hero h1 {
  margin: 6px 0 14px;
  font-size: clamp(30px, 4vw, 44px);
  letter-spacing: -.02em;
}

.page-hero .lead {
  font-size: 16px;
  line-height: 1.85;
  color: var(--ink-2);
}

.note-box {
  margin-top: 20px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--tint);
  padding: 22px 24px;
}

.note-box h3 { font-size: 15px; margin-bottom: 6px; }

.note-box p, .callout p {
  font-size: 14px;
  line-height: 1.85;
  color: var(--ink-2);
}

.note-box a, .callout a, .doc-body p a, .sec-note a {
  color: var(--green-d);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.tbl-price .cache-hit { color: var(--green-d); }

/* The header is sticky, so anchored sections need to clear it. */
.sec[id] { scroll-margin-top: 90px; }

/* Docs and pricing inside the console shell: the page already has a sidebar,
   so drop the second one and shrink the marketing-sized hero. */
.app-doc .page-hero { padding: 4px 0 0; }
.app-doc .page-hero h1 { font-size: 28px; margin: 4px 0 10px; }
.app-doc .page-hero .lead { font-size: 14.5px; }
.app-doc .doc { padding-top: 24px; }

/* docs page: sticky table of contents beside the article */

.doc { display: grid; gap: 32px; padding: 32px 0 72px; }

.doc-toc { display: none; }

.doc-toc-title {
  font-size: 12px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 10px;
}

.doc-toc a {
  display: block;
  padding: 6px 0 6px 12px;
  border-left: 2px solid var(--line-2);
  font-size: 13.5px;
  color: var(--ink-2);
  transition: color .12s ease, border-color .12s ease;
}

.doc-toc a:hover { color: var(--green-d); border-left-color: var(--green-l); }

.doc-toc-out {
  margin-top: 8px;
  border-left-color: transparent !important;
  color: var(--green-d) !important;
}

/* Editorial copy keeps a readable measure even though the site shell itself
   is full width. The table of contents remains anchored to the left. */
.doc-body { width: 100%; max-width: 900px; min-width: 0; display: grid; gap: 52px; }

/* Grid items default to min-width:auto, so a long URL or path in a <code>
   would widen the whole column instead of wrapping inside it. */
.doc-body section, .doc-body section > * { min-width: 0; }

.doc-body section { display: grid; gap: 14px; scroll-margin-top: 90px; }

/* Sits after the two 90px rules on purpose — same later-wins tiebreak as the
   640px docs block below. On a phone the header wraps to two rows (~122px), so
   the desktop offset would drop an anchored heading behind it. */
@media (max-width: 899.98px) {
  .sec[id], .doc-body section{ scroll-margin-top: 130px; }
}

.doc-body h2 {
  font-size: 24px;
  letter-spacing: -.01em;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}

.doc-body h3 { font-size: 16px; margin-top: 6px; }
/* Screenshots in the docs: fit the column, keep the aspect ratio from the
   width/height attributes so the page does not jump while they load. */
.doc-shot { margin: 12px 0 0; }
.doc-shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--panel);
}

.doc-body > section > p, .qa-body p {
  font-size: 14.5px;
  line-height: 1.9;
  color: var(--ink-2);
}

.doc-body code, .note-box code, .callout code, .deflist-doc code {
  font-family: var(--mono);
  font-size: .88em;
  background: var(--tint-2);
  border-radius: 5px;
  padding: 1px 5px;
  color: var(--green-d);
  /* model IDs and URLs have no break opportunities of their own */
  overflow-wrap: anywhere;
}

.doc-body .code code { background: none; padding: 0; color: inherit; }

.callout {
  border: 1px solid var(--line);
  border-left: 3px solid var(--green);
  border-radius: var(--r-sm);
  background: var(--tint);
  padding: 18px 22px;
  display: grid;
  gap: 6px;
}

.callout h3 { font-size: 15px; margin: 0; }
.callout-warn { border-left-color: #d97706; background: #fffbeb; }

.deflist-doc {
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  overflow: hidden;
}

/* The console's deflist is a right-aligned label/value row; in prose the
   value is a sentence, so it starts right after the term and wraps normally. */
.deflist-doc > div { justify-content: flex-start; padding: 12px 18px; }
.deflist-doc dt { flex: none; min-width: 104px; font-size: 13.5px; font-weight: 500; color: var(--ink); }

.deflist-doc dd {
  margin: 0;
  min-width: 0;
  font-size: 13.5px;
  line-height: 1.8;
  text-align: left;
  color: var(--ink-2);
}
.deflist-doc a { color: var(--green-d); text-decoration: underline; text-underline-offset: 2px; }

/* .steps is a flex row built around the .step-n badge; the docs variant
   numbers itself with a counter so the copy can stay plain markup. */
.steps-doc { counter-reset: dstep; gap: 14px; }

.steps-doc li {
  display: block;
  position: relative;
  padding: 20px 24px 22px 62px;
  counter-increment: dstep;
}

.steps-doc li::before {
  content: counter(dstep);
  position: absolute;
  left: 22px;
  top: 20px;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background: var(--tint-2);
  color: var(--green-d);
  font-size: 13px;
  font-weight: 600;
}

.steps-doc li > * + * { margin-top: 10px; }
.steps-doc p { margin-top: 8px; }
.steps-doc .muted { color: var(--ink-3); font-size: 13.5px; }

.qa-body { padding: 0 24px 20px; display: grid; gap: 12px; }
.qa-body p { padding: 0; }
.qa-body .code { margin: 0; }

/* Sits after the docs rules on purpose: an override in the shared
   max-width:900px block higher up would lose the later-wins tiebreak. */
@media (max-width: 640px) {
  .qa-body { padding: 0 18px 16px; }
  .steps-doc li { padding: 18px 18px 20px 52px; }
  .steps-doc li::before { left: 16px; top: 18px; }

  /* term over definition — 104px of label leaves too little for the value */
  .deflist-doc > div { display: block; padding: 12px 16px; }
  .deflist-doc dt { min-width: 0; margin-bottom: 2px; }
}

@media (min-width: 900px) {
  .nav { display: flex; }

  .doc { grid-template-columns: 200px minmax(0, 1fr); gap: 56px; align-items: start; }

  .doc-toc {
    display: block;
    position: sticky;
    top: 92px;
  }

  /* One sidebar per screen — the console nav already fills that role — so the
     contents list lies down above the article instead of stacking beside it. */
  .app-doc .doc { grid-template-columns: minmax(0, 1fr); gap: 28px; }

  .app-doc .doc-toc {
    position: static;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--line);
  }

  .app-doc .doc-toc-title { margin: 0 6px 0 0; }

  .app-doc .doc-toc a {
    padding: 5px 12px;
    border-left: 0;
    border: 1px solid var(--line);
    border-radius: 999px;
    font-size: 13px;
  }

  .app-doc .doc-toc a:hover { border-color: var(--green-l); }
  .app-doc .doc-toc-out { margin-top: 0; border-color: #bfe3d1 !important; }

  /* full-width prose runs ~120 characters a line inside the console */
  .app-doc .doc-body { max-width: 900px; }

  /* six feature cards read better as 3+3 than as the 4+2 auto-fit produces */
  .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  .app { grid-template-columns: 208px minmax(0, 1fr); gap: 44px; }
  .side { position: sticky; top: 84px; }
  .cols { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }

  .sec-head {
    grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr);
    align-items: end;
    gap: 48px;
  }

  .sec-note { justify-self: end; }

  .cta {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 40px;
  }

  .cta-act { align-items: flex-end; }
}

/* The rail is taller now that it carries the group QR (about 730px, stuck 84px
   below the top). In a window shorter than that a sticky rail would cut the QR
   off with no way to scroll it into view, so there it scrolls with the page. */
@media (min-width: 900px) and (max-height: 819px) {
  .side { position: static; }
}
@media (min-width: 1024px) {
  .hero-split {
    grid-template-columns: 1.1fr .9fr;
    gap: 64px;
    align-items: start;
  }

  .hero-ad-compact { display: none; }

  .hero-ad {
    display: block;
    min-width: 0;
    margin-top: 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; }
}

/* ---------- console overview dashboard ---------- */

.app[data-page="console-home"] { padding-bottom: 24px; }
.console-home { min-width: 0; }

.dash-topline {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 22px;
  margin-bottom: 18px;
}

.dash-greeting {
  font-size: 25px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.02em;
  white-space: nowrap;
}

.dash-ranges {
  display: inline-flex;
  justify-self: start;
  padding: 4px;
  border-radius: 8px;
  background: #f3f4f6;
}

.dash-range {
  min-width: 72px;
  border-radius: 5px;
  padding: 7px 14px;
  color: var(--ink-2);
  font-size: 13px;
  text-align: center;
}

.dash-range:hover { color: var(--ink); }
.dash-range.on { background: #fff; color: #2563eb; box-shadow: 0 1px 4px rgba(15, 23, 42, .08); }

.dash-refresh {
  display: grid;
  width: 36px;
  height: 36px;
  place-items: center;
  border-radius: 50%;
  background: #f1f3f4;
  color: #4b5563;
  font-size: 22px;
  line-height: 1;
}

.dash-refresh:hover { background: #e8ebed; color: var(--ink); }

.dash-cards {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}

.dash-card,
.dash-analysis,
.dash-api {
  border: 1px solid #e5e7eb;
  border-radius: 15px;
  background: #fff;
  overflow: hidden;
}

.dash-card > header,
.dash-panel-head {
  display: flex;
  align-items: center;
  min-height: 47px;
  border-bottom: 1px solid #eceef0;
  padding: 0 15px;
}

.dash-card > header {
  gap: 9px;
  font-size: 14px;
  font-weight: 500;
}

.dash-head-ico { width: 18px; color: #24292f; font-size: 16px; text-align: center; }
.dash-card-body { padding: 3px 14px 9px; }

.dash-stat-row {
  position: relative;
  display: flex;
  min-height: 67px;
  align-items: center;
  gap: 13px;
}

.dash-stat-row + .dash-stat-row { border-top: 1px solid #f0f1f2; }

.dash-round {
  display: grid;
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
  place-items: center;
  border-radius: 50%;
  color: #fff;
  font-size: 13px;
  font-weight: 700;
}

.dash-blue { background: #63b3ff; }
.dash-purple { background: #c56ed4; }
.dash-green { background: #71d280; }
.dash-cyan { background: #4bc3cf; }
.dash-yellow { background: #ffdd57; }
.dash-pink { background: #ef719b; }
.dash-indigo { background: #7d8bd7; }
.dash-orange { background: #ffbd5c; }

.dash-stat-copy { min-width: 0; }
.dash-stat-copy small { display: block; color: #72777d; font-size: 12px; }
.dash-stat-copy strong {
  display: block;
  overflow: hidden;
  margin-top: 2px;
  color: #4b4f54;
  font-size: 20px;
  line-height: 1.15;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}

.dash-mini-btn {
  margin-left: auto;
  border: 1px solid #d9dcdf;
  border-radius: 999px;
  padding: 4px 10px;
  color: #4b4f54;
  font-size: 12px;
}

.dash-mini-btn:hover { background: #f6f7f8; }

.dash-spark {
  width: 72px;
  height: 36px;
  margin-left: auto;
  overflow: visible;
  fill: none;
  stroke-width: 2;
}

.dash-spark-cyan { stroke: #08a5b5; }
.dash-spark-yellow { stroke: #f59e0b; }
.dash-spark-pink { stroke: #ec4899; }
.dash-spark-indigo { stroke: #6366f1; }
.dash-spark-orange { stroke: #f97316; }

.dash-lower {
  display: grid;
  grid-template-columns: minmax(0, 3.05fr) minmax(280px, .95fr);
  gap: 16px;
  margin-top: 16px;
}

.dash-panel-head { justify-content: space-between; gap: 18px; }
.dash-panel-head h2 { font-size: 15px; font-weight: 500; white-space: nowrap; }
.dash-panel-head h2 span { display: inline-block; width: 19px; text-align: center; }

.dash-view-tabs { display: flex; align-items: center; gap: 0; }
.dash-view-tabs a { color: #8b9095; font-size: 13px; white-space: nowrap; }
.dash-view-tabs a:hover,
.dash-view-tabs a.on { color: #1f2328; font-weight: 600; }
.dash-view-tabs a + a::before { content: "/"; margin: 0 14px; color: #aeb2b6; font-weight: 400; }

.dash-analysis-body { min-height: 390px; padding: 48px 40px 22px; }
.dash-analysis-body h3 { font-size: 16px; }
.dash-analysis-body > p { margin-top: 5px; color: #7a7f84; font-size: 13px; }

.dash-chart-wrap { position: relative; height: 250px; margin-top: 16px; padding: 0 0 26px 32px; }
.dash-grid-lines {
  position: absolute;
  inset: 0 0 26px 32px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  pointer-events: none;
}
.dash-grid-lines i { display: block; border-top: 1px solid #e8eaec; }

.dash-chart-bars {
  position: relative;
  z-index: 1;
  display: flex;
  height: 100%;
  align-items: flex-end;
  gap: 3px;
  border-bottom: 1px solid #60656a;
}

.dash-chart-col {
  display: flex;
  height: 100%;
  min-width: 0;
  flex: 1 1 0;
  flex-direction: column;
  justify-content: flex-end;
  align-items: stretch;
}

.dash-chart-stack {
  display: flex;
  height: calc(100% - 24px);
  flex-direction: column-reverse;
  justify-content: flex-start;
}
.dash-chart-stack > span { display: block; min-height: 0; }
.dash-chart-col > small {
  height: 22px;
  margin-top: 4px;
  color: #656b70;
  font-size: 8px;
  line-height: 1.15;
  text-align: center;
  white-space: normal;
}

.dash-legend { display: flex; flex-wrap: wrap; gap: 10px 18px; margin-top: 12px; color: #62686d; font-size: 11px; }
.dash-legend > span { max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-legend-dot { display: inline-block; width: 10px; height: 10px; margin-right: 6px; vertical-align: -1px; }

.c1 { background: #f4b400; }
.c2 { background: #a67fe0; }
.c3 { background: #0f9d84; }
.c4 { background: #a9e5c0; }
.c5 { background: #df72ca; }
.c6 { background: #2467eb; }
.c7 { background: #36b4c5; }
.c8 { background: #7040d8; }

.dash-chart-empty { display: grid; min-height: 235px; place-items: center; color: var(--ink-3); font-size: 13px; }

.dash-rank-list { display: grid; gap: 17px; margin-top: 25px; }
.dash-rank-row > div:first-child { display: flex; align-items: center; gap: 6px; }
.dash-rank-row code { overflow: hidden; flex: 1; text-overflow: ellipsis; white-space: nowrap; }
.dash-rank-row strong { font-size: 12px; font-variant-numeric: tabular-nums; }
.dash-rank-track { height: 8px; margin-top: 7px; border-radius: 99px; background: #f0f1f2; overflow: hidden; }
.dash-rank-track span { display: block; height: 100%; border-radius: inherit; }

.dash-api-body { padding: 0 13px; }
.dash-endpoint { position: relative; padding: 18px 46px 17px 47px; }
.dash-endpoint + .dash-endpoint { border-top: 1px solid #e8eaec; }
.dash-endpoint > div { display: flex; align-items: center; gap: 8px; }
.dash-endpoint-badge {
  position: absolute;
  left: 2px;
  top: 19px;
  display: grid;
  width: 34px;
  height: 34px;
  place-items: center;
  border-radius: 50%;
  background: #5ab6ff;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
}
.dash-endpoint strong { font-size: 14px; }
.dash-endpoint code {
  display: block;
  overflow: hidden;
  margin-top: 7px;
  color: #165dff;
  font-family: Georgia, serif;
  font-size: 13px;
  font-style: italic;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dash-endpoint p { margin-top: 5px; color: #5f6368; font-size: 12px; }
.dash-endpoint > .key-btn { position: absolute; right: 0; top: 18px; padding: 3px 9px; }

.dash-notices .dash-panel-head small { color: #8b9095; font-size: 11px; font-weight: 400; }
.dash-notice-list {
  max-height: 390px;
  overflow-y: auto;
  padding: 0 15px;
}
.dash-notice-item {
  display: block;
  width: 100%;
  border: 0;
  padding: 17px 2px 16px;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.dash-notice-item + .dash-notice-item { border-top: 1px solid #eceef0; }
.dash-notice-item:hover h3,
.dash-notice-item:hover .dash-notice-more { color: #2563eb; }
.dash-notice-item:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }
.dash-notice-item[data-notice-unread="1"] h3 { font-weight: 700; }
.dash-notice-item[data-notice-unread="1"] h3::before {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 7px;
  border-radius: 50%;
  background: #2563eb;
  content: "";
  vertical-align: 1px;
}
.dash-notice-more { display: inline-block; margin-top: 9px; color: #9aa0a6; font-size: 11px; }
.dash-notice-more::after { content: " ›"; }
.dash-notice-item time { color: #9aa0a6; font-size: 10px; }
.dash-notice-item h3 {
  overflow: hidden;
  margin-top: 5px;
  color: #31353a;
  font-size: 13px;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dash-notice-item p {
  display: -webkit-box;
  overflow: hidden;
  margin-top: 7px;
  color: #6b7075;
  font-size: 12px;
  line-height: 1.65;
  white-space: pre-wrap;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}
.dash-notice-empty { display: grid; min-height: 250px; place-items: center; align-content: center; gap: 8px; color: #a2a7ac; }
.dash-notice-empty span { font-size: 26px; }
.dash-notice-empty p { font-size: 12px; }

.announcement-modal {
  width: min(540px, calc(100vw - 32px));
  border: 0;
  border-radius: 16px;
  padding: 0;
  background: #fff;
  color: var(--ink);
  box-shadow: 0 28px 80px rgba(15, 23, 42, .25);
}
.announcement-modal::backdrop { background: rgba(15, 23, 42, .48); backdrop-filter: blur(2px); }
.announcement-modal-head {
  position: relative;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) 32px;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid #eceef0;
  padding: 20px 22px;
}
.announcement-icon {
  display: grid;
  width: 40px;
  height: 40px;
  place-items: center;
  border-radius: 50%;
  background: #e8f2ff;
  color: #2563eb;
  font-size: 18px;
  font-weight: 700;
}
.announcement-modal-head p { color: #2563eb; font-size: 10px; font-weight: 700; letter-spacing: .08em; }
.announcement-modal-head h2 { overflow: hidden; margin-top: 3px; font-size: 18px; text-overflow: ellipsis; white-space: nowrap; }
.announcement-modal-head button {
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: #7a7f84;
  font-size: 22px;
  cursor: pointer;
}
.announcement-modal-head button:hover { background: #f3f4f6; color: #1f2328; }
.announcement-modal-body {
  max-height: min(48vh, 420px);
  overflow-y: auto;
  padding: 24px 26px;
  color: #4b5055;
  font-size: 14px;
  line-height: 1.85;
  white-space: pre-wrap;
}
.announcement-modal-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  border-top: 1px solid #eceef0;
  padding: 14px 22px;
  background: #fafbfc;
}
.announcement-modal-meta { display: grid; min-width: 0; gap: 3px; }
.announcement-modal-foot time { color: #9aa0a6; font-size: 11px; }
.announcement-modal-meta [data-announcement-reminder] { color: #7a7f84; font-size: 11px; }
.announcement-modal-meta [data-announcement-error] { color: #c2413a; font-size: 12px; font-weight: 600; }
.announcement-modal-actions { display: flex; flex: 0 0 auto; align-items: center; gap: 8px; }
.announcement-modal-actions .btn { min-width: 82px; }
.announcement-modal-actions .btn:disabled { cursor: wait; opacity: .58; }

@media (max-width: 1250px) {
  .dash-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dash-lower { grid-template-columns: minmax(0, 2fr) minmax(270px, 1fr); }
}

@media (max-width: 899.98px) {
  .dash-topline { grid-template-columns: minmax(0, 1fr) auto; gap: 12px; }
  .dash-greeting { font-size: 22px; }
  .dash-ranges { grid-column: 1 / -1; grid-row: 2; max-width: 100%; overflow-x: auto; }
  .dash-range { min-width: 68px; }
  .dash-lower { grid-template-columns: minmax(0, 1fr); }
  .dash-analysis-body { min-height: 320px; padding: 28px 18px 20px; }
  .dash-panel-head { align-items: flex-start; flex-direction: column; padding-top: 13px; padding-bottom: 10px; }
  .dash-view-tabs { width: 100%; overflow-x: auto; }
}

@media (max-width: 560px) {
  .app[data-page="console-home"] { padding-bottom: 40px; }
  .dash-greeting { font-size: 20px; }
  .dash-cards { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .dash-card-body { padding-left: 13px; padding-right: 13px; }
  .dash-analysis-body { padding-left: 12px; padding-right: 12px; }
  .dash-chart-wrap { height: 220px; padding-left: 0; overflow-x: auto; }
  .dash-chart-bars { min-width: 720px; }
  .dash-grid-lines { left: 0; min-width: 720px; }
  .dash-legend { font-size: 10px; }
  .announcement-modal-head { padding: 17px 18px; }
  .announcement-modal-body { padding: 20px; }
  .announcement-modal-foot { align-items: stretch; flex-direction: column; gap: 10px; padding: 12px 18px; }
  .announcement-modal-actions { width: 100%; }
  .announcement-modal-actions .btn { flex: 1 1 0; min-width: 0; }
}

/* 推荐有礼 —— 邀请链接行在窄屏换行，复制按钮不被挤成一条竖线 */
/* 未开启态既不是成功也不是错误，.alert 基类本身没有边框和底色，
   不给它一个中性容器就会浮成一行无主的文字 */
.referral-terms-off {
  border: 1px solid var(--line);
  background: var(--bg-soft, #fafafa);
  color: var(--ink-2, #555);
}
.referral-terms { margin-bottom: 18px; }
.referral-link-card { margin-bottom: 18px; }
.referral-link-row {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  margin: 10px 0 6px;
}
.referral-link-input {
  flex: 1 1 320px;
  min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
}
.referral-link-row .btn { flex: 0 0 auto; }
/* 「已达上限」是解释，不是警告，所以用弱化的琥珀色而不是报错红 */
.referral-capped {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e;
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}

/* ---------- enterprise signup experience ---------- */

/* Both the plain and attributed signup routes use the same trust-first shell.
   The attributed route adds pricing without becoming a visually separate app.

   The page is built to be read without scrolling on a laptop (about 1440x800):
   one thin header row, a one-line campaign strip, a story panel whose pieces are
   each a single compact row, and a form whose paired controls (OAuth buttons,
   the two password boxes) share a line. Spacing is tight on purpose; do not
   loosen it without checking the form still fits one screen. */
.auth-signup {
  position: relative;
  justify-content: flex-start;
  gap: 12px;
  min-height: 100vh;
  padding: 14px 20px 16px;
  background:
    radial-gradient(circle at 15% 8%, rgba(4, 120, 87, .09), transparent 30%),
    radial-gradient(circle at 88% 22%, rgba(14, 116, 144, .07), transparent 27%),
    var(--tint);
}

/* Language switch rides on the brand's row instead of taking one of its own. */
.auth-signup > .lang-switch {
  position: absolute;
  top: 18px;
  right: 28px;
  margin: 0;
  justify-content: flex-end;
}

.auth-signup .signup-deal,
.auth-source .signup-deal {
  width: min(100%, 1360px);
  max-width: none;
  gap: 10px;
  padding: 8px 16px;
  border-radius: 12px;
}

.auth-signup .signup-deal .deal-title { font-size: 16px; }
.auth-signup .signup-deal .deal-note { font-size: 12px; }
.auth-signup .signup-deal .deal-off { padding: 3px 12px; font-size: 13px; }

.signup-main {
  width: min(100%, 1360px);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(400px, 440px);
  grid-template-areas: "story form";
  gap: 16px;
  align-items: stretch;
}

.signup-main-source.signup-lead-grid {
  width: min(100%, 1360px);
  grid-template-columns: minmax(0, 1fr) minmax(400px, 440px);
  grid-template-areas: "story form";
  gap: 16px;
  align-items: stretch;
}

.signup-story {
  grid-area: story;
  position: relative;
  overflow: hidden;
  display: grid;
  gap: 14px;
  /* The form decides the height; leftover room is shared between the rows. */
  align-content: space-between;
  min-width: 0;
  height: 100%;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: var(--r-lg);
  background: linear-gradient(145deg, #073f37 0%, #075b4b 58%, #0b5160 100%);
  color: #fff;
  padding: 24px 30px;
  box-shadow: 0 20px 50px rgba(5, 64, 55, .18);
}

.signup-story::after {
  content: "";
  position: absolute;
  right: -96px;
  bottom: -130px;
  width: 320px;
  height: 320px;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 50%;
  box-shadow: 0 0 0 42px rgba(255, 255, 255, .035), 0 0 0 84px rgba(255, 255, 255, .025);
  pointer-events: none;
}

.signup-story-copy,
.signup-proof,
.signup-rates,
.signup-story .signup-lead-gift { position: relative; z-index: 1; }

.signup-story-kicker {
  display: inline-flex;
  align-items: center;
  width: fit-content;
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 999px;
  background: rgba(255, 255, 255, .08);
  padding: 5px 10px;
  color: rgba(255, 255, 255, .88);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.signup-hvoy-title {
  display: block;
  width: auto;
  margin: 10px 0 0;
  color: rgba(255, 255, 255, .78);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0;
}

.signup-hvoy-title strong { color: #fff; font-weight: 720; }

.signup-story h1 {
  max-width: 620px;
  margin-top: 10px;
  font-size: clamp(26px, 2.6vw, 36px);
  font-weight: 800;
  line-height: 1.14;
  letter-spacing: -.04em;
}

.signup-story-copy > p {
  max-width: 630px;
  margin-top: 8px;
  color: rgba(255, 255, 255, .74);
  font-size: 13px;
  line-height: 1.65;
}

.signup-proof {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  margin: 0;
}

.signup-proof-item {
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 14px;
  background: rgba(255, 255, 255, .095);
  padding: 12px 16px;
  backdrop-filter: blur(4px);
}

.signup-proof-item dt {
  color: rgba(255, 255, 255, .7);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
}

.signup-proof-item dd {
  margin: 5px 0 3px;
  color: #fff;
  font-size: clamp(24px, 2.4vw, 32px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.04em;
  font-variant-numeric: tabular-nums;
}

.signup-proof-live dd { color: #a7f3d0; }

.signup-proof-item small {
  display: flex;
  align-items: center;
  gap: 6px;
  color: rgba(255, 255, 255, .62);
  font-size: 10px;
  line-height: 1.4;
}

.signup-live-dot {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #6ee7b7;
  box-shadow: 0 0 0 3px rgba(110, 231, 183, .14);
}

#signup-activity.is-updated { animation: signup-metric-pop .35s ease-out; }

@keyframes signup-metric-pop {
  0% { opacity: .55; transform: translateY(2px); }
  100% { opacity: 1; transform: translateY(0); }
}

/* The gift is one row: chip, amount, then the sentence. */
.signup-story .signup-lead-gift {
  width: auto;
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  grid-template-areas: "badge amount copy";
  align-items: center;
  gap: 14px;
  margin: 0;
  border: 1px solid rgba(253, 230, 138, .86);
  border-radius: 14px;
  background: linear-gradient(110deg, #fff7d6 0%, #fde68a 100%);
  padding: 12px 18px;
  color: #713f12;
  box-shadow: 0 12px 28px rgba(3, 31, 27, .18);
}

.signup-gift-badge {
  grid-area: badge;
  width: fit-content;
  border-radius: 999px;
  background: #b45309;
  padding: 4px 9px;
  color: #fff;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .08em;
  white-space: nowrap;
}

.signup-story .signup-gift-amount {
  grid-area: amount;
  min-width: 0;
  color: #92400e;
  font-size: 34px;
}

.signup-story .signup-gift-copy { grid-area: copy; gap: 2px; }
.signup-story .signup-gift-copy strong { color: #78350f; font-size: 16px; }
.signup-story .signup-gift-copy small { color: rgba(120, 53, 15, .78); font-size: 11px; }

.signup-main .signup-lead-form {
  grid-area: form;
  width: 100%;
  max-width: none;
  height: 100%;
  align-self: stretch;
  position: sticky;
  top: 18px;
  border-color: rgba(15, 76, 92, .12);
  box-shadow: 0 18px 42px rgba(15, 76, 92, .11);
}

/* ---- the form card ---- */

.signup-main .auth-card { padding: 20px 26px 16px; }
.signup-main .auth-h { font-size: 21px; }
.signup-main .auth-sub { margin: 4px 0 12px; font-size: 12px; line-height: 1.55; }

.signup-main .form { gap: 9px; }
.signup-main .field { gap: 4px; }
.signup-main .field-label { font-size: 12px; }
.signup-main .input { padding: 9px 12px; font-size: 14px; }
.signup-main .field-hint { font-size: 11px; line-height: 1.45; }
.signup-main .btn-block { padding: 11px; margin-top: 2px; }
.signup-main .auth-foot { margin-top: 10px; padding-top: 10px; }

/* Google and GitHub share a line; the divider spans both. */
.signup-main .oauth-entry { gap: 8px; margin-bottom: 8px; }
.signup-main .oauth-entry .auth-divider { margin-top: 2px; }
.signup-main .oauth-entry-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.signup-main .oauth-entry-pair .auth-divider { grid-column: 1 / -1; }
.signup-main .btn-google,
.signup-main .btn-github {
  min-height: 40px;
  padding: 0 10px 0 38px;
  font-size: 13px;
}
.signup-main .google-mark { left: 12px; }

.field-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

/* The invite-code hint only speaks when it has something to say (the code is
   valid, or matches nobody); its idle sentence just costs a line. */
#aff-hint:not(.aff-ok):not(.aff-warn) { display: none; }

.auth-signup .auth-alt { margin-top: 0; }

/* A shorter window gives up the redundant extras before anything scrolls. */
@media (min-width: 901px) and (max-height: 820px) {
  .auth-signup .auth-alt { display: none; }
}

@media (min-width: 901px) and (max-height: 740px) {
  .signup-main .auth-sub { display: none; }
  .signup-main .auth-h { margin-bottom: 10px; }
  .signup-main .auth-card { padding-top: 16px; }
}

/* A 1366x768 laptop leaves about 650px under the browser's own chrome. */
@media (min-width: 901px) and (max-height: 700px) {
  .auth-signup { gap: 10px; padding-top: 10px; padding-bottom: 10px; }
  .auth-signup > .lang-switch { top: 14px; }
  .signup-main .auth-card { padding: 12px 24px 10px; }
  .signup-main .auth-h { margin-bottom: 8px; }
  .signup-main .form { gap: 7px; }
  .signup-main .input { padding: 7px 12px; }
  .signup-main .btn-block { padding: 9px; }
  .signup-main .btn-google,
  .signup-main .btn-github { min-height: 36px; }
  .signup-main .auth-foot { margin-top: 8px; padding-top: 8px; }
}

@media (max-width: 900px) {
  .auth-signup .signup-deal,
  .auth-source .signup-deal,
  .signup-main,
  .signup-main-source.signup-lead-grid { width: min(100%, 560px); }

  /* Stacked, the form comes first: it is what the visitor came for, and the
     price board is the supporting argument underneath it. */
  .signup-main,
  .signup-main-source.signup-lead-grid {
    grid-template-columns: 1fr;
    grid-template-areas:
      "form"
      "story";
  }

  .signup-story { height: auto; gap: 12px; padding: 18px 20px; }
  .signup-story-copy > p { display: none; }
  .signup-main .signup-lead-form { height: auto; position: static; }
}

@media (max-width: 600px) {
  .auth-signup { gap: 10px; padding: 12px 12px 18px; }
  .auth-signup > .lang-switch { top: 16px; right: 14px; }
  .signup-story h1 { font-size: 24px; }

  /* Three small tiles in a row rather than a column of big ones. */
  .signup-proof { gap: 8px; }
  .signup-proof-item { padding: 9px 10px; border-radius: 12px; }
  .signup-proof-item dt { font-size: 11px; white-space: normal; }
  .signup-proof-item dd { margin: 4px 0 0; font-size: 20px; }
  .signup-proof-item small { display: none; }

  .signup-story .signup-lead-gift { gap: 10px; padding: 10px 14px; }
  .signup-story .signup-gift-amount { font-size: 28px; }
  .signup-story .signup-gift-copy strong { font-size: 14px; }
  .signup-story .signup-gift-copy small { display: none; }

  .signup-main .auth-card { padding: 18px 16px 14px; }
}


/* ---------- price board (home + sign-up) ----------
   One tile per token group (倍率 and 折) and one row per vendor's headline
   model. The home page shows it on paper, the sign-up page inside the dark
   story card; the dark variant only recolours the same markup. */
.rate-toggle { position: absolute; opacity: 0; pointer-events: none; }
.rate-expand { display: none; }
.rate-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
.rate-card {
  min-width: 0;
  display: grid;
  gap: 7px;
  border: 1px solid var(--line-2);
  border-radius: 14px;
  background: #fff;
  padding: 12px 14px;
}
.rate-top, .rate-bot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-width: 0;
}
.rate-name {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
}
.rate-name > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rate-dot { flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; background: #9ca3af; }
.rate-dot-amber { background: #f59e0b; } .rate-dot-blue { background: #3b82f6; }
.rate-dot-cyan { background: #06b6d4; } .rate-dot-green { background: #10b981; }
.rate-dot-grey { background: #9ca3af; } .rate-dot-indigo { background: #6366f1; }
.rate-dot-light-blue { background: #38bdf8; } .rate-dot-lime { background: #84cc16; }
.rate-dot-orange { background: #f97316; } .rate-dot-pink { background: #ec4899; }
.rate-dot-purple { background: #a855f7; } .rate-dot-red { background: #ef4444; }
.rate-dot-teal { background: #14b8a6; } .rate-dot-violet { background: #8b5cf6; }
.rate-dot-yellow { background: #eab308; }
.rate-mult {
  flex: 0 0 auto;
  color: var(--green);
  font-size: 21px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
}
.rate-mult-text { color: var(--ink-2); font-size: 12px; font-weight: 700; letter-spacing: 0; }
.rate-models {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-3);
  font-family: var(--mono);
  font-size: 11.5px;
}
.rate-off {
  flex: 0 0 auto;
  border-radius: 999px;
  background: #fff3d6;
  padding: 2px 9px;
  color: #92400e;
  font-size: 11.5px;
  font-style: normal;
  font-weight: 700;
  white-space: nowrap;
}

/* Headline models: name | group | input / output | 折. */
.mrows { border: 1px solid var(--line-2); border-radius: 16px; background: #fff; overflow: hidden; }
.mrow {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1.2fr) minmax(0, 1fr) 120px;
  align-items: center;
  gap: 12px;
  padding: 11px 18px;
  border-top: 1px solid var(--line);
  font-size: 14px;
}
.mrow:first-child { border-top: 0; }
.mrow-head { background: var(--tint); color: var(--ink-2); font-size: 12px; font-weight: 600; }
.mrow-name { display: grid; gap: 1px; min-width: 0; }
.mrow-name code { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13.5px; font-weight: 600; }
.mrow-name small { color: var(--ink-3); font-size: 11.5px; }
.mrow-grp { min-width: 0; }
.mrow-grp .ntag { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mrow-price { font-variant-numeric: tabular-nums; white-space: nowrap; }
.mrow-price b { font-weight: 700; }
.mrow-price i { margin: 0 5px; color: var(--ink-3); font-style: normal; }
.mrow-head .mrow-price { font-variant-numeric: normal; }
.mrow-off { text-align: right; color: #92400e; font-weight: 700; white-space: nowrap; }
.mrow-head .mrow-off { color: var(--ink-2); font-weight: 600; }

/* ---------- home page ---------- */
.hp-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
  gap: 16px;
  margin-top: 16px;
  align-items: stretch;
}
/* Without a campaign poster the hero is one dark card holding the text and the
   vendor comparison; with one, the text card and the poster stay separate. */
.hp-hero-card {
  position: relative;
  overflow: hidden;
  grid-template-columns: minmax(0, 1.1fr) minmax(320px, .9fr);
  gap: 40px;
  align-items: center;
  border-radius: var(--r-lg);
  background:
    radial-gradient(circle at 8% 0%, rgba(110, 231, 183, .24), transparent 42%),
    radial-gradient(circle at 100% 100%, rgba(56, 189, 248, .2), transparent 46%),
    linear-gradient(145deg, #073f37 0%, #075b4b 58%, #0b5160 100%);
  color: #fff;
  padding: 40px 44px;
  box-shadow: 0 20px 50px rgba(5, 64, 55, .18);
}
.hp-hero-card::after {
  content: "";
  position: absolute;
  right: -110px;
  bottom: -150px;
  width: 340px;
  height: 340px;
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: 50%;
  box-shadow: 0 0 0 44px rgba(255, 255, 255, .03), 0 0 0 88px rgba(255, 255, 255, .02);
  pointer-events: none;
}
.hp-hero-card > * { position: relative; z-index: 1; }
.hp-hero:not(.hp-hero-card) .hp-hero-main {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: linear-gradient(145deg, #073f37 0%, #075b4b 58%, #0b5160 100%);
  color: #fff;
  padding: 32px 36px;
  box-shadow: 0 20px 50px rgba(5, 64, 55, .18);
}
.hp-hero-main { display: grid; align-content: center; justify-items: start; gap: 20px; min-width: 0; }
.hp-hero h1 {
  margin: 0;
  font-size: clamp(28px, 3.3vw, 46px);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -.04em;
  text-wrap: balance;
}
.hp-hero h1 .g { color: #a7f3d0; }
.hp-h1-sub {
  display: block;
  margin-top: 12px;
  color: #a7f3d0;
  font-size: clamp(16px, 1.5vw, 20px);
  font-weight: 600;
  letter-spacing: 0;
}
.hp-hero-act { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.hp-gift {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  border-radius: 999px;
  background: linear-gradient(110deg, #fff7d6 0%, #fde68a 100%);
  padding: 14px 26px;
  color: #78350f;
  font-size: 16px;
  font-weight: 700;
  box-shadow: 0 12px 28px rgba(3, 31, 27, .26);
}
.hp-gift b { color: #92400e; font-size: 21px; font-weight: 800; }
.hp-gift:hover { filter: brightness(1.03); }
.hp-ghost {
  display: inline-flex;
  align-items: center;
  border: 1px solid rgba(255, 255, 255, .34);
  border-radius: 999px;
  padding: 13px 22px;
  color: #fff;
  font-size: 15px;
  font-weight: 600;
}
.hp-ghost:hover { background: rgba(255, 255, 255, .1); }
.hp-ticks { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 0; padding: 0; list-style: none; }
.hp-ticks li { position: relative; padding-left: 18px; color: rgba(255, 255, 255, .74); font-size: 12.5px; }
.hp-ticks li::before { content: "✓"; position: absolute; left: 0; color: #a7f3d0; font-weight: 800; }

/* Vendor comparison: the bar is our price as a share of the official price. */
.hp-panel {
  display: grid;
  gap: 16px;
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 20px;
  background: rgba(255, 255, 255, .08);
  padding: 20px 22px;
  backdrop-filter: blur(6px);
}
.hp-panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.hp-panel-head b { font-size: 14.5px; }
.hp-panel-head span { color: rgba(255, 255, 255, .6); font-size: 11.5px; }
.hp-vendors { display: grid; gap: 13px; margin: 0; padding: 0; list-style: none; }
.hp-vendors li {
  display: grid;
  grid-template-columns: 104px minmax(0, 1fr) 96px;
  align-items: center;
  gap: 12px;
}
.hp-v-name { display: flex; align-items: center; gap: 8px; font-size: 13.5px; font-weight: 600; white-space: nowrap; }
.hp-v-ico {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #fff;
}
.hp-v-ico img { width: 15px; height: 15px; }
.hp-v-bar {
  position: relative;
  height: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, .14);
  overflow: hidden;
}
.hp-v-bar i {
  position: absolute;
  inset: 0 auto 0 0;
  border-radius: inherit;
  background: linear-gradient(90deg, #6ee7b7, #34d399);
}
.hp-v-off { color: #fde68a; font-size: 12.5px; font-weight: 700; text-align: right; white-space: nowrap; }

.hp-urlbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 12px;
  margin-top: 12px;
  border: 1px solid var(--line-2);
  border-radius: 14px;
  background: #fff;
  padding: 10px 16px;
}
.hp-url-label { color: var(--ink-2); font-size: 12.5px; font-weight: 600; }
.hp-urlbar code { border-radius: 8px; background: var(--tint); padding: 4px 10px; font-family: var(--mono); font-size: 13px; }
.hp-urlbar a { margin-left: auto; color: var(--green); font-size: 14px; font-weight: 600; }
.hp-urlbar .copy {
  border: 1px solid var(--line-3);
  border-radius: 8px;
  background: #fff;
  padding: 4px 12px;
  color: var(--green);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.hp-urlbar .copy:hover { background: var(--tint-2); }

.hp-sec { margin-top: 40px; }
.hp-sec-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; margin-bottom: 14px; }
.hp-sec-head h2 { margin: 0; font-size: 22px; letter-spacing: -.02em; }
.hp-sec-head p { margin: 0; color: var(--ink-2); font-size: 13px; }
.hp-sec-head a { margin-left: auto; color: var(--green); font-size: 14px; font-weight: 600; }
.hp-service { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.hp-service:has(> :only-child) { grid-template-columns: minmax(0, 1fr); }
.svc-card {
  display: flex;
  align-items: center;
  gap: 14px;
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  background: #fff;
  padding: 16px 18px;
}
.svc-card > .ico { flex: 0 0 auto; width: 28px; height: 28px; stroke: var(--green); }
.svc-qr { flex: 0 0 auto; width: 72px; height: 72px; border-radius: 8px; }
.svc-body { flex: 1 1 auto; min-width: 0; }
.svc-body h3 { margin: 0; font-size: 15px; }
.svc-body h3 code { margin-left: 4px; font-size: 13px; }
.svc-body p { margin: 2px 0 0; color: var(--ink-2); font-size: 12.5px; line-height: 1.55; }

/* ---------- sign-up story card ---------- */
.signup-rates { display: grid; gap: 10px; }
.signup-rates-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; }
.signup-rates-head h2 { margin: 0; color: #fff; font-size: 15px; font-weight: 700; }
.signup-rates-head span { color: rgba(255, 255, 255, .6); font-size: 12px; }
.signup-rates-head a { margin-left: auto; color: #a7f3d0; font-size: 12.5px; font-weight: 600; }
.signup-rates .rate-grid { gap: 8px; }
.signup-rates .rate-card {
  gap: 4px;
  border-color: rgba(255, 255, 255, .18);
  background: rgba(255, 255, 255, .095);
  padding: 9px 12px;
}
.signup-rates .rate-name { color: #fff; font-size: 13px; }
.signup-rates .rate-mult { color: #a7f3d0; font-size: 18px; }
.signup-rates .rate-mult-text { color: rgba(255, 255, 255, .75); font-size: 11.5px; }
.signup-rates .rate-models { color: rgba(255, 255, 255, .55); font-size: 11px; }
.signup-rates .rate-off { background: rgba(253, 230, 138, .18); color: #fde68a; font-size: 11px; padding: 1px 8px; }
.signup-rates .rate-expand { color: #a7f3d0; }
/* The tile is narrow once the 折 pill is on the same line: one model name. */
.signup-rates .rate-m2 { display: none; }

@media (max-width: 899.98px) {
  .hp-hero, .hp-hero-card { grid-template-columns: minmax(0, 1fr); }
  .hp-hero-card { gap: 28px; }
  .rate-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .hp-hero-card { padding: 26px 20px; }
  .hp-hero:not(.hp-hero-card) .hp-hero-main { padding: 24px 20px; }
  .hp-hero h1 { font-size: 28px; }
  .hp-panel { padding: 16px; }
  .hp-vendors li { grid-template-columns: 92px minmax(0, 1fr) auto; gap: 10px; }
  .hp-urlbar a { margin-left: 0; }
  .hp-gift { padding: 11px 18px; font-size: 14px; }
  .hp-sec { margin-top: 30px; }
  .hp-sec-head h2 { font-size: 19px; }
  .hp-service { grid-template-columns: minmax(0, 1fr); }
  .rate-grid { grid-template-columns: minmax(0, 1fr); }
  .rate-more { display: none; }
  .rate-toggle:checked ~ .rate-grid .rate-more { display: grid; }
  .rate-expand {
    display: block;
    margin-top: 8px;
    border: 1px dashed var(--line-3);
    border-radius: 12px;
    padding: 9px;
    color: var(--green);
    font-size: 13px;
    font-weight: 600;
    text-align: center;
    cursor: pointer;
  }
  .rate-toggle:checked ~ .rate-expand { display: none; }
  .mrow-head { display: none; }
  .mrow {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "name price" "grp off";
    row-gap: 6px;
    padding: 12px 14px;
  }
  .mrow-name { grid-area: name; }
  .mrow-price { grid-area: price; text-align: right; }
  .mrow-grp { grid-area: grp; }
  .mrow-off { grid-area: off; }
}

@media (prefers-reduced-motion: reduce) {
  #signup-activity.is-updated { animation: none; }
}


/* The proof strip sits under the price board as a footnote-sized row. */
.signup-story .signup-proof { gap: 8px; }
.signup-story .signup-proof-item { padding: 8px 12px; border-radius: 12px; }
.signup-story .signup-proof-item dt { font-size: 11px; }
.signup-story .signup-proof-item dd { margin: 3px 0 2px; font-size: clamp(18px, 1.7vw, 22px); }
.signup-story .signup-proof-item small { font-size: 10px; }
