/*
  rbrc shared stylesheet. Design direction B, "exchange-grade clarity", modernised (design v3).

  One file for everything more than one page uses: tokens, base type, the shell (header, top
  navigation, language switch, wallet button, tab bar, footer) and the components listed in
  COMPONENTS.md. A page's own layout goes in assets/page-<name>.css, loaded with a
  <!-- style: --> marker in its fragment, so nobody porting a page edits this file.

  What changed from v2 (archived in archive-design-v2/): the same palette and rules, but layered
  instead of uniform. One quiet ground; grouped surfaces behind hairlines with a lit top edge; a
  real shadow only on what floats (header, tab bar, sheet, toast). A tighter type scale where
  weight and colour rank the figures instead of size. Generated token avatars instead of letter
  tiles, compact list rows and a table on desktop instead of a tall card per token, a segmented
  control with a sliding thumb, badges for states, and press feedback on everything tappable.

  Palette (every text pair checked for WCAG AA 4.5:1 against its real background):
    ground #0D1012 · surface-1 (panel) #16191C · surface-2 (raised) #1F2427 · surface-3 #1B1F22
    chalk #F1F4EE text · ash #B4BCB6 secondary (8.9:1 on panel, 7.9:1 on raised)
    smoke #939C96 tertiary (5.6:1 on raised, 6.1:1 on panel) for labels only
    lime #C6F000 fills and key figures, with #121600 ink on lime
    amber #F2B544 settling and warnings (8.4:1 on its own #2A2416 ground)
    teal #6FE3CD for "new" (9.9:1 on panel)
    err #FF8A7A (7.3:1 on panel)
  Type: Manrope for latin text and figures, tabular numbers everywhere; system CJK stack for
  Chinese; JetBrains Mono only for addresses and inscription text. Body 16px, secondary 14px,
  13px only for badges and tab labels.
  Hit areas: every control is at least 44 x 44 px. Where the visual is smaller (a compact button,
  the header controls) the hit area is padded with ::after, not the visual inflated.
*/

:root {
  --bg: #0d1012;
  --panel: #16191c;
  --raised: #1f2427;
  --raised-hover: #272d31;
  --surface-3: #1b1f22;
  --line: #2c3237;
  --line-strong: #434c53;
  --hair: rgba(255, 255, 255, 0.07);
  --hair-strong: rgba(255, 255, 255, 0.12);
  --edge: rgba(255, 255, 255, 0.05);
  --track: rgba(255, 255, 255, 0.09);
  --well: #090b0c;
  --tabbar: rgba(14, 17, 19, 0.95);
  --text: #f1f4ee;
  --text2: #b4bcb6;
  --text3: #939c96;
  --lime: #c6f000;
  --lime-soft: rgba(198, 240, 0, 0.12);
  --lime-line: rgba(198, 240, 0, 0.3);
  --ink: #121600;
  --teal: #6fe3cd;
  --teal-soft: rgba(111, 227, 205, 0.12);
  --amber: #f2b544;
  --amber-bg: #2a2416;
  --amber-line: #4a3e22;
  --err: #ff8a7a;
  --err-bg: #2b1a18;
  --err-line: #5a2e28;

  --shadow-float: 0 1px 0 var(--edge) inset, 0 20px 48px -20px rgba(0, 0, 0, 0.8);
  --shadow-card: 0 1px 0 var(--edge) inset, 0 12px 32px -24px rgba(0, 0, 0, 0.9);
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);

  --sans: "Manrope", system-ui, -apple-system, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI",
    "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC", "Noto Sans SC", sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, "PingFang SC", "Microsoft YaHei",
    "Noto Sans CJK SC", monospace;

  /* spacing scale: use these, not ad hoc pixel values */
  --s0: 2px; /* optical nudge only: a label sitting on its figure */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;
  --s7: 32px;
  --s8: 40px;
  --s9: 56px;

  /* type scale */
  --fs-xs: 13px; /* badges and tab labels only, never a sentence */
  --fs-sm: 14px; /* secondary floor */
  --fs-md: 15px;
  --fs-base: 16px;
  --fs-lg: 18px; /* smallest key figure */
  --fs-xl: 20px;
  --fs-2xl: 24px;
  --fs-3xl: 28px;
  --fs-4xl: 40px;
  /* the in-between steps the components use, named so no page writes a raw size */
  --fs-lead: 17px; /* lead text, h3, a row's name */
  --fs-h1: 24px;
  --fs-h1-lg: 30px; /* desktop h1, the sheet's amount */
  --fs-hero: 32px; /* the largest figure, a token name on a small phone */
  --fs-hero-lg: 40px; /* a token name on desktop, the home title */

  --r-sm: 10px;
  --r: 12px;
  --r-lg: 16px;
  --r-xl: 20px;
  --r-2xl: 24px;

  --hit: 44px;
  --btn-h: 48px;
  --headh: 56px;
  --tabh: 64px;
  --safe-b: env(safe-area-inset-bottom, 0px);
  /* written by ui.js actionBar(); 0 when no bar is mounted */
  --actionbar-h: 0px;
  /* what is fixed at the bottom of a phone screen: tab bar, safe area, action bar */
  --bottom-fixed: calc(var(--tabh) + 1px + var(--safe-b));
  --gutter: 16px;
  --maxw: 1120px;
}

/* ------------------------------------------------------------------ base */

*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--bg);
  scroll-padding-top: calc(var(--headh) + var(--s4));
}
body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: var(--fs-base);
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  overflow-x: hidden;
  /* phones: the tab bar and, when a page mounts one, the action bar are fixed, so the page ends
     above both. Reserved on the body rather than .main, so the footer clears them too. */
  padding-bottom: calc(var(--bottom-fixed) + var(--actionbar-h));
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-tap-highlight-color: transparent;
}
html[lang|="zh"] body {
  line-height: 1.7;
}
[hidden] {
  display: none !important;
}
img,
svg {
  max-width: 100%;
}
svg {
  flex: none;
}
button,
input,
textarea,
select {
  font: inherit;
  color: inherit;
}
button {
  cursor: pointer;
  border: 0;
  background: none;
  padding: 0;
}
a {
  color: inherit;
}
:focus-visible {
  outline: 2px solid var(--lime);
  outline-offset: 2px;
}
::selection {
  background: var(--lime);
  color: var(--ink);
}

h1,
h2,
h3 {
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
}
html[lang|="zh"] h1,
html[lang|="zh"] h2,
html[lang|="zh"] h3 {
  letter-spacing: 0;
  line-height: 1.35;
}
h1 {
  font-size: var(--fs-h1);
}
h2 {
  font-size: var(--fs-xl);
}
h3 {
  font-size: var(--fs-lead);
  font-weight: 700;
  letter-spacing: -0.01em;
}
p {
  margin: 0 0 var(--s3);
}
code,
pre,
.mono {
  font-family: var(--mono);
  font-size: var(--fs-sm);
  letter-spacing: 0;
}
code {
  background: var(--raised);
  border-radius: 6px;
  padding: 1px 6px;
  overflow-wrap: anywhere;
}
strong {
  font-weight: 700;
}
.num {
  font-variant-numeric: tabular-nums;
}
.sub,
.muted {
  color: var(--text2);
  font-size: var(--fs-sm);
}
.lead {
  font-size: var(--fs-lead);
  color: var(--text2);
  max-width: 62ch;
}
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  color: var(--text2);
  font-size: var(--fs-sm);
  font-weight: 600;
}
.lime {
  color: var(--lime);
}
.amber {
  color: var(--amber);
}
.err-text {
  color: var(--err);
}
.addr {
  font-family: var(--mono);
  font-size: var(--fs-sm);
  overflow-wrap: anywhere;
}
.vh {
  position: absolute !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
.skip {
  position: absolute;
  left: var(--s4);
  top: -60px;
  z-index: 100;
  background: var(--lime);
  color: var(--ink);
  font-weight: 700;
  padding: 12px 16px;
  border-radius: var(--r);
  text-decoration: none;
}
.skip:focus {
  top: var(--s2);
}

/* Pad a small link or icon to a 44px hit area without changing how it looks. */
.tap {
  position: relative;
}
.tap::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(100%, var(--hit));
  height: max(100%, var(--hit));
  transform: translate(-50%, -50%);
}

