:root {
  /* leaf-green brand (matches chianfts / watchtower) */
  --brand: #237c41;        /* leaf-600 */
  --brand-2: #329a53;      /* leaf-500 */
  --brand-dark: #1d6336;   /* leaf-700 */
  --brand-soft: rgba(35,124,65,.12);
  /* light surfaces */
  --bg: #f4f6f5;
  --bg-2: #eaefec;
  --panel: #ffffff;
  --panel-2: #f4f7f5;
  --line: #e5eae7;
  --text: #1f2530;         /* ink-900 */
  --muted: #63728d;        /* ink-500 */
  /* vivid semantics (read well on white) */
  --green: #15a35a;
  --red: #e5484d;
  --amber: #c77d18;
  --radius: 14px;
  --shadow: 0 1px 2px rgba(16,24,40,.05), 0 10px 28px -16px rgba(16,24,40,.22);
  --shadow-sm: 0 1px 2px rgba(16,24,40,.06);
  --font: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-display: "Sora", "Inter", ui-sans-serif, system-ui, sans-serif;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background:
    radial-gradient(1100px 560px at 82% -12%, #dcf3e0 0%, transparent 60%),
    linear-gradient(135deg, #f6f8f7, #eceef1);
  background-attachment: fixed;
  color: var(--text);
  font: 15px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}
h1, h2, h3, .hero h2, .brand { font-family: var(--font-display); }
a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.muted { color: var(--muted); }

/* ---- top nav ---- */
.nav {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 16px;
  padding: 11px 22px; border-bottom: 1px solid var(--line);
  background: rgba(255,255,255,.82); backdrop-filter: blur(10px);
  box-shadow: 0 1px 0 rgba(16,24,40,.03);
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 800; font-size: 18px; }
.brand .mark {
  width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center;
  background: linear-gradient(135deg, var(--brand), var(--brand-2)); color: #fff; font-weight: 900;
}
.brand small { font-weight: 600; color: var(--muted); font-size: 11px; display: block; margin-top: -3px; }
.nav .links { display: flex; gap: 4px; margin-left: 10px; flex-wrap: wrap; }
.nav .links a {
  color: var(--muted); padding: 7px 13px; border-radius: 9px; font-weight: 600; font-size: 14px;
}
.nav .links a:hover { color: var(--brand-dark); background: var(--brand-soft); text-decoration: none; }
.nav .links a.active { color: #fff; background: linear-gradient(135deg, var(--brand), var(--brand-2)); box-shadow: var(--shadow-sm); }
.nav .spacer { flex: 1; }
.net { font-size: 12px; color: var(--muted); border: 1px solid var(--line); padding: 5px 11px; border-radius: 20px; }
.wallet-btn {
  background: var(--brand); border: 1px solid var(--brand); color: #fff; font-weight: 700;
  border-radius: 10px; padding: 8px 14px; font-size: 13px; cursor: pointer;
}
.wallet-btn:hover { background: var(--brand-dark); }
.wallet-btn.connected { background: rgba(46,204,113,.15); border-color: var(--green); color: var(--green); }

/* Lock button — only rendered when the access veil is on. Deliberately quiet:
   it sits beside Connect Wallet but must not compete with it, because locking
   is a thing you reach for on purpose, not something to invite by accident. */
.veil-lock {
  display: inline-flex; align-items: center; gap: 6px;
  background: transparent; border: 1px solid var(--line); color: var(--muted);
  border-radius: 10px; padding: 7px 11px; font-size: 12.5px; font-weight: 600;
  cursor: pointer; transition: color .12s, border-color .12s, background .12s;
}
.veil-lock svg { width: 13px; height: 13px; }
.veil-lock:hover { color: var(--text); border-color: var(--brand); background: rgba(255,255,255,.03); }
.veil-lock[hidden] { display: none; }

/* ---- layout ---- */
main { max-width: 1120px; margin: 0 auto; padding: 26px 22px 60px; }
.hero { margin-bottom: 22px; }
.hero h2 { margin: 0 0 4px; font-size: 26px; }
.hero p { margin: 0; color: var(--muted); }

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin: 18px 0; }
.stat { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 13px 16px; box-shadow: var(--shadow-sm); }
.stat b { display: block; font-size: 24px; }
.stat span { color: var(--muted); font-size: 12px; }

.toolbar { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; align-items: center; }
input, select, button, textarea {
  background: var(--panel-2); color: var(--text); border: 1px solid var(--line);
  border-radius: 10px; padding: 10px 13px; font: inherit;
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--brand); border-color: var(--brand); }
input[type="search"] { flex: 1; min-width: 220px; }
button { cursor: pointer; }
button.primary { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 700; }
button.primary:hover { background: var(--brand-dark); }
button.ghost:hover { border-color: var(--brand); color: #fff; }

/* ---- offer cards ---- */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 14px; }
.card {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 16px; display: flex; flex-direction: column; gap: 12px;
  box-shadow: var(--shadow-sm); transition: border-color .15s, transform .15s, box-shadow .15s;
}
.card:hover { border-color: var(--brand-2); transform: translateY(-2px); box-shadow: var(--shadow); }
.swap { display: flex; align-items: center; gap: 10px; }
.swap .side { flex: 1; }
.swap .arrow { color: var(--brand-2); font-size: 20px; }
.assetline { display: flex; align-items: center; gap: 8px; margin: 3px 0; }
.coin {
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  font-size: 11px; font-weight: 800; color: #fff; background: #333; flex: none;
}
.coin.xch { background: linear-gradient(135deg,#3fae6b,#2ecc71); }
.coin.cat { background: linear-gradient(135deg,#4655ff,#6f7bff); }
.coin.nft { background: linear-gradient(135deg,#a64bff,#d36bff); }
.assetline .amt { font-weight: 700; }
.assetline .code { color: var(--muted); font-size: 13px; }
.card .meta { display: flex; align-items: center; gap: 8px; justify-content: space-between; border-top: 1px solid var(--line); padding-top: 10px; }
.card .meta .left { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.card .meta a { font-size: 13px; }

.pill { font-size: 11px; padding: 2px 9px; border-radius: 20px; font-weight: 700; white-space: nowrap; }
.pill.accepted { background: rgba(46,204,113,.15); color: var(--green); }
.pill.rejected { background: rgba(255,92,108,.15); color: var(--red); }
.pill.pending_review { background: rgba(255,176,32,.15); color: var(--amber); }
.badge-verified { background: rgba(35,124,65,.18); color: var(--brand-2); }

/* ---- tables ---- */
table { width: 100%; border-collapse: collapse; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-sm); }
th, td { text-align: left; padding: 12px 15px; border-bottom: 1px solid var(--line); vertical-align: middle; }
th { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: .04em; }
tr:last-child td { border-bottom: none; }
tbody tr:hover { background: var(--panel-2); }

.empty { text-align: center; color: var(--muted); padding: 48px; }

/* ---- panels / forms ---- */
.panel { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; margin-bottom: 16px; box-shadow: var(--shadow-sm); }
.panel h3 { margin: 0 0 12px; }
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin: 8px 0; }
.field { flex: 1; min-width: 160px; }
textarea { width: 100%; min-height: 110px; font-family: ui-monospace, monospace; font-size: 12px; resize: vertical; }
.result { font-size: 13px; padding: 10px 13px; border-radius: 9px; margin-top: 10px; display: none; }

/* ---- offer detail ---- */
.detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 720px) { .detail-grid { grid-template-columns: 1fr; } }
.kv { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border-bottom: 1px dashed var(--line); }
.kv:last-child { border-bottom: none; }
.kv .k { color: var(--muted); }
.offerbox { background: var(--bg-2); border: 1px solid var(--line); border-radius: 10px; padding: 12px; word-break: break-all; font-size: 12px; max-height: 220px; overflow: auto; }
.btnrow { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.copied { color: var(--green); font-size: 13px; }
.back { display: inline-block; margin-bottom: 14px; color: var(--muted); }

.powered { font-size: 12px; color: var(--muted); margin-right: 14px; }
.powered a { color: var(--brand-2); }
.powered .pw { color: var(--brand-2); font-weight: 600; }
@media (max-width: 900px) { .powered { display: none; } }

footer { color: var(--muted); font-size: 12px; text-align: center; padding: 30px; border-top: 1px solid var(--line); }
footer .madewith { margin-top: 6px; }
footer .heart { color: var(--green); }

/* ============ TRADE TERMINAL ============ */
/* The trade route renders a full-bleed terminal; widen the shell for it. */
main:has(.terminal) { max-width: 1640px; padding: 14px 16px 40px; }
.terminal {
  display: grid; grid-template-columns: 244px 1fr; gap: 12px; align-items: start;
}
.bp, .bamt, .btot, .mid-last, .ps b, .pair-last b, .act-price, .act-amt, .tk-q b, .tk-total b, .depth-svg {
  font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1;
}
.live-dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--green);
  box-shadow: 0 0 0 3px rgba(34,211,154,.16); margin-right: 6px; vertical-align: middle;
  animation: livePulse 2s ease-in-out infinite; }
@keyframes livePulse { 0%,100% { opacity: 1; } 50% { opacity: .4; } }

/* ---- markets rail ---- */
.rail {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 11px; position: sticky; top: 74px; display: flex; flex-direction: column; gap: 9px;
  max-height: calc(100vh - 90px); box-shadow: var(--shadow-sm);
}
.rail-head { display: flex; justify-content: space-between; align-items: center; font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.rail-head span { background: var(--panel-2); color: var(--text); border-radius: 20px; padding: 1px 9px; font-size: 11px; }
.rail-filter { width: 100%; padding: 8px 11px; font-size: 13px; }
.rail-list { display: flex; flex-direction: column; gap: 3px; overflow: auto; flex: 1; margin: 0 -4px; padding: 0 4px; }
.mkt {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: transparent; border: 1px solid transparent; border-radius: 10px; padding: 8px 10px; cursor: pointer;
  transition: background .12s, border-color .12s;
}
.mkt:hover { background: var(--panel-2); }
.mkt.active { background: rgba(35,124,65,.14); border-color: var(--brand); }
.mkt .coin { width: 30px; height: 30px; font-size: 11px; }
.mkt-name { display: flex; flex-direction: column; line-height: 1.15; flex: 1; }
.mkt-name b { font-size: 14px; }
.mkt-name small { color: var(--muted); font-size: 11px; }
.mkt-cnt { display: flex; flex-direction: column; align-items: flex-end; font-weight: 700; font-size: 14px; line-height: 1.1; }
.mkt-cnt small { color: var(--muted); font-weight: 500; font-size: 10px; text-transform: uppercase; letter-spacing: .04em; }
.rail-note { font-size: 11px; color: var(--muted); border-top: 1px solid var(--line); padding-top: 9px; }

/* ---- main column ---- */
.term-main { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.pair-head {
  background:
    radial-gradient(420px 120px at 12% -40%, rgba(35,124,65,.14), transparent 70%),
    var(--panel);
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 13px 18px; display: flex; align-items: center; gap: 24px; flex-wrap: wrap;
}
.pair-id { display: flex; align-items: center; gap: 12px; }
.coin.lg { width: 44px; height: 44px; font-size: 15px; border-radius: 13px; }
.pair-title h2 { margin: 0; font-size: 22px; letter-spacing: -.01em; line-height: 1.1; }
.pair-title h2 span { font-size: 15px; font-weight: 600; margin-left: 1px; }
.pair-tags { display: flex; gap: 6px; margin-top: 5px; flex-wrap: wrap; }
.chip { font-size: 10.5px; font-weight: 700; padding: 2px 8px; border-radius: 6px; background: var(--panel-2); color: var(--muted); border: 1px solid var(--line); }
.chip.ok { background: rgba(34,211,154,.12); color: var(--green); border-color: rgba(34,211,154,.3); }
.chip.mono { font-family: ui-monospace, monospace; font-weight: 600; }

.pair-last { display: flex; align-items: center; gap: 10px; padding-left: 4px; }
.pair-last .pl-arrow { font-size: 16px; }
.pair-last.up .pl-arrow, .pair-last.up b { color: var(--green); }
.pair-last.down .pl-arrow, .pair-last.down b { color: var(--red); }
.pair-last b { font-size: 26px; font-weight: 800; letter-spacing: -.02em; display: block; line-height: 1.05; }
.pair-last small { font-size: 10px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); }

.pair-stats { display: flex; gap: 22px; flex-wrap: wrap; margin-left: auto; }
.ps { display: flex; flex-direction: column; gap: 2px; }
.ps label { font-size: 9.5px; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); }
.ps b { font-size: 14px; font-weight: 700; }
.ps b.red { color: var(--red); }
.ps b.green { color: var(--green); }

/* three-column terminal body: chart+activity | book | ticket+info */
.term-grid { display: grid; grid-template-columns: minmax(0,1fr) 312px 300px; gap: 12px; align-items: start; }
.term-col { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.term-grid .panel { margin-bottom: 0; }
.panel-h {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: 700;
  margin-bottom: 12px; border-bottom: 1px solid var(--line); padding-bottom: 9px;
}
.panel-h .ph-right { color: var(--text); font-weight: 600; letter-spacing: 0; text-transform: none; opacity: .7; }

/* ---- depth chart ---- */
.chart-panel { padding: 14px 14px 12px; }
.depth-wrap { background:
    linear-gradient(180deg, rgba(35,124,65,.05), transparent);
  border: 1px solid var(--line); border-radius: 10px; padding: 4px; }
.depth-svg { width: 100%; height: 224px; display: block; }
.dc-grid { stroke: var(--line); stroke-width: 1; stroke-dasharray: 2 5; opacity: .7; }
.dc-mid { stroke: var(--brand-2); stroke-width: 1.2; stroke-dasharray: 3 3; opacity: .8; }
.depth-legend { display: flex; gap: 16px; font-size: 11px; margin-top: 9px; color: var(--muted); }
.lg-bid { color: var(--green); } .lg-ask { color: var(--red); } .lg-mid { color: var(--brand-2); }

/* ---- recent listings ---- */
.activity-panel { padding: 14px 14px 10px; }
.act-head, .act-row {
  display: grid; grid-template-columns: 56px 1fr 1fr 76px; gap: 8px; align-items: center;
  padding: 5px 8px; font-size: 12px;
}
.act-head { color: var(--muted); font-size: 9.5px; text-transform: uppercase; letter-spacing: .05em; padding-bottom: 6px; }
.act-head span:nth-child(2), .act-head span:nth-child(3) { text-align: right; }
.act-list { display: flex; flex-direction: column; max-height: 248px; overflow: auto; }
.act-row { width: 100%; border: none; background: transparent; cursor: pointer; border-radius: 6px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.act-row:hover { background: var(--panel-2); }
.act-row.sel { outline: 1px solid var(--brand); background: rgba(35,124,65,.10); }
.act-side { font-size: 9.5px; font-weight: 800; padding: 2px 0; border-radius: 5px; text-align: center; letter-spacing: .03em; font-family: system-ui, sans-serif; }
.act-side.ask { background: rgba(255,92,108,.14); color: var(--red); }
.act-side.bid { background: rgba(34,211,154,.14); color: var(--green); }
.act-price { text-align: right; font-weight: 700; }
.act-price.red { color: var(--red); } .act-price.green { color: var(--green); }
.act-amt { text-align: right; color: var(--text); }
.act-time { text-align: right; color: var(--muted); font-size: 11px; font-family: system-ui, sans-serif; }

/* ---- order book ---- */
.book-panel { padding: 14px 12px; position: sticky; top: 74px; }
.book-head, .brow {
  display: grid; grid-template-columns: 1.25fr 1fr 1fr; gap: 8px; align-items: center;
  padding: 4px 12px; font-size: 12.5px;
}
.book-head { color: var(--muted); font-size: 9.5px; text-transform: uppercase; letter-spacing: .05em; padding-bottom: 7px; }
.book-head span:nth-child(2), .book-head span:nth-child(3) { text-align: right; }

/* Four columns on the Trade book: the price, the same price the other way up,
   the size and the total. Scoped to .wide and .brow so the Streaming Orders
   ladder — which renders .lvl rows against the same .book-head — keeps its
   three and is not silently knocked out of alignment. */
.book-head.wide, .brow { grid-template-columns: 1.15fr 1fr .95fr .95fr; }
.book-head.wide span:nth-child(4) { text-align: right; }
.bper { text-align: right; color: var(--muted); }
.brow.sel .bper, .brow:hover .bper { color: var(--text); }
.book-side { display: flex; flex-direction: column; }
.book-side.asks { justify-content: flex-end; }
.brow {
  position: relative; width: 100%; border: none; background: transparent; cursor: pointer;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; border-radius: 5px; overflow: hidden;
  transition: background .1s;
}
.brow .depth { position: absolute; top: 1px; bottom: 1px; right: 0; border-radius: 5px 0 0 5px; z-index: 0; }
.brow .depth.ask { background: linear-gradient(90deg, rgba(255,92,108,0), rgba(255,92,108,.18)); }
.brow .depth.bid { background: linear-gradient(90deg, rgba(34,211,154,0), rgba(34,211,154,.18)); }
.brow > span:not(.depth) { position: relative; z-index: 1; }
.brow .bp { font-weight: 700; }
.brow.ask .bp { color: var(--red); }
.brow.bid .bp { color: var(--green); }
.brow .bamt, .brow .btot { text-align: right; color: var(--text); }
.brow .btot { color: var(--muted); }
.brow:hover { background: var(--panel-2); }
.brow.sel { outline: 1px solid var(--brand); background: rgba(35,124,65,.12); }
.book-empty { color: var(--muted); font-size: 12px; padding: 16px 12px; text-align: center; }
.book-mid {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: 7px 0; padding: 9px 12px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  background: var(--bg-2);
}
.book-mid.up .mid-last { color: var(--green); } .book-mid.down .mid-last { color: var(--red); }
.mid-last { font-size: 18px; font-weight: 800; font-family: ui-monospace, monospace; }
.mid-last small { font-size: 11px; color: var(--muted); font-weight: 600; }
.mid-spread { font-size: 10.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

/* ---- trade ticket ---- */
.ticket-panel { padding: 11px 13px 12px; }
.tk-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; background: var(--bg-2); border: 1px solid var(--line); border-radius: 10px; padding: 3px; margin-bottom: 9px; }
.tk-tab { border: none; background: transparent; color: var(--muted); font-weight: 700; font-size: 12.5px; padding: 6px; border-radius: 7px; cursor: pointer; transition: background .12s, color .12s; }
.tk-tab:disabled { opacity: .35; cursor: not-allowed; }
.tk-tab.buy.on { background: rgba(34,211,154,.16); color: var(--green); }
.tk-tab.sell.on { background: rgba(255,92,108,.16); color: var(--red); }
.tk-quote { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 10px; }
.tk-q { background: var(--bg-2); border: 1px solid var(--line); border-radius: 10px; padding: 9px 11px; display: flex; flex-direction: column; gap: 2px; }
.tk-q label { font-size: 9.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.tk-q b { font-size: 15px; font-weight: 800; word-break: break-all; }
.tk-q span { font-size: 10px; color: var(--muted); }
.tk-total { display: flex; justify-content: space-between; align-items: baseline; padding: 10px 12px; border-radius: 10px; margin-bottom: 12px; border: 1px solid var(--line); }
.tk-total span { font-size: 12px; color: var(--muted); }
.tk-total b { font-size: 16px; font-weight: 800; }
.tk-total.buy { background: rgba(34,211,154,.08); border-color: rgba(34,211,154,.25); }
.tk-total.buy b { color: var(--green); }
.tk-total.sell { background: rgba(255,92,108,.08); border-color: rgba(255,92,108,.25); }
.tk-total.sell b { color: var(--red); }
.tk-meta { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.tk-rank { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.tk-cta { width: 100%; padding: 10px; border-radius: 9px; font-weight: 800; font-size: 13px; border: none; color: #fff; cursor: pointer; transition: filter .12s, transform .05s; }
.tk-cta:hover { filter: brightness(1.08); } .tk-cta:active { transform: translateY(1px); }
.tk-cta.buy { background: linear-gradient(135deg, #1fc78f, #22d39a); }
.tk-cta.sell { background: linear-gradient(135deg, #ff5160, #ff6b78); }
.tk-alt { display: block; text-align: center; margin-top: 11px; font-size: 12px; }
.tk-flash { font-size: 12.5px; margin-top: 10px; min-height: 16px; color: var(--muted); text-align: center; }
.tk-flash.ok { color: var(--green); } .tk-flash.err { color: var(--red); }
.tk-note { font-size: 11px; color: var(--muted); margin-top: 11px; text-align: center; line-height: 1.5; border-top: 1px solid var(--line); padding-top: 11px; }
.tk-empty { color: var(--muted); font-size: 13px; text-align: center; padding: 22px 8px; }

/* ---- order-matching sweep ticket ---- */
.tk-amt { margin-bottom: 12px; }
.tk-amt > label { display: flex; align-items: center; justify-content: space-between; font-size: 9.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin-bottom: 5px; }
.tk-max { background: var(--bg-2); border: 1px solid var(--line); color: var(--brand-2); font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 6px; cursor: pointer; text-transform: none; letter-spacing: 0; }
.tk-max:hover { border-color: var(--brand); }
.tk-in { width: 100%; background: var(--bg-2); border: 1px solid var(--line); border-radius: 10px; padding: 11px 12px; color: var(--text); font-size: 18px; font-weight: 800; font-family: ui-monospace, monospace; }
.tk-in:focus { outline: 2px solid var(--brand); border-color: var(--brand); }
.tk-range { width: 100%; margin-top: 9px; accent-color: var(--brand); }
.tk-fillbar { height: 5px; border-radius: 4px; background: var(--bg-2); border: 1px solid var(--line); overflow: hidden; margin: 4px 0 12px; }
.tk-fillbar span { display: block; height: 100%; background: linear-gradient(90deg, var(--brand), var(--brand-2)); }
.tk-rows { margin-bottom: 12px; }
.tk-row { display: flex; justify-content: space-between; align-items: baseline; font-size: 12.5px; padding: 4px 0; }
.tk-row span { color: var(--muted); }
.tk-row b { font-weight: 700; }
.tk-row.warn b { color: var(--amber); }
.tk-plan { margin-bottom: 12px; border: 1px solid var(--line); border-radius: 9px; background: var(--bg-2); }
.tk-plan summary { cursor: pointer; font-size: 11.5px; color: var(--muted); padding: 8px 11px; }
.tk-plan summary:hover { color: var(--text); }
.tk-plan-row { display: grid; grid-template-columns: 18px 1fr auto; gap: 8px; font-size: 12px; padding: 5px 11px; border-top: 1px solid var(--line); font-family: ui-monospace, monospace; }
.tk-plan-row span:first-child { color: var(--muted); }
.tk-plan-row .buy { color: var(--green); }
.tk-plan-row .sell { color: var(--red); }
.tk-cta:disabled { opacity: .45; cursor: not-allowed; filter: none; }
.brow.inplan { box-shadow: inset 2px 0 0 var(--brand); background: rgba(35,124,65,.08); }

/* ---- AMM: swap + pools ---- */
.sandbox { background: rgba(255,176,32,.1); border: 1px solid rgba(255,176,32,.3); color: var(--amber); border-radius: 10px; padding: 9px 14px; font-size: 12.5px; margin-bottom: 18px; }
.sandbox b { color: var(--amber); }
.swap-wrap { display: grid; grid-template-columns: minmax(0,1fr) 320px; gap: 18px; align-items: start; max-width: 880px; margin: 0 auto; }
@media (max-width: 760px) { .swap-wrap { grid-template-columns: 1fr; } }
.swap-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; }
.swap-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.swap-top h2 { margin: 0; font-size: 20px; }
.swap-top select { background: var(--panel-2); color: var(--text); border: 1px solid var(--line); border-radius: 9px; padding: 8px 11px; }
.swap-box { background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; margin-bottom: 4px; }
.swap-box label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.swap-in { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.swap-in input { flex: 1; background: transparent; border: none; color: var(--text); font-size: 24px; font-weight: 800; font-family: ui-monospace, monospace; width: 100%; outline: none; }
.swap-in .tok { font-weight: 800; color: var(--text); background: var(--panel); border: 1px solid var(--line); padding: 6px 12px; border-radius: 20px; font-size: 14px; white-space: nowrap; }
.swap-bal { font-size: 11.5px; color: var(--muted); margin-top: 6px; }
.mini { background: var(--panel); border: 1px solid var(--line); color: var(--brand-2); font-size: 10px; font-weight: 700; padding: 1px 6px; border-radius: 6px; cursor: pointer; margin-left: 6px; }
.swap-flip { text-align: center; margin: 2px 0; }
.swap-flip button { width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--line); background: var(--panel-2); color: var(--brand-2); cursor: pointer; font-size: 16px; }
.swap-flip button:hover { border-color: var(--brand); }
.swap-info { margin: 12px 0; }
.swap-info .kv { display: flex; justify-content: space-between; font-size: 12.5px; padding: 3px 0; }
.swap-info .kv .k { color: var(--muted); }
.swap-go { width: 100%; padding: 14px; border-radius: 12px; border: none; background: linear-gradient(135deg, var(--brand), var(--brand-2)); color: #fff; font-weight: 800; font-size: 15px; cursor: pointer; margin-top: 8px; }
.swap-go:hover { filter: brightness(1.08); }
.swap-go:disabled { opacity: .45; cursor: not-allowed; filter: none; }
.swap-go.sell { background: linear-gradient(135deg, #ff5160, #ff6b78); }
.swap-side .panel { margin-bottom: 14px; }
.faucet-row { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.faucet-row .ghost { font-size: 12px; padding: 7px 10px; }
.warn { color: var(--red); } .amber { color: var(--amber); }
.lp-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; background: var(--bg-2); border: 1px solid var(--line); border-radius: 11px; padding: 4px; margin-bottom: 14px; }
.lp-tab { border: none; background: transparent; color: var(--muted); font-weight: 800; padding: 9px; border-radius: 8px; cursor: pointer; }
.lp-tab.on { background: var(--panel); color: var(--text); }
.lp-label { display: flex; align-items: center; justify-content: space-between; font-size: 12px; color: var(--muted); margin-bottom: 7px; }
.rm-pct { text-align: center; font-size: 22px; font-weight: 800; margin: 6px 0; }
.pos-box { margin-top: 12px; padding: 11px; border: 1px solid var(--brand); border-radius: 10px; background: rgba(35,124,65,.07); }
.pos-box > b { display: block; margin-bottom: 6px; color: var(--brand-2); }
.swap-info .kv.warn span { color: var(--amber); }

/* ---- markets (trading pairs) table ---- */
/* Fill the page rather than a fixed 980px.
   This cap outranked everything downstream: widening `main` to 1440px left the
   table still 980px wide with 460px of empty page beside it, and the column
   percentages — correct against the container — were computing against 980px
   instead, so Price, 24h, Bid, Ask, Volume and Liquidity all clipped at 1280.
   One stale number produced both halves of the complaint: the empty space and
   the cramped columns. */
.markets-table { max-width: 100%; width: 100%; }
.markets-table .mkt-row { cursor: pointer; }
.markets-table th:nth-child(3), .markets-table td.price-cell { font-weight: 700; }
.markets-table td.price-cell, .markets-table td.green, .markets-table td.red { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; }
.markets-table th, .markets-table td { padding: 10px 14px; }          /* tighter rows */
.markets-table th.rank, .markets-table td.rank { width: 34px; text-align: center; padding-left: 8px; padding-right: 8px; }
.markets-table td.actions a { font-size: 13px; font-weight: 600; }
.markets-table tbody tr:hover { background: var(--brand-soft); }
.pill.amm { background: rgba(21,163,90,.14); color: var(--brand); font-size: 10px; padding: 1px 7px; margin-left: 6px; }

/* ---- compact page modifiers ("shrink the place") ---- */
.hero-sm { margin-bottom: 14px; }
.hero-sm h2 { font-size: 22px; }
.hero-sm p { font-size: 13.5px; }
.stats-sm { gap: 10px; margin: 12px 0 16px; }
.stats-sm .stat { padding: 11px 14px; }
.stats-sm .stat b { font-size: 21px; }

/* WHY THE MARKETS PAGE IS WIDE
   1020px is a good measure for reading prose and a bad one for a ten-column
   price table. Capped there, the table rendered 976px wide inside a 1440px
   window: a third of the screen unused down both sides while Pair, Volume and
   Liquidity fought over what was left. That is the "empty space and some
   things tightly packed" in the same view — one cause, not two.

   The trading terminal already takes 1640px on the same screens, so this is
   not a new claim on the layout, just consistency: the pages made of columns
   of numbers get the width; the pages made of sentences keep the 1120px
   default set on `main`. */
main:has(.markets-table) { max-width: 1440px; }
main:has(.markets-table) .toolbar { max-width: 100%; }
main:has(.markets-table) .toolbar input[type="search"] { min-width: 0; }

/* ---- market info ---- */
.info-panel { padding: 14px; }
.info-panel .kv { padding: 7px 0; font-size: 13px; }
.info-panel .kv .green { color: var(--green); font-weight: 700; }
.info-panel .kv .red { color: var(--red); font-weight: 700; }
.info-note { font-size: 11.5px; color: var(--muted); margin-top: 10px; line-height: 1.55; border-top: 1px solid var(--line); padding-top: 11px; }

/* ---- responsive ---- */
@media (max-width: 1340px) {
  /* THE .term-grid RULES THAT USED TO LIVE HERE ARE GONE. They were written
     before the terminal became a fixed-height single window, and by 2026-08-09
     they were actively breaking it.

     What they did at any width under 1340px — which includes 1293px, an
     ordinary 1366 laptop once you subtract chrome:
         collapse the grid to two columns
         move the ticket+tape column to `grid-column: 1 / -1` as a full-width
         ROW underneath, `flex-direction: row`

     Adding a row to a grid that is height-locked with `overflow: hidden` has
     only one outcome: the row is clipped. Measured at 1293x622 —
         .term-col.right   display=flex  dir=row  height 185px
           child .term-form   471px tall
           child .term-tape   471px tall
     two 471px panels inside a 185px box, with no scrollbar. That is the
     owner's screenshot: a ticket cut off above its own Buy button.

     Worse, the terminal-aware reflow already exists at `max-width: 1200px`
     below, with the explicit heights that make a stacked layout work. This
     block fired 140px earlier and did half the job, so 1201-1340px got the
     reflow without any of the compensation.

     One reflow, one breakpoint, and it lives with the terminal rules. */
  .book-panel { position: static; }
}
@media (max-width: 980px) {
  .term-grid { grid-template-columns: 1fr; }
  .term-grid > .term-col:last-child { flex-direction: column; }
  .pair-stats { gap: 16px; width: 100%; margin-left: 0; }
  .pair-last { margin-left: auto; }
}
@media (max-width: 820px) {
  .terminal { grid-template-columns: 1fr; }
  .rail { position: static; max-height: none; }
  .rail-list { max-height: 220px; }
}

/* ============ WALLET BUTTON + MODAL ============ */
.wallet-btn { display: inline-flex; align-items: center; gap: 7px; }
.wallet-btn .wdot { width: 7px; height: 7px; border-radius: 50%; background: var(--green); box-shadow: 0 0 0 3px rgba(46,204,113,.18); }
body.wc-lock { overflow: hidden; }
.wc-overlay {
  position: fixed; inset: 0; z-index: 100; display: none; align-items: center; justify-content: center;
  background: rgba(6,7,11,.66); backdrop-filter: blur(4px); padding: 20px;
}
.wc-overlay.open { display: flex; animation: wcfade .15s ease; }
@keyframes wcfade { from { opacity: 0; } to { opacity: 1; } }
.wc-modal {
  width: 100%; max-width: 440px; background: var(--panel); border: 1px solid var(--line);
  border-radius: 18px; padding: 24px; position: relative; box-shadow: 0 24px 70px rgba(0,0,0,.5);
  animation: wcpop .18s ease;
}
@keyframes wcpop { from { transform: translateY(8px) scale(.98); opacity: .6; } to { transform: none; opacity: 1; } }
.wc-x { position: absolute; top: 14px; right: 14px; background: transparent; border: none; color: var(--muted); font-size: 16px; cursor: pointer; padding: 4px 8px; }
.wc-x:hover { color: var(--text); }
.wc-modal h3 { margin: 0 0 4px; font-size: 19px; }
.wc-sub { margin: 0 0 18px; color: var(--muted); font-size: 13px; }
.wc-options { display: flex; flex-direction: column; gap: 10px; }
.wc-opt {
  display: flex; align-items: center; gap: 13px; width: 100%; text-align: left; cursor: pointer;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 13px; padding: 13px 15px;
  transition: border-color .12s, transform .12s, background .12s;
}
.wc-opt:hover { border-color: var(--brand); transform: translateY(-1px); }
.wc-opt.dim { opacity: .6; }
.wc-ic { width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center; font-weight: 900; font-size: 18px; color: #fff; flex: none; }
.wc-ic.sage { background: linear-gradient(135deg,#3fae6b,#2ecc71); }
.wc-meta { flex: 1; display: flex; flex-direction: column; line-height: 1.25; }
.wc-meta b { font-size: 15px; }
.wc-meta small { color: var(--muted); font-size: 12px; }
.wc-arrow { color: var(--muted); font-size: 20px; }
.wc-pair { display: none; margin-top: 16px; text-align: center; }
.wc-qr { width: 200px; height: 200px; border-radius: 12px; background: #fff; padding: 8px; }
.wc-qr-fallback { color: var(--muted); font-size: 13px; padding: 14px; }
.wc-pair-help { font-size: 12.5px; color: var(--muted); margin: 12px 0 8px; }
.wc-uri-row { display: flex; gap: 8px; }
.wc-uri { flex: 1; font-family: ui-monospace, monospace; font-size: 11px; padding: 9px 11px; }
.wc-copy { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 700; padding: 9px 14px; border-radius: 10px; white-space: nowrap; }
.wc-copy:hover { background: var(--brand-dark); }
.wc-pid { text-align: left; background: var(--panel-2); border: 1px solid var(--line); border-radius: 12px; padding: 14px; }
.wc-pid b { font-size: 13px; } .wc-pid p { font-size: 12.5px; color: var(--muted); margin: 6px 0 10px; }
.wc-status { display: none; margin-top: 14px; font-size: 13px; padding: 10px 12px; border-radius: 10px; background: var(--panel-2); text-align: center; }
.wc-status.ok { background: rgba(46,204,113,.15); color: var(--green); }
.wc-status.err { background: rgba(255,92,108,.15); color: var(--red); }
.wc-foot { margin-top: 18px; font-size: 12px; color: var(--muted); border-top: 1px solid var(--line); padding-top: 14px; line-height: 1.5; }
.wc-settings-link { display: inline-block; margin-top: 6px; }

/* ---- CLOB order ticket / orders / trades ---- */
.ot-tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-bottom: 9px; }
.ot-tab { border: 1px solid var(--line); background: var(--bg-2); color: var(--muted); font-weight: 600; font-size: 11.5px; padding: 5px; border-radius: 7px; cursor: pointer; }
.ot-tab.on { background: var(--panel); color: var(--text); border-color: var(--brand); }
.ord-field { margin-bottom: 8px; }
.ord-field.hidden { display: none; }
.ord-field label { display: flex; align-items: center; justify-content: space-between; font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); margin-bottom: 4px; }
.ord-in { width: 100%; background: var(--bg-2); border: 1px solid var(--line); border-radius: 8px; padding: 8px 11px; color: var(--text); font-size: 14px; font-weight: 700; font-family: ui-monospace, monospace; }
.ord-in:focus { outline: 2px solid var(--brand); border-color: var(--brand); }
.ord-total { display: flex; justify-content: space-between; align-items: baseline; padding: 7px 10px; border: 1px solid var(--line); border-radius: 8px; background: var(--bg-2); margin-bottom: 7px; }
.ord-total span { font-size: 12px; color: var(--muted); }
.ord-total b { font-weight: 800; }
.ord-avail { font-size: 11px; margin-bottom: 8px; }
.orders-panel { margin-top: 14px; }
.myord { display: grid; grid-template-columns: 44px 1fr auto auto; gap: 8px; align-items: center; font-size: 12px; padding: 6px 0; border-bottom: 1px solid var(--line); }
.myord:last-child { border-bottom: none; }
.mo-side { font-weight: 800; font-size: 10px; padding: 2px 6px; border-radius: 5px; text-align: center; }
.mo-side.buy { background: rgba(34,211,154,.16); color: var(--green); }
.mo-side.sell { background: rgba(255,92,108,.16); color: var(--red); }
.mo-p, .mo-a { font-family: ui-monospace, monospace; }
.mo-x { color: var(--red); font-size: 11px; }
.trades-panel { margin-top: 16px; }
.trade-head, .trow { display: grid; grid-template-columns: 1.4fr 1fr .7fr 1fr; gap: 8px; }
.trade-head { font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); padding: 6px 12px; border-bottom: 1px solid var(--line); }
.trade-tape { max-height: 220px; overflow: auto; }
.trow { font-size: 12.5px; padding: 5px 12px; border-bottom: 1px solid var(--line); font-family: ui-monospace, monospace; }
.trow:last-child { border-bottom: none; }
.book-panel .brow { cursor: pointer; }

/* ---- live-offer take panel (Trade page) ---- */
.take-panel { padding: 12px 14px 13px; }
.tkr { display: flex; align-items: baseline; justify-content: space-between; padding: 6px 0; border-bottom: 1px dashed var(--line); font-size: 13px; }
.tkr:last-of-type { border-bottom: none; }
.tkr span { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
.tkr b { font-weight: 800; font-family: ui-monospace, monospace; word-break: break-all; text-align: right; }
.take-panel .tk-cta { margin-top: 10px; }
.tk-row2 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 6px; margin-top: 9px; }
.tk-row2 .ghost { text-align: center; padding: 7px 6px; font-size: 12px; border-radius: 8px; }
.info-ent { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }

/* ---- Trade v2: clean two-sided book ---- */
.trade2 { display: grid; grid-template-columns: minmax(0,1fr) 318px; gap: 14px; align-items: start; }
@media (max-width: 920px) { .trade2 { grid-template-columns: 1fr; } }
.term-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 12px; padding: 11px 15px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px; font-size: 12.5px; color: var(--muted); }
.term-foot b { color: var(--text); font-weight: 700; }
.term-foot .dot { opacity: .4; }
.term-foot a { margin-left: auto; color: var(--brand); font-weight: 600; }

/* Buy/Sell segmented toggle */
.tk-seg { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; background: var(--bg-2); border: 1px solid var(--line);
  border-radius: 10px; padding: 3px; margin-bottom: 11px; }
.tk-seg button { border: none; background: transparent; color: var(--muted); font-weight: 700; font-size: 13px;
  padding: 8px; border-radius: 7px; cursor: pointer; transition: background .12s, color .12s; }
.tk-seg button.on.buy { background: rgba(34,211,154,.16); color: var(--green); }
.tk-seg button.on.sell { background: rgba(255,92,108,.16); color: var(--red); }
.tkr b.ent { font-family: inherit; font-weight: 700; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* tighter, prettier book */
.book-panel { padding: 12px 12px 14px; }
/* Spacing for both books; COLUMNS for the three-column one only.
   This rule used to set grid-template-columns for `.book-head, .brow` — three
   tracks. `.brow` is the Trade book row and has four cells (price, per-XCH,
   amount, total). `.book-head.wide` beat this rule on specificity and kept its
   four, so the header had four tracks and the rows had three: every row's
   per-XCH figure landed under the price heading and ran into the price itself.
   That is the collision on /#/trade.
   The four-column rule above says in its own comment that it is "scoped to
   .wide and .brow ... so the ladder keeps its three and is not silently
   knocked out of alignment" — and then this rule, added later for spacing,
   silently knocked it out of alignment. Padding and font-size are shared;
   track counts are not. */
.book-head, .brow { padding: 3px 10px; font-size: 12px; }
/* Only the three-column header. The ladder's own rows are `#clobBook .lvl`,
   which sets its tracks at higher specificity, so naming .lvl here would read
   as load-bearing while doing nothing. */
.book-head:not(.wide) { grid-template-columns: 1.25fr 1fr .9fr; }
.brow { padding-top: 4px; padding-bottom: 4px; }
.book-mid { margin: 6px 0; padding: 8px 11px; }
.mid-last { font-size: 16px; }
.brow .depth.ask { background: linear-gradient(90deg, rgba(255,92,108,0), rgba(255,92,108,.16)); }
.brow .depth.bid { background: linear-gradient(90deg, rgba(34,211,154,0), rgba(34,211,154,.16)); }
.take-panel .tk-cta { margin-top: 11px; padding: 11px; font-size: 13.5px; }

/* ---- network toggle pill ---- */
.net { cursor: pointer; font-weight: 700; transition: background .12s, color .12s, border-color .12s; user-select: none; }
.net:hover { border-color: var(--brand); color: var(--text); }
.net.testnet { color: var(--amber, #c77d18); border-color: rgba(199,125,24,.4); background: rgba(199,125,24,.1); }
.net.switching { opacity: .6; cursor: progress; }

/* ---- Trade: fit the whole terminal in one viewport (no scroll to trade) ---- */
main:has(.terminal) { padding-top: 10px; padding-bottom: 16px; }
.terminal .pair-head { padding: 9px 16px; gap: 16px; }
.terminal .coin.lg { width: 36px; height: 36px; font-size: 13px; border-radius: 11px; }
.terminal .pair-title h2 { font-size: 18px; }
.terminal .pair-title h2 span { font-size: 13px; }
.terminal .pair-tags { margin-top: 3px; }
.terminal .pair-last b { font-size: 20px; }
.terminal .pair-stats { gap: 16px; }
.terminal .term-main { gap: 10px; }
.terminal .chart-panel { padding: 9px 12px 7px; }
.terminal .chart-panel .panel-h { margin-bottom: 6px; }
.terminal .depth-wrap { padding: 3px; }
.terminal .depth-svg { height: 132px; }
.terminal .take-panel { padding: 11px 13px 12px; }
.terminal .take-panel .tkr { padding: 4px 0; font-size: 12.5px; }
.terminal .term-foot { margin-top: 10px; padding: 8px 14px; }

/* ---- markets table: dexie-style numeric alignment ---- */
.markets-table th:nth-child(n+3), .markets-table td:nth-child(n+3) { text-align: right; }
.markets-table th:nth-child(2), .markets-table td:nth-child(2) { text-align: left; }
.markets-table td.green, .markets-table td.red { font-weight: 600; }
.markets-table thead th { font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: 600; }
.markets-table td.actions a { white-space: nowrap; }

/* ---- take panel: target-network note ---- */
.tk-net { margin-top: 9px; font-size: 11px; color: var(--muted); text-align: center; border-top: 1px solid var(--line); padding-top: 9px; }
.tk-net b { color: var(--text); }
.tk-net.testnet b { color: var(--amber, #c77d18); }

/* --- Segmented controls (Markets: Tokens/NFTs · Recent Trades filters) --- */
.seg-bar { justify-content: flex-start; gap: 12px; }
.seg-bar input[type="search"] { margin-left: auto; }
.seg {
  display: inline-flex; gap: 4px; background: var(--bg-2);
  border: 1px solid var(--line); border-radius: 11px; padding: 4px;
}
.seg button {
  appearance: none; border: 1px solid transparent; background: transparent;
  color: var(--muted); font: inherit; font-weight: 700; font-size: 13px;
  padding: 7px 14px; border-radius: 8px; cursor: pointer; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 7px; transition: background .12s, color .12s;
}
.seg button:hover { color: var(--text); }
.seg button.on { background: var(--panel); color: var(--text); border-color: var(--brand); }
.seg .cnt {
  font-size: 11px; font-weight: 800; padding: 1px 7px; border-radius: 20px;
  background: rgba(127,127,127,.16); color: inherit;
}
.seg button.on .cnt { background: rgba(21,163,90,.18); color: var(--brand); }

/* --- CLOB terminal --- */
.clob-grid { display: grid; grid-template-columns: 1.1fr .9fr .7fr; gap: 14px; align-items: start; }
@media (max-width: 1080px) { .clob-grid { grid-template-columns: 1fr; } }
.clob-bal { margin-left: auto; display: flex; gap: 16px; align-items: center; font-size: 13px; }
.clob-bal b { font-family: ui-monospace, Menlo, monospace; }
.pad { padding: 12px 14px; }
.muted.pad { padding: 18px 14px; text-align: center; }
#clobBook .lvl {
  position: relative; display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 6px;
  padding: 3px 12px; font-size: 12px; font-family: ui-monospace, Menlo, monospace;
  cursor: pointer; align-items: center;
}
#clobBook .lvl:hover { background: rgba(127,127,127,.08); }
#clobBook .lvl .bar { position: absolute; right: 0; top: 0; bottom: 0; opacity: .1; }
#clobBook .lvl.ask .bar { background: var(--red); }
#clobBook .lvl.bid .bar { background: var(--green); }
#clobBook .lvl .q, #clobBook .lvl .t { text-align: right; position: relative; }
#clobBook .lvl .p { position: relative; }
.fills { max-height: 340px; overflow: auto; }
.fills .fill {
  display: grid; grid-template-columns: 1fr 1fr auto; gap: 8px; padding: 4px 14px;
  font-size: 12px; font-family: ui-monospace, Menlo, monospace;
}
.fld { display: block; margin: 10px 0; }
.fld span { display: block; font-size: 12px; color: var(--muted); margin-bottom: 5px; font-weight: 600; }
.fld input {
  width: 100%; padding: 10px 12px; border-radius: 9px; border: 1px solid var(--line);
  background: var(--bg-2); color: var(--text); font: inherit;
  font-family: ui-monospace, Menlo, monospace;
}
.fld-row { display: flex; justify-content: space-between; align-items: center; font-size: 13px; margin: 8px 0; }
button.wide { width: 100%; padding: 11px; margin-top: 6px; }
.ord-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.ord-table th { text-align: left; font-size: 11px; color: var(--muted); padding: 8px 14px; font-weight: 700; }
.ord-table td { padding: 8px 14px; border-top: 1px solid var(--line); }

/* --- Asset avatars: real artwork, or a colour derived from the asset id --- */
.av {
  position: relative; width: 34px; height: 34px; flex: 0 0 34px;
  border-radius: 10px; overflow: hidden; display: inline-flex;
  align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800; color: #fff; letter-spacing: .3px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.10), 0 1px 4px rgba(0,0,0,.28);
  background: var(--bg-2);
}
.av img { width: 100%; height: 100%; object-fit: cover; display: block; }
.av i { display: none; font-style: normal; }
.av.av-fallback { background: linear-gradient(135deg,#5a4bff,#a64bff); }
.av.av-fallback i { display: block; }
.av.nft-ring { box-shadow: inset 0 0 0 2px rgba(214,107,255,.55), 0 1px 4px rgba(0,0,0,.28); }
.av.lg { width: 46px; height: 46px; flex-basis: 46px; border-radius: 13px; font-size: 14px; }
.av.sm { width: 26px; height: 26px; flex-basis: 26px; border-radius: 8px; font-size: 9px; }

.mktcell { display: flex; align-items: center; gap: 10px; min-width: 0; }
.mktcell-txt { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.mktcell-txt b { font-weight: 700; }
.mktcell-txt small { font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 190px; }
.nowrap { white-space: nowrap; }
.trades-table td { vertical-align: middle; }

/* Side tags */
.tag { font-size: 11px; font-weight: 800; padding: 3px 10px; border-radius: 7px; letter-spacing: .3px; }
.tag.buy  { background: rgba(34,211,154,.16); color: var(--green); }
.tag.sell { background: rgba(255,92,108,.16); color: var(--red); }
.pill.net { background: rgba(127,140,170,.16); color: var(--muted); }

/* --- Pagination --- */
.pager {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin: 16px 0 28px; padding: 12px 14px;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px;
}
.pg-info { font-size: 13px; color: var(--muted); }
.pg-info b { color: var(--text); }
.pg-btns { display: flex; gap: 5px; flex-wrap: wrap; margin-left: auto; }
.pg {
  appearance: none; min-width: 38px; padding: 7px 11px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--panel); color: var(--text);
  font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
}
.pg:hover:not(:disabled) { border-color: var(--brand); }
.pg.on { background: var(--brand); border-color: var(--brand); color: #fff; }
.pg:disabled { opacity: .35; cursor: default; }
.pg-gap { color: var(--muted); padding: 0 3px; align-self: center; }
.pg-jump select, .edge-ctl select {
  padding: 8px 10px; border-radius: 8px; border: 1px solid var(--line);
  background: var(--panel); color: var(--text); font: inherit; font-size: 13px;
}
.edge-ctl { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); }

/* --- Sniper --- */
.notice {
  background: rgba(255,176,32,.08); border: 1px solid rgba(255,176,32,.30);
  border-radius: 12px; padding: 13px 16px; margin: 14px 0 18px;
  font-size: 13px; line-height: 1.55; color: var(--text);
}
.notice b { color: var(--amber); }
.edge { font-weight: 800; color: var(--green); background: rgba(34,211,154,.14); padding: 3px 9px; border-radius: 7px; }
.pill.conf-high   { background: rgba(34,211,154,.16); color: var(--green); }
.pill.conf-medium { background: rgba(255,176,32,.16); color: var(--amber); }
.pill.conf-low    { background: rgba(255,92,108,.16); color: var(--red); }
button.sm { padding: 6px 12px; font-size: 12px; border-radius: 8px; }
.seg.tight button { padding: 5px 11px; font-size: 12px; }
.fillbar { height: 3px; background: rgba(127,127,127,.18); border-radius: 3px; margin-top: 4px; overflow: hidden; }
.fillbar span { display: block; height: 100%; background: var(--brand); border-radius: 3px; }
.panel-h .seg { border: none; background: transparent; padding: 0; }
.mkt-more { margin: 6px 0 26px; }
.mkt-more button { width: 100%; padding: 12px; font-size: 13px; }

/* --- CLOB price chart --- */
.chart-wrap { padding: 10px 12px 4px; }
svg.candles { width: 100%; height: 210px; display: block; }
svg.candles .grid { stroke: var(--line); stroke-width: 1; opacity: .55; }
svg.candles .axis { fill: var(--muted); font-size: 9px; font-family: ui-monospace, Menlo, monospace; }
svg.candles .wick { stroke-width: 1; }
svg.candles .wick.up { stroke: var(--green); }
svg.candles .wick.down { stroke: var(--red); }
svg.candles .cndl.up { fill: var(--green); }
svg.candles .cndl.down { fill: var(--red); }

/* --- pre-trade quote --- */
.quote { margin: 10px 0 4px; padding: 10px 12px; border-radius: 10px;
  background: var(--bg-2); border: 1px solid var(--line); font-size: 12px; }
.quote:empty { display: none; }
.quote-row { display: flex; justify-content: space-between; padding: 2px 0; }
.quote-row span { color: var(--muted); }
.quote-row b { font-family: ui-monospace, Menlo, monospace; }
.quote-note { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--line);
  color: var(--amber); font-size: 11px; line-height: 1.45; }

/* --- provenance badges --- */
.vbadge { font-size: 10px; font-weight: 800; padding: 3px 9px; border-radius: 20px;
  letter-spacing: .3px; white-space: nowrap; cursor: help; }
.vbadge.ok   { background: rgba(34,211,154,.16); color: var(--green); }
.vbadge.warn { background: rgba(255,176,32,.14); color: var(--amber); }
.vbadge.bad  { background: rgba(255,92,108,.18); color: var(--red); }

/* ============================================================================
   VISUAL PASS — depth, colour and rhythm on top of the existing brand.
   Kept additive so nothing above is disturbed; every rule here is either a
   refinement of an existing class or net-new.
   ========================================================================== */
:root {
  --accent: #6d5efc;              /* violet, for non-brand emphasis */
  --accent-2: #00b8d9;            /* cyan */
  --grad-brand: linear-gradient(135deg, #237c41, #3fae6b 55%, #52c98a);
  --grad-accent: linear-gradient(135deg, #6d5efc, #9b8bff);
  --grad-warm: linear-gradient(135deg, #f5a524, #f76808);
  --grad-cool: linear-gradient(135deg, #00b8d9, #6d5efc);
  --ring: 0 0 0 3px rgba(35,124,65,.14);
  --shadow-lg: 0 2px 4px rgba(16,24,40,.04), 0 24px 48px -24px rgba(16,24,40,.30);
}

/* --- hero: give the page a confident opening ---------------------------- */
.hero, .hero-sm {
  position: relative;
  border-radius: 20px;
  padding: 26px 28px;
  margin-bottom: 6px;
  background:
    radial-gradient(620px 200px at 6% -40%, rgba(63,174,107,.22), transparent 70%),
    radial-gradient(520px 200px at 92% -30%, rgba(109,94,252,.14), transparent 70%),
    linear-gradient(180deg, #ffffff, #f7faf8);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.hero::after, .hero-sm::after {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: var(--grad-brand);
}
.hero h2, .hero-sm h2 { margin: 0 0 6px; font-size: 27px; letter-spacing: -.5px; }
.hero p, .hero-sm p { margin: 0; color: var(--muted); max-width: 68ch; }

/* --- stat cards: distinct, scannable, alive ----------------------------- */
.stats-sm { gap: 12px; }
.stat {
  position: relative; overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow-sm);
  transition: transform .14s ease, box-shadow .14s ease;
}
.stat:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.stat::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--grad-brand);
}
.stats-sm .stat:nth-child(2)::before { background: var(--grad-accent); }
.stats-sm .stat:nth-child(3)::before { background: var(--grad-cool); }
.stats-sm .stat:nth-child(4)::before { background: var(--grad-warm); }
.stats-sm .stat:nth-child(5)::before { background: linear-gradient(135deg,#15a35a,#00b8d9); }
.stat b {
  font-family: var(--font-display); letter-spacing: -.4px;
  font-variant-numeric: tabular-nums;
}
.stat span { color: var(--muted); font-size: 12px; font-weight: 600; }

/* --- market tables: a real exchange table ------------------------------- */
.markets-table {
  width: 100%; border-collapse: separate; border-spacing: 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.markets-table thead th {
  /* Offset must equal the real nav height, not a guessed constant. 62px was
     taller than the nav, so the header floated below it and the first row
     showed through the gap — which reads as the header overlapping row 1.
     app.js measures the nav on load and writes --nav-h. */
  position: sticky; top: var(--nav-h, 54px); z-index: 12;
  background: linear-gradient(180deg, #fbfdfc, #f4f7f5);
  border-bottom: 1px solid var(--line);
  font-size: 11px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase;
  color: var(--muted); padding: 13px 14px; text-align: left; white-space: nowrap;
  box-shadow: 0 1px 0 var(--line), 0 6px 12px -10px rgba(16,24,40,.5);
}
/* The table clips its own corners, which would cut the sticky header off.
   Let the header sit above the clip instead. */
.markets-table { overflow: visible; }
.markets-table tbody td {
  padding: 12px 14px; border-bottom: 1px solid var(--line);
  font-variant-numeric: tabular-nums; vertical-align: middle;
}
.markets-table tbody tr:last-child td { border-bottom: none; }
.markets-table tbody tr { transition: background .12s ease; }
.markets-table tbody tr:hover { background: linear-gradient(90deg, rgba(35,124,65,.05), transparent 60%); cursor: pointer; }
.markets-table .num, .price-cell { font-family: ui-monospace, Menlo, monospace; font-size: 13px; }
.price-cell { font-weight: 700; }
.unit { color: var(--muted); font-size: 11px; margin-left: 4px; font-family: var(--font); }
/* Marks a liquidity figure measured from our own resting book rather than
   taken from the network index. Quiet on purpose — it qualifies the number
   beside it, it is not a second number. See liqCell() in app.js. */
.src-book { color: var(--muted); font-size: 9px; font-family: var(--font); opacity: .75; cursor: help; }

/* rank badges — top three get the brand treatment */
td.rank { width: 54px; }
.rank-pill {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 26px; height: 24px; padding: 0 7px; border-radius: 8px;
  background: var(--bg-2); color: var(--muted);
  font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums;
}
.rank-pill.top { background: var(--grad-brand); color: #fff; box-shadow: 0 2px 8px -2px rgba(35,124,65,.55); }

.tag-amm {
  display: inline-block; margin-left: 6px; padding: 1px 6px; border-radius: 5px;
  background: rgba(109,94,252,.14); color: var(--accent);
  font-size: 10px; font-weight: 800; letter-spacing: .3px;
}

/* the action cell should read as a button, not a link */
a.go {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 13px; border-radius: 9px;
  background: var(--brand-soft); color: var(--brand);
  font-size: 12px; font-weight: 800; text-decoration: none;
  border: 1px solid transparent; transition: all .13s ease; white-space: nowrap;
}
a.go::after { content: "→"; transition: transform .13s ease; }
a.go:hover { background: var(--grad-brand); color: #fff; text-decoration: none; box-shadow: 0 3px 12px -4px rgba(35,124,65,.6); }
a.go:hover::after { transform: translateX(2px); }

/* --- avatars: larger, softer, with a subtle ring ------------------------ */
.av { border-radius: 11px; box-shadow: inset 0 0 0 1px rgba(16,24,40,.08), 0 2px 6px -2px rgba(16,24,40,.28); }
.av img { background: var(--bg-2); }
.mktcell { gap: 12px; }
.mktcell-txt b { font-size: 14px; letter-spacing: -.2px; }
.mktcell-txt small { font-size: 11px; }

/* --- segmented controls ------------------------------------------------- */
.seg { background: var(--panel); box-shadow: var(--shadow-sm); }
.seg button.on { background: var(--grad-brand); color: #fff; border-color: transparent; box-shadow: 0 3px 10px -3px rgba(35,124,65,.55); }
.seg button.on .cnt { background: rgba(255,255,255,.22); color: #fff; }

/* --- percentage change pills ------------------------------------------- */
.markets-table td.green, .markets-table td.red { font-weight: 700; }
.pct-pill {
  display: inline-block; padding: 3px 9px; border-radius: 7px;
  font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums;
}
.pct-pill.up { background: rgba(21,163,90,.13); color: var(--green); }
.pct-pill.down { background: rgba(229,72,77,.12); color: var(--red); }
.pct-pill.flat { background: var(--bg-2); color: var(--muted); }

/* --- panels ------------------------------------------------------------- */
.panel { border-radius: 16px; box-shadow: var(--shadow-sm); overflow: hidden; }
.panel-h {
  background: linear-gradient(180deg, #fbfdfc, #f5f8f6);
  border-bottom: 1px solid var(--line);
  font-size: 12px; font-weight: 800; letter-spacing: .4px; text-transform: uppercase;
  color: var(--muted);
}

/* --- pagination --------------------------------------------------------- */
.pager { border-radius: 14px; box-shadow: var(--shadow-sm); background: var(--panel); }
.pg.on { background: var(--grad-brand); border-color: transparent; box-shadow: 0 3px 10px -3px rgba(35,124,65,.55); }

/* --- buttons ------------------------------------------------------------ */
button.primary {
  background: var(--grad-brand); color: #fff; border: none; border-radius: 10px;
  font-weight: 800; cursor: pointer; transition: filter .13s ease, transform .13s ease;
  box-shadow: 0 4px 14px -6px rgba(35,124,65,.7);
}
button.primary:hover { filter: brightness(1.06); transform: translateY(-1px); }
button.primary:active { transform: translateY(0); }

@media (max-width: 860px) {
  .markets-table thead th:nth-child(n+7),
  .markets-table tbody td:nth-child(n+7) { display: none; }
  .hero h2, .hero-sm h2 { font-size: 22px; }
}
.qc { margin-left: 5px; font-size: 10px; font-weight: 700; opacity: .75; }
.ofx-hero .ofx-id { display: flex; align-items: center; gap: 16px; }
.ofx-mark { border-radius: 14px; box-shadow: 0 4px 16px -6px rgba(35,124,65,.6); flex: 0 0 56px; }
.ofx-hero h2 { margin-bottom: 2px; }
code { background: var(--bg-2); padding: 1px 5px; border-radius: 4px; font-size: 12px; }
.notice.ok-notice { background: rgba(21,163,90,.07); border-color: rgba(21,163,90,.28); }
.notice.ok-notice b { color: var(--green); }
.notice.ok-notice { background: rgba(21,163,90,.07); border-color: rgba(21,163,90,.28); }
.notice.ok-notice b { color: var(--green); }
.notice.ok-notice { background: rgba(21,163,90,.07); border-color: rgba(21,163,90,.28); }
.notice.ok-notice b { color: var(--green); }

/* --- toasts --- */
.toasts {
  position: fixed; right: 18px; bottom: 18px; z-index: 400;
  display: flex; flex-direction: column; gap: 8px; align-items: flex-end;
  pointer-events: none;
}
.toast {
  background: var(--panel); border: 1px solid var(--line);
  border-left: 3px solid var(--brand);
  border-radius: 11px; padding: 11px 16px; font-size: 13px; font-weight: 600;
  box-shadow: var(--shadow-lg); max-width: 380px;
  animation: toast-in .18s ease-out;
  transition: opacity .5s ease, transform .5s ease;
}
.toast.ok  { border-left-color: var(--green); }
.toast.err { border-left-color: var(--red); }
.toast.out { opacity: 0; transform: translateY(6px); }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* --- network selector -------------------------------------------------- */
/* Two explicit choices in the header. The previous control was a small badge
   that happened to be clickable, which meant nobody found it — and behind it
   sat an action that deleted the whole book. Both halves of that are fixed. */
.netpick {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--line, #2a3b31);
  border-radius: 999px;
  background: rgba(0, 0, 0, .18);
}
.netpick button {
  appearance: none;
  border: 0;
  cursor: pointer;
  font: 600 12px/1 Inter, system-ui, sans-serif;
  letter-spacing: .01em;
  padding: 6px 12px;
  border-radius: 999px;
  color: var(--muted, #9fb3a8);
  background: transparent;
  transition: background .15s ease, color .15s ease;
}
.netpick button:hover { color: #fff; background: rgba(255, 255, 255, .07); }
.netpick button.on {
  color: #06120b;
  background: linear-gradient(180deg, #4fd28a, #29a35f);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .25) inset;
}
/* Testnet reads as a caution colour when selected: it should never be mistaken
   for mainnet at a glance. */
.netpick button[data-net="testnet11"].on {
  background: linear-gradient(180deg, #f2c14e, #d99b1c);
}
.netpick.switching { opacity: .55; pointer-events: none; }
/* No operator token: the control is real but not yours. Dimmed and
   non-interactive, with the reason on the button's title. */
.netpick.needs-operator { opacity: .5; }
.netpick button:disabled { cursor: not-allowed; }
.netpick.switching button.on { animation: netpulse 1s ease-in-out infinite; }
@keyframes netpulse { 50% { opacity: .5; } }

@media (max-width: 900px) {
  .netpick button { padding: 5px 9px; font-size: 11px; }
}

/* --- book row actions: a small popover on hover ------------------------ */
/* Every level is a real offer file, so hovering surfaces what you can do with
   it: copy the bytes, save them, take it (your wallet signs), or club it with
   everything better-priced. Rendered as a floating card rather than inline
   buttons so it never fights the numbers underneath for space. */
.brow { position: relative; }
.brow .bacts {
  position: absolute;
  right: 4px; top: 50%;
  transform: translateY(-50%) scale(.96);
  display: flex; gap: 4px;
  padding: 4px;
  border-radius: 8px;
  background: rgba(6, 16, 11, .97);
  border: 1px solid var(--line, #2a3b31);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .5);
  opacity: 0; pointer-events: none;
  transition: opacity .12s ease, transform .12s ease;
  z-index: 5;
}
.brow:hover .bacts,
.brow:focus-within .bacts { opacity: 1; pointer-events: auto; transform: translateY(-50%) scale(1); }
.bact {
  appearance: none; border: 1px solid var(--line, #2a3b31);
  background: rgba(255, 255, 255, .04);
  color: var(--muted, #9fb3a8);
  font: 600 11px/1 Inter, system-ui, sans-serif;
  white-space: nowrap;
  padding: 5px 8px;
  border-radius: 6px; cursor: pointer;
}
.bact:hover { color: #fff; border-color: #4fd28a; background: #12301f; }
.bact.take:hover { color: #06120b; background: #4fd28a; border-color: #4fd28a; }
.bact.club:hover { color: #06120b; background: #f2c14e; border-color: #f2c14e; }

/* Tokens / NFTs selector in the terminal rail */
.rail-kind { margin: 0 8px 8px; }
.rail-kind small { opacity: .6; margin-left: 4px; font-weight: 600; }

/* --- fit the page in one window --------------------------------------- */
/* Wide tables and the terminal grid were pushing past the viewport, so every
   page needed horizontal scrolling to read. Nothing here should ever be wider
   than the window; where content genuinely cannot shrink, it scrolls inside
   its own panel instead of moving the whole page. */
html, body { max-width: 100%; overflow-x: hidden; }
.nav { flex-wrap: wrap; row-gap: 6px; }
.nav .links { flex-wrap: wrap; }
main, footer { max-width: 100%; box-sizing: border-box; }
table { max-width: 100%; }
.markets-table, .trades-table { display: block; overflow-x: auto; }
.markets-table thead, .markets-table tbody,
.trades-table thead, .trades-table tbody { display: table; width: 100%; table-layout: fixed; }
.markets-table td, .markets-table th,
.trades-table td, .trades-table th { overflow: hidden; text-overflow: ellipsis; }
.terminal.clob, .clob-grid, .trade2 { max-width: 100%; }
.toolbar { flex-wrap: wrap; row-gap: 8px; }
.stats { flex-wrap: wrap; }
@media (max-width: 1100px) {
  .trade2, .clob-grid { grid-template-columns: 1fr; }
  .terminal.clob { grid-template-columns: 1fr; }
  .rail { max-height: 220px; overflow-y: auto; }
}

/* --- mempool pill ------------------------------------------------------ */
/* Chain state decides whether a signed offer actually goes through, so it sits
   where it is always visible. The dot's colour is congestion, not decoration. */
.mempool {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px; border-radius: 999px;
  border: 1px solid var(--line, #2a3b31);
  background: rgba(0, 0, 0, .18);
  font: 600 12px/1 Inter, system-ui, sans-serif;
  color: var(--muted, #9fb3a8);
  text-decoration: none; white-space: nowrap;
}
.mempool:hover { color: #fff; border-color: #4fd28a; }
.mp-dot { width: 7px; height: 7px; border-radius: 50%; background: #6b7f74; }
.mempool.calm .mp-dot { background: #4fd28a; box-shadow: 0 0 6px #4fd28a88; }
.mempool.warm .mp-dot { background: #f2c14e; box-shadow: 0 0 6px #f2c14e88; }
.mempool.busy .mp-dot { background: #ff5c6c; box-shadow: 0 0 6px #ff5c6c88; animation: mp 1.2s ease-in-out infinite; }
.mempool.off  { opacity: .55; }
@keyframes mp { 50% { opacity: .45; } }

/* --- richer price chart ------------------------------------------------- */
.candles.rich { width: 100%; height: auto; display: block; }
.candles .grid { stroke: rgba(255, 255, 255, .06); stroke-width: 1; }
.candles .sep  { stroke: rgba(255, 255, 255, .12); stroke-width: 1; }
.candles .axis { fill: var(--muted, #9fb3a8); font: 10px Inter, system-ui, sans-serif; }
.candles .axis.dim { opacity: .5; }
.candles .wick.up,  .candles .cndl.up  { stroke: #4fd28a; fill: #4fd28a; }
.candles .wick.down,.candles .cndl.down{ stroke: #ff5c6c; fill: #ff5c6c; }
.candles .vol.up   { fill: #4fd28a; opacity: .32; }
.candles .vol.down { fill: #ff5c6c; opacity: .32; }
.candles .ma { fill: none; stroke: #7db6ff; stroke-width: 1.4; opacity: .85; }
/* An invisible full-height strip per candle, so hovering anywhere in the
   column reads that candle rather than only the few pixels of the body. */
.candles .hit { fill: transparent; }
.candles .cg:hover .hit { fill: rgba(255, 255, 255, .05); }
.chart-legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  padding: 6px 10px 2px;
  font: 500 11px/1.5 Inter, system-ui, sans-serif;
  color: var(--muted, #9fb3a8);
}
.chart-legend .ma-key { color: #7db6ff; }
.chart-legend .hover-read { margin-left: auto; font-variant-numeric: tabular-nums; }

/* Simulate-only button: visually secondary to the real, signed action. */
.sim-go {
  width: 100%; margin-top: 8px;
  font-size: 12px; opacity: .8;
}

/* --- compact book rows, dexie-style ------------------------------------ */
/* The book was set at 12.5px with 4px of vertical padding per row, so nine
   levels filled a screen and the panel read as mostly empty space. dexie packs
   its rows tight because a book is a shape you scan, not a list you read: the
   value is in seeing many levels at once. Tightened to ~19px per row. */
.book-head, .brow {
  padding: 1px 10px;
  font-size: 11.5px;
  gap: 6px;
  line-height: 17px;
}
.book-head { padding-bottom: 4px; font-size: 9px; }
.brow { border-radius: 3px; }
.brow .depth { top: 0; bottom: 0; border-radius: 3px 0 0 3px; }
.book-side { gap: 0; }
.book-mid { padding: 5px 10px; }
/* Numbers line up when they share a width, which is the whole point of a book. */
.brow .bp, .brow .bamt, .brow .btot { font-variant-numeric: tabular-nums; }

/* Rows in the trade terminal are the ones with the hover popover, so they need
   a little more room for it to sit in without covering the numbers. */
/* THE ACTUAL CAUSE OF THE CLIPPED NUMBERS.
   .brow is a three-column grid holding four children — price, amount, total,
   and the hover-actions card. That card is meant to float above the row
   (.brow .bacts sets position: absolute at line ~1024), but an earlier rule,
   .brow > span:not(.depth), has specificity 0,2,1 against that rule's 0,2,0
   and forced it back to relative. In flow, a fourth child in a three-column
   grid wraps to a SECOND grid row — the row computed
   grid-template-rows: 3.5px 9.5px — and both rows were crushed into the
   row's fixed height, which is what pushed the digits up into the row above.
   No amount of padding was ever going to fix that.

   Higher specificity, so the card floats as it was designed to. */
.book-side .brow > .bacts { position: absolute; }
.book-panel .brow { min-height: 20px; align-items: center; }

/* --- freshness indicator ------------------------------------------------ */
/* Tracks the SERVER's last sync, not the last repaint — those fail for
   different reasons and need different fixes. */
.freshness {
  display: inline-flex; align-items: center; gap: 6px;
  margin-left: auto;
  font: 500 11.5px/1 Inter, system-ui, sans-serif;
  color: var(--muted, #9fb3a8);
  white-space: nowrap;
}
.fdot { width: 7px; height: 7px; border-radius: 50%; background: #6b7f74; }
.fdot.on  { background: #4fd28a; box-shadow: 0 0 6px #4fd28a88; animation: fpulse 2.4s ease-in-out infinite; }
.fdot.off { background: #ff5c6c; }
@keyframes fpulse { 50% { opacity: .45; } }

/* Chart panel header holds two segmented controls plus a label. */
.chart-panel .panel-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.chart-panel .panel-h .ph-right { margin-left: auto; }

/* --- artwork everywhere ------------------------------------------------- */
/* The Market tab showed real token and collection art; every other surface
   showed a coloured chip with three letters. Same asset, two identities. The
   avatar helper is now used throughout, so a token looks like itself wherever
   it appears. */
.seg button .av { width: 16px; height: 16px; font-size: 8px; margin-right: 5px; flex: 0 0 auto; }
.seg button { display: inline-flex; align-items: center; }
.av.sm { width: 16px; height: 16px; font-size: 8px; }
.pairline { display: flex; align-items: center; gap: 10px; }
.pairline .av { flex: 0 0 auto; }
.rail .mkt .av { width: 26px; height: 26px; flex: 0 0 auto; }
.pair-id .av { width: 38px; height: 38px; flex: 0 0 auto; }
.assetline .av { width: 20px; height: 20px; font-size: 9px; flex: 0 0 auto; }

/* --- the book, dexie-dense ---------------------------------------------- */
/* Two problems, one appearance. The rows were loose AND there were only nine of
   them, so a tall panel sat mostly empty and read as "orders are so separated".
   Depth is now 40 a side inside a scroll area, packed at ~17px a row. */
.book-panel .book-side {
  max-height: 340px;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
}
.book-panel .book-side.asks { justify-content: flex-start; }
.book-panel .book-side::-webkit-scrollbar { width: 6px; }
.book-panel .book-side::-webkit-scrollbar-thumb { background: rgba(255,255,255,.12); border-radius: 3px; }
.book-head, .brow {
  /* Was padding: 0 with a 17px line box in a 17px row, forced with
     !important. Zero vertical padding means the glyphs sit flush against the
     row edge and the tops of the digits clip into the row above — on a column
     of numbers that is not a cosmetic problem, it is how a 0 starts reading
     as an 8. Two and a half pixels, and a line box with room in it. */
  padding: 2.5px 10px !important;
  line-height: 1.5;
  min-height: 0;
  font-size: 11.5px;
  gap: 6px;
}
.book-head { line-height: 14px; min-height: 0; padding-bottom: 3px !important; font-size: 9px; }
.brow { border-radius: 2px; }
.brow .depth { top: 0; bottom: 0; border-radius: 2px 0 0 2px; }
.book-mid { margin: 4px 0 !important; padding: 4px 10px !important; }
.mid-last { font-size: 13px !important; }

/* Hovering selects the whole sweep from the best price to the cursor, because
   that is what taking it would consume. The range reads as one block. */
.brow.in-range { background: rgba(255,255,255,.07); }
.brow.ask.in-range { background: rgba(255,92,108,.14); box-shadow: inset 2px 0 0 #ff5c6c; }
.brow.bid.in-range { background: rgba(79,210,138,.14); box-shadow: inset 2px 0 0 #4fd28a; }

.book-sweep {
  margin-top: 8px; padding: 7px 10px;
  border-top: 1px solid var(--line, #2a3b31);
  font: 500 11.5px/1.5 Inter, system-ui, sans-serif;
  color: var(--muted, #9fb3a8);
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  min-height: 32px;
}
.book-sweep.on { color: #fff; }
.book-sweep.on.ask { background: rgba(255,92,108,.08); }
.book-sweep.on.bid { background: rgba(79,210,138,.08); }
.book-sweep b { font-variant-numeric: tabular-nums; }
.sweep-cta {
  margin-left: auto; padding: 2px 8px; border-radius: 999px;
  background: #4fd28a; color: #06120b; font-weight: 700; font-size: 10.5px;
}

/* Per-offer actions shrink to icons — the row is dense now, and the sweep is
   the primary gesture. */
.brow .bacts { padding: 2px; gap: 2px; }
.brow .bact { padding: 3px 6px; font-size: 10px; }

/* --- TradingView chart -------------------------------------------------- */
.lwc-legend {
  position: absolute; top: 8px; left: 10px; z-index: 3;
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  font: 500 11px/1 Inter, system-ui, sans-serif;
  color: var(--muted, #9fb3a8);
  pointer-events: none;
  font-variant-numeric: tabular-nums;
}
.lwc-legend b { color: #fff; font-weight: 600; }
.lwc-legend .lwc-pair { color: #fff; font-weight: 700; font-size: 12px; }
.lwc-legend .lwc-pair small { color: var(--muted); font-weight: 500; margin-left: 5px; }
/* `min-height: 300px` here is what actually set the Streaming Orders chart
   height — not the number passed to mountChart. The grid gives that panel
   284px at 1366x768, so 300 of chart plus ~61 of panel header ran to 361 and
   the bottom 77px, including the whole time axis, was clipped away by the
   panel's `overflow: hidden`. Measured: `.panel.term-chart shows 284 of 361`.

   A floor of 300 inside a box of 284 is a contradiction. 220 leaves the axis
   inside the panel at the tightest size the grid produces, and the panels that
   have more room (Trade, wide screens) size from their own rules rather than
   this floor. */
#clobChart, .depth-wrap { position: relative; min-height: 220px; }

/* --- mempool panel ------------------------------------------------------ */
.mp-panel {
  position: fixed; top: 58px; right: 16px; z-index: 60;
  width: min(460px, calc(100vw - 32px));
  max-height: min(560px, calc(100vh - 90px));
  overflow: auto;
  background: #0b1712; border: 1px solid var(--line, #2a3b31);
  border-radius: 12px; box-shadow: 0 18px 50px rgba(0,0,0,.6);
}
.mp-panel[hidden] { display: none; }
.mp-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 11px 14px; border-bottom: 1px solid var(--line, #2a3b31);
  font: 700 13px Inter, system-ui, sans-serif; color: #fff;
  position: sticky; top: 0; background: #0b1712;
}
.mp-x { background: none; border: 0; color: var(--muted); font-size: 20px; line-height: 1; cursor: pointer; }
.mp-x:hover { color: #fff; }
.mp-body { padding: 12px 14px 16px; }
.mp-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 12px; }
.mp-stats div {
  background: rgba(255,255,255,.04); border-radius: 8px; padding: 8px 6px; text-align: center;
}
.mp-stats b { display: block; font: 700 14px Inter, system-ui, sans-serif; color: #fff; }
.mp-stats span { font-size: 10px; color: var(--muted); }
.mp-table { width: 100%; border-collapse: collapse; font-size: 11.5px; }
.mp-table th {
  text-align: left; color: var(--muted); font-size: 9.5px; text-transform: uppercase;
  letter-spacing: .05em; padding: 5px 6px; border-bottom: 1px solid var(--line, #2a3b31);
}
.mp-table td { padding: 5px 6px; border-bottom: 1px solid rgba(255,255,255,.04); font-variant-numeric: tabular-nums; }
.mp-empty { color: var(--muted); text-align: center; padding: 22px 10px; line-height: 1.6; }
.mp-empty small { opacity: .7; }

/* --- governance & roadmap ----------------------------------------------- */
.gov-warn {
  background: rgba(242,193,78,.10); border: 1px solid rgba(242,193,78,.35);
  border-radius: 8px; padding: 11px 13px; margin-bottom: 16px;
  font-size: 12.5px; line-height: 1.65; color: #e9d9ae;
}
.gov-warn b { color: #f2c14e; }
.gov-h {
  margin: 20px 0 8px; font: 700 12px Inter, system-ui, sans-serif;
  text-transform: uppercase; letter-spacing: .06em; color: var(--muted);
  border-bottom: 1px solid var(--line, #2a3b31); padding-bottom: 6px;
}
.gov-p { font-size: 12.5px; line-height: 1.65; margin: 7px 0; color: var(--text); }
.gov-p.muted { color: var(--muted); }
.gov-steps { margin: 8px 0 0 18px; font-size: 12.5px; line-height: 1.9; color: var(--text); }
.gov-steps b { color: #fff; }
.gov-table { font-size: 12px; }
.gov-never { margin: 8px 0 0 18px; font-size: 12.5px; line-height: 1.8; color: var(--text); }
.gov-never li::marker { color: #ff5c6c; }
.gov-alloc { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-top: 10px; }
.ga {
  background: rgba(255,255,255,.04); border-radius: 8px; padding: 11px;
  border-left: 3px solid #4fd28a;
}
.ga b { display: block; font-size: 20px; color: #fff; line-height: 1.1; }
.ga span { display: block; font-size: 12px; color: #fff; margin-top: 3px; }
.ga small { display: block; font-size: 10.5px; color: var(--muted); margin-top: 4px; line-height: 1.5; }

.rm-wrap { display: grid; gap: 14px; }
.rm-phase { border-left: 2px solid var(--line, #2a3b31); padding-left: 14px; }
.rm-phase.done { border-left-color: #4fd28a; }
.rm-phase.next { border-left-color: #f2c14e; }
.rm-head { font-size: 13px; color: #fff; margin-bottom: 7px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.rm-head b { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .05em; }
.rm-chip {
  font-size: 9.5px; text-transform: uppercase; letter-spacing: .05em;
  padding: 2px 7px; border-radius: 999px;
  background: rgba(255,255,255,.07); color: var(--muted);
}
.rm-chip.ok { background: rgba(79,210,138,.18); color: #4fd28a; }
.rm-chip.amber { background: rgba(242,193,78,.18); color: #f2c14e; }
.rm-items { list-style: none; margin: 0; padding: 0; }
.rm-items li {
  display: flex; align-items: flex-start; gap: 8px;
  font-size: 12.5px; line-height: 1.75; color: var(--text);
}
.rm-dot { width: 6px; height: 6px; border-radius: 50%; background: #6b7f74; margin-top: 8px; flex: 0 0 auto; }
.rm-done .rm-dot { background: #4fd28a; }
.rm-next .rm-dot { background: #f2c14e; }
.rm-researching { opacity: .65; }
.rm-researching .rm-dot { background: transparent; border: 1px dashed #6b7f74; }

/* --- security budget ----------------------------------------------------- */
/* The number BonkDAO's holders could have computed and nobody published. It
   sits next to the treasury it protects, and it is allowed to say "unknown". */
.sb-box {
  display: flex; gap: 16px; align-items: center; flex-wrap: wrap;
  padding: 14px 16px; border-radius: 10px; margin: 10px 0 12px;
  border: 1px solid var(--line, #2a3b31);
}
.sb-box.safe    { background: rgba(79,210,138,.10); border-color: rgba(79,210,138,.40); }
.sb-box.unsafe  { background: rgba(255,92,108,.10); border-color: rgba(255,92,108,.45); }
.sb-box.unknown { background: rgba(255,255,255,.03); }
.sb-ratio { text-align: center; min-width: 120px; }
.sb-ratio b { display: block; font: 800 30px/1 Sora, Inter, system-ui, sans-serif; color: #fff; }
.sb-box.safe   .sb-ratio b { color: #4fd28a; }
.sb-box.unsafe .sb-ratio b { color: #ff5c6c; }
.sb-ratio span { font-size: 10px; color: var(--muted); letter-spacing: .03em; }
.sb-verdict { flex: 1 1 260px; font-size: 12.5px; line-height: 1.6; color: var(--text); }
.sb-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; margin-bottom: 10px; }
.sb-grid div { background: rgba(255,255,255,.04); border-radius: 8px; padding: 9px 11px; }
.sb-grid label { display: block; font-size: 10px; color: var(--muted); margin-bottom: 3px; }
.sb-grid b { font-size: 14px; color: #fff; font-variant-numeric: tabular-nums; }
.sb-rules li::marker { color: #f2c14e; }

/* Two chambers */
.gov-houses { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; margin: 10px 0; }
.gh { background: rgba(255,255,255,.04); border-radius: 8px; padding: 12px; border-left: 3px solid #7db6ff; }
.gh b { display: block; font-size: 13px; color: #fff; }
.gh span { display: block; font-size: 11.5px; color: #7db6ff; margin: 3px 0 6px; }
.gh small { display: block; font-size: 11.5px; color: var(--muted); line-height: 1.6; }
.dg-effect { font-size: 11.5px; color: var(--text); text-align: right; max-width: 60%; line-height: 1.5; }

/* --- security budget ----------------------------------------------------- */
/* The number BonkDAO's holders could have computed and nobody published. It
   sits next to the treasury it protects, and it is allowed to say "unknown". */
.sb-box {
  display: flex; gap: 16px; align-items: center; flex-wrap: wrap;
  padding: 14px 16px; border-radius: 10px; margin: 10px 0 12px;
  border: 1px solid var(--line, #2a3b31);
}
.sb-box.safe    { background: rgba(79,210,138,.10); border-color: rgba(79,210,138,.40); }
.sb-box.unsafe  { background: rgba(255,92,108,.10); border-color: rgba(255,92,108,.45); }
.sb-box.unknown { background: rgba(255,255,255,.03); }
.sb-ratio { text-align: center; min-width: 120px; }
.sb-ratio b { display: block; font: 800 30px/1 Sora, Inter, system-ui, sans-serif; color: #fff; }
.sb-box.safe   .sb-ratio b { color: #4fd28a; }
.sb-box.unsafe .sb-ratio b { color: #ff5c6c; }
.sb-ratio span { font-size: 10px; color: var(--muted); letter-spacing: .03em; }
.sb-verdict { flex: 1 1 260px; font-size: 12.5px; line-height: 1.6; color: var(--text); }
.sb-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; margin-bottom: 10px; }
.sb-grid div { background: rgba(255,255,255,.04); border-radius: 8px; padding: 9px 11px; }
.sb-grid label { display: block; font-size: 10px; color: var(--muted); margin-bottom: 3px; }
.sb-grid b { font-size: 14px; color: #fff; font-variant-numeric: tabular-nums; }
.sb-rules li::marker { color: #f2c14e; }

/* Two chambers */
.gov-houses { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; margin: 10px 0; }
.gh { background: rgba(255,255,255,.04); border-radius: 8px; padding: 12px; border-left: 3px solid #7db6ff; }
.gh b { display: block; font-size: 13px; color: #fff; }
.gh span { display: block; font-size: 11.5px; color: #7db6ff; margin: 3px 0 6px; }
.gh small { display: block; font-size: 11.5px; color: var(--muted); line-height: 1.6; }
.dg-effect { font-size: 11.5px; color: var(--text); text-align: right; max-width: 60%; line-height: 1.5; }

/* --- security budget ----------------------------------------------------- */
/* The number BonkDAO's holders could have computed and nobody published. It
   sits next to the treasury it protects, and it is allowed to say "unknown". */
.sb-box {
  display: flex; gap: 16px; align-items: center; flex-wrap: wrap;
  padding: 14px 16px; border-radius: 10px; margin: 10px 0 12px;
  border: 1px solid var(--line, #2a3b31);
}
.sb-box.safe    { background: rgba(79,210,138,.10); border-color: rgba(79,210,138,.40); }
.sb-box.unsafe  { background: rgba(255,92,108,.10); border-color: rgba(255,92,108,.45); }
.sb-box.unknown { background: rgba(255,255,255,.03); }
.sb-ratio { text-align: center; min-width: 120px; }
.sb-ratio b { display: block; font: 800 30px/1 Sora, Inter, system-ui, sans-serif; color: #fff; }
.sb-box.safe   .sb-ratio b { color: #4fd28a; }
.sb-box.unsafe .sb-ratio b { color: #ff5c6c; }
.sb-ratio span { font-size: 10px; color: var(--muted); letter-spacing: .03em; }
.sb-verdict { flex: 1 1 260px; font-size: 12.5px; line-height: 1.6; color: var(--text); }
.sb-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; margin-bottom: 10px; }
.sb-grid div { background: rgba(255,255,255,.04); border-radius: 8px; padding: 9px 11px; }
.sb-grid label { display: block; font-size: 10px; color: var(--muted); margin-bottom: 3px; }
.sb-grid b { font-size: 14px; color: #fff; font-variant-numeric: tabular-nums; }
.sb-rules li::marker { color: #f2c14e; }

/* Two chambers */
.gov-houses { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; margin: 10px 0; }
.gh { background: rgba(255,255,255,.04); border-radius: 8px; padding: 12px; border-left: 3px solid #7db6ff; }
.gh b { display: block; font-size: 13px; color: #fff; }
.gh span { display: block; font-size: 11.5px; color: #7db6ff; margin: 3px 0 6px; }
.gh small { display: block; font-size: 11.5px; color: var(--muted); line-height: 1.6; }
.dg-effect { font-size: 11.5px; color: var(--text); text-align: right; max-width: 60%; line-height: 1.5; }

/* --- transaction links & per-market tape -------------------------------- */
/* Chips sized to be clicked, not just seen. 10.5px text in 2px of padding was
   a 16px-tall target squeezed into a column too narrow to hold it on one line;
   now that Links has the width, they get a real hit area and stop wrapping. */
.txlinks { display: inline-flex; gap: 7px; flex-wrap: wrap; align-items: center; }
.txlinks a {
  font-size: 11px; padding: 3px 9px; border-radius: 5px;
  background: rgba(255,255,255,.05); border: 1px solid var(--line, #2a3b31);
  color: var(--muted, #9fb3a8); text-decoration: none; white-space: nowrap;
}
.txlinks a:hover { color: #fff; border-color: #4fd28a; background: #12301f; }
.tape-wrap { max-height: 260px; overflow-y: auto; }
.mini-tape { width: 100%; border-collapse: collapse; font-size: 11.5px; }
.mini-tape th {
  position: sticky; top: 0; background: var(--panel, #0e1a14);
  text-align: left; color: var(--muted); font-size: 9px; text-transform: uppercase;
  letter-spacing: .05em; padding: 5px 8px; border-bottom: 1px solid var(--line, #2a3b31);
}
.mini-tape td { padding: 4px 8px; border-bottom: 1px solid rgba(255,255,255,.04); font-variant-numeric: tabular-nums; }
/* A row still in the mempool is not a trade yet, and must not look like one. */
.pending-row { background: rgba(242,193,78,.07); }
.pending-row td { color: #e9d9ae; }
.pend-dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: #f2c14e; margin-right: 6px; animation: fpulse 1.4s ease-in-out infinite;
}
.chip.amber { background: rgba(242,193,78,.18); color: #f2c14e; }

/* --- site-wide fee bar --------------------------------------------------- */
/* Stated once, on every page. A fee you have to go looking for is a fee you
   discover at the wrong moment. Values are read from the live fee schedule, so
   the bar cannot drift from what is actually charged. */
.feebar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 7px 18px;
  background: linear-gradient(90deg, rgba(79,210,138,.10), rgba(79,210,138,.03));
  border-bottom: 1px solid rgba(79,210,138,.22);
  font: 500 12px/1.4 Inter, system-ui, sans-serif;
  color: var(--muted, #9fb3a8);
}
.feebar b { color: #fff; font-weight: 700; }
.feebar a { color: #4fd28a; text-decoration: none; margin-left: auto; white-space: nowrap; }
.feebar a:hover { text-decoration: underline; }
.fee-pill {
  background: #4fd28a; color: #06120b;
  font-weight: 800; font-size: 11px;
  padding: 2px 8px; border-radius: 999px;
}
@media (max-width: 700px) { .feebar { font-size: 11px; padding: 6px 12px; } .feebar a { margin-left: 0; } }

/* ===========================================================================
   COSMETIC PASS
   Appended last so it wins on equal specificity, and so the whole pass can be
   read — or reverted — as one block.
   =========================================================================== */

/* --- The colour utilities the markup was already asking for ----------------
   The order book renders <span class="p red"> and <span class="p green">, the
   fills list colours by taker side, and several panels use .green/.red on
   plain spans. There was no unscoped rule for either — only .ps b.red,
   .act-price.red, .info-panel .kv .red and .markets-table td.red. Measured in
   the browser, bid and ask prices both computed to rgb(31,37,48): the book was
   monochrome, and the one cue a ladder exists to give was missing. */
.green { color: var(--green); }
.red   { color: var(--red); }
.amber { color: var(--amber); }

/* --- Figures that line up --------------------------------------------------
   Proportional digits make a column of prices ragged, so the eye cannot scan
   down it. Every numeric surface gets tabular figures and slashed zero. */
.lvl, .brow, .fill, .ord-table td, .markets-table td,
.trades-table td, .book-mid, .clob-bal b, .mono, code, pre {
  font-variant-numeric: tabular-nums slashed-zero;
}

/* --- Depth ladder ---------------------------------------------------------
   The bars now carry the cumulative total, so they read as "what it costs to
   sweep to here". At .1 opacity they were invisible against white; .18 with a
   gradient fading away from the price column keeps them legible without
   competing with the figures. */
#clobBook .lvl .bar {
  opacity: .18;
  border-radius: 2px 0 0 2px;
}
#clobBook .lvl.ask .bar { background: linear-gradient(270deg, var(--red) 0%, rgba(229,72,77,.35) 100%); }
#clobBook .lvl.bid .bar { background: linear-gradient(270deg, var(--green) 0%, rgba(21,163,90,.35) 100%); }
#clobBook .lvl { padding: 4px 12px; transition: background .09s ease; }
#clobBook .lvl:hover { background: rgba(35,124,65,.07); }
#clobBook .lvl.in-range { background: rgba(35,124,65,.12); }
/* Keyboard users get the same affordance as the mouse: these rows are
   role="button" tabindex="0" and had no visible focus state at all. */
#clobBook .lvl:focus-visible,
.brow:focus-visible { outline: 2px solid var(--brand-2); outline-offset: -2px; }
#clobBook .lvl .p { font-weight: 600; }

/* --- Mid / spread ---------------------------------------------------------
   The spread is the first number a trader looks for. It was not shown at all
   on this book; mid alone does not say whether crossing costs a rounding error
   or a third of the price. */
.book-mid {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  background: var(--panel-2);
}
.book-mid .spread {
  margin-left: auto; font-size: 11px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.book-mid .spread.one-sided { color: var(--amber); }

/* --- Sell means red -------------------------------------------------------
   Both sides of the buy/sell toggle went green when selected, so the single
   most consequential control on the page gave no colour cue about which way
   the order would go. */
.seg button.on[data-v="sell"], .seg button.on[data-side="sell"] {
  background: var(--red); border-color: var(--red); color: #fff;
}
.seg button.on[data-v="buy"], .seg button.on[data-side="buy"] {
  background: var(--green); border-color: var(--green); color: #fff;
}

/* --- Panels ---------------------------------------------------------------
   Consistent header rhythm and a slightly tighter radius; the mixed 14px
   radius on small panels read as soft next to the dense tables inside them. */
.panel { border-radius: 12px; }
.panel-h {
  font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); font-weight: 700;
}
.panel + .panel { margin-top: 14px; }

/* --- Recent fills ---------------------------------------------------------
   Alternating tint so a long tape does not read as one block. */
.fills .fill:nth-child(even) { background: rgba(127,127,127,.035); }
.fills .fill { padding: 5px 14px; }

/* --- Empty states ---------------------------------------------------------
   "no asks" in muted grey looked like a loading failure. */
.book-empty, .muted.pad {
  color: var(--muted); font-size: 12px; font-style: normal;
  opacity: .85;
}

/* --- Focus visible everywhere --------------------------------------------- */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
  outline: 2px solid var(--brand-2); outline-offset: 2px; border-radius: 6px;
}

/* --- Respect reduced motion ----------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* A crossed book — best bid above best ask — is a real and takeable state on a
   book of independent offer files, not an error. Marked, not hidden. */
.mid-spread.crossed {
  color: var(--amber); font-weight: 700;
  background: rgba(199,125,24,.10); border-radius: 999px; padding: 1px 8px;
}
.mid-spread.one-sided { color: var(--muted); }

/* ===========================================================================
   HELP PAGE
   =========================================================================== */
.help-panel { margin-bottom: 18px; }
.help-panel .pad { padding: 18px 20px 22px; }
.help-lead {
  margin: 0 0 16px; color: var(--muted); font-size: 14px; line-height: 1.55;
  max-width: 70ch;
}
.help-panel svg { display: block; margin: 6px 0 4px; }

.help-callout {
  margin-top: 16px; padding: 13px 16px; border-radius: 10px;
  background: rgba(35,124,65,.07); border-left: 3px solid var(--brand);
  font-size: 13.5px; line-height: 1.6; color: var(--text);
}
.help-callout.warn { background: rgba(199,125,24,.09); border-left-color: var(--amber); }
.help-callout b { color: var(--brand); }
.help-callout.warn b { color: var(--amber); }

/* Numbered steps. The number is the anchor the eye returns to, so it gets the
   brand colour and a fixed column rather than a bullet that moves with text. */
.hsteps { list-style: none; margin: 0; padding: 0; counter-reset: hstep; }
.hstep {
  display: grid; grid-template-columns: 34px 1fr; gap: 14px;
  padding: 12px 0; border-bottom: 1px solid var(--line);
}
.hstep:last-child { border-bottom: 0; }
.hstep-n {
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--grad-brand); color: #fff;
  font: 800 13px/1 Inter, system-ui, sans-serif;
}
.hstep b { display: block; font-size: 14px; margin-bottom: 3px; color: var(--text); }
.hstep p { margin: 0; color: var(--muted); font-size: 13.5px; line-height: 1.6; max-width: 78ch; }

.help-table { margin-top: 18px; }
.help-table td { vertical-align: top; font-size: 13px; line-height: 1.55; }
.help-table td:first-child { white-space: nowrap; }
.help-note { margin: 12px 0 0; font-size: 12.5px; color: var(--muted); font-style: italic; }

.help-fees { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; }
.help-fee {
  padding: 16px; border-radius: 12px; background: var(--panel-2);
  border: 1px solid var(--line);
}
.help-fee b {
  display: block; font: 800 26px/1 Sora, Inter, system-ui, sans-serif;
  color: var(--brand); font-variant-numeric: tabular-nums;
}
.help-fee span {
  display: block; margin: 4px 0 8px; font-size: 11px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; color: var(--muted);
}
.help-fee small { color: var(--muted); font-size: 12.5px; line-height: 1.5; }

.help-gloss { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: 10px 20px; }
.help-gloss dt { font-weight: 700; font-size: 13.5px; color: var(--text); }
.help-gloss dd { margin: 0; color: var(--muted); font-size: 13.5px; line-height: 1.6; }

/* The Help link earns a little separation from the operator tools next to it. */
.nav-help { color: var(--brand) !important; font-weight: 700; }

@media (max-width: 760px) {
  .help-gloss { grid-template-columns: 1fr; gap: 2px 0; }
  .help-gloss dd { margin-bottom: 10px; }
  .hstep { grid-template-columns: 28px 1fr; gap: 10px; }
}

/* ===========================================================================
   OPERATOR SURFACES
   =========================================================================== */

/* The operator group sits last in the nav, after the spacer, and reads as a
   different class of thing from the trading tabs — muted, bordered off, with a
   small label saying what it is. Someone who has it should be able to tell at a
   glance that these are not user features. */
.nav .links.ops {
  margin-left: 8px; padding-left: 12px;
  border-left: 1px solid var(--line);
  align-items: center; gap: 2px;
}
.nav .links.ops .ops-label {
  font-size: 9.5px; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); opacity: .75; margin-right: 4px; cursor: default;
}
.nav .links.ops a { color: var(--muted); font-weight: 600; }
.nav .links.ops a:hover { color: var(--amber); background: rgba(199,125,24,.10); }
.nav .links.ops a.active {
  background: linear-gradient(135deg, #8a5a12, var(--amber)); color: #fff;
}

/* The lock screen shown in place of an operator view. Deliberately calm — this
   is the ordinary state for almost everyone who reaches it, not an error. */
.locked {
  max-width: 620px; margin: 56px auto; text-align: center;
  padding: 40px 32px; background: var(--panel);
  border: 1px solid var(--line); border-radius: 16px; box-shadow: var(--shadow);
}
.locked-badge {
  width: 56px; height: 56px; margin: 0 auto 18px; border-radius: 50%;
  display: grid; place-items: center; font-size: 24px;
  background: rgba(199,125,24,.12);
}
.locked h2 { margin: 0 0 12px; font-size: 22px; }
.locked p { margin: 0 auto 18px; color: var(--muted); font-size: 14px; line-height: 1.6; max-width: 46ch; }
.locked-form { display: flex; gap: 8px; justify-content: center; margin: 22px auto 10px; max-width: 380px; }
.locked-form .field { flex: 1; }
.locked-note { font-size: 12.5px; color: var(--muted); min-height: 1.2em; }
.locked-links { font-size: 13px; margin-top: 22px !important; }
.locked-links a { color: var(--brand); font-weight: 600; }

@media (max-width: 720px) {
  /* The main links already collapse on narrow screens; the operator group goes
     with them rather than being the only thing left in the bar. */
  .nav .links.ops { display: none; }
}

/* `hidden` must actually hide.
   The attribute works via the UA stylesheet's `[hidden] { display: none }`,
   which ANY author rule setting `display` beats — and `.nav .links` sets
   `display: flex`. So the operator group carried hidden="" and rendered
   anyway: measured in the browser as hidden=true, offsetParent non-null.
   A silent failure, and precisely the one that matters here. */
[hidden] { display: none !important; }

/* ===========================================================================
   FEE CURRENCY — paying the taker fee in OFX
   =========================================================================== */
.feepay { margin: 12px 0 6px; }
.feepay-h {
  display: block; margin-bottom: 6px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
}
.feepay .seg { width: 100%; }
.feepay .save {
  font-style: normal; font-weight: 800; font-size: 10px;
  margin-left: 5px; padding: 1px 5px; border-radius: 999px;
  background: rgba(21,163,90,.16); color: var(--green);
}
.feepay .seg button.on .save { background: rgba(255,255,255,.22); color: #fff; }
.feepay-note {
  margin-top: 7px; font-size: 12px; line-height: 1.5; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.feepay-note a { color: var(--brand); font-weight: 600; }
.save-badge {
  display: inline-block; margin-left: 4px; padding: 1px 7px; border-radius: 999px;
  background: rgba(21,163,90,.14); color: var(--green); font-weight: 700; font-size: 11.5px;
}
/* OFX in the sandbox balance strip — spendable here, so it is shown here. */
.clob-bal .bal-ofx { color: var(--accent); }
.clob-bal .bal-ofx b { color: var(--accent); }
/* "sandbox today" on the fee bar: the discount is real on the Order Book's own
   ledger and cannot settle on chain until the CAT is minted. Saying so costs
   one word and prevents the app from implying otherwise. */
.fee-soon {
  font-style: normal; font-size: 10px; font-weight: 800;
  padding: 1px 6px; border-radius: 999px; margin-left: 4px;
  background: rgba(255,255,255,.20); color: #fff; cursor: help;
}

/* The OFX fee card on the Help page — the discount is the reason to hold the
   token, so it does not look like the other three. */
.help-fee.ofx { background: rgba(109,94,252,.07); border-color: rgba(109,94,252,.28); }
.help-fee.ofx b { color: var(--accent); }

/* ===========================================================================
   CONTRAST — WCAG AA across the palette
   ===========================================================================
   Measured, not guessed. tools/contrast.mjs walks the rendered page, resolves
   each text node's real colour against the background actually painted behind
   it, and reports the ratio. The starting palette failed badly for text:

     --green  #15a35a   3.27:1 on white   (every price, every % pill)
     --amber  #c77d18   3.29:1
     --red    #e5484d   3.91:1
     --muted  #63728d   4.48:1 on the page background
     --accent #6d5efc   4.51:1  (borderline)

   AA wants 4.5:1 for body text. These are the same hues, darkened until they
   clear it on white, on the page background, AND on their own tinted chips
   (a green badge on rgba(21,163,90,.14) is a lighter background than white, so
   passing on white alone is not enough).

   Redefining the variables rather than patching ~40 individual rules is
   deliberate: every one of those rules wanted "the green", and a second green
   that some rules used and others did not is how this drifts again. The few
   places that paint a FILL rather than text get darker too — white on #15a35a
   was 3.27:1 and failing, so the Buy button and depth bars are better for it.
   =========================================================================== */
:root {
  --green: #0f7a43;   /* 5.41:1 on white · 4.98 on bg · 4.63 on its own chip */
  --red:   #c22d33;   /* 5.65 · 5.21 · 4.97 */
  --amber: #a05a02;   /* 5.31 · 4.89 · 4.78 */
  --muted: #5a6880;   /* 5.64 · 5.19 */
  --accent: #4f3fd0;  /* 7.11 · 6.55 */
  /* Kept bright for the chart, where these are large filled shapes rather than
     text and legibility comes from area, not from a contrast ratio. */
  --green-vivid: #15a35a;
  --red-vivid: #e5484d;
}

/* The "powered by" line used --brand-2 (#329a53, 3.57:1). --brand is 5.21. */
.powered a, .powered .pw { color: var(--brand); }

/* ---------------------------------------------------------------------------
   THE FEE BAR
   A dark-theme component left behind when the site went light. It set
   `color: #fff` on its bold numbers over a 10%-green tint on a near-white
   page — white on almost-white, measured at 1.71:1, which is why the fee
   figures read as missing rather than as low contrast. The link was 1.12:1 and
   the "sandbox today" chip 1.52:1.

   Rebuilt for the theme it actually renders on.
   --------------------------------------------------------------------------- */
.feebar {
  background: linear-gradient(90deg, rgba(35,124,65,.10), rgba(35,124,65,.04));
  border-bottom: 1px solid rgba(35,124,65,.20);
  color: var(--muted);
}
.feebar b { color: var(--text); font-weight: 800; }
.feebar a { color: var(--brand); font-weight: 600; }
.fee-pill {
  background: var(--brand); color: #fff;   /* 5.21:1 */
  font-weight: 800;
}
.fee-soon {
  background: var(--amber); color: #fff;   /* 5.31:1 */
  font-style: normal; font-size: 10px; font-weight: 800;
  padding: 1px 6px; border-radius: 999px; margin-left: 4px; cursor: help;
}

/* The OFX saving badge and balance, on their tinted chips. */
.feepay .save { background: rgba(15,122,67,.14); color: var(--green); }
.save-badge { background: rgba(15,122,67,.13); color: var(--green); }
.clob-bal .bal-ofx, .clob-bal .bal-ofx b { color: var(--accent); }

/* Small print that sits on tinted panels rather than white. */
.hero p, .sandbox, .freshness { color: var(--muted); }

/* ---------------------------------------------------------------------------
   THE CHART LEGEND — the third dark-theme relic
   `color: #fff` on the OHLC readout, over a white chart panel. Measured 1:1:
   the price, the change and the volume on every chart were painted white on
   white. This is the "fee numbers have bad contrast" complaint in its most
   literal form — the numbers were not faint, they were absent.
   --------------------------------------------------------------------------- */
.lwc-legend b { color: var(--text); font-weight: 700; }
.lwc-legend .lwc-pair { color: var(--text); }
.lwc-legend .lwc-pair small { color: var(--muted); }
.lwc-legend { color: var(--muted); }

/* ---------------------------------------------------------------------------
   BRAND GRADIENT — white text needs the whole ramp to be dark enough
   The ramp ran to #52c98a, where white text measures about 2.2:1. Every
   gradient control uses white labels: the active nav pill, Connect Wallet,
   Place order, the selected segment. Darkened so the LIGHTEST stop still
   carries white text.
   --------------------------------------------------------------------------- */
:root {
  /* White on #2b8f4d is 4.09:1 — fine for a large bold label, short of AA for
     the 14px nav pill. The ramp now tops out at #237c41 (5.21:1), so every
     white label on it clears AA regardless of where it falls on the gradient. */
  --grad-brand: linear-gradient(135deg, #175c2f, #1e6f3a 55%, #237c41);
}
.seg .cnt { background: rgba(255,255,255,.28); color: #fff; }
.seg button.on .cnt { background: rgba(255,255,255,.30); color: #fff; }

/* Counts sitting on a tinted chip rather than a solid fill. */
.seg button .cnt { color: var(--text); background: rgba(31,37,48,.08); }

/* --- the last few, all marginal rather than invisible ---------------------- */

/* The active nav pill built its own ramp from --brand → --brand-2 rather than
   using --grad-brand, so darkening the shared ramp missed it. White on
   --brand-2 (#329a53) is 3.57:1. */
.nav .links a.active { background: var(--grad-brand); }

/* Count chips. On a solid brand fill a white-tinted chip is LIGHTER than what
   it sits on, so white digits lost contrast against their own badge. Darkened
   instead, which also reads as recessed rather than raised. */
.seg button.on .cnt { background: rgba(0,0,0,.26); color: #fff; }

/* Chrome-adjacent controls sitting on grey pills rather than on the page. */
.mp-txt, .netpick button { color: #455060; }          /* 7.5:1 on the pill */
.netpick button.on { color: #fff; }

/* Hero subtitles sit on the page's tinted radial, not on white. */
.hero p { color: #4b5769; }                            /* 6.8:1 */

/* Brand-coloured links on tinted chips need the darker brand, not the base. */
.feebar a, a.go, .locked-links a, .help-callout a { color: var(--brand-dark); }
.feepay .save, .save-badge { color: #0b6435; }         /* on their own chip */

/* ===========================================================================
   FOOTER — multi-column, the way an exchange's is
   ===========================================================================
   The old footer was two lines of grey text. A trading site's footer is a
   second navigation: the places you go occasionally (create an offer, your own
   offers, the API, what this thing actually is) do not deserve top-nav space
   but must be findable. Colours here are the AA-corrected ones, so the "small
   grey print" is still legible small grey print.
   =========================================================================== */
footer {
  text-align: left; padding: 0;
  background: var(--panel); border-top: 1px solid var(--line);
  margin-top: 48px;
}
.foot-cols {
  max-width: 1180px; margin: 0 auto; padding: 40px 28px 28px;
  display: grid; gap: 32px;
  grid-template-columns: minmax(220px, 1.6fr) repeat(4, minmax(120px, 1fr));
}
.foot-brand .foot-mark {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--text); font-size: 16px; text-decoration: none;
}
.foot-brand .foot-mark .mark {
  display: grid; place-items: center; width: 26px; height: 26px; border-radius: 8px;
  background: var(--grad-brand); color: #fff; font-size: 14px;
}
.foot-brand p {
  margin: 12px 0 14px; color: var(--muted); font-size: 12.5px; line-height: 1.6; max-width: 34ch;
}
.foot-net {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11.5px; font-weight: 600; color: var(--muted);
  background: var(--panel-2); border: 1px solid var(--line);
  padding: 4px 10px; border-radius: 999px;
}
.foot-net .fdot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--green);
  box-shadow: 0 0 0 3px rgba(15,122,67,.16);
}
.foot-col h4 {
  margin: 0 0 12px; font-size: 10.5px; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; color: var(--text);
}
.foot-col a {
  display: block; padding: 5px 0;
  color: var(--muted); font-size: 13px; text-decoration: none;
}
.foot-col a:hover { color: var(--brand-dark); }
.foot-col .ext { font-size: 10px; opacity: .6; }
.foot-base {
  max-width: 1180px; margin: 0 auto; padding: 16px 28px 26px;
  border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; gap: 14px; flex-wrap: wrap;
  color: var(--muted); font-size: 12px;
}
footer .heart { color: var(--red); }

@media (max-width: 900px) {
  .foot-cols { grid-template-columns: repeat(2, 1fr); gap: 26px; padding: 30px 18px 22px; }
  .foot-brand { grid-column: 1 / -1; }
  .foot-base { padding: 14px 18px 22px; }
}

/* ===========================================================================
   API PAGE
   =========================================================================== */
.api-table-wrap { overflow-x: auto; }
.api-table td { vertical-align: top; font-size: 13px; line-height: 1.55; }
.api-table td code {
  font-family: ui-monospace, Menlo, monospace; font-size: 12.5px;
  background: var(--panel-2); border: 1px solid var(--line);
  padding: 1px 6px; border-radius: 5px; color: var(--text);
}
.api-m {
  display: inline-block; min-width: 46px; text-align: center;
  font-size: 10.5px; font-weight: 800; letter-spacing: .04em;
  padding: 2px 7px; border-radius: 5px;
}
.api-m.get { background: rgba(15,122,67,.14); color: var(--green); }
.api-m.post { background: rgba(79,63,208,.13); color: var(--accent); }
.api-lock {
  font-size: 10px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  background: rgba(160,90,2,.14); color: var(--amber);
  padding: 1px 6px; border-radius: 999px; margin-left: 6px;
}
.api-pre {
  margin: 0; padding: 14px 16px; border-radius: 10px; overflow-x: auto;
  background: var(--panel-2); border: 1px solid var(--line);
  font-family: ui-monospace, Menlo, monospace; font-size: 12.5px; line-height: 1.7;
  color: var(--text);
}

/* ===========================================================================
   TREASURY / GOVERNANCE — the fourth and largest dark-theme relic
   ===========================================================================
   This whole block was authored for a dark background: `color: #fff` on the
   allocation figures and roadmap headings, #e9d9ae body copy, #f2c14e and
   #4fd28a chips, and rgba(255,255,255,.04) "panels" that are invisible on
   white. Measured on the light page, several of these were exactly 1:1 —
   the allocation percentages, their labels and every roadmap phase heading
   were white text on a white card.

   The page looked half-empty rather than broken, which is why it survived
   this long.
   =========================================================================== */
.gov-warn { color: #6b4a05; border-color: rgba(160,90,2,.35); background: rgba(160,90,2,.09); }
.gov-warn b { color: var(--amber); }
.gov-warn em { color: #6b4a05; }
.gov-steps b { color: var(--text); }
.gov-never li::marker { color: var(--red); }

.ga { background: var(--panel-2); border: 1px solid var(--line); border-left: 3px solid var(--green); }
.ga b { color: var(--text); }
.ga span { color: var(--muted); }

.rm-phase { border-left-color: var(--line); }
.rm-phase.done { border-left-color: var(--green); }
.rm-phase.next { border-left-color: var(--amber); }
.rm-head { color: var(--text); }
.rm-chip { background: rgba(31,37,48,.07); color: var(--muted); }
.rm-chip.ok { background: rgba(15,122,67,.13); color: #0b6435; }
.rm-chip.amber { background: rgba(160,90,2,.13); color: #7a4502; }

/* The treasury's allocation legend used a dark-theme sky blue (#7db6ff, 2.1:1). */
.gov-alloc span, .chart-legend .ma-key, .ga small { color: var(--muted); }
.chart-legend .ma-key { color: #2f5fa8; }

/* --- network picker -------------------------------------------------------
   The active pill's ramp ran to #4fd28a; white on it is 2.08:1. */
.netpick button.on { background: linear-gradient(180deg, #2b8f4d, #1b6a37); color: #fff; }
.netpick button[data-net="testnet11"].on { background: linear-gradient(180deg, #a05a02, #7a4502); color: #fff; }

/* --- the Help link, when it is the active tab -----------------------------
   `.nav-help { color: var(--brand) !important }` from the operator-nav work
   beat the active pill's white, so selecting Help painted brand green on
   brand green — 1.22:1, the tab you are standing on made unreadable by a
   rule meant only to tint it in its resting state. */
.nav .links a.nav-help.active { color: #fff !important; }

/* --- chips that were a hair short of AA ----------------------------------- */
.api-m.get { color: #0b6435; }
.api-lock { color: #7a4502; }
.pill.amm, .pill.clob { color: var(--brand-dark); }

/* --- swap and pools ------------------------------------------------------- */
/* MAX used --brand-2 (3.57:1) on a white field. */
.mini { color: var(--brand-dark); }
/* The swap CTA built its own ramp from --brand → --brand-2, like the nav pill
   did, so it missed the darkened shared ramp. */
.swap-go { background: var(--grad-brand); }
.swap-go.sell { background: linear-gradient(135deg, #b3272d, #c22d33); }
/* The CAT avatar chip: white initials on #4655ff→#6f7bff, 4.32:1. */
.coin.cat { background: linear-gradient(135deg,#3742d6,#4b56e8); }

/* ===========================================================================
   THE DARK-THEME CLUSTER
   ===========================================================================
   Not four isolated relics — one family. These components were all authored
   against a dark background and share the same two tells: `color: #fff` on
   their figures, and `rgba(255,255,255,.04)` as a "raised panel" surface. On
   white, the surface is invisible and the text is invisible with it.

   Measured on /treasury: the allocation percentages, the security-budget
   figures, the chamber headings and the roadmap phases were all exactly 1:1.
   The page rendered as a set of empty boxes.

   Fixed as a group so the next component someone copies from this family
   inherits the light-theme treatment rather than the dark one.
   =========================================================================== */

/* Surfaces: a white tint over white is nothing. Tint with ink instead. */
.sb-grid div, .gh, .ga, .mp-stats div, .sb-box.unknown, .mini-tape, .txlinks a {
  background: var(--panel-2);
  border: 1px solid var(--line);
}
.rm-chip { background: rgba(31,37,48,.07); }

/* Figures and headings. */
.sb-ratio b, .sb-grid b, .gh b, .mp-stats b, .rm-head, .ga b, .gov-steps b {
  color: var(--text);
}
.gh span, .sb-grid span, .mp-stats span, .sb-ratio span { color: var(--muted); }

/* #7db6ff was a dark-theme sky blue: 2.1:1 on white. */
.gh { border-left: 3px solid #2f5fa8; }
.gh small, .gov-alloc .ga span { color: var(--muted); }

/* Mempool panel — same family, and it opens over the page rather than a dark
   sheet. */
.mp-head { color: var(--text); }
.mp-x, .mp-x:hover { color: var(--muted); }
.mp-table td { border-bottom-color: var(--line); }
.mini-tape td { border-bottom-color: var(--line); }

/* Hover states that assumed a dark sheet to lift off. */
.bact:hover { color: #fff; border-color: var(--brand); background: var(--brand); }
.bact.take:hover { color: #fff; background: var(--green); border-color: var(--green); }
.bact.club:hover { color: #fff; background: var(--amber); border-color: var(--amber); }
.mempool:hover { color: var(--text); border-color: var(--brand); }
.netpick button:hover { color: var(--text); background: rgba(31,37,48,.06); }
.txlinks a:hover { color: #fff; border-color: var(--brand); background: var(--brand); }
.button.ghost:hover, button.ghost:hover { border-color: var(--brand); color: var(--brand-dark); }
.book-sweep.on { color: var(--text); }
.brow.in-range { background: rgba(35,124,65,.09); }

/* Chart fallback SVG grid, drawn in white on a white panel. */
.candles .grid { stroke: rgba(31,37,48,.08); }
.candles .cg:hover .hit { fill: rgba(31,37,48,.05); }

/* The WalletConnect setup panel. A visitor arriving at a site with no Project
   ID configured was previously told to go and create one — which is the site
   operator's job, not theirs. The alternatives come first now. */
.wc-pid-alt { background: rgba(35,124,65,.08); border-radius: 8px; padding: 9px 11px; }
.wc-pid-own { font-size: 12px; color: var(--muted); border-top: 1px solid var(--line); padding-top: 10px; margin-top: 12px; }
.wc-pid-own code {
  font-family: ui-monospace, Menlo, monospace; font-size: 11.5px;
  background: var(--panel-2); border: 1px solid var(--line); padding: 1px 5px; border-radius: 4px;
}

/* Error state for a view that failed to load. Previously a bare line of text
   that replaced the whole app; now it reads as a panel like everything else,
   so a failure looks handled rather than like the site fell over. */
.err-panel { max-width: 640px; margin: 32px auto; text-align: left; }
.err-panel h2 { margin: 0 0 10px; font-size: 20px; color: var(--red); }
.err-panel .err-why {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px; background: rgba(0,0,0,.04); border-left: 3px solid var(--red);
  padding: 10px 12px; border-radius: 4px; word-break: break-word; margin: 0 0 12px;
}
.err-panel .muted { color: var(--muted); font-size: 14px; }

/* WalletConnect self-test output. Monospace because it is a checklist of
   pass/fail lines and column alignment is what makes it readable at a glance. */
.wc-diag {
  margin: 8px 0 0; padding: 10px 12px; border-radius: 6px;
  background: rgba(0,0,0,.05); border: 1px solid rgba(0,0,0,.08);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; line-height: 1.55; white-space: pre-wrap; color: var(--muted);
  max-height: 220px; overflow: auto;
}

/* Fee estimate inside the mempool panel. Set apart from the node's own figures
   because it comes from a different source, and a number whose provenance is
   ambiguous is worse than one that is clearly labelled. */
.mp-fees { border-top: 1px solid rgba(0,0,0,.08); margin-top: 8px; padding-top: 8px; }
.mp-fees-h { font-size: 12px; font-weight: 600; padding: 0 12px 6px; color: var(--muted); }
.mp-fees .mp-stats { padding-top: 0; }
.muted.sm { font-size: 11px; font-weight: 400; margin-left: 8px; }
.notice-warn { border-left: 3px solid var(--amber); }

/* --- Issuer listing ------------------------------------------------------ */
.tier-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; margin: 16px 0; }
.tier-card { border: 1px solid rgba(0,0,0,.10); border-radius: 10px; padding: 16px; background: #fff; }
.tier-h { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.tier-h b { font-size: 17px; }
.tier-fee { font-size: 13px; font-weight: 600; color: var(--green); white-space: nowrap; }
.tier-checks { margin: 10px 0 14px; padding-left: 18px; font-size: 13px; line-height: 1.7; }
.std-table td { vertical-align: top; font-size: 13px; }
.apply-form .panel { margin-bottom: 14px; }
.apply-form .grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 720px) { .apply-form .grid2 { grid-template-columns: 1fr; } }
.fld { display: flex; flex-direction: column; gap: 5px; font-size: 13px; }
.fld > span { font-weight: 600; }
.fld input, .fld textarea, .fld select {
  padding: 9px 10px; border: 1px solid rgba(0,0,0,.16); border-radius: 6px;
  font: inherit; font-size: 14px; background: #fff;
}
.fld input:focus, .fld textarea:focus, .fld select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.fld .hint { color: var(--muted); font-style: normal; font-size: 12px; }
.fld .req { color: var(--red); font-style: normal; font-size: 11px; font-weight: 600; }
.tier-pick { display: grid; gap: 10px; }
.tier-opt { display: flex; gap: 10px; align-items: flex-start; cursor: pointer; }
.tier-opt .hint { display: block; color: var(--muted); font-style: normal; font-size: 12px; }
.ev-row { display: grid; grid-template-columns: 1fr 2fr auto; gap: 8px; margin-bottom: 8px; }
.ev-row input { padding: 8px 10px; border: 1px solid rgba(0,0,0,.16); border-radius: 6px; font: inherit; font-size: 13px; }
.panel.dim { opacity: .55; }

/* Region separators in the jurisdiction table. 80 rows read as a wall without
   them; grouped, an applicant can find their own country quickly. */
.reg-table .reg-region td {
  background: rgba(0,0,0,.035); font-weight: 700; font-size: 12px;
  text-transform: uppercase; letter-spacing: .04em; padding-top: 10px;
}

/* ═══════════════════════════════════════════════════════════════════════
   THE TERMINAL
   ═══════════════════════════════════════════════════════════════════════
   Book left, chart centre, ticket right, activity below. That arrangement
   is not a preference — it is what every serious exchange has converged on,
   and somebody arriving from one of them should not have to learn where
   anything is. Trade and Streaming Orders share this skeleton exactly, so
   the layout is learned once and the only thing that changes between them
   is what fills the right rail.

   The earlier attempt put the ticket in a horizontal strip under the chart.
   That is why it looked bolted on: a ticket is a column of label/value
   rows, and a column wants a column. In the right rail the same rows read
   as a form, because that is what they are.
   ═══════════════════════════════════════════════════════════════════════ */
.term {
  --book-w: 300px;
  --form-w: 292px;
  --bar-h: 54px;
  display: flex; flex-direction: column; gap: 10px;
  margin: 0 0 4px;
}

/* ---- the pair bar: one line, everything you glance at ---------------- */
.term-bar {
  display: flex; align-items: center; gap: 0; flex-wrap: nowrap;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  padding: 0 6px 0 8px; min-height: var(--bar-h);
  /* NOT overflow:hidden. The market dropdown is absolutely positioned inside
     this bar, and an overflow-y:hidden ancestor clips it to the bar's own
     44px — which is why the picker opened onto a sliver of empty space
     instead of a list. The bar stays on one line by dropping its least
     important stats on narrow screens, below, rather than by clipping. */
  overflow: visible;
}

.tb-pick {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer; flex: 0 0 auto;
  background: none; border: 0; border-radius: 9px; padding: 8px 12px 8px 8px;
  color: var(--text); font-family: inherit; font-size: 15px; margin-right: 4px;
}
.tb-pick:hover { background: var(--panel-2); }
.tb-pick b { font-weight: 700; letter-spacing: -.01em; white-space: nowrap; }
.tb-pick .chev { color: var(--muted); font-size: 10px; }

.tb-last { display: flex; flex-direction: column; gap: 0; padding: 0 16px; flex: 0 0 auto; }
.tb-last b { font-size: 17px; font-weight: 700; line-height: 1.2; font-variant-numeric: tabular-nums; }
.tb-last span { font-size: 11px; color: var(--muted); }
.tb-last b.up { color: var(--green); } .tb-last b.down { color: var(--red); }

.tb-stat { display: flex; flex-direction: column; gap: 1px; padding: 0 15px; flex: 0 0 auto; border-left: 1px solid var(--line); }
/* The asset id is 64 hex characters shown truncated, so it reads as a
   reference rather than a number: monospaced, quieter, and clickable. */
.tb-assetid b { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; cursor: pointer; }
.tb-assetid b:hover { color: var(--accent, #7fe0b0); }
/* IT SURVIVES THE NARROW-SCREEN RULES BELOW, DELIBERATELY.
   Those rules drop stats to keep the bar on one line, and they are right to:
   bid, ask, spread and depth are all readable from the order book directly
   underneath. The asset id is not — it appears nowhere else on the page, and
   it is the only thing that says WHICH token this is. So it is marked as
   identity rather than as a reading, and the hiding rules below exempt it. */
.term-bar .tb-stat.tb-assetid { display: flex !important; }
.tb-stat label { font-size: 9.5px; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); white-space: nowrap; }
.tb-stat b { font-size: 12.5px; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.tb-stat b.up { color: var(--green); } .tb-stat b.down { color: var(--red); }
.tb-spacer { flex: 1 1 auto; }
.tb-tag { flex: 0 0 auto; padding-right: 8px; }

/* ---- three columns, each a stack -------------------------------------
       book | chart        | ticket
       book | my offers    | recent trades

   THIS WAS A 3x2 GRID AND THAT WAS THE BUG.
   A grid row has one height across every column. The chart column is the tall
   one, so row 1 was sized to it and the ticket column got padded down to
   match — leaving a band of dead space between "Settles on mainnet" and the
   tape below it. No amount of tuning fixes that; rows simply cannot have
   per-column heights.

   Columns that are their own flex stacks can. The ticket now takes exactly the
   height its content needs and the tape begins on the next line down. The
   chart takes what is left in its column, with My offers beneath it.

   Height still comes from the flex parent (.term is a column bounded to the
   viewport), so the whole terminal is one screen. */
.term-grid {
  display: grid;
  grid-template-columns: var(--book-w) minmax(0, 1fr) var(--form-w);
  gap: 10px; align-items: stretch;
  flex: 1 1 auto;
  min-height: 0;
}
.term-grid > .panel { margin: 0; display: flex; flex-direction: column; min-height: 0; overflow: hidden; }

/* The trade terminal is a column the height of the viewport: bar, grid, foot.
   Restoring this — the block rewrite above dropped it, and without a bounded
   parent `flex: 1 1 auto` on the grid means "as tall as your content", which
   is 613px of a 1000px window. The terminal shrank to fit the panels instead
   of the panels filling the terminal.

   Scoped away from .clob-term, which sizes its own grid directly. */
.term:not(.clob-term) {
  display: flex; flex-direction: column; gap: 10px;
  height: calc(100vh - var(--term-chrome, 104px));
  min-height: 560px;
}
.term:not(.clob-term) > .term-bar,
.term:not(.clob-term) > .term-foot { flex: 0 0 auto; }

/* overflow:hidden matters. A flex item's default min-height is auto, and the
   ticket below is flex:0 1 auto — it can shrink, but only to its content. On a
   short window that content is still taller than the column, and without a clip
   the column grows, the grid row grows, and .term ends up past the fold. It did:
   66px over at 1600x1000. The panels scroll inside themselves instead. */
.term-col { display: flex; flex-direction: column; gap: 10px; min-height: 0; overflow: hidden; }
.term-col > .panel { margin: 0; display: flex; flex-direction: column; min-height: 0; overflow: hidden; }

/* Middle: the chart takes the slack, My offers sits under it. The chart keeps
   a floor so a tall offers list cannot squeeze it to nothing. */
/* The chart was flex:1 1 auto — it took every spare pixel and My offers got
   whatever was left over, which is the opposite of what was asked for. Explicit
   shares instead: the chart gives up its claim on the slack so the panel below
   it has real room. 52/48 rather than 50/50 because the chart still carries
   axis labels and a legend that a shorter box starts to crowd. */
.term-col.mid > .term-chart { flex: 1 1 52%; min-height: 200px; }
.term-col.mid > .term-mine  { flex: 1 1 48%; min-height: 190px; }

/* Right: the ticket is content-height — that is the whole point — and the tape
   takes the remainder. */
/* 0 1, not 0 0: natural height when it fits — which is the point, so the tape
   starts at the ticket's last line — but able to give way rather than push the
   whole terminal off screen when it does not. */
.term-col.right > .term-form { flex: 0 1 auto; min-height: 0; }
.term-col.right > .term-form > .pad,
.term-col.right > .term-form > .tk-body { overflow: auto; min-height: 0; }
.term-col.right > .term-tape { flex: 1 1 auto; min-height: 120px; }

.term-mine .mine-body,
.term-mine .mine-create,
.term-tape #tradeTape { flex: 1 1 auto; min-height: 0; overflow: auto; max-height: none; }
.term-tape > .panel-h, .term-mine .mine-head { flex: 0 0 auto; }

/* Book: header and spread pinned, each ladder scrolls in its own right. */
.term-book .book-head, .term-book .book-mid, .term-book .book-sweep,
.term-book .panel-h { flex: 0 0 auto; }
.term-book .book-side { flex: 1 1 0; min-height: 0; overflow: auto; scrollbar-width: thin; }
.term-book .book-side::-webkit-scrollbar { width: 6px; }
.term-book .book-side::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
.term-book .book-mid { border-block: 1px solid var(--line); background: var(--panel-2); padding: 8px 12px; }
.term-book .brow { padding-top: 2.5px; padding-bottom: 2.5px; font-size: 12px; }
.term-book .book-head { font-size: 10px; letter-spacing: .05em; opacity: .8; }

/* Chart takes the middle and every spare pixel. */
.term-chart .depth-wrap, .term-chart .chart-wrap { flex: 1 1 auto; min-height: 0; }

/* Ticket rail. */
.term-form { overflow: hidden; }
.term-form > .pad, .term-form > #takePanel, .term-form .form-scroll {
  flex: 1 1 auto; min-height: 0; overflow: auto; scrollbar-width: thin;
}

/* ---- below the fold -------------------------------------------------- */
.term-below { display: grid; grid-template-columns: var(--book-w) minmax(0,1fr); gap: 10px; margin-top: 4px; }
.term-below > .panel { margin: 0; }

/* Shared look for the two lower panels, wherever they are placed. The
   .term-below.two row they used to live in is gone — they are grid children of
   .term-grid now, so their placement and scrolling live with the grid. */
.term-mine, .term-tape { display: flex; flex-direction: column; min-height: 0; }
.term-mine .mine-tabs { margin: 8px 10px; }
.term-mine .mine-body table, .term-tape table { font-size: 12px; }
.term-mine .quote-row { padding: 5px 0; }

/* Narrow: the columns become one column, and the stacks stop being height-fed.
   .term-mine and .term-tape are inside .term-col now, not children of
   .term-grid, so every `.term-grid > .term-mine` rule that used to live here
   stopped matching anything. Left in place they would have read as responsive
   handling that was not happening. */
@media (max-width: 1200px) {
  .term-grid { grid-template-columns: var(--book-w) minmax(0,1fr); }
  .term-col.right { grid-column: 1 / -1; }
  /* Off the fixed-height frame: below this width the terminal scrolls, so the
     stacks size to content and each panel gets a sensible cap instead of a
     share of a viewport it no longer fills. */
  .term-col { min-height: 0; }
  /* Definite, for the same reason as the block above: a content-sized chart
     panel lets the chart grow the panel that sizes the chart. */
  .term-col.mid > .term-chart { flex: 0 0 auto; height: 380px; }
  .term-col.mid > .term-mine  { flex: 0 0 auto; max-height: none; height: 340px; }
  .term-col.right { flex-direction: row; flex-wrap: wrap; }
  .term-col.right > .term-form { flex: 1 1 300px; }
  .term-col.right > .term-tape { flex: 1 1 320px; height: 300px; }
}
@media (max-width: 860px) {
  .term-col.right { flex-direction: column; }
  .term-col.right > .term-form,
  .term-col.right > .term-tape { flex: 0 0 auto; }
}
@media (max-width: 900px) {
  .term-col.mid > .term-mine { height: 300px; }
  .term-col.right > .term-tape { height: 260px; }
}
.term-below .fills, .term-below #clobOrders { max-height: 380px; overflow: auto; }

/* ---- the market picker popover --------------------------------------- */
.tb-pop {
  position: absolute; z-index: 60; top: calc(100% + 6px); left: 0; width: 340px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 22px 54px rgba(0,0,0,.45); padding: 10px;
  display: flex; flex-direction: column; gap: 8px; max-height: min(60vh, 500px);
}
.tb-pop[hidden] { display: none; }
.tb-pop-wrap { position: relative; flex: 0 0 auto; }
.tb-pop-list { overflow: auto; display: flex; flex-direction: column; gap: 2px; min-height: 0; }
.mkt-opt {
  display: grid; grid-template-columns: auto auto 1fr auto; align-items: center; gap: 9px;
  background: none; border: 0; border-radius: 8px; padding: 7px 9px; cursor: pointer;
  text-align: left; color: var(--text); font-family: inherit; font-size: 13px; width: 100%;
}
.mkt-opt:hover { background: var(--panel-2); }
.mkt-opt.on { background: rgba(34,211,154,.12); }
.mkt-opt[hidden] { display: none; }
.mo-code { font-weight: 700; }
.mo-name { font-size: 11.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mo-n { font-size: 10.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.tb-pop .seg { flex: 0 0 auto; }

/* ---- narrower screens ------------------------------------------------ */
@media (max-width: 1400px) { .term { --book-w: 270px; --form-w: 268px; } }
@media (max-width: 1200px) {
  .term-grid { grid-template-columns: var(--book-w) minmax(0,1fr); height: auto; max-height: none; }
  .term-form { grid-column: 1 / -1; max-height: none; }
  .term-book { min-height: 420px; }

  /* A DEFINITE height, not a floor.
     The chart sizes itself to its container's measured height. Above this
     breakpoint .term-grid has an explicit height, so the container is bounded
     by the grid and that is safe. Here the grid drops to `height: auto`, the
     row becomes content-sized, and `min-height` leaves no ceiling — so the
     chart grows its own container and then chases it. Measured on a 390px
     viewport: 139 -> 505 -> 889 -> 425 -> 729px, oscillating rather than
     settling, until it had swallowed the page.
     `height` breaks the cycle: the container's size stops depending on what
     is inside it, so there is nothing left to chase. */
  .term-chart { height: 380px; min-height: 0; }
}
@media (max-width: 860px) {
  .term-grid, .term-below { grid-template-columns: 1fr; }
  .term-book, .term-chart, .term-form { grid-column: 1; }
  /* Shorter again on a phone: 380px of chart above the book puts the book
     below the fold on an 844px screen, and the book is what the page is for. */
  .term-chart { height: 300px; }
}
/* Landscape phones and short windows: 300px of chart against a 400px-tall
   viewport is most of the screen. Track the viewport rather than invent
   another width breakpoint. */
@media (max-width: 1200px) and (max-height: 700px) {
  .term-chart { height: min(300px, 45vh); }
}

/* ---- the take ticket, in the rail ------------------------------------ */
.tk-body { padding: 12px; display: flex; flex-direction: column; gap: 9px; }
.tk-body .tk-seg { margin-bottom: 3px; }

.tk-line {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 7px 0; border-bottom: 1px dashed var(--line); font-size: 12.5px;
}
.tk-line span { color: var(--muted); }
.tk-line b { font-weight: 700; font-variant-numeric: tabular-nums; text-align: right;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 62%; }
.tk-line b.ent { font-size: 12px; }

/* The one number the decision turns on gets a block of its own. Four
   equally-loud rows is four rows nobody reads. */
.tk-total {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 11px 12px; border-radius: 10px; margin: 3px 0 2px;
  background: rgba(34,211,154,.09); border: 1px solid rgba(34,211,154,.32);
}
.tk-total.sell { background: rgba(255,92,108,.08); border-color: rgba(255,92,108,.3); }
.tk-total span { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.tk-total b { font-size: 19px; font-weight: 800; font-variant-numeric: tabular-nums; }
.tk-total b small { font-size: 11px; font-weight: 600; color: var(--muted); }
.tk-total.buy b { color: var(--green); }
.tk-total.sell b { color: var(--red); }

.tk-body .tk-cta { margin: 2px 0 0; padding: 12px; font-size: 14px; }
.tk-body .tk-row2 { display: grid; grid-template-columns: repeat(3,1fr); gap: 6px; margin: 0; }
.tk-body .tk-row2 > * { text-align: center; padding: 7px 4px; font-size: 11.5px; }
.tk-body .tk-net { font-size: 10.5px; color: var(--muted); text-align: center; margin: 2px 0 0; }

.tk-hint {
  display: flex; flex-direction: column; gap: 5px; padding: 12px;
  border-radius: 10px; background: var(--panel-2); border: 1px solid var(--line);
  border-left: 3px solid var(--green); font-size: 12.5px;
}
.tk-hint b { font-weight: 700; }
.tk-hint span { color: var(--muted); font-size: 11.5px; line-height: 1.5; }
/* The terminal starts right under the pair bar; measured, not guessed. */
.term { --term-top: 250px; }

/* ---- the place-order form, in the rail -------------------------------
   Ten controls in a 650px column is a scroll unless the rhythm is tight.
   Nothing here shrinks a hit target — the segmented rows keep their height
   because they are what people aim at; it is the gaps, labels and the
   secondary faucet row that give up their space. */
.term-form .pad { padding: 11px 12px; display: flex; flex-direction: column; gap: 8px; }
.term-form .pad > .seg { margin: 0 !important; width: 100%; }
.term-form .pad .fld { margin: 0; }
.term-form .pad .fld > span { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.term-form .pad .fld input { padding: 8px 10px; font-size: 13px; }
.term-form .feepay { margin: 0; padding: 8px 10px; }
.term-form .feepay-h { font-size: 10px; }
.term-form .feepay-note { font-size: 10.5px; }
.term-form .fld-row { margin: 0; font-size: 12.5px; }
.term-form #clobSubmit { margin: 2px 0 0; padding: 12px; font-size: 14px; }
.term-form #clobFaucet { padding: 7px; font-size: 11.5px; width: 100%; }
.term-form .quote { font-size: 11.5px; }
.term-form .quote-row { padding: 3px 0; }

/* Short screens: the nav and fee bar cost the same pixels but there are far
   fewer to spend, so the deck gives up its floor rather than overflowing. */
@media (max-height: 850px) {
  .term { --term-top: 292px; }
  .clob-term .term-grid { min-height: 400px; }
}
.term-below.one { grid-template-columns: 1fr; }
/* The book is a grid cell now, so the old sticky positioning would fight it. */
.term-grid .book-panel { position: static; top: auto; padding: 0; }

/* ═══════════════════════════════════════════════════════════════════════
   COMPACT CHROME
   ═══════════════════════════════════════════════════════════════════════
   The header was taking 233px before a single price appeared. Thirteen nav
   links plus the wallet cluster wrapped to three rows, and every one of
   those rows was spending full height to hold items that are one line tall.
   That space belongs to the book, the chart and the ticket.

   The rule that made it wrap is the one being undone: the links now sit on
   a single line and scroll sideways if they must. A nav that reflows into
   three rows is not showing you more, it is showing you the same thing
   while stealing a third of the terminal.
   ═══════════════════════════════════════════════════════════════════════ */
.nav {
  flex-wrap: nowrap; row-gap: 0; gap: 8px;
  padding: 6px 14px; min-height: 46px;
}
.nav .links {
  flex-wrap: nowrap; margin-left: 4px; gap: 1px;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none; min-width: 0;
}
.nav .links::-webkit-scrollbar { display: none; }
.nav .links a { padding: 5px 9px; font-size: 13px; white-space: nowrap; border-radius: 7px; }

/* The brand keeps its mark but loses the tagline: it is decoration, it is
   repeated in the footer, and it was the reason the first row was 44px. */
.brand { font-size: 15px; gap: 8px; flex: 0 0 auto; }
.brand .mark { width: 24px; height: 24px; border-radius: 7px; font-size: 13px; }
.brand small { display: none; }

/* "Powered by Splash & Chia" is already in the footer, twice. In the nav it
   was a whole flex item pushing the wallet controls onto another row. */
.nav .powered { display: none; }

.nav .spacer { flex: 0 1 auto; min-width: 0; }
.nav .mempool { font-size: 11px; padding: 4px 9px; flex: 0 0 auto; white-space: nowrap; }
.netpick { flex: 0 0 auto; }
.netpick button { padding: 4px 9px; font-size: 11px; }
.nav .wallet-btn { padding: 6px 12px; font-size: 12.5px; flex: 0 0 auto; white-space: nowrap; }
.nav .net { font-size: 11px; padding: 3px 9px; flex: 0 0 auto; white-space: nowrap; }
.nav .ops { flex: 0 0 auto; }

/* The fee bar says four short things. It does not need 34px and a gradient
   to say them. */
.feebar {
  padding: 3px 14px; font-size: 11px; gap: 7px; flex-wrap: nowrap;
  overflow-x: auto; scrollbar-width: none; white-space: nowrap;
}
.feebar::-webkit-scrollbar { display: none; }
.feebar .fee-pill { padding: 1px 7px; font-size: 10.5px; }

/* Less air above the terminal, too — the page gutter was tuned for reading
   pages, and a terminal is not one. */
main#view { padding-top: 10px; }

/* ---- rebalanced columns ---------------------------------------------
   Width moves from the book and the chart to the ticket. The book needs
   enough for three numbers and the chart is elastic by nature; the ticket
   holds inputs, and a cramped input is the one thing here that costs
   somebody money. */
.term { --book-w: 268px; --form-w: 352px; --term-top: 166px; }
@media (max-width: 1500px) { .term { --book-w: 244px; --form-w: 344px; } }
@media (max-width: 1280px) { .term { --book-w: 232px; --form-w: 312px; } }
/* Short screens: the 600px floor above assumes room for two rows. On a
   768px-tall laptop that floor plus the header is taller than the window, so
   the terminal would scroll — which is the one thing this layout is for. Give
   the floor back and let the rows share what there actually is. */
/* No min-height on the trade grid any more: it is flex-sized, and a floor is
   exactly how it would be pushed past the fold again on a short screen. The
   rows just share less. The clob grid keeps its floor — it is still
   height-driven. */
@media (max-height: 850px) { .term { --term-top: 176px; } .clob-term .term-grid { min-height: 480px; } }
@media (max-height: 740px) {
  .term:not(.clob-term) { min-height: 0; }
  .term-grid { grid-template-rows: minmax(0,1.1fr) minmax(0,1fr); }
}

/* Six tabs were falling off the end of the nav. Everything below is width
   reclaimed from things that were saying something twice, or at length. */

/* This pill reads "mainnet" while the toggle immediately to its left already
   shows Mainnet selected. Two controls, one fact, 64px. */
.nav .net { display: none; }

.nav .links { flex: 1 1 auto; }
.nav .links a { padding: 5px 8px; }
.netpick button { padding: 4px 8px; font-size: 10.5px; letter-spacing: -.01em; }
.nav .mempool { max-width: 132px; overflow: hidden; text-overflow: ellipsis; }

/* Under ~1150px the full set genuinely cannot fit at a readable size, so the
   bar scrolls rather than shrinking the text to nothing. Scrolling a nav is
   a poor outcome; unreadable labels is a worse one. */
@media (max-width: 1150px) {
  .nav .links { overflow-x: auto; }
}

/* Below ~1520px the thirteen tabs and the wallet cluster genuinely exceed the
   bar, so the two items that repeat themselves give way first: the wordmark
   (the mark alone still says whose site this is, and it is a link home either
   way) and the verb on the wallet button. Tabs are navigation; a wordmark is
   branding, and branding yields to navigation. */
@media (max-width: 1520px) {
  .brand > span:not(.mark) { display: none; }
  .nav .links a { padding: 5px 7px; font-size: 12.5px; }
  .nav .wallet-btn { padding: 6px 10px; font-size: 12px; }
}

@media (max-width: 1400px) { .nav .links a { padding: 5px 6px; font-size: 12px; } }

/* The mempool pill SHRINKS, it does not disappear.
   It used to be hidden outright below 1320px on the theory that a tab you
   cannot see is worse than telemetry you can open a page for. Adding a
   thirteenth tab pushed the nav past that breakpoint on ordinary laptops, so
   the pill vanished from the bar entirely — and it is the one element there
   that answers "will my transaction go through right now", which is not a
   question worth navigating for. Below 1320 it drops the words and keeps the
   dot and the number; below 1120 it keeps the dot, which still carries the
   calm/warm/busy colour. The full reading stays in the title attribute and on
   the panel behind the click. */
@media (max-width: 1320px) {
  .nav .mempool { max-width: none; padding: 4px 7px; }
  .nav .mempool .mp-txt .mp-word { display: none; }
}
@media (max-width: 1120px) {
  .nav .mempool .mp-txt { display: none; }
  .nav .mempool { padding: 4px 6px; }
}

/* ═══════════════════════════════════════════════════════════════════════
   PAGE HEADERS, EVERYWHERE
   ═══════════════════════════════════════════════════════════════════════
   Every page opened with a 123px block to say a two-word title and one line
   of explanation — a 27px heading, a paragraph, and 22px of margin under it.
   Thirteen pages, the same tax on each, and it pushed the actual content
   below the fold before the content had done anything wrong.

   The title and its one line now sit on the SAME baseline: the heading tells
   you where you are, the sentence after it tells you what to do, and neither
   needed its own row to do that. Nothing is removed — it is 52px instead of
   123px because it stopped stacking.
   ═══════════════════════════════════════════════════════════════════════ */
.hero, .hero-sm {
  margin-bottom: 10px; display: flex; align-items: baseline;
  gap: 12px; flex-wrap: wrap;
  /* It was a full card — 26/28px padding, two radial gradients, a border, a
     shadow and a 3px accent bar across the top — to hold a two-word title.
     That is a lot of furniture for a label, and the furniture was most of
     the 123px. The heading and its sentence carry the page perfectly well
     on their own. */
  padding: 2px 2px 8px; border: 0; border-radius: 0;
  background: none; box-shadow: none;
  border-bottom: 1px solid var(--line);
}
.hero::after, .hero-sm::after { display: none; }
.hero h2, .hero-sm h2 {
  margin: 0; font-size: 20px; letter-spacing: -.3px; flex: 0 0 auto; line-height: 1.25;
}
.hero p, .hero-sm p {
  margin: 0; font-size: 13px; line-height: 1.45; max-width: 78ch;
  flex: 1 1 320px; min-width: 0;
}
/* Multi-paragraph heroes (the listing standard, the blacklist) keep stacking —
   they are genuinely explaining something, not labelling a table. */
.hero:has(p + p), .hero-sm:has(p + p) { display: block; }
.hero:has(p + p) h2, .hero-sm:has(p + p) h2 { margin-bottom: 6px; }
.hero:has(p + p) p { margin-bottom: 6px; }

.stats { margin: 12px 0; }
.toolbar { margin-bottom: 11px; }
main#view { padding-top: 8px; }

/* ── The terminal, tightened ────────────────────────────────────────────
   The segmented rows were 46px each. Three of them — side, type,
   time-in-force — is 138px of a 660px column spent on six words, and it is
   the reason the form ran past the fold. They are 34px now, which is still
   a comfortable target: the shrink comes out of padding, not out of the
   button's clickable area, and the label size is unchanged.  */
.term { --bar-h: 44px; }
.term-bar { min-height: 44px; padding: 0 6px 0 6px; }
.tb-pick { padding: 6px 10px 6px 6px; font-size: 14px; }
.tb-last { padding: 0 13px; }
.tb-last b { font-size: 15px; }
.tb-last span { font-size: 10px; }
.tb-stat { padding: 0 12px; }
.tb-stat label { font-size: 9px; }
.tb-stat b { font-size: 12px; }

/* Panel headers: a label and a control, not a band. */
.term-grid .panel-h { padding: 6px 10px; min-height: 0; font-size: 12px; }
.term-grid .panel-h .seg.tight button { padding: 3px 8px; font-size: 11px; }

/* The segmented rows in both tickets. */
.term-form .pad > .seg button,
.tk-body .tk-seg button { padding: 6px 8px; font-size: 12.5px; }
.term-form .pad > .seg, .tk-body .tk-seg { padding: 2px; border-radius: 8px; }
.term-form .pad { gap: 7px; padding: 10px; }
.tk-body { gap: 7px; padding: 10px; }

/* Inputs keep their height — they are typed into, not just clicked. */
.term-form .pad .fld input { padding: 7px 10px; }
.term-form .feepay { padding: 7px 9px; }
.term-form #clobSubmit, .tk-body .tk-cta { padding: 11px; font-size: 13.5px; }
.term-form #clobFaucet { padding: 6px; font-size: 11px; }
.tk-line { padding: 5px 0; font-size: 12px; }
.tk-total { padding: 9px 11px; }
.tk-total b { font-size: 17px; }

/* With a 10px shorter bar the deck starts higher. */
.term { --term-top: 152px; }
@media (max-height: 850px) { .term { --term-top: 162px; } }

/* On a 768px-tall laptop the order form lands 4px past its column. Four
   pixels still means a scrollbar and a form that looks cut off, so the
   short-screen tier gives the gaps back rather than the controls. */
@media (max-height: 800px) {
  .term-form .pad { gap: 6px; padding: 9px; }
  .term-form .feepay { padding: 6px 9px; }
  .term-form #clobFaucet { padding: 5px; }
}

/* ── Cosmetic pass: four things that made you work for the data ─────────── */

/* 1. THE STREAMING BOOK SLID SIDEWAYS.
   Each row wanted 254px of monospace inside a 206px column, so reading the
   far side of the book meant dragging it. Monospace is right for a ladder —
   digits must line up — but 12px of it across three columns is more than the
   column can hold, and the ladder is unreadable if you have to scroll it. */
.term { --book-w: 262px; }
@media (max-width: 1500px) { .term { --book-w: 254px; } }
#clobBook .lvl, .term-book .brow, .term-book .book-head {
  font-size: 10.5px; padding-left: 8px; padding-right: 8px; gap: 4px;
  letter-spacing: -.2px;
}
#clobBook .lvl > *, .term-book .brow > * {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Amount and total are context; price is what you are reading down the
   ladder, so price keeps the room when something has to give. */
#clobBook .lvl { grid-template-columns: 1.15fr .95fr .9fr; }

/* 2. RECENT TRADES WAS A SLIVER NEXT TO RECENT FILLS.
   The row below the terminal inherited the book's column width, so the tape
   got 244px and the fills got 1142px. They are equally interesting; they get
   equal space. */
.term-below { grid-template-columns: 1fr 1fr; }
.term-below.one { grid-template-columns: 1fr; }
@media (max-width: 900px) { .term-below { grid-template-columns: 1fr; } }

/* 3. THE ORDER FORM STILL SCROLLED.
   Three segmented rows at 39px each. The height comes off the padding and
   the border radius, never the label — 32px is still a comfortable target
   and the text is the same size it was. */
.term-form .pad > .seg button { padding: 4px 8px; font-size: 12px; }
.term-form .pad > .seg { padding: 2px; }
.term-form .pad .fld > span { margin-bottom: 2px; }
.term-form .pad { gap: 6px; }

/* 4. THE RECENT TRADES TABLE HAD 107px ROWS.
   12/14px padding and a 15px font on a table whose job is to be scanned.
   A tape is read by running your eye down it, and 107px means six rows fill
   a screen that could hold twenty. */
table.trades-table td, table.trades-table th { padding: 5px 10px; font-size: 12.5px; }
/* The row was 98px because the asset avatar is 34px square and the cell adds
   12px top and bottom around it. The avatar is an aid to recognition, not the
   subject of the row — it can be the size of the text beside it. */
table.trades-table .av { width: 21px; height: 21px; flex: 0 0 21px; font-size: 9px; border-radius: 6px; }
table.trades-table .mktcell { gap: 7px; }
table.trades-table .mktcell-txt small { font-size: 10px; }
table.trades-table .pill, table.trades-table .vbadge,
table.trades-table .tag { padding: 1px 6px; font-size: 10px; }
table.trades-table tbody tr { line-height: 1.3; }

/* ── Three fixes ────────────────────────────────────────────────────────

   1. THE BOOK ROWS WERE CLIPPING.
   Tightening the ladder took the vertical padding to zero, so a 10.5px glyph
   with a 17px line box sat flush against a 19px row and the tops of the
   digits ran into the row above. Breathing room is not decoration on a
   column of numbers — it is what keeps a 0 from reading as an 8. */
#clobBook .lvl, .term-book .brow {
  padding-top: 2.5px; padding-bottom: 2.5px; line-height: 1.5;
}
.term-book .book-head { padding-top: 4px; padding-bottom: 4px; }

/* 2. THE STREAMING BOOK HAD NO SCROLLERS.
   #clobBook was display:block, so the whole panel scrolled as one and the
   spread — the line you read the ladder against — slid off the top. It is a
   flex column now, exactly like the Trade book: header and spread pinned,
   each ladder scrolling in its own right. */
.term-book > #clobBook {
  display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow: hidden;
}
.term-book > #clobBook > .book-head,
.term-book > #clobBook > .book-mid,
.term-book > #clobBook > .book-sweep { flex: 0 0 auto; }
.term-book > #clobBook > .book-side {
  flex: 1 1 0; min-height: 0; overflow: auto; scrollbar-width: thin;
}
.term-book > #clobBook > .book-side::-webkit-scrollbar { width: 6px; }
.term-book > #clobBook > .book-side::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }

/* 3. THE ORDER FORM STILL RAN PAST THE FOLD.
   Shaving padding had reached its limit — the form was simply taller than
   the column on any window shorter than about 900px. So the layout changes
   instead: price and amount are a pair, not a stack. They are read together
   and typed one after the other, which is exactly the case for putting them
   on one line, and it returns ~50px. The faucet stops being a full row. */
.term-form .pad {
  display: grid; grid-template-columns: 1fr 1fr; gap: 7px 9px; align-content: start;
}
.term-form .pad > .seg,
.term-form .pad > .feepay,
.term-form .pad > .quote,
.term-form .pad > #clobSubmit,
.term-form .pad > #clobMsg,
.term-form .pad > .fld-row { grid-column: 1 / -1; }
.term-form .pad > .fld { grid-column: auto; margin: 0; min-width: 0; }
/* Sandbox funding is a setup action, not part of placing an order. */
.term-form .pad > .fld-row:last-of-type { justify-content: center; }
.term-form #clobFaucet {
  width: auto; background: none; border: 0; color: var(--muted);
  text-decoration: underline; padding: 2px; font-size: 11px;
}
.term-form #clobFaucet:hover { color: var(--brand-dark); }

/* Very short windows (a laptop with a bookmarks bar and a dock) still ran the
   order form 12px past its column. The fee note is the one line here that is
   explanation rather than control, so it goes first. */
@media (max-height: 690px) {
  .term-form .feepay-note { display: none; }
  .term-form .pad { gap: 5px; padding: 8px; }
  .term-form .pad .fld input { padding: 6px 9px; }
}

/* The bar keeps to one line by shedding stats, not by clipping the dropdown.
   Order matters: the last two are context, bid and ask are the trade. */
@media (max-width: 1500px) { .tb-stat:nth-of-type(4) { display: none; } }
@media (max-width: 1320px) { .tb-stat:nth-of-type(3) { display: none; } }
@media (max-width: 1150px) { .tb-tag { display: none; } }

/* ── Book display controls (both terminals) ──────────────────────────────
   Which side, and to how many decimals — the two things a trader changes
   constantly. Side first because it is a click; decimals second because it
   is a considered choice. */
.book-ctl {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 4px 8px 5px; border-bottom: 1px solid var(--line); flex: 0 0 auto;
}
.book-ctl .bk-side { padding: 1px; }
.book-ctl .bk-side button {
  padding: 2px 8px; font-size: 11px; line-height: 1.4; min-width: 26px;
}
.book-ctl .bk-side button.on { background: var(--brand-soft); color: var(--brand-dark); }
.bk-dec { display: flex; align-items: center; gap: 5px; }
.bk-dec > span { font-size: 9.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); }
.bk-dec select {
  padding: 2px 6px; font-size: 11px; border-radius: 6px; min-width: 46px;
  background: var(--panel-2); border: 1px solid var(--line); color: var(--text);
}

/* CloBook gets more width: three monospace columns at ten decimals were
   packed tight enough that the numbers ran into each other. */
.clob-term { --book-w: 300px; }
@media (max-width: 1500px) { .clob-term { --book-w: 286px; } }
@media (max-width: 1280px) { .clob-term { --book-w: 262px; } }
.clob-term #clobBook .lvl { gap: 7px; padding-left: 9px; padding-right: 9px; }

/* ── YOUR OWN ORDERS, MADE OBVIOUS ─────────────────────────────────────────
   `.mine-row` and `.you-tag` have been emitted by the tape renderer since
   2026-08-02 and NEVER HAD ANY CSS — the classes went onto the rows and
   styled nothing, so "your own fills pop" was a feature that shipped
   invisible. That is why nothing of yours contrasted anywhere on the site.

   Violet, deliberately: red and green already mean sell and buy in this book,
   so ownership cannot borrow either without saying something false about the
   side. --accent is the palette's non-brand emphasis colour and collides with
   nothing else here.

   A left bar plus a tint, not a background swap: the depth gradient behind a
   book row still has to read, and the price must stay red or green. */
.brow.mine { background: color-mix(in srgb, var(--accent) 9%, transparent); }
.brow.mine::before {
  content: ""; position: absolute; left: 0; top: 1px; bottom: 1px; width: 3px;
  border-radius: 3px; background: var(--accent); z-index: 2;
}
.brow.mine .bamt { font-weight: 700; }

/* Cancel is destructive and irreversible — it spends a coin — so it does not
   look like Download sitting next to it. Red on hover only: the row is a list
   of your own orders, and a wall of red buttons reads as an error state. */
.ghost.sm.danger { color: var(--red); border-color: color-mix(in srgb, var(--red) 35%, var(--line)); }
.ghost.sm.danger:hover:not(:disabled) { background: var(--red); border-color: var(--red); color: #fff; }
.ghost.sm.danger:disabled { opacity: .55; cursor: progress; }

tr.mine-row > td { background: color-mix(in srgb, var(--accent) 8%, transparent); }
tr.mine-row > td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.you-tag {
  display: inline-block; margin-left: 6px; padding: 0 5px;
  font-size: 9.5px; font-weight: 800; letter-spacing: .04em; line-height: 15px;
  border-radius: 4px; color: #fff; background: var(--accent); vertical-align: 1px;
}

/* ── Streaming Orders: the same column shares Trade uses ───────────────────
   Until 2026-08-09 the middle column held the chart and then a
   `div.term-below` grid containing two bare `<div class="panel">`. Neither
   had a term-* class, so `.term-col > .panel` never matched them, they got
   no flex share, and the column could not divide its height. Measured at
   1366x768: two orphan panels at 331x264, the book at 560 against Trade's
   464, and the chart painting its crosshair label and time axis straight
   over the trades table.

   Now the shape is Trade's shape:
       left   book
       mid    chart + tape          (Trade: chart + my offers)
       right  ticket + orders + fills
   and every panel is a named direct child of its column, so each one gets a
   share of a bounded height instead of overflowing onto its neighbour. */
.clob-term .term-col.mid > .term-tape { flex: 1 1 48%; min-height: 150px; }
.clob-term .term-col.right > .term-form { flex: 0 1 auto; min-height: 0; }
.clob-term .term-col.right > .term-orders { flex: 1 1 auto; min-height: 130px; }
.clob-term .term-col.right > .term-fills { flex: 1 1 auto; min-height: 110px; }
.clob-term .term-tape > table,
.clob-term .term-tape #tradeTape,
.clob-term .term-fills .fills { flex: 1 1 auto; min-height: 0; overflow: auto; }

/* The chart host takes the room the panel actually has, rather than a floor
   of its own. `min-height: 300px` here was larger than the panel the grid
   hands out, which is how 77px of chart ended up outside a panel with
   `overflow: hidden`; mountChart then clamps its own height to this box. */
.clob-term .term-chart > #clobChart { flex: 1 1 auto; min-height: 0; overflow: hidden; }

/* ═══════════════════════════════════════════════════════════════════════
   MARKETS TABLE — column widths that match what is in the columns
   ═══════════════════════════════════════════════════════════════════════
   .markets-table sets table-layout:fixed with no column widths, so the
   browser divided the row into ten equal 104px slices. A two-character
   percentage got the same room as a pair name with an avatar and a
   collection under it, and the table stopped 420px short of its container
   because display:block let it shrink to that arbitrary sum.

   Widths are percentages so the table breathes with the window, and the
   two fixed columns (rank, action) are the only two whose content never
   changes size.
   ═══════════════════════════════════════════════════════════════════════ */
/* MARKETS COLUMN WIDTHS
   thead and tbody are separate `display: table` blocks so the header can stay
   put while the body scrolls, and `table-layout: fixed` is what keeps the two
   in step. Fixed layout ignores content, so without explicit widths it divides
   the row equally — which is how a 1396px container ended up holding a 976px
   table of ten identical 104px columns, some cramped and some half empty.

   The percentages sum to exactly 100. They have to: fixed layout scales an
   over-subscribed set down proportionally, so 99.5% + two pixel columns
   silently shrank EVERY column below its stated width and clipped the numbers
   inside. Widths here are derived from measured content — the widest real
   value in each column, plus padding — not from eyeballing the header. */
.markets-table.mkt-grid { width: 100%; }
.markets-table.mkt-grid thead, .markets-table.mkt-grid tbody { width: 100%; }

/* Tokens: # · Pair · Price · 24h · Bid · Ask · Offers · Volume · Liquidity · ⋯ */
.mkt-grid th:nth-child(1),  .mkt-grid td:nth-child(1)  { width: 5%;  }
.mkt-grid th:nth-child(2),  .mkt-grid td:nth-child(2)  { width: 18%; text-align: left; }
.mkt-grid th:nth-child(3),  .mkt-grid td:nth-child(3)  { width: 10%; }
/* 24h carries a direction arrow and a sign, so it is wider than its three-
   character header suggests — measured at 122px against the 86px that 7%
   bought at 1280. The extra three points come from Pair, which wraps and can
   afford them. */
.mkt-grid th:nth-child(4),  .mkt-grid td:nth-child(4)  { width: 10%; }
.mkt-grid th:nth-child(5),  .mkt-grid td:nth-child(5)  { width: 10%; }
.mkt-grid th:nth-child(6),  .mkt-grid td:nth-child(6)  { width: 10%; }
.mkt-grid th:nth-child(7),  .mkt-grid td:nth-child(7)  { width: 8%;  }
.mkt-grid th:nth-child(8),  .mkt-grid td:nth-child(8)  { width: 10%; }
.mkt-grid th:nth-child(9),  .mkt-grid td:nth-child(9)  { width: 10%; }
.mkt-grid th:nth-child(10), .mkt-grid td:nth-child(10) { width: 9%;  }
/* 5 + 18 + 10 + 10 + 10 + 10 + 8 + 10 + 10 + 9 = 100 */

/* NFTs: # · Item/Collection · Floor · Last traded · Best bid · Offers ·
   Trades 24h · Volume 24h · ⋯  — nine columns, so the freed share goes to the
   collection name, which is the longest text on the page. Also sums to 100. */
.mkt-nft th:nth-child(2), .mkt-nft td:nth-child(2) { width: 27%; }
.mkt-nft th:nth-child(3), .mkt-nft td:nth-child(3) { width: 11%; }
.mkt-nft th:nth-child(4), .mkt-nft td:nth-child(4) { width: 12%; }
.mkt-nft th:nth-child(5), .mkt-nft td:nth-child(5) { width: 11%; }
.mkt-nft th:nth-child(6), .mkt-nft td:nth-child(6) { width: 8%;  }
.mkt-nft th:nth-child(7), .mkt-nft td:nth-child(7) { width: 8%;  }
.mkt-nft th:nth-child(8), .mkt-nft td:nth-child(8) { width: 9%;  }
.mkt-nft th:nth-child(9), .mkt-nft td:nth-child(9) { width: 9%;  }

/* 10px rather than 12px: four pixels a side, times ten columns, is 80px of the
   row spent on gaps that were pushing figures out of their cells. */
.mkt-grid td, .mkt-grid th { padding: 8px 10px; }
/* The rank and the row actions are the two narrowest columns and the two that
   were clipping worst, so they give their padding back first. */
.mkt-grid td:first-child, .mkt-grid th:first-child { padding-inline: 6px; }
.mkt-grid td:last-child,  .mkt-grid th:last-child  { padding-inline: 4px; }
.mkt-grid td:not(:nth-child(2)):not(:first-child) { font-variant-numeric: tabular-nums; }
.mkt-grid .mktcell-txt { min-width: 0; }
.mkt-grid .mktcell-txt small { max-width: 100%; }

/* RECENT TRADES COLUMN WIDTHS
   Same defect the markets table had, same cause: thead and tbody are separate
   `display: table` blocks under `table-layout: fixed`, and with no widths fixed
   layout splits the row into eight identical columns. That gave Price 122px to
   hold values measuring 133px, so every price on the tape was clipped on the
   right — at both 1440 and 1280. Widths below are content-derived and sum to
   exactly 100; an over-subscribed set is scaled down proportionally and would
   quietly reintroduce the clipping across every column at once. */
.trades-table th:nth-child(1), .trades-table td:nth-child(1) { width: 10%; }  /* When   */
.trades-table th:nth-child(2), .trades-table td:nth-child(2) { width: 18%; }  /* Market */
.trades-table th:nth-child(3), .trades-table td:nth-child(3) { width: 7%;  }  /* Side   */
.trades-table th:nth-child(4), .trades-table td:nth-child(4) { width: 12%; }  /* Price  */
.trades-table th:nth-child(5), .trades-table td:nth-child(5) { width: 11%; }  /* Amount */
.trades-table th:nth-child(6), .trades-table td:nth-child(6) { width: 11%; }  /* Total  */
.trades-table th:nth-child(7), .trades-table td:nth-child(7) { width: 10%; }  /* Source */
/* Links gets the largest share, not the smallest.
   It was 12% — narrower than Amount — so two or three explorer chips wrapped
   onto stacked lines and sat squashed against the edge, while Price, Amount
   and Total each held a short number in 180px. The numeric columns give back
   what they were not using; 21% fits three chips on one line at 1280. */
.trades-table th:nth-child(8), .trades-table td:nth-child(8) { width: 21%; }  /* Links  */
/* 10 + 18 + 7 + 12 + 11 + 11 + 10 + 21 = 100 */
.trades-table td, .trades-table th { padding: 7px 10px; }
.trades-table td:last-child { padding-inline: 8px 12px; }

/* Your own orders sit directly under the ticket, so they need the same top gap
   the tape panels get from .term-below rather than butting against the form. */
.term-orders { margin-top: 12px; }

/* ═══════════════════════════════════════════════════════════════════════
   CONVERT — any asset for any other
   The route cards carry a judgement, not just a price: whether a route is
   atomic is more important than whether it is a fraction of a percent
   cheaper, so the badge outranks the number visually.
   ═══════════════════════════════════════════════════════════════════════ */
.cv-wrap { display: grid; grid-template-columns: 380px 1fr; gap: 16px; align-items: start; }
@media (max-width: 1000px) { .cv-wrap { grid-template-columns: 1fr; } }
.cv-form .fld { display: block; margin-bottom: 12px; }
.cv-form .fld > span { display: block; font-size: 12px; color: var(--muted); margin-bottom: 5px; }
.cv-form select, .cv-form input {
  width: 100%; box-sizing: border-box; padding: 9px 10px; font-size: 14px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--panel); color: var(--text);
}
.cv-flip { display: flex; justify-content: center; margin: -4px 0 8px; }
.cv-flip button { width: 34px; height: 34px; border-radius: 50%; padding: 0; font-size: 15px; }
.cv-hint { font-size: 12px; line-height: 1.5; margin: 10px 0 0; }

.cv-results { display: grid; gap: 12px; }
.cv-route { border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; background: var(--panel); }
.cv-route.best { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand) inset; }
.cv-route-h { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.cv-title { font-weight: 700; font-size: 14px; }
.cv-badge { font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: 999px; white-space: nowrap; }
.cv-badge.ok   { background: rgba(21,163,90,.12);  color: #15a35a; border: 1px solid rgba(21,163,90,.35); }
.cv-badge.warn { background: rgba(199,125,24,.12); color: #c77d18; border: 1px solid rgba(199,125,24,.35); }
.cv-badge.sim  { background: rgba(99,114,141,.12); color: var(--muted); border: 1px solid var(--line); }
.cv-out { font-family: ui-monospace, Menlo, monospace; margin: 6px 0 10px; }
.cv-out b { font-size: 24px; }
.cv-out span { color: var(--muted); font-size: 14px; margin-left: 4px; }
.cv-kv { display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px; padding: 3px 0; }
.cv-kv > span:first-child { color: var(--muted); }
.cv-kv > span:last-child { font-family: ui-monospace, Menlo, monospace; }
.cv-hops { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 9px 0 4px; font-size: 12px; }
.cv-hop { background: var(--panel-2); border: 1px solid var(--line); border-radius: 6px; padding: 3px 8px; }
.cv-hop b { color: var(--muted); margin-right: 4px; }
.cv-hop i { font-family: ui-monospace, monospace; font-style: normal; color: var(--muted); }
.cv-arrow { color: var(--muted); }
.cv-short { font-size: 12px; color: #c77d18; margin-top: 8px; }
.cv-note { font-size: 12px; color: var(--muted); line-height: 1.5; margin: 9px 0 12px; }
.cv-go { width: 100%; }
.cv-tradeoff {
  border: 1px solid rgba(199,125,24,.35); background: rgba(199,125,24,.07);
  border-radius: 10px; padding: 12px 14px; font-size: 13px; line-height: 1.6;
}
.cv-tradeoff.good { border-color: rgba(21,163,90,.35); background: rgba(21,163,90,.07); }
.cv-none { border: 1px dashed var(--line); border-radius: 12px; padding: 22px; text-align: center; }
.cv-none b { display: block; margin-bottom: 6px; font-size: 15px; }
.cv-none p { font-size: 13px; margin: 6px 0; }

/* Swap prices TOKEN/XCH only. This sends the token-for-token case to Convert
   rather than letting someone do it as two trades without being told. */
.swap-xref {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  max-width: 520px; margin: 0 auto 12px; padding: 9px 14px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2);
  font-size: 13px;
}
.swap-xref span { color: var(--muted); }
.swap-xref a { font-weight: 600; color: var(--brand-2); text-decoration: none; }
.swap-xref a:hover { text-decoration: underline; }

/* Roadmap list on the treasury page, now that the governance spec it used to
   sit beneath has been retired. */
.rm-list { list-style: none; padding: 0; margin: 8px 0 0; }
.rm-list li { display: flex; justify-content: space-between; align-items: center;
  gap: 12px; padding: 7px 0; border-bottom: 1px solid var(--line); font-size: 13px; }
.rm-list li:last-child { border-bottom: 0; }

/* Why the real book produced no offer file. Sits ABOVE the routes, because
   when the only quote is a simulation the explanation is the answer. */
.cv-why { border: 1px solid rgba(199,125,24,.35); background: rgba(199,125,24,.07);
  border-radius: 12px; padding: 14px 16px; }
.cv-why > b { display: block; margin-bottom: 8px; font-size: 14px; }
.cv-why ul { margin: 6px 0 8px; padding-left: 18px; font-size: 13px; line-height: 1.65; }
.cv-why p { font-size: 12.5px; line-height: 1.6; margin: 8px 0 12px; }
.cv-why-acts { display: flex; gap: 10px; flex-wrap: wrap; }
.cv-why-acts .btn { font-size: 13px; }

/* A warning toast: not an error — the action did something useful (the offer
   is on the clipboard) but did not do what was asked. Amber rather than red,
   because red reads as "that failed, try again" and this one is "that worked
   differently, here is how to finish". */
.toast.warn { border-left-color: var(--amber, #c77d18); }

/* SageX in the connect modal. Green, matching the rest of the site — it was
   distinguished from Goby's violet, and Goby is gone. */
.wc-ic.sagex { background: linear-gradient(135deg, #237c41, #0f6e56); color: #fff; }

/* ═══════════════════════════════════════════════════════════════════════
   WHAT XCH IS WORTH — a block above the markets table, not a tab
   Everything in the table below is priced IN XCH, so XCH's own price is the
   unit those prices are quoted in. It belongs above them and always visible.
   ═══════════════════════════════════════════════════════════════════════ */
/* SIZED AGAINST THE TABLE IT SITS ON TOP OF.
   At 110px per card plus a heading row plus the stats strip, the first CAT row
   began at y=470 and only five of them fitted on a 1280x800 screen. This is a
   ranked list of markets; five visible ranks is not a ranked list. The cards
   are now two lines, and the heading shares their row instead of taking one.
   scripts/measure_market_header.mjs is the check — it counts rows above the
   fold and fails the layout if a card starts clipping its own numbers. */
/* Scoped to Markets rather than folded into .stats-sm, which five other pages
   also use. Those pages end at their stats; this one has 2,150 ranked rows
   underneath, so it is the only one where the strip's height is competing with
   the actual content. */
.stats-tight { gap: 8px; margin: 10px 0 12px; }
.stats-tight .stat { padding: 8px 12px; border-radius: 11px; }
.stats-tight .stat b { font-size: 17px; }
.stats-tight .stat span { font-size: 11px; }
.stats-tight .stat:hover { transform: none; }

.xq-block { margin: 0 0 12px; }
/* The heading is a grid cell beside the cards, deliberately narrower than one
   (it is a label, not a peer), and it does not stretch the row's height. */
.xq-block-h {
  display: flex; flex-direction: column; justify-content: center; gap: 2px;
  font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted); line-height: 1.25;
}
.xq-block-h small { text-transform: none; letter-spacing: 0; font-weight: 500; font-size: 10.5px; }
.xq-cards {
  display: grid; align-items: stretch; gap: 10px;
  grid-template-columns: minmax(96px, .55fr) repeat(auto-fit, minmax(190px, 1fr));
}
@media (max-width: 860px) {
  .xq-cards { grid-template-columns: 1fr 1fr; }
  .xq-block-h { flex-direction: row; align-items: baseline; gap: 8px; grid-column: 1 / -1; }
  .xq-block-h span br { display: none; }
}
@media (max-width: 560px) { .xq-cards { grid-template-columns: 1fr; } }

.xq-card {
  border: 1px solid var(--line); border-radius: 12px; padding: 8px 12px 9px;
  background: var(--panel); position: relative;
}
.xq-card.dim { opacity: .62; }
.xq-head { display: flex; align-items: baseline; gap: 7px; margin-bottom: 2px; }
/* The ticker is ONE unit and must never wrap: "XCH / wUSDC.b" broken across
   lines reads as a different token. */
.xq-sym { white-space: nowrap; font-size: 12.5px; }
.xq-sym b { font-weight: 700; }
/* Pushed to the right edge so the ticker and the badge stay together on the
   left; truncates rather than wrapping, because wrapping would put the card
   back on three lines and undo the whole point. */
.xq-meta {
  margin-left: auto; font-size: 10.5px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The bid/ask column and its "unverified book" badge are gone — the card shows
   the settled price alone, which is the one figure on it that needs no
   caveat. .xq-row and .xq-ba are retained only so an older cached app.js does
   not lose its layout mid-deploy; nothing renders them now. */
.xq-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.xq-big { font-family: ui-monospace, Menlo, monospace; line-height: 1.1; }
.xq-big b { font-size: 22px; letter-spacing: -.5px; }
.xq-big span { font-size: 12px; color: var(--muted); margin-left: 4px; }
.xq-big .xq-none { font-family: inherit; font-size: 14px; margin: 0; }
.xq-ba { display: inline-flex; align-items: baseline; gap: 4px; font-family: ui-monospace, Menlo, monospace; font-size: 11px; color: var(--muted); white-space: nowrap; }
.xq-ba i { font-style: normal; }
.xq-ba span { font-family: var(--font, inherit); font-size: 10px; margin-right: 3px; }
/* Whether the venue is actually verifying its own listings, stated on the page.
   Quiet by default — this is reassurance, not an announcement — but it turns
   amber the moment the checker stops, because a verification claim that has
   silently stopped being true is the one thing here worth interrupting for. */
.xq-chain {
  margin-top: 9px; font-size: 11.5px; color: var(--muted);
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap; cursor: help;
}
.xq-chain b { color: var(--text); font-weight: 600; }
.xq-chain i {
  width: 7px; height: 7px; border-radius: 50%; flex: none;
  background: #15a35a; box-shadow: 0 0 0 3px rgba(21,163,90,.16);
  animation: xqpulse 2.4s ease-in-out infinite;
}
@keyframes xqpulse { 0%,100% { opacity: 1 } 50% { opacity: .45 } }
@media (prefers-reduced-motion: reduce) { .xq-chain i { animation: none } }
.xq-chain.bad, .xq-chain.off { color: #c77d18; cursor: default; }

/* Amber, not red: a crossed book is stale data, not a failure, and the settled
   price beside it is unaffected. Red would say "this number is broken". */
.xq-crossed {
  font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 999px;
  background: rgba(199,125,24,.12); color: #c77d18;
  border: 1px solid rgba(199,125,24,.35); cursor: help; white-space: nowrap;
}


/* ---- stacked price: XCH per token, with tokens per XCH beneath ---- */
/* One cell, two readings of the same number. The reciprocal is a shade
   lighter and a size smaller so it reads as a restatement rather than as a
   second, competing price. */
.px2 { display: flex; flex-direction: column; line-height: 1.25; }
.px2 b { font-weight: 700; }
.px2 i {
  font-style: normal; font-size: 11px; font-weight: 500;
  color: var(--muted); opacity: .78; letter-spacing: -.01em;
}
.markets-table td.green .px2 i,
.markets-table td.red   .px2 i { color: var(--muted); }
.th-sub {
  display: block; font-size: 8.5px; font-weight: 500; letter-spacing: .04em;
  color: var(--muted); opacity: .7; text-transform: none; margin-top: 1px;
}

/* ============================================================================
   PHONES
   ============================================================================
   Measured before writing any of this, at 390x844. What was actually wrong:

     · `.nav .links { display: none }` below 720px. The links were hidden to
       stop them overflowing and nothing took their place, so on a phone the
       site had NO navigation at all — every route reachable only by typing a
       URL. That one rule is the whole "not mobile friendly" complaint.

     · The controls that remained (network toggle, Connect Wallet, Lock) still
       overran the right edge, so Lock was half off-screen.

     · 31 tap targets under 32px tall on every route. A 19px-high button is
       not a button on a touchscreen, it is a dare.

   Everything below is scoped to a width where it applies. Nothing here changes
   the desktop layout, which was never the problem.
   ============================================================================ */

.nav-toggle {
  display: none; align-items: center; justify-content: center;
  width: 40px; height: 40px; padding: 0; margin-left: auto;
  background: transparent; border: 1px solid var(--line); border-radius: 10px;
  color: var(--text); cursor: pointer; flex: none;
}
.nav-toggle svg { width: 20px; height: 20px; }
.nav-toggle:active { background: rgba(0,0,0,.05); }

@media (max-width: 860px) {
  /* THE BACKDROP FILTER HAD TO GO, AND NOT FOR TASTE.
     `backdrop-filter` on an ancestor makes that ancestor a containing block
     for `position: fixed` descendants. So the drawer, asked for top:0 bottom:0
     of the VIEWPORT, was laid out against the 92px-tall nav instead: a stub
     panel showing one link. Measured — 300x92 at left:90 instead of 300x844 at
     left:90... the width was right, which is exactly why it looked plausible.
     Dropping the blur here restores the viewport as the containing block, and
     costs a phone nothing but a compositing pass it was better off without. */
  .nav { gap: 10px; padding: 9px 14px; flex-wrap: nowrap;
         backdrop-filter: none; -webkit-backdrop-filter: none;
         background: var(--bg, #f4f6f5); }
  .nav .spacer { display: none; }
  .nav-toggle { display: inline-flex; }
  .brand { font-size: 16px; min-width: 0; }
  .brand small { display: none; }
  .brand > span:last-child { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .powered, .netpick, .nav .ops-label { display: none; }
  .mempool { display: none; }
  .net { display: none; }
  .wallet-btn { padding: 9px 12px; font-size: 13px; white-space: nowrap; flex: none; }
  .veil-lock { padding: 9px 10px; flex: none; }
  .veil-lock span { display: none; }   /* the padlock alone is unambiguous */

  /* The drawer. Off-canvas rather than pushing the page down, so opening it
     does not reflow whatever you were reading underneath. */
  .nav .links#navlinks {
    position: fixed; top: 0; right: 0; bottom: 0; width: min(78vw, 300px);
    flex-direction: column; align-items: stretch; gap: 2px; margin: 0;
    padding: 68px 14px 24px; overflow-y: auto;
    background: var(--panel); border-left: 1px solid var(--line);
    box-shadow: -18px 0 40px -20px rgba(0,0,0,.35);
    transform: translateX(100%); transition: transform .22s ease;
    z-index: 40;
  }
  .nav.open .links#navlinks { transform: translateX(0); }
  .nav .links#navlinks a {
    padding: 12px 14px; font-size: 15px; border-radius: 10px;
  }
  .nav .links.ops {
    position: fixed; right: 0; bottom: 0; width: min(78vw, 300px);
    flex-direction: column; align-items: stretch; padding: 0 14px 18px;
    background: var(--panel); border-left: 1px solid var(--line);
    transform: translateX(100%); transition: transform .22s ease; z-index: 41;
  }
  .nav.open .links.ops { transform: translateX(0); }
  .nav-scrim {
    position: fixed; inset: 0; background: rgba(8,17,12,.45);
    opacity: 0; pointer-events: none; transition: opacity .22s ease; z-index: 39;
  }
  .nav.open ~ .nav-scrim, body.nav-open .nav-scrim { opacity: 1; pointer-events: auto; }

  /* Wide tables scroll inside their own box rather than stretching the page.
     Sideways-scrolling a table is normal; sideways-scrolling a whole site is
     what people mean by "not mobile friendly".

     `display: block` on the table itself was the first attempt and it does not
     work: it turns the table into a block box, the internal table layout
     collapses, and the columns squeeze to fit rather than overflowing —
     measured at scrollWidth 344 inside a 346px box, i.e. no scroll and
     unreadable columns. The table must stay a table; the PARENT scrolls. */
  .markets-table, .trades-table, .ord-table { min-width: 660px; }
  *:has(> .markets-table), *:has(> .trades-table), *:has(> .ord-table),
  .table-wrap {
    overflow-x: auto; -webkit-overflow-scrolling: touch;
  }
  .markets-table thead, .trades-table thead, .ord-table thead { white-space: nowrap; }
  .markets-table td, .trades-table td { white-space: nowrap; }

  /* Touch targets. 36px is the floor; 44 where there is room. */
  .seg button, .netpick button, .tabs button, .chip, .bact {
    min-height: 36px; padding-top: 8px; padding-bottom: 8px;
  }
  .nav .links a, .foot-col a { min-height: 40px; display: flex; align-items: center; }

  /* The fee bar ran off the edge mid-sentence. */
  .feebar { white-space: normal; line-height: 1.5; }
}

@media (max-width: 560px) {
  /* Below this the order book's four columns cannot all be legible, so the
     total goes — it is the one value you can derive from the other two. */
  .book-head.wide span:nth-child(4), .brow .btot { display: none; }
  .book-head.wide, .brow { grid-template-columns: 1.15fr 1fr .9fr; }
  .hero h2 { font-size: 22px; }
  .term, .clob-grid { gap: 10px; }
  /* Stacked prices stay stacked, just tighter. */
  .px2 i { font-size: 10px; }
}

/* "My offers | Create offer" — two adjacent tabs in the panel header, with the
   open/completed/cancelled/rewards tabs sitting under whichever is chosen. */
.term-mine .mine-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.term-mine .mine-top { flex: 0 0 auto; }
.term-mine .mine-create { overflow: auto; max-height: 320px; padding: 0 10px 10px; }
.term-mine .mine-create .hero { display: none; }   /* the panel header already says it */
@media (max-width: 900px) { .term-mine .mine-create { max-height: 260px; } }

/* ---- phone: three things ran off the right edge -----------------------
   Measured at 390px on the live Trade page. The document did not scroll
   (scrollWidth == viewport), so none of this announced itself — it was simply
   cut off, which is the version of broken you do not notice in a screenshot. */
@media (max-width: 900px) {
  /* 1. The four tabs do not fit on one line at this width, and .seg is
        inline-flex with no wrap, so the fourth sat 66px past the edge. Wrap
        rather than scroll: a scroll container here would clip the panel, and
        a tab you have to discover by swiping is a tab nobody presses. */
  .term-mine .mine-tabs, .term-mine .mine-top { flex-wrap: wrap; }

  /* 2. The tape is width:100% but auto-layout, so its columns refused to
        shrink below their content and the table ran 50px wide of its own
        panel. Fixed layout makes the columns share what there is; the long
        cells ellipsize instead of pushing. Scoped to the terminal's copy —
        the full-width Recent Trades page has the room and should keep it. */
  .term-tape .mini-tape { table-layout: fixed; }
  .term-tape .mini-tape td, .term-tape .mini-tape th {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* 3. Bid / Ask / Spread / Levels on one nowrap line needs ~540px; at 390 the
        last two sat 147px off-screen. The bar cannot be given overflow — the
        market picker is absolutely positioned inside it and an overflow
        ancestor clips the dropdown to the bar's own 44px, which is a bug this
        file already carries a comment about. So drop the two least useful
        readings instead: bid and ask are the ones being traded on, and both
        spread and level count are readable from the book directly below.

        :nth-of-type would have been wrong here — it counts every sibling div,
        not the ones carrying this class, so any other div in the bar shifts
        which stats vanish. The sibling chain below means literally "a .tb-stat
        with at least two .tb-stats before it", whatever else shares the row. */
  .term-bar .tb-stat ~ .tb-stat ~ .tb-stat { display: none; }
}

/* Two that survived the first pass, both measured at 390px.

   The bar: hiding the last two stats was not enough. The market picker alone
   takes most of a 390px row, so Bid and Ask still sat 147px and 31px past the
   edge. Below 600px they go too — every one of those four readings is on
   screen already, in the order book directly beneath, so this costs a phone
   nothing. The 900px step keeps Bid and Ask for tablets, where they do fit. */
@media (max-width: 600px) {
  .term-bar .tb-stat { display: none; }
}

/* Panel headers: a title on the left and a reading on the right, on one nowrap
   line. At 390px the right-hand reading ran 36px off the edge instead of
   moving down. Wrapping costs a line only when it is actually needed. */
@media (max-width: 900px) {
  .term .panel-h { flex-wrap: wrap; row-gap: 2px; }
  .term .panel-h .ph-right { margin-left: auto; max-width: 100%; }
}

/* ---- Streaming Orders: the same column stacks as Trade ----------------
       CLOBOOK | chart        | place order
       CLOBOOK | your orders  | recent trades + fills

   The `display: contents` version I tried first put all five panels into one
   grid — which fixed "below the fold" but not the real complaint. A grid row
   is one height across every column, so the order form was padded down to the
   chart's height and the tape started level with the orders panel instead of
   level with the bottom of the form. Per-column stacks are what actually puts
   a panel under the one above it.

   This does need the two wrapper divs in the template. Editing that template
   broke views.clob once before, so this time the suite ran before anything was
   deployed. 20/20. */
.clob-term > .term-grid {
  display: grid;
  grid-template-columns: var(--book-w) minmax(0, 1fr) var(--form-w);
  gap: 10px; align-items: stretch;
  height: calc(100vh - var(--term-top, 250px));
  min-height: 560px; max-height: 940px;
}
/* Middle column: chart, then the market's activity beneath it — which is what
   the tape and the fills describe. Same 52/48 split as the Trade terminal.
   The two panels sit SIDE BY SIDE across the chart's width rather than stacked;
   stacked they were two narrow strips. */
.clob-term .term-col.mid > .term-chart { flex: 1 1 52%; min-height: 200px; }
.clob-term .term-col.mid > .term-below {
  flex: 1 1 48%; min-height: 170px; margin: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
}
.clob-term .term-col.mid > .term-below > .panel {
  min-height: 0; overflow: auto; margin: 0; display: flex; flex-direction: column;
}

/* Right column: the order form at its natural height, and your own orders
   directly beneath the button that creates them. */
.clob-term .term-col.right > .term-form   { flex: 0 1 auto; min-height: 0; }
.clob-term .term-col.right > .term-orders { flex: 1 1 auto; min-height: 140px; }
.clob-term .term-orders > .panel-h { flex: 0 0 auto; }
.clob-term .term-orders > #clobOrders { flex: 1 1 auto; min-height: 0; overflow: auto; }

@media (max-width: 1200px) {
  .clob-term > .term-grid {
    grid-template-columns: var(--book-w) minmax(0,1fr);
    height: auto; max-height: none; min-height: 0;
  }
  .clob-term .term-col.right { grid-column: 1 / -1; flex-direction: row; flex-wrap: wrap; }
  .clob-term .term-col.mid > .term-chart  { flex: 0 0 auto; height: 300px; }
  .clob-term .term-col.mid > .term-below  { flex: 0 0 auto; height: 300px; }
  .clob-term .term-col.right > .term-form   { flex: 1 1 300px; }
  .clob-term .term-col.right > .term-orders { flex: 1 1 320px; height: 300px; }
}
@media (max-width: 860px) {
  .clob-term > .term-grid { grid-template-columns: 1fr; }
  .clob-term .term-col.right { flex-direction: column; }
  .clob-term .term-col.right > .term-form,
  .clob-term .term-col.right > .term-orders { flex: 0 0 auto; }
  .clob-term .term-col.mid > .term-below { grid-template-columns: 1fr; height: auto; }
}


/* ---- denser tape rows -------------------------------------------------
   The whole page is meant to fit one window, and the tape is the panel that
   most wants to be taller. Rows were 4px of padding on a 11.5px line — about
   24px each. At 17px you see seven trades in the space that used to show
   five, which is the difference between the panel answering "what is trading"
   and merely proving that something did.

   Scoped to the terminals: the full-width Recent Trades page is a table you
   read, not a strip you scan, and it keeps its breathing room. */
.term-tape .mini-tape td,
.term-below .mini-tape td {
  padding: 1.5px 8px; font-size: 11px; line-height: 14px;
}
.term-tape .mini-tape th,
.term-below .mini-tape th {
  padding: 3px 8px; font-size: 9px; line-height: 12px;
}
.term-tape .mini-tape, .term-below .mini-tape { font-size: 11px; }
/* Same for your own rows in the two order panels. */
.term-mine .mine-body table td, .term-orders table td { padding: 2px 8px; font-size: 11px; line-height: 14px; }
.term-mine .mine-body table th, .term-orders table th { padding: 3px 8px; font-size: 9px; }
.term-below .fills .fill { padding: 2px 8px; font-size: 11px; line-height: 14px; }

/* The tape's Links cell is what actually made the rows tall.
   .txlinks is flex-wrap:wrap, and in a 352px column its three or four chain
   chips wrapped onto three lines — 84px per row, measured. Tightening td
   padding did nothing, because the padding was never the problem; a row is as
   tall as its tallest cell. One line, smaller chips, and anything that still
   does not fit is clipped rather than allowed to push the row down. */
.term-tape .txlinks, .term-below .txlinks { flex-wrap: nowrap; gap: 4px; }
.term-tape .txlinks a, .term-below .txlinks a {
  padding: 0 4px; font-size: 9.5px; line-height: 15px; white-space: nowrap;
}
.term-tape .mini-tape td:last-child,
.term-below .mini-tape td:last-child {
  max-width: 96px; overflow: hidden; white-space: nowrap;
}
.term-tape .mini-tape tbody tr, .term-below .mini-tape tbody tr { height: 18px; }

/* ---- Create offer, inside the terminal panel --------------------------
   Measured: the panel gives it 280px and the form wanted 457 — 177px over, so
   it scrolled. Everything below is scoped to .mine-create, because the same
   markup is the full /submit page where the roominess is right.

   Where the 177px comes from, and where it goes back:
     · the Build / Paste toggle was 46px on its own row      -> 30
     · the panel header repeats what the tab above already says, twice -> gone
     · .pad 12/14 and .mkrow gaps                            -> 7/10, tighter
     · the ↓ between the two rows was a full text line       -> 12px glyph
     · the "npm run mint" footnote is developer trivia in a
       panel with no room for it                             -> hidden here
   Nothing is removed that carries information the form needs. */
.term-mine .mine-create .seg { max-width: 240px; margin-bottom: 8px !important; padding: 2px; }
.term-mine .mine-create .seg button { padding: 4px 8px; font-size: 12px; }
.term-mine .mine-create > .panel { border: 0; background: none; margin: 0; }
.term-mine .mine-create > .panel > .panel-h { display: none; }
.term-mine .mine-create .pad { padding: 0 2px 4px; }
.term-mine .mine-create .mkrow { gap: 6px; margin-bottom: 6px; }
.term-mine .mine-create .mkrow label { font-size: 11px; }
.term-mine .mine-create .mkarrow { font-size: 12px; line-height: 12px; margin: 2px 0; }
.term-mine .mine-create .field,
.term-mine .mine-create select { padding: 5px 8px; font-size: 12px; }
.term-mine .mine-create .quote-row { padding: 1px 0; font-size: 12px; }
.term-mine .mine-create .row { margin-top: 6px !important; gap: 6px; }
.term-mine .mine-create button.primary { padding: 6px 12px; font-size: 12.5px; }
.term-mine .mine-create textarea { min-height: 90px; font-size: 11px; }
/* Developer footnote — not in a panel this size. It stays on /submit. */
.term-mine .mine-create > .panel > .pad > p.muted:last-child { display: none; }

/* ---- Verified page ----------------------------------------------------
   Every selector here is .vf-*, on purpose. The Trade and Streaming terminals
   are signed off and frozen; a page-specific prefix is what makes it
   impossible for this work to reach them. Nothing below touches .term-*,
   .mine-* or the tape density rules. */
.vf-panel { margin-bottom: 14px; }
.vf-lede { margin: 0 0 10px; font-size: 13px; max-width: 76ch; }

/* The coverage bar: one strip, segments proportional to the real counts, so
   the shape of the claim is visible before any number is read. */
.vf-bar {
  display: flex; height: 9px; border-radius: 5px; overflow: hidden;
  background: var(--bg-2); border: 1px solid var(--line); margin-bottom: 12px;
}
.vf-seg { display: block; height: 100%; }
.vf-seg.ok   { background: var(--green); }
.vf-seg.warn { background: #d9a441; }
.vf-seg.bad  { background: var(--red); }

.vf-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  margin-right: 7px; vertical-align: middle;
}
.vf-dot.ok { background: var(--green); }
.vf-dot.warn { background: #d9a441; }
.vf-dot.bad { background: var(--red); }

.vf-table { width: 100%; }
.vf-table td, .vf-table th { vertical-align: top; }
.vf-table .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

.vf-tiers { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; }
.vf-tier {
  border: 1px solid var(--line); border-radius: 10px; padding: 11px 13px; background: var(--bg-2);
}
.vf-tier b { display: block; margin-bottom: 3px; }
.vf-tier p { margin: 0 0 7px; font-size: 12.5px; }
.vf-tier ul { margin: 0; padding-left: 16px; }
.vf-tier li { font-size: 12px; color: var(--muted); margin-bottom: 2px; }
.vf-reg { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }

@media (max-width: 700px) {
  .vf-table td:last-child, .vf-table th:last-child { display: none; }
  .vf-tiers { grid-template-columns: 1fr; }
}

/* Dexie-style tape: the price carries the direction, so the Side column is
   gone. The unit sub-label inside a coloured price cell must stay muted —
   without this it inherits the red/green and reads as part of the number. */
.px-side { font-variant-numeric: tabular-nums; }
.px-side .qc, .px-side small { color: var(--muted) !important; }

/* ---------------------------------------------------------------------------
   Order-book action tooltips.

   The four row buttons are single glyphs — ⧉ ↓ ⊙ ✓ — and were relying on the
   native `title` tooltip, which takes about a second to appear and is drawn by
   the OS in a font nothing else here uses. In practice that meant four
   unlabelled buttons, one of which spends money.

   These pop instantly, sit ABOVE the button (the actions are already pinned to
   the right edge of the row, so a tooltip below would fall outside the panel on
   the bottom rows), and are pointer-events:none so they can never eat the click
   they are describing.
   --------------------------------------------------------------------------- */
.bact { position: relative; }

.bact[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  bottom: calc(100% + 7px);
  left: 50%;
  transform: translateX(-50%) translateY(3px);
  padding: 5px 8px;
  border-radius: 6px;
  background: #0a1a12;
  border: 1px solid var(--line, #2a3b31);
  color: #eaf6ef;
  font: 600 10.5px/1.25 Inter, system-ui, sans-serif;
  letter-spacing: .1px;
  white-space: nowrap;
  box-shadow: 0 8px 22px rgba(0, 0, 0, .6);
  opacity: 0;
  pointer-events: none;      /* never intercept the click it describes */
  transition: opacity .1s ease, transform .1s ease;
  z-index: 40;               /* above .bacts (5), which is itself above the row */
}
/* The little pointer. Same colour as the bubble, no border, so it reads as one
   shape rather than a diamond stuck underneath. */
.bact[data-tip]::before {
  content: "";
  position: absolute;
  bottom: calc(100% + 3px);
  left: 50%;
  transform: translateX(-50%) translateY(3px);
  border: 4px solid transparent;
  border-top-color: #0a1a12;
  opacity: 0;
  pointer-events: none;
  transition: opacity .1s ease, transform .1s ease;
  z-index: 40;
}
.bact[data-tip]:hover::after,
.bact[data-tip]:focus-visible::after,
.bact[data-tip]:hover::before,
.bact[data-tip]:focus-visible::before {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* Club is a real button now, not a hint glyph. It is the only action here that
   spends across MULTIPLE offers, so it is tinted differently from ✓ (which
   spends on exactly one) — the two must never be mistaken for each other at a
   glance. The amber matches the existing .bact.club:hover rule further up. */
.bact.club { color: #f2c14e; border-color: rgba(242, 193, 78, .45); }

/* The leftmost button's tooltip is wide and would clip on the panel edge;
   anchor those to the right instead of the centre. */
.brow .bacts > :first-child[data-tip]::after { left: 0; transform: translateX(0) translateY(3px); }
.brow .bacts > :first-child[data-tip]:hover::after { transform: translateX(0) translateY(0); }
.brow .bacts > :last-child[data-tip]::after { left: auto; right: 0; transform: translateX(0) translateY(3px); }
.brow .bacts > :last-child[data-tip]:hover::after { transform: translateX(0) translateY(0); }

@media (max-width: 700px) {
  /* No hover on a touch screen, so the tooltips are dead weight and the hint
     glyph is just clutter competing for a narrow row. */
  .bact[data-tip]::after, .bact[data-tip]::before { display: none; }
}

/* ---------------------------------------------------------------------------
   Clubbed-offer QR. Appended to <body> on demand, never part of the frozen
   terminal grid.
   --------------------------------------------------------------------------- */
.clubqr-wrap {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  background: rgba(2, 8, 5, .72);
  backdrop-filter: blur(2px);
}
.clubqr {
  width: min(380px, 92vw);
  background: #0a1a12;
  border: 1px solid var(--line, #2a3b31);
  border-radius: 12px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .6);
  padding: 14px 16px 16px;
  text-align: center;
}
.clubqr-h {
  display: flex; align-items: center; justify-content: space-between;
  font: 700 12px/1 Inter, system-ui, sans-serif;
  color: #eaf6ef; letter-spacing: .3px; text-transform: uppercase;
  margin-bottom: 10px;
}
.clubqr-x {
  appearance: none; background: none; border: 0; cursor: pointer;
  color: var(--muted, #9fb3a8); font-size: 15px; line-height: 1; padding: 2px 4px;
}
.clubqr-x:hover { color: #fff; }
.clubqr-note {
  margin: 0 0 10px; font: 500 11.5px/1.45 Inter, system-ui, sans-serif;
  color: #f2c14e;
}
/* White quiet zone: a QR on a dark panel does not scan reliably. */
.clubqr-img {
  width: 100%; max-width: 300px; height: auto;
  background: #fff; padding: 10px; border-radius: 8px;
}
.clubqr-sub {
  margin: 10px 0 12px; font: 500 11.5px/1.45 Inter, system-ui, sans-serif;
  color: var(--muted, #9fb3a8);
}
/* Live status under the QR: what the wallet and the chain are saying. Empty
   until there is something to report, so it takes no room when unused. */
.clubqr-state {
  margin: 0 0 10px; font: 500 11.5px/1.45 Inter, system-ui, sans-serif;
  color: var(--accent, #7fe0b0); min-height: 0;
}
.clubqr-state:empty { display: none; }
.clubqr-acts { display: flex; gap: 8px; justify-content: center; }
.clubqr-btn {
  appearance: none; cursor: pointer; text-decoration: none;
  border: 1px solid var(--line, #2a3b31);
  background: rgba(255, 255, 255, .04);
  color: #eaf6ef;
  font: 600 11.5px/1 Inter, system-ui, sans-serif;
  padding: 8px 12px; border-radius: 7px;
}
.clubqr-btn:hover { border-color: #4fd28a; color: #fff; background: #12301f; }

/* Create Offer: the expiry row and its explanation.
   The note is not decoration — it is the only place the page admits that the
   connected wallet may not be able to honour what the picker offers. */
.mkexp select { flex: 1 1 auto; }
.mkexp-note.ok   { color: var(--accent, #7fe0b0); }
.mkexp-note.warn { color: var(--warn, #e0b45f); }

/* Verified: the listed-assets panel. The list IS the claim, so it gets the
   room a table needs rather than being tucked into a summary line. */
.vf-search { min-width: 260px; font-size: 12px; padding: 4px 8px; }
.vf-tabs { gap: 6px; margin-bottom: 10px; }
.vf-delist { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line, #2a3b31); }

/* Supply and market cap in the pair ribbon. These ARE readings, not identity —
   so unlike the asset id they are allowed to drop on narrow screens, where the
   bar has no room and the numbers are not needed to place a trade. */
.tb-cap b { font-variant-numeric: tabular-nums; }

/* ===========================================================================
   FIT — measured, not guessed
   ===========================================================================
   Every rule below exists because scripts/measure_viewport.mjs found a real
   number, on a real Chrome, at a size somebody actually uses. The numbers in
   the comments are the readings taken before the fix, so a later change can be
   checked against them rather than against a memory of how it looked.

   Sizes that matter, from xrandr on the owner's machine:
     1366x768   the laptop panel — the tight desktop case
     1920x1080  the external monitor
     390x844    iPhone 14/15
     360x740    the common Android floor
   =========================================================================== */

/* --- A token logo is a MARK, not a picture -------------------------------- */
/*
   `.av img` was `object-fit: cover` for everything. Cover fills the tile and
   throws away whatever does not fit, which is right for NFT artwork and wrong
   for a logo: most token marks are drawn to the edge of their own canvas, so
   any aspect-ratio difference shaves the sides off. That is the "image is a
   little cut off at the edges" on the Trade ribbon.

   Logos are now contained — shown whole, letterboxed against the tile — with a
   hair of padding so the mark is not welded to the rounded corner. Artwork
   keeps cover, because a cropped photograph looks composed and a cropped logo
   looks broken.
*/
.av img            { object-fit: contain; }
.av.av-logo img    { object-fit: contain; padding: 2px; }
.av.av-art img     { object-fit: cover;   padding: 0; }
.av.av-logo.sm img { padding: 1px; }

/* --- The terminal promises one screen; the footer was breaking it ---------- */
/*
   Measured at 1366x768 on #/trade: the terminal itself ends at 742px — inside
   the viewport, as designed. Then the site footer adds 48px of margin and
   ~470px of five-column links, and the document becomes 1260px: a 492px
   scroll on the one page whose entire point is not to have one.

   The footer is not deleted, it is collapsed to its base line. The links still
   exist on every other route, which is where somebody browsing for them
   actually is.
*/
body.is-terminal footer { margin-top: 0; }
body.is-terminal .foot-cols { display: none; }
body.is-terminal .foot-base {
  border-top: 0; padding: 10px 28px; font-size: 11.5px;
}

/*
   Collapsing the footer got Trade from 1260px to 851px — better, still 83px
   past a 768px screen. The remaining 83px is not one thing to trim; it is the
   terminal being CONTENT-SIZED while the space available to it is not.

   So stop doing arithmetic and let the box model do it. On terminal routes the
   page becomes a flex column — nav, main, footer — where main takes exactly
   what is left and the terminal fills main. Whatever the viewport is, and
   whatever the nav or the fee bar decide to be that day, the terminal ends
   where the footer begins. The order book gives up rows instead of the page
   gaining a scrollbar, which is the trade this layout was built to make.

   `100dvh`, not `100vh`: on mobile browsers vh counts the address bar that is
   about to slide away, so vh overshoots by ~60-100px on exactly the devices
   with the least room to spare. The vh line above it is the fallback for
   anything too old to know dvh.
*/
/*
   `min-height: 100dvh` was the first attempt and it did nothing: a MINIMUM is
   not a constraint. Flexbox only shrinks children when the container has a
   definite size smaller than its content, so at 851px of content the body just
   grew to 851px and every child kept its natural height. Measured, unchanged.

   A definite `height` is what makes the terminal give ground. `overflow:
   hidden` then states the intent out loud: on these two routes the page does
   not scroll, full stop. Everything inside already scrolls in its own panel.

   Desktop only — see the phone block further down, where the grid stops being
   a grid and the page is allowed to scroll, because 390px of screen cannot
   hold a trading terminal and pretending otherwise is what made the type 8px.
*/
/*
   AND `min-height`, which the first version of this rule did not have.
   That omission is what the owner's screenshot showed on 2026-08-09.

   THE CONTRADICTION
     `.term:not(.clob-term)` carries `min-height: 560px` — a floor it will not
     go below — and the chrome above it (nav, fee bar, pair ribbon) plus the
     footer runs to about 104px. So the terminal needs ~664px of viewport
     before it can honour its own floor. This rule then said `height: 100dvh;
     overflow: hidden` at ANY height, so on a shorter window the floor won, the
     clip ate the difference, and there was no scrollbar to recover it.

     Measured at 1293x622 with scripts/measure_reachable.mjs:
         div.term-col.right   shows 156px of 385px   229px unreachable
         div.term-col.mid     shows 172px of 400px   228px unreachable
         page can scroll: false
     which is exactly the screenshot: one order-book row, a ticket cut off
     above its own Buy button, and no way to reach any of it.

   WHY measure_viewport.mjs SAID IT WAS FINE
     It asks "is scrollHeight greater than the viewport". Under
     `overflow: hidden` that can never be true — the check was measuring the
     constraint imposed here rather than whether a person could use the page,
     and reported "fits height, 0 faults" for a terminal nobody could trade on.
     scripts/measure_reachable.mjs asks the answerable question instead: is
     any control outside the viewport, and does any panel hide content with no
     way to scroll it.

   THE GATE
     700px, because 664px is the arithmetic and the chrome is not a fixed
     number — it grows with a wrapped nav or a second fee line. Above it,
     nothing changes at all: 1366x768 and 1920x1080 keep the frozen layout
     pixel for pixel. Below it the page simply scrolls, which is not a defeat
     — a 600px window cannot hold a trading terminal, and clipping it silently
     is worse than letting someone scroll.
*/
/*
   AND `min-width: 1201px`, matching the reflow breakpoint below.

   The `max-width: 1200px` block that stacks the terminal says in its own
   comment "below this width the terminal scrolls" — and nothing ever made it
   scroll, because this rule started at 721px. So every width from 721 to 1200
   got the stacked layout crammed into a locked viewport with `overflow:
   hidden`. The two rules have to agree on where the single-window terminal
   ends, or one of them is lying.
*/
@media (min-width: 1201px) and (min-height: 700px) {
  body.is-terminal {
    height: 100vh; height: 100dvh; overflow: hidden;
    display: flex; flex-direction: column;
  }
  body.is-terminal > main#view {
    flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; overflow: hidden;
  }
  body.is-terminal > footer { flex: 0 0 auto; }
  body.is-terminal .term { flex: 1 1 auto; min-height: 0; }
}

/* --- and the other side of that switch --------------------------------------
   When the window CANNOT hold the single-window terminal, the terminal has to
   stop behaving like one. Letting the page scroll was necessary but not
   sufficient: `.term` still carried `height: calc(100vh - var(--term-chrome))`,
   so at 622px it handed its columns 204px and `.term-col { overflow: hidden }`
   ate the rest. Measured after the first fix —
       div.term-col.mid       shows 204px of 400px   196px unreachable
       section.term-chart     shows 198px of 358px   160px unreachable
   the page scrolled, and scrolling reached nothing, because the clipping was
   inside the columns rather than at the page.

   A viewport-derived height only makes sense when the viewport is the frame.
   Here it is not: the panels take their natural height, the columns stop
   clipping, and the page grows. The inner lists keep their own caps so a long
   My-offers list cannot make the page a mile long.

   The width half of this duplicates the `max-width: 1200px` block on purpose —
   that block cannot know about height, and a rule that only half-applies is
   how the terminal ended up locked and stacked at the same time. */
@media (max-width: 1200px), (max-height: 699px) {
  .term:not(.clob-term) { height: auto; min-height: 0; }
  .term-col { overflow: visible; min-height: 0; }
  .term-col > .panel { overflow: visible; }
  /* A DEFINITE HEIGHT, not `min-height` — the chart panel must not be able to
     track its own content.

     With `flex: 0 0 auto; min-height: 220px` the panel is content-sized, so
     anything the chart adds to itself after mount feeds straight back into the
     panel. Measured at 1293x622 on the DBX book, sampling the panel height:
         t=8s  406px    t=15s  414px    t=25s  430px
     still climbing — the "chart elongates after opening the tab" the owner
     reported. At 1366x768 the same chart is stable at 246px, because there the
     locked layout gives the panel a definite share (`flex: 1 1 52%`) and the
     feedback path does not exist.

     mountChart() already creates the chart at a fixed 300px and the previous
     instance is torn down, so the growth is not stacked charts — it is the
     panel following its content. 380px = header + controls + that 300px chart,
     and being definite it cannot grow. Same treatment as .term-mine below. */
  .term-col.mid > .term-chart { flex: 0 0 auto; height: 380px; }
  .term-col.mid > .term-mine  { flex: 0 0 auto; height: 340px; }
  .term-col.right > .term-form { flex: 0 0 auto; }
  .term-col.right > .term-tape { flex: 0 0 auto; height: 300px; }

  /* Streaming Orders needs its own definite heights here for the same reason
     Trade does. Measured at 1293x622 before these: the clob chart panel came
     out 599x200 and the chart canvas ran 79px past it — clipped rather than
     overlapping, but a cropped chart with no axis is not much better. */
  .clob-term .term-col.mid > .term-chart { flex: 0 0 auto; height: 320px; }
  .clob-term .term-col.mid > .term-tape  { flex: 0 0 auto; height: 260px; }
  .clob-term .term-col.right > .term-orders { flex: 0 0 auto; height: 240px; }
  .clob-term .term-col.right > .term-fills  { flex: 0 0 auto; height: 200px; }

  /* The book is a direct grid child, not a column child, so none of the
     per-column heights above reach it — and with the page free to scroll it
     took its natural height: measured 254x781 at 1293x622, a panel taller
     than the window it sits in, with the spread stranded somewhere in the
     middle of a very long ladder.

     440px shows roughly a dozen levels a side around the spread, which is the
     part anyone reads, and both ladders keep their own scroll for the rest. */
  .term-grid > .term-book { height: 440px; }
}

/* --- Horizontal overflow inside panels ------------------------------------ */
/*
   `span.txlinks` sat 45px past the right edge of the tape, fifteen times over,
   at BOTH 1366 and 390. The row is a fixed grid; the links column has to live
   inside its cell rather than deciding its own width.
*/
.txlinks { min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The cell has to be allowed to be narrow, or the span inside it can never be:
   a table cell sizes to its content by default and hands the overflow to the
   row. */
.mini-tape td, .term-tape td { min-width: 0; max-width: 0; overflow: hidden; }
.mini-tape, .term-tape table { table-layout: fixed; width: 100%; }

/* The asset id is identity and must not be dropped — but at 390px it was 19px
   wider than the screen. It shrinks instead. */
.tb-stat.tb-assetid { min-width: 0; }
.tb-stat.tb-assetid b { overflow: hidden; text-overflow: ellipsis; }

/* ===========================================================================
   PHONE — a terminal cannot be a terminal at 390px, and pretending costs more
   ===========================================================================
   Measured at 390x844 before any of this: the Trade route had 887 elements
   with text under 11px, 533 controls under 32px tall, an order book row 20px
   high, and a nav panel 300px wider than the screen. Shrinking a five-column
   trading grid onto a phone is what produced all of it.

   So on a phone the grid stops being a grid. Panels stack, at a size a thumb
   can hit and an eye can read, and the page is allowed to scroll — because a
   phone screen genuinely cannot hold a trading terminal, and insisting it can
   is what made the type 8px in the first place.
   =========================================================================== */
@media (max-width: 720px) {
  /* One column, natural height, no inner scroll traps. */
  .term-grid,
  .clob-term .term-grid {
    display: flex; flex-direction: column; gap: 10px;
    min-height: 0; height: auto;
  }
  .term, .clob-term { height: auto; min-height: 0; }
  .term-col { width: auto !important; max-width: none; min-width: 0; overflow: visible; }
  .term-col.left, .term-col.mid, .term-col.right { flex: 0 0 auto; height: auto; }

  /* Give each panel a real, bounded height rather than letting one of them
     own the whole page. Scroll happens INSIDE the panel, once, on purpose. */
  .term-book, .term-tape, .term-mine, #takePanel {
    height: auto; max-height: 46vh; overflow-y: auto;
  }
  .term-chart { height: 200px; min-height: 200px; }

  /* Readable, tappable — aimed at what was actually measured, not at a guess.
     At 390px the Trade route had 887 elements under 11px and 529 controls
     under 32px. Counted by selector:

        490  small                         @10px
        240  .bamt / .bper / .btot / .bp   @10.5px   (order book cells)
         45  a inside .txlinks             @9.5px
        160  button.bact                   31x31
         79  .brow                         344x20    (a 20px trading row)

     12px is the floor for a number somebody is about to trade on. 34px is a
     fingertip with a margin for error — 32 measured as 31 once padding and
     borders were counted, which is the sort of near-miss that keeps a control
     technically compliant and practically unhittable.

     Specificity is deliberate: the defaults these override are set on
     descendant selectors, so a bare `.brow` loses and nothing changes. */
  .term small, .term-tape small, .term-book small { font-size: 11.5px; }
  .term-book .brow .bp,
  .term-book .brow .bamt,
  .term-book .brow .bper,
  .term-book .brow .btot { font-size: 12px; }
  .term-book .brow, .term-tape .trow { min-height: 34px; align-items: center; }
  .term-book .bact, .term .bact { min-width: 34px; min-height: 34px; }
  /* The tape's explorer links were 46x17 — three of them per row, fifteen rows,
     and the single largest remaining group of unhittable controls. The row is
     already 34px tall, so filling it costs nothing. */
  .term .txlinks a, .term-tape a {
    font-size: 11.5px; min-height: 30px;
    display: inline-flex; align-items: center; padding: 0 3px;
  }
  .term h4, .term th { font-size: 11px; }
  .term label, .term th { font-size: 11px; }
  .term select, .term input, .term button { min-height: 34px; font-size: 12px; }

  /* The pair ribbon wraps instead of forcing a sideways scroll, and the
     readings that were hidden at narrow desktop widths come back — a phone has
     vertical room even when it has no horizontal room. */
  /* The bar is `flex-wrap: nowrap` on desktop so the pair line stays one line.
     On a phone that is what pushed MARKET CAP off the right edge with no way to
     reach it. Here it wraps — a phone has vertical room even when it has none
     horizontally, which is the whole shape of this breakpoint. */
  .term-bar { flex-wrap: wrap; row-gap: 4px; min-height: 0; padding: 6px 8px; }
  .tb-stats, #tbStats, #clobStats { flex-wrap: wrap; row-gap: 6px; }
  .tb-stat { flex: 0 1 auto; }
  .tb-stat:nth-of-type(3), .tb-stat:nth-of-type(4) { display: flex; }

  /* Markets was 292px wider than the screen: a six-column table on a 390px
     phone. It scrolls in its own box rather than dragging the page sideways.
     Both classes in the selector — the rule it overrides carries both, so a
     single-class selector loses on specificity and silently does nothing. */
  table.markets-table, table.mkt-grid, table.markets-table.mkt-grid {
    display: block; overflow-x: auto; -webkit-overflow-scrolling: touch;
    max-width: 100%; white-space: nowrap;
  }

  /* The collapsed nav panel measured 300px past the right edge even while
     hidden. Off-canvas means off-canvas. */
  .nav .links:not(.open) { max-width: 100vw; }

  footer { margin-top: 20px; }
  body.is-terminal .foot-base { padding: 10px 16px; }
}

/* The Android floor is narrower than the iPhone, and that is where a fixed
   min-width finally bites. */
@media (max-width: 380px) {
  .term-chart { height: 170px; min-height: 170px; }
  .tb-stat { font-size: 11px; }
}
