/* FastCheck — terminal-dark, loud where it counts.
   The verdict colours are the only palette; everything else is greyscale, so
   TRUE / FALSE / UNVERIFIED read instantly wherever they appear. */

:root {
  --bg: #060608;
  --panel: #0d0d10;
  --panel-2: #121216;
  --line: rgba(255, 255, 255, 0.09);
  --line-2: rgba(255, 255, 255, 0.14);
  --text: rgba(255, 255, 255, 0.94);
  --muted: rgba(255, 255, 255, 0.48);
  --faint: rgba(255, 255, 255, 0.26);

  --accent: #5b9cf6;
  --accent-2: #a78bfa;

  --true: #22c55e;
  --false: #ef4444;
  --unverified: #f59e0b;
  --danger: #f87171;

  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Inter, sans-serif;

  --r: 14px;
}

* { box-sizing: border-box; }

/* The `hidden` attribute is only a user-agent style, so ANY class that sets
   display beats it. .topup-row { display: flex } was doing exactly that: the
   attribute said hidden, the element rendered as an empty bordered box under
   the plans. Making it explicit fixes every case rather than that one. */
[hidden] { display: none !important; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a { color: inherit; }
.hidden { display: none !important; }
.muted { color: var(--muted); }
.small { font-size: 12.5px; }
.centered { text-align: center; }

/* ── Reveal ──────────────────────────────────────────────────────────────── */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .6s cubic-bezier(.2,.7,.3,1), transform .6s cubic-bezier(.2,.7,.3,1);
  transition-delay: var(--d, 0ms);
}
.reveal.in { opacity: 1; transform: none; }

/* Motion is decoration here — the page must read identically without it. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* ── Backdrop ────────────────────────────────────────────────────────────── */
.grid-bg {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(255,255,255,0.028) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.028) 1px, transparent 1px);
  background-size: 62px 62px;
  mask-image: radial-gradient(ellipse 90% 55% at 50% 0%, #000 35%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 90% 55% at 50% 0%, #000 35%, transparent 78%);
}
.landing::before {
  content: '';
  position: fixed; z-index: 0; pointer-events: none;
  top: -30vh; left: 50%; transform: translateX(-50%);
  width: 120vw; height: 80vh;
  background: radial-gradient(ellipse at center, rgba(91,156,246,0.14), transparent 62%);
  filter: blur(20px);
}
.landing main, .landing .nav, .landing .foot { position: relative; z-index: 1; }

/* ── Nav ─────────────────────────────────────────────────────────────────── */
.nav {
  max-width: 1120px; margin: 0 auto; padding: 26px 28px;
  display: flex; align-items: center; justify-content: space-between;
}
.logo, .logo-sm { font-weight: 700; letter-spacing: -0.02em; }
.logo { font-size: 17px; }
.logo-sm { font-size: 14px; }
.nav-cta {
  font-size: 13.5px; color: var(--muted); text-decoration: none;
  padding: 7px 14px; border: 1px solid var(--line); border-radius: 9px;
  transition: color .15s, border-color .15s, background .15s;
}
.nav-cta:hover { color: var(--text); border-color: var(--line-2); background: rgba(255,255,255,0.04); }

/* ── Hero ────────────────────────────────────────────────────────────────── */
.hero {
  max-width: 1120px; margin: 0 auto; padding: 56px 28px 96px;
  display: grid; grid-template-columns: 1.02fr 0.98fr;
  gap: 64px; align-items: center;
}
.eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .04em;
  color: var(--muted);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 5px 13px; margin-bottom: 26px;
}
.dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--true);
  animation: pulse 2.4s ease-out infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(34,197,94,.5); }
  70%  { box-shadow: 0 0 0 7px rgba(34,197,94,0); }
  100% { box-shadow: 0 0 0 0 rgba(34,197,94,0); }
}

