/* Shared application shell: reset, sidebar, topbar, cards, buttons, pills,
   dialogs and motion. Every page loads tokens.css then this file. */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: 'Inter', -apple-system, 'Segoe UI', sans-serif;
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

.num,
table td,
.stat-value,
.portfolio-value {
  font-variant-numeric: tabular-nums;
}

/* Components below set explicit `display`, which would otherwise beat the
   `hidden` attribute. */
[hidden] {
  display: none !important;
}

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
textarea,
select {
  font: inherit;
  color: inherit;
}

::selection {
  background: var(--cyan-dim);
}

:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ------------------------------------------------------------------ */
/* Layout                                                              */
/* ------------------------------------------------------------------ */

.app {
  display: flex;
  min-height: 100vh;
}

.main {
  flex: 1;
  min-width: 0;
  margin-inline-start: 232px;
  padding: 26px 30px 56px;
  max-width: 1520px;
}

/* ------------------------------------------------------------------ */
/* Sidebar                                                             */
/* ------------------------------------------------------------------ */

.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  width: 232px;
  background: var(--surface);
  border-inline-end: .5px solid var(--border);
  display: flex;
  flex-direction: column;
  padding: 18px 14px 14px;
  z-index: 20;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 4px 8px 20px;
}

.brand-mark {
  /* The mark is the accent itself — it does not sit in a filled tile. */
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  flex: none;
}

.brand-name {
  font-size: 15px;
  font-weight: 650;
  letter-spacing: -.01em;
}

.brand-sub {
  font-size: 10.5px;
  color: var(--text-muted);
  letter-spacing: .06em;
  text-transform: uppercase;
}

.nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.nav-label {
  font-size: 10.5px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 6px 10px;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  border: .5px solid transparent;
  font-size: 13.5px;
  transition: background .16s var(--ease), color .16s var(--ease),
    border-color .16s var(--ease);
}

.nav-item svg {
  flex: none;
  opacity: .85;
}

.nav-item:hover {
  background: var(--surface-raised);
  color: var(--text);
}

.nav-item.is-active {
  background: var(--cyan-dim);
  border-color: var(--border-strong);
  color: var(--text);
}

.nav-item.is-active svg {
  color: var(--cyan);
  opacity: 1;
}

.nav-soon {
  margin-inline-start: auto;
  font-size: 9.5px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
  border: .5px solid var(--border);
  border-radius: 20px;
  padding: 1px 6px;
}

.sidebar-spacer {
  flex: 1;
}

.profile {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px;
  border-radius: var(--radius-md);
  border: .5px solid var(--border);
  background: var(--surface-raised);
  transition: border-color .18s var(--ease);
}

.profile:hover {
  border-color: var(--border-strong);
}

.avatar {
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 50%;
  background: var(--purple-dim);
  color: var(--purple);
  display: grid;
  place-items: center;
  font-weight: 650;
  font-size: 12.5px;
  border: .5px solid var(--border-strong);
}

.profile-name {
  font-size: 13px;
  font-weight: 550;
  line-height: 1.25;
}

.profile-plan {
  font-size: 11px;
  color: var(--text-muted);
}

/* ------------------------------------------------------------------ */
/* Page header                                                         */
/* ------------------------------------------------------------------ */

.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: 22px;
}

/* Both halves of a page head are flex items, and a flex item keeps its
   content width unless told otherwise. A longer greeting therefore widened
   the header instead of wrapping inside it. */
.page-head > * {
  min-width: 0;
}

.page-title {
  font-size: 22px;
  font-weight: 650;
  letter-spacing: -.02em;
  margin: 0;
  /* A greeting carries the reader's name, and a translated greeting is
     longer before the name even starts. It wraps rather than widening the
     header. */
  min-width: 0;
  overflow-wrap: anywhere;
}

.page-sub {
  color: var(--text-secondary);
  font-size: 13px;
  margin: 3px 0 0;
}

.head-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* The Portfolio switcher (portfolio-switch.js): only present when the
   account has more than one portfolio. */
.book-switch {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-secondary);
}

.book-switch select {
  background: var(--surface);
  color: var(--text);
  border: .5px solid var(--border-strong);
  border-radius: var(--radius-sm, 8px);
  padding: 6px 10px;
  font: inherit;
  font-size: 13px;
  max-width: 220px;
}

.book-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* ------------------------------------------------------------------ */
/* Cards                                                               */
/* ------------------------------------------------------------------ */

.card {
  background: var(--surface);
  border: .5px solid var(--border);
  border-radius: var(--radius-lg);
  transition: border-color .18s var(--ease);
}

.card:hover {
  border-color: var(--border-strong);
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px 18px;
  border-bottom: .5px solid var(--border);
  flex-wrap: wrap;
}

/* The title block inside a card head is a flex item, and a flex item will
   not shrink below its own content unless it is told it may. A longer
   translated title therefore widened the card instead of wrapping. */
.card-head > div {
  min-width: 0;
}

/* A table that is genuinely wider than a phone scrolls inside its own box
   rather than taking the page with it. Defined here so every page has it,
   not only the two that happened to declare their own. */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* A path, an address or a key inside running text has no spaces in it,
   so without this it is one unbreakable word as wide as it is long. */
.row-hint code,
.hint code,
.field-hint code {
  overflow-wrap: anywhere;
}

.card-title {
  font-size: 14px;
  font-weight: 600;
  margin: 0;
  letter-spacing: -.01em;
  /* A German compound — "Performance-Aufschlüsselung" — is one word and
     has nowhere ordinary to break, so at 390px it pushed the whole card
     head past the screen. Let it break inside itself rather than making
     the type smaller. */
  min-width: 0;
  overflow-wrap: anywhere;
}

.card-sub {
  font-size: 12px;
  color: var(--text-secondary);
  margin: 2px 0 0;
}

.card-body {
  padding: 18px;
}

