/* ==========================================================================
   Components
   ========================================================================== */

/* --- Rail (sidebar) ------------------------------------------------------ */

.rail {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100dvh;
  z-index: var(--z-rail);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-5) var(--sp-4);
  box-shadow: var(--shadow-1), inset -1px 0 0 var(--stroke);
}
.rail::before { display: none; }

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3) var(--sp-5);
}
.brand__mark {
  width: 34px; height: 34px;
  border-radius: 11px;
  display: grid; place-items: center;
  background: linear-gradient(145deg, var(--accent-hi), var(--accent-lo));
  color: var(--text-on-accent);
  font-weight: 700; font-size: .9rem;
  letter-spacing: -.02em;
  box-shadow: 0 4px 14px -4px var(--accent-ring), inset 0 1px 0 rgba(255,255,255,.4);
}
.brand__name { font-family: var(--font-display); font-weight: 650;
               color: var(--text-1); letter-spacing: -.02em; }
.brand__role { font-size: var(--t-micro); letter-spacing: .09em;
               text-transform: uppercase; color: var(--text-3); }

.nav { display: grid; gap: 2px; }
.nav__item {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-3);
  border-radius: var(--r-sm);
  color: var(--text-2);
  font-size: var(--t-body);
  font-weight: 500;
  transition: background-color var(--dur-1) linear, color var(--dur-1) linear;
}
.nav__item:hover { background: var(--row-hover); color: var(--text-1); }
.nav__item[aria-current="page"] {
  background: var(--accent-wash);
  color: var(--text-1);
  font-weight: 600;
  box-shadow: inset 0 0 0 1px var(--accent-ring);
}
.nav__icon { width: 18px; height: 18px; flex: none; opacity: .85; }
.nav__group { margin-top: var(--sp-5); padding: 0 var(--sp-3) var(--sp-2); }

.rail__foot { margin-top: auto; display: grid; gap: var(--sp-3);
              padding-top: var(--sp-4); }

/* --- Topbar -------------------------------------------------------------- */

.topbar {
  position: sticky; top: 0;
  z-index: var(--z-topbar);
  height: var(--topbar-h);
  display: flex; align-items: center; gap: var(--sp-4);
  padding: 0 var(--sp-6);
  box-shadow: var(--shadow-1), inset 0 -1px 0 var(--stroke);
}
.topbar::before { display: none; }
.topbar__title { font-family: var(--font-display); font-size: 1.0625rem;
                 font-weight: 600; color: var(--text-1); letter-spacing: -.015em;
                 min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar__stamp { white-space: nowrap; }
@media (max-width: 480px) {
  /* The clock alone: the word does not fit beside a burger, a title and the
     theme button on a phone. */
  .topbar__stamp-word { display: none; }
}

@media (max-width: 960px) {
  /* The open menu lies over everything, the topbar included (the sticky
     topbar is in the same stacking context and would otherwise cover the
     brand and the first items); the scrim just under it. */
  .rail {
    position: fixed; inset: 0 auto 0 0;
    z-index: calc(var(--z-topbar) + 2);
    width: min(84vw, var(--rail-w));
    transform: translate3d(-102%, 0, 0);
    transition: transform var(--dur-3) var(--ease-out);
    box-shadow: var(--shadow-4);
  }
  .rail.is-open { transform: translate3d(0, 0, 0); }
  .topbar { padding: 0 var(--sp-4); }
  .rail-scrim {
    position: fixed; inset: 0; z-index: calc(var(--z-topbar) + 1);
    background: var(--scrim); opacity: 0; visibility: hidden;
    transition: opacity var(--dur-2) linear, visibility var(--dur-2);
  }
  .rail-scrim.is-open { opacity: 1; visibility: visible; }
}

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

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--sp-2);
  padding: 9px var(--sp-4);
  border: 0;
  border-radius: var(--r-sm);
  background: var(--glass-inset);
  box-shadow: inset 0 0 0 1px var(--stroke);
  color: var(--text-2);
  font: 550 var(--t-sm)/1 var(--font-ui);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--dur-1) linear, color var(--dur-1) linear,
              box-shadow var(--dur-1) linear, transform var(--dur-1) var(--ease-out);
}
.btn:hover { background: var(--row-hover); color: var(--text-1);
             box-shadow: inset 0 0 0 1px var(--stroke-strong); }
.btn:active { transform: translateY(1px); }
.btn--primary {
  background: linear-gradient(140deg, var(--accent-hi), var(--accent-lo));
  color: var(--text-on-accent);
  font-weight: 600;
  box-shadow: 0 4px 16px -6px var(--accent-ring), inset 0 1px 0 rgba(255,255,255,.35);
}
.btn--primary:hover { color: var(--text-on-accent); filter: brightness(1.06); }
.btn--block { width: 100%; padding: 12px var(--sp-4); font-size: var(--t-body); }
.btn--icon { padding: 8px; width: 36px; height: 36px; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; pointer-events: none; }
.btn__icon { width: 14px; height: 14px; flex: none; }
/* Quiet until hovered: a destructive action should not shout from every row. */
.btn--danger { color: var(--loss); }
.btn--danger:hover { background: var(--loss-wash); color: var(--loss);
                     box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--loss) 40%, transparent); }