h1 {
  font-size: clamp(42px, 6.4vw, 74px);
  line-height: .98; letter-spacing: -.045em; font-weight: 800;
  margin: 0 0 22px;
  text-wrap: balance;
}
.grad {
  background: linear-gradient(100deg, var(--accent), var(--accent-2) 55%, var(--true));
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.lede { color: var(--muted); font-size: 17px; max-width: 46ch; margin: 0 0 30px; }

.cta-row { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.cta-note { color: var(--faint); font-size: 12.5px; }

.btn-primary {
  display: inline-flex; align-items: center; gap: 10px;
  background: #fff; color: #101014;
  font-weight: 650; font-size: 14.5px;
  padding: 13px 22px; border-radius: 11px; text-decoration: none;
  transition: transform .15s cubic-bezier(.2,.7,.3,1), box-shadow .15s;
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 10px 34px -12px rgba(255,255,255,.4); }
.btn-primary.big { font-size: 16px; padding: 16px 30px; }

.error {
  background: rgba(248,113,113,.09);
  border: 1px solid rgba(248,113,113,.28);
  color: #fca5a5;
  border-radius: 10px; padding: 10px 14px;
  font-size: 13px; margin-bottom: 20px; max-width: 46ch;
}

/* ── Hero demo ───────────────────────────────────────────────────────────── */
.demo {
  border: 1px solid var(--line); border-radius: 18px;
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  overflow: hidden;
  box-shadow: 0 40px 90px -40px rgba(0,0,0,.9), 0 0 0 1px rgba(255,255,255,.02) inset;
}
.demo-chrome {
  display: flex; align-items: center; gap: 7px;
  padding: 12px 15px; border-bottom: 1px solid var(--line);
  background: rgba(255,255,255,.018);
}
.demo-dot { width: 9px; height: 9px; border-radius: 50%; background: rgba(255,255,255,.13); }
.demo-label { margin-left: 8px; font-family: var(--mono); font-size: 11.5px; color: var(--faint); }
.demo-body { padding: 18px; }

.post { border-bottom: 1px solid var(--line); padding-bottom: 15px; }
.post-head { display: flex; gap: 11px; align-items: center; margin-bottom: 11px; }
.avatar { width: 38px; height: 38px; border-radius: 50%; flex-shrink: 0; transition: background .4s; }
.post-name { font-weight: 650; font-size: 14px; }
.post-handle { color: var(--faint); font-size: 12.5px; font-family: var(--mono); }
.post-text {
  font-size: 14px; line-height: 1.6; margin: 0 0 14px;
  white-space: pre-wrap; color: rgba(255,255,255,.86);
}

.fc-btn-demo {
  display: inline-flex; align-items: center; gap: 6px;
  background: #141418; color: var(--text);
  border: 1px solid var(--line-2); border-radius: 20px;
  padding: 6px 14px; font-size: 12.5px; font-weight: 550;
  font-family: inherit; cursor: default;
}
.fc-btn-demo.is-busy { color: var(--muted); }
.fc-btn-demo.is-busy svg { animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.verdict { padding-top: 16px; }
.verdict.in { animation: rise .45s cubic-bezier(.2,.7,.3,1) both; }
@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

.verdict-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.verdict-eyebrow {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--faint);
}
.verdict-conf { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.verdict-badge {
  display: inline-block; font-family: var(--mono);
  font-size: 12px; font-weight: 700; letter-spacing: .09em;
  padding: 5px 12px; border-radius: 7px;
  border: 1px solid transparent; margin-bottom: 12px;
}
.verdict-bar { height: 2px; background: rgba(255,255,255,.07); border-radius: 2px; overflow: hidden; margin-bottom: 14px; }
.verdict-bar-fill { height: 100%; width: 0; transition: width 1s cubic-bezier(.2,.7,.3,1); }
.verdict-summary { font-size: 13.5px; line-height: 1.62; color: rgba(255,255,255,.74); margin: 0 0 14px; }
/* The demo card is held at the height of its tallest frame (see landing.js), so
   the page below it never moves. That leaves the verdict slot empty while the
   check is "running" — this fills it the way the extension's own loading state
   does, instead of showing a black gap half the height of the card. */
.verdict-skel { padding-top: 16px; }
.verdict-skel .verdict-eyebrow { display: block; margin-bottom: 12px; }
.skel-badge { height: 25px; width: 86px; border-radius: 7px; margin-bottom: 16px; }
.skel-line { height: 9px; border-radius: 5px; margin-bottom: 11px; }
.skel-chips { display: flex; gap: 7px; margin-top: 17px; }
.skel-chip { height: 22px; width: 96px; border-radius: 6px; }
.skel-badge, .skel-line, .skel-chip { background: rgba(255,255,255,.045); }

.demo.is-scanning .skel-badge,
.demo.is-scanning .skel-line,
.demo.is-scanning .skel-chip {
  background: linear-gradient(90deg,
    rgba(255,255,255,.045) 0%, rgba(255,255,255,.115) 50%, rgba(255,255,255,.045) 100%);
  background-size: 220% 100%;
  animation: shimmer 1.5s linear infinite;
}
@keyframes shimmer { from { background-position: 220% 0; } to { background-position: -220% 0; } }

@media (prefers-reduced-motion: reduce) {
  .demo.is-scanning .skel-badge,
  .demo.is-scanning .skel-line,
  .demo.is-scanning .skel-chip { animation: none; }
}

.verdict-sources { display: flex; flex-wrap: wrap; gap: 7px; }
.verdict-source {
  font-family: var(--mono); font-size: 11px; color: var(--accent);
  border: 1px solid var(--line); border-radius: 6px; padding: 3px 9px;
}

/* ── Bands ───────────────────────────────────────────────────────────────── */
.band { max-width: 1120px; margin: 0 auto; padding: 84px 28px; }
.section-head { margin-bottom: 44px; }
.section-head h2 {
  font-size: clamp(27px, 3.4vw, 38px);
  letter-spacing: -.032em; line-height: 1.12; font-weight: 750;
  margin: 0 0 12px;
  /* Measured in em so the limit scales with the heading itself. On the parent
     this was 60ch of the 15px body text, which forced a two-word second line. */
  max-width: 18em;
  text-wrap: balance;
}
.section-head p { color: var(--muted); margin: 0; font-size: 16px; max-width: 58ch; }

.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.step { border: 1px solid var(--line); border-radius: var(--r); padding: 24px; background: var(--panel); }
.step-n { font-family: var(--mono); font-size: 11.5px; color: var(--accent); letter-spacing: .08em; }
.step h3 { font-size: 16px; font-weight: 650; margin: 12px 0 6px; letter-spacing: -.015em; }
.step p { color: var(--muted); font-size: 13.5px; margin: 0; }

.verdict-legend { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
.legend-item { border: 1px solid var(--line); border-radius: var(--r); padding: 22px; background: var(--panel); }
.legend-badge {
  display: inline-block; font-family: var(--mono);
  font-size: 11.5px; font-weight: 700; letter-spacing: .09em;
  padding: 4px 11px; border-radius: 6px; margin-bottom: 12px;
  border: 1px solid transparent;
}
.is-true       { color: var(--true);       background: rgba(34,197,94,.1);    border-color: rgba(34,197,94,.3); }
.is-false      { color: var(--false);      background: rgba(239,68,68,.1);    border-color: rgba(239,68,68,.3); }
.is-unverified { color: var(--unverified); background: rgba(245,158,11,.1);   border-color: rgba(245,158,11,.3); }
.is-noclaim    { color: var(--muted);      background: rgba(255,255,255,.05); border-color: var(--line); }
.legend-item p { color: var(--muted); font-size: 13.5px; margin: 0; }

/* ── Safety ──────────────────────────────────────────────────────────────
   Green here is deliberate and matches TRUE in the verdict palette: on this
   site green means "checked and it holds up", and that is exactly the claim
   this section is making about the extension itself. */
.band-tag {
  display: inline-block; font-family: var(--mono);
  font-size: 10px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--true); margin-bottom: 14px;
  padding: 4px 10px; border-radius: 6px;
  background: rgba(34,197,94,.08); border: 1px solid rgba(34,197,94,.22);
}

.trust-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px; }
.trust-item {
  position: relative;
  border: 1px solid var(--line); border-radius: var(--r);
  padding: 22px 22px 22px 58px; background: var(--panel);
}
.trust-tick {
  position: absolute; left: 21px; top: 22px;
  width: 20px; height: 20px; color: var(--true);
}
.trust-item h3 {
  font-size: 15.5px; font-weight: 650; margin: 0 0 7px;
  letter-spacing: -.015em; line-height: 1.35;
}
.trust-item p { color: var(--muted); font-size: 13.5px; margin: 0; }

#safety .small.centered { margin-top: 26px; }

/* The same assurance on the checkout card. .trust-tick is absolutely positioned
   for the landing grid, so it has to be put back in flow here. */
.pay-safe {
  display: flex; gap: 9px; align-items: flex-start;
  color: var(--muted); font-size: 12.5px; line-height: 1.55;
  margin: 16px 0 0; padding-top: 15px; border-top: 1px solid var(--line);
}
.pay-safe .trust-tick {
  position: static; width: 15px; height: 15px;
  flex-shrink: 0; margin-top: 3px;
}

/* ── What it costs ───────────────────────────────────────────────────────
   Numbers first, prose second. The figures are the argument — a measured cost
   next to a charged price is more persuasive than any sentence about value. */
.cost-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.cost-item {
  border: 1px solid var(--line); border-radius: var(--r);
  padding: 24px 22px; background: var(--panel);
  display: flex; flex-direction: column;
}
.cost-figure {
  font-size: clamp(28px, 3.6vw, 38px); font-weight: 800;
  letter-spacing: -.04em; line-height: 1;
  color: var(--text);
}
.cost-to { opacity: .45; margin: 0 2px; font-weight: 500; }
.cost-label {
  font-family: var(--mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--faint);
  margin: 12px 0 10px;
}
.cost-item p { color: var(--muted); font-size: 13.5px; margin: 0; line-height: 1.6; }

.cost-close {
  margin: 26px auto 0; max-width: 62ch; text-align: center;
  color: var(--muted); font-size: 14.5px; line-height: 1.65;
}

/* ── Pricing ─────────────────────────────────────────────────────────────── */
.tiers { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 22px; }
.tier {
  position: relative;
  border: 1px solid var(--line); border-radius: var(--r);
  padding: 26px 22px; background: var(--panel);
  display: flex; flex-direction: column;
  transition: transform .18s cubic-bezier(.2,.7,.3,1), border-color .18s;
}
.tier:hover { transform: translateY(-3px); border-color: var(--line-2); }
.tier.is-popular {
  border-color: rgba(91,156,246,.42);
  background: linear-gradient(180deg, rgba(91,156,246,.07), var(--panel) 55%);
}
.tier-tag {
  position: absolute; top: -10px; left: 22px;
  background: var(--accent); color: #06121f;
  font-size: 10px; font-weight: 700; letter-spacing: .05em;
  padding: 3px 10px; border-radius: 999px;
}
.tier-name { font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.tier-price { font-size: 36px; font-weight: 780; letter-spacing: -.04em; margin: 10px 0 2px; }
.tier-per { font-size: 14px; font-weight: 500; color: var(--faint); letter-spacing: 0; margin-left: 3px; }
.tier-credits { font-size: 13.5px; margin-bottom: 10px; }
.tier-blurb { color: var(--faint); font-size: 12.5px; line-height: 1.5; margin: 0 0 20px; flex: 1; }
.tier-cta {
  display: block; text-align: center; text-decoration: none;
  border: 1px solid var(--line-2); border-radius: 9px;
  padding: 10px; font-size: 13.5px; font-weight: 600;
  transition: background .15s, border-color .15s;
}
.tier-cta:hover { background: rgba(255,255,255,.06); }
.tier-cta.is-primary { background: var(--accent); border-color: var(--accent); color: #06121f; }
.tier-cta.is-primary:hover { opacity: .9; }

/* ── Closer ──────────────────────────────────────────────────────────────── */
.closer { text-align: center; padding: 96px 28px 110px; }
.closer h2 {
  text-wrap: balance;
  font-size: clamp(32px, 5vw, 54px);
  letter-spacing: -.042em; line-height: 1.04; font-weight: 800;
  margin: 0 0 30px;
}

.hero-copy .link-btns { margin-top: 26px; }
.closer-sub { color: var(--muted); margin: -14px 0 30px; }
.dash .link-btns { margin-top: 2px; }

.foot {
  max-width: 1120px; margin: 0 auto; padding: 26px 28px 44px;
  border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: center;
}
.foot-links { display: flex; gap: 20px; }
.foot a { color: var(--faint); font-size: 12.5px; text-decoration: none; }
.foot a:not(.is-pending):hover { color: var(--muted); }
.foot-narrow { max-width: 880px; padding: 26px 24px 44px; }
.foot-brand { display: flex; flex-direction: column; gap: 3px; }
.foot-tag {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .07em;
  color: var(--faint);
}

/* Marks the Chrome Web Store link until the extension is published. links.js
   removes the href, so this only has to stop it looking clickable. */
.is-pending { color: var(--faint); cursor: default; }

/* ══ Link buttons ════════════════════════════════════════════════════════
   In the hero and on the dashboard, not only in the footer — nobody goes
   looking in a footer for the Discord. Each one lights up in its own brand
   colour on hover; at rest they stay greyscale so they do not compete with
   the verdict colours, which are the only palette that carries meaning. */
.link-btns { display: flex; flex-wrap: wrap; gap: 10px; }

/* The buy button sits among the social links but is not one of them, so it
   carries the token's colour rather than the neutral border the others share.
   Loud enough to find, quiet enough that it is not competing with "Start with
   3 free checks" on the landing page — that is still the thing to click first. */
.link-btn.lb-pons {
  border-color: rgba(34, 197, 94, .35);
  background: rgba(34, 197, 94, .08);
  color: var(--true);
  font-weight: 600;
}
.link-btn.lb-pons:hover {
  border-color: rgba(34, 197, 94, .55);
  background: rgba(34, 197, 94, .14);
}
.link-btn.lb-pons svg { width: 15px; height: 15px; }
.link-btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 10px 15px; border-radius: 11px;
  border: 1px solid var(--line);
  background: rgba(255,255,255,.028);
  color: var(--text); text-decoration: none;
  font-size: 13.5px; font-weight: 600; line-height: 1;
  transition: transform .18s ease, border-color .18s ease,
              background .18s ease, box-shadow .18s ease;
}
.link-btn svg {
  width: 16px; height: 16px; flex-shrink: 0;
  fill: var(--muted); transition: fill .18s ease;
}
.link-btn:hover {
  transform: translateY(-2px);
  border-color: var(--line-2);
  background: rgba(255,255,255,.06);
}
.link-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.lb-chrome:hover  { box-shadow: 0 10px 28px -14px rgba(66,133,244,.8); }
.lb-chrome:hover svg  { fill: #4285F4; }
.lb-discord:hover { box-shadow: 0 10px 28px -14px rgba(88,101,242,.9); }
.lb-discord:hover svg { fill: #5865F2; }
.lb-x:hover       { box-shadow: 0 10px 28px -14px rgba(255,255,255,.45); }
.lb-x:hover svg       { fill: var(--text); }

.link-btn.is-pending { color: var(--muted); opacity: .55; }
.link-btn.is-pending:hover {
  transform: none; box-shadow: none;
  border-color: var(--line); background: rgba(255,255,255,.028);
}
.link-btn.is-pending:hover svg { fill: var(--muted); }

@media (prefers-reduced-motion: reduce) {
  .link-btn { transition: none; }
  .link-btn:hover { transform: none; }
}

@media (max-width: 940px) {
  .hero { grid-template-columns: 1fr; gap: 44px; padding-bottom: 64px; }
  .steps { grid-template-columns: 1fr; }
  .cost-grid { grid-template-columns: 1fr; }
  .tiers { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 620px) {
  .band { padding: 60px 20px; }
  .hero { padding: 32px 20px 52px; }
  .nav { padding: 20px; }
  .verdict-legend { grid-template-columns: 1fr; }
  .trust-grid { grid-template-columns: 1fr; }
  .cost-grid { grid-template-columns: 1fr; }
  .tiers { grid-template-columns: 1fr; }
  .foot { flex-direction: column; gap: 16px; }
  .foot-brand { align-items: center; }
  .foot-links { flex-wrap: wrap; justify-content: center; gap: 14px 20px; }
  .hero-copy .link-btns { gap: 8px; }
}

/* ══ Dashboard ═══════════════════════════════════════════════════════════ */
.wrap { max-width: 880px; margin: 0 auto; padding: 48px 24px 88px; }
.view.hidden { display: none; }

.dash-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  margin-bottom: 30px;
}
.dash-brand { display: flex; flex-direction: column; gap: 3px; }
.dash-brand .logo { color: var(--text); text-decoration: none; }
.dash-tag {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .07em;
  color: var(--faint);
}
.dash-account { display: flex; align-items: center; gap: 16px; }
/* Same flex trap as .token: an email has no spaces to break at, so without
   min-width it would push the header past the screen edge. Truncated rather
   than scrolled — it is a label, not something you copy. */
.dash-email {
  font-size: 13px; color: var(--muted);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Only ever shown when a payment nobody was watching turns out to have landed.
   Green, because on this site green means checked and it holds up. */
.settled-note {
  margin: 0 0 16px; padding: 12px 16px;
  border: 1px solid rgba(34,197,94,.28); border-radius: 11px;
  background: rgba(34,197,94,.07);
  color: var(--true); font-size: 13.5px;
}

/* ── The credits panel ───────────────────────────────────────────────────
   This is the only reason most people open the dashboard, so it gets the
   weight the old two-column "Checks  0 / 150" row never had. The bar shifts
   from green to amber to red as the balance runs down, which is the same
   meaning green and red carry everywhere else on this site. */
.usage-panel {
  position: relative; overflow: hidden;
  border: 1px solid var(--line-2); border-radius: 18px;
  padding: 26px 28px 24px; margin-bottom: 16px;
  background:
    radial-gradient(ellipse 60% 130% at 0% 0%,
      color-mix(in srgb, var(--usage-tint, var(--accent)) 13%, transparent), transparent 62%),
    linear-gradient(180deg, var(--panel-2), var(--panel));
  transition: background .4s ease;
}
.usage-head {
  display: flex; justify-content: space-between; align-items: center;
  gap: 12px; margin-bottom: 18px;
}
.plan-badge {
  font-family: var(--mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  padding: 5px 11px; border-radius: 7px;
  color: var(--accent);
  background: rgba(91,156,246,.1);
  border: 1px solid rgba(91,156,246,.28);
}
.usage-renew { font-size: 12.5px; color: var(--faint); }

.usage-figure { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.usage-big {
  font-size: clamp(46px, 8vw, 68px); font-weight: 800;
  letter-spacing: -.045em; line-height: 1;
  color: var(--usage-tint, var(--text));
  transition: color .4s ease;
}
.usage-unit { font-size: 15px; color: var(--muted); }

.usage-bar {
  height: 8px; border-radius: 6px; overflow: hidden;
  background: rgba(255,255,255,.06);
  margin: 22px 0 12px;
}
.usage-bar-fill {
  display: block; height: 100%; width: 0; border-radius: 6px;
  background: var(--usage-tint, var(--accent));
  box-shadow: 0 0 16px -2px var(--usage-tint, var(--accent));
  transition: width .9s cubic-bezier(.2,.7,.3,1), background .4s ease;
}
.usage-foot {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 14px; font-size: 12.5px; color: var(--faint);
}
.usage-foot .warn { color: var(--unverified); }
.usage-foot .out { color: var(--danger); }

/* ── XP and levels ───────────────────────────────────────────────────────
   Lives inside the usage panel, under the checks bar, because checks are what
   earn it. Its own rule above so it reads as a second thing rather than more
   of the first. */
/* The whole card carries the level, not just the badge — a hairline, well
   under the weight of a real accent, so the tier is felt before it is read. */
#airdrop-card {
  border-color: color-mix(in srgb, var(--xp-tint, var(--line)) 22%, var(--line));
}

/* The card's own header: label on the left, level on the right, the way the
   usage panel puts its plan badge opposite its expiry. */
.xp-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.xp-head .card-label { margin-bottom: 15px; }
.xp-head-right { display: flex; align-items: center; gap: 10px; min-width: 0; }

/* The running total. Quieter than the badge next to it: the level is the
   headline, the XP is the arithmetic behind it. */
.xp-total {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--faint); white-space: nowrap;
}

/* Shaped like .plan-badge, but tinted to the level rather than the accent —
   it is the one place the level is named rather than merely highlighted. */
.level-badge {
  font-family: var(--mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  padding: 5px 11px; border-radius: 7px; white-space: nowrap;
  color: var(--xp-tint, var(--accent));
  background: color-mix(in srgb, var(--xp-tint, var(--accent)) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--xp-tint, var(--accent)) 30%, transparent);
}

/* The payout, and the ring showing how far into the next one. Given real
   weight because it is the only part of this somebody can act on today. */
.xp-payout { display: flex; align-items: center; gap: 18px; margin-bottom: 18px; }
.xp-payout-main { flex: 1; min-width: 0; }
.xp-payout-label {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 4px;
}
.xp-payout-figure {
  font-size: 23px; font-weight: 750; letter-spacing: -.025em; line-height: 1.2;
}
.xp-payout-figure b { color: var(--xp-tint, var(--text)); font-weight: 800; }
.xp-payout-figure .sub { display: block; font-size: 12px; font-weight: 500; color: var(--muted); letter-spacing: 0; margin-top: 2px; }

/* A ring rather than a bar. The checks bar directly above is already a bar, and
   two stacked bars read as one thing continuing rather than two things. */
.xp-dial { position: relative; width: 64px; height: 64px; flex-shrink: 0; }
.xp-dial svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.xp-dial circle { fill: none; stroke-width: 5; stroke-linecap: round; }
.xp-dial .track { stroke: rgba(255,255,255,.08); }
.xp-dial .value { stroke: var(--xp-tint, var(--accent)); transition: stroke-dashoffset .6s cubic-bezier(.2,.75,.3,1); }
.xp-dial-num {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 12.5px; font-weight: 700; color: var(--text);
}

/* The ladder. Every rung always visible, so the ones ahead are a reason to
   keep going rather than a surprise on arrival.

   min-width: 0 on the rungs because a flex item defaults to min-width: auto
   and would refuse to shrink below its label on a phone. */
/* Every rung always visible, so the ones ahead are a reason to keep going
   rather than a surprise on arrival.

   min-width: 0 on the rungs is load-bearing: a flex item defaults to
   min-width: auto and would refuse to shrink below "PLATINUM" on a phone. */
.xp-ladder { display: flex; gap: 5px; }
.xp-rung {
  flex: 1; min-width: 0; text-align: center;
  padding: 8px 2px 7px; border-radius: 9px;
  border: 1px solid transparent;
  background: rgba(255,255,255,.02);
  overflow: hidden;
  transition: background .2s, border-color .2s;
}
.xp-gem { display: block; margin: 0 auto 5px; width: 15px; height: 15px; opacity: .45; }
.xp-name {
  display: block;
  font-family: var(--mono); font-size: 8.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.xp-mult { display: block; font-size: 11px; font-weight: 700; color: var(--faint); margin-top: 2px; }

/* Reached, but behind you. */
.xp-rung.done .xp-gem { opacity: .7; }
.xp-rung.done .xp-name, .xp-rung.done .xp-mult { color: var(--muted); }

/* Where you are. */
.xp-rung.here {
  border-color: var(--rung-tint);
  background: color-mix(in srgb, var(--rung-tint) 12%, transparent);
}
.xp-rung.here .xp-gem { opacity: 1; }
.xp-rung.here .xp-name { color: var(--rung-tint); }
.xp-rung.here .xp-mult { color: var(--rung-tint); }

/* The balance and the way to take it. Separated from the note above by a rule
   because it is the only part of this card that does anything — everything
   above it is a report. */
.xp-claim {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--line);
}
.xp-claim-main { min-width: 0; }
.xp-claim-label {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--faint); margin-bottom: 4px;
}
.xp-claim-figure {
  font-size: 20px; font-weight: 750; letter-spacing: -.02em; line-height: 1.2;
  color: var(--xp-tint, var(--text));
}
.xp-claim-figure .sub {
  display: block; font-size: 12px; font-weight: 500;
  color: var(--muted); letter-spacing: 0; margin-top: 2px;
}
/* Tinted to the level like the rest of the card, rather than to the green the
   referral button uses — they are different balances on different ledgers and
   should not read as one control repeated. */
.xp-claim-btn {
  flex-shrink: 0; padding: 11px 20px; font-weight: 550;
  color: var(--xp-tint, var(--accent));
  background: color-mix(in srgb, var(--xp-tint, var(--accent)) 12%, transparent);
  border-color: color-mix(in srgb, var(--xp-tint, var(--accent)) 35%, transparent);
}
.xp-claim-btn:hover:not(:disabled) {
  background: color-mix(in srgb, var(--xp-tint, var(--accent)) 20%, transparent);
}
.xp-claim-btn:disabled {
  background: rgba(255,255,255,.04); border-color: var(--line); color: var(--faint);
  opacity: 1;
}

.xp-note { margin-top: 12px; font-size: 12px; line-height: 1.55; color: var(--muted); }
.xp-note b { color: var(--text); font-weight: 650; }
.xp-note .dim { color: var(--faint); }

/* Token and links sit side by side; the token needs the room, the links do
   not, and stacked buttons read better in a narrow column anyway. */
/* A little more than the 16px card rhythm, so account settings and billing
   read as two groups rather than one long stack. */
.dash-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: 16px; align-items: start; margin-bottom: 26px; }
.dash-grid .card { margin-bottom: 0; height: 100%; }
.dash-grid .link-btns { flex-direction: column; align-items: stretch; gap: 8px; }
.dash-grid .link-btn { justify-content: flex-start; }

.sub { color: var(--muted); margin: 0 0 30px; max-width: 44ch; }
.hint { color: var(--faint); font-size: 12px; margin-top: 12px; }
.token-input-wrap { display: flex; gap: 8px; }
.token-input-wrap input {
  flex: 1; background: rgba(255,255,255,.04);
  border: 1px solid var(--line); border-radius: 9px;
  padding: 10px 13px; color: var(--text); font-family: var(--mono); font-size: 12.5px;
}

.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); padding: 22px; margin-bottom: 16px;
}
.card-label {
  font-family: var(--mono); font-size: 10px;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 15px;
}
.row { display: flex; justify-content: space-between; align-items: center; padding: 7px 0; color: var(--muted); }
.row .val { color: var(--text); font-weight: 500; }

.token-row { display: flex; gap: 8px; align-items: center; margin: 4px 0 12px; }
/* min-width: 0 is load-bearing, not tidying. A flex item defaults to
   min-width: auto, which refuses to shrink below its content's intrinsic
   width — and with white-space: nowrap that is the whole unbroken string. So
   `flex: 1` said shrink and `min-width: auto` said never, the row could not
   fit, and the card was forced wider than the phone: 65px over for a 36-char
   token, 123px for a 44-char Solana address. overflow-x: auto did nothing,
   because the element never became smaller than what it held. */
.token {
  flex: 1; min-width: 0; background: rgba(255,255,255,.035);
  border: 1px solid var(--line); border-radius: 9px; padding: 10px 13px;
  font-family: var(--mono); font-size: 12px;
  overflow-x: auto; white-space: nowrap;
}

/* The extension token, hidden until asked for. It is a password in every way
   that matters — anybody holding it can spend the account's checks — and it
   used to sit in plain sight on a page people screenshot.
   `button.token` rather than a styled div: the reveal has to work from a
   keyboard as well as a pointer, and a button is the only thing that does that
   without re-implementing focus and activation by hand. */
button.token {
  color: var(--text); text-align: left; cursor: pointer;
  font-family: var(--mono); font-size: 12px;
  transition: filter .18s ease;
}

/* The blur is on a child span, not on the element itself: filter on the button
   would blur its own focus ring too, which is the one thing that has to stay
   sharp for anybody navigating by keyboard. */
.token-hidden .token-value {
  filter: blur(5px);
  /* A blurred string is still selectable, and a selection copies the real
     characters. Hiding it from the pointer is what makes the blur mean
     something rather than decorate. */
  user-select: none;
}
.token-hidden:hover .token-value { filter: blur(4px); }

/* Sits over the blur rather than replacing it, so the row never changes height
   or width between states — a token that reflows the card when revealed is a
   token you cannot screenshot around. */
.token-reveal {
  position: absolute; inset: 0; display: flex;
  align-items: center; justify-content: center;
  font-family: var(--sans); font-size: 11.5px; letter-spacing: .04em;
  color: var(--muted); pointer-events: none;
  transition: opacity .18s ease;
}
button.token { position: relative; }
.token:not(.token-hidden) .token-reveal { opacity: 0; }
.token-hidden:hover .token-reveal { color: var(--text); }

.btn-sm {
  background: rgba(255,255,255,.06);
  border: 1px solid var(--line-2); color: var(--text);
  border-radius: 9px; padding: 9px 15px;
  font-size: 13px; font-family: inherit; cursor: pointer;
  transition: background .15s; white-space: nowrap;
}
.btn-sm:hover:not(:disabled) { background: rgba(255,255,255,.11); }
.btn-sm:disabled { opacity: .4; cursor: default; }

.link { background: none; border: none; color: var(--muted); font-size: 13px; font-family: inherit; cursor: pointer; padding: 0; }
.link:hover { color: var(--text); }
.link.danger { color: var(--faint); font-size: 12px; }
.link.danger:hover { color: var(--danger); }

.plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 14px; }
.plan {
  position: relative; display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: 12px; padding: 20px 18px;
  background: rgba(255,255,255,.018);
  transition: border-color .18s ease, background .18s ease, transform .18s ease;
}
.plan:hover { border-color: var(--line-2); transform: translateY(-2px); }
.plan.current { border-color: rgba(91,156,246,.45); background: rgba(91,156,246,.05); }
.plan.current:hover { transform: none; }
.plan.popular { border-color: rgba(91,156,246,.3); }
.plan .btn-sm { margin-top: auto; }
.plan-tag {
  position: absolute; top: -9px; right: 12px;
  background: var(--accent); color: #06121f;
  font-size: 9.5px; font-weight: 700; letter-spacing: .05em;
  padding: 2px 8px; border-radius: 999px;
}
.plan-name {
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  letter-spacing: .17em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 10px;
}
.plan-price { font-size: 26px; font-weight: 780; letter-spacing: -.035em; line-height: 1; }
.plan-price .per { font-size: 12.5px; font-weight: 500; color: var(--muted); letter-spacing: 0; }
.plan-quota { color: var(--text); font-size: 12.5px; margin: 8px 0 8px; }
.plan-blurb { color: var(--faint); font-size: 11.5px; line-height: 1.5; margin-bottom: 16px; }
.plan .btn-sm { width: 100%; }

.topup-row {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  border: 1px solid var(--line); border-radius: 12px;
  padding: 15px 17px; margin: 4px 0 14px;
}
.topup-title { font-size: 13px; }
.topup-sub { color: var(--faint); font-size: 11px; margin-top: 2px; }

.checkout-head { display: flex; justify-content: space-between; align-items: center; }
.pay-amount { font-size: 30px; font-weight: 750; letter-spacing: -.03em; margin: 10px 0 2px; font-family: var(--mono); }
.btn-pay {
  display: block; text-align: center;
  background: var(--accent); color: #06121f;
  font-weight: 650; font-size: 14.5px;
  padding: 12px; border-radius: 10px;
  text-decoration: none; margin: 16px 0 4px;
  transition: opacity .15s;
}
.btn-pay:hover { opacity: .9; }
/* Paying is copy-the-amount, copy-the-address. Both get their own row and
   their own button, because the amount has to match to the lamport and a
   mistyped digit is a payment that arrives and is never matched. */
.pay-field {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  border: 1px solid var(--line); border-radius: 10px;
  padding: 12px 12px 12px 14px; margin: 12px 0 6px;
  background: rgba(255,255,255,.03);
}
.pay-field-text { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.pay-label {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--faint);
}
.pay-field .pay-amount { margin: 0; font-size: 24px; }
.pay-field .token {
  overflow-x: auto; white-space: nowrap; padding: 0;
  background: none; border: none;
}
.pay-field .btn-sm { flex-shrink: 0; }

/* ── Which rail ──────────────────────────────────────────────────────────
   A segmented control rather than a dropdown. There are two or three options,
   they are the whole decision, and a <select> would hide the fact that paying
   in ETH is possible at all behind a click nobody knows to make.

   min-width: 0 on the tabs is load-bearing, not tidying: a flex item defaults
   to min-width: auto and refuses to shrink below its content, and with
   white-space: nowrap that is the whole label — which is what widened this
   card past the viewport on a phone the last time. */
.chain-tabs {
  display: flex; gap: 6px; margin: 2px 0 14px;
  padding: 4px; border-radius: 11px;
  border: 1px solid var(--line); background: rgba(255,255,255,.03);
}
.chain-tab {
  flex: 1; min-width: 0;
  background: none; border: 0; border-radius: 8px;
  color: var(--muted); font-family: var(--mono);
  font-size: 11.5px; letter-spacing: .09em; text-transform: uppercase;
  padding: 8px 6px; cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color .15s, background .15s;
}
.chain-tab:hover { color: var(--text); }
.chain-tab.is-on {
  background: var(--panel-2); color: var(--text);
  box-shadow: inset 0 0 0 1px var(--line-2);
  cursor: default;
}

/* Which network the address expects, in the warning colour rather than the
   muted one. An EVM address is the same string on every chain, so ETH sent on
   the wrong one arrives somewhere real and is never seen here — the only
   mistake on this screen that loses the money outright. */
.pay-network {
  margin: 2px 0 0; font-size: 12px; line-height: 1.5;
  color: var(--unverified);
}

/* Kept for the phone, where a solana: link does open a wallet. */
.btn-pay.ghost {
  background: none; color: var(--muted);
  border: 1px solid var(--line);
}
.btn-pay.ghost:hover { color: var(--text); border-color: var(--line-2); opacity: 1; }

.pay-or { text-align: center; margin: 12px 0 6px; }
.warn { color: var(--unverified); }

/* These have to live below the dashboard's base rules, not up with the
   landing page's media queries — same specificity, so source order decides. */
@media (max-width: 940px) {
  .dash-grid { grid-template-columns: 1fr; }
  .dash-grid .card { height: auto; }
  .dash-grid .link-btns { flex-direction: row; }
}
@media (max-width: 620px) {
  .wrap { padding: 40px 18px 72px; }
  .plans { grid-template-columns: 1fr; }
  .topup-row { flex-direction: column; align-items: stretch; }
  .dash-head { flex-direction: column; align-items: flex-start; gap: 14px; }
  .dash-account { width: 100%; justify-content: space-between; }
  .usage-panel { padding: 22px 20px; }
  .usage-foot { flex-direction: column; gap: 4px; }
  .dash-grid .link-btns { flex-direction: column; }
}

/* ── referrals ───────────────────────────────────────────────────────────── */
.form-error {
  color: var(--danger); font-size: 12.5px; margin: 8px 0 0;
}

/* An input styled as .token so the claim field and the resulting link sit in
   the same place, at the same size — claiming should look like it filled in
   the thing above it, because that is what happened. */
input.token {
  color: var(--text); outline: none;
  transition: border-color .15s ease;
}
input.token::placeholder { color: var(--faint); }
input.token:focus { border-color: var(--line-2); }

.ref-stats {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 12px; margin: 18px 0 6px;
}
@media (max-width: 620px) { .ref-stats { grid-template-columns: repeat(2, 1fr); } }

.ref-stat {
  display: flex; flex-direction: column; gap: 3px;
  padding: 13px 14px; border-radius: 11px;
  background: rgba(255,255,255,.022); border: 1px solid var(--line);
}
.ref-stat-value {
  font-family: var(--mono); font-size: 19px; font-weight: 600;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.ref-stat-label {
  font-size: 11.5px; color: var(--faint); letter-spacing: .01em;
}
/* Money owed is the number people open this page for. */
.ref-stat.is-owed { border-color: rgba(52,199,123,.32); background: rgba(52,199,123,.055); }
.ref-stat.is-owed .ref-stat-value { color: var(--true); }

.ref-payout { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line); }
.ref-payout .card-label { display: block; margin-bottom: 10px; }

/* ── referrals band ──────────────────────────────────────────────────────── */
/* Three steps in order, so the numbering is structural rather than decorative:
   you cannot post a card before claiming a handle, or earn before posting. */
.ref-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
@media (max-width: 820px) { .ref-steps { grid-template-columns: 1fr; } }

.ref-step {
  position: relative;
  border: 1px solid var(--line); border-radius: var(--r);
  padding: 22px 22px 22px 58px; background: var(--panel);
}
.ref-step-n {
  position: absolute; left: 20px; top: 21px;
  width: 23px; height: 23px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--mono); font-size: 11px; font-weight: 600;
  color: var(--accent); border: 1px solid rgba(91,156,246,.4);
  background: rgba(91,156,246,.08);
}
.ref-step h3 {
  font-size: 15.5px; font-weight: 650; margin: 0 0 7px;
  letter-spacing: -.015em; line-height: 1.35;
}
.ref-step p { color: var(--muted); font-size: 13.5px; margin: 0; }
.ref-step code {
  font-family: var(--mono); font-size: 12.5px;
  color: var(--text); background: rgba(255,255,255,.045);
  border: 1px solid var(--line); border-radius: 5px; padding: 1px 5px;
}

