/* =============================================================
   Cultural Infrastructure — suite launcher
   Mini-app chrome ported from apps/web (bridge) so the suite
   reads as one product. Two surfaces, one stylesheet:
     [data-splash="0"] — Telegram mini app shell (appbar/cards/tabbar)
     [data-splash="1"] — browser splash (gallery wordmark, one CTA)
   Set on <html> by app.js based on Telegram WebApp detection.
============================================================= */

:root {
  --paper: #fafaf7;
  --ink:   #0a0a0a;
  --hint:  #6c6b69;
  --line:  rgba(10, 10, 10, 0.12);
  --soft:  rgba(10, 10, 10, 0.04);
  --softer:rgba(10, 10, 10, 0.025);
  --chip:  rgba(10, 10, 10, 0.06);

  --ok:    #1a7f4f;
  --warn:  #a76b1c;
  --bad:   #b3261e;

  /* Chart palette — single source for the suite's candle identity (CI.chart /
   * ci/chart.js reads these; the bot's server-rendered PNG uses the same hexes).
   * Theme-independent so candles read the same in light + dark. */
  --up:     #26d07c;
  --down:   #ef5b5b;
  --accent: #6aa6ff;

  --bg: var(--paper);
  --fg: var(--ink);
  --card: var(--soft);
  --card-soft: var(--softer);
  --border: var(--line);

  --tabbar-h: 60px;

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --sans:  ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, sans-serif;
  --mono:  ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #0a0a0a;
    --ink:   #fafaf7;
    --hint:  #8a8987;
    --line:  rgba(250, 250, 247, 0.14);
    --soft:  rgba(250, 250, 247, 0.05);
    --softer:rgba(250, 250, 247, 0.03);
    --chip:  rgba(250, 250, 247, 0.07);
    --ok:    #4ade80;
    --warn:  #f5b342;
    --bad:   #f87171;
  }
}

/* Telegram theme override — explicit when set */
[data-mode="light"] {
  --paper: #fafaf7;
  --ink:   #0a0a0a;
  --hint:  #6c6b69;
  --line:  rgba(10, 10, 10, 0.12);
  --soft:  rgba(10, 10, 10, 0.04);
  --softer:rgba(10, 10, 10, 0.025);
  --chip:  rgba(10, 10, 10, 0.06);
}
[data-mode="dark"] {
  --paper: #0a0a0a;
  --ink:   #fafaf7;
  --hint:  #8a8987;
  --line:  rgba(250, 250, 247, 0.14);
  --soft:  rgba(250, 250, 247, 0.05);
  --softer:rgba(250, 250, 247, 0.03);
  --chip:  rgba(250, 250, 247, 0.07);
}

* { box-sizing: border-box; margin: 0; padding: 0; }
[hidden] { display: none !important; }
html, body {
  background: var(--bg); color: var(--fg);
  font-family: var(--sans);
  font-size: 15px; line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
}
button, input { font-family: inherit; color: inherit; }
button { cursor: pointer; }
a { color: var(--fg); text-decoration: none; }

/* =============================================================
   TELEGRAM MINI APP SHELL ([data-splash="0"])
============================================================= */
html[data-splash="0"] body { padding-bottom: var(--tabbar-h); }

.appbar {
  position: sticky; top: 0; z-index: 10;
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 18px 14px;
  /* In Telegram fullscreen (desktop), clear the floating window controls. */
  padding-top: calc(18px + var(--tg-top-inset, 0px));
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}
.appbar-left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.brand-mark {
  display: block;
  width: 38px; height: 36px;
  object-fit: contain;
  flex: none;
  user-select: none; -webkit-user-drag: none;
}
@media (prefers-color-scheme: dark) { .brand-mark { filter: invert(1); } }
[data-mode="dark"] .brand-mark { filter: invert(1); }
[data-mode="light"] .brand-mark { filter: none; }
.appbar-words { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.brand {
  font-family: var(--serif);
  font-size: 22px;
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
}
/* Long product names (e.g. "Cultural Infrastructure" on Home) need a
 * smaller cap to stay on one line in the appbar. Toggled by app.js
 * based on string length so short names like "Bridge" keep the big
 * display treatment. */
.brand.brand-long {
  font-size: 15px;
  letter-spacing: 0.06em;
  line-height: 1.1;
}
.brand-sub {
  font-family: var(--serif);
  font-style: italic;
  font-size: 12.5px;
  color: var(--hint);
  margin-top: 4px;
}

.appbar-right { display: flex; align-items: center; gap: 12px; flex: none; }
.appbar-status {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--hint);
  letter-spacing: 0.04em;
  text-transform: lowercase;
}
/* Universal token-search trigger (opens CI.search launcher). */
.appbar-search {
  appearance: none; flex: none;
  width: 34px; height: 34px; border-radius: 999px;
  border: 1px solid var(--line); background: transparent; color: var(--fg);
  font-size: 17px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.appbar-search:hover { background: var(--card-soft); }
.appbar-search:active { transform: scale(0.94); }

/* Contextual back ("up") chevron — first item in appbar-left, only shown on
 * surfaces with a logical parent (set by app.js). [hidden] collapses it so the
 * appbar gap doesn't reserve space on Home/Settings. */
.appbar-back {
  appearance: none; flex: none;
  width: 30px; height: 30px; border-radius: 999px;
  border: 1px solid var(--line); background: transparent; color: var(--fg);
  font-size: 22px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  padding: 0 0 2px; margin-right: -2px;
}
.appbar-back[hidden] { display: none; }
.appbar-back:hover { background: var(--card-soft); }
.appbar-back:active { transform: scale(0.92); }

/* Live TON balance pill — shown in appbar-status when wallet is linked.
 * Polled every 30s; .pulse flash on each refresh as a subtle liveness
 * signal so the user knows it's actually current. */
.wallet-status {
  appearance: none;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--fg);
  border-radius: 999px;
  padding: 5px 11px 5px 8px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: background 120ms ease, border-color 240ms ease;
}
.wallet-status:hover { background: var(--chip); }
.wallet-status .wallet-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--ok);
  flex: none;
}
.wallet-status.pulse { border-color: var(--ok); }
.wallet-bal { white-space: nowrap; }

.content {
  max-width: 480px;
  margin: 0 auto;
  padding: 14px 18px 28px;
  display: flex; flex-direction: column; gap: 16px;
}
.view { display: none; flex-direction: column; gap: 16px; }
.view-active { display: flex; }

/* ===== CARDS ============================================== */
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 16px;
}
.card-title-row {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 14px;
}
.card-title {
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--hint);
}
.badge {
  background: var(--chip);
  font-family: var(--mono);
  font-size: 10.5px; font-weight: 500;
  padding: 2px 8px; border-radius: 999px;
  color: var(--fg);
  letter-spacing: 0.04em;
}

.card-soft {
  background: transparent;
  border-top: 1px solid var(--line);
  padding: 16px 2px 4px;
}
.card-soft-body {
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  color: var(--hint);
  line-height: 1.55;
}

.empty {
  font-family: var(--serif);
  font-style: italic;
  color: var(--hint);
  font-size: 13px;
  padding: 6px 0;
}
.error {
  font-family: var(--serif);
  font-style: italic;
  color: var(--bad);
  font-size: 13px;
}

/* ===== PRODUCT TILES ======================================
   Single-column list of tappable rows inside a card. Brand
   mark on the left, name + sub on the right, soft chevron. */
.tile-list { display: flex; flex-direction: column; }
.tile {
  display: grid;
  grid-template-columns: 38px 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 14px 0;
  border-top: 1px solid var(--line);
  color: inherit;
  transition: opacity 120ms ease;
}
.tile:first-child { border-top: 0; padding-top: 4px; }
.tile:last-child { padding-bottom: 4px; }
.tile:hover { opacity: 0.7; }
.tile.muted { opacity: 0.45; pointer-events: none; }
.tile.muted:hover { opacity: 0.45; }
.tile-mark {
  width: 38px; height: 36px;
  object-fit: contain;
  user-select: none; -webkit-user-drag: none;
}
@media (prefers-color-scheme: dark) { .tile-mark { filter: invert(1); } }
[data-mode="dark"] .tile-mark { filter: invert(1); }
[data-mode="light"] .tile-mark { filter: none; }
.tile-glyph {
  width: 38px; height: 36px;
  display: flex; align-items: center; justify-content: center;
  font-size: 22px; line-height: 1;
  color: var(--fg);
  opacity: 0.85;
}
.tile-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tile-name {
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 400;
  letter-spacing: 0.005em;
  line-height: 1.2;
}
.tile-sub {
  font-family: var(--serif);
  font-style: italic;
  font-size: 12.5px;
  color: var(--hint);
}
.tile-chev {
  font-family: var(--mono);
  font-size: 14px;
  color: var(--hint);
  opacity: 0.6;
}

/* ===== RECENT LIST ======================================== */
/* Used in two layouts:
 * - .recent-list (vertical rows): Watchlist, sub-pages
 * - .recent-carousel (horizontal scroll-snap squares): Home Recent */