/* ------------------------------------------------------------------ */
/* Buttons                                                             */
/* ------------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 550;
  cursor: pointer;
  border: .5px solid transparent;
  background: transparent;
  transition: background .16s var(--ease), border-color .16s var(--ease),
    color .16s var(--ease), opacity .16s var(--ease);
  white-space: nowrap;
}

.btn:disabled {
  opacity: .55;
  cursor: default;
}

.btn-primary {
  background: var(--cyan);
  color: var(--on-accent);
  font-weight: 600;
}

.btn-primary:hover:not(:disabled) {
  background: #4FE6DB;
}

.btn-secondary {
  border-color: var(--border-strong);
  color: var(--text);
}

.btn-secondary:hover:not(:disabled) {
  border-color: var(--cyan);
  background: var(--cyan-dim);
}

.btn-cyan {
  border-color: var(--border-strong);
  background: var(--cyan-dim);
  color: var(--cyan);
}

.btn-cyan:hover:not(:disabled) {
  border-color: var(--cyan);
}

.btn-danger {
  background: var(--red-dim);
  border-color: var(--red);
  color: var(--red);
}

.btn-danger:hover:not(:disabled) {
  background: rgba(241, 102, 122, .2);
}

.btn-ghost {
  color: var(--text-secondary);
  padding: 6px 8px;
}

.btn-ghost:hover:not(:disabled) {
  color: var(--text);
  background: var(--surface-raised);
}

.btn-sm {
  padding: 6px 11px;
  font-size: 12.5px;
}

/* ------------------------------------------------------------------ */
/* Inputs                                                              */
/* ------------------------------------------------------------------ */

.input,
.textarea {
  width: 100%;
  background: var(--bg);
  border: .5px solid var(--border-strong);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  font-size: 13px;
  transition: border-color .16s var(--ease), background .16s var(--ease);
}

.input::placeholder,
.textarea::placeholder {
  color: var(--text-muted);
}

.input:focus,
.textarea:focus {
  outline: none;
  border-color: var(--cyan);
  background: var(--surface-raised);
}

.textarea {
  resize: vertical;
  min-height: 84px;
  line-height: 1.55;
}

.field {
  display: block;
  margin-bottom: 14px;
}

.field-label {
  display: block;
  font-size: 12px;
  color: var(--text-secondary);
  margin-bottom: 6px;
}

.field-hint {
  font-size: 11.5px;
  color: var(--text-muted);
  margin-top: 6px;
}

.search {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.search svg {
  position: absolute;
  inset-inline-start: 10px;
  color: var(--text-muted);
  pointer-events: none;
}

.search .input {
  padding-inline-start: 32px;
  min-width: 220px;
}

/* Toggle switch */
.switch {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}

.switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.switch-track {
  width: 38px;
  height: 21px;
  border-radius: 20px;
  background: var(--surface-raised);
  border: .5px solid var(--border-strong);
  position: relative;
  transition: background .16s var(--ease), border-color .16s var(--ease);
  flex: none;
}

.switch-track::after {
  content: '';
  position: absolute;
  top: 2px;
  inset-inline-start: 2px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: var(--text-muted);
  transition: transform .18s var(--ease), background .18s var(--ease);
}

.switch input:checked + .switch-track {
  background: var(--cyan-dim);
  border-color: var(--cyan);
}

.switch input:checked + .switch-track::after {
  transform: translateX(17px);
  background: var(--cyan);
}

.switch input:focus-visible + .switch-track {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------ */
/* Status pills                                                        */
/* ------------------------------------------------------------------ */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  border-radius: 20px;
  font-size: 11.5px;
  font-weight: 500;
  border: .5px solid transparent;
  /* A pill holds a status word, and a status word does not want to break
     mid-phrase — but a translated one can be a whole sentence, and
     `nowrap` alone made that a 500px element on a 390px screen. It may
     now use a second line when there is nothing else it can do. */
  white-space: nowrap;
  max-width: 100%;
}

/* A pill that is a message rather than a label: let it wrap. */
p.pill,
.pill.is-message {
  white-space: normal;
}

.pill::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

.pill-plain::before {
  display: none;
}

.pill-green {
  background: var(--green-dim);
  color: var(--green);
}

.pill-red {
  background: var(--red-dim);
  color: var(--red);
}

.pill-amber {
  background: var(--amber-dim);
  color: var(--amber);
}

.pill-cyan {
  background: var(--cyan-dim);
  color: var(--cyan);
}

.pill-purple {
  background: var(--purple-dim);
  color: var(--purple);
}

.pill-muted {
  background: var(--surface-raised);
  color: var(--text-secondary);
  border-color: var(--border);
}

.tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border-radius: var(--radius-sm);
  font-size: 11px;
  color: var(--text-secondary);
  background: var(--surface-raised);
  border: .5px solid var(--border);
}

.pos {
  color: var(--green);
}

.neg {
  color: var(--red);
}

.muted {
  color: var(--text-muted);
}

.secondary {
  color: var(--text-secondary);
}

/* Exchange avatar */
.exchange-mark {
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: var(--radius-md);
  display: grid;
  place-items: center;
  font-weight: 650;
  font-size: 14px;
  border: .5px solid var(--border-strong);
}

.tone-cyan {
  background: var(--cyan-dim);
  color: var(--cyan);
}

.tone-green {
  background: var(--green-dim);
  color: var(--green);
}

.tone-red {
  background: var(--red-dim);
  color: var(--red);
}

.tone-amber {
  background: var(--amber-dim);
  color: var(--amber);
}

.tone-purple {
  background: var(--purple-dim);
  color: var(--purple);
}

/* ------------------------------------------------------------------ */
/* Dialogs                                                             */
/* ------------------------------------------------------------------ */

dialog {
  border: none;
  padding: 0;
  background: transparent;
  color: var(--text);
  max-width: min(640px, calc(100vw - 32px));
  width: 100%;
}

dialog::backdrop {
  background: var(--overlay);
  backdrop-filter: blur(2px);
  animation: backdrop-in .2s var(--ease);
}

dialog[open] .dialog-panel {
  animation: panel-in .2s var(--ease);
}

.dialog-panel {
  background: var(--surface);
  border: .5px solid var(--border-strong);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .55);
}

.dialog-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding: 16px 18px;
  border-bottom: .5px solid var(--border);
}

.dialog-title {
  font-size: 15px;
  font-weight: 620;
  margin: 0;
  letter-spacing: -.01em;
}

.dialog-sub {
  font-size: 12.5px;
  color: var(--text-secondary);
  margin: 3px 0 0;
}

.dialog-body {
  padding: 18px;
  max-height: min(64vh, 560px);
  overflow-y: auto;
}

