/* ═══════════════════════════════════════════════════════════════════════
   THE BASKET VISUAL — one row per position, all the same width.

   Its own file because three pages draw it: the Polygonal board, a package's
   detail page, and the PUBLIC LANDING PAGE. The landing page must not have to
   load the whole dashboard stylesheet to show one example, and the example must
   not be a second, drifting copy of the component — a visitor who signs up has
   to meet the screen they were shown.

   Scoped on .bvz, not on .ml-page, for the same reason. The palette tokens fall
   back to literals so the rules hold on a page that never defined them.
   ═══════════════════════════════════════════════════════════════════════ */
.bvz{
  --bvz-bg:var(--c2,#0F1116);
  --bvz-b:var(--b,rgba(255,255,255,.07));
  --bvz-b2:var(--b2,rgba(255,255,255,.13));
  --bvz-t0:var(--t0,#F2F4F7);
  --bvz-t1:var(--t1,#A9B1BD);
  --bvz-t2:var(--t2,#6B7280);
  --bvz-bull:var(--bull,#12D18E);
  --bvz-bear:var(--bear,#F7485F);
  --bvz-br:var(--br,#F0B90B);
  --bvz-mono:var(--font-mono,'JetBrains Mono',monospace);
  --bvz-disp:var(--font-display,'Space Grotesk',sans-serif);
}
.bvz *{box-sizing:border-box}
/* ═══════════════════════════════════════════════════════════════════════
   BASKET VISUAL (.bvz) — one row per position, all the same width.
   Replaces the polygon diagram, whose edges implied a sequence that a basket
   does not have. See templates/signals_app/_basket_viz.html for the reasoning.
   ═══════════════════════════════════════════════════════════════════════ */
.bvz{display:flex;flex-direction:column;gap:12px}
.bvz-row{
  display:grid;grid-template-columns:104px 1fr 96px;align-items:center;
  gap:16px;padding:12px 12px;
  border:1px solid var(--bvz-b);border-radius:14px;
  background:var(--bvz-bg);transition:border-color .2s cubic-bezier(.16,1,.3,1);
}
.bvz-row:hover{border-color:var(--bvz-b2)}
/* State is carried by a left edge, not by tinting the whole row: three
   differently-coloured blocks stacked read as a warning, not as a portfolio. */
.bvz-executed{box-shadow:inset 3px 0 0 var(--bvz-bull)}
.bvz-failed{box-shadow:inset 3px 0 0 var(--bvz-bear)}
.bvz-active{box-shadow:inset 3px 0 0 var(--bvz-br)}
.bvz-pending{box-shadow:inset 3px 0 0 var(--t2)}

.bvz-id{display:flex;flex-direction:column;gap:2px;min-width:0}
.bvz-sym{font-family:var(--bvz-disp);font-weight:700;font-size:15px;color:var(--bvz-t0);letter-spacing:.2px}
.bvz-dir{font-size:10px;font-weight:700;letter-spacing:.8px}
.bvz-dir-buy{color:var(--bvz-bull)}
.bvz-dir-sell{color:var(--bvz-bear)}

.bvz-track{position:relative;height:34px}
.bvz-line{
  position:absolute;inset-inline:0;top:16px;height:2px;border-radius:2px;
  background:linear-gradient(90deg,var(--bvz-bear),rgba(255,255,255,.16) 30%,var(--bvz-bull));
}
.bvz-end{
  position:absolute;top:22px;font-family:var(--bvz-mono);font-size:10px;color:var(--t2);
  white-space:nowrap;
}
.bvz-end-sl{inset-inline-start:0}
.bvz-end-tp{inset-inline-end:0}
.bvz-entry{position:absolute;inset-inline-start:30%;top:9px;transform:translateX(-50%)}
.bvz-entry::before{
  content:"";display:block;width:9px;height:9px;margin:0 auto;border-radius:50%;
  background:var(--bvz-t0);box-shadow:0 0 0 3px var(--bvz-bg);
}
/* The entry price sits BELOW the line, in the same lane as the stop and target
   labels; the live price sits above it. They shared a lane at first, and on a
   position whose price is near its entry the two numbers landed on the same
   pixels — measured on SOL: entry label at x=463, price label at x=469, both
   36px wide. Two prices printed on top of each other is worse than either one
   missing. Separate lanes make the collision impossible rather than unlikely. */
.bvz-entry i{
  position:absolute;top:15px;left:50%;transform:translateX(-50%);
  font-style:normal;font-family:var(--bvz-mono);font-size:10px;color:var(--bvz-t0);
  white-space:nowrap;font-weight:600;
}
/* Price-now only appears on a live basket, so it never sits under a result. */
.bvz-now{position:absolute;top:6px;transform:translateX(-50%)}
.bvz-now::before{
  content:"";display:block;width:2px;height:18px;margin:0 auto;background:var(--bvz-br);border-radius:2px;
}
.bvz-now b{
  position:absolute;top:-13px;left:50%;transform:translateX(-50%);
  font-family:var(--bvz-mono);font-size:10px;font-weight:600;color:var(--bvz-br);white-space:nowrap;
}

.bvz-state{text-align:end;font-size:11px;font-weight:600}
.bvz-won{color:var(--bvz-bull)}
.bvz-lost{color:var(--bvz-bear)}
.bvz-live{color:var(--bvz-br)}
.bvz-wait{color:var(--t2)}
.bvz-foot{margin:8px 0 0;font-size:12px;color:var(--t2);line-height:1.55}
.bvz-foot b{color:var(--bvz-t1)}

/* Below 640px the three columns stop fitting: the symbol goes above the track
   and the state joins it, so the line keeps the full width it needs to read. */
@media (max-width:640px){
  .bvz-row{grid-template-columns:1fr;gap:8px;padding:12px}
  .bvz-id{flex-direction:row;align-items:baseline;gap:8px}
  .bvz-state{text-align:start}
  .bvz-track{height:40px}
}

/* The words that name each end. Set small and dim so the PRICE stays the thing
   you read; without them the track is an unlabelled line, and on a short its
   prices descend left-to-right, which looks like a mistake rather than a
   risk-to-reward axis. */
.bvz-end em,.bvz-entry i em{
  display:block;font-style:normal;font-size:8.5px;letter-spacing:.7px;
  text-transform:uppercase;color:var(--bvz-t2);font-weight:600;line-height:1.35;
}
.bvz-entry i em{margin-block-end:-1px}
.bvz-end-tp{text-align:end}
.bvz-track{height:42px}
@media (max-width:640px){.bvz-track{height:48px}}