.recent-list { display: flex; flex-direction: column; }
.recent-row {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px;
  padding: 12px 0;
  border-top: 1px solid var(--line);
  color: inherit;
  transition: opacity 120ms ease;
}
.recent-row:first-child { border-top: 0; padding-top: 4px; }
.recent-row:last-child { padding-bottom: 4px; }
.recent-row:hover { opacity: 0.7; }
.recent-row .what {
  font-family: var(--serif);
  font-style: italic;
  font-size: 12.5px;
  color: var(--hint);
  margin-right: 6px;
}
.recent-row .label {
  font-family: var(--serif);
  font-size: 15px;
  font-weight: 400;
}
.recent-row .when {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--hint);
  letter-spacing: 0.04em;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Horizontal swipe carousel of square tiles. Card padding is bled
 * full-bleed so tiles can scroll under the card edge while remaining
 * touch-friendly. scroll-snap-x landing on each tile. */
.recent-carousel {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-padding-left: 16px;
  padding: 4px 16px 4px;
  margin: 0 -16px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.recent-carousel::-webkit-scrollbar { display: none; }
.rcard {
  flex: 0 0 140px;
  height: 140px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card-soft);
  color: inherit;
  text-decoration: none;
  transition: transform 140ms ease, background 140ms ease;
  position: relative;
}
.rcard:active { transform: scale(0.97); background: var(--chip); }
.rcard-scan { padding: 0; }
.rcard-body {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 12px;
  height: 100%;
  width: 100%;
  color: inherit;
  text-decoration: none;
}
.rcard-x {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  appearance: none;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--hint);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 120ms ease, background 120ms ease, color 120ms ease;
}
.rcard-x:hover { opacity: 1; background: var(--chip); color: var(--bad); }
.rcard-icon { font-size: 22px; line-height: 1; }
.rcard-kind {
  font-family: var(--sans);
  font-size: 9.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--hint);
}
.rcard-label {
  font-family: var(--serif);
  font-size: 15px;
  line-height: 1.15;
  font-weight: 400;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.rcard-when {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--hint);
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Trending tiles — smaller than rcard, 4-ish fit per phone width. Same
 * scroll-snap pattern. Color-coded percentage badge. */
.trend-carousel {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-padding-left: 16px;
  padding: 4px 16px;
  margin: 0 -16px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.trend-carousel::-webkit-scrollbar { display: none; }
.tcard {
  flex: 0 0 96px;
  height: 96px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card-soft);
  color: inherit;
  text-decoration: none;
  transition: transform 140ms ease, background 140ms ease;
}
.tcard:active { transform: scale(0.96); background: var(--chip); }
.tcard-sym {
  font-family: var(--serif);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tcard-price {
  font-family: var(--serif);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tcard-chg {
  font-family: var(--mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: var(--hint);
}
.tcard-chg.pct-up { color: var(--ok); }
.tcard-chg.pct-dn { color: var(--bad); }

/* ===== KEY/VALUE GRID (Settings, ID) ====================== */
.kv {
  display: flex; flex-direction: column;
}
.kv-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px;
  padding: 12px 0;
  border-top: 1px solid var(--line);
}
.kv-row:first-child { border-top: 0; padding-top: 4px; }
.kv-row:last-child { padding-bottom: 4px; }
.kv-key {
  font-family: var(--sans);
  font-size: 10.5px; font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--hint);
  flex: none;
}
.kv-val {
  font-family: var(--serif);
  font-size: 15px;
  color: var(--fg);
  text-align: right;
  word-break: break-word;
  display: inline-flex; align-items: baseline; gap: 8px;
}
.kv-val.mono {
  font-family: var(--mono);
  font-size: 12px;
  word-break: break-all;
  max-width: 240px;
}
.kv-sub { color: var(--hint); font-style: italic; font-size: 12px; }

.copy-btn {
  appearance: none;
  border: 1px solid var(--line);
  background: transparent; color: var(--fg);
  border-radius: 4px;
  padding: 2px 8px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 120ms ease;
}
.copy-btn:hover { background: var(--chip); }

/* Settings — radio rows + action buttons */
.opt-row {
  appearance: none;
  width: 100%;
  display: grid;
  grid-template-columns: 22px 1fr;
  align-items: start;
  gap: 12px;
  padding: 12px 4px;
  border: 0;
  border-top: 1px solid var(--line);
  background: transparent;
  color: var(--fg);
  cursor: pointer;
  text-align: left;
  transition: background 120ms ease;
}
.opt-row:first-child { border-top: 0; padding-top: 4px; }
.opt-row:last-child { padding-bottom: 4px; }
.opt-row:hover { background: var(--chip); }
.opt-radio {
  font-family: var(--mono);
  font-size: 16px;
  line-height: 1.2;
  color: var(--hint);
  text-align: center;
}
.opt-row.opt-active .opt-radio { color: var(--fg); }
.opt-text { display: flex; flex-direction: column; gap: 2px; }
.opt-label {
  font-family: var(--serif);
  font-size: 15px;
  font-weight: 400;
}
.opt-row.opt-active .opt-label { font-weight: 500; }
.opt-sub {
  font-family: var(--serif);
  font-style: italic;
  font-size: 12.5px;
  color: var(--hint);
}

.action-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 12px;
}
.action-row .btn { flex: 1; min-width: 120px; }
.btn-danger {
  border-color: var(--bad);
  color: var(--bad);
}
.btn-danger:hover { background: rgba(179, 38, 30, 0.08); }
@media (prefers-color-scheme: dark) {
  .btn-danger:hover { background: rgba(248, 113, 113, 0.12); }
}

/* ===== WATCHLIST ROW ======================================
   Card-per-watch. Top line: glyph + sym + price/chg on the
   right. Sub line: address + balance/MC + "watching since" /
   "last alert" hint. Action cluster on the right: tap-to-scan
   primary, pin toggle, unwatch. Single tap zone for the row;
   button cluster is on a separate z-stack so the row click
   doesn't double-fire. */
.watch-list { display: flex; flex-direction: column; }
.watch-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 14px 0;
  border-top: 1px solid var(--line);
  color: inherit;
  transition: opacity 120ms ease;
}
.watch-row:first-child { border-top: 0; padding-top: 4px; }
.watch-row:last-child  { padding-bottom: 4px; }
.watch-row-body {
  display: flex; flex-direction: column; gap: 4px; min-width: 0;
  cursor: pointer;
}
.watch-row-body:hover { opacity: 0.7; }
.watch-row-head {
  display: flex; align-items: center; gap: 10px; min-width: 0;
  font-family: var(--serif);
  font-size: 15px;
}
.watch-row-glyph { font-size: 14px; }
.watch-row-sym  { font-weight: 500; }
.watch-row-addr {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--hint);
  white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.watch-row-meta {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  font-family: var(--serif);
  font-size: 12.5px;
  color: var(--hint);
}
.watch-row-price {
  font-variant-numeric: tabular-nums;
  color: var(--fg);
}
.watch-row-chg {
  font-family: var(--mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: var(--hint);
}
.watch-row-chg.pct-up { color: var(--ok); }
.watch-row-chg.pct-dn { color: var(--bad); }
.watch-row-sub {
  font-family: var(--serif);
  font-style: italic;
  font-size: 11.5px;
  color: var(--hint);
}
.watch-row-actions {
  display: flex; gap: 6px;
  flex: 0 0 auto;
}
.watch-row-actions .icon-btn {
  appearance: none;
  width: 36px; height: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--fg);
  border-radius: 6px;
  font-size: 14px; line-height: 1;
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease;
}
.watch-row-actions .icon-btn:hover { background: var(--chip); }
.watch-row-actions .icon-btn.is-active {
  border-color: var(--fg);
  color: var(--fg);
}
.watch-row-actions .icon-btn.is-danger:hover {
  border-color: var(--bad);
  color: var(--bad);
  background: transparent;
}
.watch-row.is-removing { opacity: 0.35; pointer-events: none; }

/* ===== TOKEN AVATAR + SOCIALS =============================
   Single source of truth for jetton avatars used across tiles
   (Pinned, Discovery, Watchlist, Recent) + the Scanner card.
   Falls back to a soft circle glyph via JS when image loading
   errors (third-party CDNs go down). Avatars are square with
   a subtle radius — distinct from suite product marks (which
   are full-bleed PNG with no border).

   Sizes:
     .token-avatar.sm  → 18px (recent / inline row hint)
     .token-avatar.md  → 28px (pinned / discovery tile)
     .token-avatar.lg  → 36px (watchlist row)
     .token-avatar.xl  → 56px (scanner hero) */
.token-avatar {
  display: inline-block;
  flex: 0 0 auto;
  border-radius: 6px;
  background: var(--chip);
  object-fit: cover;
  vertical-align: middle;
  border: 1px solid var(--line);
}
.token-avatar.sm { width: 18px; height: 18px; border-radius: 4px; }
.token-avatar.md { width: 28px; height: 28px; }
.token-avatar.lg { width: 36px; height: 36px; }
.token-avatar.xl { width: 56px; height: 56px; border-radius: 10px; }
/* Glyph fallback — same dimensions, centered initial(s). The data-fallback
 * attr carries the symbol or short address so we can swap text-in-place
 * when the <img> 404s. */
.token-avatar.is-fallback {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--serif);
  font-weight: 500;
  color: var(--hint);
  background: var(--chip);
  line-height: 1;
  letter-spacing: 0;
  text-transform: uppercase;
  user-select: none;
}
.token-avatar.is-fallback.sm { font-size: 9px; }
.token-avatar.is-fallback.md { font-size: 11px; }
.token-avatar.is-fallback.lg { font-size: 13px; }
.token-avatar.is-fallback.xl { font-size: 18px; }