/* Declared after .btn on purpose: both selectors have the same specificity, so
   the later rule wins, and .btn { display: inline-flex } would otherwise keep
   the burger visible on desktop. */
@media (min-width: 961px) {
  .burger, .rail-scrim { display: none; }
}

/* --- Segmented control (period picker) ----------------------------------- */

.seg {
  display: inline-flex;
  padding: 3px;
  gap: 2px;
  border-radius: var(--r-sm);
  background: var(--glass-inset);
  box-shadow: inset 0 0 0 1px var(--stroke);
}
.seg__item {
  padding: 6px var(--sp-3);
  border-radius: 7px;
  color: var(--text-3);
  font: 550 var(--t-sm)/1.2 var(--font-ui);
  white-space: nowrap;
  transition: background-color var(--dur-1) linear, color var(--dur-1) linear;
}
.seg__item:hover { color: var(--text-1); }
/* aria-current: the same control used as navigation between sections. */
.seg__item[aria-selected="true"],
.seg__item[aria-current="page"] {
  background: var(--glass-3);
  color: var(--text-1);
  font-weight: 600;
  box-shadow: var(--shadow-1), inset 0 0 0 1px var(--stroke);
}
.seg--wrap { flex-wrap: wrap; max-width: 100%; }
.seg { max-width: 100%; }
/* The period picker wraps to a second row on a phone rather than pushing the
   page wider than the screen. */
@media (max-width: 640px) { .page-head .seg { flex-wrap: wrap; } }

/* The period picker: the named periods and, beside them, two dates of the
   user's own. Both are the same control; the dates light up like a chosen
   period when they are the period in force. */
.periods { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center;
           justify-content: flex-end; max-width: 100%; }
.seg--range { align-items: center; gap: 2px; }
.seg--range.is-active { box-shadow: inset 0 0 0 1px var(--accent-ring);
                        background: var(--accent-wash); }
.seg__date { display: inline-flex; }
.seg--range .input--date {
  width: auto; min-width: 0;
  padding: 4px 6px;
  background: transparent; box-shadow: none;
  color: var(--text-2);
  font: 550 var(--t-sm)/1.2 var(--font-ui);
  font-variant-numeric: tabular-nums;
}
.seg--range .input--date:focus { background: var(--glass-3);
                                 box-shadow: inset 0 0 0 1px var(--accent-ring); }
.seg--range .input--date::-webkit-calendar-picker-indicator { opacity: .55; cursor: pointer; }
.seg--range.is-active .input--date { color: var(--text-1); }
.seg__sep { color: var(--text-4); font-size: var(--t-sm); padding: 0 2px; }
.seg__go { border: 0; background: transparent; cursor: pointer; font-family: inherit; }
.seg__go:hover { background: var(--row-hover); }
@media (max-width: 640px) {
  .periods { justify-content: flex-start; }
  .seg--range { flex-wrap: wrap; }
}
.seg__n { color: var(--text-4); font-weight: 600; margin-inline-start: 3px; }
.seg__item[aria-selected="true"] .seg__n { color: var(--text-3); }

/* The same control as a radio group inside a form: as tall as an input, the
   checked option lit in its own meaning — a deposit green, a withdrawal amber. */
.seg--field { display: flex; min-height: 43px; }
.seg--field .seg__item {
  flex: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  cursor: pointer;
  position: relative;
}
.seg--field input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.seg--field .seg__item:has(input:checked) {
  background: var(--glass-3);
  color: var(--text-1);
  font-weight: 600;
  box-shadow: var(--shadow-1), inset 0 0 0 1px var(--stroke);
}
.seg--field .seg__item[data-kind="in"]:has(input:checked)  { color: var(--profit); }
.seg--field .seg__item[data-kind="out"]:has(input:checked) { color: var(--warn); }
/* A participant's status, in the colours of its badge. */
.seg--field .seg__item[data-kind="owner"]:has(input:checked)  { color: var(--info); }
.seg--field .seg__item[data-kind="client"]:has(input:checked) { color: var(--text-1); }
.seg--field .seg__item:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 1px; }

/* --- Badges / pills ------------------------------------------------------ */

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  border-radius: var(--r-pill);
  font: 600 var(--t-micro)/1.4 var(--font-ui);
  letter-spacing: .07em;
  text-transform: uppercase;
  white-space: nowrap;
}
.badge--up      { background: var(--profit-wash); color: var(--profit); }
.badge--down    { background: var(--loss-wash);   color: var(--loss);
                  box-shadow: inset 0 0 0 1.5px var(--loss); }
.badge--warn    { background: var(--warn-wash);   color: var(--warn); }
.badge--danger  { background: var(--loss-wash);   color: var(--loss); }
.badge--info    { background: var(--info-wash);   color: var(--info); }
.badge--neutral { background: var(--neutral-wash); color: var(--text-3); }
.badge--accent  { background: var(--accent-wash); color: var(--accent); }