/* A live dot: the index is being read. Still under reduced motion. */
.live-dot {
  position: relative;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--lime);
  flex: none;
}
.live-dot::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 2px solid var(--lime);
  opacity: 0;
  animation: live 2.4s var(--ease) infinite;
}
@keyframes live {
  0% {
    transform: scale(0.5);
    opacity: 0.7;
  }
  100% {
    transform: scale(1.4);
    opacity: 0;
  }
}

/* Prose: explanatory text under a page's working part. */
.prose {
  max-width: 68ch;
}
.prose p {
  font-size: var(--fs-base);
  line-height: 1.65;
  color: var(--text);
}
html[lang|="zh"] .prose p {
  line-height: 1.8;
}
.prose a,
a.inline {
  color: var(--lime);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  /* an inline link in a sentence keeps its line and its spacing; its tap target grows to at
     least 44px tall, and 10px to each side so a one-word link is 44px wide as well */
  padding: 13px 10px;
  margin: -13px -10px;
}
/* The same for a link inside a 14px hint or note line. */
.field-hint a,
.note a,
.why a,
.sub a,
.lead a {
  padding: 13px 10px;
  margin: -13px -10px;
}
.prose h2 {
  margin: var(--s7) 0 var(--s3);
}

/* ------------------------------------------------------------------ shell: header */

/* Glass: the ground carries through the chrome. bg.css keeps an opaque fallback where the
   browser cannot blur. */
header.top {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(13, 16, 18, 0.94);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  backdrop-filter: blur(20px) saturate(160%);
  border-bottom: 1px solid var(--hair);
}
.top-in {
  max-width: var(--maxw);
  margin: 0 auto;
  height: var(--headh);
  padding: 0 var(--gutter);
  display: flex;
  align-items: center;
  gap: var(--s2);
}
.mark {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--hit);
  min-width: var(--hit);
  font-weight: 800;
  font-size: var(--fs-lg);
  letter-spacing: -0.02em;
  text-decoration: none;
  white-space: nowrap;
  flex: none;
}
.mark-p {
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: var(--lime);
  color: var(--ink);
  font-family: var(--mono);
  font-weight: 600;
  font-size: var(--fs-md);
  line-height: 1;
}
.seal {
  display: none;
  margin-left: 2px;
  padding: 0 5px;
  border: 1px solid var(--lime-line);
  border-radius: 6px;
  color: var(--lime);
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 20px;
  letter-spacing: 0.04em;
}
@media (min-width: 420px) {
  .seal {
    display: inline-block;
  }
}
.top-gap {
  flex: 1;
  min-width: 0;
}
.topnav {
  display: none;
}

/* Segmented control. The segment is the full 44px hit area; the track and the thumb are drawn
   inset, so the control reads compact while every segment is tappable. Works on
   <a aria-current> (the language switch) and <button aria-pressed> (a view switch).

   Without script the active segment draws its own pill (::before). ui.js segmented() adds one
   .seg-thumb that slides to the active segment, and .has-thumb turns the per-segment pill off. */
.seg {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  flex: none;
  padding: 0 3px;
}
.seg::before {
  content: "";
  position: absolute;
  inset: 3px 0;
  z-index: -2;
  border-radius: var(--r);
  background: var(--raised);
  box-shadow: inset 0 0 0 1px var(--hair);
}
.seg > a,
.seg > button {
  position: relative;
  z-index: 1;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: var(--hit);
  min-width: var(--hit);
  padding: 0 12px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--text2);
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.2s var(--ease);
}
.seg > a::before,
.seg > button::before {
  content: "";
  position: absolute;
  inset: 7px 0;
  border-radius: 9px;
  z-index: -1;
}
.seg > a:hover,
.seg > button:hover {
  color: var(--text);
}
.seg > [aria-current="true"],
.seg > [aria-current="page"],
.seg > [aria-pressed="true"],
.seg > [aria-selected="true"] {
  color: var(--bg);
}
.seg:not(.has-thumb) > [aria-current="true"]::before,
.seg:not(.has-thumb) > [aria-current="page"]::before,
.seg:not(.has-thumb) > [aria-pressed="true"]::before,
.seg:not(.has-thumb) > [aria-selected="true"]::before {
  background: var(--text);
}
.seg-thumb {
  position: absolute;
  top: 7px;
  bottom: 7px;
  left: 0;
  z-index: 0;
  width: var(--seg-w, 0);
  border-radius: 9px;
  background: var(--text);
  box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.5);
  transform: translateX(var(--seg-x, 0));
}
.seg.is-ready .seg-thumb {
  transition: transform 0.28s var(--ease), width 0.28s var(--ease);
}
.seg > :focus-visible {
  outline-offset: -5px;
  border-radius: 11px;
}
/* The header's language switch: the smallest segment. */
.langseg > a {
  padding: 0 10px;
}
/* Under 600px the switch is one 44px button that shows the other language ("中" on an English
   page, "en" on a Chinese one) and leads straight to it, so the wordmark and the wallet keep their
   room. The segment is back from 600px. */
.langbtn {
  display: none;
  place-items: center;
  flex: none;
  width: var(--hit);
  height: var(--hit);
  border-radius: var(--r);
  color: var(--text2);
  font-weight: 700;
  font-size: var(--fs-md);
  text-decoration: none;
  transition: background-color 0.15s, color 0.15s, transform 0.12s var(--ease);
}
.langbtn > span {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: var(--r-sm);
  background: var(--raised);
  box-shadow: inset 0 0 0 1px var(--hair);
}
.langbtn:hover {
  color: var(--text);
}
.langbtn:active {
  transform: scale(0.94);
}
@media (max-width: 599px) {
  .langseg {
    display: none;
  }
  .langbtn {
    display: inline-grid;
  }
}

/* The header wallet button. data-state: none (no wallet found), idle (not connected),
   wrong (connected, other network), on (connected), busy (a request is open).
   Compact to look at (40px); ::after pads the hit area to 44. */