/* The one control here that moves money, so it gets the weight the rest of the
   card does not. Disabled until a payout would actually succeed — an enabled
   button that always answers "not yet" trains people to ignore it. */
/* Both withdraw buttons, styled as one control rather than as a button and its
   alternative. This used to live on .payout-request alone, from when it was the
   only one and sat full width on its own line — carrying a margin-top that, once
   there were two side by side, pushed one of them 14px below the other. */
.payout-actions .btn-sm {
  background: rgba(52,199,123,.12); border-color: rgba(52,199,123,.35);
  color: var(--true); font-weight: 550;
}
.payout-actions .btn-sm:hover:not(:disabled) { background: rgba(52,199,123,.2); }
.payout-actions .btn-sm:disabled { background: rgba(255,255,255,.04); border-color: var(--line); color: var(--faint); }

/* ── $FASTCHECK to credits ──────────────────────────────────────────────────

   Rebuilt because the first version was four full-width rows of equal visual
   weight — a rate sentence, a calculator, an address, a status line — and
   nothing said which of them was the reader's job. It also dressed the
   destination address as a text input, which invites people to type in the one
   place on the card where typing does nothing.

   The shape now: reference figures at the top, the exchange on its own surface,
   then two numbered steps. Send, then wait. */

.convert-rate {
  display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: baseline;
  margin: 2px 0 14px;
  font-size: 12.5px; color: var(--muted);
}
.convert-rate b {
  font-family: var(--mono); font-weight: 600; color: var(--text);
  font-size: 12.5px; letter-spacing: -.01em;
}
.convert-rate .convert-rate-note { color: var(--faint); }