.dot { width: 7px; height: 7px; border-radius: 50%; flex: none;
       background: currentColor; }
.dot--live { box-shadow: 0 0 0 0 currentColor; animation: pulse 2.6s ease-out infinite; }
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, currentColor 55%, transparent); }
  70%  { box-shadow: 0 0 0 7px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) { .dot--live { animation: none; } }

/* --- KPI tile ------------------------------------------------------------ */

.kpi {
  --kpi-tint: transparent;
  padding: var(--sp-5);
  display: grid;
  gap: var(--sp-2);
  align-content: start;
  min-height: 124px;
  overflow: hidden;
}
.kpi[data-tone="up"]   { --kpi-tint: var(--profit-wash); }
.kpi[data-tone="down"] { --kpi-tint: var(--loss-wash); }
.kpi::after {
  background: radial-gradient(85% 60% at 50% -25%, var(--kpi-tint), transparent 70%),
              var(--sheen);
}
.kpi__head { display: flex; align-items: center; justify-content: space-between;
             gap: var(--sp-2); min-height: 20px; }
.kpi__value {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.2rem + 1.2vw, 1.95rem);
  font-weight: 650;
  line-height: 1.08;
  letter-spacing: -0.026em;
  color: var(--text-1);
}
.kpi__unit { font-size: .48em; font-weight: 550; color: var(--text-3);
             margin-inline-start: .3em; vertical-align: .1em; }
/* A result: the number itself in the profit or the loss ink (the sign is
   already there; the colour repeats it), with a soft glow on dark glass. */
.kpi__value--up   { color: var(--profit); }
.kpi__value--down { color: var(--loss); }
.kpi__value--up .dec, .kpi__value--down .dec { color: inherit; opacity: .72; }
:root[data-theme="dark"] .kpi__value--up   { text-shadow: 0 0 24px color-mix(in srgb, var(--profit) 38%, transparent); }
:root[data-theme="dark"] .kpi__value--down { text-shadow: 0 0 24px color-mix(in srgb, var(--loss) 38%, transparent); }
.kpi__foot { display: flex; align-items: baseline; gap: var(--sp-3);
             font-size: var(--t-sm); color: var(--text-3); }

/* A small figure inside a tile's footer: «внесено владельцами 13 200.00».
   One step brighter than the words around it, so it reads as a number.
   nowrap: the thousands gap is a thin space, a break opportunity — in a
   narrow tile «14 360.00» split into «14» and «360.00» on the next line. */
.kpi__aside { color: var(--text-2); font-weight: 600; white-space: nowrap; }

/* --- Panels -------------------------------------------------------------- */

.panel { padding: var(--sp-5); display: grid; gap: var(--sp-4); align-content: start; }
/* A grid item's minimum width is its content's — and for a box with an
   aspect ratio and a min-height, that minimum is the min-height carried
   across the ratio (130px at 16:4 is 520px wide). In a narrow column that
   pushed a chart out of its panel. Zero, everywhere a chart can sit. */
.panel > *, .strat > *, .stack > *, .well > *, .balance > * { min-width: 0; }
.panel__head { display: flex; align-items: center; justify-content: space-between;
               gap: var(--sp-4); flex-wrap: wrap; }
.panel__title { font-size: var(--t-h2); font-weight: 600; color: var(--text-1); }
.panel__sub { font-size: var(--t-sm); color: var(--text-3); }

/* --- Charts -------------------------------------------------------------- */

.chart {
  position: relative;
  min-width: 0;                 /* see .panel > *: never wider than its column */
  max-width: 100%;
  aspect-ratio: 16 / 7;
  min-height: 200px;
  border-radius: var(--r-md);
  background: var(--glass-inset);
  box-shadow: inset 0 1px 0 var(--stroke);
  overflow: hidden;
  contain: layout paint;
}
.chart > canvas { display: block; width: 100%; height: 100%; }
.chart--short { aspect-ratio: 16 / 4; min-height: 130px; }
@media (max-width: 640px) { .chart { aspect-ratio: 4 / 3; } }

.chart-tip {
  position: absolute;
  z-index: var(--z-tooltip);
  padding: var(--sp-3) var(--sp-4);
  min-width: 150px;
  font-size: var(--t-sm);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-1) linear, transform var(--dur-1) var(--ease-out);
}
.chart-tip.is-on { opacity: 1; }
.chart-tip__t { font: 600 var(--t-micro)/1.2 var(--font-ui); letter-spacing: .09em;
                text-transform: uppercase; color: var(--text-3);
                margin-bottom: var(--sp-2); }
.chart-tip__row { display: flex; justify-content: space-between; gap: var(--sp-4);
                  padding: 2px 0; }
.chart-tip__val { color: var(--text-1); font-weight: 600; }