.dialog-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  padding: 14px 18px;
  border-top: .5px solid var(--border);
  background: var(--surface-raised);
}

.dialog-foot .foot-note {
  margin-inline-end: auto;
  font-size: 11.5px;
  color: var(--text-muted);
}

@keyframes backdrop-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes panel-in {
  from { opacity: 0; transform: scale(.98); }
  to { opacity: 1; transform: scale(1); }
}

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

.reveal {
  opacity: 0;
  transform: translateY(6px);
  animation: reveal .28s var(--ease) forwards;
}

@keyframes reveal {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.spinner {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  animation: spin .7s linear infinite;
  flex: none;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.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;
}

/* ------------------------------------------------------------------ */
/* Responsive                                                          */
/* ------------------------------------------------------------------ */

@media (max-width: 1080px) {
  .sidebar {
    width: 68px;
    padding: 18px 10px 14px;
  }
  .sidebar .brand-text,
  .sidebar .nav-label,
  .sidebar .nav-item span,
  .sidebar .profile-text {
    display: none;
  }
  .nav-item,
  .brand,
  .profile {
    justify-content: center;
  }
  .main {
    margin-inline-start: 68px;
    padding: 22px 18px 48px;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal {
    opacity: 1;
    transform: none;
  }
}

/* ------------------------------------------------------------------ */
/* Global "Add trade" (sidebar, above the profile card)                */
/* ------------------------------------------------------------------ */

/* Upgrade card (sidebar, free accounts only) and the shared upgrade modal. */
.upgrade-card {
  position: relative;
  margin-bottom: 10px;
  padding: 11px 12px 12px;
  border-radius: var(--radius-md);
  border: .5px solid rgba(45, 217, 206, .35);
  background: var(--cyan-dim);
}

.upgrade-title {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--cyan);
  font-size: 12.5px;
  font-weight: 600;
}

.upgrade-text {
  margin: 5px 0 9px;
  color: var(--text-secondary);
  font-size: 11.5px;
  line-height: 1.45;
}

.upgrade-card .upgrade-cta { width: 100%; }

.upgrade-dismiss {
  position: absolute;
  top: 6px;
  inset-inline-end: 6px;
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
}

.upgrade-dismiss:hover { color: var(--text); background: var(--surface-raised); }

html[data-nav="collapsed"] .sidebar .upgrade-card { display: none; }

.upgrade-dialog { border: none; background: none; padding: 0; max-width: min(900px, calc(100vw - 32px)); }
.upgrade-dialog::backdrop { background: rgba(3, 7, 12, .62); }

.upgrade-period {
  display: inline-flex;
  padding: 3px;
  border-radius: var(--radius-sm);
  border: .5px solid var(--border-strong);
  background: var(--surface);
  margin-bottom: 14px;
}

.upgrade-period button {
  padding: 6px 14px;
  border: none;
  border-radius: calc(var(--radius-sm) - 2px);
  background: none;
  color: var(--text-secondary);
  font: inherit;
  font-size: 12.5px;
  font-weight: 550;
  cursor: pointer;
}

.upgrade-period button.is-active { background: var(--cyan-dim); color: var(--cyan); }

.upgrade-plans {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px;
}

.upgrade-plan {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 16px 14px 14px;
  border-radius: var(--radius-md);
  border: .5px solid var(--border);
  background: var(--surface-raised);
}

.upgrade-plan.is-recommended { border-color: rgba(45, 217, 206, .5); }
.upgrade-plan.is-current { border-color: var(--border-strong); opacity: .92; }

.upgrade-flag {
  position: absolute;
  top: -8px;
  inset-inline-start: 14px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--cyan);
  color: #04121a;
  font-size: 10.5px;
  font-weight: 650;
}

.upgrade-flag.is-current-flag { background: var(--surface); color: var(--text-secondary); border: .5px solid var(--border-strong); }

.upgrade-plan h3 { margin: 2px 0 0; font-size: 14px; font-weight: 600; }
.upgrade-price { font-size: 22px; font-weight: 650; letter-spacing: -.4px; }
.upgrade-price .muted { font-size: 12.5px; font-weight: 500; }
.upgrade-sub-price { color: var(--text-muted); font-size: 11.5px; margin-top: -4px; }

.upgrade-trial {
  align-self: flex-start;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--green-dim);
  color: var(--green);
  font-size: 11px;
  font-weight: 550;
}

.upgrade-feats { list-style: none; margin: 6px 0 10px; padding: 0; display: grid; gap: 5px; }
.upgrade-feats li { display: flex; align-items: flex-start; gap: 7px; font-size: 12px; color: var(--text-secondary); }
.upgrade-feats li svg { flex: none; margin-top: 1px; color: var(--green); }
.upgrade-feats li.is-off { color: var(--text-muted); }
.upgrade-feats li.is-off svg { color: var(--text-muted); }
.upgrade-plan .btn { margin-top: auto; }

.upgrade-note {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  padding: 9px 11px;
  border-radius: var(--radius-sm);
  border: .5px solid rgba(244, 183, 64, .45);
  background: var(--amber-dim);
  color: var(--text-secondary);
  font-size: 12px;
}

.upgrade-note svg { color: var(--amber); flex: none; }

.upgrade-foot {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 14px 0 0;
  color: var(--text-muted);
  font-size: 11.5px;
}

.upgrade-foot svg { flex: none; color: var(--cyan); }

/* Sign out — same sidebar footprint in the app and the Admin workspace. */
.sidebar-signout {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin-top: 8px;
  padding: 9px 12px;
  border-radius: var(--radius-md);
  border: .5px solid var(--border);
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: 12.5px;
  font-weight: 550;
  cursor: pointer;
}

.sidebar-signout:hover:not(:disabled) {
  color: var(--red);
  border-color: var(--red);
  background: var(--red-dim);
}

.sidebar-signout:disabled {
  opacity: .6;
  cursor: default;
}

.add-trade-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin-bottom: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  border: .5px solid rgba(45, 217, 206, .35);
  background: var(--cyan-dim);
  color: var(--cyan);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background .16s var(--ease), border-color .16s var(--ease);
}

.add-trade-btn:hover {
  background: rgba(45, 217, 206, .2);
  border-color: var(--cyan);
}

.add-trade-btn:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}