/* The exchange. Grid rather than flex so the arrow stays put when either side
   changes width, on a panel so the pair reads as one control rather than two
   fields that happen to be adjacent. */
.convert-calc {
  display: grid; grid-template-columns: 1fr auto 1fr;
  gap: 16px; align-items: center;
  margin: 0 0 18px; padding: 14px 16px;
  background: var(--panel-2, rgba(255, 255, 255, .02));
  border: 1px solid var(--line); border-radius: 10px;
}
.convert-side { min-width: 0; }
.convert-side-out { text-align: right; }
.convert-cap {
  display: block; margin-bottom: 7px;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--faint);
}
.convert-arrow { color: var(--faint); font-size: 15px; line-height: 1; }

/* The input and its unit share one border, so the unit reads as part of the
   field rather than as a label that wandered next to it. */
.convert-input, .addr-field {
  display: flex; align-items: center; gap: 8px;
  padding: 0 10px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
  transition: border-color .15s ease;
}
.convert-input:focus-within, .addr-field:focus-within { border-color: var(--line-2); }
.convert-input input, .addr-field input {
  flex: 1; min-width: 0;
  background: none; border: 0; outline: none;
  padding: 9px 0;
  font-family: var(--mono); font-size: 14px; color: var(--text);
}
.convert-input input::placeholder, .addr-field input::placeholder { color: var(--faint); }
.convert-unit {
  font-family: var(--mono); font-size: 10.5px; color: var(--faint);
  white-space: nowrap; letter-spacing: .04em;
}
.convert-input-wide { margin: 0 0 8px; }
.convert-input-wide .btn-sm { margin: 5px -5px 5px 0; }