/* Rows of the balance chart's readout: a short line key, the name, the value. */
.chart-tip__name { display: inline-flex; align-items: center; gap: var(--sp-2); color: var(--text-3); }
.chart-tip__key { width: 12px; height: 2px; border-radius: 2px; flex: none; }
.chart-tip__key--dash { height: 0; border-radius: 0; background: none;
                        border-top: 2px dashed var(--text-3); }
.chart-tip__val.pnl--up   { color: var(--profit); }
.chart-tip__val.pnl--down { color: var(--loss); }
.chart-tip__val.pnl--flat { color: var(--text-3); }

/* --- A participant's balance over time (macros.balance) ------------------ */

.balance { display: grid; gap: var(--sp-3); }
.balance__head { display: flex; align-items: center; justify-content: space-between;
                 gap: var(--sp-2) var(--sp-4); flex-wrap: wrap; }
/* The line takes the profit colour above the invested step and the loss colour
   below it, so its key shows both. */
.balance__key { width: 16px; height: 2px; border-radius: 2px; flex: none;
                background: linear-gradient(90deg, var(--profit) 50%, var(--loss) 50%); }
.chart--balance { aspect-ratio: 16 / 6; min-height: 240px; cursor: crosshair; }
.chart--balance:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 640px) { .chart--balance { aspect-ratio: 4 / 3; } }
.balance__stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
                  gap: var(--sp-3) var(--sp-4); }
@media (max-width: 560px) { .balance__stats { grid-template-columns: 1fr; } }
.balance__table summary { cursor: pointer; font-size: var(--t-sm); color: var(--text-3);
                          padding: var(--sp-1) 0; }
.balance__table summary:hover { color: var(--text-1); }
.balance__table[open] summary { margin-bottom: var(--sp-2); }

.legend { display: flex; gap: var(--sp-2) var(--sp-4); flex-wrap: wrap;
          font-size: var(--t-sm); color: var(--text-3); }
.legend__item { display: inline-flex; align-items: center; gap: var(--sp-2); }
.legend__swatch { width: 10px; height: 3px; border-radius: 2px; background: currentColor; }
/* A threshold guide — drawn dashed on the canvas, so dashed here too. */
.legend__swatch--dash { width: 14px; height: 0; border-radius: 0; background: none;
                        border-top: 2px dashed currentColor; }

/* --- Tables -------------------------------------------------------------- */

.tbl-wrap {
  border-radius: var(--r-md);
  overflow: auto;
  max-height: 70vh;
  scrollbar-gutter: stable;
  background: var(--glass-inset);
  box-shadow: inset 0 1px 0 var(--stroke);
}
.tbl { width: 100%; border-collapse: separate; border-spacing: 0;
       font-size: var(--t-sm); }

.tbl thead th {
  position: sticky; top: 0; z-index: 2;
  background-color: var(--glass-1);
  backdrop-filter: blur(var(--blur-1)) saturate(var(--sat-1));
  -webkit-backdrop-filter: blur(var(--blur-1)) saturate(var(--sat-1));
  font: 600 var(--t-label)/1.2 var(--font-ui);
  letter-spacing: .075em; text-transform: uppercase;
  color: var(--text-3);
  text-align: left; white-space: nowrap;
  padding: var(--sp-3) var(--sp-4);
  box-shadow: inset 0 -1px 0 var(--row-rule);
}
.tbl th.is-num, .tbl td.is-num { text-align: right; }
.tbl tbody td {
  padding: var(--sp-3) var(--sp-4);
  color: var(--text-2);
  box-shadow: inset 0 -1px 0 var(--row-rule);
  white-space: nowrap;
}
.tbl tbody td:first-child { color: var(--text-1); font-weight: 550;
                            border-inline-start: 2px solid transparent; }
.tbl tbody tr { transition: background-color var(--dur-1) linear; }
@media (hover: hover) { .tbl tbody tr:hover { background: var(--row-hover); } }

/* The row rail: a third, non-colour-dependent P&L channel that also makes a
   long table scannable without reading a single number. */
.tbl tbody tr[data-pnl="up"]   td:first-child { border-inline-start-color: var(--profit); }
.tbl tbody tr[data-pnl="down"] td:first-child { border-inline-start-color: var(--loss); }

.tbl tfoot td { padding: var(--sp-3) var(--sp-4); color: var(--text-3);
                font-weight: 600; white-space: nowrap; }
/* A second, quieter line in a cell: the money behind a volume, the parts of
   a result. */
.cell__sub { font-size: var(--t-label); color: var(--text-3); margin-top: 2px;
             letter-spacing: .01em;
             /* Wraps: on a phone the cell is half a card wide, and a line
                that cannot break pushes the whole page past the screen. */
             white-space: normal; overflow-wrap: anywhere; }
/* One short line under a figure («итог +31.17»): on a wide table it
   stays a line — the table scrolls inside its box; on a phone (cards) the
   rule above wraps it as usual. */
@media (min-width: 721px) { .cell__sub--line { white-space: nowrap; } }