/* Tile variants — avatar in col 1 spanning all rows; right column stacks
 * symbol (top), price (middle), chg (bottom). Earlier layout put price + chg
 * in the same grid cell with `justify-self: end` for chg — at typical tile
 * widths (~60px usable second column) the labels overlapped, rendering as
 * "$1₀0.1%" with digits stacked. Three rows guarantee clean separation. */
.tcard.has-avatar {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr);
  grid-template-rows: auto auto auto;
  gap: 2px 8px;
  align-items: center;
}
.tcard.has-avatar .token-avatar { grid-row: 1 / span 3; align-self: start; }
.tcard.has-avatar .tcard-sym   { grid-column: 2; grid-row: 1; }
.tcard.has-avatar .tcard-price { grid-column: 2; grid-row: 2; }
.tcard.has-avatar .tcard-chg   { grid-column: 2; grid-row: 3; }

/* ===== WATCHING HERO + CHIPS ==============================
   Home Watching section. Previously rendered as a horizontal
   carousel of 96px tiles — clipped tickers ("USDT" → "USDɸ"),
   truncated prices ("$1.0…"), and wasted ~70% of the card
   width when the user only watched one token. New layout:
   first item is a hero card (large avatar + price + 24h
   sparkline), additional items are small chips below. */
.watch-hero {
  display: grid;
  grid-template-columns: 48px 1fr auto;
  grid-template-rows: auto auto auto;
  column-gap: 14px;
  row-gap: 2px;
  align-items: center;
  padding: 6px 2px 8px;
  color: inherit;
  border-radius: 8px;
  transition: background 120ms ease;
}
.watch-hero:hover { background: var(--chip); }
.watch-hero .token-avatar { grid-column: 1; grid-row: 1 / span 3; width: 48px; height: 48px; border-radius: 8px; align-self: center; }
.watch-hero-sym {
  grid-column: 2; grid-row: 1;
  font-family: var(--serif);
  font-size: 18px;
  font-weight: 500;
  letter-spacing: 0.02em;
  line-height: 1.1;
}
.watch-hero-name {
  grid-column: 2; grid-row: 2;
  font-family: var(--serif);
  font-style: italic;
  font-size: 12.5px;
  color: var(--hint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.watch-hero-spark {
  grid-column: 2; grid-row: 3;
  margin-top: 4px;
  height: 22px;
  width: 100%;
  display: block;
  /* SVG inside; flex inline-grid renders the polyline at full container width */
  overflow: hidden;
}
.watch-hero-spark svg { width: 100%; height: 100%; display: block; }
.watch-hero-price {
  grid-column: 3; grid-row: 1;
  font-family: var(--serif);
  font-size: 18px;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
.watch-hero-chg {
  grid-column: 3; grid-row: 2;
  font-family: var(--mono);
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  text-align: right;
  color: var(--hint);
}
.watch-hero-chg.pct-up { color: var(--ok); }
.watch-hero-chg.pct-dn { color: var(--bad); }
.watch-hero-spark-empty {
  /* Soft baseline placeholder when no series came back (no pool / cold-cache).
     Keeps the hero shape stable so the layout doesn't jump when series lands. */
  border-top: 1px dashed var(--line);
}

/* Chip row — additional watched tokens after the hero, plus the entire
 * Recent feed. Horizontal wrap, dense, tap-targets. */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding-top: 10px;
  margin-top: 8px;
  border-top: 1px solid var(--line);
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px 5px 6px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--serif);
  font-size: 12.5px;
  background: transparent;
  color: var(--fg);
  text-decoration: none;
  transition: background 120ms ease, border-color 120ms ease;
  max-width: 100%;
  white-space: nowrap;
}
.chip:hover { background: var(--chip); }
.chip .token-avatar { width: 18px; height: 18px; border-radius: 4px; flex: none; }
.chip-glyph {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  font-size: 13px; line-height: 1;
  flex: none;
}
.chip-label {
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 12ch;
}
.chip-meta {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--hint);
  letter-spacing: 0.02em;
}
.chip-meta.pct-up { color: var(--ok); }
.chip-meta.pct-dn { color: var(--bad); }
.chip-x {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--hint);
  font-size: 13px;
  line-height: 1;
  padding: 0 2px 0 4px;
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 120ms ease, color 120ms ease;
}
.chip-x:hover { opacity: 1; color: var(--bad); }

/* ===== DISCOVERY DENSE ROW ================================
   Replaces an earlier 96px tcard carousel. One row per jetton:
   avatar + ticker on the left, sparkline in the middle taking
   the slack, price + chg right-aligned. All ~10 visible at once
   on a typical mobile viewport, no truncation. */
.discovery-row {
  display: grid;
  grid-template-columns: 28px minmax(48px, auto) 1fr auto auto;
  align-items: center;
  column-gap: 10px;
  padding: 9px 4px;
  border-top: 1px solid var(--line);
  color: inherit;
  text-decoration: none;
  transition: background 120ms ease;
}
.discovery-row:first-child { border-top: 0; padding-top: 4px; }
.discovery-row:last-child { padding-bottom: 4px; }
.discovery-row:hover { background: var(--chip); }
.discovery-row .token-avatar { grid-column: 1; }
.discovery-sym {
  grid-column: 2;
  font-family: var(--serif);
  font-size: 14.5px;
  font-weight: 500;
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 90px;
}
.discovery-spark {
  grid-column: 3;
  display: block;
  height: 18px;
  min-width: 32px;
  overflow: hidden;
  /* The spark takes the slack column so the row visually telegraphs
   * direction even before the user reads the % below. */
}
.discovery-spark svg { width: 100%; height: 100%; display: block; }
.discovery-price {
  grid-column: 4;
  font-family: var(--serif);
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}
.discovery-chg {
  grid-column: 5;
  font-family: var(--mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  text-align: right;
  min-width: 56px;
  color: var(--hint);
}
.discovery-chg.pct-up { color: var(--ok); }
.discovery-chg.pct-dn { color: var(--bad); }

/* ===== COLLAPSIBLE + REORDERABLE CARDS ====================
   The Home view cards (Watching, Discovery, Recent, Products)
   share two ergonomic affordances:
     1. Tap the title row to collapse — hides everything except
        the title row itself. State persists in localStorage so
        a user who only cares about Watching can quietly hide
        the rest and never re-collapse on each open.
     2. Long-press the title row to enter reorder mode (a slight
        scale + outline highlight), then drag the card up or down
        and release to commit. Order persists in localStorage so
        people who actually use Discovery first can put it first. */
.card-collapsible .card-title-row {
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  /* Inline `margin-left:auto` on the badge in HTML pushes it to the right —
   * the original justify-content: space-between is overridden here so chevron
   * + title can sit together on the left. */
}
.card-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--hint);
  opacity: 0.7;
  transition: transform 160ms ease, opacity 120ms ease;
  flex: none;
}
.card-collapsible.is-collapsed .card-chevron { transform: rotate(-90deg); }
.card-collapsible:hover .card-chevron { opacity: 1; }
/* Collapse all card children except the title row when collapsed. The
 * title row stays clickable to expand. */
.card-collapsible.is-collapsed > *:not(.card-title-row) { display: none; }
.card-collapsible.is-collapsed { padding-bottom: 12px; }

/* Drag-reorder mode */
.card-draggable.is-drag-prep { transition: transform 120ms ease, box-shadow 120ms ease; }
.card-draggable.is-dragging {
  /* Lifted off the page during drag — soft scale + ring so the user
   * sees the card has been picked up. translate3d set inline by JS. */
  transform: scale(1.01);
  z-index: 100;
  box-shadow: 0 8px 28px rgba(0,0,0,0.18);
  cursor: grabbing;
  position: relative;
  transition: box-shadow 120ms ease;
}
.card-draggable.is-drop-target {
  /* Visual hint that the drop will land here */
  background: var(--chip);
}
/* Reorder-mode placeholder — the card stays in the doc, but we render a
 * thin tinted ghost where it'll land on release. Updated in JS via
 * inline transform. */
.card-drag-ghost {
  background: var(--chip);
  border: 1px dashed var(--line);
  border-radius: 8px;
  margin: 0 0 16px;
  transition: height 140ms ease;
}

/* Scanner hero — promote avatar to a large square on the left, keep the
 * symbol/name/address column legible. */
.hero-head.has-avatar {
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 12px;
  align-items: start;
}

/* Socials button row inside the Scanner card. Same .btn chrome as the
 * trade/explorer rows but with a coloured glyph so each platform is
 * scannable at a glance. */
.socials-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(76px, 1fr));
  gap: 6px;
  margin-top: 6px;
}
.socials-row .btn.social-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
  font-size: 12px;
}
.socials-row .btn.social-btn .social-glyph { font-size: 13px; }

/* ===== SCANNER ============================================
   Scanner views render inside the launcher (one mini-app slot,
   no host hops). Search card → hero header → kv stats → list
   rows → button grids. Shares card chrome above. */
/* Scanner scan box — a tappable bar that opens the shared CI.search modal (same
 * picker as the Swap token switcher + appbar ⌕). Replaces the old inline form so
 * search looks/behaves the same across products. */