.convert-out {
  font-size: 24px; font-weight: 750; letter-spacing: -.02em; line-height: 1.15;
  color: var(--true);
}
.convert-out-sub {
  font-size: 12px; color: var(--muted); margin-top: 4px; min-height: 17px;
}
.convert-note { margin: 0; }

/* ── the two steps ─────────────────────────────────────────────────────────
   Numbered, and the number is the thing that carries the rhythm: it gives the
   eye a left edge to travel down and makes "which bit is mine" answerable
   without reading a word. */
.convert-step { display: flex; gap: 12px; align-items: flex-start; }
.convert-step + .convert-step { margin-top: 16px; }
.convert-step-n {
  flex: 0 0 auto; width: 20px; height: 20px; margin-top: 1px;
  display: grid; place-items: center;
  border: 1px solid var(--line-2); border-radius: 50%;
  font-family: var(--mono); font-size: 10.5px; color: var(--muted);
}
.convert-step-body { min-width: 0; flex: 1; }

/* Not an input, and it should not look like one. A flat inset block with the
   copy button attached reads as a value to take away. */
.convert-addr {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 8px 8px 11px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
}
.convert-addr code {
  flex: 1; min-width: 0;
  font-family: var(--mono); font-size: 12.5px; color: var(--text);
  /* An address has no spaces to break at, so without this it forces the whole
     card wider than the column on a narrow screen. */
  overflow-wrap: anywhere;
}