/* Below 720px a table stops being a table and becomes a list of cards. */
@media (max-width: 720px) {
  /* Drop the inner scroller: a scroll region inside a scrolling page is a
     trap on touch — you swipe to scroll the page and the list moves instead. */
  /* !important: an inline max-height (Safari kept a 340px box while the
     content flowed on) would otherwise win and spill the table over the
     next panel. On a phone a table is never a scroll box. */
  .tbl-wrap { max-height: none !important; overflow: visible; }
  /* Tiles carry one number each on a phone; the desktop min-height just adds
     dead space and pushes content below the fold. */
  .kpi { min-height: 0; padding: var(--sp-4); }
  .grid--kpi { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

  .tbl, .tbl tbody, .tbl tfoot, .tbl tr, .tbl td { display: block; width: 100%; }
  .tbl thead { display: none; }
  /* A card: the first cell is its title across the full width, the rest are
     label-over-value pairs in two even, left-aligned columns — no zigzag of
     right-aligned numbers against left-aligned words. */
  .tbl tbody tr, .tbl tfoot tr {
    padding: var(--sp-3) var(--sp-4) var(--sp-4);
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-3) var(--sp-4);
    box-shadow: inset 0 -1px 0 var(--row-rule);
    border-inline-start: 2px solid transparent;
  }
  .tbl tbody tr[data-pnl="up"]   { border-inline-start-color: var(--profit); }
  .tbl tbody tr[data-pnl="down"] { border-inline-start-color: var(--loss); }
  /* The inner scroller is gone above, so text must wrap or it is simply
     unreadable — body has overflow-x: hidden and would clip it away. */
  .tbl tbody td, .tbl tfoot td { padding: 0; box-shadow: none; border: 0;
                                 white-space: normal; overflow-wrap: anywhere; }
  .tbl tbody td:first-child, .tbl tfoot td:first-child {
    grid-column: 1 / -1; border: 0;
    font-size: var(--t-body); font-weight: 650; color: var(--text-1);
  }
  .tbl tbody td:first-child[data-label]::before { display: none; }
  .tbl tbody td.is-num, .tbl tfoot td.is-num { text-align: left; white-space: nowrap; }
  .tbl tbody td:empty, .tbl tfoot td:empty { display: none; }
  .tbl tbody td[data-label]::before, .tbl tfoot td[data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 1px;
    font: 600 var(--t-label)/1.2 var(--font-ui);
    letter-spacing: .07em; text-transform: uppercase; color: var(--text-3);
  }
  /* A badge cell (direction, status) sits on the value line like any other. */
  .tbl tbody td .badge { vertical-align: middle; }
}

/* --- Forms --------------------------------------------------------------- */

.field { display: grid; gap: var(--sp-2); }
.label { font-size: var(--t-sm); font-weight: 550; color: var(--text-2); }
.input, .select {
  width: 100%;
  padding: 11px var(--sp-4);
  border: 0;
  border-radius: var(--r-sm);
  background: var(--glass-inset);
  box-shadow: inset 0 0 0 1px var(--stroke);
  color: var(--text-1);
  font: 400 var(--t-body)/1.4 var(--font-ui);
  transition: box-shadow var(--dur-1) linear, background-color var(--dur-1) linear;
}
.input::placeholder { color: var(--text-4); }
.input[type="date"], .input[type="time"] { color-scheme: light dark; }
/* Logins and passwords: monospace, so l/1 and O/0 can be told apart when the
   admin reads a password out to someone. */
.input--mono { font-family: var(--font-mono); letter-spacing: .02em; }
.hint { font-size: var(--t-sm); color: var(--text-3); margin: 0; }
.hint b { color: var(--text-2); font-weight: 600; }
/* A field with a button beside it (password + «Сгенерировать»). */
.field__row { display: flex; gap: var(--sp-2); align-items: stretch; }
.field__row > .input, .field__row > .select { flex: 1; min-width: 0; }

/* A form laid out as a grid of fields; the last cell holds the button. */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--sp-4);
  align-items: end;
}
.form-grid .field--wide { grid-column: span 2; }
@media (max-width: 640px) { .form-grid .field--wide { grid-column: auto; } }
.input:focus, .select:focus {
  outline: none;
  background: var(--glass-3);
  box-shadow: inset 0 0 0 1px var(--accent-ring), 0 0 0 3px var(--accent-wash);
}
.select {
  appearance: none;
  padding-right: var(--sp-8);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' fill='none'%3E%3Cpath d='M1 1.5 6 6.5l5-5' stroke='%23808C9E' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-3) center;
  cursor: pointer;
}

/* --- Alerts -------------------------------------------------------------- */

.alert {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-sm);
  font-size: var(--t-sm);
  background: var(--neutral-wash);
  color: var(--text-2);
  box-shadow: inset 0 0 0 1px var(--stroke);
}
.alert--danger { background: var(--loss-wash); color: var(--loss);
                 box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--loss) 35%, transparent); }
.alert--warn   { background: var(--warn-wash); color: var(--warn);
                 box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warn) 30%, transparent); }