.walletbtn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  max-width: 48vw;
  height: 40px;
  padding: 0 14px 0 12px;
  border-radius: var(--r);
  /* soft lime: the header offers the wallet without outshouting the page's own primary action */
  background: var(--lime-soft);
  color: var(--lime);
  font-weight: 700;
  font-size: var(--fs-sm);
  white-space: nowrap;
  box-shadow: inset 0 0 0 1px rgba(198, 240, 0, 0.26);
  transition: transform 0.12s var(--ease), background-color 0.15s;
}
.walletbtn::after {
  content: "";
  position: absolute;
  inset: -2px 0;
}
.walletbtn-i {
  display: inline-flex;
}
.walletbtn-i svg {
  width: 18px;
  height: 18px;
}
.walletbtn-t {
  overflow: hidden;
  text-overflow: ellipsis;
}
.walletbtn:hover {
  background: rgba(198, 240, 0, 0.2);
}
.walletbtn:active {
  transform: scale(0.97);
}
.walletbtn[data-state="on"],
.walletbtn[data-state="on"]:hover {
  background: var(--raised);
  color: var(--text);
  font-family: var(--mono);
  font-weight: 600;
  box-shadow: inset 0 0 0 1px var(--hair);
  padding-left: 12px;
}
.walletbtn[data-state="on"] .walletbtn-i,
.walletbtn[data-state="busy"] .walletbtn-i {
  display: none;
}
.walletbtn[data-state="on"]::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--lime);
  box-shadow: 0 0 0 3px var(--lime-soft);
  flex: none;
}
.walletbtn[data-state="wrong"] {
  background: var(--amber-bg);
  color: var(--amber);
  box-shadow: inset 0 0 0 1px var(--amber-line);
}
.walletbtn[data-state="busy"] {
  background: var(--raised);
  color: var(--text2);
  box-shadow: inset 0 0 0 1px var(--hair);
  cursor: progress;
}
@media (max-width: 374px) {
  .top-in {
    gap: 6px;
  }
  .walletbtn {
    padding: 0 10px;
  }
  .walletbtn-i {
    display: none;
  }
  .walletbtn[data-state="on"] {
    gap: 6px;
  }
}

/* The quiet line an English page shows a browser that prefers Chinese. */
.langoffer {
  background: var(--panel);
  border-bottom: 1px solid var(--hair);
}
.langoffer-in {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--s2) var(--gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s3);
  font-size: var(--fs-md);
}
.langoffer-in > span {
  flex: 1 1 12em;
}

/* ------------------------------------------------------------------ shell: main, footer, tab bar */

.main {
  flex: 1 0 auto;
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--s4) var(--gutter) var(--s6);
}
.main:focus {
  outline: none;
}
/* The digit texture (bg.css) fades out under the reading column: a still, fixed wash of the ground
   colour centred on the viewport, strongest where headings and sentences sit and gone at the
   edges, so the digits stay in the corners and gutters. It sits between bg.css's layers (-3, -2)
   and the content. */
.main::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse 78% 68% at 50% 32%, rgba(13, 16, 18, 0.8) 0%, rgba(13, 16, 18, 0.62) 55%, rgba(13, 16, 18, 0) 100%);
}

.foot {
  border-top: 1px solid var(--hair);
}
.foot-in {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: var(--s2) var(--gutter);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--s5);
}
.foot-in a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--hit);
  min-width: var(--hit);
  color: var(--text2);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
}
.foot-in a:hover,
.foot-in a[aria-current="page"] {
  color: var(--text);
}

/* The phone tab bar: glass, with a lime-tinted pill behind the active tab's icon. */
nav.tabbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 45;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  background: var(--tabbar);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  backdrop-filter: blur(20px) saturate(160%);
  border-top: 1px solid var(--hair);
  padding-bottom: var(--safe-b);
}
nav.tabbar a {
  height: var(--tabh);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  color: var(--text2);
  font-size: var(--fs-xs);
  font-weight: 600;
  text-decoration: none;
  line-height: 1.2;
  transition: color 0.2s var(--ease);
}
.tab-ic {
  display: grid;
  place-items: center;
  width: 56px;
  height: 30px;
  border-radius: 999px;
  transition: background-color 0.25s var(--ease), transform 0.15s var(--ease);
}
.tab-ic svg {
  width: 22px;
  height: 22px;
}
nav.tabbar a:active .tab-ic {
  transform: scale(0.92);
}
nav.tabbar a[aria-current="page"] {
  color: var(--text);
}
nav.tabbar a[aria-current="page"] .tab-ic {
  background: var(--lime-soft);
  color: var(--lime);
}
nav.tabbar a:focus-visible {
  outline-offset: -4px;
  border-radius: var(--r);
}

/* ------------------------------------------------------------------ page scaffolding */

/* The page head, one rhythm for every page. The first block in .main (a page's head, or a token
   page's back row) starts at the main's own top padding plus a 4px optical nudge on a phone, and
   with no nudge from 900px, so every title sits at the same top. A title has no margins of its
   own, and a lead right under it sits 8px below. Page css does not set these margins; the gap
   from the head to the content under it stays with the page. */
.main > :first-child {
  margin-top: var(--s1);
}
h1 + .lead {
  margin: var(--s2) 0 0;
}
.pagehead {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s3);
  margin: 0 0 var(--s4);
}
.pagehead .sub {
  margin: 2px 0 0;
}
.section {
  margin-top: var(--s7);
}
.section > h2,
.section-title {
  margin-bottom: var(--s3);
}
/* A section head: a title (with an optional count) on the left, a control on the right. */
.sechead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2) var(--s3);
  margin-bottom: var(--s3);
}
.sechead h2 {
  font-size: var(--fs-lg);
  display: flex;
  align-items: baseline;
  gap: var(--s2);
}
.sechead h2 .sub {
  font-weight: 500;
  letter-spacing: 0;
}
.stack > * + * {
  margin-top: var(--s3);
}
.row-flex {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
}
.grow {
  flex: 1;
  min-width: 0;
}
.list {
  display: grid;
  gap: var(--s3);
}
.only-desktop {
  display: none !important;
}

/* ------------------------------------------------------------------ buttons */

/* Primary lime is for the one main action of a view. Secondary (raised with a hairline) and
   tertiary (text only) carry everything else. */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-height: var(--btn-h);
  padding: 0 var(--s5);
  border-radius: var(--r);
  background: var(--lime);
  color: var(--ink);
  font-weight: 700;
  font-size: var(--fs-base);
  letter-spacing: -0.01em;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 6px 20px -10px rgba(198, 240, 0, 0.45);
  transition: transform 0.12s var(--ease), filter 0.15s, background-color 0.15s, box-shadow 0.15s;
}
html[lang|="zh"] .btn {
  letter-spacing: 0;
}
.btn:hover {
  filter: brightness(1.06);
}
.btn:active:not(:disabled):not([aria-disabled="true"]) {
  transform: scale(0.97);
}
.btn-block {
  display: flex;
  width: 100%;
}
.btn-ghost,
.btn-secondary {
  background: var(--raised);
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--hair), inset 0 1px 0 var(--edge);
}
.btn-ghost:hover,
.btn-secondary:hover {
  background: var(--raised-hover);
  filter: none;
}
.btn-quiet {
  background: transparent;
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--line);
}
.btn-quiet:hover {
  background: var(--raised);
  filter: none;
}
/* Soft lime: a tinted action that repeats down a list (a row's mint), where solid lime on every
   row would leave no primary action on the screen. Lime on its tint is 11:1. */