.convert-warn {
  margin: 8px 0 0;
  font-size: 12px; line-height: 1.5; color: var(--unverified);
}
.convert-from-note {
  margin: 6px 0 0;
  font-size: 12px; color: var(--faint);
}
.convert-from-note code {
  font-family: var(--mono); color: var(--muted); overflow-wrap: anywhere;
}

/* ── waiting ───────────────────────────────────────────────────────────────
   The old version was the words "Waiting for the transfer…" and nothing else,
   which is indistinguishable from a page that has stopped working — and on the
   one occasion it HAD stopped working, that is exactly how it read. */
.convert-wait {
  display: flex; align-items: center; gap: 9px;
  font-size: 13px; color: var(--muted);
}
.convert-wait #convert-cancel { margin-left: auto; flex: 0 0 auto; }

.convert-dot {
  flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%;
  background: var(--faint);
  animation: convert-pulse 1.6s ease-in-out infinite;
}
/* Seen, and now only a matter of time. A different colour because it is a
   different state, not a louder version of the same one. */
.convert-dot.is-seen { background: var(--true); }

@keyframes convert-pulse {
  0%, 100% { opacity: .35; transform: scale(.85); }
  50%      { opacity: 1;   transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .convert-dot { animation: none; opacity: .8; }
  .convert-bar span { transition: none; }
}

.convert-bar {
  margin-top: 9px; height: 3px; border-radius: 2px;
  background: var(--line); overflow: hidden;
}
.convert-bar span {
  display: block; height: 100%; width: 0;
  background: var(--true); border-radius: 2px;
  transition: width .4s ease;
}

.convert-done {
  margin: 14px 0 0; font-size: 13px; color: var(--true);
}

/* ── a one-time destination ─────────────────────────────────────────────────

   Used by the referral withdrawal and the airdrop claim, which each ask for
   their own. Nothing is stored between uses, so this is a field you fill in at
   the moment you want paying and never see filled in again.

   The button sits inside the field because the two are one action: an address
   with nothing to press is half a control, and a Withdraw button floating
   under a saved wallet was what made the old version read as a settings
   screen rather than a thing you do. */
.addr-field { margin: 0 0 8px; padding: 0 10px; }
.addr-field .btn-sm { margin: 5px -5px 5px 0; flex: 0 0 auto; }
.addr-cap {
  display: block; margin-bottom: 7px;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--faint);
}
.addr-note {
  margin: 0; font-size: 12px; line-height: 1.55; color: var(--faint);
}
/* Losing the money to the wrong network is a different order of mistake from
   pasting the address again next time, so it does not share a colour with the
   sentence about convenience. */