.alert--info   { background: var(--info-wash); color: var(--info); }
.alert__strong { font-weight: 650; }

/* --- Empty & loading states ---------------------------------------------- */

.empty {
  display: grid; gap: var(--sp-2); justify-items: center;
  padding: var(--sp-10) var(--sp-4);
  text-align: center;
  color: var(--text-3);
}
.empty__title { font-size: var(--t-h3); font-weight: 600; color: var(--text-2); }
.empty__hint  { font-size: var(--t-sm); max-width: 44ch; }

.skeleton {
  border-radius: var(--r-sm);
  background: linear-gradient(100deg, var(--glass-inset) 30%,
              var(--row-hover) 50%, var(--glass-inset) 70%);
  background-size: 220% 100%;
  animation: shimmer 1.4s linear infinite;
}
@keyframes shimmer { to { background-position: -220% 0; } }
@media (prefers-reduced-motion: reduce) { .skeleton { animation: none; } }

/* A value we could not fetch reads as stale, never as zero: showing 0 USDT
   during an API blip is the worst failure mode this dashboard has. */
.is-stale { opacity: .55; }

/* --- Strategy card ------------------------------------------------------- */

.strat { padding: var(--sp-5); display: grid; gap: var(--sp-4); align-content: start; }
.strat__head { display: flex; align-items: flex-start; gap: var(--sp-3); }
.strat__mark {
  width: 38px; height: 38px; border-radius: 12px; flex: none;
  display: grid; place-items: center;
  font: 700 .82rem/1 var(--font-display);
  color: var(--text-on-accent);
}
.strat[data-accent="accent-a"] .strat__mark {
  background: linear-gradient(145deg, var(--accent-a), color-mix(in srgb, var(--accent-a) 70%, #000));
}
.strat[data-accent="accent-b"] .strat__mark {
  background: linear-gradient(145deg, var(--accent-b), color-mix(in srgb, var(--accent-b) 70%, #000));
}
.strat__name { font-family: var(--font-display); font-weight: 650;
               color: var(--text-1); letter-spacing: -.015em; }
.strat__blurb { font-size: var(--t-sm); color: var(--text-3); margin: 0; }
.strat__stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
                gap: var(--sp-3); }

/* --- Owner card (admin → «Депозиты») ------------------------------------- */

.owner { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-4);
         min-width: 0; }
.owner__head { display: flex; align-items: center; gap: var(--sp-3); }
.owner__mark {
  width: 40px; height: 40px; border-radius: 13px; flex: none;
  display: grid; place-items: center;
  font: 700 .82rem/1 var(--font-display); letter-spacing: -.01em;
  color: var(--text-1);
  background: var(--glass-inset);
  box-shadow: inset 0 0 0 1px var(--stroke-strong);
}
/* The admin wears the brand mark; depositors stay neutral — owner colours
   would collide with the two strategy accents used on the same page. */
.owner[data-admin] .owner__mark {
  background: linear-gradient(145deg, var(--accent-hi), var(--accent-lo));
  color: var(--text-on-accent);
  box-shadow: 0 4px 14px -4px var(--accent-ring), inset 0 1px 0 rgba(255,255,255,.4);
}
.owner[data-orphan] .owner__mark { color: var(--warn); background: var(--warn-wash);
                                   box-shadow: none; }
.owner__who { flex: 1; min-width: 0; }
.owner__name { font-family: var(--font-display); font-weight: 650; color: var(--text-1);
               letter-spacing: -.015em; line-height: 1.25;
               overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.owner__login { font-size: var(--t-sm); color: var(--text-3);
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.owner__login .mono { font-size: .78rem; color: var(--text-2); }
/* Status badge + login under the name. The login moves under the badge when
   the two do not fit side by side, and is cut short only if it does not fit
   even on a line of its own. */
.owner__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--sp-2);
               min-width: 0; margin-top: 3px; }
.owner__meta .badge { flex: none; }
.owner__meta .owner__login { max-width: 100%; }
.owner__value {
  font-family: var(--font-display);
  font-size: 1.5rem; font-weight: 650; line-height: 1.15;
  letter-spacing: -.022em;
  color: var(--text-1);
  margin-top: 2px;
}
.owner__value.t-mute { color: var(--text-4); }
.owner__result { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap;
                 margin-top: var(--sp-1); font-size: var(--t-sm); }
.owner__none { margin-top: var(--sp-2); }
.owner__split { display: grid; gap: var(--sp-2); padding: var(--sp-3) var(--sp-4); }
.owner__row { display: flex; align-items: baseline; justify-content: space-between;
              gap: var(--sp-3); font-size: var(--t-sm); }
.owner__row .num { color: var(--text-1); white-space: nowrap; }
.owner__row--total { padding-top: var(--sp-2); box-shadow: inset 0 1px 0 var(--row-rule); }
.owner__acct { display: inline-flex; align-items: center; gap: var(--sp-2); color: var(--text-2);
               min-width: 0; }
.owner__link { font-size: var(--t-sm); justify-self: start; }
.owner__actions { display: flex; gap: var(--sp-2); margin-top: auto; }
.owner__actions .btn { flex: 1; }
.owner__actions .btn--icon { flex: 0 0 auto; height: auto; }

/* A group of participant cards («Владельцы», «Клиенты») under its heading. */
.group-head { display: flex; align-items: baseline; gap: var(--sp-2) var(--sp-3); flex-wrap: wrap; }
.group-head__title { font-size: var(--t-h2); font-weight: 600; color: var(--text-1); }
.group-head__n { font-weight: 600; color: var(--text-3); font-variant-numeric: tabular-nums; }
.group-head__hint { font-size: var(--t-sm); color: var(--text-3); }
/* A figure's caption: small, but in the label ink and size — it is read, not
   just glanced at, and 10px in the decorative grey was not legible. */
.stat__k { font-size: var(--t-label); letter-spacing: .07em; text-transform: uppercase;
           color: var(--text-3); }
.stat__v { font-size: 1.0625rem; font-weight: 600; color: var(--text-1);
           font-variant-numeric: tabular-nums; }

/* --- Login --------------------------------------------------------------- */

.auth-wrap {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--sp-5);
  position: relative;
  z-index: var(--z-content);
}
.auth-card { width: min(100%, 396px); padding: var(--sp-8); display: grid;
             gap: var(--sp-5); }
.auth-card__head { display: grid; gap: var(--sp-2); justify-items: center;
                   text-align: center; }
.auth-card__title { font-size: 1.375rem; font-weight: 650; color: var(--text-1); }
.auth-card__sub { font-size: var(--t-sm); color: var(--text-3); }

/* --- Pagination ---------------------------------------------------------- */

.pager { display: flex; align-items: center; justify-content: center;
         gap: var(--sp-3); font-size: var(--t-sm); color: var(--text-3); }

/* --- Entry animation ----------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .enter { animation: rise var(--dur-4) var(--ease-out) both;
           animation-delay: calc(var(--i, 0) * 45ms); }
}
@keyframes rise {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
  to   { opacity: 1; transform: none; }
}

/* Theme swap should feel like a dissolve, not a flash — but only on the
   surfaces whose colour actually changes. */
.theme-anim, .theme-anim * {
  transition: background-color var(--dur-3) var(--ease-in-out),
              color var(--dur-3) var(--ease-in-out),
              box-shadow var(--dur-3) var(--ease-in-out) !important;
}

/* ==========================================================================
   Bot filters (admin → «Фильтры»)

   Every status is carried by text and a glyph as well as by hue: "запрещено"
   must read as such in greyscale and for a colour-blind admin, so the verdict
   line always names the state and the rail/dot only reinforce it.
   ========================================================================== */

.verdict {
  --v-tint: var(--neutral-wash);
  --v-ink: var(--text-3);
  padding: var(--sp-5);
  display: grid;
  gap: var(--sp-4);
  align-content: start;
  overflow: hidden;
}
.verdict[data-state="allow"]    { --v-tint: var(--profit-wash); --v-ink: var(--profit); }
.verdict[data-state="deny"]     { --v-tint: var(--loss-wash);   --v-ink: var(--loss); }
.verdict[data-state="downsize"] { --v-tint: var(--warn-wash);   --v-ink: var(--warn); }
.verdict::after {
  background: radial-gradient(90% 70% at 100% -20%, var(--v-tint), transparent 70%),
              var(--sheen);
}
.verdict__head { display: flex; align-items: flex-start; gap: var(--sp-3); }
.verdict[data-accent="accent-a"] .strat__mark {
  background: linear-gradient(145deg, var(--accent-a), color-mix(in srgb, var(--accent-a) 70%, #000));
}
.verdict[data-accent="accent-b"] .strat__mark {
  background: linear-gradient(145deg, var(--accent-b), color-mix(in srgb, var(--accent-b) 70%, #000));
}
.verdict__line {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-2) var(--sp-3);
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.05rem + .7vw, 1.55rem);
  font-weight: 650;
  letter-spacing: -.02em;
  line-height: 1.2;
  color: var(--text-1);
}
.verdict__state { color: var(--v-ink); }
.verdict__state::before {
  content: "●"; font-size: .55em; vertical-align: .32em; margin-inline-end: .45em;
}
.verdict[data-state="deny"] .verdict__state::before { content: "✕"; font-size: .7em; vertical-align: .18em; }
.verdict[data-state="allow"] .verdict__state::before { content: "✓"; font-size: .75em; vertical-align: .14em; }
.verdict__sub { font-size: var(--t-body); font-weight: 550; color: var(--text-3);
                font-family: var(--font-ui); letter-spacing: 0; }
.verdict__why { margin: 0; font-size: var(--t-sm); color: var(--text-2); }
.verdict__why b { color: var(--text-1); font-weight: 600; }

/* Key–value facts under a verdict. */
.facts { display: grid; gap: 0; border-radius: var(--r-md);
         background: var(--glass-inset); box-shadow: inset 0 1px 0 var(--stroke); }
.facts__row {
  display: grid; grid-template-columns: minmax(120px, 34%) 1fr; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--t-sm);
  box-shadow: inset 0 -1px 0 var(--row-rule);
}
.facts__row:last-child { box-shadow: none; }
.facts__k { color: var(--text-3); }
.facts__v { color: var(--text-1); font-weight: 550; }
.facts__v .t-dim { font-weight: 450; }
@media (max-width: 560px) { .facts__row { grid-template-columns: 1fr; gap: 2px; } }

/* A threshold scale: where the value sits against the filter's cut-offs. */
.meter { display: grid; gap: var(--sp-2); }
.meter__head { display: flex; justify-content: space-between; align-items: baseline;
               gap: var(--sp-3); font-size: var(--t-sm); }
.meter__track {
  position: relative; height: 10px; border-radius: var(--r-pill);
  background: var(--glass-inset);
  box-shadow: inset 0 0 0 1px var(--stroke);
  margin: 6px 0 18px;
}
.meter__zone { position: absolute; top: 0; bottom: 0; border-radius: var(--r-pill); }
.meter__zone--deny  { background: color-mix(in srgb, var(--loss) 26%, transparent); }
.meter__zone--long  { background: color-mix(in srgb, var(--profit) 24%, transparent); }
.meter__zone--short { background: color-mix(in srgb, var(--loss) 18%, transparent); }
.meter__zone--band  { background: color-mix(in srgb, var(--text-3) 14%, transparent); }
.meter__tick { position: absolute; top: -4px; bottom: -4px; width: 1px;
               background: var(--text-4); }
.meter__tick span { position: absolute; top: 18px; transform: translateX(-50%);
                    font: 600 var(--t-micro)/1 var(--font-ui); color: var(--text-3);
                    white-space: nowrap; }
.meter__dot {
  position: absolute; top: 50%; width: 16px; height: 16px; margin: -8px 0 0 -8px;
  border-radius: 50%;
  background: var(--text-1);
  box-shadow: 0 0 0 3px var(--glass-2-solid), 0 0 0 4px var(--stroke-strong), var(--shadow-1);
}

/* Decision strip: one cell per day (or bar), newest on the right. */
.strip { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
         gap: 4px; }
.strip__cell {
  display: grid; gap: 4px; justify-items: center;
  font: 600 var(--t-micro)/1.1 var(--font-ui); color: var(--text-3);
  min-width: 0;
}
.strip__bar { width: 100%; height: 26px; border-radius: 6px;
              background: var(--neutral-wash);
              box-shadow: inset 0 0 0 1px var(--stroke);
              display: grid; place-items: center;
              font-size: .7rem; color: var(--text-3); }
.strip__cell[data-state="deny"]  .strip__bar { background: var(--loss-wash);
                                              color: var(--loss);
                                              box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--loss) 40%, transparent); }