.btn-soft {
  background: var(--lime-soft);
  color: var(--lime);
  box-shadow: inset 0 0 0 1px rgba(198, 240, 0, 0.24);
}
.btn-soft:hover {
  background: rgba(198, 240, 0, 0.2);
  filter: none;
}
.btn-compact.btn-soft {
  box-shadow: inset 0 0 0 1px rgba(198, 240, 0, 0.24);
}
.btn-tertiary {
  background: transparent;
  color: var(--text);
  box-shadow: none;
  padding: 0 var(--s3);
}
.btn-tertiary:hover {
  background: var(--raised);
  filter: none;
}
.btn-danger {
  background: var(--err-bg);
  color: var(--err);
  box-shadow: inset 0 0 0 1px var(--err-line);
}
.btn-danger:hover {
  filter: brightness(1.15);
}
.btn-sm {
  min-height: var(--hit);
  padding: 0 var(--s4);
  border-radius: var(--r-sm);
  font-size: var(--fs-md);
}
/* Compact: 36px to look at, a 44px hit area. For an action inside a list row. */
.btn-compact {
  min-height: 36px;
  padding: 0 14px;
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  gap: 6px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
}
.btn-compact::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(100%, var(--hit));
  height: var(--hit);
  transform: translate(-50%, -50%);
}
.btn-compact.btn-secondary,
.btn-compact.btn-ghost {
  box-shadow: inset 0 0 0 1px var(--hair), inset 0 1px 0 var(--edge);
}
.btn-compact svg {
  width: 16px;
  height: 16px;
}
.btn:disabled,
.btn[aria-disabled="true"] {
  background: var(--raised);
  color: var(--text2);
  box-shadow: inset 0 0 0 1px var(--hair);
  cursor: not-allowed;
  filter: none;
}
/* A row action marked .explains is aria-disabled but still opens the sheet that says why. */
.btn.explains[aria-disabled="true"] {
  cursor: pointer;
}
/* Waiting for the ten minutes: amber text, a clock, and plainly not a working button. */
.btn.btn-settling,
.btn.btn-settling:disabled,
.btn.btn-settling[aria-disabled="true"] {
  background: var(--amber-bg);
  color: var(--amber);
  box-shadow: inset 0 0 0 1px var(--amber-line);
}
.btn.is-busy {
  cursor: progress;
}
.btn svg {
  width: 18px;
  height: 18px;
}

/* Icon-only button, 44px square. */
.iconbtn {
  display: inline-grid;
  place-items: center;
  width: var(--hit);
  height: var(--hit);
  border-radius: var(--r);
  color: var(--text);
  transition: background-color 0.15s, transform 0.12s var(--ease);
}
.iconbtn:hover {
  background: var(--raised);
}
.iconbtn:active {
  transform: scale(0.94);
}

/* A text button for secondary actions inside cards: 44px tall, reads as a link. */
.textbtn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--hit);
  padding: 0 var(--s2);
  margin: 0 calc(-1 * var(--s2));
  border-radius: var(--r-sm);
  color: var(--text2);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.15s, background-color 0.15s;
}
.textbtn:hover {
  color: var(--text);
  background: var(--raised);
}
.textbtn svg {
  width: 16px;
  height: 16px;
}

.spin {
  display: inline-block;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-right-color: transparent;
  animation: spin 0.8s linear infinite;
  flex: none;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* ------------------------------------------------------------------ surfaces, cards, tiles, rows */

/* A card is a surface-1 panel with a hairline and a lit top edge. Groups of related content sit
   in one card; do not nest cards (use .inset inside one). */
.card {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.025), rgba(255, 255, 255, 0) 40%), var(--panel);
  border: 1px solid var(--hair);
  border-radius: var(--r-xl);
  padding: var(--s4);
  box-shadow: var(--shadow-card);
}
/* A card that is itself a link or opens something: lifts on hover, gives on press. */
.card-press {
  transition: transform 0.15s var(--ease), border-color 0.15s, background-color 0.15s;
}
.card-press:active {
  transform: scale(0.985);
}
@media (hover: hover) {
  .card-press:hover {
    border-color: var(--hair-strong);
    transform: translateY(-2px);
  }
}
/* An inset group inside a card or a sheet: surface-2 with a hairline, no shadow. */
.inset {
  background: var(--raised);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  padding: var(--s3) var(--s4);
}
.card-head {
  display: flex;
  align-items: center;
  gap: var(--s3);
}
.card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2) var(--s4);
  flex-wrap: wrap;
  margin-top: var(--s2);
}
.card > .btn-block,
.card-action {
  margin-top: var(--s3);
}

/* Legacy letter tile. New code uses avatar() (below); the tile keeps working, restyled round
   with a quiet gradient so an unported page does not look like a different product. */
.tile {
  flex: none;
  width: var(--hit);
  height: var(--hit);
  border-radius: 50%;
  background: radial-gradient(120% 120% at 30% 20%, #2e353a, #1c2124);
  box-shadow: inset 0 0 0 1px var(--hair);
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: var(--fs-lg);
  color: var(--lime);
  line-height: 1;
  text-decoration: none;
}
.tile-lg {
  width: 60px;
  height: 60px;
  font-size: var(--fs-3xl);
}
.tile-lime {
  background: var(--lime);
  color: var(--ink);
}

/* Generated token avatar (ui.js avatar()). The gradient comes from the ticker, the letter is its
   first character; ui.js picks lightness so the letter keeps 4.5:1 or better. */
.avatar {
  --av: 40px;
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: var(--av);
  height: var(--av);
  border-radius: 50%;
  overflow: hidden;
  color: #fff;
  font-weight: 700;
  font-size: calc(var(--av) * 0.44);
  line-height: 1;
  letter-spacing: -0.02em;
  text-decoration: none;
  text-transform: uppercase;
  background: var(--av-bg, var(--raised));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.18);
  user-select: none;
}
.avatar[lang|="zh"] {
  font-size: calc(var(--av) * 0.46);
  font-weight: 600;
  letter-spacing: 0;
}
/* the sheen: a soft light from the top left */
.avatar::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(90% 70% at 28% 18%, rgba(255, 255, 255, 0.28), rgba(255, 255, 255, 0) 60%);
  pointer-events: none;
}
.avatar > span {
  position: relative;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
.avatar-sm {
  --av: 32px;
}
.avatar-lg {
  --av: 56px;
}
.avatar-xl {
  --av: 72px;
}

/* One list radius on every page, the same as .card: a list and a card side by side, or the same
   list on two pages, must not change corner. */
.rows {
  background: var(--panel);
  border: 1px solid var(--hair);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  min-height: 56px;
}
.row + .row {
  border-top: 1px solid var(--hair);
}
a.row {
  text-decoration: none;
}
/* .rows clips to its radius, so an outside ring on a full-width row is cut on three sides; the
   ring is drawn inside the row instead. */
.rows > .row:focus-visible,
.rows > li > .row:focus-visible {
  outline-offset: -3px;
  border-radius: 17px;
}
a.row,
button.row {
  transition: background-color 0.15s;
}
a.row:hover,
button.row:hover {
  background: rgba(255, 255, 255, 0.03);
}
a.row:active,
button.row:active {
  background: rgba(255, 255, 255, 0.05);
}
button.row {
  width: 100%;
  text-align: left;
}
.row-end {
  text-align: right;
  flex: none;
}
.row .rank {
  width: 24px;
  font-weight: 700;
  color: var(--text3);
  font-size: var(--fs-sm);
  flex: none;
}
.row-title {
  display: block;
  font-weight: 700;
  font-size: var(--fs-base);
  letter-spacing: -0.01em;
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.row-meta {
  display: block;
  color: var(--text2);
  font-size: var(--fs-sm);
  line-height: 1.4;
}

/* Figures and labels. A label is ash 14px; a key figure is at least 18px. */
.label {
  display: block;
  color: var(--text2);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.35;
}
.fig {
  display: block;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-lg);
}
.fig-sm {
  font-size: var(--fs-lead);
}
.fig-lg {
  font-size: var(--fs-xl);
}
.fig-xl {
  font-size: var(--fs-2xl);
}
.fig-2xl {
  font-size: var(--fs-hero);
  font-weight: 800;
}
.fig-lime {
  color: var(--lime);
}
.fig .of {
  color: var(--text2);
  font-weight: 600;
}

.kv {
  display: flex;
  justify-content: space-between;
  gap: var(--s2);
  flex-wrap: wrap;
  font-size: var(--fs-sm);
  color: var(--text2);
}
.kv b {
  color: var(--text);
  font-weight: 600;
}

/* Label and value lines, as in a confirmation. */
.kvrows {
  margin: 0;
  border-top: 1px solid var(--hair);
}
.kvrows > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s3);
  padding: var(--s3) 0;
  border-bottom: 1px solid var(--hair);
  font-size: var(--fs-md);
}
.kvrows dt {
  color: var(--text2);
}
.kvrows dd {
  margin: 0;
  font-weight: 600;
  text-align: right;
  overflow-wrap: anywhere;
}
.kvrows dd .sub {
  display: block;
  font-weight: 500;
}
/* kvrows as an inset group: the confirm sheet uses this. */
.kvrows.kv-inset {
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  background: var(--raised);
  padding: 0 var(--s4);
}
.kvrows.kv-inset > div:last-child {
  border-bottom: 0;
}

.stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--hair);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-card);
}
.stats > div {
  background: var(--panel);
  padding: var(--s3) var(--s4);
  min-width: 0;
}

/* ------------------------------------------------------------------ badges */

/* A short state word on a tint. 13px/700, 22px tall; each pairing is AA on its tint over a panel.
   Use badge(kind, text) from ui.js. Kinds: hot, new, settling, full, capped, neutral. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 22px;
  padding: 0 8px;
  border-radius: 999px;
  font-size: var(--fs-xs);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0;
  white-space: nowrap;
  vertical-align: middle;
  background: var(--raised);
  color: var(--text2);
  box-shadow: inset 0 0 0 1px var(--hair);
}
.badge svg {
  width: 12px;
  height: 12px;
}
.badge-hot {
  background: var(--lime-soft);
  color: var(--lime);
  box-shadow: inset 0 0 0 1px rgba(198, 240, 0, 0.22);
}
.badge-new {
  background: var(--teal-soft);
  color: var(--teal);
  box-shadow: inset 0 0 0 1px rgba(111, 227, 205, 0.22);
}
.badge-settling {
  background: var(--amber-bg);
  color: var(--amber);
  box-shadow: inset 0 0 0 1px var(--amber-line);
}
.badge-full {
  background: rgba(241, 244, 238, 0.1);
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--hair-strong);
}
.badge-capped {
  background: var(--err-bg);
  color: var(--err);
  box-shadow: inset 0 0 0 1px var(--err-line);
}

/* ------------------------------------------------------------------ progress */

.progress {
  position: relative;
  height: 6px;
  border-radius: 999px;
  background: var(--track);
  overflow: hidden;
}
.progress > i {
  display: block;
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, #a6d400, var(--lime));
  box-shadow: 0 0 10px rgba(198, 240, 0, 0.5);
  transition: width 0.5s var(--ease);
}
/* Anything minted shows as the start of a fill, not a dot: a launch-stage 0.23% of a 150px bar is
   a third of a pixel, which reads as an empty (broken) bar. */
.progress > i.has-some {
  min-width: 10px;
}
.progress-lg {
  height: 8px;
}
.progress-thin {
  height: 4px;
}
/* A meter: a bar with its percent in a badge at the end (ui.js meter()). */
.meter {
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-width: 0;
}
.meter > .progress,
.meter > .skel-bar {
  flex: 1;
  min-width: 24px;
  height: 6px;
}
.meter-pct {
  flex: none;
  min-width: 52px;
  text-align: right;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--lime);
  letter-spacing: -0.01em;
}
.meter.is-full .meter-pct {
  color: var(--text);
}

/* ------------------------------------------------------------------ chips */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--hit);
  padding: 0 14px;
  border-radius: var(--r);
  border: 1px solid var(--hair);
  background: var(--raised);
  color: var(--text2);
  font-size: var(--fs-sm);
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
  transition: color 0.15s, background-color 0.15s, border-color 0.15s, transform 0.12s var(--ease);
}
.chip:hover {
  color: var(--text);
  border-color: var(--hair-strong);
}
.chip:active {
  transform: scale(0.97);
}
.chip[aria-pressed="true"],
.chip[aria-current="page"],
.chip[aria-current="true"],
.chip[aria-selected="true"] {
  background: var(--text);
  border-color: var(--text);
  color: var(--bg);
}
.chip .count {
  font-weight: 500;
  opacity: 0.85;
}
.chip[aria-disabled="true"],
.chip:disabled {
  color: var(--text3);
  background: transparent;
  border-color: var(--hair);
  cursor: not-allowed;
  transform: none;
}

/* ------------------------------------------------------------------ dot-joined figures */

/* A line of short figures joined by a middle dot that never starts a wrapped line: each item
   carries its own leading dot, the list is shifted left by one dot's width and clipped there, so
   the dot of whichever item begins a line is cut off. Put spans (or any inline items) inside. */
.dotlist {
  --dot-w: 16px;
  display: flex;
  flex-wrap: wrap;
  margin-left: calc(-1 * var(--dot-w));
  clip-path: inset(-4px -4px -4px var(--dot-w));
  min-width: 0;
}
.dotlist > * {
  white-space: nowrap;
}
/* A forced line break inside a dotlist: an empty item as wide as the line (its own dot is
   suppressed). Do not reset the list's margin-left in page css; the shift is what hides the dots. */
.dotlist > .dotlist-br {
  flex-basis: 100%;
  height: 0;
}
.dotlist > .dotlist-br::before {
  content: none;
}
.dotlist > *::before {
  content: "·";
  display: inline-block;
  width: var(--dot-w);
  text-align: center;
  color: var(--text3);
  font-weight: 500;
}

/* ------------------------------------------------------------------ forms */

.field {
  margin-bottom: var(--s4);
}
.field > label,
.field-label {
  display: block;
  font-weight: 600;
  font-size: var(--fs-md);
  margin-bottom: 6px;
}
.input {
  display: block;
  width: 100%;
  min-height: 52px;
  border-radius: var(--r);
  background: var(--raised);
  border: 1px solid var(--line);
  padding: 0 14px;
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--text);
  transition: border-color 0.15s, box-shadow 0.15s;
}
textarea.input {
  min-height: 120px;
  padding: var(--s3) 14px;
  font-size: var(--fs-base);
  line-height: 1.5;
  resize: vertical;
}
.input.mono,
textarea.input.mono {
  font-family: var(--mono);
  font-size: var(--fs-base);
  font-weight: 500;
}
.input::placeholder {
  color: #9ea7a1;
  font-weight: 500;
}
.input:hover {
  border-color: var(--line-strong);
}
.input:focus {
  outline: none;
  border-color: var(--lime);
  box-shadow: 0 0 0 3px var(--lime-soft);
}
.input[aria-invalid="true"] {
  border-color: var(--err);
}
.input[aria-invalid="true"]:focus {
  box-shadow: 0 0 0 3px rgba(255, 138, 122, 0.18);
}
.input:disabled {
  color: var(--text2);
  cursor: not-allowed;
}
.field-hint {
  color: var(--text2);
  font-size: var(--fs-sm);
  margin-top: 6px;
}
.field-err {
  display: flex;
  gap: 6px;
  align-items: flex-start;
  color: var(--err);
  font-size: var(--fs-sm);
  margin-top: 6px;
  line-height: 1.45;
}
.field-err:empty {
  display: none;
}
.field-err svg {
  width: 16px;
  height: 16px;
  margin-top: 2px;
}
.input-row {
  display: flex;
  gap: var(--s2);
}
.input-row > .input {
  flex: 1;
  min-width: 0;
}

/* ------------------------------------------------------------------ notes, warnings, disclosure */