@media (max-width: 1080px) {
  .sidebar .add-trade-btn span {
    display: none;
  }

  .sidebar .add-trade-btn {
    padding: 10px 0;
  }
}

/* ------------------------------------------------------------------ */
/* Collapsible sidebar (html[data-nav="collapsed"] = icon rail)     */
/* ------------------------------------------------------------------ */

.sidebar,
.main {
  transition: width .18s var(--ease), margin-left .18s var(--ease), padding .18s var(--ease);
}

.brand {
  position: relative;
}

.brand-text {
  min-width: 0;
}

.sidebar-toggle {
  margin-inline-start: auto;
  width: 28px;
  height: 28px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: var(--radius-sm);
  border: .5px solid transparent;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: background .16s var(--ease), color .16s var(--ease), border-color .16s var(--ease);
}

.sidebar-toggle:hover {
  background: var(--surface-raised);
  color: var(--text);
  border-color: var(--border);
}

.sidebar-toggle:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}

.sidebar-toggle .ico-expand {
  display: none;
}

html[data-nav="collapsed"] .sidebar {
  width: 68px;
  padding: 18px 10px 14px;
}

html[data-nav="collapsed"] .main {
  margin-inline-start: 68px;
}

html[data-nav="collapsed"] .sidebar .brand {
  flex-direction: column;
  gap: 8px;
  padding: 4px 0 16px;
}

html[data-nav="collapsed"] .sidebar .brand-text,
html[data-nav="collapsed"] .sidebar .nav-label,
html[data-nav="collapsed"] .sidebar .nav-item span,
html[data-nav="collapsed"] .sidebar .add-trade-btn span,
html[data-nav="collapsed"] .sidebar .sidebar-signout span,
html[data-nav="collapsed"] .sidebar .profile-text {
  display: none;
}

html[data-nav="collapsed"] .sidebar .sidebar-toggle {
  margin-inline-start: 0;
}

html[data-nav="collapsed"] .sidebar .sidebar-toggle .ico-collapse {
  display: none;
}

html[data-nav="collapsed"] .sidebar .sidebar-toggle .ico-expand {
  display: block;
}

html[data-nav="collapsed"] .sidebar .nav-item,
html[data-nav="collapsed"] .sidebar .profile {
  justify-content: center;
  padding-inline-start: 0;
  padding-inline-end: 0;
}

html[data-nav="collapsed"] .sidebar .add-trade-btn {
  padding: 10px 0;
}

/* Below 1080px the rail is forced; the toggle would only overlap content. */
@media (max-width: 1080px) {
  .sidebar .sidebar-toggle {
    display: none;
  }
}

/* ------------------------------------------------------------------ */
/* Phone: the sidebar is a drawer                                      */
/* ------------------------------------------------------------------ */

/* Measured on the signed-in shell before this existed: the icon rail is 68px
   at every width below 1080px, so on a 360px phone the eleven pages all
   rendered into 256px — 71% of the screen — and Accounts and Trades, the two
   densest pages in the app, were the ones paying for it. At 768px the same
   rail costs 8.9%, which is a fair price for navigation that is always there.
   So the rail stays everywhere it is cheap and becomes a drawer where it is
   not, and 720px is where that line falls.

   The drawer is the sidebar itself, moved off-canvas. There is no second
   navigation anywhere in this stylesheet or in app-shell.js: active state,
   icons, badges, the Admin entry, the feature-flagged entries, Add trade, the
   profile card and Sign out are the same nodes they always were, which is why
   none of them can drift out of step with the desktop menu. */

/* Both exist in the markup at every width; only the phone shows them. */
.app-bar,
.nav-scrim,
.nav-close {
  display: none;
}

@media (max-width: 720px) {
  /* A fixed bar rather than a sticky one: on a 60-row Trades table the menu
     has to be reachable without scrolling back to the top. .main pays for its
     height in padding below. */
  .app-bar {
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    gap: 10px;
    block-size: 52px;
    padding-inline: 10px;
    background: var(--surface);
    border-block-end: .5px solid var(--border);
  }

  .nav-trigger {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 11px 7px 9px;
    border-radius: var(--radius-md);
    border: .5px solid var(--border);
    background: var(--surface-raised);
    color: var(--text);
    font: inherit;
    font-size: 13px;
    font-weight: 550;
    cursor: pointer;
  }

  .nav-trigger:hover {
    border-color: var(--border-strong);
  }

  .nav-trigger:focus-visible {
    outline: 2px solid var(--cyan);
    outline-offset: 2px;
  }

  /* The count the nav entries already carry, surfaced on the closed trigger:
     with the menu shut, an unread badge inside it cannot be seen. */
  .nav-trigger-dot {
    inline-size: 6px;
    block-size: 6px;
    border-radius: 50%;
    background: var(--cyan);
    flex: none;
  }

  .app-bar .brand-mark {
    inline-size: 26px;
    block-size: 26px;
  }

  .app-bar-name {
    font-size: 14px;
    font-weight: 650;
    letter-spacing: -.01em;
  }

  /* The drawer. `visibility` is what keeps a closed drawer out of the tab
     order and out of the accessibility tree — no inert polyfill, and nothing
     for a screen reader to walk into behind the page. */
  .sidebar {
    inline-size: min(292px, 84vw);
    padding: 14px 12px 14px;
    z-index: 60;
    visibility: hidden;
    transform: translateX(var(--drawer-out, -100%));
    transition: transform .24s var(--ease), visibility 0s linear .24s;
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  html[data-drawer="open"] .sidebar {
    visibility: visible;
    transform: translateX(0);
    transition: transform .24s var(--ease), visibility 0s;
    box-shadow: 0 0 60px rgba(0, 0, 0, .55);
  }

  .nav-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 50;
    background: rgba(0, 0, 0, .5);
    opacity: 0;
    visibility: hidden;
    transition: opacity .24s var(--ease), visibility 0s linear .24s;
  }

  html[data-drawer="open"] .nav-scrim {
    opacity: 1;
    visibility: visible;
    transition: opacity .24s var(--ease), visibility 0s;
  }

  /* The X. It sits in the brand row, where the collapse toggle sits on a
     desktop — the same corner, the same size, the opposite job. */
  .nav-close {
    display: grid;
    place-items: center;
    margin-inline-start: auto;
    inline-size: 30px;
    block-size: 30px;
    flex: none;
    border-radius: var(--radius-sm, 8px);
    border: .5px solid var(--border);
    background: var(--surface-raised);
    color: var(--text-secondary);
    cursor: pointer;
  }

  .nav-close:hover {
    color: var(--text);
    border-color: var(--border-strong);
  }

  .nav-close:focus-visible {
    outline: 2px solid var(--cyan);
    outline-offset: 2px;
  }

  /* The collapse toggle is a desktop control; inside a drawer it would offer
     to turn a full-width panel into a 68px one on top of the page. */
  .sidebar .sidebar-toggle {
    display: none;
  }

  /* The page gets the whole width back, and the bar's height in padding. */
  .main {
    margin-inline-start: 0;
    padding: 66px 14px 48px;
  }

  /* A drawer is a panel, so it reads as one: the labels the 1080px rail hides
     come back, and a collapse saved on a desktop does not follow the account
     onto its phone. */
  .sidebar .brand-text,
  .sidebar .nav-label,
  .sidebar .nav-item span,
  .sidebar .add-trade-btn span,
  .sidebar .sidebar-signout span,
  .sidebar .admin-link span,
  .sidebar .profile-text,
  html[data-nav="collapsed"] .sidebar .brand-text,
  html[data-nav="collapsed"] .sidebar .nav-label,
  html[data-nav="collapsed"] .sidebar .nav-item span,
  html[data-nav="collapsed"] .sidebar .add-trade-btn span,
  html[data-nav="collapsed"] .sidebar .sidebar-signout span,
  html[data-nav="collapsed"] .sidebar .admin-link span,
  html[data-nav="collapsed"] .sidebar .profile-text {
    display: block;
  }

  .sidebar .nav-item,
  .sidebar .brand,
  .sidebar .profile,
  html[data-nav="collapsed"] .sidebar .nav-item,
  html[data-nav="collapsed"] .sidebar .profile {
    justify-content: flex-start;
  }

  html[data-nav="collapsed"] .sidebar .upgrade-card {
    display: block;
  }

  html[data-nav="collapsed"] .sidebar .add-trade-btn {
    justify-content: center;
  }

  /* Background scrolling stops while the drawer is open. Both elements are
     named because which one scrolls is the browser's choice, and hiding
     overflow on the scrolling element keeps its position rather than
     resetting it, which is why the page is where it was on close. */
  html[data-drawer="open"],
  html[data-drawer="open"] body {
    overflow: hidden;
  }
}