.strip__cell[data-state="allow"] .strip__bar { background: var(--profit-wash); color: var(--profit); }
.strip__cell[data-state="downsize"] .strip__bar { background: var(--warn-wash); color: var(--warn); }
.strip__cell[data-today] .strip__bar { outline: 2px solid var(--accent-ring); outline-offset: 1px; }
.strip__cell span { overflow: hidden; text-overflow: clip; white-space: nowrap; max-width: 100%; }
@media (max-width: 720px) { .strip__cell span { display: none; } .strip__bar { height: 20px; } }

/* A fired arm / failed check gets the loss rail, a met one stays quiet. */
.tbl tbody tr[data-fired] td:first-child { border-inline-start-color: var(--loss); }
.tbl tbody tr[data-first] { background: color-mix(in srgb, var(--loss) 7%, transparent); }
@media (max-width: 720px) {
  .tbl tbody tr[data-fired] { border-inline-start-color: var(--loss); }
}

.check { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-2) var(--sp-3);
         padding: var(--sp-3) var(--sp-4); align-items: start;
         box-shadow: inset 0 -1px 0 var(--row-rule); font-size: var(--t-sm); }
.check:last-child { box-shadow: none; }
.check__title { color: var(--text-1); font-weight: 600; }
.check__detail { color: var(--text-3); grid-column: 2; }
.check__items { grid-column: 2; display: grid; gap: 2px; margin-top: var(--sp-1); }
.check[data-state="fail"] { background: color-mix(in srgb, var(--loss) 7%, transparent); }
.check[data-state="fail"] .check__title { color: var(--loss); }

.src { font-size: var(--t-sm); color: var(--text-3); display: flex; flex-wrap: wrap;
       gap: var(--sp-2) var(--sp-5); }
.src code { font-family: var(--font-mono); font-size: .78rem; color: var(--text-2); }

/* Long tables scroll inside themselves on desktop only; on a phone the
   card list flows with the page (see the 720px rule above). */
.tbl-wrap--free { max-height: none; }
@media (min-width: 721px) { .tbl-wrap--scroll { max-height: 420px; } }