.addr-warn { color: var(--unverified); }

.claim-to { margin-top: 14px; }

/* ── folding a long earnings list ───────────────────────────────────────────
   Seven rows of the same shape is a wall. The first few are the ones anybody
   reads; the rest are there to be checked, not scanned. */
.ref-fold {
  display: inline-block; margin-top: 10px;
  font-size: 12.5px; color: var(--muted);
}
.ref-fold:hover { color: var(--text); }

/* On a phone the arrow between two stacked fields points the wrong way, so it
   goes rather than rotating into something that reads as a bullet. */
@media (max-width: 560px) {
  .convert-calc { grid-template-columns: 1fr; gap: 14px; }
  .convert-arrow { display: none; }
  .convert-side-out { text-align: left; }
}

.payout-sent { color: var(--true); }
.payout-sent a { color: var(--true); }

/* Which network the address has to be on, in the warning colour rather than
   the muted one — the same treatment .pay-network gets at checkout, for the
   same reason. An EVM address is the same string on every chain, so tokens
   sent to one that exists elsewhere arrive somewhere real and are never seen
   again. It is the only mistake on this card that loses the money outright,
   and it should not look like an aside. */
.payout-network {
  margin: 10px 0 0;
  font-size: 12.5px; line-height: 1.55;
  color: var(--unverified);
}