/* A drawer that appears and disappears is a drawer, not an animation. */
@media (prefers-reduced-motion: reduce) {
  .sidebar,
  .nav-scrim {
    transition: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar,
  .main {
    transition: none;
  }
}

a.profile,
a.brand-mark {
  color: inherit;
  text-decoration: none;
}

a.brand-mark {
  color: inherit;
}

/* Admin entry (admins only) above Add trade */
.admin-link {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-bottom: 8px;
  padding: 9px 12px;
  border-radius: var(--radius-md);
  border: .5px solid var(--border);
  background: var(--purple-dim);
  color: var(--purple);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
}

.admin-link:hover {
  border-color: var(--purple);
}

/* The label is hidden when the sidebar is collapsed, but the link still has
   to promise not to grow: a longer word — "Administración" — was widening
   the sidebar itself on a phone. */
.admin-link span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

html[data-nav="collapsed"] .sidebar .admin-link span {
  display: none;
}

.nav-item.is-planned {
  opacity: .55;
  cursor: default;
}

.tag.tag-amber {
  color: var(--amber);
  background: var(--amber-dim);
}

.tag.tag-amber {
  color: var(--amber);
  background: var(--amber-dim);
}

/* Admin-controlled banners ------------------------------------------ */
.app-banners { display: grid; gap: 8px; margin: 0 0 14px; }
.app-banners:empty { display: none; }
.app-banner { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; border-radius: var(--radius-md); border: .5px solid var(--border-strong); background: var(--surface-raised); font-size: 12.5px; line-height: 1.45; }
.app-banner svg { flex: none; margin-top: 1px; }
.app-banner > div { flex: 1; }
.app-banner.is-info { border-color: rgba(45, 217, 206, .4); background: var(--cyan-dim); }
.app-banner.is-info svg { color: var(--cyan); }
.app-banner.is-warning { border-color: rgba(244, 183, 64, .45); background: var(--amber-dim); }
.app-banner.is-warning svg { color: var(--amber); }
.app-banner.is-success { border-color: rgba(62, 213, 152, .45); background: var(--green-dim); }
.app-banner.is-success svg { color: var(--green); }
.app-banner-close { background: none; border: none; color: var(--text-muted); font-size: 16px; line-height: 1; cursor: pointer; padding: 0 2px; }
.app-banner-close:hover { color: var(--text); }
/* A close button reached by keyboard needs a ring of its own: the banner sits
   on a tinted panel where the page's default outline colour disappears. */
.app-banner-close:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; border-radius: 4px; color: var(--text); }
/* The optional link inside a banner. Inline so it flows with the sentence
   rather than becoming a second block on a narrow screen. */
.app-banner-cta { margin-inline-start: 6px; color: var(--cyan); text-decoration: underline; text-underline-offset: 2px; white-space: nowrap; }
.app-banner-cta:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; border-radius: 3px; }

/* Standing disclosure that a page's figures cover allocated trades only. */
.journal-notice {
  padding: 10px 12px;
  border: .5px solid var(--amber);
  border-radius: var(--radius-sm);
  background: var(--amber-dim);
  color: var(--text-secondary);
  font-size: 12.5px;
  line-height: 1.5;
}

.journal-notice b {
  color: var(--text);
}

/* ------------------------------------------------------------------ */
/* Language selector                                                   */
/*                                                                     */
/* A plain <select>. It is the control a visitor is most likely to look */
/* for in a language they cannot read, which is the argument for the    */
/* platform's own widget over a prettier custom menu: it is keyboard-   */
/* operable, screen-reader-labelled and familiar on a phone, in every   */
/* language, for free.                                                  */
/* ------------------------------------------------------------------ */