.scan-search-bar {
  appearance: none; width: 100%;
  display: flex; align-items: center; gap: 10px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--hint);
  border-radius: 12px;
  padding: 13px 14px;
  font-family: var(--sans);
  font-size: 14px;
  cursor: pointer;
  text-align: left;
  transition: border-color 120ms ease, transform 80ms ease;
}
.scan-search-bar:hover { border-color: var(--fg); }
.scan-search-bar:active { transform: scale(0.995); }
.scan-search-ico { flex: none; font-size: 16px; color: var(--hint); }
.scan-search-txt {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.scan-search-txt.scan-search-on { color: var(--fg); font-family: var(--mono); font-size: 13px; }

.search-card {
  display: flex; flex-direction: column; gap: 10px;
  padding: 12px;
}
.search-label {
  font-family: var(--serif);
  font-style: italic;
  font-size: 12.5px;
  color: var(--hint);
  padding: 0 4px;
}
.search-row { display: flex; gap: 6px; }
.search-input {
  flex: 1;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--fg);
  border-radius: 6px;
  padding: 10px 12px;
  font-family: var(--mono);
  font-size: 13px;
  outline: none;
  transition: border-color 120ms ease;
  min-width: 0;
}
.search-input:focus { border-color: var(--fg); }
.search-go {
  appearance: none;
  border: 1px solid var(--fg);
  background: var(--fg);
  color: var(--bg);
  border-radius: 6px;
  padding: 0 16px;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transition: opacity 120ms ease;
  flex: none;
}
.search-go:hover { opacity: 0.85; }

.search-paste {
  appearance: none;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--fg);
  border-radius: 6px;
  padding: 0 12px;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.04em;
  transition: background 120ms ease;
  flex: none;
}
.search-paste:hover { background: var(--chip); }

.quick-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 0 4px 2px;
}
.quick {
  appearance: none;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--fg);
  border-radius: 999px;
  padding: 5px 12px;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background 120ms ease;
}
.quick:hover { background: var(--chip); }

.hero-card { padding: 16px; }
.hero-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 12px;
  margin-bottom: 10px;
}
.hero-name {
  font-family: var(--serif);
  font-size: 22px;
  font-weight: 400;
  letter-spacing: 0.005em;
  line-height: 1.15;
}
.hero-sub {
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  color: var(--hint);
  margin-top: 2px;
}
.hero-addr {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--fg);
  opacity: 0.75;
  word-break: break-all;
  margin-top: 6px;
}
.hero-num {
  font-family: var(--serif);
  font-size: 30px;
  font-weight: 400;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  margin-top: 14px;
  display: flex; align-items: baseline; gap: 10px;
}
.hero-num .sub {
  font-family: var(--serif);
  font-style: italic;
  font-size: 13.5px;
  font-weight: 400;
  color: var(--hint);
}
.hero-sub-inline {
  font-family: var(--serif);
  font-style: italic;
  font-size: 14.5px;
  font-weight: 400;
  color: var(--hint);
  margin-left: 4px;
}

/* Badge strip — chain · age · mintable, dot-separated. Matches the bot
 * card's compact tag row. */
.badge-strip {
  margin-top: 8px;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--hint);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  letter-spacing: 0.02em;
}
.badge-strip .badge-sep { color: var(--fg); opacity: 0.8; }
.badge-strip .badge-dot { color: var(--hint); opacity: 0.5; }

/* Tree-style stat + security blocks — mirror the bot's ├ / └ rendering. */
.block { margin-top: 16px; }
.block-head {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--fg);
  margin-bottom: 8px;
}
.tree { display: flex; flex-direction: column; }
.tree-row {
  display: grid;
  grid-template-columns: 14px 50px 1fr;
  align-items: baseline;
  font-family: var(--mono);
  font-size: 13px;
  padding: 3px 0;
  line-height: 1.4;
}
.tree-c { color: var(--hint); opacity: 0.7; }
.tree-k { color: var(--hint); text-transform: uppercase; font-size: 11px; letter-spacing: 0.06em; }
.tree-v { color: var(--fg); font-variant-numeric: tabular-nums; }
.pct-up { color: var(--ok); }
.pct-dn { color: var(--bad); }
.tree em { font-family: var(--serif); font-style: italic; color: var(--hint); }

.supply-line {
  margin-top: 14px;
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  color: var(--hint);
}

/* 5-column compact button grid for the DS/GT/DT/EXP/Xs link strip. */
.btn-grid.five {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 6px;
}
.btn.xs {
  padding: 8px 4px;
  font-size: 11.5px;
  letter-spacing: 0.08em;
}
.pill-row { display: flex; flex-wrap: wrap; gap: 6px; }
.hero-change {
  display: inline-flex;
  margin-left: 10px;
  align-self: center;
}

/* Live chart inside jetton hero card. Default min-height holds the
 * placeholder/skeleton state; when the GeckoTerminal iframe loads it
 * expands to its full height. */
.chart-wrap {
  margin: 14px -4px 4px;
  min-height: 120px;
  position: relative;
}
.chart-frame {
  width: 100%;
  height: 320px;
  border: 0;
  border-radius: 8px;
  background: var(--soft);
  display: block;
  color-scheme: light dark;
}
.chart-wrap.chart-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed var(--line);
  border-radius: 6px;
  height: 80px;
  min-height: 80px;
  margin: 14px 0 4px;
}
.chart-empty-msg {
  font-family: var(--serif);
  font-style: italic;
  font-size: 13px;
  color: var(--hint);
}
/* CI.chart (KLineChart) mount states — applies wherever CI.chart mounts
 * (#term-chart on Swap; .chart-wrap on Scanner). KLineChart fills the box with a
 * canvas, so the overlay only shows when we have no data to draw. */
.ci-chart-empty { position: relative; }
.ci-chart-empty::after {
  content: "No chart data yet";
  position: absolute; inset: 0;
  display: grid; place-items: center;
  color: var(--hint); font-size: 12px; pointer-events: none;
}
.chart-skel {
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--soft), transparent);
  background-size: 200% 100%;
  animation: chart-shimmer 1.4s infinite linear;
  border-radius: 4px;
  opacity: 0.6;
}
@keyframes chart-shimmer {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/* Compact 2x2 stat block inside hero — replaces the separate Token stats
 * card for a much tighter scan-and-go layout. */
.stat-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 18px;
  margin: 14px 0 12px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}
.stat-k {
  font-family: var(--sans);
  font-size: 10px; font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--hint);
  margin-bottom: 3px;
}
.stat-v {
  font-family: var(--serif);
  font-size: 15px;
  font-variant-numeric: tabular-nums;
}

.badge.ok   { background: transparent; border: 1px solid var(--ok);   color: var(--ok); }
.badge.warn { background: transparent; border: 1px solid var(--warn); color: var(--warn); }
.badge.bad  { background: transparent; border: 1px solid var(--bad);  color: var(--bad); }

.row-list { display: flex; flex-direction: column; }
.row {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px;
  padding: 12px 0;
  border-top: 1px solid var(--line);
}
.row:first-child { border-top: 0; padding-top: 4px; }
.row:last-child { padding-bottom: 4px; }
.row-l { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.row-r { display: flex; flex-direction: column; gap: 2px; align-items: flex-end; text-align: right; }
.row-name {
  font-family: var(--serif);
  font-size: 15px;
  font-weight: 400;
}
.row-meta {
  font-family: var(--serif);
  font-style: italic;
  font-size: 12px;
  color: var(--hint);
}
.row-num {
  font-family: var(--serif);
  font-size: 14.5px;
  font-variant-numeric: tabular-nums;
}
.row-num.muted { color: var(--hint); }
.row-mono {
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--hint);
  letter-spacing: 0.02em;
}
.row.aborted { opacity: 0.5; }
.row .arrow {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--hint);
  margin-right: 4px;
}

