/* Crypto War Room — members area
   Inherits tokens, chamfers and type from styles.css. */

body { overflow-x: hidden; }

/* The fixed chrome above every pane: the topbar, plus the gainers ticker
   under it. The screener deck and the chat column size themselves against
   this, so changing either bar's height only needs editing here. */
:root {
  --topbar-h: 62px;
  --ticker-h: 34px;
  --chrome-h: calc(var(--topbar-h) + var(--ticker-h));
}

.app {
  display: grid;
  grid-template-columns: 244px minmax(0, 1fr);
  min-height: 100vh;
}

/* ---------- sidebar ---------- */

.side {
  position: sticky; top: 0; align-self: start;
  height: 100vh;
  display: flex; flex-direction: column;
  background: var(--bg);
  border-inline-end: 1px solid var(--line);
  padding: 20px 14px 16px;
}

.side__brand {
  padding: 0 8px 20px;
  display: flex; align-items: center; gap: 9px;
}
.side__brand-dot {
  width: 7px; height: 7px; border-radius: 999px; background: var(--accent);
  display: inline-block; flex: none;
}
.side__brand-word {
  font-family: var(--mono); font-size: 14px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--fg);
}

/* Practice capital, sidebar footer -- account-level state, not something
   scoped to whichever coin the ticket happens to be showing. */
.side__capital { margin-top: auto; padding: 4px 10px 16px; display: grid; gap: 6px; }
.side__capital[hidden] { display: none; }
.side__capital-label {
  font-family: var(--mono); font-size: 13px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--fg-3);
}
.side__capital-value {
  font-family: var(--mono); font-size: 24px; line-height: 1;
  letter-spacing: -.03em; color: var(--fg); font-variant-numeric: tabular-nums;
}
.side__capital-sub {
  display: flex; gap: 12px;
  font-family: var(--mono); font-size: 13px; letter-spacing: -.02em;
  text-transform: uppercase; color: var(--fg-3);
}
.side__capital-sub span:nth-child(2) { color: var(--fg-2); font-variant-numeric: tabular-nums; }
.side__capital-sub span:nth-child(3) { font-variant-numeric: tabular-nums; }
.side__capital-sub span:nth-child(3)[data-dir="up"]   { color: var(--gain); }
.side__capital-sub span:nth-child(3)[data-dir="down"] { color: var(--loss); }

.side__group {
  font-family: var(--techno); font-size: 13px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--fg-3);
  padding: 18px 10px 8px;
}

.side__nav { display: grid; gap: 2px; }

.navlink {
  --cut: 6px;
  display: flex; align-items: center; gap: 11px;
  padding: 10px 11px;
  color: var(--fg-3); font-size: 16px; font-weight: 510;
  background: transparent; border: 1px solid transparent;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  cursor: pointer; text-align: start; width: 100%;
  font-family: inherit;
  transition: color .16s, background-color .16s;
}
.navlink svg { flex: none; }
.navlink:hover { color: var(--fg-2); background: rgba(255,255,255,.04); }
.navlink[aria-current="page"] {
  color: var(--fg); background: var(--accent-soft); border-color: var(--accent-line);
}
.navlink[aria-current="page"] svg { color: var(--accent); }
.navlink__dot {
  width: 6px; height: 6px; border-radius: 999px; background: var(--fg-3);
  display: inline-block; flex: none; transition: background-color .16s;
}
.navlink[aria-current="page"] .navlink__dot { background: var(--accent); }
.navlink__label { flex: 1; }
.navlink__count {
  margin-inline-start: auto;
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
}

/* The profile sits at the foot of the nav. It used to be pushed there
   by the capital block's margin-top:auto; that block moved into the
   trading sidebar, so the push has to belong to the foot itself. */
.side__foot { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--line); }
.userchip {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 8px;
}
.userchip img {
  width: 32px; height: 32px; border-radius: 50%; object-fit: cover;
  object-position: 50% 36%; border: 1px solid var(--line-strong);
}
.userchip__name { font-size: 15px; font-weight: 590; line-height: 1.2; }
.userchip__plan {
  font-family: var(--techno); font-size: 13px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--accent);
}

/* ---------- topbar + main ---------- */

.main { min-width: 0; display: flex; flex-direction: column; }

.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 16px;
  height: var(--topbar-h); padding-inline: clamp(18px, 3vw, 34px);
  background: rgba(9,9,9,.78);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border-bottom: 1px solid var(--line);
}
.topbar h1 {
  font-size: 19px; letter-spacing: -.025em; font-weight: 590;
}
.topbar__spacer { margin-inline-start: auto; }

.topbar__scan { display: flex; align-items: center; gap: 16px; }
.topbar__scan[hidden] { display: none; }
.topbar__divider { width: 1px; height: 20px; background: var(--line); flex: none; }
.topbar__counts { display: flex; align-items: center; gap: 16px; }
.topbar__counts span {
  font-family: var(--mono); font-size: 14px; letter-spacing: -.02em;
  text-transform: uppercase; color: var(--fg-3);
}
.topbar__counts b { font-weight: 400; color: var(--fg-2); }
.topbar__counts span:last-child b { color: var(--gain); }

.view { padding: clamp(22px, 3.4vw, 40px) clamp(18px, 3vw, 34px) 80px; }
.view[hidden] { display: none; }

.view__lede {
  color: var(--fg-2); max-width: 68ch; margin-bottom: 30px; font-size: 18px;
}

.blockhead {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; margin: 42px 0 18px;
}
.blockhead:first-of-type { margin-top: 0; }
.blockhead h2 { font-size: 20px; letter-spacing: -.028em; }
.blockhead a {
  font-family: var(--techno); font-size: 13px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--accent);
}
.blockhead a:hover { text-decoration: underline; text-underline-offset: 4px; }

/* ---------- stat row ---------- */

.stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: clamp(12px, 1.4vw, 18px);
  margin-bottom: 8px;
}
.statbox {
  --cut: var(--cut-sm);
  background: var(--bg-elev); border: 1px solid var(--line);
  padding: 17px 19px;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.statbox b {
  display: block; font-family: var(--mono); font-size: 24px; font-weight: 590;
  letter-spacing: -.035em; line-height: 1.1; margin-bottom: 4px;
}
.statbox b[data-tone="gain"] { color: var(--gain); }
.statbox b[data-tone="accent"] { color: var(--accent); }
.statbox span {
  font-family: var(--techno); font-size: 13px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--fg-3);
}

/* ---------- cards grid ---------- */

.grid { display: grid; gap: clamp(14px, 1.5vw, 20px); }
.grid--signals { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }

.card {
  --cut: var(--cut-md);
  background: var(--bg-elev); border: 1px solid var(--line);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  display: flex; flex-direction: column;
  transition: transform .3s var(--ease-out), border-color .3s var(--ease-out);
}
.card:hover { transform: translateY(-3px); border-color: var(--line-strong); }

/* ---------- signal card ---------- */

.sig { --cut: var(--cut-md); }
.sig__head {
  display: flex; align-items: center; gap: 10px;
  padding: 14px 17px; border-bottom: 1px solid var(--line);
}
.sig__pair { font-family: var(--mono); font-weight: 590; font-size: 17px; letter-spacing: -.02em; }
.sig__state {
  margin-inline-start: auto;
  --cut: 4px;
  font-family: var(--techno); font-size: 13px; letter-spacing: .13em; text-transform: uppercase;
  padding: 4px 8px; border: 1px solid var(--line-strong); color: var(--fg-3);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.sig__state[data-state="open"] { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }
.sig__state[data-state="hit"] { color: var(--gain); border-color: var(--gain-line); background: var(--gain-soft); }

.sig__rows { padding: 14px 17px; display: grid; gap: 8px; }
.sig__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-family: var(--mono); font-size: 15px; }
.sig__row span { color: var(--fg-3); }
.sig__row b { font-weight: 510; color: var(--fg-2); }
.sig__row b[data-tone="tp"] { color: var(--gain); }
.sig__row b[data-tone="stop"] { color: var(--loss); }

.sig__foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 17px; border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
}

.filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 22px; }
.filter {
  --cut: 5px;
  font-family: var(--mono); font-size: 14px; letter-spacing: -.02em; text-transform: uppercase;
  padding: 8px 14px; cursor: pointer;
  background: rgba(255,255,255,.03); border: 1px solid var(--line); color: var(--fg-3);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  transition: color .16s, border-color .16s, background-color .16s;
}
.filter:hover { color: var(--fg-2); border-color: var(--line-strong); }
/* Both spellings of "selected". aria-pressed is the component's real
   API and what the older views already set; is-on crept in with the
   dashboards, where it silently styled nothing and left those filters
   with no visible selected state at all. */
.filter[aria-pressed="true"],
.filter.is-on { color: var(--accent-ink); background: var(--accent); border-color: transparent; }

/* ---------- chat ---------- */

.chat-layout { display: grid; grid-template-columns: minmax(0,1fr) 300px; gap: clamp(18px, 2.4vw, 30px); align-items: start; }
@media (max-width: 1000px) { .chat-layout { grid-template-columns: 1fr; } }

.widget-frame {
  --cut: var(--cut-lg);
  border: 1px solid var(--line); background: var(--bg-elev);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  overflow: hidden;
  min-height: 560px;
  display: grid;
}
.widget-frame iframe { width: 100%; height: 100%; min-height: 560px; border: 0; display: block; }

.notice {
  --cut: var(--cut-sm);
  border: 1px solid var(--accent-line); background: var(--accent-soft);
  padding: 15px 17px; font-size: 15px; color: var(--fg-2); line-height: 1.6;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.notice b { color: var(--fg); }
.notice code {
  font-family: var(--mono); font-size: 14px; color: var(--accent);
  background: rgba(0,0,0,.35); padding: 1px 5px;
}

.demo-flag {
  --cut: var(--cut-sm);
  display: flex; align-items: center; gap: 10px;
  border: 1px dashed var(--line-strong); background: rgba(255,255,255,.02);
  padding: 12px 16px; margin-bottom: 26px;
  font-size: 15px; color: var(--fg-3);
}
.demo-flag svg { flex: none; color: var(--warn); }

/* ---------- mobile ---------- */

@media (max-width: 860px) {
  .app { grid-template-columns: 1fr; }
  .side {
    position: fixed; bottom: 0; top: auto; left: 0; right: 0;
    height: auto; z-index: 60;
    flex-direction: row; align-items: center;
    padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
    border-inline-end: 0; border-top: 1px solid var(--line);
    background: rgba(5,6,7,.94);
    backdrop-filter: blur(14px);
  }
  .side__brand, .side__group, .side__foot { display: none; }
  .side__nav { display: flex; width: 100%; gap: 4px; }
  .navlink {
    flex-direction: column; gap: 5px; padding: 8px 4px;
    font-size: 13px; font-family: var(--techno); letter-spacing: .08em;
    text-transform: uppercase; text-align: center; justify-content: center;
  }
  .navlink__count { display: none; }
  .view { padding-bottom: 110px; }
}

.stack { display: grid; gap: 16px; }
.notice--quiet { border-color: var(--line-strong); background: rgba(255,255,255,.02); }

/* ---------- chat: join panel leads, widget is secondary ---------- */

.joinpanel {
  --cut: var(--cut-lg);
  border: 1px solid var(--accent-line);
  background: linear-gradient(150deg, rgba(255,90,31,.10), var(--bg-elev) 58%);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  padding: clamp(24px, 3vw, 36px);
  display: grid; gap: 13px; justify-items: start;
}
.joinpanel__mark {
  width: 46px; height: 46px; display: grid; place-items: center;
  color: var(--accent); background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  --cut: 7px;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.joinpanel__mark svg { width: 22px; height: 22px; }
.joinpanel h2 { font-size: clamp(1.375rem, 2.2vw, 1.875rem); letter-spacing: -.032em; }
.joinpanel__stat {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: 15px; color: var(--fg-3);
}
.joinpanel__stat b { color: var(--fg-2); font-weight: 510; }
.joinpanel__body { color: var(--fg-2); font-size: 17px; max-width: 54ch; line-height: 1.62; }
.joinpanel .btn { margin-top: 6px; }

.widget-frame[data-widget] { min-height: 620px; }
.widget-frame[data-widget] iframe { min-height: 620px; }

.joinpanel .btn + .btn { margin-top: 0; }
.joinpanel__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 6px; }

/* ---------- chat room ---------- */

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

.view--chat { padding-bottom: 0; height: calc(100vh - var(--chrome-h)); display: flex; }
@media (max-width: 860px) { .view--chat { height: calc(100vh - var(--chrome-h) - 96px); } }

.room {
  --cut: var(--cut-lg);
  flex: 1; min-height: 0;
  display: grid; grid-template-rows: auto minmax(0,1fr) auto auto;
  border: 1px solid var(--line); background: var(--bg-elev);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
[dir="rtl"] .room {
  clip-path: polygon(0 0, calc(100% - var(--cut)) 0, 100% var(--cut), 100% 100%, var(--cut) 100%, 0 calc(100% - var(--cut)));
}

.room__bar {
  display: flex; align-items: center; gap: 10px;
  padding: 15px 20px; border-bottom: 1px solid var(--line);
  background: rgba(0,0,0,.24);
}
.room__name { font-size: 17px; letter-spacing: -.02em; }
.room__status {
  font-family: var(--techno); font-size: 13px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--fg-3);
}
.room__online {
  margin-inline-start: auto;
  font-family: var(--mono); font-size: 14px; color: var(--fg-3);
}
.room__online b { color: var(--gain); font-weight: 590; }

.dot[data-conn-dot] { background: var(--warn); box-shadow: 0 0 0 3px rgba(245,165,36,.16); }
.dot[data-conn-dot][data-state="on"] { background: var(--gain); box-shadow: 0 0 0 3px rgba(36,197,94,.16); }
.dot[data-conn-dot][data-state="off"] { background: var(--loss); box-shadow: 0 0 0 3px rgba(240,80,58,.16); }

.room__log {
  overflow-y: auto; padding: 20px;
  display: flex; flex-direction: column; gap: 16px;
  scrollbar-width: thin;
}
.room__empty { color: var(--fg-3); font-size: 16px; margin: auto; }

.line { display: grid; grid-template-columns: 34px minmax(0,1fr); gap: 12px; }
.line__av {
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--bg-elev-2); border: 1px solid var(--line);
  font-family: var(--mono); font-size: 14px; font-weight: 590; color: var(--fg-3);
}
.line__head { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; margin-bottom: 3px; }
.line__who { font-weight: 590; font-size: 16px; }
.line--mine .line__who { color: var(--accent); }
.line__at { font-family: var(--mono); font-size: 13px; color: var(--fg-3); }
.line__body {
  font-size: 17px; color: #D6DAE1; line-height: 1.6;
  overflow-wrap: anywhere; white-space: pre-wrap;
}
.line__body a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }

.room__form {
  display: grid; grid-template-columns: 150px minmax(0,1fr) auto; gap: 10px;
  padding: 14px 20px 6px; border-top: 1px solid var(--line);
  align-items: end;
}
@media (max-width: 620px) {
  .room__form { grid-template-columns: minmax(0,1fr) auto; }
  .room__name-input { grid-column: 1 / -1; }
}

.room__name-input, .room__input {
  --cut: 6px;
  font: inherit; font-size: 17px;
  background: var(--bg-inset); color: var(--fg);
  border: 1px solid var(--line);
  padding: 11px 13px; width: 100%;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  transition: border-color .16s;
}
.room__name-input { font-family: var(--mono); font-size: 15px; }
.room__input { resize: none; max-height: 160px; line-height: 1.5; }
.room__name-input:focus, .room__input:focus { outline: none; border-color: var(--accent-line); }
.room__name-input::placeholder, .room__input::placeholder { color: var(--fg-3); }

.room__send { align-self: end; }
.room__hint {
  padding: 0 20px 14px;
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
}

/* ---------- sign-in gate ---------- */

.gate {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  padding: clamp(20px, 5vw, 48px);
  background:
    radial-gradient(58% 46% at 50% 0%, rgba(255,90,31,.13), transparent 70%),
    var(--bg);
  overflow-y: auto;
}
.gate[hidden] { display: none; }

.gate__card {
  --cut: var(--cut-lg);
  width: 100%; max-width: 400px;
  background: var(--bg-elev); border: 1px solid var(--line);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  padding: clamp(28px, 4vw, 40px);
  display: grid; gap: 16px;
}
.gate__logo { height: 34px; width: auto; margin-bottom: 6px; }
.gate__title { font-size: 24px; letter-spacing: -.032em; }
.gate__lede { color: var(--fg-3); font-size: 16px; margin-top: -8px; }
.gate__submit { width: 100%; margin-top: 4px; }
.gate__foot { font-size: 14px; color: var(--fg-3); text-align: center; }

.gate__error {
  --cut: 5px;
  border: 1px solid rgba(240,80,58,.4); background: rgba(240,80,58,.10);
  color: #FF9C8B; font-size: 15px; padding: 10px 13px;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.gate__error[hidden] { display: none; }

/* ---------- form controls ---------- */

.field { display: grid; gap: 7px; }
.field__label {
  font-family: var(--techno); font-size: 13px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--fg-3);
}
.field__input {
  --cut: 6px;
  font: inherit; font-size: 17px;
  background: var(--bg-inset); color: var(--fg);
  border: 1px solid var(--line); padding: 12px 14px; width: 100%;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  transition: border-color .16s;
}
.field__input:focus { outline: none; border-color: var(--accent-line); }
.field__input:disabled { color: var(--fg-3); cursor: not-allowed; }
.field__hint { font-size: 14px; color: var(--fg-3); margin-top: -4px; }

/* ---------- user chip ---------- */

.userchip {
  width: 100%; text-align: start; font: inherit; cursor: pointer;
  background: transparent; border: 1px solid transparent;
  --cut: 6px;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  transition: background-color .16s, border-color .16s;
}
.userchip:hover { background: rgba(255,255,255,.05); border-color: var(--line); }
.userchip__text { min-width: 0; }
.userchip__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.userchip svg { margin-inline-start: auto; color: var(--fg-3); flex: none; }

/* ---------- profile ---------- */

.profile {
  display: grid; grid-template-columns: 256px minmax(0,1fr);
  gap: clamp(24px, 4vw, 48px); align-items: start; max-width: 760px;
}
@media (max-width: 720px) { .profile { grid-template-columns: 1fr; } }

.profile__shot { display: grid; gap: 12px; justify-items: start; }
.profile__shot img {
  --cut: var(--cut-md);
  width: 100%; max-width: 256px; aspect-ratio: 1; object-fit: cover;
  background: var(--bg-elev-2); border: 1px solid var(--line);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.profile__upload { cursor: pointer; }
.profile__upload .btn { pointer-events: none; }
.profile__note { font-size: 14px; color: var(--fg-3); }
.profile__form { display: grid; gap: 16px; }
.profile__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 4px; }

/* chat avatars now carry real pictures */
.line__av { overflow: hidden; }
.line__av img { width: 100%; height: 100%; object-fit: cover; }
.room__form { grid-template-columns: minmax(0,1fr) auto; }

/* ---------- chat attachments ---------- */

.room__form { grid-template-columns: auto minmax(0,1fr) auto; }

.room__attach { cursor: pointer; align-self: end; }
.room__attach-btn {
  --cut: 6px;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  background: var(--bg-inset); border: 1px solid var(--line); color: var(--fg-3);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  transition: color .16s, border-color .16s;
}
.room__attach:hover .room__attach-btn { color: var(--accent); border-color: var(--accent-line); }

.room__pending {
  display: flex; align-items: center; gap: 12px;
  margin: 0 20px; padding: 10px 12px;
  border: 1px dashed var(--line-strong); background: rgba(255,255,255,.02);
}
.room__pending[hidden] { display: none; }
.room__pending img {
  width: 54px; height: 54px; object-fit: cover; border: 1px solid var(--line);
}
.room__pending-note { font-size: 15px; color: var(--fg-3); }
.room__pending-x {
  margin-inline-start: auto;
  width: 28px; height: 28px; display: grid; place-items: center;
  background: transparent; border: 1px solid var(--line); color: var(--fg-2); cursor: pointer;
}
.room__pending-x:hover { border-color: var(--line-strong); color: var(--fg); }

.room[data-drop="true"] { border-color: var(--accent-line); }

/* posted media */
.line__media { margin-top: 9px; max-width: 460px; }
.line__media img {
  --cut: 8px;
  width: 100%; border: 1px solid var(--line); cursor: zoom-in;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  background: var(--bg-inset);
}
.line__embed {
  --cut: 8px;
  margin-top: 9px; max-width: 460px; aspect-ratio: 16/9;
  border: 1px solid var(--line); background: #000;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.line__embed iframe { width: 100%; height: 100%; border: 0; display: block; }

.shot {
  position: fixed; inset: 0; z-index: 300;
  display: grid; place-items: center; padding: clamp(16px, 4vw, 56px);
  background: rgba(4,5,6,.92); backdrop-filter: blur(10px);
  border: 0; cursor: zoom-out;
}
.shot[hidden] { display: none; }
.shot img { max-width: 100%; max-height: 100%; object-fit: contain; border: 1px solid var(--line-strong); }

/* ---------- track record export modal ---------- */

.expmodal {
  position: fixed; inset: 0; z-index: 300;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(16px, 4vw, 56px);
  background: rgba(4,5,6,.82); backdrop-filter: blur(6px);
}
.expmodal[hidden] { display: none; }
.expmodal__panel {
  --cut: var(--cut-md);
  width: min(920px, 100%); max-height: 84vh;
  display: flex; flex-direction: column; min-height: 0;
  background: var(--bg-elev); border: 1px solid var(--line-strong);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.expmodal__head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 16px; border-bottom: 1px solid var(--line);
}
.expmodal__head h2 { font-size: 19px; }
.expmodal__actions { display: flex; align-items: center; gap: 8px; }
.expmodal__x {
  display: grid; place-items: center; width: 26px; height: 26px;
  background: rgba(255,255,255,.06); border: 0; border-radius: 3px;
  color: var(--fg-3); cursor: pointer; transition: background-color .14s, color .14s;
}
.expmodal__x:hover { background: rgba(255,255,255,.16); color: var(--fg); }

.expmodal__summary {
  display: flex; gap: 28px; padding: 14px 16px; border-bottom: 1px solid var(--line);
}
.expmodal__stat { display: grid; gap: 2px; }
.expmodal__stat b { font-family: var(--mono); font-size: 20px; font-weight: 590; color: var(--fg); }
.expmodal__stat b[data-dir="up"]   { color: var(--gain); }
.expmodal__stat b[data-dir="down"] { color: var(--loss); }
.expmodal__stat small {
  font-family: var(--techno); font-size: 13px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--fg-3);
}

.expmodal__body {
  overflow: auto; min-height: 0; flex: 1;
  display: grid; gap: 16px; padding: 16px; align-content: start;
}
.expmodal__body .tbl { min-width: 480px; }
.expmodal__monthly .tbl { min-width: 320px; }

/* Save as PDF just calls window.print() with everything but the modal
   hidden -- no extra library, and it's exactly what "print to PDF" is
   for. body.exporting is toggled by JS only while the print dialog is
   actually open. */