.lang-field { display: inline-flex; align-items: center; gap: 8px; }
.lang-field select {
  appearance: none;
  background: var(--surface-raised);
  border: .5px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: 12.5px;
  padding: 6px 28px 6px 10px;
  cursor: pointer;
  /* The chevron is drawn on the trailing edge whichever way the page reads. */
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 12px center, right 7px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
[dir="rtl"] .lang-field select {
  padding: 6px 10px 6px 28px;
  background-position: left 12px center, left 7px center;
  background-image: linear-gradient(135deg, transparent 50%, currentColor 50%), linear-gradient(45deg, currentColor 50%, transparent 50%);
}
.lang-field select:hover { border-color: var(--border-strong); color: var(--text); }
.lang-field select:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }
.lang-field select:disabled { opacity: .6; cursor: progress; }
/* Same reason as the in-app .select option rule: the native popup would
   otherwise print the names in the control's muted grey on white. */
.lang-field select option { background: var(--surface); color: var(--text); }

/* On the auth pages it sits under the card, centred and quiet. */
.auth-lang { display: flex; justify-content: center; margin-top: 16px; }

/* ---- sync control: "● Live API · Updated 42s ago · [↻ Sync]" ---------- */
/* One control on every page (scripts/sync-control.js). Logical properties
   only, so Arabic mirrors it without a rule in rtl.css. */
.sync-ctl { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.sync-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-muted); flex: 0 0 auto; }
.sync-dot.is-live { background: var(--green); box-shadow: 0 0 0 3px color-mix(in srgb, var(--green) 22%, transparent); }
.sync-dot.is-attention { background: var(--amber); box-shadow: 0 0 0 3px color-mix(in srgb, var(--amber) 22%, transparent); }
.sync-dot.is-running { background: var(--cyan); animation: sync-pulse 1.2s ease-in-out infinite; }
.sync-dot.is-off { background: var(--text-muted); }
.sync-text { display: inline-flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.sync-label { font-size: 12px; font-weight: 600; color: var(--text); white-space: nowrap; }
/* The per-connection line is announced, not displayed. Spelling out
   "Coinbase — Main: Syncing deposits and withdrawals…" in the header reserved
   260px for a sentence that changes every few seconds and pushed the rest of
   the row around as it did. The dot already carries the state and the button
   already says "Syncing"; the detail is on the control's tooltip.

   Hidden the accessible way rather than with display:none, because this is the
   live region a screen reader reads progress from — same idiom as the button
   label below. */
.sync-updated { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.sync-btn { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
/* While a run is in flight the refresh glyph gives way to the brand mark —
   see styles/logo.css. One indicator, never two. */
.sync-btn-icon { display: inline-grid; place-items: center; }
@keyframes sync-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) {
  .sync-dot.is-running { animation: none; }
}
@media (max-width: 480px) {
  .sync-btn .sync-btn-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .sync-btn { padding-inline: 9px; }
}

/* ---- toast: one quiet result notification (scripts/toast.js) ----------- */
.toast-host { position: fixed; inset-block-end: 18px; inset-inline-end: 18px; z-index: 60; max-width: min(420px, calc(100vw - 32px)); }
.toast { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border-radius: var(--radius-md, 12px); background: var(--surface-elevated, var(--surface)); border: 1px solid var(--border-strong); box-shadow: 0 12px 32px rgba(0, 0, 0, .28); color: var(--text); animation: toast-in .18s ease-out; }
.toast-icon { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: 50%; flex: 0 0 auto; margin-block-start: 1px; }
.toast.is-ok .toast-icon { background: color-mix(in srgb, var(--green) 18%, transparent); color: var(--green); }
.toast.is-warn .toast-icon { background: color-mix(in srgb, var(--amber) 18%, transparent); color: var(--amber); }
.toast.is-error .toast-icon { background: color-mix(in srgb, var(--red) 18%, transparent); color: var(--red); }
.toast.is-info .toast-icon { background: color-mix(in srgb, var(--cyan) 18%, transparent); color: var(--cyan); }
.toast-body { min-width: 0; flex: 1 1 auto; }
.toast-title { font-weight: 600; font-size: 13.5px; }
.toast-detail { font-size: 12.5px; color: var(--text-secondary); margin-block-start: 2px; }
.toast-action { display: inline-block; margin-block-start: 6px; font-size: 12.5px; font-weight: 600; color: var(--cyan); }
.toast-close { flex: 0 0 auto; border: 0; background: transparent; color: var(--text-secondary); cursor: pointer; padding: 2px; border-radius: 6px; }
.toast-close:hover { color: var(--text); }
@keyframes toast-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .toast { animation: none; } }

/* How many things are waiting on the reader behind a navigation entry.
   Quiet by design: a count, not a colour-shout, and hidden when it is zero. */
.nav-item .nav-badge {
  margin-inline-start: auto;
  min-width: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--cyan-dim);
  color: var(--cyan);
  font-size: 10.5px;
  font-weight: 650;
  line-height: 17px;
  text-align: center;
}

/* ------------------------------------------------------------------ */
/* Client view: the owner's pages, read-only                           */
/* ------------------------------------------------------------------ */

/* One line that never leaves the screen. Deliberately small: a mentor on a
   call or a recording should be looking at UnifyTrade, not at a page
   covered in permission notices. */
.client-bar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 14px;
  padding: 8px 14px;
  border: 1px solid color-mix(in srgb, var(--cyan) 45%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, var(--cyan) 12%, var(--bg-elevated));
  font-size: 13px;
  backdrop-filter: blur(6px);
}

.client-bar > svg { flex: none; color: var(--cyan); }
.client-bar .cb-who { min-width: 0; }
.client-bar .cb-ro {
  padding: 2px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--cyan) 22%, transparent);
  color: var(--cyan);
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .02em;
  text-transform: uppercase;
  white-space: nowrap;
}
.client-bar .cb-exit { margin-inline-start: auto; flex: none; }

/* Everything that would change the client's data, hidden in one place.
   This is presentation only — the server refuses every one of these
   regardless, and api() refuses to send them. It exists so a mentor is
   never offered a control that cannot work. The list is generated from
   MUTATION_CONTROL_SELECTORS and MUTATION_ACTIONS in client-view.js, which
   is also what the regression test reads, so the two cannot drift. */