/* One line with an icon: info (ash), why (amber, the reason a button is waiting), err. */
.note,
.why,
.errline {
  display: flex;
  gap: var(--s2);
  align-items: flex-start;
  font-size: var(--fs-sm);
  line-height: 1.5;
  margin: var(--s2) 0 0;
}
.note {
  color: var(--text2);
}
.why {
  color: var(--amber);
}
.errline {
  color: var(--err);
}
.note svg,
.why svg,
.errline svg {
  width: 16px;
  height: 16px;
  margin-top: 3px;
}
html[lang|="zh"] .note svg,
html[lang|="zh"] .why svg,
html[lang|="zh"] .errline svg {
  margin-top: 4px;
}

.callout {
  display: flex;
  gap: var(--s3);
  align-items: flex-start;
  background: var(--raised);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  padding: var(--s3) 14px;
  font-size: var(--fs-md);
}
.callout svg {
  width: 18px;
  height: 18px;
  margin-top: 3px;
}
.callout-warn {
  background: var(--amber-bg);
  border-color: var(--amber-line);
  color: var(--text);
}
.callout-warn svg {
  color: var(--amber);
}
.callout-err {
  background: var(--err-bg);
  border-color: var(--err-line);
}
.callout-err svg {
  color: var(--err);
}

details.disclosure,
details.warn {
  background: var(--panel);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
}
details.warn {
  background: var(--amber-bg);
  border-color: var(--amber-line);
}
details.disclosure > summary,
details.warn > summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--s2);
  min-height: 48px;
  padding: 0 14px;
  font-weight: 600;
  cursor: pointer;
  border-radius: var(--r-lg);
}
details.warn > summary {
  color: var(--amber);
}
details.disclosure > summary::-webkit-details-marker,
details.warn > summary::-webkit-details-marker {
  display: none;
}
details > summary .chev {
  margin-left: auto;
  transition: transform 0.2s var(--ease);
}
details[open] > summary .chev {
  transform: rotate(180deg);
}
details.disclosure > :not(summary),
details.warn > :not(summary) {
  margin: 0;
  padding: 0 14px 14px;
  font-size: var(--fs-md);
  color: var(--text);
}
details.disclosure > :not(summary) + :not(summary),
details.warn > :not(summary) + :not(summary) {
  padding-top: 0;
}

/* A closed explanation: a row with an icon, a title and a reading time, which opens into prose.
   For the documentation a page carries under its working part, so it does not double the page. */
details.learn {
  background: var(--panel);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
}
details.learn > summary {
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 64px;
  padding: var(--s2) var(--s4);
  cursor: pointer;
  border-radius: var(--r-lg);
  transition: background-color 0.15s;
}
details.learn > summary::-webkit-details-marker {
  display: none;
}
details.learn > summary:hover {
  background: rgba(255, 255, 255, 0.025);
}
details.learn > summary:focus-visible {
  outline-offset: -3px;
}
.learn-ic {
  display: grid;
  place-items: center;
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--raised);
  box-shadow: inset 0 0 0 1px var(--hair);
  color: var(--text2);
}
.learn-t {
  flex: 1;
  min-width: 0;
}
.learn-title {
  display: block;
  font-weight: 700;
  font-size: var(--fs-base);
  letter-spacing: -0.01em;
  line-height: 1.35;
}
.learn-meta {
  display: block;
  color: var(--text2);
  font-size: var(--fs-sm);
}
details.learn > summary .chev {
  margin-left: 0;
  color: var(--text2);
}
.learn-body {
  max-width: none;
  padding: var(--s1) var(--s4) var(--s2);
  border-top: 1px solid var(--hair);
}
.learn-body > * {
  max-width: 68ch;
}
.learn-body p:first-child {
  margin-top: var(--s3);
}
.callout-title {
  margin: 0;
  font-weight: 700;
}
.callout-body {
  margin: var(--s1) 0 0;
  color: var(--text);
}

/* Look-alike ticker warning (similar.js). */
.similar {
  display: block;
  color: var(--amber);
  font-size: var(--fs-sm);
  margin: var(--s2) 0 0;
}
.similar a {
  color: var(--amber);
  font-weight: 700;
  text-underline-offset: 3px;
  padding-block: 10px;
  margin-block: -10px;
}

/* ------------------------------------------------------------------ inscription text */

.inscr {
  background: var(--well);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  padding: var(--s1) 14px var(--s3);
}
.inscr-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  min-height: var(--hit);
}
.inscr-head .label {
  display: flex;
  align-items: center;
  gap: 6px;
}
.inscr code,
.inscr pre {
  display: block;
  margin: 0;
  padding: 0;
  background: none;
  font-family: var(--mono);
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--lime);
  white-space: pre-wrap;
  /* ui.js breakable() puts break points after json punctuation; a token longer than the line
     (a 64-character id) still breaks anywhere */
  overflow-wrap: anywhere;
}

.copyfield {
  display: block;
  width: 100%;
  margin-top: var(--s2);
  min-height: var(--hit);
  padding: 0 var(--s3);
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--raised);
  font-family: var(--mono);
  font-size: var(--fs-sm);
  color: var(--text);
}

/* ------------------------------------------------------------------ skeletons */

/* A shimmer sweep drawn by a moving highlight (transform only), over a flat placeholder. */
.skel {
  position: relative;
  overflow: hidden;
  display: block;
  border-radius: 6px;
  background: var(--raised);
}
.skel::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.06) 50%, rgba(255, 255, 255, 0) 100%);
  animation: skel 1.5s ease-in-out infinite;
}
@keyframes skel {
  to {
    transform: translateX(100%);
  }
}
.skel-line {
  height: 14px;
  margin: 6px 0;
}
.skel-fig {
  height: 22px;
  width: 72px;
}
.skel-tile {
  width: var(--hit);
  height: var(--hit);
  border-radius: 50%;
}
.skel-avatar {
  width: var(--av, 40px);
  height: var(--av, 40px);
  border-radius: 50%;
  flex: none;
}
.skel-btn {
  height: var(--btn-h);
  border-radius: var(--r);
}
.skel-bar {
  height: 6px;
  border-radius: 999px;
}
.skel-card {
  pointer-events: none;
}
/* On a surface-2 group (an inset, the confirm rows) the placeholder steps up one surface, or it
   would be the same colour as its ground. */
.inset .skel,
.kv-inset .skel {
  background: var(--raised-hover);
}

/* ------------------------------------------------------------------ empty and error states */

.state {
  text-align: center;
  padding: var(--s8) var(--s4);
  background: var(--panel);
  border: 1px solid var(--hair);
  border-radius: var(--r-xl);
}
.state-icon {
  display: inline-grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--raised);
  box-shadow: inset 0 0 0 1px var(--hair);
  color: var(--text2);
  margin-bottom: var(--s3);
}
.state-icon svg {
  width: 26px;
  height: 26px;
}
.state-err .state-icon {
  background: var(--err-bg);
  color: var(--err);
}
.state-title {
  font-size: var(--fs-lg);
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 var(--s1);
}
.state-body {
  color: var(--text2);
  font-size: var(--fs-md);
  max-width: 44ch;
  margin: 0 auto;
}
.state .btn {
  margin-top: var(--s4);
  min-width: 200px;
}

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