/* The referral bonus, on a pack that currently carries one. Accent-coloured
   because it is temporary: it disappears after the first purchase, and a
   number that shrinks without explanation reads as a price rise. */
.plan-bonus, .tier-bonus {
  font-family: var(--mono); font-size: 11px; letter-spacing: .02em;
  color: var(--true); margin-top: 4px;
}
.tier-bonus { margin-top: 6px; }

/* ── earnings history ────────────────────────────────────────────────────── */
.ref-history { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line); }
.ref-history .card-label { display: block; margin-bottom: 10px; }

.ref-rows { display: flex; flex-direction: column; }
.ref-row {
  display: grid; grid-template-columns: auto 1fr auto auto;
  gap: 12px; align-items: baseline;
  padding: 9px 0; border-bottom: 1px solid var(--rule, rgba(255,255,255,.05));
  font-size: 13px;
}
.ref-rows .ref-row:last-child { border-bottom: none; }

.ref-row-date {
  font-family: var(--mono); font-size: 11.5px; color: var(--faint);
  font-variant-numeric: tabular-nums;
}
.ref-row-plan { color: var(--muted); }
.ref-row-amt {
  font-family: var(--mono); color: var(--text);
  font-variant-numeric: tabular-nums;
}
/* Paid and unpaid are the distinction that matters, so it is a state chip
   rather than another column of text. */
.ref-row-state {
  font-family: var(--mono); font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; padding: 2px 7px; border-radius: 5px;
  border: 1px solid var(--line); color: var(--faint);
}
.ref-row-state.is-paid {
  color: var(--true); border-color: rgba(52,199,123,.32); background: rgba(52,199,123,.06);
}
.ref-row-state a { color: inherit; text-decoration: none; }
.ref-row-state a:hover { text-decoration: underline; }

/* ── loading a card's contents ───────────────────────────────────────────── */
/* The referral card cannot know which half to show until the server answers,
   and the markup has to pick one. Without this it picks the claim form, so
   anyone who already has a handle watches it flash past on every load. Blurred
   until the answer arrives, the swap happens behind frosted glass.

   The transition lives on the base selector, not on :not(.is-loading). Put it
   there and the property arrives in the same frame the blur is removed, so
   there is nothing to animate from and it cuts instead of easing. */
/* Any card or panel that fills in from a fetch. Scoped to .loadable rather
   than to one id, so the whole dashboard behaves the way the referral card
   already did: structure first, blurred, then the real content easing in.

   The transition lives on the base selector, not on :not(.is-loading). Put it
   there and the property arrives in the same frame the blur is removed, so
   there is nothing to animate from and it cuts instead of easing. */
.loadable { position: relative; }
.loadable > * {
  transition: filter .32s ease, opacity .32s ease;
}
/* The label stays sharp — it says what you are waiting for. */
.loadable.is-loading > *:not(.card-loading):not(.card-label) {
  filter: blur(7px);
  opacity: .35;
  pointer-events: none;
  user-select: none;
}

.card-loading {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r);
  transition: opacity .24s ease;
}
/* Faded rather than display:none, which cannot transition. Kept out of the
   layout with visibility so it cannot swallow a click once invisible. */
.loadable:not(.is-loading) .card-loading {
  opacity: 0; visibility: hidden; pointer-events: none;
}

.spinner {
  width: 20px; height: 20px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,.12);
  border-top-color: var(--accent);
  animation: fc-spin .7s linear infinite;
}
@keyframes fc-spin { to { transform: rotate(360deg); } }

/* Stand-ins for the three plan tiles, which are built entirely in JS — without
   them the plans card would be a blurred empty box, and blurring nothing reads
   as a broken layout rather than as loading. */
.plan-skeleton {
  border: 1px solid var(--line); border-radius: 12px;
  min-height: 188px;
  background: rgba(255,255,255,.018);
}

@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 2.4s; }
  .loadable > *, .card-loading { transition: none; }
}

/* One way to take a balance, so one full-width button.
   This was two equal columns while a balance could also be taken as credits,
   and when that went the survivor kept half the row — a button sized for a
   neighbour that no longer exists. A single fraction is the whole fix.

   Still grid rather than flex: `flex: 1 1 auto` sizes from the label, so the
   button would shrink to fit its own text rather than filling the row. */
.payout-actions {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  /* On the row, not on the button inside it. */
  margin-top: 14px;
}

/* It is the only action on this card and the last step of the whole referral
   flow, so it carries a little more height than a .btn-sm elsewhere. Styled
   through the row rather than on #payout-request, which is what kept it
   matching its neighbour when it had one — and what a test still enforces. */
.payout-actions .btn-sm {
  min-width: 0;
  padding: 12px 16px;
  font-size: 13.5px;
  letter-spacing: .01em;
  /* A long balance in the label has somewhere to go rather than overflowing. */
  overflow: hidden;
  text-overflow: ellipsis;
}