.btn-grid {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: 6px;
}
.btn-grid.three { grid-template-columns: 1fr 1fr 1fr; }
.btn-grid.four { grid-template-columns: 1fr 1fr 1fr 1fr; }
.btn {
  appearance: none;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--fg);
  border-radius: 6px;
  padding: 11px 12px;
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-align: center;
  cursor: pointer;
  text-decoration: none;
  transition: background 120ms ease;
}
.btn:hover { background: var(--chip); }
.btn.primary {
  background: var(--fg);
  color: var(--bg);
  border-color: var(--fg);
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.btn.primary:hover { opacity: 0.85; background: var(--fg); }

/* ===== SCANNER DETAIL — ACTION CARD (P2) ====================
   In-app actions (Swap / Watch / Bridge) are prominent real controls; external
   destinations are a clearly-secondary group, each marked as leaving the app
   (the ↗ is CSS-generated). Replaces the old DS/GT/DT/EXP/Xs abbreviation grid. */
.scan-actions { display: flex; flex-direction: column; gap: 10px; }
.scan-swap { width: 100%; padding: 13px 12px; }
.scan-main { display: grid; grid-template-columns: 1fr 1fr auto; gap: 8px; }
.scan-refresh { padding-left: 15px; padding-right: 15px; }
.scan-ext { margin-top: 2px; padding-top: 12px; border-top: 1px solid var(--line); }
.scan-ext-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--hint); margin-bottom: 8px;
}
.scan-ext-links { display: flex; flex-wrap: wrap; gap: 6px; }
.scan-ext-link {
  display: inline-flex; align-items: center;
  border: 1px solid var(--line); border-radius: 999px;
  padding: 6px 12px; font-size: 12.5px; color: var(--fg);
  text-decoration: none; background: transparent;
}
.scan-ext-link::after { content: "↗"; margin-left: 5px; font-size: 11px; color: var(--hint); }
.scan-ext-link:hover { background: var(--card-soft); border-color: var(--accent, #6aa6ff); }

/* ===== SCANNER DISCOVER FEED (P3) ===========================
   Ranked, sortable token screener on the empty Scanner view. Columns disclose
   progressively: mobile = Token/Price/24h/buy; Vol ≥560px; MC ≥760px. The
   visible-child count must match the grid template at each breakpoint. */
.discover-card .card-title-row { margin-bottom: 4px; }
.disc-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 6px; }
.disc-tab {
  appearance: none; border: 1px solid var(--line); background: transparent;
  color: var(--hint); border-radius: 999px; padding: 5px 13px;
  font-size: 12.5px; font-weight: 600; cursor: pointer;
}
.disc-tab.disc-tab-on { background: var(--fg); color: var(--bg); border-color: var(--fg); }

.disc-head, .disc-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto;
  gap: 10px; align-items: center;
}
.disc-head {
  padding: 4px 6px; font-size: 10.5px; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--hint); border-bottom: 1px solid var(--line);
}
.disc-list { display: flex; flex-direction: column; }
.disc-row { padding: 9px 6px; border-top: 1px solid var(--line); }
.disc-row:first-child { border-top: 0; }
.disc-tok { display: flex; align-items: center; gap: 8px; min-width: 0; text-decoration: none; color: var(--fg); }
.disc-rank { flex: 0 0 auto; width: 18px; text-align: right; font-size: 11px; color: var(--hint); font-variant-numeric: tabular-nums; }
.disc-tok-txt { display: flex; flex-direction: column; min-width: 0; }
.disc-sym { font-weight: 600; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.disc-name { font-size: 11px; color: var(--hint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.disc-c { text-align: right; font-size: 13px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.disc-chg.pct-up { color: var(--ok); }
.disc-chg.pct-dn { color: var(--bad); }
.disc-vol, .disc-mc { display: none; }
.disc-buy {
  appearance: none; border: 1px solid var(--line); background: transparent;
  color: var(--fg); border-radius: 8px; width: 34px; height: 30px;
  font-size: 14px; cursor: pointer; justify-self: end;
}
.disc-buy:hover { background: var(--card-soft); border-color: var(--accent, #6aa6ff); }
@media (min-width: 560px) {
  .disc-head, .disc-row { grid-template-columns: minmax(0, 1fr) auto auto auto auto; }
  .disc-vol { display: block; }
}
@media (min-width: 760px) {
  .disc-head, .disc-row { grid-template-columns: minmax(0, 1fr) 96px 72px 92px 104px 44px; }
  .disc-mc { display: block; }
}

/* ===== ID — ACCOUNT / PORTFOLIO / SOCIAL HUB (P5) ===========
   The ID view is the identity hub: profile header + stat strip, wallet,
   portfolio (holdings), and collapsible Telegram details. */
.id-hub { display: flex; flex-direction: column; gap: 16px; }
.id-back { align-self: flex-start; color: var(--hint); font-size: 13px; text-decoration: none; margin-bottom: -4px; }
.id-back:hover { color: var(--fg); }
.id-profile { display: flex; flex-direction: column; gap: 14px; }
.id-head { display: flex; align-items: center; gap: 12px; }
.id-avatar { width: 52px; height: 52px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.id-avatar-fb {
  display: flex; align-items: center; justify-content: center;
  background: var(--chip); color: var(--fg); font-size: 20px; font-weight: 600;
}
.id-id { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.id-name { font-size: 17px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.id-premium { color: var(--accent, #6aa6ff); font-size: 14px; }
.id-handle { font-size: 13px; color: var(--hint); }
.id-share { flex: 0 0 auto; padding: 8px 16px; }
.id-stats { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.id-stat {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 10px 6px; border: 1px solid var(--line); border-radius: 10px;
}
.id-stat-v { font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; }
.id-stat-k { font-size: 10.5px; color: var(--hint); text-transform: uppercase; letter-spacing: 0.04em; }
.id-manage { margin-left: auto; padding: 6px 14px; }
.id-meta summary { cursor: pointer; font-size: 13px; color: var(--hint); list-style: revert; }
.id-stat-v.id-up { color: var(--ok); }
.id-stat-v.id-dn { color: var(--bad); }
/* Opt-in public profile toggle + share link. */
.id-public { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding-top: 4px; }
.id-public-k { font-size: 13px; color: var(--hint); }
.id-public-link { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.id-hint { font-size: 12px; color: var(--hint); }
/* Native multi-wallet: add row + per-wallet rows with value + remove. */
.id-addwallet { display: flex; gap: 6px; margin-bottom: 10px; }
.id-addwallet .text-input { flex: 1; min-width: 0; }
.id-wallet-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-top: 1px solid var(--line); }
.id-wallet-row:first-child { border-top: 0; }
.id-wallet-main { display: flex; flex-direction: column; min-width: 0; flex: 1; text-decoration: none; color: var(--fg); }
.id-wallet-label { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.id-wallet-conn { font-size: 10px; font-weight: 600; color: var(--accent, #6aa6ff); text-transform: uppercase; letter-spacing: 0.04em; }
.id-wallet-addr { font-size: 11px; color: var(--hint); font-family: var(--mono, monospace); }
.id-wallet-val { font-size: 13px; font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.id-wallet-x { appearance: none; border: 0; background: transparent; color: var(--hint); cursor: pointer; font-size: 13px; padding: 4px 6px; flex: 0 0 auto; }
.id-wallet-x:hover { color: var(--bad); }

/* Skeleton loading rows */
.skel {
  background: transparent;
  border-top: 1px solid var(--line);
  padding: 16px 0;
}
.skel:first-child { border-top: 0; padding-top: 4px; }
.skel-row {
  height: 12px;
  background: var(--chip);
  border-radius: 3px;
  position: relative; overflow: hidden;
}
.skel-row::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--soft), transparent);
  animation: shimmer 1.4s infinite linear;
}
.skel-row.w50 { width: 50%; }
.skel-row.w30 { width: 30%; margin-top: 8px; }
.skel-row.w100 { width: 100%; margin-top: 14px; height: 38px; border-radius: 6px; }
@keyframes shimmer {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

/* ===== TAB BAR ============================================ */
.tabbar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 50;
  display: flex; justify-content: space-around;
  padding: 8px 8px calc(8px + env(safe-area-inset-bottom));
  background: var(--bg);
  border-top: 1px solid var(--line);
}
.tab {
  appearance: none; border: 0; background: transparent;
  color: var(--hint);
  flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 6px 4px;
  border-radius: 6px;
  font-family: var(--sans);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.tab-i { font-size: 18px; line-height: 1; opacity: 0.8; }
.tab-l { font-size: 10px; }
.tab-active { color: var(--fg); }
.tab-active .tab-i { opacity: 1; }

/* Mini-app shell hides splash markup */
html[data-splash="0"] .splash { display: none; }

/* Bridge view: bridge.js's internal sub-nav (.bridge-subnav) renders as a
 * top segmented strip *inside* the bridge view, not a second fixed bottom
 * tabbar. The launcher's main tabbar at the page bottom is the only fixed
 * navigation in the shell. */
#view-bridge .bridge-subnav.tabbar {
  position: static;
  display: flex;
  justify-content: space-around;
  padding: 0 0 10px;
  background: transparent;
  border-top: 0;
  border-bottom: 1px solid var(--line);
  margin: -6px -2px 12px;
}
#view-bridge .bridge-subnav .tab { padding-top: 4px; }
#view-bridge .bridge-pill-row {
  display: flex;
  justify-content: flex-end;
  margin: 0 0 8px;
}

/* ===== FOLD CHROME — tablet/desktop sidebar (S2, #63) ========
   CI.shell publishes the viewport fold to html[data-fold]. At tablet width
   (>=768) and up — the wide canvas, e.g. Telegram Desktop fullscreen or a
   resized browser — the bottom Home/Settings tabbar becomes a LEFT sidebar
   rail (iPadOS/macOS), and the shell shifts right to clear it. Everything here
   is gated under [data-fold="tablet"|"desktop"] AND [data-splash="0"] (the
   shell is only shown then), so phone (<768, which is every in-Telegram-mobile
   session) and the browser splash render byte-identically to before. */
/* TABLET only — desktop gets a bottom dock + window manager (below). */
html[data-fold="tablet"][data-splash="0"] body { --ci-rail: 76px; }

/* The fixed rail sits in the gutter; body padding shifts the sticky appbar +
   centered .content right of it (fixed positioning ignores the body padding,
   so the rail itself stays flush left). */
html[data-fold="tablet"][data-splash="0"] body { padding-left: var(--ci-rail); }

html[data-fold="tablet"][data-splash="0"] .tabbar {
  flex-direction: column;
  justify-content: flex-start;
  top: 0; bottom: 0; left: 0; right: auto;
  width: var(--ci-rail);
  padding: 14px 8px calc(14px + env(safe-area-inset-bottom));
  border-top: 0;
  border-right: 1px solid var(--line);
  gap: 4px;
}
html[data-fold="tablet"][data-splash="0"] .tabbar .tab {
  flex: 0 0 auto;
  padding: 10px 4px;
}

/* ===== OPEN-BESIDE SPLIT — tablet/desktop 2-pane (S2, #63) ===
   CI.shell sets body[data-split] when a companion intent opens a second pane
   (the Scanner|Swap loop). .content becomes two columns: the primary surface
   (.pane-primary = the .view-active section) beside the secondary pane
   (.pane-secondary). Only on tablet/desktop folds (the shell collapses the
   split on phone). The html[data-fold] body[data-split] .content specificity
   intentionally beats bridge.css's body[data-current-view] .content width. */
html[data-fold="tablet"] body[data-split="1"] .content,
html[data-fold="desktop"] body[data-split="1"] .content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 18px;
  max-width: min(100%, 1400px);
  align-items: start;
}
body[data-split="1"] .pane-primary { grid-column: 1; min-width: 0; }
body[data-split="1"] .pane-secondary {
  display: flex; /* override .view{display:none} for the non-active pane */
  grid-column: 2; min-width: 0; position: relative;
}
/* Each pane is ~half a wide viewport, but the legacy wide layouts key off the
   VIEWPORT media query (not pane width), so the .view-active primary would go
   2-col inside a half pane. Force the loop apps into single-column form in a
   split. (Container-query-perfect per-app pane polish is S4.) */
body[data-split="1"] #view-scanner.view-active:not(.surface-wide) #scanner-result { display: block; }
body[data-split="1"] #view-trade.view-active:not(.surface-wide) {
  display: flex; flex-direction: column;
}
/* Pane close affordance (shell-injected button). */
.pane-close {
  position: absolute; top: 6px; right: 6px; z-index: 6;
  appearance: none; border: 1px solid var(--line); background: var(--bg);
  color: var(--hint); width: 28px; height: 28px; border-radius: 7px;
  font-size: 18px; line-height: 1; cursor: pointer;
}
.pane-close:hover { color: var(--fg); background: var(--card-soft); }

/* ===== DESKTOP WINDOW MANAGER (S3, #64) =====================
   On the desktop fold the shell sets body[data-desktop]; main.content becomes a
   blank window canvas, the tabbar a bottom dock, and each surface a draggable/
   resizable .ci-win frame (positioned in place, content via render()). Gated to
   the desktop fold + shell shown; tablet/phone are untouched. */
html[data-fold="desktop"][data-splash="0"] main.content {
  position: relative;
  max-width: none;
  margin: 0;
  padding: 0;
  height: calc(100dvh - 124px);
  overflow: hidden;
}

/* Slim menubar — the phone appbar (big brand mark + subtitle + back arrow) thins
   to a macOS-ish top bar: small focused-window title + status + ⌕. */
html[data-fold="desktop"][data-splash="0"] .appbar { padding: 8px 18px; }
html[data-fold="desktop"][data-splash="0"] .appbar-back { display: none; }
html[data-fold="desktop"][data-splash="0"] .brand-mark { width: 22px; height: 22px; }
html[data-fold="desktop"][data-splash="0"] #appbar-brand { font-size: 14px; letter-spacing: 0.04em; }
html[data-fold="desktop"][data-splash="0"] #appbar-sub { display: none; }
/* Bottom dock (the launcher) — the tabbar, recentred + horizontal. */
html[data-fold="desktop"][data-splash="0"] .tabbar {
  flex-direction: row;
  justify-content: center;
  gap: 6px;
  left: 50%; right: auto; bottom: 16px;
  transform: translateX(-50%);
  width: auto;
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--card);
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.45);
}
html[data-fold="desktop"][data-splash="0"] .tabbar .tab { flex: 0 0 auto; padding: 8px 12px; }
/* Dock product launchers (shell-injected). Icon over a small label. */
html[data-fold="desktop"][data-splash="0"] .ci-dock-icon {
  width: 26px; height: 26px; border-radius: 7px; object-fit: contain; display: block; margin: 0 auto 2px;
}
@media (prefers-color-scheme: dark) {
  html[data-fold="desktop"][data-splash="0"] .ci-dock-icon { filter: invert(1); }
}
/* A subtle divider between the Home/Settings nav and the product launchers. */
html[data-fold="desktop"][data-splash="0"] .tabbar .ci-dock-app:first-of-type {
  border-left: 1px solid var(--line); margin-left: 4px; padding-left: 14px;
}

/* Minimized window — hidden (lives in the dock as a running-dot). Must beat
   .ci-win's display:flex !important, hence the class + !important. */
body[data-desktop="1"] .ci-win.ci-min { display: none !important; }

/* A surface, framed as a window (.ci-win overrides .view{display:none}). */
body[data-desktop="1"] .ci-win {
  display: flex !important;
  position: absolute;
  flex-direction: column;
  gap: 14px;
  padding: 0 14px 14px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 12px 48px rgba(0, 0, 0, 0.55);
  overflow: auto;
  overscroll-behavior: contain;
}
/* Title bar spans the full window width (cancels the side padding) and sticks
   while the window scrolls; doubles as the drag handle. */
body[data-desktop="1"] .ci-win > .ci-win-bar {
  position: sticky; top: 0; z-index: 3;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 0 -14px 2px; padding: 9px 12px;
  background: var(--card);
  border-bottom: 1px solid var(--line);
  border-radius: 12px 12px 0 0;
  cursor: move; user-select: none;
}
body[data-desktop="1"] .ci-win-title {
  font-size: 13px; font-weight: 600; letter-spacing: 0.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body[data-desktop="1"] .ci-win-ctrls { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }
body[data-desktop="1"] .ci-win-min,
body[data-desktop="1"] .ci-win-close {
  appearance: none; border: 0; background: transparent; color: var(--hint);
  width: 24px; height: 24px; border-radius: 6px; font-size: 17px; line-height: 1;
  cursor: pointer; flex: 0 0 auto;
}
body[data-desktop="1"] .ci-win-min:hover,
body[data-desktop="1"] .ci-win-close:hover { color: var(--fg); background: var(--card-soft); }

/* Dock running-state (the folded-in taskbar): a dot under apps with a live
   window; brighter when focused, hollow when minimized. */
html[data-fold="desktop"][data-splash="0"] .tabbar .tab[data-go] { position: relative; }
html[data-fold="desktop"][data-splash="0"] .ci-dock-running::after,
html[data-fold="desktop"][data-splash="0"] .tab-active.tab[data-go]::after {
  content: ""; position: absolute; bottom: -1px; left: 50%; transform: translateX(-50%);
  width: 4px; height: 4px; border-radius: 50%; background: var(--hint);
}
html[data-fold="desktop"][data-splash="0"] .ci-dock-active::after { background: var(--accent, #6aa6ff); }
html[data-fold="desktop"][data-splash="0"] .ci-dock-min::after { background: transparent; box-shadow: inset 0 0 0 1px var(--hint); }
/* Resize grip, bottom-right corner. */
body[data-desktop="1"] .ci-win-resize {
  position: absolute; right: 2px; bottom: 2px; width: 16px; height: 16px;
  cursor: nwse-resize; z-index: 4;
  background: linear-gradient(135deg, transparent 50%, var(--line) 50%, var(--line) 62%, transparent 62%, transparent 74%, var(--line) 74%, var(--line) 86%, transparent 86%);
}
/* Snap-zone preview shown while dragging near an edge/corner. */
body[data-desktop="1"] .ci-snap-hint {
  position: absolute; display: none; z-index: 1; pointer-events: none;
  background: color-mix(in srgb, var(--accent, #6aa6ff) 18%, transparent);
  border: 1.5px solid var(--accent, #6aa6ff);
  border-radius: 10px;
}
/* Window content fit: the charts are sized for a full page — cap them so a
   window reads as a window, not a squeezed full view. (Deeper per-app pane/
   window-aware rendering is S4.) */
body[data-desktop="1"] .ci-win:not(.surface-wide) .term-chart,
body[data-desktop="1"] .ci-win:not(.surface-wide) .chart-wrap {
  height: 230px !important; max-height: 34vh; aspect-ratio: auto;
}
body[data-desktop="1"] .ci-win #trade-terminal { margin-bottom: 0; }
/* The discover/detail stays single-column until the window itself is wide. */
body[data-desktop="1"] .ci-win:not(.surface-wide) #scanner-result { display: block; }

/* ===== WINDOW-AWARE 2-COL (S4, #65) — .surface-wide is toggled by the shell's
   ResizeObserver when a window/pane is itself wide enough (not the viewport),
   so a maximized window or wide pane gets the full side-by-side layout. */
.view.surface-wide#view-scanner #scanner-result {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 16px; align-items: start;
}
.view.surface-wide#view-scanner #scanner-result > .scan-actions { position: sticky; top: 8px; }

/* token-lens component windows (multi-instance Scanner detail, #65). The lens
   root holds the same cards as #scanner-result, so it mirrors that layout: the
   ResizeObserver toggles .surface-wide on the WINDOW, and a maximized lens lays
   out 2-col while a narrow one stays single-column. */
body[data-desktop="1"] .ci-win-instance .ci-component.token-lens { min-width: 0; width: 100%; }
.ci-win.surface-wide .token-lens {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 16px; align-items: start;
}
.ci-win.surface-wide .token-lens > .scan-actions { position: sticky; top: 8px; }
.view.surface-wide#view-trade {
  display: grid !important; grid-template-columns: minmax(0, 1fr) 340px;
  grid-template-areas: "chart panel" "tape tape"; gap: 16px; align-items: start;
}
.view.surface-wide#view-trade #trade-terminal { grid-area: chart; margin-bottom: 0; }
.view.surface-wide#view-trade .trade-panel { grid-area: panel; }
.view.surface-wide#view-trade #trade-tape { grid-area: tape; margin-top: 0; }
.view.surface-wide#view-trade .term-chart { aspect-ratio: auto; height: 320px; max-height: none; }

/* Wallet view is hosted inside view-bridge as a sub-section (sharing the
 * TON Connect setup), but when the user lands on it from the launcher's
 * bottom Wallet tab, the Bridge swap/history sub-nav + wallet pill are
 * irrelevant clutter. Scope chrome by body[data-current-view] so those
 * Bridge-only chrome bits stay hidden until the user actually navigates
 * to Bridge proper. */
body[data-current-view="wallet"] .bridge-subnav,
body[data-current-view="wallet"] .bridge-pill-row {
  display: none !important;
}
body[data-current-view="wallet"] #view-swap,
body[data-current-view="wallet"] #view-swaps {
  display: none !important;
}
body[data-current-view="wallet"] #view-wallet {
  display: block !important;
}
/* Center the Connect Wallet card so it doesn't float in the upper-left
 * leaving 70% empty real estate. */
body[data-current-view="wallet"] .wallet-card {
  margin-top: 24px;
  text-align: center;
}
body[data-current-view="wallet"] .wallet-card .tcb-wrap {
  display: flex;
  justify-content: center;
  padding-top: 8px;
}

/* Home-foot status button — tiny pill at the bottom of Home view that
 * shows the live system-status dot and opens the public status page
 * via Telegram's WebApp browser. Click handled by app.js. */
.home-foot {
  display: flex; justify-content: center;
  padding: 12px 0 4px;
}
.home-status {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px;
  background: var(--soft);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  cursor: pointer;
}
.home-status:hover { background: var(--chip); }
.home-status-dot {
  display: inline-block;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--hint);
}
.home-status-dot.ok   { background: #4ade80; box-shadow: 0 0 6px rgba(74, 222, 128, 0.55); animation: home-status-pulse 2.4s ease-in-out infinite; }
.home-status-dot.warn { background: #f5b342; box-shadow: 0 0 6px rgba(245, 179, 66, 0.6); animation: home-status-pulse 1.6s ease-in-out infinite; }
.home-status-dot.bad  { background: #f87171; box-shadow: 0 0 6px rgba(248, 113, 113, 0.7); animation: home-status-blink 0.9s ease-in-out infinite; }
@keyframes home-status-pulse { 0%,100% { opacity: 0.55; } 50% { opacity: 1; } }
@keyframes home-status-blink { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }
.home-status-arrow { color: var(--hint); font-size: 12px; }

/* =============================================================
   BROWSER LANDING  ([data-splash="1"])
   Shown when not opened from Telegram. Black + white only —
   "inky" aesthetic from the rest of the brand. The 3D scene is
   the centrepiece: the constellation IS the hero, not chrome.
   Telegram users get data-splash="0" set before this stylesheet
   ever applies, so this whole block is skipped for them.
============================================================= */
html[data-splash="1"] {
  --land-bg:      #0a0a0a;
  --land-ink:     #fafaf7;
  --land-ink-dim: #8a8987;
  --land-line:    rgba(250, 250, 247, 0.14);
  --land-soft:    rgba(250, 250, 247, 0.05);
}
html[data-splash="1"] body {
  background: var(--land-bg);
  color: var(--land-ink);
  font-family: var(--sans);
  min-height: 100dvh;
  overflow-x: hidden;
}
html[data-splash="1"] .appbar,
html[data-splash="1"] .content,
html[data-splash="1"] .tabbar { display: none; }

.splash {
  position: relative;
  min-height: 100dvh;
  width: 100%; max-width: 880px; margin: 0 auto;
  padding: clamp(28px, 5vh, 48px) clamp(20px, 5vw, 40px) clamp(40px, 6vh, 64px);
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: clamp(28px, 5vh, 44px);
}

/* Top strip — left: bare status light (no text). Right: telegram
 * chips + status link. Live state colors the dot. */
.land-top {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  font-family: var(--mono);
  font-size: 11.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--land-ink-dim);
}
.land-top a { text-decoration: none; }
.land-status {
  display: inline-flex; align-items: center;
  width: 22px; height: 22px;
  justify-content: center;
  border-radius: 50%;
  transition: background 160ms ease;
}
.land-status:hover { background: rgba(250, 250, 247, 0.06); }
.land-dot {
  display: inline-block;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--land-ink-dim);
  transition: background 240ms ease, box-shadow 240ms ease;
}
.land-dot.ok   { background: #4ade80; box-shadow: 0 0 8px rgba(74, 222, 128, 0.55); animation: land-pulse 2.4s ease-in-out infinite; }
.land-dot.warn { background: #f5b342; box-shadow: 0 0 8px rgba(245, 179, 66, 0.6);  animation: land-pulse 1.6s ease-in-out infinite; }
.land-dot.bad  { background: #f87171; box-shadow: 0 0 8px rgba(248, 113, 113, 0.7); animation: land-blink 0.9s ease-in-out infinite; }
@keyframes land-pulse { 0%,100% { opacity: 0.5; } 50% { opacity: 1; } }
@keyframes land-blink { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }

/* Right side of top strip — telegram chips + Status link. */
.land-top-right {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
}
.land-tg {
  display: inline-flex; align-items: center;
  font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.04em; text-transform: none;
  padding: 5px 10px;
  border: 1px solid rgba(250, 250, 247, 0.18);
  border-radius: 999px;
  color: var(--land-ink);
}
.land-tg:hover {
  border-color: var(--land-ink);
  background: rgba(250, 250, 247, 0.06);
}
.land-status-link {
  color: var(--land-ink);
  border-bottom: 1px solid rgba(250, 250, 247, 0.25);
  padding-bottom: 1px;
  margin-left: 6px;
}
.land-status-link:hover { border-bottom-color: var(--land-ink); }

/* Carousel — the hero. Each slide pairs a 3D mark (in the stage canvas)
 * with its name + description below. Left/right buttons cycle slides;
 * dots show position. Auto-advance pauses on hover/focus. */
.land-carousel {
  display: grid;
  grid-template-rows: auto auto auto auto;
  gap: clamp(16px, 2.6vh, 26px);
  align-items: center;
  justify-items: center;
  text-align: center;
}

/* Stage row = [prev btn] [3D canvas + static fallback] [next btn].
 * Buttons sit beside the stage on wide screens, fade under on narrow. */
.land-stage-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(8px, 2vw, 20px);
  width: 100%;
}
.land-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  max-width: min(440px, 70vw);
  margin: 0 auto;
}
.land-stage-mark {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;
  user-select: none; -webkit-user-drag: none;
  /* Brand PNGs are dark-on-transparent; invert for the dark canvas. */
  filter: invert(1);
  transition: opacity 600ms ease;
}
.land-canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0;
  transition: opacity 800ms ease;
}
.land-canvas.is-ready { opacity: 1; }
.land-stage.is-ready .land-stage-mark { opacity: 0; }

/* Arrows: clean ink-on-dark, larger tap target than the visual disc. */
.land-arrow {
  width: 44px; height: 44px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent;
  border: 1px solid rgba(250, 250, 247, 0.2);
  border-radius: 999px;
  color: var(--land-ink);
  font-family: var(--serif);
  font-size: 22px; line-height: 1;
  cursor: pointer;
  transition: background 160ms ease, border-color 160ms ease, transform 160ms ease;
  flex-shrink: 0;
}
.land-arrow:hover {
  background: rgba(250, 250, 247, 0.06);
  border-color: rgba(250, 250, 247, 0.45);
  transform: translateY(-1px);
}
.land-arrow:focus-visible {
  outline: 1px solid var(--land-ink);
  outline-offset: 2px;
}

/* Slide words: name + description. Pair gets swapped under fade-out then
 * fade-in (.is-leaving / .is-entering toggled by the carousel JS). */
.land-slide-words {
  display: flex; flex-direction: column;
  align-items: center; gap: clamp(8px, 1.4vh, 14px);
  padding: 0 8px;
  min-height: clamp(110px, 14vh, 150px);
  width: 100%;
  transition: opacity 240ms ease, transform 240ms ease;
}
.land-slide-words.is-leaving {
  opacity: 0;
  transform: translateY(6px);
}
.land-slide-eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--land-ink-dim);
}
.land-slide-name {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(36px, 6.4vw, 56px);
  line-height: 0.98;
  letter-spacing: 0.005em;
  text-transform: uppercase;
}
.land-slide-desc {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(15px, 2vw, 19px);
  color: var(--land-ink-dim);
  max-width: 44ch;
  line-height: 1.5;
}

/* Dot indicators — one per slide, current is filled. Click to jump. */
.land-dots {
  display: flex; gap: 10px;
  justify-content: center;
  padding-top: 4px;
}
.land-dot-btn {
  width: 8px; height: 8px;
  padding: 0; margin: 0;
  border-radius: 50%;
  border: 1px solid rgba(250, 250, 247, 0.35);
  background: transparent;
  cursor: pointer;
  transition: background 160ms ease, border-color 160ms ease, transform 160ms ease;
}
.land-dot-btn[aria-current="true"] {
  background: var(--land-ink);
  border-color: var(--land-ink);
  transform: scale(1.15);
}
.land-dot-btn:hover { border-color: var(--land-ink); }
.land-dot-btn:focus-visible {
  outline: 1px solid var(--land-ink);
  outline-offset: 3px;
}

/* CTA row beneath the carousel — context-sensitive: primary button label
 * + href both update when the slide changes (the JS picks them up from
 * data attrs on the slide def). */
.land-cta-row {
  display: flex; flex-wrap: wrap; gap: 10px;
  justify-content: center;
  margin-top: 4px;
}
.land-cta {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 13px 22px;
  background: var(--land-ink);
  color: var(--land-bg);
  text-decoration: none;
  border: 1px solid var(--land-ink);
  font-family: var(--sans);
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transition: opacity 120ms ease;
}
.land-cta:hover { opacity: 0.82; }
.land-cta[hidden] { display: none; }
.land-cta-secondary {
  background: transparent;
  color: var(--land-ink);
  border-color: rgba(250, 250, 247, 0.3);
}
.land-cta-secondary:hover {
  background: rgba(250, 250, 247, 0.05);
  opacity: 1;
}

/* Bottom strip — single contact link, centered. */
.land-foot {
  display: flex; align-items: center; justify-content: center;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
}
.land-foot a {
  color: var(--land-ink-dim);
  text-decoration: none;
  border-bottom: 1px solid rgba(250, 250, 247, 0.18);
  padding-bottom: 1px;
}
.land-foot a:hover { color: var(--land-ink); border-bottom-color: var(--land-ink); }

/* Reduced motion: skip the 3D scene + auto-advance entirely. The static
 * CI mark stays visible as the carousel still pages through products
 * via the arrows / dots (just no animation between them). */
@media (prefers-reduced-motion: reduce) {
  .land-canvas { display: none; }
  .land-slide-words { transition: none; }
}

/* Narrow screens — shrink stage; arrows still flank it (smaller). */
@media (max-width: 520px) {
  .splash { gap: 22px; padding-bottom: 32px; }
  .land-stage { max-width: 78vw; }
  .land-arrow { width: 38px; height: 38px; font-size: 18px; }
  .land-stage-row { gap: 4px; }
}

/* ===== 4-status settlement tracker (#67 — advantage Catchain 2.0) ============
   A compact pill below the swap button that progresses pending → confirmed →
   settled / failed, driven by the wallet-lt probe + our own live swap stream. */
.trade-status {
  display: flex; align-items: center; gap: 8px;
  margin-top: 8px; padding: 8px 12px; border-radius: 10px;
  font-size: 13px; font-weight: 500; line-height: 1.3;
  border: 1px solid var(--line); background: var(--card-soft);
}
.trade-status .ts-ic { flex: 0 0 auto; font-size: 14px; }
.trade-status .ts-tx { min-width: 0; }
.trade-status.ts-pending { color: var(--hint); }
.trade-status.ts-confirmed {
  color: var(--fg);
  border-color: color-mix(in srgb, var(--accent, #6aa6ff) 40%, var(--line));
}
.trade-status.ts-settled {
  color: #1bbf83;
  border-color: color-mix(in srgb, #1bbf83 45%, var(--line));
  background: color-mix(in srgb, #1bbf83 10%, var(--card-soft));
}
.trade-status.ts-failed {
  color: #e0a23a;
  border-color: color-mix(in srgb, #e0a23a 45%, var(--line));
  background: color-mix(in srgb, #e0a23a 10%, var(--card-soft));
}
.trade-status.ts-pending .ts-ic,
.trade-status.ts-confirmed .ts-ic { animation: ts-pulse 1.1s ease-in-out infinite; }
@keyframes ts-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

/* ===== Axiom-grade trade terminal (#74) — instance-scoped component ==========
   Multi-instance: each .ci-win-instance hosts one .tt. Narrow window = vertical
   stack; wide window (.surface-wide) = chart | sticky order-panel, trades below. */
.ci-component.tt { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.tt-head { display: flex; align-items: center; gap: 10px; }
.tt-id { display: flex; align-items: center; gap: 9px; cursor: pointer; min-width: 0; flex: 1 1 auto; }
.tt-logo img, .tt-logo .tok-fallback { width: 30px; height: 30px; border-radius: 50%; }
.tt-id-txt { display: flex; flex-direction: column; min-width: 0; }
.tt-sym { font-size: 16px; font-weight: 700; letter-spacing: 0.01em; }
.tt-addr { font-size: 11px; color: var(--hint); font-family: var(--mono, ui-monospace, monospace); }
.tt-px-wrap { text-align: right; flex: 0 0 auto; }
.tt-px { font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; }
.tt-chg { font-size: 12px; font-weight: 600; }
.tt-chg.up { color: #1bbf83; } .tt-chg.dn { color: #ef5350; }
.tt-scan { flex: 0 0 auto; appearance: none; border: 1px solid var(--line); background: transparent; color: var(--hint); width: 30px; height: 30px; border-radius: 8px; cursor: pointer; }
.tt-scan:hover { color: var(--fg); background: var(--card-soft); }
.tt-stats { display: flex; gap: 8px; flex-wrap: wrap; }
.tt-stat { display: flex; flex-direction: column; gap: 1px; padding: 5px 10px; border: 1px solid var(--line); border-radius: 8px; background: var(--card-soft); flex: 1 1 auto; }
.tt-stat-k { font-size: 10px; color: var(--hint); text-transform: uppercase; letter-spacing: 0.04em; }
.tt-stat-v { font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }
.tt-tf { display: flex; gap: 6px; }
.tt-tf-chip { appearance: none; border: 1px solid var(--line); background: var(--card-soft); color: var(--hint); padding: 4px 12px; border-radius: 7px; font-size: 12px; font-weight: 600; cursor: pointer; }
.tt-tf-chip.on { color: var(--fg); border-color: color-mix(in srgb, var(--accent, #6aa6ff) 55%, var(--line)); background: color-mix(in srgb, var(--accent, #6aa6ff) 14%, var(--card-soft)); }
.tt-chart { height: 240px; min-height: 200px; border-radius: 10px; overflow: hidden; background: var(--card); position: relative; }
.tt-panel { display: flex; flex-direction: column; gap: 10px; padding: 12px; border: 1px solid var(--line); border-radius: 12px; background: var(--card); }
.tt-side { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.tt-tab { appearance: none; border: 1px solid var(--line); background: var(--card-soft); color: var(--hint); padding: 9px; border-radius: 9px; font-size: 14px; font-weight: 700; cursor: pointer; }
.tt-tab.buy.on { color: #06281c; background: #1bbf83; border-color: #1bbf83; }
.tt-tab.sell.on { color: #2a0d0d; background: #ef5350; border-color: #ef5350; }
.tt-amount { display: flex; align-items: center; gap: 8px; border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; background: var(--bg); }
.tt-amt-in { flex: 1 1 auto; min-width: 0; background: transparent; border: 0; outline: 0; color: var(--fg); font-size: 19px; font-weight: 600; font-variant-numeric: tabular-nums; }
.tt-unit { flex: 0 0 auto; font-size: 13px; font-weight: 700; color: var(--hint); }
.tt-presets { display: flex; gap: 6px; }
.tt-presets .chip { flex: 1 1 auto; appearance: none; border: 1px solid var(--line); background: var(--card-soft); color: var(--fg); padding: 7px; border-radius: 8px; font-size: 13px; font-weight: 600; cursor: pointer; }
.tt-presets .chip:hover { border-color: var(--accent, #6aa6ff); }
.tt-meta { display: flex; justify-content: space-between; gap: 8px; font-size: 12px; color: var(--hint); min-height: 16px; }
.tt-receive { color: var(--fg); } .tt-holding { flex: 0 0 auto; }
.tt-swap { appearance: none; border: 0; border-radius: 11px; padding: 13px; font-size: 15px; font-weight: 700; cursor: pointer; background: #1bbf83; color: #06281c; }
.tt-swap.sell { background: #ef5350; color: #2a0d0d; }
.tt-swap:disabled { opacity: 0.5; cursor: default; }
.tt-status { margin-top: 2px; }
.tt-tape { display: flex; flex-direction: column; gap: 2px; max-height: 260px; overflow: auto; }
.tt-tape-empty { color: var(--hint); font-size: 12px; padding: 10px; text-align: center; }
.tt-fill { display: grid; grid-template-columns: 42px 1fr auto 44px; gap: 8px; align-items: center; padding: 5px 8px; border-radius: 6px; font-size: 12px; font-variant-numeric: tabular-nums; }
.tt-fill:nth-child(odd) { background: var(--card-soft); }
.tt-fill-side { font-weight: 700; font-size: 10px; }
.tt-fill.buy .tt-fill-side { color: #1bbf83; } .tt-fill.sell .tt-fill-side { color: #ef5350; }
.tt-fill-amt { color: var(--hint); } .tt-fill-ago { color: var(--hint); text-align: right; font-size: 11px; }
/* Wide window → Axiom 2-col: chart left (tall), order panel right (sticky), trades below. */
.ci-win.surface-wide .ci-component.tt {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 12px 16px; align-items: start;
  grid-template-areas: "head head" "stats panel" "tf panel" "chart panel" "tape panel";
}
.ci-win.surface-wide .tt-head { grid-area: head; }
.ci-win.surface-wide .tt-stats { grid-area: stats; }
.ci-win.surface-wide .tt-tf { grid-area: tf; }
.ci-win.surface-wide .tt-chart { grid-area: chart; height: 360px; }
.ci-win.surface-wide .tt-panel { grid-area: panel; position: sticky; top: 8px; }
.ci-win.surface-wide .tt-tape { grid-area: tape; max-height: 200px; }