.steps {
  list-style: none;
  margin: 0;
  padding: 0;
}
.step {
  display: flex;
  gap: var(--s3);
  align-items: flex-start;
  padding: 10px 0;
}
.step + .step {
  border-top: 1px solid var(--hair);
}
.step-dot {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--raised);
  color: var(--text2);
}
.step-dot svg {
  width: 16px;
  height: 16px;
}
.step-dot .spin {
  width: 16px;
  height: 16px;
}
.step[data-state="done"] .step-dot {
  background: var(--lime);
  color: var(--ink);
}
.step[data-state="active"] .step-dot {
  color: var(--lime);
}
.step[data-state="warn"] .step-dot {
  background: var(--amber-bg);
  color: var(--amber);
}
.step[data-state="err"] .step-dot {
  background: var(--err-bg);
  color: var(--err);
}
.step[data-state="todo"] .step-title {
  color: var(--text2);
}
.step-title {
  font-weight: 600;
  line-height: 28px;
}
.step-body {
  color: var(--text2);
  font-size: var(--fs-sm);
  margin: 0;
}
.step-body a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--hit);
  color: var(--lime);
  text-underline-offset: 3px;
}
.step-body a svg {
  width: 16px;
  height: 16px;
}

/* ------------------------------------------------------------------ sticky action bar */

.actionbar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: var(--bottom-fixed);
  z-index: 40;
  /* opaque: at 97% the red and amber lines scrolling behind it read as text colliding with text */
  background: var(--bg);
  border-top: 1px solid var(--hair);
  box-shadow: 0 -12px 24px -16px rgba(0, 0, 0, 0.8);
}
.actionbar-in {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 10px var(--gutter);
}
.actionbar .why,
.actionbar .note {
  margin-top: 6px;
}

/* ------------------------------------------------------------------ bottom sheet */

.scrim {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(4, 6, 7, 0.64);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity 0.22s var(--ease);
}
.scrim.show {
  opacity: 1;
}
.sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 81;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.03), rgba(255, 255, 255, 0) 120px), var(--surface-3);
  border-radius: var(--r-2xl) var(--r-2xl) 0 0;
  border-top: 1px solid var(--hair-strong);
  box-shadow: 0 -24px 60px -20px rgba(0, 0, 0, 0.8);
  /* The sheet scrolls as a whole; its foot (actions and live note) is sticky, so it carries the
     bottom padding and the sheet itself has none below. */
  --sheet-px: var(--s5);
  --sheet-pb: calc(var(--s4) + var(--safe-b));
  padding: var(--s2) var(--sheet-px) 0;
  max-height: 88vh;
  max-height: 88dvh;
  overflow: auto;
  overscroll-behavior: contain;
  transform: translateY(100%);
  transition: transform 0.32s var(--ease);
}
.sheet.show {
  transform: none;
}
.sheet:focus {
  outline: none;
}
.sheet-grab {
  width: 36px;
  height: 5px;
  border-radius: 3px;
  background: var(--line-strong);
  margin: var(--s1) auto 6px;
}
.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s2);
}
.sheet-title {
  font-size: var(--fs-lg);
  font-weight: 700;
  letter-spacing: -0.01em;
  overflow-wrap: anywhere;
}
.sheet-head .iconbtn {
  margin-right: -10px;
  color: var(--text2);
}
.sheet-head .iconbtn svg {
  width: 20px;
  height: 20px;
}
.sheet-body > * + * {
  margin-top: var(--s3);
}
.sheet-sum {
  font-size: var(--fs-h1-lg);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 2px 0 var(--s3);
  overflow-wrap: anywhere;
}
.sheet-sum small {
  font-size: var(--fs-lg);
  color: var(--text2);
  font-weight: 600;
  letter-spacing: 0;
}
.sheet-sum-wrap {
  min-width: 0;
}
.sheet-sum-sub {
  margin: 2px 0 0;
  color: var(--text2);
  font-size: var(--fs-md);
  font-weight: 600;
}
.sheet-status:empty,
.sheet-status > div:empty {
  display: none;
}
.sheet-status > div + div {
  margin-top: 0;
}
/* The amount with its token avatar, as the head of a confirm sheet. */
.sheet-hero {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s1) 0 var(--s2);
}
.sheet-hero .sheet-sum {
  margin: 0;
  min-width: 0;
}
/* Sticky foot: stays at the bottom edge of the sheet while a long body scrolls under it. It spans
   the sheet's side padding so nothing shows beside it, and gets a hairline only while there is
   more content below (ui.js sets .is-under). */
.sheet-foot {
  position: sticky;
  bottom: 0;
  z-index: 1;
  display: grid;
  gap: var(--s2);
  margin: 0 calc(-1 * var(--sheet-px));
  padding: var(--s4) var(--sheet-px) var(--sheet-pb);
  background: var(--surface-3);
  border-top: 1px solid transparent;
}
.sheet-foot:not(:has(> .sheet-actions:not([hidden]), > .sheet-note:not(:empty))) {
  padding-top: 0;
}
.sheet.is-under .sheet-foot {
  border-top-color: var(--hair);
  box-shadow: 0 -10px 18px -12px rgba(0, 0, 0, 0.7);
}
.sheet-actions {
  display: grid;
  gap: var(--s2);
}
/* The live note inside a sheet: where a toast goes while a sheet is open. */
.sheet-note {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
  text-align: center;
}
.sheet-note:empty {
  display: none;
}

/* The quantity in a confirm sheet (ui.js confirm with `quantity`, used by confirmMint): a label and
   a stepper with 44px buttons, four quick picks, and the reason for the ceiling. */
.qty {
  background: var(--raised);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  padding: var(--s2) var(--s3) var(--s3) var(--s4);
}
.qty-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s3);
}
.qty-label {
  font-weight: 600;
  font-size: var(--fs-md);
}
.stepper {
  display: inline-flex;
  align-items: center;
  gap: var(--s1);
}
.stepper-btn {
  display: grid;
  place-items: center;
  width: var(--hit);
  height: var(--hit);
  border-radius: var(--r);
  background: var(--raised-hover);
  box-shadow: inset 0 0 0 1px var(--hair), inset 0 1px 0 var(--edge);
  color: var(--text);
  transition: background-color 0.15s, transform 0.12s var(--ease);
}
.stepper-btn:hover {
  background: #30373c;
}
.stepper-btn:active:not([aria-disabled="true"]) {
  transform: scale(0.94);
}
.stepper-btn[aria-disabled="true"] {
  background: transparent;
  color: var(--text3);
  cursor: not-allowed;
}
.stepper-val {
  min-width: 48px;
  text-align: center;
  font-size: var(--fs-xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.qty-picks {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--s2);
  margin: var(--s2) var(--s1) 0 0;
}
.qty-picks .chip {
  justify-content: center;
  padding: 0 var(--s2);
  background: var(--raised-hover);
}
.qty-picks .chip[aria-pressed="true"] {
  background: var(--text);
  border-color: var(--text);
  color: var(--bg);
}
.qty-picks .chip[aria-disabled="true"] {
  background: transparent;
  color: var(--text3);
}
.qty-hint {
  margin: var(--s2) 0 0;
  color: var(--text2);
  font-size: var(--fs-sm);
  line-height: 1.45;
}
.qty.is-off .stepper-val {
  color: var(--text2);
}

/* A run of several transactions: "k / n sent" over a bar, then one line per transaction. */
.batch-head {
  background: var(--raised);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
  padding: var(--s3) var(--s4);
}
.batch-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
  margin-bottom: var(--s2);
}
.batch-top .label {
  min-width: 0;
  overflow-wrap: anywhere;
}
.batch-count {
  flex: none;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.mintlog {
  list-style: none;
  margin: 0;
  padding: 0 0 0 var(--s4);
  background: var(--raised);
  border: 1px solid var(--hair);
  border-radius: var(--r-lg);
}
.mintlog-i {
  display: grid;
  grid-template-columns: 24px auto minmax(0, 1fr) var(--hit);
  align-items: center;
  column-gap: var(--s3);
  min-height: 48px;
  padding-right: var(--s1);
}
.mintlog-i + .mintlog-i {
  border-top: 1px solid var(--hair);
}
.mintlog-dot {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--line-strong);
  color: var(--text2);
}
.mintlog-dot .spin {
  width: 14px;
  height: 14px;
}
.mintlog-dot svg {
  width: 14px;
  height: 14px;
}
.mintlog-k {
  font-weight: 600;
  font-size: var(--fs-md);
  white-space: nowrap;
}
.mintlog-s {
  color: var(--text2);
  font-size: var(--fs-sm);
  text-align: right;
  line-height: 1.35;
}
.mintlog-x .iconbtn {
  color: var(--text2);
}
.mintlog-why {
  grid-column: 2 / -1;
  margin: 0 0 var(--s2);
  color: var(--err);
  font-size: var(--fs-sm);
}
.mintlog-i[data-state="skipped"] .mintlog-k {
  color: var(--text2);
}
.mintlog-i[data-state="skipped"] .mintlog-dot {
  box-shadow: inset 0 0 0 1.5px var(--line);
}
.mintlog-i[data-state="ask"] .mintlog-dot {
  box-shadow: inset 0 0 0 1.5px var(--lime-line);
  color: var(--lime);
}
.mintlog-i[data-state="ask"] .mintlog-s {
  color: var(--text);
  font-weight: 600;
}
.mintlog-i[data-state="sent"] .mintlog-dot {
  background: var(--raised-hover);
  box-shadow: inset 0 0 0 1px var(--hair-strong);
  color: var(--text);
}
.mintlog-i[data-state="done"] .mintlog-dot {
  background: var(--lime);
  box-shadow: none;
  color: var(--ink);
}
.mintlog-i[data-state="warn"] .mintlog-dot {
  background: var(--amber-bg);
  box-shadow: inset 0 0 0 1px var(--amber-line);
  color: var(--amber);
}
.mintlog-i[data-state="warn"] .mintlog-s {
  color: var(--amber);
}
.mintlog-i[data-state="err"] .mintlog-dot {
  background: var(--err-bg);
  box-shadow: inset 0 0 0 1px var(--err-line);
  color: var(--err);
}
.mintlog-i[data-state="err"] .mintlog-s {
  color: var(--err);
}