[data-client-view] [data-add-trade],
[data-client-view] [data-admin-link],
[data-client-view] [data-sync-status],
[data-client-view] #btn-import,
[data-client-view] #btn-manual,
[data-client-view] [data-fav],
[data-client-view] [data-review],
[data-client-view] [data-add-tx],
[data-client-view] [data-tx-add],
[data-client-view] [data-tx-remove],
[data-client-view] [data-remove-tag],
[data-client-view] #btn-add-source,
[data-client-view] #btn-allocate,
[data-client-view] [data-add-source],
[data-client-view] [data-add-src],
[data-client-view] [data-add-activity],
[data-client-view] [data-add-allocation],
[data-client-view] [data-remove-activity],
[data-client-view] [data-remove-holding],
[data-client-view] [data-src-sync],
[data-client-view] [data-qa="tx"],
[data-client-view] [data-src-remove],
[data-client-view] [data-ep-allocate],
[data-client-view] [data-ep-settings],
[data-client-view] [data-portfolio-access],
[data-client-view] [data-pm-create],
[data-client-view] [data-pm-edit],
[data-client-view] [data-pm-save],
[data-client-view] [data-pm-delete],
[data-client-view] [data-pm-rotate],
[data-client-view] [data-camp-edit],
[data-client-view] [data-camp-delete],
[data-client-view] [data-add],
[data-client-view] #btn-add-widget,
[data-client-view] #btn-dash-menu,
[data-client-view] .customize-toggle,
[data-client-view] [data-cx-edit],
[data-client-view] [data-cx-remove],
[data-client-view] [data-cx-form],
[data-client-view] [data-connect],
[data-client-view] [data-edit-conn],
[data-client-view] [data-delete-conn],
[data-client-view] .acc-actions,
[data-client-view] .row-actions button,
[data-client-view] .src-actions button,
[data-client-view] [data-act="add"],
[data-client-view] [data-act="allocate"],
[data-client-view] [data-act="allocate-more"],
[data-client-view] [data-act="customize"],
[data-client-view] [data-act="delete"],
[data-client-view] [data-act="edit"],
[data-client-view] [data-act="fav"],
[data-client-view] [data-act="reset"],
[data-client-view] [data-act="return"],
[data-client-view] [data-act="review"],
[data-client-view] [data-act="revoke"],
[data-client-view] [data-act="role"],
[data-client-view] [data-act="tx"] {
  display: none !important;
}

/* A shared portfolio's bar also carries the exports its owner allowed. */
.client-bar .cb-exports { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.client-bar.is-shared .cb-exports { margin-inline-start: auto; }
.client-bar.is-shared .cb-exports + .cb-exit { margin-inline-start: 0; }

@media (max-width: 640px) {
  .client-bar { flex-wrap: wrap; row-gap: 8px; }
  .client-bar .cb-exit { margin-inline-start: 0; }
  .client-bar.is-shared .cb-exports { margin-inline-start: 0; }
}

/* ---------------------------------------------------------------------
   The mark on a chart somebody else is reading.

   Two surfaces show a trader's charts to someone who is not that trader:
   a mentor inside a client view, and whoever opens a shared portfolio
   link. Both are places the picture travels from — a screenshot into a
   coaching call, a link into a group — and it used to arrive saying
   nothing about where it was made. So the main charts on those two
   surfaces sign themselves once, in the corner.

   It is a signature, not a control: the opacity of a printed watermark,
   no pointer events, nothing to click, and the U comes from the same
   /assets/brand/logo-mark.svg every other surface uses, so the geometry
   still lives in one file. A trader's own charts in their own account
   carry nothing — they already know whose they are. */
:is(
  [data-client-view] .chart-wrap,
  [data-client-view] .value-chart,
  [data-client-view] .big-chart,
  [data-client-view] .asset-chart,
  .pub-chart-wrap
)::after {
  content: "UnifyTrade";
  position: absolute;
  inset-inline-end: 14px;
  bottom: 10px;
  z-index: 1;
  display: flex;
  align-items: center;
  padding-inline-start: 21px;
  background: url("/assets/brand/logo-mark.svg") no-repeat left center / 15px 15px;
  font-size: 12.5px;
  font-weight: 650;
  letter-spacing: -.01em;
  line-height: 1;
  color: var(--cyan);
  opacity: .17;
  pointer-events: none;
  user-select: none;
}

/* In Arabic the row reads right to left, so the mark leads from the right.
   The padding is already logical — it reserves the start side whichever way
   the page runs — and only the image, which has no logical position of its
   own, has to be told. */
[dir="rtl"] :is(
  [data-client-view] .chart-wrap,
  [data-client-view] .value-chart,
  [data-client-view] .big-chart,
  [data-client-view] .asset-chart,
  .pub-chart-wrap
)::after {
  background-position: right center;
}

/* A chart with nothing in it is not a chart to sign. Written as its own
   rule so that a browser without :has() simply keeps the signature rather
   than losing it along with the whole block. */
:is(
  [data-client-view] .chart-wrap,
  [data-client-view] .value-chart,
  [data-client-view] .big-chart,
  [data-client-view] .asset-chart,
  .pub-chart-wrap
):has(.chart-empty)::after {
  content: none;
}

/* The shared portfolio's own chart, which is an <svg> and so cannot carry a
   pseudo-element of its own. */
.pub-chart-wrap {
  position: relative;
}

/* ---------------------------------------------------------------------
   The Notification Center.

   A bell in the header group every page already has, and a panel anchored
   under it. Compact on purpose: this is a short list of things that
   happened, not a page. Category is never carried by colour — green and
   red belong to money, and a notification's own kind is told by its words
   and, where it helps, by weight. */

.ntf-wrap { position: relative; display: inline-flex; }

.ntf-bell { position: relative; }

/* The count is a visual shorthand; the button's accessible name carries the
   same number in words, so the badge is never the only way to know. */
.ntf-count {
  position: absolute;
  top: -4px;
  inset-inline-end: -4px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--cyan);
  color: var(--on-accent, #05201f);
  font-size: 10.5px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}

.ntf-panel {
  position: absolute;
  top: calc(100% + 8px);
  inset-inline-end: 0;
  z-index: 60;
  /* 400, not 360: a title and its time now share a line, and 360 made the
     longer titles wrap under the time. */
  width: min(400px, calc(100vw - 32px));
  max-height: min(76vh, 600px);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, .34);
  overflow: hidden;
}
.ntf-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
.ntf-head h2 { margin: 0; font-size: 14px; font-weight: 650; }
/* The one action in this panel, in the accent the rest of the product uses
   for one: .btn .btn-cyan .btn-sm, the family already defined above. It was
   btn-ghost, which is --text-secondary on a dark panel — quiet to the point
   of not being seen. Before that it carried an invented class of its own,
   which matched no rule at all and left the browser to draw it a grey box
   with an outset border. Both tokens it uses are redefined for the light
   theme, so it follows that too. */