@media print {
  body.exporting > *:not(.expmodal) { display: none !important; }
  body.exporting { background: #fff !important; }
  body.exporting .expmodal {
    position: static; inset: auto; padding: 0; background: none; backdrop-filter: none;
  }
  body.exporting .expmodal__panel {
    width: 100%; max-height: none; border: 0; clip-path: none; background: #fff; color: #000;
  }
  body.exporting .expmodal__head, body.exporting .expmodal__actions { display: none !important; }
  body.exporting .expmodal__body { overflow: visible; }
  body.exporting .expmodal__summary { border-bottom-color: #ccc; }
  body.exporting .expmodal__stat small { color: #555 !important; }
  body.exporting .tbl th, body.exporting .tbl td { color: #111 !important; border-color: #ccc !important; }
  /* PNL keeps its colour in the PDF -- that was the whole point of asking
     for it printed, not just the raw numbers. */
  body.exporting .tradelog__pl[data-dir="up"],
  body.exporting .expmodal__stat b[data-dir="up"]   { color: var(--fg-2) !important; }
  body.exporting .tradelog__pl[data-dir="down"],
  body.exporting .expmodal__stat b[data-dir="down"] { color: #c23b1f !important; }
}

/* ---------- emoji picker ---------- */

.room__form { grid-template-columns: auto auto minmax(0,1fr) auto; }

.room__emoji-btn {
  --cut: 6px;
  align-self: end;
  width: 44px; height: 44px; display: grid; place-items: center;
  background: var(--bg-inset); border: 1px solid var(--line); color: var(--fg-3);
  cursor: pointer;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  transition: color .16s, border-color .16s;
}
.room__emoji-btn:hover,
.room__emoji-btn[aria-expanded="true"] { color: var(--accent); border-color: var(--accent-line); }

.emoji-pop {
  --cut: 10px;
  margin: 0 20px 10px;
  border: 1px solid var(--line-strong); background: var(--bg-elev-2);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  overflow: hidden;
}
.emoji-pop[hidden] { display: none; }

.emoji-pop__tabs {
  display: flex; gap: 2px; padding: 8px 10px;
  border-bottom: 1px solid var(--line); overflow-x: auto;
}
.emoji-tab {
  font-family: var(--techno); font-size: 13px; letter-spacing: .12em;
  text-transform: uppercase; white-space: nowrap;
  padding: 6px 10px; cursor: pointer;
  background: transparent; border: 1px solid transparent; color: var(--fg-3);
}
.emoji-tab:hover { color: var(--fg-2); }
.emoji-tab[aria-selected="true"] { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }

.emoji-pop__grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(38px, 1fr));
  gap: 2px; padding: 10px; max-height: 190px; overflow-y: auto;
}
.emoji-cell {
  font-size: 20px; line-height: 1;
  aspect-ratio: 1; display: grid; place-items: center;
  background: transparent; border: 0; cursor: pointer;
  transition: background-color .12s, transform .12s;
}
.emoji-cell:hover { background: rgba(255,255,255,.07); transform: scale(1.15); }

/* a message that is only emoji reads better large */
.line__body[data-jumbo="true"] { font-size: 32px; line-height: 1.25; }

/* Narrow screens: the two icon buttons and Send share a row under the box,
   so the message field keeps its full width. */
@media (max-width: 700px) {
  .room__form {
    grid-template-columns: auto auto minmax(0,1fr);
    grid-template-areas:
      "text text text"
      "emoji attach send";
    gap: 8px;
  }
  .room__emoji-btn { grid-area: emoji; }
  .room__attach    { grid-area: attach; }
  .room__input     { grid-area: text; }
  .room__send      { grid-area: send; justify-self: end; }
}

/* ---------- posted video ---------- */

.room__form { grid-template-columns: auto auto auto minmax(0,1fr) auto; }
@media (max-width: 700px) {
  .room__form {
    grid-template-columns: auto auto auto minmax(0,1fr);
    grid-template-areas:
      "text text text text"
      "emoji video attach send";
  }
  .room__attach--video { grid-area: video; }
}

.line__video {
  --cut: 8px;
  margin-top: 9px; max-width: 460px;
  border: 1px solid var(--line); background: #000;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.line__video video { width: 100%; display: block; max-height: 420px; background: #000; }

.room__pending video { width: 54px; height: 54px; object-fit: cover; border: 1px solid var(--line); }

/* ---------- screener ---------- */

.filters__note {
  margin-inline-start: auto; align-self: center;
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
}





.screen__search { font-size: 16px; }

.coinlist {
  display: grid; gap: 2px; max-height: 620px; min-height: 620px; overflow-y: auto; align-content: start;
  border: 1px solid var(--line); background: var(--bg-elev); padding: 6px;
}

/* Themed scrollbars for the app's own scrolling panels -- the default OS
   scrollbar was the one un-styled thing left on the page. Square, not
   rounded: this design has no round corners anywhere else either. */
.coinlist, .livepos__body, .ticket, .table-wrap[data-tradelog], .table-wrap[data-orderlog] {
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}
.coinlist::-webkit-scrollbar,
.livepos__body::-webkit-scrollbar,
.ticket::-webkit-scrollbar,
.table-wrap[data-tradelog]::-webkit-scrollbar,
.table-wrap[data-orderlog]::-webkit-scrollbar {
  width: 8px; height: 8px;
}
.coinlist::-webkit-scrollbar-track,
.livepos__body::-webkit-scrollbar-track,
.ticket::-webkit-scrollbar-track,
.table-wrap[data-tradelog]::-webkit-scrollbar-track,
.table-wrap[data-orderlog]::-webkit-scrollbar-track {
  background: transparent;
}
.coinlist::-webkit-scrollbar-thumb,
.livepos__body::-webkit-scrollbar-thumb,
.ticket::-webkit-scrollbar-thumb,
.table-wrap[data-tradelog]::-webkit-scrollbar-thumb,
.table-wrap[data-orderlog]::-webkit-scrollbar-thumb {
  background: var(--line-strong); border: 2px solid transparent; background-clip: padding-box;
}
.coinlist::-webkit-scrollbar-thumb:hover,
.livepos__body::-webkit-scrollbar-thumb:hover,
.ticket::-webkit-scrollbar-thumb:hover,
.table-wrap[data-tradelog]::-webkit-scrollbar-thumb:hover,
.table-wrap[data-orderlog]::-webkit-scrollbar-thumb:hover {
  background: var(--accent-line);
}
.coinrow {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 12px;
  padding: 10px 12px; width: 100%; text-align: start; cursor: pointer;
  background: transparent; border: 1px solid transparent; color: var(--fg-2); font: inherit;
  --cut: 5px;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  transition: background-color .14s, border-color .14s, color .14s;
}
.coinrow:hover { background: rgba(255,255,255,.04); color: var(--fg); }
.coinrow[aria-selected="true"] { background: var(--accent-soft); border-color: var(--accent-line); color: var(--fg); }
.coinrow__sym {
  font-family: var(--mono); font-size: 16px; font-weight: 590; line-height: 1.15;
}
.coinrow__net {
  font-family: var(--mono); font-size: 14px; line-height: 1.2; color: var(--fg-3);
  text-transform: uppercase; letter-spacing: -.01em;
}
.coinrow__chg { font-family: var(--mono); font-size: 13px; font-weight: 590; }
.coinrow__chg[data-dir="up"] { color: var(--gain); }
.coinrow__chg[data-dir="down"] { color: var(--loss); }
.coinlist__empty { padding: 22px 12px; color: var(--fg-3); font-size: 15px; text-align: center; }



.chartbox {
  --cut: var(--cut-md);
  max-width: 860px;
  border: 1px solid var(--line); background: var(--bg-elev);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  overflow: hidden;
}
.chartbox__bar {
  display: flex; align-items: baseline; gap: 12px;
  padding: 13px 17px; border-bottom: 1px solid var(--line); background: rgba(0,0,0,.22);
  /* Every dropdown in this bar opens downward over the chart, and the
     lightweight-charts canvas sits at z-index 2. Lifting the bar itself
     puts the bar and everything anchored to it above the canvas in one
     place, instead of each menu having to out-stack it on its own. */
  position: relative; z-index: 50;
}
.chartbox__pair { font-family: var(--mono); font-weight: 590; font-size: 17px; }
.chartbox__price { font-family: var(--mono); font-size: 15px; color: var(--fg-2); }
.chartbox__venue {
  font-family: var(--techno); font-size: 13px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--fg-3); border: 1px solid var(--line); padding: 3px 6px; align-self: center; flex: none;
}
.chartbox__chg { font-family: var(--mono); font-size: 15px; font-weight: 590; margin-inline-start: auto; }
.chartbox__chg[data-dir="up"] { color: var(--gain); }
.chartbox__chg[data-dir="down"] { color: var(--loss); }
.chartbox__frame { height: 626px; display: grid; place-items: center; background: var(--bg-elev); }
.chartbox__frame iframe { width: 100%; height: 100%; border: 0; display: block; }
.chartbox__empty { color: var(--fg-3); font-size: 16px; }

/* trade panel */
.trade {
  --cut: var(--cut-md);
  max-width: 860px;
  border: 1px solid var(--line); background: var(--bg-elev); padding: clamp(18px, 2.2vw, 26px);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  display: grid; gap: 18px;
}
.trade[hidden] { display: none; }
.trade__head { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.trade__head h3 { font-size: 19px; letter-spacing: -.026em; }

.seg { display: inline-flex; border: 1px solid var(--line); }
.seg__b {
  font-family: var(--techno); font-size: 13px; letter-spacing: .12em; text-transform: uppercase;
  padding: 9px 14px; cursor: pointer; background: transparent; border: 0; color: var(--fg-3);
  transition: background-color .14s, color .14s;
}
.seg__b:hover { color: var(--fg-2); }
.seg__b[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); }
.seg--side .seg__b--buy[aria-pressed="true"] { background: var(--gain); color: #0c0c0c; }
.seg--side .seg__b--sell[aria-pressed="true"] { background: var(--loss); color: #0c0c0c; }

.trade__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; align-items: end; }
.trade__foot { display: flex; gap: 10px; flex-wrap: wrap; }
.trade__out {
  --cut: 5px;
  font-family: var(--mono); font-size: 15px; line-height: 1.6;
  padding: 12px 15px; border: 1px solid var(--line); background: var(--bg-inset); color: var(--fg-2);
  white-space: pre-wrap; overflow-wrap: anywhere;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.trade__out[hidden] { display: none; }
.trade__out[data-tone="bad"] { border-color: rgba(240,80,58,.45); color: #FF9C8B; }
.trade__out[data-tone="good"] { border-color: var(--gain-line); color: var(--gain); }

/* binance connection */
.connect {
  --cut: var(--cut-md);
  max-width: 860px;
  border: 1px solid var(--line); background: var(--bg-elev); padding: clamp(18px, 2.2vw, 26px);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  display: grid; gap: 14px;
}
.connect__head { display: flex; align-items: center; gap: 12px; }
.connect__head h3 { font-size: 19px; letter-spacing: -.026em; }
.connect__state {
  margin-inline-start: auto;
  font-family: var(--techno); font-size: 13px; letter-spacing: .13em; text-transform: uppercase;
  padding: 4px 9px; border: 1px solid var(--line-strong); color: var(--fg-3);
}
.connect__state[data-on="true"] { color: var(--gain); border-color: var(--gain-line); background: var(--gain-soft); }
.connect__lede { color: var(--fg-2); font-size: 17px; }
.connect__form { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); align-items: end; }
.connect__form .gate__error, .connect__actions { grid-column: 1 / -1; }
.connect__actions { display: flex; gap: 10px; flex-wrap: wrap; }
.connect__fine { font-size: 14px; color: var(--fg-3); line-height: 1.6; }

/* ---------- screener: one screenful, three columns ---------- */

.view--screener {
  padding-bottom: 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: clamp(22px, 3vw, 36px);
}

/* The deck is sized to the viewport so a trader sees list, chart and ticket
   without scrolling. Anything historical lives below the fold on purpose. */
.deck {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr) 348px;
  gap: clamp(12px, 1.2vw, 18px);
  height: calc(100vh - var(--chrome-h) - clamp(22px, 3.4vw, 40px) * 2);
  min-height: 460px;
}
.deck__col { min-width: 0; min-height: 0; display: grid; }
.deck__col--ticket { grid-template-rows: minmax(0, 1fr); }
.deck__col--list { grid-template-rows: auto auto minmax(0, 1fr); gap: 10px; }

.deck__bar { display: flex; align-items: center; gap: 10px; }
.deck__count { margin-inline-start: auto; font-family: var(--mono); font-size: 13px; color: var(--fg-3); }
.seg--tf .seg__b { padding: 7px 12px; }

.coinlist { max-height: none; min-height: 0; height: 100%; }

.chartbox { max-width: none; height: 100%; display: grid; grid-template-rows: auto minmax(0, 1fr); }
.chartbox__frame { height: auto; min-height: 0; }

/* Track record — lives in .below next to Order history, styled the same
   way, except it caps at four rows and scrolls instead of growing forever. */
.table-wrap[data-tradelog] { max-height: 156px; overflow-y: auto; }
/* Order history runs to fifty rows. Capped and scrolled like the trade log
   above it, with the header staying put, rather than pushing the rest of
   the page down. */
.table-wrap[data-orderlog] { max-height: 264px; overflow-y: auto; }
.table-wrap[data-orderlog] .tbl thead th { position: sticky; top: 0; background: var(--bg-elev); z-index: 1; }
.table-wrap[data-tradelog] .tbl thead th { position: sticky; top: 0; background: var(--bg-elev); z-index: 1; }
.tradelog__pl[data-dir="up"]   { color: var(--gain); }
.tradelog__pl[data-dir="down"] { color: var(--loss); }
.tradelog__reason[data-reason="stop_loss"]   { color: var(--loss); }
.tradelog__reason[data-reason="take_profit"] { color: var(--gain); }

/* ---------- ticket ---------- */

.ticket {
  --cut: var(--cut-md);
  border: 1px solid var(--line); background: var(--bg-elev);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  padding: 14px;
  display: flex; flex-direction: column; gap: 11px;
  overflow-y: auto; min-height: 0;
}
.ticket .seg { width: 100%; }
.ticket .seg__b { flex: 1; text-align: center; padding: 9px 6px; }
.ticket__pair {
  font-family: var(--mono); font-weight: 590; font-size: 17px;
  text-align: center; padding: 2px 0 1px; letter-spacing: -.02em;
}
.ticket .field__input { padding: 9px 11px; font-size: 16px; }
.ticket .field { gap: 5px; }
.ticket__actions { display: grid; grid-template-columns: auto 1fr; gap: 8px; margin-top: 2px; }
.ticket__actions .btn { width: 100%; }
.ticket__out {
  --cut: 5px;
  font-family: var(--mono); font-size: 14px; line-height: 1.55;
  padding: 9px 11px; border: 1px solid var(--line); background: var(--bg-inset); color: var(--fg-2);
  white-space: pre-wrap; overflow-wrap: anywhere; max-height: 150px; overflow-y: auto;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.ticket__out[hidden] { display: none; }
.ticket__out[data-tone="bad"] { border-color: rgba(240,80,58,.45); color: #FF9C8B; }
.ticket__out[data-tone="good"] { border-color: var(--gain-line); color: var(--gain); }
.ticket__warn {
  font-size: 14px; color: var(--warn); line-height: 1.5;
  border: 1px solid rgba(245,165,36,.35); background: rgba(245,165,36,.08); padding: 8px 10px;
}
.ticket__warn[hidden] { display: none; }
.ticket__balance {
  margin-top: auto; padding-top: 11px; border-top: 1px solid var(--line);
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  font-size: 14px; color: var(--fg-3);
}
.ticket__balance b { font-family: var(--mono); font-size: 20px; font-weight: 590; color: var(--fg); }

/* ---------- below the fold ---------- */

.below { display: grid; gap: clamp(14px, 1.6vw, 20px); padding-bottom: 80px; }
.below .connect { max-width: none; }

.table-wrap { overflow-x: auto; border: 1px solid var(--line); background: var(--bg-elev); }
.tbl { width: 100%; border-collapse: collapse; font-size: 15px; min-width: 560px; }
.tbl th {
  text-align: start; font-family: var(--techno); font-size: 13px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--fg-3); font-weight: 400;
  padding: 11px 14px; border-bottom: 1px solid var(--line); white-space: nowrap;
}
.tbl td { padding: 11px 14px; border-bottom: 1px solid var(--line); color: var(--fg-2); }
.tbl tr:last-child td { border-bottom: 0; }
.tbl__num { font-family: var(--mono); }
.tbl__empty { color: var(--fg-3); text-align: center; padding: 26px 14px; }
.tbl__up { color: var(--gain); font-family: var(--mono); }
.tbl__down { color: var(--loss); font-family: var(--mono); }

@media (max-width: 1180px) {
  .deck { grid-template-columns: 280px minmax(0,1fr); grid-template-rows: minmax(0,1fr) auto; height: auto; }
  .deck__col--ticket { grid-column: 1 / -1; }
  .ticket { overflow: visible; }
  .coinlist { height: 420px; }
  .chartbox { height: 460px; }
}
@media (max-width: 820px) {
  .deck { grid-template-columns: 1fr; }
  .view--screener { grid-template-rows: auto auto; }
}

/* ---------- lightweight chart ---------- */

.chartbox__frame { position: relative; display: block; }
.chartbox__canvas { position: absolute; inset: 0; }
.chartbox__empty {
  position: absolute; inset: 0; display: grid; place-items: center;
  color: var(--fg-3); font-size: 16px; pointer-events: none;
}
.chartbox__empty[hidden] { display: none; }

.seg--int { margin-inline-start: auto; }
.seg--int .seg__b { padding: 6px 9px; font-size: 13px; }

/* The bar aligns on the baseline, which has nothing to say about an icon —
   centre these two on their own. */
.seg--layout { align-self: center; flex: none; }
.seg--layout .seg__b { padding: 6px 8px; display: grid; place-items: center; }

/* ---------- four-up terminal ---------- */

/* Occupies the same grid row as the single frame; only ever one of the two
   is displayed, so switching leaves the bar above it exactly where it was.
   The 1px gap over a line-coloured ground draws the hairlines between panes
   without four separate borders doubling up. */
.multi {
  display: none;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 1px; background: var(--line);
  min-width: 0; min-height: 0;
}
.chartbox[data-layout="4"] .multi { display: grid; }
.chartbox[data-layout="4"] .chartbox__frame { display: none; }
/* The bar's interval picker drives the single chart. In four-up each pane
   carries its own, so this one has nothing left to control. */
.chartbox[data-layout="4"] .seg--int { display: none; }
.chartbox[data-layout="4"] .chartlevels { display: none; }

/* Read-only Target/Entry/Stop/R:R strip under the chart -- the always
   -legible version of what the on-chart overlay already draws and lets
   you drag. Hidden whenever the overlay itself has nothing to show. */
.chartlevels {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  border-top: 1px solid var(--line); flex: none;
}
.chartlevels[hidden] { display: none; }
.chartlevels__cell {
  padding: 12px 16px; border-inline-end: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 7px; min-width: 0;
}
.chartlevels__cell:last-child { border-inline-end: 0; }
.chartlevels__label {
  display: flex; align-items: center; gap: 7px;
  font-family: var(--mono); font-size: 13px; letter-spacing: -.02em;
  text-transform: uppercase; color: var(--fg-3);
}
.chartlevels__dot { width: 6px; height: 6px; border-radius: 999px; flex: none; background: var(--fg-3); }
.chartlevels__dot[data-dot="target"] { background: var(--gain); }
.chartlevels__dot[data-dot="entry"]  { background: #bcbcc6; }
.chartlevels__dot[data-dot="stop"]   { background: var(--loss); }
.chartlevels__value {
  font-family: var(--mono); font-size: 17px; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums; color: var(--fg);
}
.chartlevels__cell:nth-child(1) .chartlevels__value { color: var(--gain); }
.chartlevels__cell:nth-child(3) .chartlevels__value { color: var(--loss); }

.mini {
  display: grid; grid-template-rows: auto minmax(0, 1fr);
  min-width: 0; min-height: 0;
  background: #0a0a0a;
}
.mini__bar {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 8px; border-bottom: 1px solid var(--line); background: rgba(0,0,0,.22);
}
.mini__pair {
  font-family: var(--mono); font-size: 13px; font-weight: 590; color: var(--fg-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mini__int {
  margin-inline-start: auto; flex: none;
  font-family: var(--mono); font-size: 13px; font-weight: 590;
  color: var(--fg-2); background: var(--bg-inset);
  border: 1px solid var(--line); padding: 2px 4px; cursor: pointer;
}
.mini__int:focus-visible { outline: 1px solid var(--accent-line); outline-offset: 1px; }

.mini__frame { position: relative; min-width: 0; min-height: 0; }
.mini__canvas { position: absolute; inset: 0; }
.mini__empty {
  position: absolute; inset: 0; margin: 0;
  display: grid; place-items: center;
  font-size: 14px; color: var(--fg-3); text-align: center; padding: 0 10px;
}
.mini__empty[hidden] { display: none; }
.chartbox__chg { margin-inline-start: 0; }

.chartlegend {
  position: absolute; inset-inline-start: 12px; top: 10px; z-index: 3;
  display: flex; gap: 12px; pointer-events: none;
}
.chartlegend__i {
  display: none; align-items: center; gap: 5px;
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
  background: rgba(9,9,9,.72); padding: 3px 7px; border: 1px solid var(--line);
}
.chartlegend__i[data-on="true"] { display: inline-flex; }
.chartlegend__i::before { content: ''; width: 12px; height: 2px; }
.chartlegend__i[data-leg="entry"]::before  { background: #bcbcc6; }
.chartlegend__i[data-leg="stop"]::before   { background: var(--loss); }
.chartlegend__i[data-leg="target"]::before { background: var(--gain); }

/* ---------- live positions, under the ticket ---------- */

/* Flat list, not a card -- matches the coin list and guard card's own
   restraint. Component 9 in the handoff: header row with the aggregate
   P&L, then plain rows separated by a single hairline, no per-row surface
   or accent bar. */
.livepos {
  border: 0; background: none;
  display: grid; grid-template-rows: auto minmax(0, 1fr); min-height: 0;
}
.livepos__bar {
  display: flex; align-items: center; gap: 10px;
  padding: 0 0 10px; border-bottom: 1px solid var(--line); background: none;
}
.livepos__title {
  font-family: var(--mono); font-size: 14px; letter-spacing: .08em;
  text-transform: uppercase; color: var(--fg-3);
}
.livepos__pnl { margin-inline-start: auto; font-family: var(--mono); font-size: 15px; font-weight: 590; font-variant-numeric: tabular-nums; }
.livepos__pnl[data-dir="up"] { color: var(--gain); }
.livepos__pnl[data-dir="down"] { color: var(--loss); }

.livepos__body { overflow-y: auto; min-height: 0; padding: 0; display: grid; gap: 0; align-content: start; }
.livepos__empty { color: var(--fg-3); font-size: 15px; padding: 20px 0; }

.posrow {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 0; background: none; border: 0; border-top: 1px solid var(--line);
  transition: background-color .14s;
}
.posrow:hover { background: rgba(255,255,255,.02); }
.posrow__row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.posrow__sym { font-family: var(--mono); font-size: 15px; font-weight: 590; letter-spacing: .01em; color: var(--fg); }
.posrow__pnl { font-family: var(--mono); font-size: 15px; font-weight: 590; font-variant-numeric: tabular-nums; }
.posrow__pnl[data-dir="up"] { color: var(--gain); }
.posrow__pnl[data-dir="down"] { color: var(--loss); }
.posrow__meta {
  font-family: var(--mono); font-size: 13px; letter-spacing: -.02em;
  text-transform: uppercase; color: var(--fg-3); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 1180px) {
  .deck__col--ticket { grid-template-rows: auto auto; }
  .livepos { min-height: 220px; }
}

/* ---------- ticket fixes ---------- */

/* .field is display:grid, which was overriding the hidden attribute and
   leaving the limit-price box on screen for market orders. */
.field[hidden] { display: none; }

.seg--int { flex-wrap: wrap; justify-content: flex-end; }
.seg--int .seg__b { padding: 5px 7px; font-size: 13px; }

/* the action button takes the colour of the side being traded */
.btn--go[data-side="sell"] { --btn-bg: var(--loss); --btn-fg: #0c0c0c; }
.btn--go[data-side="sell"]:hover { --btn-bg: #FF6A55; }
.btn--go[data-side="buy"] { --btn-bg: var(--gain); --btn-fg: #0c0c0c; }
.btn--go[data-side="buy"]:hover { --btn-bg: #19d98b; }

.ticket__balance--sub { padding-top: 0; border-top: 0; margin-top: -6px; }
.ticket__balance--sub b { font-size: 15px; color: var(--fg-2); }

/* ---------- position overlay (TradingView Long Position style) ----------
   Palette matches TradingView's own tool exactly, sampled from the user's
   own chart: blue entry, teal target, orange stop -- not red. */

.poslayer { position: absolute; inset: 0; pointer-events: none; z-index: 4; overflow: hidden; }

/* the shaded band between entry and each exit */
.poszone { position: absolute; left: 0; right: 0; display: none; }
.poszone[data-on="true"] { display: block; }
.poszone--reward { background: rgba(8,153,129,.12);  border-top: 1px solid rgba(8,153,129,.35);   border-bottom: 0; }
.poszone--risk   { background: rgba(255,152,0,.09);  border-bottom: 1px solid rgba(255,152,0,.35); border-top: 0; }

/* the pill that rides on each line -- just the $ made/lost there, and on
   entry a close button. No tag, no price: the axis already shows the price
   via the line itself, so a second copy of it here would be noise. */
.poscard {
  position: absolute; inset-inline-end: 78px;
  display: none; align-items: center; gap: 6px;
  padding: 3px 8px; transform: translateY(-50%);
  border-radius: 3px;
  font-family: var(--mono); font-size: 13px; font-weight: 590; line-height: 1.2;
  background: rgba(9,9,9,.92); border: 1px solid var(--line-strong);
  white-space: nowrap;
}
.poscard[data-on="true"] { display: inline-flex; }
.poscard__pl { font-weight: 590; }

.poscard--entry  { border-color: #2962FF; pointer-events: auto; }
.poscard--entry  .poscard__pl[data-dir="up"]   { color: var(--fg-2); }
.poscard--entry  .poscard__pl[data-dir="down"] { color: #FF9800; }

.poscard--target { border-color: var(--line-strong); }
.poscard--target .poscard__pl { color: var(--fg-2); }

.poscard--stop   { border-color: #FF9800; }
.poscard--stop   .poscard__pl { color: #FF9800; }

/* risk : reward badge */
.posrr {
  position: absolute; inset-inline-end: 74px; top: 10px;
  display: none; padding: 4px 9px;
  font-family: var(--mono); font-size: 13px; font-weight: 590;
  background: rgba(9,9,9,.9); border: 1px solid var(--line-strong); color: var(--fg-2);
}
.posrr[data-on="true"] { display: block; }
.posrr b { color: var(--fg-2); }

/* ---------- dragging the levels ---------- */

.posgrab {
  position: absolute; left: 0; right: 0; height: 15px;
  transform: translateY(-50%);
  display: none; cursor: ns-resize; pointer-events: auto;
  touch-action: none;
}
.posgrab[data-on="true"] { display: block; }
.posgrab:hover::after {
  content: ''; position: absolute; left: 0; right: 0; top: 50%;
  height: 3px; transform: translateY(-50%);
  background: rgba(255,255,255,.16);
}

.pospull {
  position: absolute; inset-inline-end: 78px;
  transform: translateY(-50%);
  display: none; align-items: center; justify-content: center;
  min-width: 30px; padding: 3px 7px;
  font-family: var(--techno); font-size: 13px; letter-spacing: .1em;
  background: rgba(9,9,9,.92); border: 1px dashed var(--line-strong); color: var(--fg-3);
  cursor: ns-resize; pointer-events: auto; touch-action: none; user-select: none;
}
.pospull[data-on="true"] { display: inline-flex; }
.pospull:hover { color: var(--fg); border-style: solid; }
.pospull[data-pull="target"]:hover { border-color: var(--line-strong); color: var(--fg-2); }
.pospull[data-pull="stop"]:hover   { border-color: #FF9800; color: #FF9800; }

/* while a level is being dragged the chart should not pan underneath */
.chartbox[data-dragging="true"] .chartbox__canvas { pointer-events: none; }
.chartbox[data-dragging="true"] { cursor: ns-resize; }

/* close/remove button, on each pill -- a small solid chip in the line's own
   colour (a colourless icon on a near-black pill was too faint to read) */
.poscard__x {
  display: none; place-items: center;
  width: 22px; height: 22px; margin-inline-start: 3px;
  color: #070707; border: 0; border-radius: 4px;
  cursor: pointer; pointer-events: auto;
  transition: opacity .14s;
}
.poscard__x[data-on="true"] { display: grid; }
.poscard__x:hover { opacity: .8; }
.poscard__x:active { transform: scale(.94); }

.poscard--entry  .poscard__x { background: #2962FF; }
.poscard--target .poscard__x { background: var(--btn-neutral-hi); }
.poscard--stop   .poscard__x { background: #FF9800; }

/* The grab strips come later in the DOM and were covering the close button,
   so the cards are lifted above them. */
.poscard { z-index: 3; }
.posgrab { z-index: 2; }
.poscard__x { position: relative; z-index: 4; }

/* close button on each open-position row -- its own flex column now
   (see .posrow above), not absolutely positioned over the text */
.posrow__x {
  flex: none;
  width: 24px; height: 24px; display: grid; place-items: center;
  background: var(--loss); border: 1px solid #FF7A66; border-radius: 3px;
  color: #FFFFFF; cursor: pointer; opacity: .55;
  transition: opacity .14s, background-color .14s, transform .14s;
}
.posrow:hover .posrow__x, .posrow__x:focus-visible { opacity: 1; }
.posrow__x:hover { background: #FF6A55; transform: scale(1.1); }
.posrow__body {
  flex: 1; min-width: 0; display: grid; gap: 4px;
  text-align: start; background: none; border: 0; color: inherit;
  font: inherit; cursor: pointer; padding: 0;
}

/* ---------- neon-glass chart ---------- */

/* A navy wash behind the canvas so the candle glow blooms into something
   rather than dying on flat black. */
/* Chart ground, dropped a shade to sit under the darkened red. Deep enough
   that both candle colours keep their separation from it without either one
   having to be brighter than the other. */
.chartbox__frame { background: var(--bg-elev); }

/* the position overlay sits above the glow and must stay crisp */
.poslayer { mix-blend-mode: normal; }

/* ---------- candle palette ----------
   Green sits at 80% saturation, the red-magenta a notch lower at 76%. Its hue
   is 350 rather than 342 — far enough round to read as red while keeping the
   magenta undertone. Brightness is solved on each so they stay close to each
   other — green glares first on a dark screen, so it is the
   one held back. Wicks take the body colour, lifted a step so a thin one does
   not disappear against the ground. */
:root {
  --candle-up:        #19d98b;
  --candle-up-wick:   #19d98b;
  --candle-down:      #ff2d8f;
  --candle-down-wick: #ff5ba8;
}


/* ---------- live gainers ticker ---------- */

/* Sits at the top of the page and stays there — deliberately NOT sticky, so
   scrolling leaves it behind rather than dragging a moving strip down the
   screen over the chart.
   .ticker[hidden] needs saying out loud: display:flex would otherwise beat
   the hidden attribute and the empty strip would show before data lands. */
.ticker {
  height: var(--ticker-h);
  display: flex; align-items: center;
  background: rgba(12,12,12,.86);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border-bottom: 1px solid var(--line);
  overflow: hidden;
}
.ticker[hidden] { display: none; }

/* No feathered ends. The mask faded the first and last 56px of the strip,
   which dimmed whichever coin happened to be passing through them. */
.ticker__rail {
  flex: 1; min-width: 0; overflow: hidden;
}

.ticker__track {
  display: flex; align-items: center; width: max-content;
  animation: ticker-run var(--ticker-dur, 60s) linear infinite;
  will-change: transform;
  /* Held back at rest. Moving text beside a chart is the most distracting
     thing on a trading screen, and the chart is what the screen is for. This
     is the one dimmer — the colours underneath stay at full strength, so it
     reads as a step back rather than as washed out. */
  opacity: .78;
  transition: opacity .22s ease;
}
/* Reach for it and it comes forward and holds still, so a coin can actually
   be read and clicked. The two go together on purpose. */
.ticker:hover .ticker__track,
.ticker:focus-within .ticker__track {
  animation-play-state: paused;
  opacity: 1;
}

.ticker__set { display: flex; align-items: center; }

/* The track carries the same list twice, so -50% lands exactly on the start
   of the second copy and the loop repeats with no seam to see. */
@keyframes ticker-run {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .ticker__track { animation: none; }
  .ticker__rail { overflow-x: auto; }
}

.tick {
  display: inline-flex; align-items: center; gap: 7px;
  flex: none;
  height: var(--ticker-h); padding: 0 13px;
  background: none; border: 0; color: var(--fg-2); font: inherit;
  white-space: nowrap; cursor: pointer;
  transition: color .14s;
}
/* No resting dim. The strip used to sit at --fg-3 and only lift to
   --fg-2 when the cursor entered it, so the coins looked faded until you
   hovered and the whole row changed brightness under the pointer. They
   read at full strength all the time; only the one under the cursor
   lifts further. */
.tick:hover { color: var(--fg); }
.tick:focus-visible { outline: 1px solid var(--accent-line); outline-offset: -3px; }
.tick__logo {
  width: 16px; height: 16px; flex: none;
  border-radius: 50%; object-fit: contain; background: var(--bg-elev-2);
}
.tick__sym { font-family: var(--mono); font-size: 14px; font-weight: 590; }
.tick__chg { font-family: var(--mono); font-size: 14px; font-weight: 590; color: var(--gain); }

@media (max-width: 860px) {
  :root { --ticker-h: 30px; }
  .tick { padding: 0 10px; gap: 6px; }
}

/* ---------- squawk ---------- */

.view--squawk { padding-bottom: 60px; }

/* Meters on the left, feed on the right. The rail is a fixed width because
   the gauges are drawn at a fixed size; the feed takes whatever is left. */
.squawkpage {
  display: grid; grid-template-columns: 258px minmax(0, 1fr);
  gap: clamp(16px, 1.8vw, 26px);
  align-items: start;
}
@media (max-width: 900px) {
  .squawkpage { grid-template-columns: 1fr; }
}

/* ---- meters rail ---- */

.pulse { display: grid; gap: 10px; position: sticky; top: 78px; }
@media (max-width: 900px) { .pulse { position: static; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); } }

.meter {
  --cut: 8px;
  border: 1px solid var(--line); background: var(--bg-elev);
  padding: 14px 15px 15px;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
.meter__head {
  font-family: var(--techno); font-size: 13px; letter-spacing: .15em; text-transform: uppercase;
  color: var(--fg-3); margin-bottom: 10px;
}
.meter__big {
  font-family: var(--mono); font-size: 24px; font-weight: 590; line-height: 1;
  letter-spacing: -.02em; color: var(--fg);
}
.meter__label { font-size: 14px; color: var(--fg-2); margin-top: 3px; }
.meter__sub {
  font-family: var(--mono); font-size: 13px; color: var(--fg-3); margin-top: 8px; line-height: 1.5;
}

/* Fear & Greed dial. The arc is one path with a dash offset, so the sweep is
   the value — no second element to keep in sync. */
.gauge { display: block; margin: 0 auto 2px; }
.gauge__track { stroke: rgba(255,255,255,.07); }
.gauge__fill { transition: stroke-dasharray .5s ease, stroke .5s ease; }
.gauge__pin { transition: cx .5s ease, cy .5s ease, fill .5s ease; }
.gauge__val {
  font-family: var(--mono); font-size: 22px; font-weight: 590;
  fill: var(--fg); text-anchor: middle;
}

/* Split bars: dominance and breadth both read as "this share of a whole". */
.bar {
  display: flex; height: 7px; overflow: hidden; margin: 4px 0 9px;
  background: rgba(255,255,255,.06);
}
.bar__seg { height: 100%; transition: width .5s ease; }
.bar__seg[data-k="btc"]  { background: #F7931A; }
.bar__seg[data-k="eth"]  { background: #8A92B2; }
.bar__seg[data-k="alt"]  { background: var(--accent); }
.bar__seg[data-k="up"]   { background: var(--gain); }

.legend { display: grid; gap: 4px; }
.legend__row {
  display: flex; align-items: center; gap: 7px;
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
}
.legend__dot { width: 7px; height: 7px; flex: none; }
.legend__dot[data-k="btc"] { background: #F7931A; }
.legend__dot[data-k="eth"] { background: #8A92B2; }
.legend__dot[data-k="alt"] { background: var(--accent); }
.legend__v { margin-inline-start: auto; color: var(--fg-2); font-weight: 590; }

.meter__skel { height: 92px; border: 1px solid var(--line); background: var(--bg-elev); opacity: .5; }

/* ---- the feed ---- */

.squawkbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.squawk__note { font-family: var(--mono); font-size: 13px; color: var(--fg-3); margin-inline-end: auto; }
.squawk__note[data-busy] { color: var(--accent); }
.squawk__note[data-busy]::after {
  content: ''; display: inline-block; width: 5px; height: 5px; border-radius: 50%;
  background: currentColor; margin-inline-start: 7px; vertical-align: middle;
  animation: squawk-pulse 1.1s ease-in-out infinite;
}
@keyframes squawk-pulse { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }

.squawk__filters { display: inline-flex; gap: 0; }

/* One dense run of rules, board-style — the eye scans headlines down a
   single column. The 1px gaps over a line-coloured ground draw the rules
   without every row carrying its own border. */
.squawk {
  display: grid; gap: 1px;
  background: var(--line); border: 1px solid var(--line);
}

.squawk__item {
  position: relative;
  display: grid; gap: 5px;
  padding: 12px 15px 12px 17px;
  background: var(--bg-elev);
  transition: background-color .14s;
}
.squawk__item:hover { background: var(--bg-elev-2); }

/* Accent edge marks a story about a coin on today's scan. */
.squawk__item[data-hot="true"]::before {
  content: ''; position: absolute; inset-block: 0; inset-inline-start: 0;
  width: 2px; background: var(--accent);
}

.squawk__title {
  font-size: 17px; line-height: 1.4; font-weight: 590; letter-spacing: -.01em;
  color: var(--fg); text-decoration: none;
}
.squawk__title:hover { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
/* Whole row is the hit area; the anchor just carries the href. */
.squawk__title::after { content: ''; position: absolute; inset: 0; }

.squawk__meta { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.squawk__src {
  font-family: var(--techno); font-size: 13px; letter-spacing: .15em; text-transform: uppercase;
  color: var(--fg-3);
}
.squawk__coins { display: flex; gap: 5px; flex-wrap: wrap; }

.chip {
  position: relative; z-index: 1;
  font-family: var(--mono); font-size: 13px; font-weight: 590; line-height: 1;
  padding: 3px 6px; color: var(--fg-3);
  border: 1px solid var(--line); background: transparent;
}
/* Only Binance-listed coins open a chart, so only they look pressable. */
.chip--go {
  color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft);
  cursor: pointer; transition: color .14s, background-color .14s, border-color .14s;
}
.chip--go:hover { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); }
.chip--go:focus-visible { outline: 1px solid var(--accent-line); outline-offset: 2px; }

.squawk__empty {
  padding: 48px 24px; text-align: center; color: var(--fg-3);
  font-size: 16px; line-height: 1.6; background: var(--bg-elev);
}

/* The first pull is a real RSS fetch and takes ~18s; blank space that long
   reads as broken. */
.squawk__skel { height: 62px; background: var(--bg-elev); animation: squawk-fade 1.4s ease-in-out infinite; }
.squawk__skel:nth-child(2) { animation-delay: .1s; }
.squawk__skel:nth-child(3) { animation-delay: .2s; }
.squawk__skel:nth-child(4) { animation-delay: .3s; }
.squawk__skel:nth-child(5) { animation-delay: .4s; }
.squawk__skel:nth-child(6) { animation-delay: .5s; }
.squawk__skel:nth-child(7) { animation-delay: .6s; }
.squawk__skel:nth-child(8) { animation-delay: .7s; }
@keyframes squawk-fade { 0%, 100% { opacity: .35; } 50% { opacity: .7; } }

@media (prefers-reduced-motion: reduce) {
  .squawk__skel, .squawk__note[data-busy]::after { animation: none; }
  .gauge__fill, .gauge__pin, .bar__seg { transition: none; }
}


/* ---------- free tier ---------- */

.gate__alt { display: grid; gap: 12px; margin-top: 4px; }
.gate__alt[hidden] { display: none; }

/* Rule with the word sitting in the gap, rather than a line then a word. */
.gate__or {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px;
  font-family: var(--techno); font-size: 13px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--fg-3);
}
.gate__or::before, .gate__or::after { content: ''; height: 1px; background: var(--line); }

.gate__google { display: flex; justify-content: center; min-height: 40px; }
.gate__free { font-size: 14px; color: var(--fg-3); line-height: 1.55; text-align: center; }

/* A locked section stays visible and readable — it is an advert, not an
   error. Dimming it and adding the padlock says "not yours yet" without
   pretending the feature does not exist. */
.navlink[data-locked="true"] { color: var(--fg-3); }
.navlink[data-locked="true"] .navlink__count { display: none; }
.navlink__lock { margin-inline-start: auto; opacity: .55; flex: none; }

.userchip__plan[data-plan="free"] { color: var(--fg-3); }
.userchip__plan[data-plan="paid"] { color: var(--accent); }

.upsell {
  --cut: var(--cut-lg);
  max-width: 560px;
  border: 1px solid var(--accent-line); background: var(--accent-soft);
  padding: clamp(24px, 3.4vw, 40px);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
  display: grid; gap: 14px; justify-items: start;
}
.upsell__tag {
  /* Was 7px, which is unreadable at any contrast, and the canvas accent,
     which only clears 3.0 against the bone card. */
  font-family: var(--techno); font-size: 13px; letter-spacing: .18em;
  text-transform: uppercase;
  color: #b3005c;   /* 5.89 on #eeeeee */
}
.upsell__h { font-size: 22px; letter-spacing: -.03em; line-height: 1.25; }
.upsell__p { color: var(--fg-2); line-height: 1.65; font-size: 17px; }
.upsell__list { display: grid; gap: 8px; padding: 0; margin: 4px 0 6px; list-style: none; }
.upsell__list li {
  position: relative; padding-inline-start: 20px;
  color: var(--fg-2); font-size: 16px; line-height: 1.5;
}
.upsell__list li::before {
  content: ''; position: absolute; inset-inline-start: 0; top: .52em;
  width: 7px; height: 7px; background: var(--accent);
}


/* ==========================================================================
   HYPERSTUDIO — members area
   Same obsidian canvas, hairlines and weight-400 type as the landing page.
   ========================================================================== */

:root {
  --bg:          #101010;
  --bg-elev:     #141414;
  --bg-elev-2:   #191919;
  --bg-inset:    #080808;
  --line:        #212121;
  --line-strong: #3f3f3f;
  --fg:          #f3f3f3;
  --fg-2:        #c1c1c1;
  --fg-3:        #8e8e9a;
  /* Series that are neither a gain nor a loss -- see DESIGN.md. */
  --chart-blue:     #6b9fd4;
  --chart-blue-dim: #3f5f80;

  /* ---- Carbon + magenta ----
     styles.css carries the Factory palette, which is warm: its lifts are
     brown-greys (#131313, #181818) and its one accent is Signal Orange,
     doing double duty as loss. Under a page of charts that warmth reads
     as a colour cast, and an accent that is also the loss colour means a
     selected filter and a falling price are the same mark.

     So the app runs a neutral carbon ramp with a vivid magenta accent,
     and gain and loss get their own vivid pair. The marketing site is
     untouched -- it has its own stylesheet. */

  --bg:          #0c0c0c;
  --bg-elev:     #131313;
  --bg-elev-2:   #1a1a1a;
  --bg-inset:    #080808;
  --bg-card:     #131313;
  --line:        #242424;
  --line-strong: #3e3e3e;
  --btn:         #1d1d1d;
  --btn-neutral:    #1d1d1d;
  --btn-neutral-hi: #282828;

  --fg:   #f4f4f6;
  --fg-2: #bcbcc6;

  --accent:      #ff2d8f;
  --accent-hi:   #ff5ba8;
  --accent-soft: rgba(255,255,255,0.06);
  --accent-line: rgba(255,255,255,0.08);
  --accent-ink:  #0e0e0e;

  /* Gain and loss are their own pair rather than borrowing the accent, so
     a falling price never looks like a selected control. */
  --gain:      #19d98b;
  --gain-soft: rgba(255,255,255,0.05);
  --gain-line: rgba(255,255,255,0.08);
  --loss:      #ff3d63;
  --warn:      #ffb020;

  --candle-up:        #19d98b;
  --candle-up-wick:   #19d98b;
  --candle-down:      #ff2d8f;
  --candle-down-wick: #ff5ba8;
  --shadow-sm: none; --shadow-md: none; --shadow-lg: none;
  --cut-sm: 0px; --cut-md: 0px; --cut-lg: 0px;
}

body { background: var(--bg); }

/* ---- chrome ---- */
.side { background: var(--bg); border-inline-end: 1px solid var(--line); }
.topbar { background: rgba(12,12,12,.86); border-bottom: 1px solid var(--line); }
.topbar h1 { font-weight: 400; letter-spacing: -.011em; font-size: 19px; }

/* Michroma is retired here as on the landing page; mono is the meta voice. */
.side__group, .field__label, .seg__b, .plane__venue, .chartbox__venue,
.deck__count, .tbl thead th, .ticket__pair, .userchip__plan, .navlink__count {
  font-family: var(--mono); letter-spacing: -.022em; text-transform: none;
  font-weight: 400;
}
.side__group { font-size: 14px; color: var(--fg-3); }
.field__label { font-size: 14px; color: var(--fg-3); }

.navlink {
  clip-path: none; border-radius: 4px;
  font-weight: 400; color: var(--fg-3);
}
.navlink:hover { background: rgba(255,255,255,.03); color: var(--fg); }
.navlink[aria-current="page"] {
  background: rgba(255,255,255,.05); border-color: var(--line-strong); color: var(--fg);
}
.navlink[aria-current="page"] svg { color: var(--fg); }

/* ---- panels: hairline, no chamfer, no shadow ---- */
.chartbox, .ticket, .card, .coinlist, .table-wrap, .connect, .meter,
.squawk__item, .room-card, .statbox, .sig, .course, .upsell {
  clip-path: none; border-radius: 8px;
  border: 1px solid var(--line); background: var(--bg-elev);
  box-shadow: none;
}
.chartbox__bar, .deck__bar { background: none; border-bottom: 1px solid var(--line); }
.chartbox__frame, .plane--chart { background: var(--bg-elev); }

/* ---- controls ---- */
.seg { border: 1px solid var(--line); border-radius: 4px; overflow: hidden; }
.seg__b { font-size: 14px; padding: 8px 12px; color: var(--fg-3); background: none; }
.seg__b:hover { color: var(--fg); background: rgba(255,255,255,.03); }

/* Active state reads as light on dark rather than a colour fill — except for
   side, which stays green/red because that is what stops a mis-click. */
.seg__b[aria-pressed="true"] { background: #f3f3f3; color: #101010; }
.seg--side .seg__b--buy[aria-pressed="true"]  { background: #19d98b; color: #0c0c0c; }
.seg--side .seg__b--sell[aria-pressed="true"] { background: #ff3d63; color: #0c0c0c; }

.btn { border-radius: 9999px; clip-path: none; font-family: var(--mono);
       letter-spacing: -.022em; font-weight: 400; text-transform: none; }
.btn--primary { background: #ffffff; color: #101010; border: 0; }
.btn--primary:hover { background: #e6e6e6; }
.btn--ghost { background: none; color: var(--fg); border: 1px solid var(--line-strong); }
.btn--ghost:hover { border-color: var(--fg-3); }

.field__input, select.field__input {
  border-radius: 4px; background: var(--bg-inset);
  border: 1px solid var(--line); color: var(--fg);
  font-family: var(--mono); letter-spacing: -.022em;
}
.field__input:focus { border-color: var(--fg-3); outline: none; }

/* ---- coin list ---- */
.coinrow {
  clip-path: none; border-radius: 4px; color: var(--fg-3);
  border-inline-start: 2px solid transparent;
}
.coinrow:hover { background: rgba(255,255,255,.03); color: var(--fg); }
.coinrow[aria-selected="true"] {
  background: rgba(255,255,255,.06); border-color: var(--line-strong); color: var(--fg);
}
.coinrow__sym { font-weight: 400; color: var(--fg); }

/* ---- market semantics stay coloured; everything else goes quiet ---- */
.coinrow__chg[data-dir="up"],  .tradelog__pl[data-dir="up"]   { color: #19d98b; }
.coinrow__chg[data-dir="down"], .tradelog__pl[data-dir="down"] { color: #ff6b88; }

/* ---- tables ---- */
.tbl thead th { background: none; border-bottom: 1px solid var(--line); color: var(--fg-3); font-size: 14px; }
.tbl td { border-top: 1px solid var(--line); }

/* ---- chips, tags, pills ---- */
.chip, .pill, .tagfree, .tagpaid, .navlink__lock {
  border-radius: 4px; background: none;
  border: 1px solid var(--line-strong); color: var(--fg-3);
}

/* ---- gate ---- */
.gate { background: var(--bg); }
.gate__card { clip-path: none; border-radius: 8px; border: 1px solid var(--line); background: var(--bg-elev); box-shadow: none; }
.gate__title { font-weight: 400; letter-spacing: -.011em; }

/* Nothing in this app casts a shadow. */
.card, .ticket, .chartbox, .poscard, .meter, .gate__card, .side { box-shadow: none; }

/* The scan reaches further than the ticket. Coins it cannot fill stay in the
   list — finding them is the point — but read a step back. */
.coinrow[data-tradeable="false"] { opacity: .58; }
.coinrow[data-tradeable="false"]:hover,
.coinrow[data-tradeable="false"][aria-selected="true"] { opacity: 1; }
.chartbox__venue[data-src="market"] { color: var(--fg-3); }

/* The ticket's action row is a two-column grid; anything else dropped into it
   becomes a third cell and squeezes the buttons. The warning sits above it. */
.ticket__warn[data-nospot-warn] {
  border-radius: 4px;
  margin: 0;
  font-size: 15px;
  line-height: 1.5;
}
/* A disabled action should read as unavailable, not as a filled button that
   simply ignores the click. */
.ticket__actions .btn:disabled {
  opacity: .4; cursor: not-allowed;
  background: none; color: var(--fg-3); border: 1px solid var(--line);
}

/* ---- order button: one action, rectangular, coloured by side ----
   Preview is gone, so the row is a single full-width control. Square corners
   rather than the pill: this is the one button in the app that commits
   something, and it should not look like a nav chip. */
.ticket__actions { grid-template-columns: 1fr; }

.btn--go {
  border-radius: 4px;
  padding: 14px 18px;
  font-size: 17px;
  border: 0;
  background: #ffffff;
  color: #101010;
}
.btn--go:hover { background: #e6e6e6; }

.ticket__actions .btn--go:disabled {
  background: none; color: var(--fg-3);
  border: 1px solid var(--line); border-radius: 4px;
}


/* ---- Real mode: the live DEX quote ---- */

.swapq {
  display: grid; gap: 0;
  border: 1px solid var(--line); border-radius: 4px;
  background: var(--bg-inset);
}
.swapq[hidden] { display: none; }

.swapq__row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 9px 12px;
  border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: 14px; letter-spacing: -.022em;
}
.swapq__row:first-child { border-top: 0; }
.swapq__row span { color: var(--fg-3); }
.swapq__row b { color: var(--fg-2); font-weight: 400; text-align: end; overflow-wrap: anywhere; }
.swapq__row--lead { padding-block: 12px; }
.swapq__row--lead b { color: var(--fg); font-size: 18px; }

/* Price impact is the number that decides whether a small-cap is tradeable at
   all, so it is coloured by severity rather than left as plain text. */
.swapq__row b[data-impact="ok"]   { color: #19d98b; }
.swapq__row b[data-impact="warn"] { color: #F5A524; }
.swapq__row b[data-impact="bad"]  { color: #ff6b88; }

.swapq__warn {
  margin: 0; padding: 10px 12px;
  border-top: 1px solid var(--line);
  font-size: 14px; line-height: 1.5;
  color: #F5A524;
}
.swapq__warn[data-level="danger"] { color: #ff6b88; }
.swapq__warn[hidden] { display: none; }

.swapq--loading { opacity: .5; }


/* ---- exchange connections ---- */

.blockhead__note { font-family: var(--mono); font-size: 14px; color: var(--fg-3); }

.exlist { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }

.exrow {
  display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 14px; align-items: center;
  padding: 15px 17px; background: var(--bg-elev);
}
.exrow__name { display: flex; align-items: baseline; gap: 10px; }
.exrow__name b { font-size: 17px; font-weight: 400; color: var(--fg); }
.exrow__cov { font-family: var(--mono); font-size: 14px; color: var(--fg-3); }
.exrow__note { font-size: 15px; color: var(--fg-3); line-height: 1.5; margin: 4px 0 0; max-width: 62ch; }

.exrow__state {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--mono); font-size: 14px; color: var(--fg-3);
}
.exrow__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--line-strong); }
.exrow[data-on="true"] .exrow__dot { background: #19d98b; }
.exrow[data-on="true"] .exrow__state { color: var(--fg-2); }

/* Which venue an order would go to. Answered before anyone commits, so the
   ticket never fails at submission with a surprise. */
.routeline {
  margin: 0; padding: 9px 12px;
  border: 1px solid var(--line); border-radius: 4px; background: var(--bg-inset);
  font-family: var(--mono); font-size: 14px; line-height: 1.5; color: var(--fg-3);
}
.routeline[hidden] { display: none; }
.routeline b { color: var(--fg); font-weight: 400; }
.routeline[data-state="none"] { color: #F5A524; border-color: rgba(245,165,36,.35); }


/* ---- connect dialog ---- */

.exdlg {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center; padding: 22px;
  background: rgba(8,8,8,.82); backdrop-filter: blur(6px);
}
.exdlg[hidden] { display: none; }
.exdlg__card {
  position: relative; width: min(420px, 100%);
  display: grid; gap: 13px;
  background: var(--bg-elev); border: 1px solid var(--line); border-radius: 8px;
  padding: 26px;
}
.exdlg__x {
  position: absolute; top: 14px; inset-inline-end: 14px;
  background: none; border: 0; color: var(--fg-3); cursor: pointer; padding: 4px;
}
.exdlg__x:hover { color: var(--fg); }
.exdlg__title { font-size: 20px; font-weight: 400; margin: 0; }
.exdlg__lede { font-size: 15px; line-height: 1.6; color: var(--fg-3); margin: 0; }
.exdlg__lede b { color: var(--fg-2); font-weight: 400; }


/* ---- token identity + depth, above the buy button ---- */

.tokenbox {
  display: grid; gap: 6px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 4px; background: var(--bg-inset);
  font-family: var(--mono); font-size: 14px;
}
.tokenbox[hidden] { display: none; }
.tokenbox__kicker {
  display: flex; align-items: center; gap: 7px;
  font-size: 13px; letter-spacing: .02em; text-transform: uppercase; color: var(--fg-3);
}
.tokenbox__dot { width: 6px; height: 6px; border-radius: 999px; background: var(--gain); flex: none; }
/* Same verdict the card's own background is about to carry. */
.tokenbox[data-verdict="blocked"] .tokenbox__dot { background: var(--loss); }
.tokenbox__row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.tokenbox__chain { color: var(--fg); }
.tokenbox__depth { color: var(--fg-2); }
.tokenbox__row--sub { color: var(--fg-3); }
.tokenbox__addr {
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 60%;
}
.tokenbox__impact[data-level="ok"]   { color: #19d98b; }
.tokenbox__impact[data-level="warn"] { color: #F5A524; }
.tokenbox__impact[data-level="bad"]  { color: #ff5c5c; }
.tokenbox__warn {
  margin: 0; padding-top: 6px; border-top: 1px solid var(--line);
  color: #ff5c5c; line-height: 1.5;
}
.tokenbox__warn[hidden] { display: none; }

/* pool depth, on its screener row -- thin or missing liquidity is exactly
   what makes a coin's advertised volume a lie, so it's flagged here before
   the ticket even loads rather than only after picking the coin. */
.coinrow__pool {
  font-family: var(--mono); font-size: 14px; text-align: end;
  text-transform: uppercase; letter-spacing: -.01em; color: var(--fg-3);
}
.coinrow__pool[data-risk="thin"] { color: var(--warn); }
.coinrow__pool[data-risk="none"] { color: var(--loss); }


/* ---- "this will cost you money" ---- */

.costdlg {
  position: fixed; inset: 0; z-index: 70;
  display: grid; place-items: center; padding: 22px;
  background: rgba(8,8,8,.85); backdrop-filter: blur(6px);
}
.costdlg[hidden] { display: none; }
.costdlg__card {
  width: min(440px, 100%); display: grid; gap: 14px; padding: 26px;
  background: var(--bg-elev); border: 1px solid rgba(255,92,92,.4); border-radius: 8px;
}
.costdlg__title { margin: 0; font-size: 20px; font-weight: 400; color: #ff5c5c; }
.costdlg__lede { margin: 0; font-size: 16px; line-height: 1.6; color: var(--fg-2); }

.costdlg__nums { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
.costdlg__num { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 11px 14px; background: var(--bg-inset); }
.costdlg__k { font-size: 15px; color: var(--fg-3); }
.costdlg__num b { font-family: var(--mono); font-size: 17px; font-weight: 400; color: var(--fg); }
.costdlg__num--bad b { color: #ff5c5c; }

.costdlg__hint {
  margin: 0; padding: 10px 12px; border-radius: 4px;
  background: var(--bg-inset); border: 1px solid var(--line);
  font-size: 15px; line-height: 1.55; color: var(--fg-2);
}
.costdlg__hint[hidden] { display: none; }
.costdlg__actions { display: flex; gap: 10px; justify-content: flex-end; }
.btn--danger { background: #ff5c5c; border-color: #ff5c5c; color: #0b0b0b; }
.btn--danger:hover { filter: brightness(1.08); }


/* Practice vs Real is a venue switch, so it reads as one choice of two
   rather than a toggle with an "on" state. */
.seg--acct { display: grid; grid-template-columns: 1fr 1fr; gap: 0; margin-bottom: 4px; }
.seg--acct .seg__b { width: 100%; }
.seg--acct .seg__b[aria-pressed="true"] { background: var(--fg); color: var(--bg); }

.tokenbox__max { border-top: 1px solid var(--line); padding-top: 6px; margin-top: 2px; }
.tokenbox__max[hidden] { display: none; }
.tokenbox__k { color: var(--fg-3); }
.tokenbox__max b { font-weight: 400; color: var(--fg); }


/* ---- wallet ---- */
.wallet {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 9px 12px; border: 1px solid var(--line); border-radius: 4px;
  background: var(--bg-inset); font-family: var(--mono); font-size: 14px;
}
.wallet[hidden] { display: none; }
.wallet__state { color: var(--fg-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wallet[data-on="true"] .wallet__state { color: #19d98b; }


/* The amount is the loudest thing on the card - it is what the trader is
   actually deciding. */
.swap__amt, .swap__out {
  flex: 1 1 auto; min-width: 0;
  font-family: var(--mono); font-size: 22px; font-weight: 400;
  color: var(--fg); background: none; border: 0; padding: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.swap__amt:focus { outline: none; }
.swap__amt::-webkit-outer-spin-button,
.swap__amt::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.swap__amt { -moz-appearance: textfield; }
.swap__out { color: var(--fg-2); }

.swap__token {
  display: inline-flex; align-items: center; gap: 7px; flex: 0 0 auto;
  padding: 5px 10px 5px 6px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--bg-elev);
}
.swap__token b { font-size: 15px; font-weight: 400; color: var(--fg); }
.swap__logo { width: 20px; height: 20px; border-radius: 50%; object-fit: cover; display: block; }
.swap__logo[hidden] { display: none; }

/* The arrow overlaps both legs so they read as one control, not two boxes. */
.swap__arrow {
  justify-self: center; margin: -9px 0; z-index: 1;
  width: 26px; height: 26px; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 7px;
  background: var(--bg-elev); color: var(--fg-3);
}

.swap__facts {
  margin: 10px 0 0; padding: 11px 13px; display: grid; gap: 6px;
  border: 1px solid var(--line); border-radius: 6px; background: var(--bg-inset);
}
.swap__facts > div { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.swap__facts dt { font-size: 14px; color: var(--fg-3); }
.swap__facts dd { margin: 0; font-family: var(--mono); font-size: 14px; color: var(--fg); }
.swap__facts dd[data-level="ok"]   { color: #19d98b; }
.swap__facts dd[data-level="warn"] { color: #F5A524; }
.swap__facts dd[data-level="bad"]  { color: #ff5c5c; }

.swap__warn {
  margin: 8px 0 0; padding: 9px 12px; border-radius: 4px;
  border: 1px solid rgba(255,92,92,.35); background: rgba(255,92,92,.07);
  font-size: 14px; line-height: 1.5; color: #ff5c5c;
}
.swap__warn[hidden] { display: none; }
.swap__warn[data-level="warn"] {
  color: #F5A524; border-color: rgba(245,165,36,.35); background: rgba(245,165,36,.07);
}


/* ---- swap ----
   Laid out the way every swap the trader has ever used is laid out: what
   leaves on top, what arrives below, the two joined by an arrow, and the
   numbers that decide the trade underneath. Nothing else competes. */

.swap { display: grid; gap: 0; margin: 0 0 12px; }
.swap[hidden] { display: none; }

.swap__leg {
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--bg-inset); padding: 16px 16px 17px;
}
.swap__leg + .swap__leg { margin-top: 0; }

.swap__legtop {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 10px;
}
.swap__k { font-size: 15px; color: var(--fg-3); }
.swap__bal, .swap__chain {
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 55%;
}

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

/* The amount is the loudest thing on the card - it is the decision. */
.swap__amt, .swap__out {
  flex: 1 1 auto; min-width: 0;
  font-family: var(--mono); font-size: 28px; font-weight: 400; line-height: 1.15;
  color: var(--fg); background: none; border: 0; padding: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.swap__amt:focus { outline: none; }
.swap__amt::-webkit-outer-spin-button,
.swap__amt::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.swap__amt { -moz-appearance: textfield; }
.swap__out { color: var(--fg-2); }

/* The token pill never shrinks - a swap where you cannot see what you are
   buying is worse than one with a cramped number. */
.swap__token {
  display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto;
  padding: 6px 13px 6px 7px; border: 1px solid var(--line-strong);
  border-radius: 999px; background: var(--bg-elev);
}
.swap__token b {
  font-size: 16px; font-weight: 400; color: var(--fg);
  white-space: nowrap; max-width: 8ch; overflow: hidden; text-overflow: ellipsis;
}
.swap__logo {
  width: 24px; height: 24px; border-radius: 50%; object-fit: cover;
  display: block; background: var(--bg-inset);
}
.swap__logo[hidden] { display: none; }

/* Overlaps both legs so they read as one control rather than two boxes. */
.swap__arrow {
  justify-self: center; margin: -14px 0; z-index: 2;
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 3px solid var(--bg); border-radius: 11px;
  background: var(--bg-elev); color: var(--fg-2);
  box-sizing: content-box;
}

.swap__facts {
  margin: 12px 0 0; padding: 13px 15px; display: grid; gap: 8px;
  border: 1px solid var(--line); border-radius: 11px; background: var(--bg-inset);
}
.swap__facts > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.swap__facts dt { font-size: 15px; color: var(--fg-3); flex: 0 0 auto; }
.swap__facts dd {
  margin: 0; font-family: var(--mono); font-size: 15px; color: var(--fg);
  flex: 1 1 auto; text-align: right;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.swap__facts dd[data-level="ok"]   { color: #19d98b; }
.swap__facts dd[data-level="warn"] { color: #F5A524; }
.swap__facts dd[data-level="bad"]  { color: #ff5c5c; }

.swap__warn {
  margin: 10px 0 0; padding: 11px 13px; border-radius: 9px;
  border: 1px solid rgba(255,92,92,.35); background: rgba(255,92,92,.08);
  font-size: 15px; line-height: 1.55; color: #ff5c5c;
}
.swap__warn[hidden] { display: none; }
.swap__warn[data-level="warn"] {
  color: #F5A524; border-color: rgba(245,165,36,.35); background: rgba(245,165,36,.08);
}

/* In Real mode the swap IS the ticket, so its button is full width and the
   card owns the panel. */
.view--screener .ticket__actions .btn--go { width: 100%; }

@media (max-width: 1180px) {
  .deck { grid-template-columns: 280px minmax(0,1fr); }
}

.swap__sub {
  margin-top: 6px; font-family: var(--mono); font-size: 14px; color: var(--fg-3);
}

.swap__legtop--tight { margin-top: -4px; margin-bottom: 9px; }
.swap__chainnote { font-family: var(--mono); font-size: 13px; color: var(--fg-3); }
.swap__chainnote[data-level="bad"] { color: #F5A524; }


/* ---- pay-token selector ---- */

.swap__row { position: relative; }

.swap__token--pick { cursor: pointer; color: var(--fg); }
.swap__token--pick:hover { border-color: var(--fg-3); }
.swap__token--pick svg { color: var(--fg-3); flex: 0 0 auto; }

/* A lettered disc rather than a logo: these are the chain's own coins, and a
   wrong logo is worse than an honest initial. */
.swap__coin {
  width: 24px; height: 24px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center;
  background: var(--line); color: var(--fg-2);
  font-family: var(--mono); font-size: 13px; letter-spacing: -.02em;
}

.paymenu {
  position: absolute; z-index: 5; top: calc(100% + 8px); inset-inline-end: 0;
  min-width: 190px; padding: 6px;
  background: var(--bg-elev); border: 1px solid var(--line-strong);
  border-radius: 11px; box-shadow: 0 14px 34px rgba(0,0,0,.5);
  display: grid; gap: 2px;
}
.paymenu[hidden] { display: none; }

.paymenu__item {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 8px 9px; border: 0; border-radius: 7px;
  background: none; color: var(--fg); cursor: pointer; text-align: start;
  font-size: 15px;
}
.paymenu__item:hover { background: var(--bg-inset); }
.paymenu__item[aria-selected="true"] { background: var(--bg-inset); }
.paymenu__item small { margin-inline-start: auto; color: var(--fg-3); font-family: var(--mono); font-size: 13px; }


/* A grid item will not shrink below its content unless told to, so the swap
   card was pushing the ticket column wider than its track and everything past
   the fold - the token pill, the rate values - was being clipped. */
.deck__col { min-width: 0; }
.deck__col--ticket { min-width: 0; overflow-x: hidden; }
.ticket { min-width: 0; }
.swap, .swap__leg, .swap__facts { min-width: 0; max-width: 100%; }
.swap__row { min-width: 0; }
.swap__amt, .swap__out { min-width: 0; }


/* ---- coin art with a chain badge ---- */

.swap__coin { position: relative; width: 24px; height: 24px; flex: 0 0 auto; display: block; }
.swap__coinimg,
.swap__coinletter {
  width: 24px; height: 24px; border-radius: 50%; display: block;
  object-fit: cover; background: var(--line);
}
.swap__coinletter {
  display: grid; place-items: center; color: var(--fg-2);
  font-family: var(--mono); font-size: 13px;
}
.swap__coinbadge {
  position: absolute; inset-block-end: -2px; inset-inline-end: -3px;
  width: 12px; height: 12px; border-radius: 50%;
  border: 1.5px solid var(--bg-elev); background: var(--bg-elev); display: block;
}

.paymenu__item { gap: 10px; }
.paymenu__name { display: grid; line-height: 1.25; }
.paymenu__name b { font-weight: 400; font-size: 15px; color: var(--fg); }
.paymenu__name em {
  font-style: normal; font-family: var(--mono); font-size: 13px; color: var(--fg-3);
}
.swap__token--pick b { max-width: 12ch; }


/* ---- size the trade off what is actually held ---- */
.pcts { display: flex; gap: 6px; margin-top: 10px; }
.pcts[hidden] { display: none; }
.pcts__b {
  flex: 1 1 0; padding: 5px 0; border: 1px solid var(--line); border-radius: 7px;
  background: var(--bg-elev); color: var(--fg-3); cursor: pointer;
  font-family: var(--mono); font-size: 13px;
}
.pcts__b:hover { color: var(--fg); border-color: var(--fg-3); }
.pcts__b:disabled { opacity: .4; cursor: default; }


/* The address box was laying chain, depth, address and impact across two
   tight rows and clipping the ends of three of them. Given the column it has,
   one item per line reads better than four squeezed onto two. */
.tokenbox { gap: 6px; padding: 9px 11px; border-radius: 8px; }
.tokenbox__row { flex-wrap: wrap; row-gap: 3px; }
.tokenbox__row--sub { display: grid; gap: 3px; }
.tokenbox__chain { font-size: 14px; }
.tokenbox__depth { margin-inline-start: auto; }

/* An address is 42 characters and will never fit. Truncating it in the middle
   keeps both ends, which is the part anyone actually checks against a block
   explorer. */
.tokenbox__addr {
  max-width: 100%; direction: ltr;
  font-size: 12px; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tokenbox__impact { font-size: 14px; }


/* ---- the DEX side, locked ---- */

.seg__soon {
  margin-inline-start: 5px; padding: 1px 5px; border-radius: 4px;
  background: var(--line); color: var(--fg-3);
  font-family: var(--mono); font-size: 13px; letter-spacing: .04em;
  text-transform: uppercase; vertical-align: middle;
}
.seg--acct .seg__b[aria-pressed="true"] .seg__soon { background: rgba(0,0,0,.14); color: inherit; }

/* The card is faded rather than hidden so members can see what is coming and
   what it will look like - a missing feature reads as a smaller product than
   one that is visibly on its way. */
.swap { position: relative; }
.swap--locked > .swap__leg,
.swap--locked > .swap__arrow,
.swap--locked > .swap__facts,
.swap--locked > .swap__warn {
  opacity: .28; filter: grayscale(.5); pointer-events: none; user-select: none;
}

.swaplock {
  position: absolute; inset: 0; z-index: 3;
  display: grid; align-content: center; justify-items: center; gap: 9px;
  padding: 18px; text-align: center;
}
.swaplock[hidden] { display: none; }
.swaplock__pill {
  padding: 6px 14px; border-radius: 999px;
  border: 1px solid var(--line-strong); background: var(--bg-elev); color: var(--fg);
  font-family: var(--mono); font-size: 14px; letter-spacing: .02em;
}
.swaplock__note {
  margin: 0; max-width: 26ch; font-size: 14px; line-height: 1.5; color: var(--fg-3);
}


/* ---- indicators ---- */

/* z-index, not just position. With z-index:auto this made no stacking
   context, so the menu's own z-index competed against the chart canvas in
   the root context -- and lightweight-charts' canvas won, drawing straight
   over an open Indicators menu. Lifting the wrapper puts the whole
   dropdown above the chart in one move, and keeps it below the modals
   (200/300) and the mobile drawer (60). */
.ind { position: relative; z-index: 40; }
.ind__open { white-space: nowrap; }
.ind__menu {
  /* fixed, not absolute: .chartbox__bar is a scroll container (overflow-x
     hidden forces overflow-y to auto, whatever the stylesheet asks for), and
     a scroll container clips its children no matter their z-index. Fixed
     positioning leaves that box entirely. Coordinates come from JS on open
     -- see placeMenu() in app.js. */
  position: fixed; z-index: 400; top: 0; inset-inline-start: 0;
  min-width: 186px; padding: 6px;
  background: var(--bg-elev); border: 1px solid var(--line-strong);
  border-radius: 9px; box-shadow: 0 14px 34px rgba(0,0,0,.5);
  display: grid; gap: 1px;
}
.ind__menu[hidden] { display: none; }
.ind__menu label {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 8px; border-radius: 6px; cursor: pointer;
  font-size: 15px; color: var(--fg);
}
.ind__menu label:hover { background: var(--bg-inset); }
.ind__menu input { accent-color: var(--accent); margin: 0; }
.ind__menu em {
  margin-inline-start: auto; font-style: normal;
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
}


/* The hidden attribute loses to any rule that sets display, and both of these
   set one. Without this the JS was correctly marking them hidden and the CSS
   was quietly drawing them anyway - which is how a practice balance stayed on
   screen under a swap panel. */
.ticket__balance[hidden] { display: none !important; }
.field[hidden] { display: none !important; }


/* ---- per-pane indicator button ---- */
.ind--mini { position: relative; z-index: 40; margin-inline-start: 4px; }
.mini__ind {
  width: 22px; height: 22px; padding: 0; line-height: 1;
  border: 1px solid var(--line); border-radius: 5px;
  background: var(--bg-elev); color: var(--fg-3); cursor: pointer;
  font-size: 14px;
}
.mini__ind:hover { color: var(--fg); border-color: var(--fg-3); }
.ind--mini .ind__menu { inset-inline-start: auto; inset-inline-end: 0; min-width: 172px; }


/* Collapses to nothing when no oscillator is on, so the candles keep the whole
   frame in the normal case. */
.osc {
  position: relative; height: 132px;
  border-top: 1px solid var(--line); background: var(--bg-inset);
}
.osc[hidden] { display: none !important; }
.osc__canvas { position: absolute; inset: 0; }
.osc__label {
  position: absolute; z-index: 2; top: 6px; inset-inline-start: 10px;
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
  pointer-events: none;
}

.ind__menu hr { margin: 5px 2px; border: 0; border-top: 1px solid var(--line); }
.ind__menu .ind__head {
  padding: 5px 8px 2px; font-family: var(--mono); font-size: 13px;
  letter-spacing: .08em; text-transform: uppercase; color: var(--fg-3);
}


/* ---- copy the contract address ---- */
.tokenbox__addrrow { display: flex; align-items: center; gap: 6px; min-width: 0; }
.tokenbox__addrrow .tokenbox__addr { flex: 1 1 auto; min-width: 0; }

.tokenbox__copy {
  flex: 0 0 auto; display: grid; place-items: center;
  width: 22px; height: 22px; padding: 0;
  border: 1px solid var(--line); border-radius: 5px;
  background: var(--bg-elev); color: var(--fg-3); cursor: pointer;
}
.tokenbox__copy:hover { color: var(--fg); border-color: var(--fg-3); }
.tokenbox__copy[hidden] { display: none !important; }
.tokenbox__copy svg { grid-area: 1 / 1; }
.tokenbox__tick { opacity: 0; }
.tokenbox__copy.is-copied { color: #19d98b; border-color: rgba(255,255,255,0.08); }
.tokenbox__copy.is-copied svg:first-of-type { opacity: 0; }
.tokenbox__copy.is-copied .tokenbox__tick { opacity: 1; }


/* ---- fullscreen + grid of charts ---- */

.seg__b--sel {
  padding-inline: 6px; appearance: none; text-align: center;
  background: var(--bg-elev); color: var(--fg-2); cursor: pointer;
}

/* The native fullscreen element paints its own black backdrop, so the box has
   to carry its own background or the chart floats on nothing. */
.chartbox:fullscreen,
.chartbox:-webkit-full-screen {
  max-width: none; width: 100vw; height: 100vh;
  background: var(--bg); clip-path: none; border: 0;
}
.chartbox:fullscreen .chartbox__frame { height: auto; }

/* A single pane blown up. Same treatment, so one CSS rule covers both. */
.mini:fullscreen, .mini:-webkit-full-screen {
  width: 100vw; height: 100vh; background: var(--bg);
  display: grid; grid-template-rows: auto minmax(0, 1fr);
}

/* Column count is set inline from the pane count - a fixed 2x2 could not grow
   past four. */
.multi { grid-template-rows: none; grid-auto-rows: minmax(0, 1fr); }

.mini { position: relative; }
.mini__zoom {
  width: 22px; height: 22px; padding: 0; display: grid; place-items: center;
  border: 1px solid var(--line); border-radius: 5px;
  background: var(--bg-elev); color: var(--fg-3); cursor: pointer;
  margin-inline-start: 4px;
}
.mini__zoom:hover { color: var(--fg); border-color: var(--fg-3); }


/* Chart tools line up with the interval and layout groups. */
.seg--tools { align-self: center; flex: none; display: flex; align-items: stretch; }
.seg--tools .seg__b { padding: 6px 9px; display: grid; place-items: center; }
.seg--tools .seg__b--sel {
  font-family: var(--mono); font-size: 14px; letter-spacing: -.01em;
  padding-inline: 9px; min-width: 34px;
}


/* The chart count opens the same dark menu the indicators use - a native
   select drops an OS popup that belongs to no design system and comes out far
   wider than the control that opened it. */
.ind--count { position: relative; display: flex; }
.seg__b--count {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--mono); font-size: 14px; letter-spacing: -.01em;
  padding: 6px 8px 6px 10px; min-width: 0;
}
.seg__b--count svg { color: var(--fg-3); flex: 0 0 auto; }
.ind__menu--count {
  inset-inline-start: auto; inset-inline-end: 0;
  min-width: 118px;
}
.ind__menu--count .paymenu__item {
  font-family: var(--mono); font-size: 14px; justify-content: flex-start;
}


/* ---- partial profits ---- */

.sellpct { display: flex; gap: 6px; margin-top: -2px; }
.sellpct[hidden] { display: none !important; }
.sellpct__b {
  flex: 1 1 0; padding: 7px 0;
  border: 1px solid var(--line); background: var(--bg-elev); color: var(--fg-3);
  font-family: var(--mono); font-size: 13px; cursor: pointer;
  transition: color .14s, border-color .14s;
}
.sellpct__b:hover { color: var(--fg); border-color: var(--fg-3); }
.sellpct__b:disabled { opacity: .4; cursor: default; }

/* Both sides act in green: the button is the confirm, and the direction is
   already chosen and shown in the Buy/Sell segment above it. Recolouring the
   confirm red on sell reads as a warning about the action rather than as the
   side it belongs to.

   Set as background rather than through --btn-bg: an earlier rule paints
   .btn--go white with a literal background, so a custom property nothing
   reads is silently ignored. */
.ticket__actions .btn--go,
.ticket__actions .btn--go[data-side="buy"] {
  background: var(--gain);
  color: #0c0c0c;
}
.ticket__actions .btn--go:hover,
.ticket__actions .btn--go[data-side="buy"]:hover { background: #19d98b; }

/* Selling is red. The confirm carries the same colour as the side above it,
   so the button and the segment never disagree about what is about to
   happen. */
.ticket__actions .btn--go[data-side="sell"] {
  background: var(--loss);
  color: #0c0c0c;
}
.ticket__actions .btn--go[data-side="sell"]:hover { background: #FF6A55; }

/* Disabled keeps the shape and drops to an outline, so the button stays where
   the eye already expects it. */
.ticket__actions .btn--go:disabled,
.ticket__actions .btn--go:disabled:hover {
  background: none; color: var(--fg-3); border: 1px solid var(--line);
}


/* The chart-count buttons read as numbers, so they take the mono face rather
   than the tracked micro-caps the other segments use. */
.seg--count { align-self: center; flex: none; }
.seg__b--n {
  font-family: var(--mono); font-size: 14px; letter-spacing: -.01em;
  text-transform: none; padding: 7px 10px; min-width: 30px;
}


/* ---- chart settings ---- */

.ind--cfg { position: relative; display: flex; }

/* Fixed, not absolute. The chartbox sets both overflow:hidden and a clip-path,
   and either one clips a dropdown positioned inside it - which is why this
   panel opened into nothing. Fixed positioning escapes both; the coordinates
   come from the button's own rect at open time. */
.cfg {
  position: fixed; z-index: 90;
  width: 214px; padding: 8px;
  background: var(--bg-elev); border: 1px solid var(--line-strong);
  border-radius: 9px; box-shadow: 0 16px 40px rgba(0,0,0,.55);
  display: grid; gap: 2px;
  max-height: 62vh; overflow-y: auto;
}
.cfg[hidden] { display: none !important; }

.cfg__head {
  padding: 7px 6px 3px; font-family: var(--techno);
  font-size: 13px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--fg-3);
}
.cfg__head:not(:first-child) { margin-top: 6px; border-top: 1px solid var(--line); }

.cfg__row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 5px 6px; border-radius: 6px;
  font-size: 15px; color: var(--fg-2); cursor: pointer;
}
.cfg__row:hover { background: var(--bg-inset); }

/* A colour input paints its own chrome in every browser; stripping it back to
   a swatch keeps the panel in one visual language. */
.cfg__row input[type="color"] {
  width: 34px; height: 22px; padding: 0; flex: 0 0 auto;
  border: 1px solid var(--line-strong); border-radius: 4px;
  background: none; cursor: pointer;
}
.cfg__row input[type="color"]::-webkit-color-swatch-wrapper { padding: 2px; }
.cfg__row input[type="color"]::-webkit-color-swatch { border: 0; border-radius: 2px; }

.cfg__row input[type="number"] {
  width: 56px; flex: 0 0 auto; text-align: end;
  font-family: var(--mono); font-size: 14px;
  background: var(--bg-inset); color: var(--fg);
  border: 1px solid var(--line); border-radius: 4px; padding: 4px 6px;
}
.cfg__row input[type="number"]:focus { border-color: var(--fg-3); outline: none; }
.cfg__row input[type="checkbox"] { accent-color: var(--accent); margin: 0; }

.cfg__reset {
  margin-top: 8px; padding: 8px; width: 100%;
  border: 1px solid var(--line); border-radius: 6px;
  background: none; color: var(--fg-3); cursor: pointer;
  font-family: var(--mono); font-size: 14px;
}
.cfg__reset:hover { color: var(--fg); border-color: var(--fg-3); }


/* ============================================================
   Chart toolbar — one line, one height
   ============================================================

   The bar was aligned on the baseline, which only lines up text. Anything
   with an icon, a border or a different font sat at its own height, so the
   interval group, the layout buttons, the gear and the fullscreen control
   each floated at a slightly different level. Centred alignment plus one
   control height fixes the whole row.                                     */

.chartbox__bar { align-items: center; }

/* Every control in the bar is 28px tall and centres its contents, whether it
   holds a letter, a number or an icon. */
.chartbox__bar .seg { align-self: center; flex: none; }
.chartbox__bar .seg__b {
  height: 28px; padding: 0 11px; display: inline-flex;
  align-items: center; justify-content: center; line-height: 1;
}
.chartbox__bar .seg--layout .seg__b,
.chartbox__bar .ind--cfg .seg__b,
.chartbox__bar > .seg__b,
.chartbox__bar .ind__open { padding: 0 9px; }

/* Icon-only controls are square, so they read as a set rather than as three
   different widths. */
.chartbox__bar .ind--cfg .seg__b,
.chartbox__bar [data-fullscreen] { width: 30px; padding: 0; }
.chartbox__bar [data-fullscreen] {
  height: 28px; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line); background: transparent; color: var(--fg-3);
  cursor: pointer;
}
.chartbox__bar [data-fullscreen]:hover { color: var(--fg); border-color: var(--fg-3); }
.chartbox__bar .ind--cfg .seg__b { border: 1px solid var(--line); }
.chartbox__bar .ind--cfg .seg__b:hover { color: var(--fg); border-color: var(--fg-3); }

/* The Indicators button carries a word rather than a glyph, so it keeps its
   horizontal padding but takes the same height as the rest. */
.chartbox__bar .ind__open {
  height: 28px; border: 1px solid var(--line);
  display: inline-flex; align-items: center;
}
.chartbox__bar .ind__open:hover { border-color: var(--fg-3); }

/* The readouts sit on the same centre line as the controls. */
.chartbox__pair, .chartbox__price, .chartbox__chg, .chartbox__venue {
  align-self: center; line-height: 1;
}
.chartbox__venue { padding: 4px 7px; }

/* ============================================================
   Empty states — bolder pass
   ============================================================
   Every "nothing here yet" moment across the app was plain grey body text on
   the panel's own background — the one place that quietly opted out of the
   system's own devices. This gives them the same well the rest of the app
   already uses for sunken surfaces (--bg-inset, per DESIGN.md) and the same
   chamfer every card on the page carries, so an empty screener, an empty
   position list and an empty chart all read as designed rather than as the
   moment the design ran out.
*/

.coinlist__empty, .chartbox__empty, .tbl__empty, .livepos__empty,
.mini__empty, .room__empty, .squawk__empty {
  --cut: var(--cut-sm);
  background: var(--bg-inset);
  border: 1px dashed var(--line-strong);
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}

/* Every one of the above is a <p> except .tbl__empty, which is the <td> that
   carries the whole empty row — display:grid there would drop it out of
   table layout, so it keeps its own centering instead. */
.coinlist__empty, .chartbox__empty, .livepos__empty,
.mini__empty, .room__empty, .squawk__empty {
  display: grid; place-items: center; gap: 6px; text-align: center;
}


/* ============================================================================
   FACTORY THEME OVERRIDE LAYER
   Merged in from design_handoff_war_room_terminal/factory-theme.css (the
   canonical handoff for Direction A). Copied verbatim except one rename:
   the handoff assumes a single combined .coinrow__chain element, which this
   app has since split into .coinrow__net (chain) + .coinrow__pool (liquidity)
   — the chain-label treatment below targets .coinrow__net instead.
   ============================================================================ */

/* ---------- no glow, no saturated blur ---------- */

.dot[data-conn-dot],
.dot[data-conn-dot][data-state="on"],
.dot[data-conn-dot][data-state="off"] { box-shadow: none; }

.topbar,
.ticker {
  background: rgba(12,12,12,.86);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.btn--primary { box-shadow: none; }

/* ---------- buttons: neutral fills only ---------- */

.btn--primary {
  --btn-bg: var(--btn-neutral);
  --btn-fg: #eeeeee;
  --btn-line: transparent;
  border-radius: 3px;
}
.btn--primary:hover { --btn-bg: var(--btn-neutral-hi); --btn-fg: #fafafa; }

/* The one light-filled button in the system (auth / top-right CTA). */
.btn--chalk {
  --btn-bg: #fafafa;
  --btn-fg: #101010;
  --btn-line: transparent;
}

/* The trade action button keeps its side as *text* colour, not a fill. */
.btn--go[data-side="buy"],
.btn--go[data-side="sell"] {
  --btn-bg: var(--btn-neutral);
  --btn-line: transparent;
}
.btn--go[data-side="buy"]  { --btn-fg: var(--gain); }
.btn--go[data-side="sell"] { --btn-fg: var(--loss); }
.btn--go[data-side="buy"]:hover,
.btn--go[data-side="sell"]:hover { --btn-bg: var(--btn-neutral-hi); }

/* Buy / Sell segmented control: selected state is a dark well plus coloured
   label, so the panel never carries a chromatic surface. */
.seg__b[aria-pressed="true"] {
  background: var(--btn-neutral);
  color: #eeeeee;
}
.seg--side .seg__b--buy[aria-pressed="true"]  { background: var(--btn-neutral); color: var(--gain); }
.seg--side .seg__b--sell[aria-pressed="true"] { background: var(--btn-neutral); color: var(--loss); }

/* ---------- chart surfaces ---------- */

.chartbox__frame,
.mini { background: var(--bg-elev); }

/* Level lines and their pills: bone for entry, green for target, orange for
   stop. Replaces the TradingView blue/teal/amber triad. */
.chartlegend__i[data-leg="entry"]::before  { background: #bcbcc6; }
.chartlegend__i[data-leg="stop"]::before   { background: #ff3d63; }
.chartlegend__i[data-leg="target"]::before { background: #19d98b; }

.poscard--entry  { border-color: #8e8e9a; }
.poscard--target { border-color: rgba(255,255,255,0.08); }
.poscard--stop   { border-color: rgba(255,255,255,0.08); }

.poscard--entry  .poscard__pl[data-dir="up"]   { color: #19d98b; }
.poscard--entry  .poscard__pl[data-dir="down"] { color: #ff3d63; }
.poscard--target .poscard__pl { color: #19d98b; }
.poscard--stop   .poscard__pl { color: #ff3d63; }
.posrr b { color: #19d98b; }

.poscard--entry  .poscard__x { background: #3d3d3d; color: #eeeeee; }
.poscard--target .poscard__x { background: #1c1c1c; color: #19d98b; }
.poscard--stop   .poscard__x { background: #1c1c1c; color: #ff3d63; }
.poscard__x { border-radius: 3px; }

.pospull[data-pull="target"]:hover { border-color: #19d98b; color: #19d98b; }
.pospull[data-pull="stop"]:hover   { border-color: #ff3d63; color: #ff3d63; }

.posrow__x {
  background: #1c1c1c;
  border: 1px solid #3b3b3b;
  border-radius: 3px;
  color: #ff3d63;
}
.posrow__x:hover { background: #272727; transform: none; }

/* ---------- alert / result states: hairline + coloured text, no wash ---------- */

.trade__out[data-tone="bad"],
.ticket__out[data-tone="bad"] { border-color: rgba(255,255,255,0.08); color: #ff3d63; }
.trade__out[data-tone="good"],
.ticket__out[data-tone="good"] { border-color: rgba(255,255,255,0.08); color: #19d98b; }

/* ---------- type ---------- */

.line__body { color: #eeeeee; }

/* Factory speaks at weight 400. Bold headings break the voice. */
.topbar h1,
.blockhead h2,
.statbox b,
.userchip__name { font-weight: 400; }

.statbox b { letter-spacing: -.028em; }

/* Accent is data-voice, never chrome: section "see all" links and the plan
   chip were orange. Muted mono instead. */
.blockhead a,
.blockhead a:visited { color: #8e8e9a; }
.blockhead a:hover { color: #eeeeee; }
.userchip__plan,
[data-me-role] { color: #8e8e9a; }
[data-me-role][data-plan="paid"] { color: #bcbcc6; }
.statbox b,
[data-stat] { color: #eeeeee; }

/* Signal state: open is a live-but-fine state, so green. Orange is reserved
   for the one that actually cost money. */
.sig__state[data-state="open"]    { color: #19d98b; border-color: rgba(255,255,255,0.08); background: none; }
.sig__state[data-state="hit"]     { color: #19d98b; border-color: rgba(255,255,255,0.08); background: none; }
.sig__state[data-state="closed"]  { color: #bcbcc6; border-color: var(--line-strong); background: none; }
.sig__state[data-state="stopped"] { color: #ff3d63; border-color: rgba(255,255,255,0.08); background: none; }
.sig__row b[data-tone="stop"] { color: #ff3d63; }
.sig__row b[data-tone="tp"]   { color: #19d98b; }

/* ---------- data-viz neutrals ---------- */

.bar__seg[data-k="btc"], .legend__dot[data-k="btc"] { background: #8e8e9a; }
.bar__seg[data-k="eth"], .legend__dot[data-k="eth"] { background: #3d3d3d; }
.bar__seg[data-k="alt"], .legend__dot[data-k="alt"] { background: #ff3d63; }
.bar__seg[data-k="up"]   { background: #19d98b; }
.bar__seg[data-k="down"] { background: #ff3d63; }

/* ---------- shape: flat, minimal radii, no chamfers ---------- */

.statbox, .course__thumb, .mres, .feat__main, .plan, .expmodal__panel {
  border-radius: 10px;
  clip-path: none;
}
.navlink, .seg__b, .btn, .pospull, .badge { border-radius: 3px; clip-path: none; }

.course__thumb,
.course__hero { background: var(--bg-elev); }

/* Active nav item: hairline + bone label, orange reserved for the icon/dot. */
.navlink[aria-current="page"] {
  background: #131313;
  border-color: #3b3b3b;
  color: #eeeeee;
}
.navlink[aria-current="page"] svg { color: #ff2d8f; }


/* ============================================================
   FULL FACTORY PASS
   The app was built on a chamfered, accent-washed language. Factory is
   flat, hairline, monochrome. This section finishes the conversion.
   ============================================================ */

/* ---------- 1. no chamfers, anywhere ----------
   The clip-path polygon corner-cut is the app's signature shape. Factory's
   shape language is a plain rect at 3px / 10px. Kill it globally rather
   than selector by selector. */

.card, .statbox, .navlink, .seg__b, .btn, .chip, .badge, .sig__state,
.course, .course__thumb, .coursecta, .lesson, .notice, .room, .chatinput,
.gate__panel, .gate__error, .gate__input, .profile__avatar, .profile__field,
.iconbtn, .line__img, .line__embed, .line__video, .expmodal__panel,
.expmodal__btn, .expmodal__table, .trade, .trade__out, .ticket,
.ticket__out, .chartbox, .chartbox__frame, .plane, .meter, .mres,
.feat__main, .plan, .joinpanel, .joinpanel__mark, .upsell, .squawk__item,
.chatline, .msg, .pill, .tick, .coinrow, .poscard, .posrow {
  clip-path: none !important;
}

/* ---------- 2. no accent washes or gradients ----------
   Factory earns depth from #eeeeee-on-#101010 contrast, never from a
   tinted gradient. */

.notice,
.upsell,
.joinpanel,
.feat__main,
.course__thumb,
.course__hero,
.plan--featured {
  background: var(--bg-elev) !important;
  border-color: var(--line) !important;
}

.joinpanel__mark {
  background: #131313 !important;
  border-color: #3b3b3b !important;
  color: #eeeeee !important;
}
.joinpanel__mark svg { color: #ff2d8f; }

/* The membership upsell is the one place the signature light card belongs:
   bone figure on obsidian ground. */
.upsell {
  background: #eeeeee !important;
  border: 0 !important;
  border-radius: 10px;
  color: #101010;
}
.upsell h2, .upsell h3, .upsell b, .upsell strong { color: #101010; }
.upsell p, .upsell li { color: #525252; }   /* 7.07 on #eeeeee */
.upsell .btn,
.upsell .btn--primary {
  --btn-bg: #101010; --btn-fg: #eeeeee; --btn-line: transparent;
}
.upsell .btn:hover { --btn-bg: #1c1c1c; --btn-fg: #fafafa; }

/* ---------- 3. squawk feed ----------
   The orange left-edge stripe is the exact accent-as-chrome move Factory
   forbids. Replaced with the system's status pulse: a 6px dot. */

.squawk__item[data-hot="true"]::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  inset-block: auto;
  top: 18px;
  width: 6px; height: 6px;
  border-radius: 999px;
  background: #ff3d63;
}
.squawk__item { padding-inline-start: 22px; border-radius: 0; }
.squawk__item:hover { background: #161514; }
.squawk__title { font-weight: 400; font-size: 17px; letter-spacing: -.02em; }
.squawk__src { font-size: 13px; letter-spacing: .1em; color: #8e8e9a; }

/* Coin chips: hairline mono tags, not filled accent pills. */
.chip {
  font-weight: 400;
  border-radius: 3px;
  background: none;
  border: 1px solid #3b3b3b;
  color: #bcbcc6;
}
.chip--go {
  color: #bcbcc6 !important;
  border-color: #3b3b3b !important;
  background: none !important;
}
.chip--go:hover {
  color: #eeeeee !important;
  border-color: #8e8e9a !important;
  background: #131313 !important;
}
.chip--go:focus-visible { outline: 1px solid #8e8e9a; outline-offset: 2px; }

/* ---------- 4. type discipline ----------
   Factory speaks at weight 400. Nothing here goes bold. */

.userchip__name,
.squawk__title,
.course__body h3,
.sig__pair,
.statbox b,
.meter__big,
.meter__head,
.tbl__num,
.coinrow__sym,
.posrow__sym,
.card__head h2,
h1, h2, h3, h4 { font-weight: 400 !important; }

.meter__big { letter-spacing: -.028em; }
.card__head h2, .course__body h3 { letter-spacing: -.025em; }

/* ---------- 5. dominance bar reads as neutral data ----------
   Three warm greys stepping down, orange only on the alt slice tip. */

.bar { border-radius: 0; }
.bar__seg[data-k="btc"], .legend__dot[data-k="btc"] { background: #bcbcc6 !important; }
.bar__seg[data-k="eth"], .legend__dot[data-k="eth"] { background: #8e8e9a !important; }
.bar__seg[data-k="alt"], .legend__dot[data-k="alt"] { background: #3d3d3d !important; }

/* Fear & Greed gauge stroke: metric green, the system's trend colour. */
.meter svg [stroke]:not([stroke="none"]) { stroke: #19d98b; }

/* ---------- 6. hairline discipline on the shell ---------- */

.card, .statbox, .course, .meter, .trade, .ticket, .chartbox, .plane,
.room, .mres, .feat__main, .plan {
  border-color: var(--line);
  background: var(--bg-elev);
}
.card:hover, .course:hover, .statbox:hover { border-color: var(--line-strong); }
.course { transition: border-color .15s cubic-bezier(.4,0,.2,1); }
.course:hover { transform: none; }

/* Section heads: mono eyebrow voice. */
.blockhead h2 { font-size: 22px; letter-spacing: -.025em; }

/* Tables: hairline rows, mono numerals, no zebra. */
.tbl th {
  font-family: var(--mono);
  font-size: 13px; text-transform: uppercase; letter-spacing: -.02em;
  color: #8e8e9a; font-weight: 400;
  border-bottom: 1px solid #131313;
}
.tbl td { border-bottom: 1px solid #131313; }
.tbl__up   { color: #19d98b; }
.tbl__down { color: #ff3d63; }

/* Coin rows in the screener list: flat, hairline separated. */
.coinrow { border-radius: 3px; }
.coinrow[aria-selected="true"] { background: #131313; border-color: #3b3b3b; }
.coinrow__chg[data-dir="up"]   { color: #19d98b; }
.coinrow__chg[data-dir="down"] { color: #ff3d63; }
.coinrow__net {
  font-family: var(--mono); font-size: 13px;
  color: #8e8e9a; background: none; border: 0; padding: 0;
}

/* Ticker: mono, muted, orange reserved for nothing here. */
.tick { border-radius: 0; background: none; border: 0; }
.tick__sym { color: #bcbcc6; font-weight: 400; }
.tick__chg { color: #19d98b; }

/* ---------- 7. motion: mechanical, 0.15s ---------- */

.card, .course, .btn, .navlink, .chip, .coinrow, .seg__b, .tick, .squawk__item {
  transition-duration: .15s !important;
  transition-timing-function: cubic-bezier(.4, 0, .2, 1) !important;
}
.card:hover, .course:hover, .feat__main:hover, .plan:hover,
.btn:hover, .tick:hover { transform: none !important; }


/* ============================================================
   TYPE LAYER — the Factory scale, applied
   Two voices, one family. Geist 400 for everything human; Geist Mono
   12px uppercase for every instrument label. Tracking is negative and
   proportional to size — never positive, except the wordmark.
   ============================================================ */

/* Page titles were 22px — two steps below the system's heading size. */
.topbar h1 {
  font-size: 28px;
  line-height: 1.1;
  letter-spacing: -.031em;
  font-weight: 400;
}

/* Section heads inside a view. */
.blockhead h2 {
  font-size: 22px;
  line-height: 1.2;
  letter-spacing: -.025em;
  font-weight: 400;
}

/* Intro / lede copy under a page title: body at muted grey, capped measure
   so it never runs the full width of a 1200px column. */
.view__intro,
.blockhead p,
.card__intro {
  font-size: 18px;
  line-height: 1.5;
  letter-spacing: 0;
  color: #8e8e9a;
  max-width: 62ch;
  text-wrap: pretty;
}

/* ---------- the mono voice ----------
   One rule, one size, one tracking. Every instrument label in the app. */

.side__group,
.field__label,
.plane__venue,
.chartbox__venue,
.course__num,
.badge,
.meter__head,
.squawk__src,
.userchip__plan,
.statbox span,
.blockhead a,
.tbl th,
.coinrow__net,
.posrow__meta,
.poscard__lab,
.sig__state,
.tick__sym,
.tick__chg {
  font-family: var(--mono), 'Geist Mono', ui-monospace, monospace;
  font-size: 14px;      /* 12px — the system's caption size and its floor */
  line-height: 1;
  letter-spacing: -.02em;
  text-transform: uppercase;
  font-weight: 400;
}

/* Segmented-control labels overflowed their box at wide tracking. Mono,
   12px, tight — and allowed to size to content. */
.seg__b {
  font-family: var(--mono), 'Geist Mono', ui-monospace, monospace;
  font-size: 14px;
  line-height: 1;
  letter-spacing: -.02em;
  text-transform: uppercase;
  font-weight: 400;
  white-space: nowrap;
}
.seg { flex-wrap: nowrap; }

/* Sidebar group labels are the one place a little air helps, but stay 12px. */
.side__group { letter-spacing: .08em; color: #8e8e9a; }

/* Nav items: Geist 14, not mono — they are navigation, not data. */
.navlink {
  font-family: var(--font-geist, 'Geist'), ui-sans-serif, system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.43;
  letter-spacing: -.02em;
  font-weight: 400;
}
.navlink__count {
  font-family: var(--mono), 'Geist Mono', ui-monospace, monospace;
  font-size: 14px; letter-spacing: -.02em; color: #8e8e9a;
}

/* ---------- numerals ----------
   Every price, percentage and metric is tabular mono so columns line up
   and a repaint never shifts the layout. */

.statbox b,
.meter__big,
.meter__label,
.meter__sub,
.tbl__num,
.coinrow__chg,
.posrow__pnl,
.poscard__pl,
.tick__chg,
.chartbox__px,
.cap__value,
[data-stat],
[data-cap-value],
[data-cap-invested] {
  font-family: var(--mono), 'Geist Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  font-weight: 400;
  letter-spacing: -.02em;
}

/* Metric values are the heading size in the tile — big, flat, tight. */
.statbox b { font-size: 36px; line-height: 1.1; letter-spacing: -.031em; }
.meter__big { font-size: 36px; line-height: 1.1; letter-spacing: -.031em; }

.meter__label { font-size: 16px; text-transform: none; color: #bcbcc6; letter-spacing: 0; }
.meter__sub   { font-size: 14px; color: #8e8e9a; }

/* ---------- body copy ---------- */

.card p,
.course__body p,
.lesson__desc,
.sig__note,
.line__body,
.squawk__empty,
.livepos__empty,
.tbl__empty {
  font-size: 16px;
  line-height: 1.43;
  letter-spacing: 0;
  color: #8e8e9a;
  text-wrap: pretty;
}

.line__body { color: #eeeeee; }

/* Card and course titles: Geist, one step above body, tight. */
.card__head h2,
.course__body h3,
.sig__pair,
.squawk__title {
  font-family: var(--font-geist, 'Geist'), ui-sans-serif, system-ui, sans-serif;
  font-size: 18px;
  line-height: 1.25;
  letter-spacing: -.025em;
  font-weight: 400;
}
.squawk__title { font-size: 17px; line-height: 1.4; color: #eeeeee; }

/* ---------- the wordmark is the one positive-tracking exception ---------- */
.brand, .brand__word, .sidebar__brand, .side__brand-word {
  font-family: var(--mono), 'Geist Mono', ui-monospace, monospace;
  font-size: 14px;
  letter-spacing: .18em;
  text-transform: uppercase;
  font-weight: 510;
}

/* ---------- user chip ---------- */
/* The chip is a <button>, and buttons do not inherit colour -- they fall
   back to the UA's black, which on this sidebar is invisible. It has to be
   set explicitly. */
.userchip__name { font-size: 16px; letter-spacing: -.02em; font-weight: 400; color: var(--fg); }
/* No colour here on purpose: the data-plan rules above paint it (dim for
   free, accent for paid), and a flat override was killing that signal --
   as well as being 2.14:1 on this background, which fails AA outright. */


/* ============================================================
   SCREENER REBUILD — pieces the handoff describes that neither the
   original Factory pass nor factory-theme.css covered on their own.
   ============================================================ */

/* The coin row's left edge carries the guard's own verdict at the ticket's
   current size — clear or blocked, recomputed on every keystroke by
   updateRowVerdicts() — so tradeability is legible before you ever click
   a row. Deliberately overrides the aria-selected rule above for this one
   edge only; the other three sides still get the muted selected-row tone. */
.coinrow[data-verdict="clear"]   { border-inline-start-color: var(--gain); }
.coinrow[data-verdict="blocked"] { border-inline-start-color: var(--loss); }

/* The guard card's signature move: cleared is a bone (#eeeeee) card on the
   near-black canvas -- the one place in the whole system a light surface
   appears. Blocked stays dark with an orange border, a refusal rather
   than a reward. Text inside flips to suit whichever surface it's on. */
.tokenbox[data-verdict="clear"] {
  background: #eeeeee; border-color: #eeeeee; color: #101010;
}
.tokenbox[data-verdict="clear"] .tokenbox__kicker,
.tokenbox[data-verdict="clear"] .tokenbox__row--sub,
.tokenbox[data-verdict="clear"] .tokenbox__addr { color: rgba(16,16,16,.6); }
.tokenbox[data-verdict="clear"] .tokenbox__chain,
.tokenbox[data-verdict="clear"] .tokenbox__depth { color: #101010; }
.tokenbox[data-verdict="clear"] .tokenbox__dot { background: #101010; }
.tokenbox[data-verdict="clear"] .tokenbox__impact[data-level="ok"]   { color: var(--fg-2); }
.tokenbox[data-verdict="clear"] .tokenbox__impact[data-level="warn"] { color: #8a5a00; }
.tokenbox[data-verdict="clear"] .tokenbox__copy {
  background: rgba(16,16,16,.06); border-color: rgba(16,16,16,.2); color: rgba(16,16,16,.6);
}
.tokenbox[data-verdict="clear"] .tokenbox__copy:hover { color: #101010; border-color: rgba(16,16,16,.4); }

.tokenbox[data-verdict="blocked"] {
  background: var(--bg-elev); border-color: var(--loss);
}

/* Critical layout constraints (README's "bugs found and fixed during
   design -- reproduce the fixes, not the bugs"): the centre column and its
   header row / levels grid need both overflow:hidden and min-width:0, or
   the price header and levels row keep their intrinsic width and paint
   over the right rail once the viewport narrows. Horizontal only -- the
   Indicators menu (.ind__menu) opens as an absolutely-positioned dropdown
   below .chartbox__bar, and clipping the vertical axis here was hiding it
   entirely. Also un-clips .chartbox's own leftover overflow:hidden (from
   the pre-Factory clip-path corner cut, itself now disabled), which was
   clipping that same dropdown a layer further up. */
.deck__col { overflow: hidden; }
/* clip, not hidden. `overflow-x: hidden` with `overflow-y: visible` is not
   a thing CSS will honour: the visible axis is forced to `auto`, which is a
   scroll container, which clips. That is why the Indicators menu kept being
   cut off at the toolbar edge even after the z-index was raised -- it was
   never a stacking problem. `clip` genuinely leaves the other axis alone. */
.deck__col--chart { min-width: 0; overflow-x: hidden; overflow-y: visible; }
.chartbox { overflow: visible; }
.chartbox__bar { min-width: 0; overflow-x: hidden; overflow-y: visible; }
.chartlevels { min-width: 0; overflow-x: hidden; }

/* Level tiles -- spec is repeat(auto-fit, minmax(112px, 1fr)); a fixed
   repeat(4, 1fr) overflows below ~1200px. 14px/16px padding, 12px labels,
   16px values per the handoff. */
.chartlevels { grid-template-columns: repeat(auto-fit, minmax(112px, 1fr)); }
.chartlevels__cell { padding: 14px 16px; }
.chartlevels__label { font-size: 14px; }
.chartlevels__value { font-size: 18px; }

/* The right rail must be a single scrolling flex column, not a grid with
   `auto auto 1fr` rows -- the ticket's auto track and the panel's own
   internal scroll left Open Positions starved to a sliver at the bottom.
   Now the ticket and the full position list flow naturally and the rail
   itself scrolls once their combined height exceeds it. */
.deck__col--ticket {
  display: flex; flex-direction: column; gap: 12px;
  min-width: 0; overflow-y: auto; overflow-x: hidden;
}
.ticket { flex: none; overflow-y: visible; }
/* Open Positions grows to fill whatever height the ticket leaves, so its
   bottom edge lines up with the chart's instead of stopping a few rows
   down with dead space below it. */
.livepos { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 160px; }
.livepos__body { overflow-y: auto; }

/* D / W / M was rendering as a cramped 12px tab strip -- sized up to read
   as the primary timeframe control it is. */
.seg--tf .seg__b { padding: 11px 20px; font-size: 16px; }

/* ============================================================
   SIGNALS -- room lead posts and closes, everyone else reads.
   ============================================================ */

.signals__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 22px; }
.signals__head .filters { margin-bottom: 0; }

.sig__shot { margin: 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.sig__shot img { display: block; width: 100%; max-height: 220px; object-fit: cover; }

.sig__actions { padding: 0 17px 14px; }
.sig__closebtn { width: 100%; }

/* ---- new-signal modal: reuses .expmodal's overlay + panel chrome ---- */

.sigmodal { position: fixed; inset: 0; z-index: 300; display: flex; align-items: center; justify-content: center; padding: clamp(16px, 4vw, 56px); background: rgba(4,5,6,.82); backdrop-filter: blur(6px); }
.sigmodal[hidden] { display: none; }
.sigmodal__panel { width: min(520px, 100%); max-height: 88vh; overflow-y: auto; }

.sigmodal__form { display: grid; gap: 16px; padding: 16px; }
.sigmodal__form .field { position: relative; }

.sigmodal__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

.sigmodal__suggest {
  position: absolute; top: calc(100% + 4px); inset-inline: 0; z-index: 5;
  max-height: 220px; overflow-y: auto;
  background: var(--bg-elev-2); border: 1px solid var(--line-strong);
}
.sigmodal__suggest[hidden] { display: none; }
.sigmodal__suggest-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 9px 12px; background: none; border: 0; border-bottom: 1px solid var(--line);
  font-family: var(--mono); font-size: 15px; color: var(--fg); cursor: pointer; text-align: start;
}
.sigmodal__suggest-row:last-child { border-bottom: 0; }
.sigmodal__suggest-row:hover { background: rgba(255,255,255,.05); }
.sigmodal__suggest-chain { font-size: 13px; color: var(--fg-3); text-transform: uppercase; }

.sigmodal__image {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 96px; padding: 12px; border: 1px dashed var(--line-strong);
  color: var(--fg-3); font-size: 15px; cursor: pointer; text-align: center;
}
.sigmodal__image:hover { border-color: var(--fg-3); color: var(--fg-2); }
.sigmodal__image img { max-width: 100%; max-height: 160px; object-fit: contain; }
.sigmodal__image-x { margin-top: 8px; }

.sigmodal__actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 4px; }

/* ============================================================
   ADDRESS PRICE -- the resolved contract's own price, next to the chain
   badge in both the coin list and the guard card, so a member can compare
   it against the TradingView price above/beside it and confirm the address
   actually is the coin before trusting it with an order.
   ============================================================ */

.tokenbox__chainwrap { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.tokenbox__addrpx {
  font-family: var(--mono); font-size: 14px; letter-spacing: -.02em;
  color: var(--fg-3); font-variant-numeric: tabular-nums;
}
.tokenbox__addrpx:empty { display: none; }
.tokenbox[data-verdict="clear"] .tokenbox__addrpx { color: rgba(16,16,16,.6); }

.coinrow__addrpx {
  font-family: var(--mono); font-size: 13px; letter-spacing: -.02em;
  color: var(--fg-3); font-variant-numeric: tabular-nums;
}

/* Impact vs fee, side by side. Two different costs with different causes:
   impact grows with the order, the fee is near-fixed in dollars and only
   bites a small one. Folding them into one number is what made a $10 trade
   look like a 2% one. */
.tokenbox__costs { justify-content: space-between; }
.tokenbox__cost {
  font-family: var(--mono); font-size: 13px; letter-spacing: -.02em;
  color: var(--fg-3); font-variant-numeric: tabular-nums;
}
.tokenbox[data-verdict="clear"] .tokenbox__cost { color: rgba(16,16,16,.6); }

/* ============================================================
   PRACTICE-ONLY LAUNCH
   The chain badge, pool depth and on-chain price describe a venue the
   practice book never touches. In their place the row carries the one
   thing a member wants beside a mover: its chart.
   ============================================================ */

.coinrow__right { display: inline-flex; align-items: center; gap: 8px; justify-self: end; }

.coinrow__tv {
  display: inline-grid; place-items: center; width: 22px; height: 22px;
  border: 1px solid var(--line); border-radius: 3px;
  color: var(--fg-3); cursor: pointer; flex: none;
  transition: color .14s, border-color .14s, background-color .14s;
}
.coinrow__tv:hover,
.coinrow__tv:focus-visible {
  color: var(--fg); border-color: var(--fg-3); background: rgba(255,255,255,.05);
}
.coinrow__tv:focus-visible { outline: 1px solid var(--accent-line); outline-offset: 1px; }

/* The verdict edge reads on pool depth, which practice has no use for. */
.coinrow[data-verdict] { border-inline-start-color: transparent; }

/* ---------- warmth, where it carries meaning ----------
   The list was green-on-grey end to end, which reads cold and flattens
   every row into the same weight. Orange is this system's attention
   colour, so it goes on the two things worth attention -- a coin that is
   running, and the row you are actually on -- and nowhere else. */

/* Every coin carries it. This is the warmth in a list that was otherwise
   green-on-grey from top to bottom. */
.coinrow__hot {
  width: 5px; height: 5px; border-radius: 999px; flex: none;
  background: var(--accent);
  display: inline-block; margin-inline-end: 7px;
  vertical-align: middle; margin-block-start: -2px;
}
.coinrow__sym { display: inline-flex; align-items: center; }

/* The selected row gets the accent on its edge -- the one place the eye
   returns to, and the row whose chart is on screen. */
.coinrow[aria-selected="true"] { border-inline-start-color: var(--accent); }
.coinrow[aria-selected="true"] .coinrow__sym { color: var(--fg); }

/* The chart button warms on approach rather than going flat white. */
.coinrow__tv:hover,
.coinrow__tv:focus-visible {
  color: var(--accent); border-color: var(--accent-line);
  background: var(--accent-soft);
}

/* ---------- Sharia check ----------
   A link out to the room's own source, not a verdict rendered here. Green
   because it is the compliant path, not because this app has judged the
   coin -- nothing in this codebase decides that. */
.halalbtn {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  width: 100%; padding: 9px 12px; margin-top: -2px;
  font-family: var(--mono); font-size: 14px; letter-spacing: -.02em;
  text-transform: uppercase;
  background: var(--gain-soft); border: 1px solid var(--gain-line);
  border-radius: var(--r-sm, 3px); color: var(--gain);
  cursor: pointer; transition: background-color .14s, border-color .14s, color .14s;
}
.halalbtn:hover { background: rgba(255,255,255,0.08); border-color: var(--gain); }
.halalbtn[hidden] { display: none; }
.halalbtn svg { flex: none; }

/* The `hidden` attribute is only `display: none` from the browser's own
   stylesheet, so ANY author rule that sets display beats it -- .seg--acct
   is display:grid, so hiding the Practice/Real switch in JS did nothing and
   "REAL · DEX SOON" stayed on screen through the practice-only launch. The
   same trap already caught .field once. This closes it for every element
   rather than one selector at a time: if something carries `hidden`, it is
   hidden, whatever else the sheet says. */
[hidden] { display: none !important; }


/* "Coming soon" marker. Sits inline ahead of the lede rather than floating
   over the cards, so it reads as a statement about the room instead of a
   badge stuck on each course. */
.soon-badge {
  display: inline-block; margin-right: 10px;
  font-family: var(--mono); font-size: 14px; line-height: 1;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--accent);
  border: 1px solid var(--accent); border-radius: 3px;
  padding: 5px 8px; vertical-align: 2px;
}


/* Lightweight Charts injects a TradingView link into the pane. Hidden here
   rather than removed from the DOM, so the library never notices it is gone
   and tries to re-add it. NOTE: the library's licence asks for this
   attribution to stay unless you hold a commercial agreement with
   TradingView -- a business decision, not a technical one. */
#tv-attr-logo,
a#tv-attr-logo,
.tv-lightweight-charts a[href*="tradingview.com"] {
  display: none !important;
}

/* ---- raises ---- */

.raises__bar { flex-wrap: wrap; gap: 10px; align-items: center; }
/* Sized to sit in the filter bar, styling inherited from .field__input so
   it matches the screener's search rather than the browser's default. */
.raises__search { min-width: 220px; flex: 1; max-width: 320px; height: 30px; }
.raises__tier[aria-pressed="true"] { color: var(--accent); border-color: var(--accent); }

/* Table and leaderboard side by side; the board drops under the table when
   there is no room for both, rather than squeezing the investor column. */
.raises__layout { display: grid; grid-template-columns: minmax(0, 1fr) 270px; gap: 20px; align-items: start; }
@media (max-width: 1100px) { .raises__layout { grid-template-columns: minmax(0, 1fr); } }

.tbl--raises td { vertical-align: top; }
.nowrap { white-space: nowrap; }
.raise__name { font-weight: 510; color: var(--fg); }
.raise__sector {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: 13px; line-height: 1.35;
  color: var(--fg-3); margin-top: 3px;
}

/* A dot rather than a badge: it marks the row without competing with the
   amount, which is the number the eye is looking for. */
.tierpip {
  display: inline-block; width: 6px; height: 6px; border-radius: 999px;
  background: var(--accent); margin-inline-start: 6px; vertical-align: 2px;
}

.raise__inv { min-width: 300px; }
/* Fixed layout so the investor column keeps its width instead of being
   squeezed to nothing by a long sector description, which was stacking the
   chips one per line. */
.tbl--raises { table-layout: fixed; width: 100%; }
.tbl--raises th:nth-child(1) { width: 92px; }
.tbl--raises th:nth-child(3) { width: 132px; }
.tbl--raises th:nth-child(4) { width: 96px; }
.tbl--raises th:nth-child(5) { width: 34%; }
/* Wraps rather than overflowing: "Public token sale" is wider than the
   column and was printing straight over the Raised figure. */
.raise__round { white-space: normal; line-height: 1.25; }

/* Round sits hard against the project description otherwise. The extra
   inset gives the column its own space without widening it. */
.tbl--raises th:nth-child(3),
.tbl--raises td:nth-child(3) { padding-inline-start: 26px; }
.inv {
  display: inline-block; font-size: 13px; line-height: 1;
  padding: 3px 6px; margin: 0 4px 4px 0; border-radius: 3px;
  border: 1px solid var(--line); color: var(--fg-3);
}
/* Who led is the signal; everyone else participated. */
.inv--lead { color: var(--fg); border-color: var(--line-lift); }
.inv--more { color: var(--fg-3); border-style: dashed; }

.raises__side { border: 1px solid var(--line); border-radius: 8px; padding: 14px; }
.raises__side .blockhead { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.raises__side .blockhead h2 { font-size: 17px; margin: 0; }
/* 11px floor: this is a functional label (which period the board covers),
   not legal smallprint, so it does not get the 10px exception. */
.raises__side .blockhead span { font-family: var(--mono); font-size: 13px; color: var(--fg-3); white-space: nowrap; }
.fundlist { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 8px; }
.fund { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; font-size: 14px; }
.fund__name { color: var(--fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fund__sum { color: var(--fg-2); font-family: var(--mono); }
.fund__deals { grid-column: 1; color: var(--fg-3); font-size: 13px; }

/* Token outlook chip. Three states, colour-coded the way the rest of the
   room reads: accent for a token that exists or is being sold, quiet grey
   for an equity round nobody will ever hold a piece of. */
.tokchip {
  /* The cell wraps so a long round label cannot overflow; the chip itself
     must not, or "Token likely" breaks across two lines. */
  display: block; width: fit-content; margin-top: 5px; white-space: nowrap;
  font-family: var(--mono); font-size: 13px; line-height: 1;
  padding: 3px 6px; border-radius: 3px; border: 1px solid var(--line);
  color: var(--fg-3);
}
.tokchip--token  { color: var(--accent); border-color: var(--accent); }
.tokchip--likely { color: var(--fg-2); border-color: var(--line-lift); }
.tokchip--equity { color: var(--fg-3); border-style: dashed; }

/* Fund mark: a circle holding initials, with the favicon laid over them.
   Doing it this way means a missing or broken logo degrades to a monogram
   with no error handling beyond hiding the image. */
.fund { grid-template-columns: 26px 1fr auto; align-items: center; }
.fund__logo {
  position: relative; grid-row: span 2;
  width: 26px; height: 26px; border-radius: 7px;
  display: grid; place-items: center;
  background: var(--btn); border: 1px solid var(--line);
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
  overflow: hidden;
}
/* contain, not cover: these are brand marks with their own margins, and
   cropping a wordmark to fill a square is how a logo stops being one.
   Same treatment as the VC portfolio cards. */
.fund__logo img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; padding: 3px;
}
.fund__name { grid-column: 2; }
.fund__deals { grid-column: 2; }
.fund__sum { grid-column: 3; grid-row: 1 / span 2; align-self: center; }

/* Project cell: mark, name, then the links that actually exist. */
.raise__head { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.raise__logo {
  position: relative;
  /* Fixed on all three axes. flex:none alone still let the disc be
     squeezed by a long project name, so some rows carried a smaller
     circle than others. */
  flex: 0 0 22px; width: 22px; height: 22px; min-width: 22px;
  border-radius: 999px;
  display: grid; place-items: center; overflow: hidden;
  /* A light disc rather than the panel colour: most of these marks are
     drawn black for a white site and vanished against a dark circle. */
  background: #e8e8ee; border: 1px solid var(--line);
  font-family: var(--mono); font-size: 13px; color: #494949;
}
.raise__logo img {
  /* Inset by two so the mark sits inside the ring instead of running
     under it, and contained rather than cropped -- several of these are
     wide wordmarks that "cover" was cutting in half. Width and height are
     stated explicitly: an absolutely positioned image with width:auto
     sizes from its own ratio and ignores the insets entirely. */
  position: absolute; inset: 2px;
  width: calc(100% - 4px); height: calc(100% - 4px);
  object-fit: contain; border-radius: 999px;
  background: transparent;
}
.raise__link {
  font-family: var(--mono); font-size: 13px; line-height: 1;
  padding: 2px 5px; border: 1px solid var(--line); border-radius: 3px;
  color: var(--fg-3); text-decoration: none;
}
.raise__link:hover { color: var(--fg); border-color: var(--fg-3); }

/* ---- portfolios ---- */

.pf__layout { display: block; }
.pf__list {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(176px, 1fr));
}

/* A card per fund rather than a table row: the name is the thing being
   chosen, and a grid of cards makes 43 of them scannable. Square, because
   the logo is the fastest way to find a fund you already know -- you
   recognise Paradigm's mark before you finish reading the word. */
.pfcard {
  position: relative;
  display: flex; flex-direction: column; align-items: flex-start;
  aspect-ratio: 1 / 1;
  gap: 0; padding: 16px; text-align: start; cursor: pointer;
  border: 1px solid var(--line); border-radius: 14px;
  background: var(--bg-elev); color: var(--fg);
  overflow: hidden;
  transition: border-color .15s ease, transform .15s ease, background .15s ease;
}
/* A wash that only shows on hover -- enough to say "this is the one" on a
   dark grid without lighting the whole card up. */
.pfcard::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 80% at 50% 0%,
              rgba(255,255,255,.05), transparent 70%);
  opacity: 0; transition: opacity .15s ease;
}
.pfcard:hover { border-color: var(--fg-3); transform: translateY(-2px); }
.pfcard:hover::after { opacity: 1; }
.pfcard:focus-visible { outline: 2px solid var(--fg-3); outline-offset: 2px; }

.pfcard__mark {
  position: relative;
  width: 46px; height: 46px; flex: none; margin-bottom: auto;
  display: grid; place-items: center;
  border-radius: 12px;
  background: var(--btn); border: 1px solid var(--line);
  font-family: var(--mono); font-size: 15px; letter-spacing: -.02em;
  color: var(--fg-2); overflow: hidden;
}
/* The logo sits over the monogram rather than replacing it, so a file that
   fails to load degrades to initials instead of an empty box. contain,
   never cover: several of these are wide wordmarks and cropping them to a
   square would cut the name in half. */
.pfcard__mark img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain; padding: 6px;
}
/* Logos are shown exactly as their owners drew them -- no white tiles,
   no inversion. A mark that is dark stays dark. */

/* The monogram is the fallback, not a backdrop: once a logo has loaded it
   is the only thing in the tile. If the image fails, the script clears
   this class and the initials come back. */
.pfcard__mark.has-logo .pfcard__mark__txt { visibility: hidden; }
.pfcard__name {
  font-size: 17px; letter-spacing: -.02em; line-height: 1.25;
  margin-top: 14px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.pfcard__row {
  display: flex; align-items: baseline; gap: 8px;
  margin-top: 6px; flex-wrap: wrap;
}
.pfcard__cap { font-family: var(--mono); font-size: 15px; color: var(--fg-2); }
.pfcard__chg { font-family: var(--mono); font-size: 14px; }
.pfcard__chg.up { color: var(--gain); }
.pfcard__chg.down { color: var(--loss); }
.pfcard__coins {
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
  margin-top: 4px; min-height: 1em;
}

.pf__detail .blockhead { display: flex; align-items: baseline; gap: 12px; margin: 14px 0 10px; }
.pf__detail .blockhead h2 { font-size: 20px; margin: 0; }
.pf__detail .blockhead span { font-family: var(--mono); font-size: 14px; color: var(--fg-3); }

.tbl--pf td { vertical-align: middle; }
.pf__sym { font-family: var(--mono); font-size: 13px; color: var(--accent); margin-inline-start: 6px; }
.pf__yes { font-family: var(--mono); font-size: 13px; color: var(--gain); }
.pf__no { color: var(--fg-3); }
.filter--sm { font-size: 13px; padding: 3px 8px; }

/* Coin cell in a portfolio: mark, name, ticker on one line. */
.pf__coin { display: flex; align-items: center; gap: 7px; }
.pf__logo {
  position: relative; flex: none;
  width: 20px; height: 20px; border-radius: 999px;
  display: grid; place-items: center; overflow: hidden;
  background: var(--bg-elev); border: 1px solid var(--line);
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
}
.pf__logo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: var(--bg-elev); }
.tbl--pf td.up { color: var(--gain); }
.tbl--pf td.down { color: var(--loss); }
.tbl--pf td.num { font-family: var(--mono); font-size: 14px; white-space: nowrap; }

/* ---- whales ---- */

.wh__bar {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; margin: 4px 0 12px;
}
.wh__filters { display: flex; gap: 6px; flex-wrap: wrap; }
.wh__search { margin-inline-start: auto; }
.wh__search input {
  width: 190px; padding: 7px 11px;
  background: var(--bg-elev); color: var(--fg);
  border: 1px solid var(--line); border-radius: 7px;
  font: inherit; font-size: 15px;
}
.wh__search input:focus { outline: none; border-color: var(--fg-3); }


.tbl--wh .wh__date { font-family: var(--mono); font-size: 14px; color: var(--fg-2); white-space: nowrap; }
.tbl--wh .wh__who { font-size: 16px; }
.wh__prod {
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
  border: 1px solid var(--line); border-radius: 4px; padding: 1px 4px;
  margin-inline-start: 4px;
}
.wh__asset {
  font-family: var(--mono); font-size: 14px; color: var(--fg-2);
  background: var(--btn); border-radius: 5px; padding: 2px 7px;
}
.wh__side {
  font-size: 13px; text-transform: uppercase; letter-spacing: .06em;
  border-radius: 5px; padding: 3px 8px;
}
.wh__side.bought { color: var(--gain); background: color-mix(in srgb, var(--gain) 13%, transparent); }
.wh__side.sold { color: var(--loss); background: color-mix(in srgb, var(--loss) 13%, transparent); }
.tbl--wh .num b { font-family: var(--mono); font-size: 15px; }
.wh__units { display: block; font-family: var(--mono); font-size: 13px; color: var(--fg-3); }
.wh__kind { font-family: var(--mono); font-size: 13px; color: var(--fg-3); }

@media (max-width: 640px) {
  .wh__search { margin-inline-start: 0; width: 100%; }
  .wh__search input { width: 100%; }
  .tbl--wh .wh__kind { display: none; }
}

/* ---- whale charts ---- */

.wh__verdict {
  display: flex; align-items: stretch; gap: 14px; flex-wrap: wrap;
  margin-bottom: 14px;
}
.wh__state {
  display: flex; flex-direction: column; justify-content: center; gap: 4px;
  padding: 13px 18px; min-width: 240px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg-elev);
  border-inline-start-width: 3px;
}
.wh__state.is-accumulation { border-inline-start-color: var(--gain); }
.wh__state.is-distribution { border-inline-start-color: var(--loss); }
.wh__state.is-mixed { border-inline-start-color: var(--fg-3); }
.wh__state-tag {
  font-size: 19px; letter-spacing: -.02em;
}
.wh__state.is-accumulation .wh__state-tag { color: var(--gain); }
.wh__state.is-distribution .wh__state-tag { color: var(--loss); }
.wh__state-note { font-size: 14px; color: var(--fg-3); }

.wh__stats {
  flex: 1; display: grid; gap: 1px; min-width: 300px;
  grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
  background: var(--line);
  border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
}
.wh__stat {
  display: flex; flex-direction: column; gap: 3px;
  padding: 11px 14px; background: var(--bg-elev);
}
.wh__stat-k {
  font-size: 13px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--fg-3);
}
.wh__stat-v { font-family: var(--mono); font-size: 17px; }
.wh__stat-v small { font-size: 13px; color: var(--fg-3); font-weight: 400; }
.wh__stat-v.up { color: var(--gain); }
.wh__stat-v.down { color: var(--loss); }

.wh__charts {
  display: grid; gap: 12px; margin-bottom: 14px;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}
.wh__chart {
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg-elev); padding: 13px 14px 8px;
  min-width: 0;                     /* or the chart canvas will not shrink */
}
.wh__chart--wide { grid-column: 1 / -1; }
.wh__chart-head { margin-bottom: 8px; }
.wh__chart-head h3 {
  font-size: 15px; font-weight: 510; letter-spacing: -.01em;
  margin: 0 0 2px;
}
.wh__chart-head span { font-size: 14px; color: var(--fg-3); }
.wh__chart-box { height: 190px; }
.wh__chart-box--tall { height: 240px; }

@media (max-width: 640px) {
  .wh__stats { min-width: 0; }
  .wh__chart-box { height: 160px; }
}

/* ---- whales as a single screen ----
   Two time-series and the feed across the top, the month comparison full
   width underneath. The page itself never scrolls -- only the feed does --
   so the gauge and the verdict stay on screen while you read the rows,
   which is the whole point of having them. */

.view--whales,
.view--raises,
.view--macro {
  padding-bottom: 14px;
  height: calc(100vh - var(--chrome-h));
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr) auto;
  gap: 10px;
}
.view--whales > * { margin: 0; }

.view--whales .wh__bar,
.view--whales .wh__verdict { margin: 0; }

.wh__top {
  display: grid; gap: 10px; min-height: 0;
  /* The feed gets the extra width: it carries five columns of text while
     the charts only need enough room to show a shape. It also runs the
     full height of the band, with the two charts and the leaderboard
     stacked beside it. */
  grid-template-columns: 1fr 1fr 1.7fr;
  grid-template-rows: auto minmax(0, 1fr);
}
.wh__chart--gauge { grid-area: 1 / 1 / 2 / 2; }
.wh__chart--cum { grid-area: 1 / 2 / 2 / 3; }
.wh__leaders { grid-area: 2 / 1 / 3 / 3; }
.wh__feed { grid-area: 1 / 3 / 3 / 4; }

.wh__leaders {
  display: flex; flex-direction: column; min-height: 0;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg-elev); padding: 10px 12px;
}
.wh__leader-list {
  flex: 1; min-height: 0; overflow: auto;
  margin-top: 6px; display: flex; flex-direction: column; gap: 3px;
}
.wh__leaders { min-height: 0; }
.wh__lead {
  display: grid; align-items: center; gap: 10px;
  grid-template-columns: 8rem minmax(0, 1fr) 4.8rem;
}
.wh__lead-track { height: 11px; }
.wh__lead-name {
  font-size: 14px; color: var(--fg-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wh__lead-track {
  position: relative; height: 13px; border-radius: 3px;
  background: var(--btn);
}
/* The zero line sits in the middle so a net seller reads as a bar going
   the other way, not just a shorter one. */
.wh__lead-track::before {
  content: ""; position: absolute; left: 50%; top: 0; bottom: 0;
  width: 1px; background: var(--line);
}
.wh__lead-bar {
  position: absolute; top: 2px; bottom: 2px; border-radius: 2px;
}
.wh__lead-bar.up { background: var(--gain); }
.wh__lead-bar.down { background: var(--loss); }
.wh__lead-val {
  font-family: var(--mono); font-size: 14px; text-align: end;
}
.wh__lead-val.up { color: var(--gain); }
.wh__lead-val.down { color: var(--loss); }
.wh__top > * { min-width: 0; min-height: 0; }

.wh__feed {
  display: flex; flex-direction: column; min-height: 0;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--bg-elev); padding: 10px 12px 10px;
}
.wh__feed-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.wh__feed .table-wrap {
  flex: 1; min-height: 0; overflow: auto;
  margin-top: 8px;
}
/* The header has to stay put once the table is its own scroll area. */
.wh__feed .tbl--wh thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--bg-elev);
}
.wh__feed .tbl--wh td, .wh__feed .tbl--wh th {
  padding-block: 7px; padding-inline: 8px;
}
/* Five columns is what fits beside two charts. The kind column is the
   first to go -- it is ETF on almost every row -- and the amount must
   never be the thing that gets clipped, since it is the number the row
   exists for. */
.wh__feed .tbl--wh .wh__kind,
.wh__feed .tbl--wh th:last-child { display: none; }
/* .tbl carries a global min-width: 560px, which is wider than this
   column and was pushing the amount -- the number the row exists for --
   off the right edge. */
.wh__feed .tbl--wh { table-layout: fixed; width: 100%; min-width: 0; }
/* Enough for "16 Sep '26" on one line. It was 4.7rem, which the
   date overran, and with the nowrap rule lost to a broken brace the
   cell wrapped to three lines and set the row height. */
.wh__feed .tbl--wh th:nth-child(1) { width: 5.4rem; }
.wh__feed .tbl--wh th:nth-child(3) { width: 3.4rem; }
.wh__feed .tbl--wh th:nth-child(4) { width: 4.6rem; }
.wh__feed .tbl--wh th:nth-child(5) { width: 5.6rem; }
.wh__feed .wh__who {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wh__feed .wh__prod { display: none; }

.view--whales .wh__chart { padding: 10px 12px 6px; display: flex; flex-direction: column; }
.view--whales .wh__chart-head { margin-bottom: 5px; }
.view--whales .wh__chart-head h3 { font-size: 14px; }
.view--whales .wh__chart-head span {
  font-size: 14px; display: block;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Shaped rather than fixed: a ratio between 16:9 and square, so the pane
   keeps its proportions as the column widens instead of turning into a
   letterbox. The max-height is what stops a wide monitor from pushing the
   leaderboard off the screen. */
.view--whales .wh__chart-box {
  flex: none; height: auto;
  aspect-ratio: 3 / 2; max-height: 25vh;
}
/* Taking height here is what shortens the band above, which is what
   makes the leaderboard scroll rather than list every name at once. */
.wh__chart--months .wh__chart-box { height: clamp(150px, 23vh, 262px); flex: none; }

.view--whales .wh__state { padding: 9px 14px; min-width: 200px; }
.view--whales .wh__state-tag { font-size: 17px; }
.view--whales .wh__stat { padding: 8px 12px; }

@media (max-width: 1200px) {
  /* The feed drops to its own full-width row rather than being squeezed
     into a third of a narrow screen. */
  .wh__top { grid-template-columns: 1fr 1fr; grid-template-rows: auto auto auto; }
  .wh__chart--gauge { grid-area: 1 / 1 / 2 / 2; }
  .wh__chart--cum { grid-area: 1 / 2 / 2 / 3; }
  .wh__leaders { grid-area: 2 / 1 / 3 / 3; min-height: 170px; }
  .wh__feed { grid-area: 3 / 1 / 4 / 3; min-height: 220px; }
}
@media (max-width: 860px) {
  .view--whales { height: auto; display: block; }
  .view--whales > * + * { margin-top: 12px; }
  .wh__top { display: flex; flex-direction: column; }
  .wh__feed .table-wrap { overflow: visible; }
  .wh__lead { grid-template-columns: 6.5rem minmax(0, 1fr) 4.4rem; }
}

/* ---- rings ----
   Shared donut chrome. It arrived with the unlocks page and stayed when that page went, because the VC deployment rings on Funding Rounds are drawn with the same markup. */

.un__rings {
  display: grid; gap: 10px; margin-bottom: 10px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.un__ringcard {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 8px;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--bg-card);
}
.un__ring-t {
  font-size: 13px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--fg-3); text-align: center;
}

.un__ring { position: relative; width: 92px; height: 92px; }
.un__ring svg { width: 100%; height: 100%; display: block; }
/* Drawn from twelve o'clock rather than three, which is where a reader
   expects a ring to start. */
.un__ring svg circle {
  fill: none; stroke-width: 11;
  transform: rotate(-90deg); transform-origin: 50% 50%;
}
.un__ring-bg { stroke: var(--btn); }
.un__ring-mid {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 1px; pointer-events: none;
}
.un__ring-mid b {
  font-family: var(--mono); font-size: 17px; font-weight: 590;
  color: var(--fg); line-height: 1;
}
.un__ring-mid small { font-size: 13px; color: var(--fg-3); }

.un__legend {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 10px;
}
.un__key {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 13px; color: var(--fg-3);
}
.un__key i { width: 7px; height: 7px; border-radius: 2px; flex: none; }

@media (max-width: 1200px) {
  .un__rings { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
}

/* ---- raises: the same dashboard shell ---- */

.view--raises { grid-template-rows: auto minmax(0, 1fr); }

/* Rounds take the width on the left, because the table is five columns
   of text; most active and the momentum rings stack down the right. */
.view--raises .wh__top {
  grid-template-columns: 1.85fr 1.05fr;
  grid-template-rows: minmax(0, 1fr) auto;
}
.rs__rounds { grid-area: 1 / 1 / 3 / 2; }
.rs__side { grid-area: 1 / 2 / 2 / 3; }
.rs__mom { grid-area: 2 / 2 / 3 / 3; }

.rs__funds { margin-top: 8px; padding-inline-end: 10px; }
.rs__funds .fundlist { margin: 0; }

.rs__rings { margin-bottom: 0; gap: 8px; }
.rs__momfoot {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  font-family: var(--mono); font-size: 13px; text-align: center;
}
.rs__momfoot .up { color: var(--gain); }
.rs__momfoot .down { color: var(--loss); }
.rs__momfoot small { font-size: 13px; color: var(--fg-3); }

.view--raises .wh__search input { width: 220px; }

.view--raises .tbl--raises { min-width: 0; }
.view--raises .wh__feed .tbl thead th {
  position: sticky; top: 0; z-index: 2; background: var(--bg-elev);
}
.view--raises .wh__feed .tbl td,
.view--raises .wh__feed .tbl th { padding-block: 7px; }

@media (max-width: 1200px) {
  .view--raises .wh__top {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto auto minmax(0, 1fr);
  }
  .rs__rounds { grid-area: 2 / 1 / 3 / 3; }
  .rs__side { grid-area: 1 / 1 / 2 / 2; min-height: 200px; }
  .rs__mom { grid-area: 1 / 2 / 2 / 3; }
}
@media (max-width: 860px) {
  .view--raises { height: auto; display: block; }
  .view--raises > * + * { margin-top: 12px; }
  .view--raises .wh__top { display: flex; flex-direction: column; }
  .view--raises .wh__search input { width: 100%; }
}

/* ---- raises: the VC deployment panel ---- */

.rs__trend {
  display: grid; gap: 8px; margin-bottom: 8px;
  /* Matches .rs__rings below, so the yearly ring sits directly over the
     quarterly one rather than 14px to its right. */
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
}
.rs__qchart {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 8px 6px;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--bg-card);
  min-width: 0;
}
.rs__qbox { width: 100%; flex: 1; min-height: 104px; }
.rs__year { grid-template-columns: 1fr; margin-bottom: 0; }

@media (max-width: 1200px) {
  .rs__trend { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 860px) {
  .rs__trend { grid-template-columns: 1fr; }
}


/* ---- raises: rounds as a feed of cards ----
   A table could not hold these. One round carries nine investors and a
   paragraph of description, the next carries two and none, so rows ran
   from 79px to 130px and no amount of ruling made that read as ordered.
   As blocks, uneven content is the layout rather than a fault in it. */

.rs__feed { padding-inline-end: 4px; }
.rcards { display: flex; flex-direction: column; gap: 8px; padding-block: 2px; }

.rcard {
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--bg-card);
  padding: 10px 12px;
  transition: border-color .14s ease, background .14s ease;
}
.rcard:hover { border-color: var(--line-strong); background: var(--bg-elev-2); }

.rcard__top {
  display: flex; align-items: center; gap: 8px; flex-wrap: nowrap;
  min-width: 0;
}
.rcard__name {
  font-size: 16px; letter-spacing: -.01em; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0;
}
.rcard__round {
  font-size: 13px; color: var(--fg-3); white-space: nowrap;
  flex: none;
}
/* The amount is the number the row exists for, so it is pinned right and
   never allowed to be the thing that gets squeezed. */
.rcard__amt {
  margin-inline-start: auto; flex: none;
  font-family: var(--mono); font-size: 16px; color: var(--fg);
}

.rcard__about {
  margin: 6px 0 0; font-size: 14px; color: var(--fg-2); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

.rcard__foot {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 10px; margin-top: 8px;
}
.rcard__inv {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; min-width: 0;
}
.rcard__meta {
  display: flex; align-items: center; gap: 6px; flex: none;
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
}
.rcard__meta time { white-space: nowrap; }

@media (max-width: 640px) {
  .rcard__top { flex-wrap: wrap; }
  .rcard__amt { margin-inline-start: 0; }
}

/* ---- dashboard filters: selected without the accent ----
   The .filter component fills its selected state with the orange accent,
   which is right in the terminal but too loud across a wall of these on
   the dashboards. Here selection reads as a lift instead: brighter text,
   a surface a step up from the bar, and a border you can actually see.
   The terminal keeps the orange. */

.view--whales .wh__bar .filter[aria-pressed="true"],
.view--whales .wh__bar .filter.is-on,
.view--raises .wh__bar .filter[aria-pressed="true"],
.view--raises .wh__bar .filter.is-on {
  color: var(--fg);
  background: var(--bg-elev-2);
  border-color: var(--line-strong);
}
.view--whales .wh__bar .filter[aria-pressed="true"]:hover,
.view--whales .wh__bar .filter.is-on:hover,
.view--raises .wh__bar .filter[aria-pressed="true"]:hover,
.view--raises .wh__bar .filter.is-on:hover {
  border-color: var(--fg-3);
}


/* ---- macro ---- */

.view--macro { grid-template-rows: auto auto minmax(0, 1fr) auto; }

/* The calendar is the thing you read, so it takes the width and the
   height; the priced rate path, the Fed wire and the tape stack beside
   it. */
/* The same three columns as the charts underneath, so the edges line up
   down the page. At 1.55fr/1fr the band broke at 963 while the charts
   broke at 1032 -- 69px out, and visible. The calendar takes two of the
   three, the stack beside it takes the third. */
.view--macro .wh__top {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: minmax(0, 1fr) auto;
}
.mc__cal  { grid-area: 1 / 1 / 3 / 3; }
.mc__path { grid-area: 1 / 3 / 2 / 4; }
.mc__news { grid-area: 2 / 3 / 3 / 4; }
.view--macro .wh__top { grid-template-rows: auto minmax(0, 1fr); }
/* ---- the two bars: hold against move ---- */

.mc__odds { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.mc__odd {
  display: grid; align-items: center; gap: 9px;
  grid-template-columns: 6.6rem minmax(0, 1fr) 2.6rem 3.2rem;
}
.mc__odd-k {
  font-size: 15px; color: var(--fg-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mc__odd-track {
  position: relative; height: 18px; border-radius: 4px;
  background: var(--btn); overflow: hidden;
}
.mc__odd-bar {
  position: absolute; left: 0; top: 0; bottom: 0; border-radius: 4px;
  transition: width .25s ease;
}
/* A hold is the base case and a move is the risk, so they do not share
   a colour. */
.mc__odd-bar.is-hold { background: var(--chart-blue); }
.mc__odd-bar.is-move { background: var(--accent); }
.mc__odd-v {
  font-family: var(--mono); font-size: 17px; color: var(--fg);
  text-align: end;
}
.mc__odd-r {
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
  text-align: end;
}

/* The longer curve as figures, so it informs without competing with the
   bars above it. */
.mc__pathstrip {
  display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap;
  margin-top: 12px; padding-top: 10px;
  border-top: 1px solid var(--line);
}
.mc__pathlab {
  width: 100%; font-size: 13px; text-transform: uppercase;
  letter-spacing: .07em; color: var(--fg-3);
}
.mc__step { display: flex; flex-direction: column; align-items: center; gap: 1px; }
.mc__step b { font-family: var(--mono); font-size: 14px; color: var(--fg-2); font-weight: 510; }
.mc__step b.up { color: var(--gain); }
.mc__step b.down { color: var(--loss); }
.mc__step small { font-family: var(--mono); font-size: 13px; color: var(--fg-3); }

/* Macro wire */
.mc__head-src {
  display: inline-block; margin-inline-end: 6px;
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
}
.mc__head:hover .mc__head-src { color: var(--accent); }
.mc__head {
  display: block; padding: 5px 0;
  font-size: 14px; line-height: 1.4; color: var(--fg-2);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
}
.mc__head:last-child { border-bottom: 0; }
.mc__head:hover { color: var(--fg); }

/* Calendar */
.view--macro .tbl--mc { table-layout: fixed; width: 100%; min-width: 0; }
.view--macro .tbl--mc th:nth-child(1) { width: 4.6rem; }
.view--macro .tbl--mc th:nth-child(2) { width: 3.2rem; }
.view--macro .tbl--mc th:nth-child(4),
.view--macro .tbl--mc th:nth-child(5) { width: 5rem; }
.view--macro .tbl--mc td,
.view--macro .tbl--mc th { padding-block: 7px; padding-inline: 8px; }
.view--macro .tbl--mc thead th {
  position: sticky; top: 0; z-index: 2; background: var(--bg-elev);
}
.mc__when { font-family: var(--mono); font-size: 14px; color: var(--fg-2); white-space: nowrap; }
.mc__ccy {
  font-family: var(--mono); font-size: 13px; color: var(--fg-2);
  background: var(--btn); border-radius: 4px; padding: 2px 5px;
}
.mc__title {
  font-size: 15px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mc__fc, .mc__prev { font-family: var(--mono); font-size: 14px; }
.mc__fc { color: var(--fg); }
.mc__prev { color: var(--fg-3); }

/* A rate decision reprices everything else on the page, so it does not
   look like another line in the list. */
.mc__fomc td { background: color-mix(in srgb, var(--accent) 9%, transparent); }
.mc__flag {
  font-family: var(--mono); font-size: 13px; color: var(--accent);
  border: 1px solid var(--accent-line); border-radius: 4px; padding: 1px 5px;
  margin-inline-start: 5px;
}

.view--macro .wh__bar .filter[aria-pressed="true"],
.view--macro .wh__bar .filter.is-on {
  color: var(--fg); background: var(--bg-elev-2); border-color: var(--line-strong);
}

@media (max-width: 1200px) {
  .view--macro .wh__top {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: minmax(0, 1fr) auto auto;
  }
  .view--macro .wh__top { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mc__cal { grid-area: 1 / 1 / 2 / 3; min-height: 240px; }
  .mc__path { grid-area: 2 / 1 / 3 / 2; }
  .mc__news { grid-area: 2 / 2 / 3 / 3; }
}
@media (max-width: 860px) {
  .view--macro { height: auto; display: block; }
  .view--macro > * + * { margin-top: 12px; }
  .view--macro .wh__top { display: flex; flex-direction: column; }
}

/* ---- macro: the inflation charts, under the calendar ---- */

/* Everything in one window, so these sit in their own row beneath the
   band rather than behind a switch. Fixed height: the band above takes
   the flexible space, and these only need enough to read a shape. */
.mc__infl {
  display: grid; gap: 10px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.mc__infl > * { min-width: 0; }
.mc__infl .wh__chart-box {
  height: clamp(118px, 17vh, 190px); flex: none; aspect-ratio: auto;
}

@media (max-width: 1100px) {
  .mc__infl { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mc__infl > *:last-child { grid-column: 1 / -1; }
}
@media (max-width: 860px) {
  .mc__infl { grid-template-columns: 1fr; }
  .mc__infl .wh__chart-box { height: 170px; }
}

/* Why a line is on the list. A promoted one is marked, because the feed
   rated it lower -- it files an FOMC member speaking as Low impact -- and
   quietly overruling the source without saying so would be worse than
   leaving it alone. */
.mc__tag {
  font-family: var(--mono); font-size: 13px; color: var(--fg-3);
  border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px;
  margin-inline-start: 5px; white-space: nowrap;
}
.mc__tag.is-up { color: var(--chart-blue); border-color: var(--chart-blue-dim); }


/* ---- terminal: the ticket column as one sidebar ----
   It used to be two separate boxes -- the ticket sized to its content
   and a positions panel floating under it -- so the column stopped
   short of the chart. One frame now, running the full height beside the
   chart: order form at the top, open positions taking the slack, and the
   practice capital pinned to the foot. */

.tradepanel {
  display: grid; grid-template-rows: auto minmax(0, 1fr) auto;
  min-height: 0; height: 100%;
  border: 1px solid var(--line); background: var(--bg-elev);
  border-radius: 10px;
  /* No overflow clip. The panel is square, so nothing needs clipping to
     a corner, and the pay-method menu opens downward from inside the
     ticket -- hiding overflow here cut it off. The parts that scroll do
     their own clipping. */
}
/* The frame belongs to the panel now, so the parts inside it stop
   drawing their own. */
.tradepanel .ticket {
  border: 0; background: none; clip-path: none;
  border-bottom: 1px solid var(--line);
  min-height: 0; overflow-y: auto;
}
.tradepanel .livepos {
  min-height: 0; padding: 0 14px;
  display: flex; flex-direction: column;
}
.tradepanel .livepos__bar { padding-top: 12px; }
.tradepanel .livepos__body { flex: 1; min-height: 0; overflow-y: auto; }

.tradepanel__capital {
  margin: 0; padding: 12px 14px 14px;
  border-top: 1px solid var(--line);
  background: var(--bg-elev-2);
  /* Follows the frame it sits in, or the fill squares off the bottom
     corners the border has already rounded. */
  border-end-start-radius: 9px; border-end-end-radius: 9px;
}

@media (max-width: 1100px) {
  /* The deck stacks below this, so the panel goes back to sizing itself
     rather than stretching to a height there is no chart to match. */
  .tradepanel { height: auto; grid-template-rows: auto auto auto; }
  .tradepanel .livepos { min-height: 150px; }
}

/* ============================================================
   SIDEBAR — the rail as a workspace nav
   Ported from a React/shadcn sidebar that reached here as
   dashboard-sidebar.tsx. None of that component ships: it is
   TypeScript, Tailwind and lucide-react, and this app has no build
   step. What is taken is its language -- a workspace tile at the top,
   grouped headings, an icon on every row, a counted item wearing a
   pill, and the account pinned under a rule at the bottom.

   This block sits last on purpose. The rail has been restyled three
   times in this sheet (chamfer, then Factory, then the shape pass);
   unpicking those would break rules that other panels still lean on,
   so the sidebar's final word is stated once, here, and wins on order.
   ============================================================ */

/* A shade below the canvas. The rail and the content used to be the
   same colour with only a hairline between them, which left the nav
   floating rather than sitting beside the work. */
.side {
  /* The rail is the app's darkest surface in Linear's product too, but it
     is #141516 rather than an inset well -- --bg-inset was two steps down
     and read as a hole beside the content. */
  background: var(--bg);
  padding: 12px 10px 10px;
  gap: 0;
}

/* ---- the workspace tile ---- */

.side__brand {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 8px; margin: 0 0 6px;
  border-radius: 8px;
  text-decoration: none;
  transition: background-color .18s ease;
}
.side__brand:hover { background: rgba(255,255,255,.045); }

.side__brand-tile {
  width: 30px; height: 30px; flex: none;
  border-radius: 7px;
  display: grid; place-items: center;
  /* Tinted, not filled. The accent is reserved for status and emphasis
     everywhere else in this app; a solid magenta square at the top of
     the rail would be the one surface spending it. */
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.08);
  color: var(--accent);
  font-family: var(--mono); font-size: 16px; font-weight: 590;
  line-height: 1; letter-spacing: 0;
}

.side__brand-text { display: grid; gap: 3px; min-width: 0; }

/* Overrides the mono, uppercase, .16em wordmark this element used to be:
   the tile carries the brand now, so the text beside it is a name. */
.side__brand-word {
  font-family: var(--sans, inherit); font-size: 15px; font-weight: 510;
  letter-spacing: -.01em; text-transform: none; color: var(--fg);
  line-height: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.side__brand-plan {
  font-family: var(--mono); font-size: 13px; letter-spacing: -.01em;
  color: var(--fg-3); line-height: 1;
}

/* ---- group headings ---- */

.side__group {
  font-family: var(--mono);
  font-size: 13px; font-weight: 510; letter-spacing: .08em;
  text-transform: uppercase; color: var(--fg-3);
  padding: 16px 10px 6px;
}
/* The first heading follows the tile, which already left its own space. */
.side__brand + .side__group { padding-top: 10px; }

/* ---- rows ---- */

.side__nav { display: grid; gap: 1px; }

.navlink {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 10px;
  border-radius: 6px; border: 1px solid transparent;
  background: transparent;
  color: var(--fg-3);
  font-family: inherit; font-size: 15px; font-weight: 400;
  letter-spacing: -.01em;
  text-decoration: none;
  transition: background-color .18s ease, color .18s ease;
}

.navlink__icon {
  width: 16px; height: 16px; flex: none;
  opacity: .72;
  transition: opacity .18s ease, color .18s ease;
}

.navlink:hover {
  background: rgba(255,255,255,.045);
  color: var(--fg-2);
  border-color: transparent;
}
.navlink:hover .navlink__icon { opacity: 1; }

.navlink[aria-current="page"] {
  background: rgba(255,255,255,.085);
  border-color: transparent;
  color: var(--fg); font-weight: 510;
}
.navlink[aria-current="page"] .navlink__icon,
.navlink[aria-current="page"] svg { color: var(--accent); opacity: 1; }

.navlink__label {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---- the count pill ----
   These spans are empty until their view reports a number. Left as a
   pill they would draw an accent dot next to five rooms that have
   nothing to count, so an empty one takes no space at all. */
.navlink__count {
  margin-inline-start: auto; flex: none;
  min-width: 20px; height: 18px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background: rgba(255,255,255,0.06); color: var(--accent);
  font-family: var(--mono); font-size: 13px; letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}
.navlink__count:empty { display: none; }

/* A locked room states it in grey, and the pill would argue with the
   padlock beside it. */
.navlink[data-locked="true"] .navlink__count { display: none; }
.navlink__lock { margin-inline-start: auto; }

/* ---- the account, under the rule ---- */

.side__foot {
  margin-top: auto;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}
.userchip {
  width: 100%;
  display: flex; align-items: center; gap: 10px;
  padding: 7px 8px;
  border-radius: 6px; border: 1px solid transparent;
  background: transparent; cursor: pointer;
  text-align: start;
  transition: background-color .18s ease;
}
.userchip:hover { background: rgba(255,255,255,.045); }
.userchip img { width: 30px; height: 30px; border-radius: 7px; flex: none; }
.userchip__text { display: grid; gap: 3px; min-width: 0; flex: 1; }
.userchip__name {
  font-size: 15px; font-weight: 510; letter-spacing: -.01em; color: var(--fg);
  line-height: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.userchip__plan {
  font-family: var(--mono); font-size: 13px; letter-spacing: -.01em;
  text-transform: none; color: var(--fg-3); line-height: 1;
}
.userchip svg { color: var(--fg-3); flex: none; }

@media (prefers-reduced-motion: reduce) {
  .side__brand, .navlink, .navlink__icon, .userchip { transition: none; }
}

/* ============================================================
   LINEAR SYSTEM — the app
   Same move as the landing page: the handoff's values are declared here
   under their own names, and the app's existing variables are re-pointed
   at them. 4,700 lines already speak in --bg / --fg / --accent, and this
   sheet carries three earlier token blocks layered on top of each other;
   renaming through all of that would be a second, riskier change wearing
   the same commit.

   Last block in the file on purpose, so it wins on source order.
   ============================================================ */

:root {
  /* -- Linear, as given -- */
  --color-void:        #08090a;
  --color-carbon:      #0f1011;
  --color-obsidian:    #161718;
  --color-graphite:    #262626;
  --color-smoke:       #3b3b3b;
  --color-ash:         #676767;
  --color-fog:         #8a8f98;
  --color-mist:        #d0d6e0;
  --color-bone:        #e5e5e6;
  --color-paper:       #ffffff;
  --color-acid-lime:   #ff2d8f;
  --color-pulse-green: #19d98b;
  --color-coral-red:   #ff3d63;

  /* -- surfaces --
     Sampled from Linear's product, not from the marketing handoff. Those
     are two different ramps: linear.app sits on #08090a, the app itself
     runs four steps lighter, from #141516 in the sidebar up to #1c1c1d on
     the panels. Using the marketing canvas here made every panel read as a
     hole rather than a surface. */
  --app-sidebar: #141516;
  --app-content: #181818;
  --app-panel:   #1c1c1d;
  --app-raised:  #232425;
  --app-hairline:#262728;

  --bg:          var(--app-sidebar);
  --bg-elev:     var(--app-content);
  --bg-elev-2:   var(--app-panel);
  --bg-inset:    #1a1a1a;
  --bg-card:     var(--app-panel);
  --bg-panel:    var(--app-panel);

  --line:        var(--app-hairline);
  --line-strong: #373737;

  --btn:            var(--app-raised);
  --btn-neutral:    var(--app-raised);
  --btn-neutral-hi: #2d2d2d;

  /* -- text --
     The product's brightest text measures #d9dee6, not white. Pure white
     is held back for the few things that have to shout; running it as the
     body colour is what makes a dark UI feel glary. */
  --fg:      #e6e6e6;
  --fg-2:    #cccccc;
  --fg-3:    #9d9d9d;
  --fg-dim:  var(--color-ash);
  --fg-quiet: #9d9d9d;
  --chalk:   var(--color-paper);

  /* The one chromatic element: acid lime, on the single primary action.
     --accent-ink is what sits ON the lime, so it has to be the canvas
     rather than white -- lime is a light fill. */
  --accent:      var(--color-acid-lime);
  --accent-hi:   #ff2d8f;
  --accent-soft: rgba(228,242,34,.12);
  --accent-line: rgba(228,242,34,.34);
  --accent-ink:  var(--color-void);

  /* Linear calls these supporting accents rather than status colours, but
     it is not a trading product and its palette has no up/down pair.
     These are the only two candidates in it. */
  --gain:      var(--color-pulse-green);
  --gain-soft: rgba(255,255,255,0.05);
  --gain-line: rgba(255,255,255,0.08);
  --loss:      var(--color-coral-red);
  --loss-soft: rgba(255,255,255,0.05);
  --warn:      var(--color-acid-lime);

  /* Candles keep the same pair, brightened on the wick so a long upper
     shadow still reads against carbon. */
  --candle-up:        #19d98b;
  --candle-up-wick:   #19d98b;
  --candle-down:      #ff3d63;
  --candle-down-wick: #ff3d63;

  /* Berkeley Mono is licensed and cannot be served; the handoff names
     JetBrains Mono as the substitute. Both faces are already imported by
     styles.css. --techno was a third display face; it collapses into the
     mono voice, which is what the handoff reserves for metadata. */
  --sans:   'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono:   'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  --techno: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;

  --shadow-sm: rgba(0, 0, 0, 0.4) 0px 2px 4px 0px;
  --shadow-subtle: #262626 0px 0px 0px 1px inset;
  --shadow-md: none; --shadow-lg: none;

  --r-sm: 4px; --r-md: 6px; --r-lg: 12px;
  --cut-sm: 0px; --cut-md: 0px; --cut-lg: 0px;
}

body {
  background: var(--bg);
  font-family: var(--sans);
  /* The alternate glyphs the handoff calls non-negotiable. */
  font-feature-settings: "cv01" on, "ss03" on, "zero" on;
  -webkit-font-smoothing: antialiased;
}

/* ---- surface hierarchy ----
   Linear's product runs three steps, and the middle one is what our sheet
   was missing: the content sits at #181818 and panels lift to #1c1c1d.
   With both on the same value a panel was only its hairline, which is why
   ours measured flat against the reference. */
body { background: var(--bg-elev); }
.side { background: var(--bg); }

.chartbox, .ticket, .card, .coinlist, .table-wrap, .connect, .meter,
.squawk__item, .room-card, .statbox, .sig, .course, .upsell,
.tradepanel, .chartbox__frame, .plane--chart {
  background: var(--bg-elev-2);
  border-radius: var(--r-lg);
}

/* Radii, the whole vocabulary: 12 for panels, 6 for controls, 4 for
   badges. Anything else in this sheet is a leftover. */
.btn, .seg, .seg__b, .navlink, .field input, .field select, .field textarea,
input[type="text"], input[type="number"], input[type="email"],
input[type="password"], select, textarea {
  border-radius: var(--r-md);
}
.badge, .tag, .pill { border-radius: var(--r-sm); }


/* ============================================================
   TYPOGRAPHY — Linear
   Measured before this block: 94% of the terminal's text was monospace,
   up to 47% of a view was forced uppercase, 405 labels on Whale Tracker
   were tracked out past .05em, and Funding Rounds rendered 176 nodes at
   10px. Linear is the opposite on every count -- Inter throughout,
   sentence case, near-zero tracking, nothing under 11px -- so this is a
   reset of the voice rather than a tune of it.
   ============================================================ */

:root {
  /* The two faces that carried the terminal voice both become Inter.
     Numbers keep their alignment through tabular figures rather than a
     monospace font, which is how Linear sets its own figures. JetBrains
     Mono stays available as --code for anything that is genuinely an id. */
  --techno: var(--sans);
  --mono:   var(--sans);
  --code:   'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}

.app {
  font-size: 15px; line-height: 1.5;
  font-variant-numeric: tabular-nums;
}

/* Sentence case and near-zero tracking everywhere in the members area.
   !important because the rules being overridden are spread across 4,700
   lines at a dozen different specificities; chasing each one would leave
   whichever was missed shouting in caps. Scoped to .app, so the landing
   page is untouched. */
.app *:not(svg):not(svg *) {
  text-transform: none !important;
  letter-spacing: -.006em !important;
}

/* Bold, as the browser defines it, is 700 -- over the scale's ceiling. */
.app b, .app strong, .app th { font-weight: 590; }

/* Headings keep a tighter set than body text, as the handoff specifies:
   the more specific selector wins between two !important declarations. */
.app h1, .app h2, .topbar h1 {
  font-weight: 510; letter-spacing: -.018em !important;
}
.app h3, .app .h-card { font-weight: 510; letter-spacing: -.012em !important; }

/* Form controls do not inherit the page font: a <button> falls back to the
   OS default -- Arial on Windows -- which is what every VC Portfolios card
   was rendering in, since each card is a button. */
.app button, .app input, .app select, .app textarea { font-family: inherit; }

/* styles.css sets the squawk headline in Geist directly rather than
   through a variable, so the token swap never reached it. */
.app .squawk__title { font-family: var(--sans); }

/* The heading rule above loses to the global reset on specificity: that
   reset's two :not() arguments score (0,1,2), which outranks .topbar h1 at
   (0,1,1). Both declare !important, so specificity decides. These carry
   an extra class to win. */
/* The weight needs !important too: an older pass pins every heading with
   `h1, h2, h3, h4 { font-weight: 400 !important }`, which a plain
   declaration can never beat. With both !important, these win on
   specificity. */
.app .topbar h1, .app .main h1, .app .main h2 {
  font-weight: 510 !important; letter-spacing: -.018em !important;
}
.app .main h3 { font-weight: 510 !important; letter-spacing: -.012em !important; }

/* ---- Macro: two sizes, not four ----
   The calendar is the model: its event names at 13px, everything that
   describes an event -- time, currency, impact, figures -- at 12px. Every
   panel on the page now follows that split. Before this, Macro mixed 11,
   12, 13 and 15, and the wire's headlines sat a size below the calendar
   beside them.

   The two large readouts (the meeting odds and the stat values) stay at
   15px: they are the figure each panel exists to show, not text. */
/* .tbl--mc .mc__title needs the table in its selector: the calendar title
   sits inside a td, and the 12px td rule below would otherwise outrank it
   and shrink the very size everything else is matched to. */
.view--macro .tbl--mc .mc__title,
.view--macro .mc__title,
.view--macro .mc__head,
.view--macro .mc__odd-k,
.view--macro .main h3,
.view--macro h3 {
  font-size: 15px;
}
.view--macro .mc__head-src,
.view--macro .mc__when,
.view--macro .mc__ccy,
.view--macro .mc__tag,
.view--macro .mc__flag,
.view--macro .mc__pathlab,
.view--macro .mc__odd-r,
.view--macro .mc__step small,
.view--macro .wh__stat-k,
.view--macro small,
.view--macro .num,
.view--macro .tbl--mc td,
.view--macro .tbl--mc th {
  font-size: 14px;
}

/* One line per headline. At 13px only 3 of 16 fit on a laptop-width panel,
   so dropping the ones that would wrap would empty the wire -- they
   truncate instead, and the full headline sits in the tooltip. */
.view--macro .mc__head {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  /* The rows are flex items in a scrolling column, and overflow:hidden
     drops a flex item's automatic minimum height to zero -- so instead of
     the list scrolling, all sixteen rows were crushed to ~10px to fit its
     171px and every headline was clipped through the middle. Holding the
     row at its own height puts the scroll back where it belongs. */
  flex-shrink: 0;
}

/* ---- Funding Rounds: most active funds, as cards ----
   Linear's subtle card: a faint white lift over the panel and an inset
   hairline, no shadow. Two across, which is what the 400px side panel
   holds without the names truncating to nothing. */
.fundlist--cards {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}
.fundcard {
  display: grid; gap: 10px; align-content: start; min-width: 0;
  padding: 12px;
  border-radius: 9px;
  /* The same ground and hairline as the VC deployment cards beside them --
     two card sets in one row reading as one set. */
  background: var(--bg-card);
  border: 1px solid var(--line);
  transition: background-color .15s var(--ease, ease), border-color .15s var(--ease, ease);
}
.fundcard:hover { background: var(--app-raised); border-color: var(--line-strong); }

.fundcard__top { display: flex; align-items: center; justify-content: space-between; }
/* The existing monogram-under-favicon mark, just larger and freed from
   the row grid it was built for. */
.fundcard .fund__logo {
  grid-row: auto; width: 42px; height: 42px;
  border-radius: 11px; font-size: 15px;
}
.fundcard .fund__logo img { padding: 6px; }
/* Marks drawn black -- a16z, Pantera, YZi Labs and half the rest -- are
   invisible on this card. Inverted, black becomes white and the card stays
   dark; a coloured mark is never touched, because inverting one would
   change the brand's own colours. logo_tiles.py decides which is which. */
.fund__logo img.is-inverted { filter: invert(1) brightness(1.1); }
.fundcard__rank {
  font-size: 14px; color: var(--fg-3);
  font-variant-numeric: tabular-nums;
}

.fundcard__name {
  font-size: 15px; font-weight: 510; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fundcard__stats {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
}
.fundcard__deals { font-size: 14px; color: var(--fg-3); }
.fundcard__sum {
  font-size: 15px; color: var(--fg-2);
  font-variant-numeric: tabular-nums;
}


/* ============================================================
   VS CODE NEUTRALS
   The surfaces are VS Code's Dark Modern ramp -- #181818 rail, #1f1f1f
   content, #252526 panels, #2b2b2b hairlines -- and every one is pure
   neutral, red = green = blue. The Linear product ramp this replaces ran a
   couple of points cool, and on top of it sat green and red washes behind
   every up and down state, which is what read as dark green and brown.

   Colour now lives only in text and lines, the way VS Code does it: a
   gain is a green number on a grey row, never a green row.
   ============================================================ */
:root {
  /* Declared here, in the last block, rather than edited in place above:
     every earlier surface token resolves through these, so this is the one
     place the ramp is set. */
  --app-sidebar:  #121212;
  --app-content:  #181818;
  --app-panel:    #1e1e1e;
  --app-raised:   #262626;
  --app-hairline: #262626;
  --bg-inset:     #141414;
  --line-strong:  #333333;
  --btn-neutral-hi: #333333;

  --fg:       #e6e6e6;
  --fg-2:     #cccccc;
  --fg-3:     #9d9d9d;
  --fg-quiet: #9d9d9d;
  --shadow-subtle: #262626 0px 0px 0px 1px inset;

  --gain-soft:   rgba(255, 255, 255, .05);
  --loss-soft:   rgba(255, 255, 255, .05);
  --accent-soft: rgba(255, 255, 255, .06);
  --gain-line:   var(--line-strong);
  --loss-line:   var(--line-strong);
  --accent-line: var(--line-strong);
  --color-ash:   #8c8c8c;
  --fg-dim:      #8c8c8c;
}

/* Investor names on a round wrap to two or three lines, and were set at
   11px on a line-height of 1 -- the lines touched. */
.inv { font-size: 14px; line-height: 1.45; }
.room__hint { font-size: 14px; line-height: 1.5; }

/* Chart grounds sit on the panel colour, not a separate near-black. */
.chartbox__frame, .plane--chart { background: var(--app-panel); }



/* ============================================================
   GREEN AND MAGENTA
   Yellow is out entirely. One green everywhere -- #19d98b, the one the
   chart settings swatch carries -- and magenta for the accent and the
   down candles. Backgrounds stay the VS Code grays; colour is text,
   lines, candles and the few solid controls, never a wash.
   ============================================================ */
:root {
  --color-acid-lime:   #ff2d8f;
  --color-pulse-green: #19d98b;
  --color-coral-red:   #ff3d63;

  --accent:      #ff2d8f;
  --accent-hi:   #ff5ba8;
  --accent-ink:  #1a0010;
  --warn:        #ff2d8f;

  --gain: #19d98b;
  --loss: #ff3d63;

  --candle-up:        #19d98b;
  --candle-up-wick:   #19d98b;
  --candle-down:      #ff2d8f;
  --candle-down-wick: #ff2d8f;
}

/* Room between the next-meeting heading and its bars: it was 10px, which
   read as the date sitting on top of the odds. */
.view--macro .mc__odds { margin-top: 26px; }

/* The top tile is the member's profile photo rather than a letter. */
.side__brand-tile--photo {
  padding: 0; object-fit: cover; background: var(--bg-elev-2);
  border: 1px solid var(--line);
}

/* The signal form's two sections: the levels and the outcome. */
.sigmodal__section { display: grid; gap: 16px; }
.sigmodal__section[hidden] { display: none; }
.sigmodal__section + .sigmodal__section { padding-top: 16px; border-top: 1px solid var(--line); }
.sig__actions { display: flex; gap: 8px; flex-wrap: wrap; }


/* ============================================================
   TERMINAL GRAY
   The content canvas moves to #202226 -- the gray in the swatch, a hair
   cooler than the neutral ramp above it. Everything that sat on that
   canvas moves with it: a panel a step lighter than the page it sits on
   is the only reason cards read as cards, so shifting the ground alone
   would flatten the whole room.
   ============================================================ */
:root {
  --app-sidebar:  #08090b;   /* one step under the canvas, as before */
  --app-content:  #0f1013;   /* the swatch, four steps down */
  --app-panel:    #15161a;
  --app-raised:   #1d1f23;
  --app-hairline: #1d1f23;
  --bg-inset:     #0b0c0e;
  --line-strong:  #292c31;
  --btn-neutral-hi: #292c31;
  --shadow-subtle: #1d1f23 0px 0px 0px 1px inset;

  /* The chart takes the room's own ground: no seam between the canvas and
     the page it sits on, which is how it reads once the panel around it is
     the only frame. */
  --chart-bg:     #0f1013;
}


/* Chart grounds take the chart colour, not the panel it sits in. */
.chartbox__frame, .plane--chart { background: var(--chart-bg); }


/* Macro, the whale tracker and the VC portfolios are reading rooms, not a
   chart: rows, names and numbers, held for minutes at a time. Their cards
   sit a step off the page instead of nearly on it, so a table reads as a
   surface. The page itself stays the terminal's black.

   Scoped to .main, not to body: body paints its own background from
   --bg-elev, so redefining it there would lift the page as well as the
   cards on it. Inside .main the same names reach every card and nothing
   underneath them. And they are the resolved names rather than
   --app-panel, because the ramp above resolves on :root -- redefining a
   token :root already substituted changes nothing this far down. */
body[data-room="macro"] .main,
body[data-room="whales"] .main,
body[data-room="portfolios"] .main {
  --bg-elev:      #16181c;
  --bg-elev-2:    #16181c;
  --bg-card:      #16181c;
  --bg-panel:     #16181c;
  --app-panel:    #16181c;
  --app-raised:   #1e2025;
  --btn:          #1e2025;
  --btn-neutral:  #1e2025;
}


/* ---- members, on the room lead's profile ---- */
.members { margin-top: clamp(32px, 4vw, 48px); display: grid; gap: 14px; }
.members__count { font-size: 13px; color: var(--fg-3); }
.table-wrap[data-memberlog] { max-height: 420px; overflow-y: auto; }
.table-wrap[data-memberlog] .tbl thead th {
  position: sticky; top: 0; background: var(--bg-elev); z-index: 1;
}
/* The handle under the display name: two people can share a first name,
   and the button acts on the handle. */
.members__user { display: block; font-family: var(--mono); font-size: 13px; color: var(--fg-3); }
.members__none { color: var(--fg-dim); }
.members__plan {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  font-size: 13px; border: 1px solid var(--line-strong); color: var(--fg-3);
}
.members__plan[data-plan="paid"] { color: var(--gain); border-color: var(--gain-line); }
.members__act { text-align: end; white-space: nowrap; }
.members__you { font-size: 13px; color: var(--fg-dim); }
.members__note { margin: 0; font-size: 13px; line-height: 1.55; color: var(--fg-dim); }