/* Wallet list in the picker sheet. */
.wlist {
  display: grid;
  gap: var(--s2);
}
.wlist-b {
  display: flex;
  align-items: center;
  gap: var(--s3);
  min-height: 56px;
  padding: 0 var(--s4);
  border-radius: var(--r-lg);
  background: var(--raised);
  box-shadow: inset 0 0 0 1px var(--hair);
  color: var(--text);
  font-weight: 600;
  text-decoration: none;
  text-align: left;
  transition: background-color 0.15s, transform 0.12s var(--ease);
}
.wlist-b:hover {
  background: var(--raised-hover);
}
.wlist-b:active {
  transform: scale(0.985);
}
.wlist-b img {
  width: 28px;
  height: 28px;
  border-radius: 8px;
}

/* ------------------------------------------------------------------ toast */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--bottom-fixed) + var(--actionbar-h) + var(--s4));
  z-index: 70;
  max-width: calc(100vw - 2 * var(--gutter));
  width: max-content;
  transform: translate(-50%, 10px) scale(0.98);
  background: var(--text);
  color: var(--bg);
  font-weight: 600;
  font-size: var(--fs-md);
  padding: var(--s3) 18px;
  border-radius: var(--r-lg);
  box-shadow: 0 12px 32px -8px rgba(0, 0, 0, 0.6);
  opacity: 0;
  transition: opacity 0.2s var(--ease), transform 0.2s var(--ease);
  pointer-events: none;
}
.toast.show {
  opacity: 1;
  transform: translate(-50%, 0);
}
.toast.is-err {
  background: var(--err);
  color: #1a0805;
}

/* ------------------------------------------------------------------ pages that still bring their
   own connect control (wallet.js attachWallet with a button) */

.deeplinks {
  margin: var(--s3) 0;
}
.deeplinks .quick {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}

/* ------------------------------------------------------------------ motion */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }
  .spin {
    border-right-color: currentColor;
    opacity: 0.6;
  }
  .skel::after,
  .live-dot::after {
    display: none;
  }
}

/* ------------------------------------------------------------------ desktop */

@media (min-width: 900px) {
  :root {
    --headh: 64px;
    --gutter: 24px;
    --bottom-fixed: 0px;
  }
  body {
    padding-bottom: var(--actionbar-h);
  }
  nav.tabbar {
    display: none;
  }
  .mark {
    font-size: var(--fs-xl);
  }
  .topnav {
    display: flex;
    gap: 2px;
    margin-left: var(--s6);
  }
  .topnav a {
    position: relative;
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 0 14px;
    border-radius: var(--r-sm);
    font-weight: 600;
    font-size: var(--fs-md);
    color: var(--text2);
    text-decoration: none;
    white-space: nowrap;
    transition: color 0.15s, background-color 0.15s;
  }
  .topnav a::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: -2px;
    bottom: -2px;
  }
  .topnav a:hover {
    color: var(--text);
    background: rgba(255, 255, 255, 0.04);
  }
  .topnav a[aria-current="page"] {
    color: var(--text);
    background: var(--raised);
    box-shadow: inset 0 0 0 1px var(--hair);
  }
  .topnav a[aria-current="page"]::before {
    content: "";
    position: absolute;
    left: 50%;
    bottom: -12px;
    width: 16px;
    height: 3px;
    margin-left: -8px;
    border-radius: 3px;
    background: var(--lime);
  }
  .walletbtn {
    max-width: none;
    font-size: var(--fs-md);
  }
  .main {
    padding-top: var(--s7);
    padding-bottom: var(--s9);
  }
  .main > :first-child {
    margin-top: 0;
  }
  h1 {
    font-size: var(--fs-h1-lg);
  }
  /* One inner padding for every card on a wide screen, so cards in one column line up. */
  .card {
    padding: var(--s5) var(--s6);
  }
  .grid-2 {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--s4);
    align-items: start;
  }
  .grid-side {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: var(--s7);
    align-items: start;
  }
  /* The same grid with a 400px side column, for a side card that carries a form's live preview
     (inscribe). Same 32px gaps. */
  .grid-side.grid-side-wide {
    grid-template-columns: minmax(0, 1fr) 400px;
  }
  .sticky-side {
    position: sticky;
    top: calc(var(--headh) + var(--s5));
  }
  .only-phone {
    display: none !important;
  }
  .only-desktop {
    display: revert !important;
  }
  /* The action bar is a phone pattern. A page that wants it on a wide screen too adds
     .actionbar-desktop; otherwise it shows the same action in a side card. */
  .actionbar:not(.actionbar-desktop) {
    display: none;
  }
  .sheet {
    left: 50%;
    right: auto;
    bottom: auto;
    top: 50%;
    width: 460px;
    max-height: min(86vh, 760px);
    border-radius: var(--r-2xl);
    border: 1px solid var(--hair-strong);
    --sheet-px: var(--s6);
    --sheet-pb: var(--s6);
    padding: var(--s3) var(--sheet-px) 0;
    transform: translate(-50%, -47%) scale(0.98);
    opacity: 0;
    transition: opacity 0.2s var(--ease), transform 0.24s var(--ease);
  }
  .sheet.show {
    transform: translate(-50%, -50%);
    opacity: 1;
  }
  .sheet-grab {
    display: none;
  }
  .toast {
    bottom: calc(var(--s7) + var(--actionbar-h));
  }
}
@media (min-width: 1200px) {
  .grid-3 {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--s4);
  }
}