.ntf-mark-all { padding-block: 4px; font-size: 12px; }
.ntf-body { overflow-y: auto; overscroll-behavior: contain; flex: 1 1 auto; }
/* The day stays in view while its rows scroll under it: at the bottom of a
   long Yesterday there is otherwise nothing on screen that says which day
   "11:52 PM" belongs to. */
.ntf-group {
  position: sticky;
  top: 0;
  z-index: 1;
  margin: 0;
  padding: 9px 14px 6px;
  background: var(--surface);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.ntf-list { margin: 0; padding: 0; list-style: none; }
.ntf-item + .ntf-item { border-top: .5px solid var(--border); }

/* One colour per kind, carried as a variable so the tile, the accent rule and
   the action all agree without each restating the palette. */
.ntf-item { --tone: var(--text-muted); --tone-dim: var(--surface-raised); }
.ntf-item[data-tone="red"] { --tone: var(--red); --tone-dim: var(--red-dim); }
.ntf-item[data-tone="amber"] { --tone: var(--amber); --tone-dim: var(--amber-dim); }
.ntf-item[data-tone="green"] { --tone: var(--green); --tone-dim: var(--green-dim); }
.ntf-item[data-tone="cyan"] { --tone: var(--cyan); --tone-dim: var(--cyan-dim); }
.ntf-item[data-tone="purple"] { --tone: var(--purple); --tone-dim: var(--purple-dim); }

.ntf-hit {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  width: 100%;
  padding: 11px 14px 12px;
  border: 0;
  border-inline-start: 2px solid transparent;
  background: none;
  color: inherit;
  font: inherit;
  text-align: start;
  text-decoration: none;
  cursor: pointer;
}
.ntf-hit:hover { background: var(--surface-raised); }
.ntf-hit:focus-visible { outline: 2px solid var(--cyan); outline-offset: -2px; }

/* The kind, at a glance. */
.ntf-ico {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 30px;
  block-size: 30px;
  border-radius: 9px;
  color: var(--tone);
  background: var(--tone-dim);
}

.ntf-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 auto; }
/* Title and time on one line: the time was a line of its own under every
   row, which made each row three lines tall and the drawer half as long as
   it looked. */
.ntf-row1 { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.ntf-title { font-size: 13px; font-weight: 550; line-height: 1.35; color: var(--text-secondary); }
.ntf-body-line,
.ntf-text .ntf-body { font-size: 12px; line-height: 1.45; color: var(--text-muted); }
.ntf-when { flex: none; font-size: 11px; color: var(--text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
/* A ticker or a position name is somebody else's string and can be long;
   it wraps rather than widening the panel. */
.ntf-title,
.ntf-text .ntf-body { overflow-wrap: anywhere; }

/* Unread is said three ways — a tint on the row, a dot, a heavier title —
   and never by colour alone. Read rows step back to the secondary text. */
.ntf-dot {
  flex: none;
  width: 7px;
  height: 7px;
  margin-top: 6px;
  border-radius: 999px;
  background: transparent;
}
.ntf-item.is-unread .ntf-hit { background: color-mix(in srgb, var(--cyan) 5%, transparent); }
.ntf-item.is-unread .ntf-hit:hover { background: color-mix(in srgb, var(--cyan) 9%, transparent); }
.ntf-item.is-unread .ntf-dot { background: var(--cyan); }
.ntf-item.is-unread .ntf-title { font-weight: 650; color: var(--text); }
.ntf-item.is-unread .ntf-text .ntf-body { color: var(--text-secondary); }

/* Something that wants the reader: an accent on the leading edge, and the
   thing to do, named. Only while unread — a retired notice is history. */
.ntf-item.is-attn .ntf-hit { border-inline-start-color: var(--tone); }
.ntf-act {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  align-self: flex-start;
  margin-top: 3px;
  font-size: 12px;
  font-weight: 600;
  color: var(--tone);
}
[dir="rtl"] .ntf-act svg { transform: scaleX(-1); }

.ntf-empty { padding: 26px 18px; text-align: center; }
.ntf-empty p { margin: 0 0 6px; font-size: 13px; }
.ntf-empty p.muted { font-size: 12px; color: var(--text-muted); }

/* The switches live in Settings; the drawer points at them. */
.ntf-foot {
  display: flex;
  align-items: center;
  gap: 7px;
  min-block-size: 40px;
  padding: 0 14px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  color: var(--text-muted);
  text-decoration: none;
}
.ntf-foot:hover,
.ntf-foot:focus-visible { color: var(--text); background: var(--surface-raised); }
/* On a phone the panel keeps its anchor and simply narrows.
   ---------------------------------------------------------------------
   It briefly did the opposite: `.ntf-wrap { position: static }` with
   `inset-inline: 16px`, so that the panel could span the screen. Taking the
   wrapper out of the positioning flow left the panel with no positioned
   ancestor, so `top: calc(100% + 8px)` resolved against the page rather
   than against the bell — it rendered 820px down a 843px viewport, half a
   screen below the button that opened it.
   The width rule above is already `min(360px, calc(100vw - 32px))`, which
   is what a phone needed all along; the anchor never had to be given up. */
@media (max-width: 560px) {
  .ntf-panel { max-height: 70vh; }
}

/* A navigation entry whose page is a preview says so in a word beside its
   label, not in a colour: the same information reaches a reader who cannot
   see the tint. It is not the .nav-planned chip, which marks an entry that
   cannot be opened at all. */
.nav-preview {
  margin-inline-start: auto;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--cyan-dim);
  color: var(--cyan);
  font-size: 9.5px;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
  white-space: nowrap;
}
html[data-nav="collapsed"] .nav-preview { display: none; }
