/* ===========================================================================
   BattleCharts component styles, scoped to .tzbc
   ---------------------------------------------------------------------------
   GENERATED — do not hand-edit. Source: tz-frontend
   public/battlecharts/assets/css/{base,components,chart,battle,arena}.css,
   passed through scope-css.js, which rewrites every selector to sit under
   .tzbc and collapses :root / html / body onto it.

   WHY: the product's base.css defines --surface-2, --surface-3 and --line-2
   on :root, and the TradeZee app defines those same tokens — every Tailwind
   bg-surface-2 / border-line-2 reads them. Importing the sheet as-is would
   restyle the app. It also ships a bare * / html / body / h1..h4 / a /
   button / table reset. Under .tzbc both stay inside the section.

   To re-generate after an upstream change, see README.md § Regenerating.
   =========================================================================== */


/* ============ base.css ============ */
/* ==========================================================================
   BattleCharts — tokens, reset, typography and page chrome
   ========================================================================== */

.tzbc {
  color-scheme: dark;

  /* ── TRADEZEE PALETTE AND TYPE (embedded build, 2026-10-17) ───────────
     Values below are TradeZee's own dark tokens (src/features/v3/v3-styles.css)
     mapped onto this file's names, so the arena reads as part of the app it
     now lives in. Where the two systems already agreed (surface-2 #0e0e0e,
     --pos #0ca30c) nothing moved.

     ONE DELIBERATE EXCEPTION — --ink-3. TradeZee's tertiary ink is white at 46%
     (≈ #757575), which measures 3.9:1 on --surface-3: below the 4.5:1 this
     system promises for every text ink on every surface. --ink-3 stays just
     above that floor rather than inheriting a value that fails it. */

  /* Canvas — TradeZee's own page and card colours, measured from the app rather
     than approximated: `bg-[#0a0a0a]` is the page every dashboard sits on (93
     uses), `bg-[#0a0b10]` is the card (37 uses, e.g. the Trade Ideas cards),
     and `#0b0c11` is SideCard, the dashboards' rail container.

     An earlier pass mapped these to the FLOW EDITOR's tokens (--surface #060606,
     pure-black slabs, a solid #2e2e2e outline). That is a different surface in
     the app — a full-bleed canvas workspace — and next to a normal page it read
     as harder and darker than anything around it. */
  --gutter-bg: #0a0a0a;
  --page: #0a0a0a;
  --rail: #0a0a0a;
  /* --frame-max / --frame-gap removed with the framed column. Content width is
     --maxw + --gutter, below, which still apply. */

  /* Surfaces: slab → raised → hover. Charts render on --surface-1 (palette validated against it). */
  --surface-1: #0a0b10; /* the app's card fill (bg-[#0a0b10]) */
  --surface-2: #0f1016; /* raised / hover, one step up from the card */
  --surface-3: #15161d; /* highest: inset wells, chips, table stripes */

  /* Hairlines: line-1 divides inside a slab, line-2 outlines slabs and controls,
     line-3 is hover. WHITE ALPHA, not solid greys — the app draws every card
     edge as `border-white/[0.06]` (393 uses) or `/[0.08]` (269), which is a
     hairline that lifts with whatever is behind it instead of a grey line
     sitting on top of it. The solid #2e2e2e here before was the single
     loudest mismatch against the rest of the product. */
  --line-1: rgba(255, 255, 255, 0.06);
  --line-2: rgba(255, 255, 255, 0.08);
  --line-3: rgba(255, 255, 255, 0.14);
  /* Chart gridlines and axes, as white alpha like every other hairline — the
     solid greys they replace were mixed for a pure-black plot and read as
     dirty against the card's slightly blue near-black. */
  --grid: rgba(255, 255, 255, 0.07);
  --axis: rgba(255, 255, 255, 0.16);

  /* Ink — neutral greys; ink-1..3 clear 4.5:1 on every surface; ink-4 is decorative only */
  --ink-1: #f5f5f5; /* TradeZee --ink (white 96%) */
  --ink-2: #b8b8b8; /* TradeZee --ink-2 (white 72%) */
  --ink-3: #858585; /* kept above 4.5:1 on --surface-3 — see the note above */
  --ink-4: #4d4d4d;

  /* Status — reserved meaning, always paired with a sign or label */
  --pos: #0ca30c; /* TradeZee --pnl-up — already identical */
  --neg: #e35d5d; /* TradeZee --pnl-down-text */
  --live: #ff4d4f;
  --bench: #707070;

  /* TradeZee's two families, as loaded by src/app/layout.tsx: Unbounded (picked to
     match the TradeZee logo) and JetBrains Mono for figures. Was Geist / Geist Mono. */
  --font-sans: "Unbounded", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo, Consolas, monospace;

  /* Corner radii: panels & cards → nested cards → controls → small chips; pills for chips/badges */
  --radius-lg: 16px;
  --radius-md: 12px;
  --radius-sm: 10px;
  --radius-xs: 7px;
  --radius-pill: 999px;

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  --nav-h: 56px;
  --gutter: clamp(16px, 2.6vw, 40px);
  --maxw: 1680px;

  /* ── THEMING CHANNELS (light mode, 2026-10-19) ───────────────────────
     user: "battlecharts does not have light mode, add the light mode, make
     sure it matches the styling of rest of the project".

     Everything below exists so ONE override block can flip the whole app.
     The dark values here reproduce what was hardcoded before them exactly,
     so dark mode is unchanged by construction — every literal that moved
     into a token is byte-equivalent to what it replaced.

     --wash-rgb IS THE BIG ONE. This stylesheet draws ~45 fills, hover
     states, gridlines and tick marks as `rgba(255,255,255,α)` — a wash
     that lifts with whatever is behind it instead of a grey sitting on top
     of it. On a cream page the same wash has to come from the other side,
     so the CHANNEL is the token and each rule keeps its own alpha.
     Swapping 45 literals for 45 light twins would have been 45 chances to
     miss one. */
  --wash-rgb: 255, 255, 255;

  /* Drop shadows. A near-opaque black is right under a near-black page and
     reads as soot on a cream one, so the whole COLOUR is the token rather
     than just the channel — light needs a different alpha, not a different
     hue. Geometry (offset/blur/spread) stays at each call site. */
  --shadow-col: rgba(0, 0, 0, 0.85);

  /* Status channels, for the tinted chips and row flashes that use
     `rgba(<status>, α)` rather than the solid --pos / --neg above. */
  --pos-rgb: 12, 163, 12;
  --neg-rgb: 227, 93, 93;
  --live-rgb: 255, 77, 79;

  /* ── "ON INK" — the inverted pill ────────────────────────────────────
     Three places fill a shape with --ink-1 and then draw ON it: the race
     chart's value pill, the signal readout, and that readout's delta. They
     are inverted ON PURPOSE ("the readout inverts the card, as the
     reference's black pill on white"), so they have to invert AGAIN in
     light mode or the pill goes black-on-black. --ink-1 flips; these flip
     with it. */
  --on-ink: #090909;
  --on-ink-2: #4d4d4d;
  --on-ink-pos: #07800a;
  --on-ink-neg: #c43c3c;

  /* The aura bubble is the same idea at panel scale — a light bubble on
     the dark card, which has to become a dark bubble on the light one. */
  --bubble-bg: #f5f5f5;
  --bubble-ink: #0a0a0a;
  --bubble-ink-2: #5c5c5c;

  /* Scrims: chrome that floats over scrolling content and has to stay
     opaque enough to read through. */
  --nav-bg: rgba(10, 10, 10, 0.8);
  --tip-bg: rgba(14, 14, 14, 0.94);
  --card-scrim: rgba(10, 11, 16, 0.86);
  --scrollbar-thumb: #2a2a2a;

  /* The primary button fills with --ink-1, so "brighter on hover" is white
     in dark and BLACK in light — the same gesture, mirrored. */
  --btn-primary-hover: #ffffff;

  /* Tinted-chip ink. The chip sits on an `rgba(--pos-rgb, 0.18)` wash, so
     its label needs a step that clears 4.5:1 against that wash over the
     card — bright on near-black, deep on white. */
  --chip-pos-ink: #3fd63f;
  --chip-neg-ink: #ff8a8a;

  /* The contour chart's hold band. A pale gold is right on near-black
     and washes out to about 1.6:1 on cream, so light gets a deeper one
     that still reads as gold rather than as brown. */
  --amber: #f2c94c;

  /* FOIL — the neutral wash the d3 layer paints with: the aura chart's
     dotted field, the race chart's scan sweep, the price chart's area
     gradient, and the low/worst event markers. All of them were a flat
     white, which is invisible on a cream page.

     NOT a mask. `fade()`/`mask()` in chart-variants.js also use #fff,
     and those stay white: there white means SHOWN, not a colour, and
     theming them would punch holes in the chart.

     The price chart's two stops were #f4f4f4 rather than #fff. At their
     0.12 stop-opacity the difference lands under 1.5/255 on the
     composite, so they share this token rather than carry their own. */
  --foil: #ffffff;

  /* ── THE BRAND PLATE STAYS DARK IN BOTH THEMES ───────────────────────
     .avatar / .sc-badge / .rc-tip__badge are a neutral disc carrying a
     brand mark in its TRUE colours — Claude's coral starburst, Gemini's
     blue washes, and ChatGPT's and Grok's monochrome marks drawn with
     --plate-ink. Those marks are designed against a dark disc, and a light
     plate would need per-brand light variants that nobody has drawn. A
     dark avatar on a light card is also the ordinary treatment elsewhere
     in the product.

     So this is a DELIBERATE non-inversion, not a token that was missed. It
     is tokenised anyway so the decision has one place to live. */
  --plate: #141414;
  --plate-ink: #fff;
  /* The muted step for monochrome marks ON the plate. Pinned to what
     dark's --ink-2 already was: --ink-2 itself inverts, and the plate
     does not, so a glyph stroked with it vanished in light mode. */
  --plate-ink-2: #b8b8b8;
  --plate-stroke: #080808;
  --plate-bench: #2d2d2d;

  /* Skeleton blocks (2026-11-04): a faint wash of the card, and the
     highlight that slides across it. See `.skel` below. */
  --skel-base: rgba(255, 255, 255, 0.055);
  --skel-shine: rgba(255, 255, 255, 0.075);
}

/* ====================================================================== */
/*  LIGHT MODE                                                            */
/* ====================================================================== */

/*  Driven by `data-theme="light"` on <html>, set by assets/js/core/theme.js
    from the host app's own `tz-light-mode` preference. See that file and
    src/app/(main)/battle-charts/page.tsx.

    THE PALETTE IS THE PRODUCT'S, not a lightened copy of the dark one. The
    values are lifted from `.light-mode .tz-v3-scope` in
    src/features/v3/v3-styles.css, which is what every other surface in
    this app is themed by:

        page   #FAF8F5            the app's page background
        canvas #EFEBE3            a shade darker, so a work surface reads
                                  as distinct from the page
        card   #FFFFFF            pure white, so cards pop against it
        line   #B8B1A0 / #CFC9BB  warm taupe hairlines
        ink    rgba(15, 15, 15, …)

    Hairlines are SOLID here where they are white-alpha in dark. That is
    the product's own finding, not a preference: an alpha-tinted border
    blurs into the cream canvas and leaves cards silhouette-less (see the
    --line note in v3-styles.css). The alpha WASHES stay alpha — they are
    fills and hovers, not edges.  */
.tzbc[data-theme="light"] {
  color-scheme: light;

  --gutter-bg: #FAF8F5;
  --page: #FAF8F5;
  --rail: #FAF8F5;

  /* Card → raised → inset, mirroring the dark ramp's direction of travel:
     there the card lifts toward grey, here it lifts toward white. */
  --surface-1: #FFFFFF;
  --surface-2: #F7F3EC;
  --surface-3: #EDE9E1;

  --line-1: rgba(15, 15, 15, 0.07);
  --line-2: #CFC9BB;
  --line-3: #B8B1A0;
  --grid: rgba(15, 15, 15, 0.09);
  --axis: rgba(15, 15, 15, 0.22);

  /* ── --ink-2 AND --ink-3 ARE NOT THE PRODUCT'S VALUES, deliberately ──
     `.light-mode .tz-v3-scope` uses 0.62 / 0.42. This file promises that
     ink-1..3 all clear 4.5:1 on EVERY surface it defines, and the worst
     case is the darkest one, --surface-3 #EDE9E1:

         0.42 → ~#909090 → 2.7:1   fails
         0.60 → ~#686868 → 4.6:1   passes

     So ink-3 sits just above the floor, and ink-2 steps up to 0.76 to keep
     three perceptibly distinct ranks above it. This is the same exception
     the dark palette already takes for --ink-3, for the same reason — see
     the note at the top of this file. --ink-4 is decorative and is not
     held to the floor. */
  --ink-1: rgba(15, 15, 15, 0.92);
  --ink-2: rgba(15, 15, 15, 0.76);
  --ink-3: rgba(15, 15, 15, 0.60);
  --ink-4: rgba(15, 15, 15, 0.34);

  /* Status. MARKS hold at the dark palette's steps, but every status used
     as TEXT has to go darker to clear 4.5:1 on cream — #0ca30c only
     reaches 3.03 there. These are the product's own light-mode text steps
     (--pnl-up-text / --pnl-down-text in v3-styles.css). */
  --pos: #006300;
  --neg: #b32626;
  --live: #c42126;
  --bench: #707070;

  --wash-rgb: 15, 15, 15;
  --shadow-col: rgba(15, 15, 15, 0.16);

  --pos-rgb: 12, 163, 12;
  --neg-rgb: 208, 59, 59;
  --live-rgb: 196, 33, 38;

  /* The inverted pill, inverted back: --ink-1 is near-black now, so what
     sits on it is near-white. */
  --on-ink: #F7F3EC;
  --on-ink-2: #a8a39a;
  --on-ink-pos: #5bd45b;
  --on-ink-neg: #ff9b9b;

  --bubble-bg: #15161d;
  --bubble-ink: #F7F3EC;
  --bubble-ink-2: #a8a39a;

  --nav-bg: rgba(250, 248, 245, 0.82);
  --tip-bg: rgba(255, 255, 255, 0.96);
  --card-scrim: rgba(255, 255, 255, 0.9);
  --scrollbar-thumb: #CFC9BB;

  --btn-primary-hover: #000000;

  --chip-pos-ink: #006300;
  --chip-neg-ink: #b32626;

  --amber: #a67c00;

  --foil: #15151a;

  /* A taupe wash on cream, and a WHITE highlight rather than a darker one:
     a shine reads as light passing over the block in either theme. */
  --skel-base: rgba(15, 15, 15, 0.065);
  --skel-shine: rgba(255, 255, 255, 0.7);

  /* --plate* are NOT redefined. See the note on them above: the brand
     discs stay dark in both themes on purpose. */
}

/* ------------------------------------------------------------------ reset */

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

/* Gutters outside the column carry a faint film grain (white noise at ~7% alpha). */
/* ── NO FRAMED COLUMN (embedded build, 2026-10-17) ────────────────────
   (user: "also remove the outer lines and bottom bar".)

   Standalone, the page was a centred column on grain-textured gutters with a
   1px rail drawn down each side — chrome that says "this is a site". Inside
   the app it is a PANE: the nav rail already frames it on the left, and a
   second frame inside that read as a page boxed within a page. So the grain,
   the gutters and the rails are gone; the surface runs edge to edge in the
   app's own page colour. */
.tzbc {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scrollbar-color: var(--scrollbar-thumb) transparent;
  background-color: var(--gutter-bg);
}

/* The page is a framed column: near-black, with 1px rails drawn as outside shadows so
   they never affect layout (on narrow screens the column is full width and they fall off-screen). */
.tzbc {
  /* Full width, no side rails — see the note on `html` above. The content
     inside still has its own max-width (--maxw) and gutters, so nothing
     stretches awkwardly on a wide monitor. */
  width: 100%;
  margin: 0;
  min-height: 100vh;
  background: var(--page);
  color: var(--ink-2);
  font: 400 14px/1.5 var(--font-sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* The --frame-gap media query that stood here widened the gutters around the
   framed column on wide screens. There is no framed column any more. */

.tzbc h1, .tzbc h2, .tzbc h3, .tzbc h4, .tzbc p, .tzbc dl, .tzbc dd, .tzbc ol, .tzbc ul, .tzbc figure {
  margin: 0;
}

.tzbc ol, .tzbc ul {
  padding: 0;
  list-style: none;
}

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

.tzbc button,
.tzbc input,
.tzbc select {
  font: inherit;
  color: inherit;
}

.tzbc button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.tzbc svg {
  display: block;
}

.tzbc [hidden] {
  display: none !important;
}

/* ------------------------------------------------------------ boot mask */

/* ── NOTHING OF THE PAGE PAINTS UNTIL IT IS READY (user, 2026-10-24:
      "the content falshes for a second and then the loading appears") ──

   There were TWO flashes, one at each end of the loader:

     1. BEFORE it. The loader was created by boot.js, which is `defer` —
        and a deferred script runs after the document is parsed, by which
        point the browser has already painted the static skeleton: empty
        headings, empty panels, a header with nothing in it. So the reader
        saw a half-built page, THEN the loader arrived on top of it.

     2. AFTER it. boot.js removed the loader and only then injected the
        page script, which still had to download and run. For that whole
        round trip the empty skeleton was showing again.

   Both are fixed by making "booting" a state of the DOCUMENT that exists
   from its first byte: `data-booting` is written into <html> in the static
   markup, so it needs no script to take effect and is in force for the very
   first paint. boot.js removes it only once the page script has actually
   RUN (see start() there), so the reveal and the content are the same
   frame.

   ── `visibility`, NOT `display`, AND IT IS LOAD-BEARING ──────────────────

   The page is laid out underneath the loader, just not painted. The charts
   measure their containers when they are built — and the line-end labels
   measure their own text (BC.RaceChart.labelFit) — so with
   `display: none` they would all read 0×0, draw for a zero-sized box, and
   redraw a frame after the reveal. That redraw would be a third flash. */
.tzbc .bc-boot {
  display: none;
}

/* ── THE LOADER IS A SKELETON OF THE PAGE (2026-11-04) ─────────────────────
   It was one centred line, "Loading the arena…". It is now the page's own
   layout in placeholder blocks (index.html, battle.html), so the reveal
   swaps blocks for content where they stood. Everything above still holds:
   it is static markup, in force from the first paint, and the real page
   stays laid out but unpainted beneath it until boot.js takes the
   attribute off — the reveal is still one frame. Sizes live with each
   page's own styles (arena.css, battle.css). */
.tzbc[data-booting] .bc-boot {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: block;
  overflow: hidden;
  background: var(--page);
  pointer-events: none;
}

/* The one-line loader, for a cached copy of the older markup (boot.js
   ensureMask builds it). */
.tzbc[data-booting] .bc-boot--line {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--ink-2);
  font: 500 13px/1.5 var(--font-sans);
  letter-spacing: 0.02em;
}

.tzbc[data-booting]  > :not(.bc-boot) {
  visibility: hidden;
}

/* ── SKELETON BLOCK ─────────────────────────────────────────────────────────
   One shared block for every placeholder: the boot shells and the inline
   ones the battle page builds while a section loads. A highlight slides
   across it, left to right, every 1.4 s; with reduced motion it is a
   still block. Width and height come from the call site. */
.tzbc .skel {
  display: block;
  height: 12px;
  border-radius: 6px;
  background-color: var(--skel-base);
  background-image: linear-gradient(90deg, transparent 0%, var(--skel-shine) 50%, transparent 100%);
  background-repeat: no-repeat;
  background-size: 50% 100%;
  background-position: -150% 0;
  animation: skel-sweep 1.4s linear infinite;
}

@keyframes skel-sweep {
  from { background-position: -150% 0; }
  to { background-position: 250% 0; }
}

@media (prefers-reduced-motion: reduce) {
  .tzbc .skel {
    animation: none;
    background-image: none;
  }
}

/* Layout borrowed from the page must not behave like it under the shell. */
.tzbc .bc-skel .bcard,
.tzbc .bc-skel .bcard:hover {
  transform: none;
  box-shadow: none;
}

.tzbc .bc-skel__grow {
  flex: 1;
  min-width: 0;
}

.tzbc .bc-boot__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.55;
  animation: bc-boot-pulse 1.1s ease-in-out infinite;
}

@keyframes bc-boot-pulse {
  0%, 100% { opacity: 0.2; transform: scale(0.8); }
  50% { opacity: 0.8; transform: scale(1); }
}

.tzbc table {
  border-collapse: collapse;
}

.tzbc :focus-visible {
  outline: 2px solid var(--ink-1);
  outline-offset: 2px;
}

.tzbc ::selection {
  background: rgba(var(--wash-rgb), 0.2);
  color: var(--ink-1);
}

/* ------------------------------------------------------------- typography */

.tzbc .eyebrow {
  font: 500 10.5px/1.3 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .mono {
  font-family: var(--font-mono);
}

.tzbc .tnum {
  font-variant-numeric: tabular-nums;
}

.tzbc .nocase {
  text-transform: none;
}

.tzbc .is-pos { color: var(--pos); }
.tzbc .is-neg { color: var(--neg); }
.tzbc .is-flat { color: var(--ink-3); }

.tzbc .vh {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.tzbc .skip {
  position: absolute;
  inset-inline-start: 16px;
  top: -40px;
  z-index: 100;
  padding: 8px 12px;
  border-radius: var(--radius-xs);
  background: var(--ink-1);
  color: var(--page);
  font: 600 12px var(--font-mono);
}

.tzbc .skip:focus {
  top: 12px;
}

/* ----------------------------------------------------------------- layout */

/* The page's content column. `.wrap` now sits only on <main>, so its bottom
   padding is the page's bottom gutter.

   THE FOOTER USED TO BE THE BOTTOM SPACING (embedded build, 2026-10-17): it
   carried `margin-top: 72px` plus `padding-block: 22px 28px`, so removing it
   left the last card sitting flush against the bottom of the scroll with
   nowhere to rest. This replaces that space rather than inheriting it from a
   component that no longer exists. */
.tzbc .wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
  /* Enough for the last row of cards to rest on without ending at the scroll
     edge. Settled between two tries: 54px read as none, and ~126px (what the
     old footer contributed) read as too much. Scales with viewport height. */
  padding-bottom: clamp(56px, 8vh, 96px);
}

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

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}

@keyframes fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes ping {
  0% { box-shadow: 0 0 0 0 currentColor; opacity: 1; }
  80%, 100% { box-shadow: 0 0 0 7px transparent; opacity: 1; }
}

@keyframes blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.tzbc .rise {
  animation: rise 0.9s var(--ease-out) both;
  animation-delay: var(--delay, 0ms);
}

@view-transition {
  navigation: auto;
}

.tzbc ::view-transition-group(*) {
  animation-duration: 0.5s;
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}

.tzbc ::view-transition-old(root),
.tzbc ::view-transition-new(root) {
  animation-duration: 0.28s;
}

@media (prefers-reduced-motion: reduce) {
  .tzbc, .tzbc *,
  .tzbc *::before,
  .tzbc *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}


/* ============ components.css ============ */
/* ==========================================================================
   BattleCharts — shared components
   ========================================================================== */

/* --------------------------------------------------------------------- nav */

.tzbc .nav {
  position: sticky;
  top: 0;
  z-index: 60;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  gap: 20px;
  padding-inline: var(--gutter);
  background: var(--nav-bg);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--rail);
}

.tzbc .brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font: 600 15px/1 var(--font-sans);
  letter-spacing: -0.02em;
  color: var(--ink-1);
}

.tzbc .brand__mark {
  width: 26px;
  height: 26px;
  padding: 4px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-xs);
  background: var(--surface-1);
}

.tzbc .brand__mark path {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tzbc .crumbs {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  height: 20px;
  padding-inline-start: 20px;
  border-inline-start: 1px solid var(--line-2);
  font: 500 13px/1 var(--font-sans);
  color: var(--ink-3);
  white-space: nowrap;
}

.tzbc .crumbs a {
  transition: color 0.15s;
}

.tzbc .crumbs a:hover {
  color: var(--ink-1);
}

.tzbc .crumbs b {
  font-weight: 500;
  color: var(--ink-1);
}

.tzbc .crumbs__sep {
  color: var(--ink-4);
}

.tzbc .nav__right {
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: 22px;
}

.tzbc .nav__stat {
  display: flex;
  align-items: baseline;
  gap: 9px;
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.1em;
  color: var(--ink-1);
  font-variant-numeric: tabular-nums;
}

.tzbc .nav__stat .eyebrow {
  font-size: 10px;
}

.tzbc .nav__divider {
  width: 1px;
  height: 20px;
  background: var(--line-2);
}

.tzbc .livepill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 28px;
  padding: 0 12px 0 11px;
  border: 1px solid rgba(var(--live-rgb), 0.35);
  border-radius: var(--radius-pill);
  background: rgba(var(--live-rgb), 0.08);
  font: 500 12.5px/1 var(--font-sans);
  color: var(--live);
  white-space: nowrap;
}

.tzbc .livepill i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  animation: ping 1.8s var(--ease-out) infinite;
}

.tzbc .livepill.is-off {
  border-color: var(--line-2);
  background: transparent;
  color: var(--ink-3);
}

.tzbc .livepill.is-off i {
  animation: none;
}

/* ------------------------------------------------------------------ panel */

.tzbc .panel {
  position: relative;
  background: var(--surface-1);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-lg);
}

.tzbc .panel__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 16px;
  min-height: 52px;
  padding: 12px 20px;
  border-bottom: 1px solid var(--line-1);
}

.tzbc .panel__title {
  font: 500 15px/1.2 var(--font-sans);
  letter-spacing: -0.01em;
  color: var(--ink-1);
}

.tzbc .panel__code {
  font: 500 10px/1.3 var(--font-mono);
  letter-spacing: 0.12em;
  color: var(--ink-3);
  text-transform: uppercase;
}

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

.tzbc .seg {
  display: inline-flex;
  gap: 2px;
  max-width: 100%;
  padding: 3px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  overflow-x: auto;
  scrollbar-width: none;
}

.tzbc .seg::-webkit-scrollbar {
  display: none;
}

.tzbc .seg__btn {
  height: 28px;
  padding: 0 12px;
  border-radius: var(--radius-xs);
  font: 500 12.5px/1 var(--font-sans);
  color: var(--ink-3);
  white-space: nowrap;
  transition: color 0.15s, background-color 0.15s;
}

.tzbc .seg__btn:hover {
  color: var(--ink-1);
}

.tzbc .seg__btn[aria-pressed="true"],
.tzbc .seg__btn[aria-selected="true"] {
  color: var(--ink-1);
  background: rgba(var(--wash-rgb), 0.08);
  box-shadow: inset 0 0 0 1px rgba(var(--wash-rgb), 0.07);
}

.tzbc .seg__count {
  margin-inline-start: 6px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.tzbc .seg__btn[aria-pressed="true"] .seg__count {
  color: var(--ink-2);
}

.tzbc .toggle {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 36px;
  padding: 0 12px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  font: 500 12.5px/1 var(--font-sans);
  color: var(--ink-3);
  transition: color 0.15s, border-color 0.15s;
}

.tzbc .toggle::before {
  content: "";
  width: 9px;
  height: 9px;
  border: 1px solid var(--ink-3);
  border-radius: 3px;
  transition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s;
}

.tzbc .toggle:hover {
  color: var(--ink-1);
  border-color: var(--line-3);
}

.tzbc .toggle[aria-pressed="true"] {
  color: var(--ink-1);
}

.tzbc .toggle[aria-pressed="true"]::before {
  background: var(--ink-1);
  border-color: var(--ink-1);
  box-shadow: 0 0 10px rgba(var(--wash-rgb), 0.45);
}

.tzbc .iconbtn {
  display: inline-grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  color: var(--ink-2);
  transition: color 0.15s, border-color 0.15s;
}

.tzbc .iconbtn:hover {
  color: var(--ink-1);
  border-color: var(--line-3);
}

.tzbc .iconbtn svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

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

.tzbc .select select {
  appearance: none;
  height: 36px;
  padding: 0 34px 0 12px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  font: 500 12.5px/1 var(--font-sans);
  color: var(--ink-1);
  cursor: pointer;
}

.tzbc .select select:hover {
  border-color: var(--line-3);
}

.tzbc .select::after {
  content: "";
  position: absolute;
  inset-inline-end: 13px;
  top: 50%;
  width: 6px;
  height: 6px;
  margin-top: -5px;
  border-inline-end: 1.5px solid var(--ink-3);
  border-bottom: 1.5px solid var(--ink-3);
  transform: rotate(45deg);
  pointer-events: none;
}

.tzbc .select option {
  background: var(--surface-2);
  color: var(--ink-1);
}

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

.tzbc .search svg {
  position: absolute;
  inset-inline-start: 12px;
  width: 14px;
  height: 14px;
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1.6;
  pointer-events: none;
}

.tzbc .search input {
  width: 220px;
  height: 36px;
  padding: 0 12px 0 34px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  font: 400 13px/1 var(--font-sans);
  color: var(--ink-1);
}

.tzbc .search input::placeholder {
  color: var(--ink-3);
}

.tzbc .search input:hover {
  border-color: var(--line-3);
}

.tzbc .search input:focus {
  outline: none;
  border-color: var(--ink-2);
}

/* Primary actions: pill buttons — solid for the main call, outlined for the alternative. */
.tzbc .btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 44px;
  padding: 0 20px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font: 500 14px/1 var(--font-sans);
  white-space: nowrap;
  transition: background-color 0.2s, border-color 0.2s;
}

.tzbc .btn svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.3s var(--ease-out);
}

.tzbc .btn:hover svg {
  transform: translateX(3px);
}

.tzbc .btn--primary {
  background: var(--ink-1);
  color: var(--page);
}

.tzbc .btn--primary:hover {
  background: var(--btn-primary-hover);
}

.tzbc .btn--ghost {
  border-color: var(--line-3);
  color: var(--ink-1);
}

.tzbc .btn--ghost:hover {
  border-color: rgba(var(--wash-rgb), 0.26);
  background: var(--surface-3);
}

/* Compact variant for in-header admin controls. The base .btn is a 44px
   hero CTA; next to a section title it would outweigh the heading. The
   hover nudge is a CTA affordance too, so it is switched off here. */
.tzbc .btn--sm {
  height: 34px;
  padding: 0 14px;
  gap: 8px;
  font-size: 13px;
}

.tzbc .btn--sm:hover svg {
  transform: none;
}

/* The section head's right side: admin controls, then the card-chart
   tabs. Wraps rather than overflowing on a narrow frame. */
.tzbc .section-head__aside {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px 20px;
}

.tzbc .arena-admin {
  display: flex;
  gap: 8px;
}

.tzbc .arena-admin[hidden] {
  display: none;
}

.tzbc .bhead__admin {
  margin-inline-start: auto;
}

.tzbc .bhead__admin[hidden] {
  display: none;
}

.tzbc .empty .btn--sm[hidden] {
  display: none;
}

.tzbc .btn__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--live);
  color: var(--live);
  animation: ping 1.8s var(--ease-out) infinite;
}

/* Keyboard / gesture hints: a keycap followed by what it does. */
.tzbc .hints {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 22px;
  font: 400 12.5px/1.4 var(--font-sans);
  color: var(--ink-3);
}

.tzbc .hints li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.tzbc kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 7px;
  border: 1px solid var(--line-2);
  border-radius: 6px;
  background: var(--surface-2);
  font: 500 11px/1 var(--font-mono);
  color: var(--ink-2);
}

.tzbc kbd + kbd {
  margin-inline-start: -4px;
}

/* ------------------------------------------------------------- identities */

/* Bot logo: a neutral plate ringed in the bot's series colour, carrying the
   brand mark in its TRUE colours.

   EMBEDDED BUILD: this was a series-colour disc with every glyph forced to
   #080808. That silhouette treatment suited abstract glyphs; on real brand
   marks it turns Claude's coral starburst black and erases Gemini's colour
   washes. The plate is neutral now, the bot's colour moves to the ring (so
   logo, legend and line still read as one), and `color` is the ink that the
   monochrome marks (ChatGPT, Grok) draw with via currentColor. */
.tzbc .avatar {
  --size: 28px;
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: var(--size);
  height: var(--size);
  border-radius: 50%;
  background: var(--plate);
  color: var(--plate-ink);
  box-shadow: inset 0 0 0 1.5px var(--agent), 0 0 0 2px var(--surface-1), 0 0 18px -6px var(--agent);
}

/* The ZeeCube sits on a rounded square, not a disc. Keep in step with
   BC.ui.drawPlate, which draws the same shape inside charts. */
.tzbc .avatar--square {
  border-radius: 26%;
}

/* 56%, not the old 62%: brand marks fill their whole viewBox where the old
   glyphs carried padding, and the ring now takes the outer 1.5px. */
.tzbc .avatar svg {
  width: 56%;
  height: 56%;
}

/* Image marks — the TradeZee ZeeCube still. Width/height are set inline from
   the mark's `scale` (see identity.js) so this box stays the single reference. */
.tzbc .avatar__img {
  display: block;
  object-fit: contain;
  pointer-events: none;
  user-select: none;
}

/* NO `fill` on .glyph. Every path carries its brand fill as an attribute, and
   a CSS fill — even `currentColor` — outranks attributes and would repaint
   them all one colour. */

/* The generic hexagon (a model with no brand logo, e.g. Kimi, GLM). In the
   model's own colour: --plate-stroke is near-black and vanished on the dark
   plate (2026-10-28, real battles). */
.tzbc .glyph--stroke {
  fill: none;
  stroke: var(--agent, var(--plate-ink-2));
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tzbc .avatar--bench {
  background: var(--plate-bench);
  box-shadow: 0 0 0 2px var(--surface-1);
}

.tzbc .avatar--bench .glyph--stroke {
  /* --plate-ink-2, not --ink-2: this draws on the plate, which stays
     dark in both themes. See base.css. */
  stroke: var(--plate-ink-2);
}

/* Market monogram: one squircle for every market (no crypto in the embedded build). */
.tzbc .micon {
  --size: 40px;
  flex: none;
  display: grid;
  place-items: center;
  width: var(--size);
  height: var(--size);
  border: 1px solid var(--line-2);
  border-radius: 10px;
  background: var(--surface-2);
  font: 600 calc(var(--size) * 0.36) / 1 var(--font-mono);
  letter-spacing: -0.02em;
  color: var(--ink-1);
}

/* Pair icon, the app's ForexIcon (ui/identity.js marketIcon): no tile, two
   overlapping round coins — base top-left, quote behind it to the bottom-right. */
.tzbc .micon--pair {
  position: relative;
  display: block;
  border: 0;
  background: none;
}

.tzbc .micon__coin {
  position: absolute;
  display: grid;
  place-items: center;
  width: var(--d);
  height: var(--d);
  overflow: hidden;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgb(0 0 0 / 0.3);
  font: 700 calc(var(--d) * 0.4) / 1 var(--font-sans);
  letter-spacing: 0;
}

/* Flags are 3:2; cover crops them to the centre of the circle. */
.tzbc .micon__coin img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.tzbc .micon__base { top: 0; inset-inline-start: 0; z-index: 1; }
.tzbc .micon__quote { top: calc(var(--size) * 0.35); inset-inline-start: calc(var(--size) * 0.35); z-index: 0; }

.tzbc .micon__coin--xau { background: linear-gradient(135deg, #ffd700, #b8860b); color: #78350f; }
.tzbc .micon__coin--xag { background: linear-gradient(135deg, #e8e8e8, #a8a8a8); color: #374151; }
.tzbc .micon__coin--xpt { background: linear-gradient(135deg, #e5e4e2, #c0c0c0); color: #4b5563; }
.tzbc .micon__coin--xpd { background: linear-gradient(135deg, #ced0dd, #9ea0a8); color: #374151; }
.tzbc .micon__coin--text { background: var(--surface-3); color: var(--ink-2); font-size: calc(var(--d) * 0.32); }

/* ------------------------------------------------------------------ badges */

.tzbc .badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 22px;
  padding: 0 10px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-pill);
  font: 600 10px/1 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
}

.tzbc .badge--live {
  color: var(--live);
  border-color: rgba(var(--live-rgb), 0.35);
  background: rgba(var(--live-rgb), 0.08);
}

/* Live and finished lead with crossed swords (ui.swords) instead of a dot:
   clashing on a loop while live, still once finished. Same motion as the
   nav icon (src/components/ui/icons/icons.css), one strike every 2.6s. */
.tzbc .badge .bsw {
  flex: none;
  width: 14px;
  height: 14px;
  margin-inline-start: -2px;
  overflow: visible;
}

.tzbc .badge--settled .bsw { color: var(--ink-3); }

.tzbc .bsw__swing,
.tzbc .bsw__spark,
.tzbc .bsw__jolt {
  transform-box: view-box;
  transform-origin: 0 0;
}

.tzbc .bsw--live .bsw__jolt { animation: bsw-jolt 2.6s infinite; }
.tzbc .bsw--live .bsw__a { animation: bsw-a 2.6s infinite; }
.tzbc .bsw--live .bsw__b { animation: bsw-b 2.6s infinite; }
.tzbc .bsw--live .bsw__spark {
  opacity: 0;
  animation: bsw-spark 2.6s infinite;
  filter: drop-shadow(0 0 1.2px #facc15) drop-shadow(0 0 2.5px rgba(250, 204, 21, 0.7));
}

@keyframes bsw-a {
  0%   { transform: rotate(0deg); animation-timing-function: cubic-bezier(.2, .7, .3, 1); }
  14%  { transform: rotate(-30deg); animation-timing-function: cubic-bezier(.6, 0, .9, .4); }
  23%  { transform: rotate(7deg); animation-timing-function: ease-out; }
  29%  { transform: rotate(-3deg); animation-timing-function: ease-in-out; }
  37%, 100% { transform: rotate(0deg); }
}

@keyframes bsw-b {
  0%   { transform: rotate(0deg); animation-timing-function: cubic-bezier(.2, .7, .3, 1); }
  14%  { transform: rotate(30deg); animation-timing-function: cubic-bezier(.6, 0, .9, .4); }
  23%  { transform: rotate(-7deg); animation-timing-function: ease-out; }
  29%  { transform: rotate(3deg); animation-timing-function: ease-in-out; }
  37%, 100% { transform: rotate(0deg); }
}

@keyframes bsw-spark {
  0%, 21%   { opacity: 0; transform: scale(.3); }
  24%       { opacity: 1; transform: scale(1.1); }
  30%       { opacity: 1; transform: scale(1); }
  44%, 100% { opacity: 0; transform: scale(1.3); }
}

@keyframes bsw-jolt {
  0%, 22%   { transform: translate(0, 0); }
  24%       { transform: translate(0, .6px); }
  28%, 100% { transform: translate(0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .tzbc .bsw--live .bsw__jolt,
  .tzbc .bsw--live .bsw__a,
  .tzbc .bsw--live .bsw__b,
  .tzbc .bsw--live .bsw__spark { animation: none; }
}

/* A configured battle that has not been started. NOT "settled": there is
   no result yet. Hollow dot rather than the settled solid one, so the
   three states read apart at a glance — pulsing (live), hollow (draft),
   solid (settled). */
.tzbc .badge--draft {
  color: var(--ink-2);
  border-style: dashed;
}

.tzbc .badge--draft::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  opacity: 0.7;
}

/* Started, then paused: nothing trades until it resumes. Two bars, the
   universal pause mark, so it reads apart from live and finished. */
.tzbc .badge--paused {
  color: var(--ink-2);
}

.tzbc .badge--paused::before {
  content: "";
  width: 6px;
  height: 7px;
  border-inline: 2px solid currentColor;
  box-sizing: border-box;
}

.tzbc .badge--story {
  border-color: transparent;
  background: rgba(var(--wash-rgb), 0.07);
  color: var(--ink-1);
}

.tzbc .badge--solid {
  border-color: var(--ink-1);
  background: var(--ink-1);
  color: var(--page);
}

/* Delta chip: signed value on a faint status wash. */
.tzbc .delta {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 22px;
  padding: 0 8px;
  border-radius: 6px;
  font: 500 11px/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tzbc .delta svg {
  width: 8px;
  height: 8px;
  fill: currentColor;
}

.tzbc .delta.is-pos {
  background: rgba(var(--pos-rgb), 0.13);
}

.tzbc .delta.is-neg {
  background: rgba(var(--neg-rgb), 0.12);
}

.tzbc .delta.is-neg svg {
  transform: rotate(180deg);
}

.tzbc .delta.is-flat {
  background: rgba(var(--wash-rgb), 0.06);
}

.tzbc .delta.is-flat svg {
  display: none;
}

/* ----------------------------------------------------------------- tooltip */

.tzbc .tip {
  position: absolute;
  z-index: 20;
  top: 0;
  inset-inline-start: 0;
  min-width: 248px;
  padding: 10px 12px 8px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--tip-bg);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  box-shadow: 0 24px 60px -16px var(--shadow-col);
  font: 400 12px/1.35 var(--font-mono);
  color: var(--ink-2);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.14s;
}

.tzbc .tip.is-on {
  opacity: 1;
}

.tzbc .tip__head {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 6px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line-1);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}

.tzbc .tip__head b {
  font-weight: 500;
  color: var(--ink-1);
}

.tzbc .tip__row {
  display: grid;
  grid-template-columns: 12px auto 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 3px 0;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.tzbc .tip__key {
  width: 12px;
  height: 2px;
  border-radius: 1px;
  background: var(--c);
}

.tzbc .tip__val {
  font-weight: 500;
  color: var(--ink-1);
}

.tzbc .tip__name {
  color: var(--ink-3);
  font-size: 11px;
  letter-spacing: 0.06em;
}

.tzbc .tip__sub {
  font-size: 11px;
}

.tzbc .tip__row.is-bench .tip__val {
  color: var(--ink-2);
}

.tzbc .tip__trades {
  margin-top: 6px;
  padding-top: 7px;
  border-top: 1px solid var(--line-1);
}

.tzbc .tip__trade {
  display: flex;
  gap: 8px;
  padding: 2px 0;
  font-size: 11px;
  white-space: nowrap;
}

.tzbc .tip__trade b {
  font-weight: 600;
  color: var(--ink-1);
}

/* ------------------------------------------------------------------ tables */

.tzbc .tablewrap {
  overflow-x: auto;
  scrollbar-width: thin;
}

/* A table that ends its panel follows the panel's rounded bottom corners. */
.tzbc .panel > .tablewrap:last-child {
  border-radius: 0 0 calc(var(--radius-lg) - 1px) calc(var(--radius-lg) - 1px);
}

.tzbc .dtable {
  width: 100%;
  min-width: 980px;
  border-collapse: separate;
  border-spacing: 0;
  font: 400 12.5px/1.2 var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.tzbc .dtable th {
  padding: 12px 16px;
  border-bottom: 1px solid var(--line-2);
  font: 500 10px/1.2 var(--font-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: end;
  color: var(--ink-3);
  white-space: nowrap;
}

.tzbc .dtable td {
  padding: 13px 16px;
  border-bottom: 1px solid var(--line-1);
  text-align: end;
  color: var(--ink-2);
  white-space: nowrap;
}

.tzbc .dtable th.is-left,
.tzbc .dtable td.is-left {
  text-align: start;
}

.tzbc .dtable td.is-pos { color: var(--pos); }
.tzbc .dtable td.is-neg { color: var(--neg); }
.tzbc .dtable td.is-flat { color: var(--ink-3); }

.tzbc .dtable tbody tr {
  transition: background-color 0.15s;
}

.tzbc .dtable tbody tr:hover {
  background: rgba(var(--wash-rgb), 0.025);
}

.tzbc .sortbtn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
}

.tzbc .sortbtn:hover {
  color: var(--ink-1);
}

.tzbc .sortbtn::after {
  content: "";
  width: 0;
  height: 0;
  border-inline-start: 3.5px solid transparent;
  border-inline-end: 3.5px solid transparent;
  border-top: 4px solid currentColor;
  opacity: 0;
  transition: opacity 0.15s, transform 0.2s;
}

.tzbc [aria-sort] .sortbtn {
  color: var(--ink-1);
}

.tzbc [aria-sort] .sortbtn::after {
  opacity: 1;
}

.tzbc [aria-sort="ascending"] .sortbtn::after {
  transform: rotate(180deg);
}
/* The footer ("BattleCharts · Autonomous trading arena" + the disclaimer) was
   removed in the embedded build along with the page frame — see the note on
   `html` in base.css. Its styles went with it.

   NOTE: the simulated-data disclaimer lived there. If this surface ever shows
   anything a reader could mistake for real market data, that line needs a new
   home rather than quietly staying deleted. */

/* ------------------------------------------------------------- empty state */

.tzbc .empty {
  display: grid;
  place-items: center;
  gap: 14px;
  padding: 72px 20px;
  text-align: center;
}

.tzbc .empty h2 {
  font: 500 22px/1.2 var(--font-sans);
  letter-spacing: -0.01em;
  color: var(--ink-1);
}

.tzbc .empty p {
  max-width: 420px;
  color: var(--ink-3);
}

.tzbc .linkbtn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  height: 38px;
  padding: 0 16px;
  border: 1px solid var(--line-3);
  border-radius: var(--radius-sm);
  font: 500 13px/1 var(--font-sans);
  color: var(--ink-1);
  transition: background-color 0.15s;
}

.tzbc .linkbtn:hover {
  background: rgba(var(--wash-rgb), 0.06);
}

.tzbc .linkbtn svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (max-width: 760px) {
  .tzbc .crumbs,
  .tzbc .nav__divider,
  .tzbc .nav__stat {
    display: none;
  }
}


/* ============ chart.css ============ */
/* ==========================================================================
   BattleCharts — chart styles (RaceChart, PriceChart, PulseStrip)
   ========================================================================== */

.tzbc .rc {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 0;
  outline: none;
}

.tzbc .rc:focus-visible {
  box-shadow: inset 0 0 0 1px var(--line-3);
}

.tzbc .rc__svg {
  position: absolute;
  inset: 0;
  overflow: visible;
}

/* ------------------------------------------------------------- furniture */

.tzbc .rc__grid line {
  stroke: var(--grid);
  stroke-width: 1;
}

.tzbc .rc__axis text {
  fill: var(--ink-3);
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
}

/* Phone layout: the y figures stand inside the plot rather than in a gutter,
   so they carry a halo in the card colour and step back a shade — a line
   crossing one must not swallow it, and it must not read as data. */
.tzbc .rc__axis--inside text,
.tzbc .vc__axis--inside text {
  fill: var(--ink-4);
  paint-order: stroke;
  stroke: var(--surface-1);
  stroke-width: 3px;
  stroke-linejoin: round;
}

.tzbc .rc__axisline {
  stroke: var(--axis);
}

.tzbc .rc__striplabels text {
  font-size: 9px;
  letter-spacing: 0.12em;
  fill: var(--ink-4);
}

.tzbc .rc__base line {
  stroke: rgba(var(--wash-rgb), 0.24);
  stroke-width: 1;
  stroke-dasharray: 2 5;
}

.tzbc .rc--mini .rc__base line {
  stroke: rgba(var(--wash-rgb), 0.16);
  stroke-dasharray: 2 4;
}

.tzbc .rc__basepill rect {
  fill: var(--surface-3);
  stroke: rgba(var(--wash-rgb), 0.22);
  shape-rendering: crispEdges;
}

.tzbc .rc__basepill-value {
  fill: var(--ink-1);
  font: 600 10px/1 var(--font-mono);
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
}

.tzbc .rc__basepill-cap {
  fill: var(--ink-3);
  font: 500 8.5px/1 var(--font-mono);
  letter-spacing: 0.16em;
}

.tzbc .rc.is-intro .rc__grid,
.tzbc .rc.is-intro .rc__axis,
.tzbc .rc.is-intro .rc__base {
  animation: fade 1.1s var(--ease-out) both;
}

/* ----------------------------------------------------------------- lines */

.tzbc .rc-line {
  fill: none;
  stroke: var(--c);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: opacity 0.3s, stroke-width 0.3s;
}

.tzbc .rc--mini .rc-line {
  stroke-width: 1.6;
}

.tzbc .rc-glow {
  fill: none;
  stroke: var(--c);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.32;
  transition: opacity 0.3s;
}

.tzbc .rc-glow.is-emph {
  opacity: 0.75;
}

.tzbc .rc-line.is-emph {
  stroke-width: 2.4;
}

.tzbc .rc-area {
  opacity: 0;
  transition: opacity 0.45s;
}

.tzbc .rc-area.is-lead {
  opacity: 0.45;
}

.tzbc .rc-area.is-on {
  opacity: 1;
}

.tzbc .rc-bench {
  fill: none;
  stroke: var(--bench);
  stroke-width: 1.5;
  stroke-linejoin: round;
  transition: opacity 0.3s;
}

.tzbc .rc.has-emph .rc-line:not(.is-emph) {
  opacity: 0.16;
}

.tzbc .rc.has-emph .rc-glow:not(.is-emph),
.tzbc .rc.has-emph .rc-bench {
  opacity: 0.12;
}

/* The line and glow selectors match the dimming rules above in weight, so a
   hidden racer stays hidden while another is emphasised; with only
   `.rc.has-emph .is-hidden` they lost and showed at 16% (found 2026-10-27,
   when the battle page's model view hides every other racer). */
.tzbc .rc .is-hidden,
.tzbc .rc.has-emph .is-hidden,
.tzbc .rc.has-emph .rc-line.is-hidden,
.tzbc .rc.has-emph .rc-glow.is-hidden {
  opacity: 0;
  pointer-events: none;
}

/* ------------------------------------------------------------------ tips */

.tzbc .rc-tip {
  transition: opacity 0.3s;
}

.tzbc .rc--full .rc-tip:not(.rc-tip--bench) {
  cursor: pointer;
}

.tzbc .rc-tip.is-dim {
  opacity: 0.32;
}

.tzbc .rc-tip__leader {
  fill: none;
  stroke: var(--c);
  stroke-width: 1;
  opacity: 0.6;
}

.tzbc .rc-tip__dot {
  fill: var(--c);
  stroke: var(--surface-1);
  stroke-width: 2;
}

.tzbc .rc-tip__halo {
  opacity: 0;
  transition: opacity 0.6s;
  pointer-events: none;
}

.tzbc .rc.is-intro .rc-tip__halo {
  opacity: 1;
}

.tzbc .rc-tip__pulse {
  fill: none;
  stroke: var(--c);
  stroke-width: 1.2;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  pointer-events: none;
  transform-box: fill-box;
  transform-origin: center;
}

.tzbc .rc.is-live.is-ready .rc-tip:not(.rc-tip--bench) .rc-tip__pulse {
  animation: rc-pulse 2.2s var(--ease-out) infinite;
}

@keyframes rc-pulse {
  from { transform: scale(1); opacity: 0.9; }
  to { transform: scale(4); opacity: 0; }
}

/* Line-end logo badge, as the original drew it: a disc in the series colour
   with the mark inked near-black.

   EMBEDDED BUILD (user, picking "Original look" for the first tab, and: "at
   the end of every line i want the logo, for each of the five style this
   should remain same"). Every main-chart design draws these same badges.
   Brand marks are multi-layer paths, so the ink goes on every layer (it also
   flattens Gemini's gradient star into one shape). The ZeeCube is an image,
   not paths: it keeps its own light face, which reads on TradeZee's purple.
   The legend's avatars (components.css) keep their brand-colour marks. */
.tzbc .rc-tip__badge {
  fill: var(--c);
  stroke: var(--surface-1);
  stroke-width: 2;
}

.tzbc .rc-tip--bench .rc-tip__badge {
  fill: var(--plate-bench);
}

.tzbc .rc-tip--bench .rc-tip__leader {
  stroke: var(--ink-3);
}

.tzbc .rc-tip__glyph path {
  fill: var(--plate-stroke);
}

.tzbc .rc-tip__glyph .is-stroke {
  fill: none;
  stroke: var(--plate-stroke);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tzbc .rc-tip--bench .rc-tip__glyph .is-stroke {
  stroke: var(--ink-2);
}

.tzbc .rc-tip__name {
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.1em;
  fill: var(--ink-2);
}

/* ── THE CHANGE FIGURE SITS IN THE VALUE ROW (user, 2026-10-24: "fit the
      values in the row below instead of decreasing chart size") ──────────

   It used to trail the NAME on the first row — "CLAUDE SONNET 5.5 −0.1%"
   — and with the API's real model names that row no longer fit the room at
   the right of the plot. Widening the room cost the lines their width, which
   is the one thing a chart should not give up. So the figure moves down to
   sit beside the value, the row that is short whatever the bot is called.

   It carries its OWN font now. It used to inherit the name's (mono, 10px);
   its new parent is the value, at 13.5px semibold sans, and inheriting that
   would turn a quiet annotation into a second headline figure. Declared
   here rather than nested under either row, so it reads the same wherever
   it is placed. */
.tzbc .rc-tip__sub {
  font: 500 10px/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  fill: var(--ink-3);
}

.tzbc .rc-tip__sub.is-pos { fill: var(--pos); }
.tzbc .rc-tip__sub.is-neg { fill: var(--neg); }

.tzbc .rc-tip__value {
  font: 600 13.5px/1 var(--font-sans);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  fill: var(--ink-1);
}

.tzbc .rc-tip--bench .rc-tip__value {
  fill: var(--ink-2);
}

/* -------------------------------------------------------- intro scanline */

.tzbc .rc__scan {
  opacity: 0;
  transition: opacity 0.5s;
  pointer-events: none;
}

.tzbc .rc__scan.is-on {
  opacity: 1;
}

.tzbc .rc__scan-line {
  stroke: rgba(var(--wash-rgb), 0.4);
  stroke-width: 1;
}

/* ------------------------------------------------------------- crosshair */

.tzbc .rc__overlay {
  fill: transparent;
  cursor: crosshair;
  touch-action: pan-y;
}

/* ── THE PAN CURSOR (embedded build, 2026-10-18) ────────────────────────
   (user: "pan should have grab cursor".) A drag already turned the cursor
   to `grabbing`, but nothing before it said the chart could be dragged at
   all. The open hand appears exactly when panning would do something —
   once zoomed in — because at full zoom there is nowhere to pan to and a
   grab cursor there would be an empty promise. The crosshair stays the
   resting cursor, since reading values is still the main thing here. */
.tzbc .rc.is-zoomed .rc__overlay,
.tzbc .vc.is-zoomed .vc__overlay {
  cursor: grab;
}

.tzbc .rc.is-panning .rc__overlay,
.tzbc .vc.is-panning .vc__overlay {
  cursor: grabbing;
}

/* ON THE ROOT AS WELL, and this is the half that matters once a drag is
   under way: a pan captures the pointer, and a captured pointer takes its
   cursor from the CAPTURING element — the chart root — not from whatever
   lies under it. With the rule only on the overlay the closed hand vanished
   the instant the drag started, which is the one moment it is wanted. */
.tzbc .rc.is-zoomed,
.tzbc .vc.is-zoomed {
  cursor: grab;
}

.tzbc .rc.is-panning,
.tzbc .vc.is-panning {
  cursor: grabbing;
}

.tzbc .rc__cross {
  pointer-events: none;
}

.tzbc .rc__cross-line {
  stroke: rgba(var(--wash-rgb), 0.38);
  stroke-width: 1;
}

.tzbc .rc__cross circle {
  fill: var(--c);
  stroke: var(--surface-1);
  stroke-width: 2;
}

.tzbc .rc__pill rect {
  fill: var(--ink-1);
}

.tzbc .rc__pill text {
  fill: var(--on-ink);
  font: 600 10px/1 var(--font-mono);
  letter-spacing: 0.08em;
}

.tzbc .rc .tip {
  will-change: transform;
}

/* -------------------------------------------------------- trade markers */

.tzbc .rc-mark {
  stroke-width: 1.5;
  stroke-linejoin: round;
}

.tzbc .rc-mark.is-buy {
  fill: var(--c);
  stroke: var(--surface-1);
}

.tzbc .rc-mark.is-sell {
  fill: var(--surface-1);
  stroke: var(--c);
}

/* -------------------------------------------------------- activity strip */

.tzbc .rc__strip rect {
  fill: rgba(var(--wash-rgb), 0.2);
  transition: fill 0.2s;
}

.tzbc .rc__strip rect.is-sell {
  fill: rgba(var(--wash-rgb), 0.153);
}

.tzbc .rc__strip rect.is-emph {
  fill: var(--c);
  opacity: 0.75;
}

.tzbc .rc__strip rect.is-emph.is-sell {
  opacity: 0.45;
}

.tzbc .rc__strip rect.is-hot {
  fill: var(--ink-1);
  opacity: 1;
}

.tzbc .rc__stripmid {
  stroke: var(--line-1);
}

/* ==========================================================================
   Main-chart designs (ui/chart-variants.js) — EMBEDDED BUILD, 2026-10-17

   Four more designs of the battle's line chart beside the original. Each
   brings its own furniture (axes, labels, readouts), so almost nothing below
   is shared beyond the root and the empty state.
   ========================================================================== */

.tzbc .vc {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 0;
  outline: none;
}

.tzbc .vc:focus-visible {
  box-shadow: inset 0 0 0 1px var(--line-3);
}

.tzbc .vc__overlay {
  fill: transparent;
  cursor: crosshair;
  touch-action: pan-y;
}

.tzbc .vc__overlay.is-near {
  cursor: pointer;
}

.tzbc .vc__fx {
  pointer-events: none;
}

.tzbc .vc__html {
  position: absolute;
}

.tzbc .vc__empty {
  font: 500 12.5px/1 var(--font-sans);
  fill: var(--ink-3);
}

.tzbc .vc:not(.is-blank) .vc__empty,
.tzbc .vc.is-blank .vc__back,
.tzbc .vc.is-blank .vc__body,
.tzbc .vc.is-blank .vc__fx,
.tzbc .vc.is-blank .vc__front,
.tzbc .vc.is-blank .vc__html {
  display: none;
}

.tzbc .vc.is-intro .vc__html:not(.vc-aura__bubble) {
  animation: fade 0.9s var(--ease-out) both;
}

/* The line-end logos are the original's labels (rc-tip, above), and they read
   the same in every design: the original's Geist type and upper-case names,
   as on the Race tab (battle.css), whatever the type around them. */
.tzbc .vc .rc-tip {
  --font-sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo, Consolas, monospace;
}

.tzbc .vc .rc-tip__nm {
  text-transform: uppercase;
}

.tzbc .vc .rc-tip:not(.rc-tip--bench) {
  cursor: pointer;
}

/* Hovering or focusing a bot pushes the rest of the field back, the way the
   original chart does — the one line you asked about stays in colour and
   everything else steps aside. The featured line sits in its own layer in
   every design, so these rules only reach the others. */
.tzbc .vc.has-emph .vc-aura__line:not(.is-hero),
.tzbc .vc.has-emph .vc-signal__line,
.tzbc .vc.has-emph .vc-pulse__line,
.tzbc .vc.has-emph .vc-contour__other {
  opacity: 0.16;
}

/* ---------------------------------------------------------------- aura */

.tzbc .vc-aura__field {
  opacity: 0.15;
}

.tzbc .vc-aura__wash {
  opacity: 0.85;
}

.tzbc .vc-aura__line {
  fill: none;
  stroke-width: 2.25;
  stroke-linecap: round;
  opacity: 0.72;
  transition: opacity 0.35s, stroke-width 0.35s;
}

.tzbc .vc-aura__line.is-hero {
  stroke-width: 3.25;
  opacity: 1;
}

.tzbc .vc-aura__line.is-bench {
  stroke-width: 1.5;
  opacity: 0.32;
}

.tzbc .vc-aura__dates text {
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.08em;
  fill: var(--ink-4);
}

.tzbc .vc-aura__halo {
  fill: var(--c);
  opacity: 0.2;
}

.tzbc .vc-aura__ring {
  fill: var(--surface-1);
  stroke: var(--c);
  stroke-width: 2.75;
}

/* The figure the bot picker used to sit above; the picker is gone. */
.tzbc .vc-aura__stat {
  pointer-events: none;
}

.tzbc .vc-aura__num {
  font: 300 38px/1 var(--font-sans);
  letter-spacing: -0.035em;
  color: var(--ink-1);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.tzbc .vc-aura__stat.is-compact .vc-aura__num {
  font-size: 26px;
}

.tzbc .vc-aura__cap {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 8px;
  font: 500 10px/1.3 var(--font-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}

.tzbc .vc-aura__cap::before {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--c);
}

/* A light bubble on the dark card, as the reference's white one on light. */
.tzbc .vc-aura__bubble {
  top: 0;
  left: 0;
  z-index: 5;
  padding: 10px 16px 11px;
  border-radius: 16px;
  background: var(--bubble-bg);
  box-shadow: 0 18px 40px -14px var(--shadow-col);
  text-align: center;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s, transform 0.09s ease-out;
}

.tzbc .vc-aura__bubble.is-on {
  opacity: 1;
}

.tzbc .vc-aura__bubble b {
  display: block;
  font: 500 13px/1.2 var(--font-sans);
  color: var(--bubble-ink);
}

.tzbc .vc-aura__bubble span {
  display: block;
  margin-top: 4px;
  font: 400 11px/1.2 var(--font-sans);
  color: var(--bubble-ink-2);
}

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

.tzbc .vc-signal__grid line {
  stroke: rgba(var(--wash-rgb), 0.055);
}

.tzbc .vc-signal__axis text {
  font: 400 10.5px/1 var(--font-sans);
  fill: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.tzbc .vc-signal__dates text {
  font: 400 10px/1 var(--font-sans);
  fill: var(--ink-4);
}

/* EVERY BOT KEEPS ITS COLOUR (user, 2026-10-18: "when i change to other
   views it is not highlighting all the line like the first chart does").
   These designs drew the field in grey so one line could carry the chart,
   but that lost the colour coding the original gives every bot — and with
   it the ability to pick your bot out of the pack at a glance. The featured
   line still leads, on weight and glow rather than on being the only one in
   colour. */
.tzbc .vc-signal__line {
  fill: none;
  stroke: var(--c);
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.72;
  transition: opacity 0.3s;
}

.tzbc .vc-signal__line.is-bench {
  stroke: var(--bench);
  stroke-dasharray: 2 5;
  opacity: 0.6;
}

.tzbc .vc-signal__glow {
  fill: none;
  stroke: var(--c);
  stroke-width: 9;
  stroke-linecap: round;
  opacity: 0.5;
}

.tzbc .vc-signal__hero {
  fill: none;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tzbc .vc-signal__cross line {
  stroke: rgba(var(--wash-rgb), 0.6);
  stroke-width: 1.25;
  stroke-dasharray: 1.5 4;
  stroke-linecap: round;
}

.tzbc .vc-signal__cap {
  fill: var(--ink-1);
}

.tzbc .vc-signal__ring {
  fill: var(--surface-1);
  stroke: var(--c);
  stroke-width: 2.5;
}

/* The readout inverts the card, as the reference's black pill on white. */
.tzbc .vc-signal__readbg {
  fill: var(--ink-1);
}

.tzbc .vc-signal__readval {
  font: 600 12.5px/1 var(--font-sans);
  fill: var(--on-ink);
  font-variant-numeric: tabular-nums;
}

.tzbc .vc-signal__readdelta {
  font: 600 11px/1 var(--font-mono);
  fill: var(--on-ink-2);
}

.tzbc .vc-signal__readdelta.is-pos { fill: var(--on-ink-pos); }
.tzbc .vc-signal__readdelta.is-neg { fill: var(--on-ink-neg); }

/* --------------------------------------------------------------- pulse */

.tzbc .vc-pulse__bars rect {
  fill: rgba(var(--wash-rgb), 0.085);
  transition: fill 0.2s, opacity 0.2s;
}

.tzbc .vc-pulse__bars rect.is-sel {
  fill: var(--c);
  opacity: 0.5;
}

.tzbc .vc-pulse__line {
  fill: none;
  stroke: var(--c);
  stroke-width: 1.5;
  stroke-linejoin: round;
  opacity: 0.66;
  transition: opacity 0.3s;
}

.tzbc .vc-pulse__line.is-bench {
  stroke: var(--bench);
  stroke-dasharray: 3 4;
  opacity: 0.55;
}

.tzbc .vc-pulse__hero {
  fill: none;
  stroke: var(--c);
  stroke-width: 2.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tzbc .vc-pulse__beam {
  stroke-width: 1;
}

.tzbc .vc-pulse__dot,
.tzbc .vc-pulse__seldot {
  fill: var(--c);
  stroke: var(--surface-1);
  stroke-width: 2.5;
}

.tzbc .vc-pulse__seldot {
  pointer-events: none;
}

.tzbc .vc-ev {
  cursor: help;
}

.tzbc .vc-ev__stem {
  stroke: var(--f);
  stroke-width: 1.5;
  opacity: 0.7;
}

.tzbc .vc-ev__dot {
  fill: var(--f);
  stroke: var(--surface-1);
  stroke-width: 2;
}

.tzbc .vc-ev__pill rect {
  fill: var(--f);
}

.tzbc .vc-ev__icon {
  fill: var(--i);
}

.tzbc .vc-pulse__head {
  top: 8px;
  text-align: center;
  pointer-events: none;
}

.tzbc .vc-pulse__head.is-compact {
  top: 4px;
}

.tzbc .vc-pulse__row {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}

.tzbc .vc-pulse__num {
  font: 300 44px/1 var(--font-sans);
  letter-spacing: -0.035em;
  color: var(--ink-1);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tzbc .vc-pulse__head.is-compact .vc-pulse__num {
  font-size: 32px;
}

.tzbc .vc-pulse__cap {
  margin-top: 10px;
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .vc-pulse__chip {
  padding: 4px 8px;
  border-radius: var(--radius-pill);
  font: 600 11px/1 var(--font-mono);
  white-space: nowrap;
  background: rgba(var(--wash-rgb), 0.08);
  color: var(--ink-2);
}

.tzbc .vc-pulse__chip.is-pos {
  background: rgba(var(--pos-rgb), 0.18);
  color: var(--chip-pos-ink);
}

.tzbc .vc-pulse__chip.is-neg {
  background: rgba(var(--neg-rgb), 0.18);
  color: var(--chip-neg-ink);
}

.tzbc .vc-pulse__card {
  top: 0;
  left: 0;
  padding: 9px 12px 10px;
  border: 1px solid color-mix(in srgb, var(--c) 38%, transparent);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--c) 14%, var(--card-scrim));
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  box-shadow: 0 16px 36px -16px var(--shadow-col);
  pointer-events: none;
  white-space: nowrap;
}

.tzbc .vc-pulse__cardrow {
  display: flex;
  align-items: center;
  gap: 9px;
}

.tzbc .vc-pulse__cardrow b {
  font: 500 15px/1 var(--font-sans);
  color: var(--ink-1);
  font-variant-numeric: tabular-nums;
}

.tzbc .vc-pulse__cardcap {
  margin-top: 6px;
  font: 400 10.5px/1.2 var(--font-sans);
  color: var(--ink-3);
}

.tzbc .vc-pulse__card.is-compact .vc-pulse__cardcap {
  display: none;
}

.tzbc .vc-pulse__track {
  fill: rgba(var(--wash-rgb), 0.03);
}

.tzbc .vc-pulse__mini {
  fill: var(--c);
  fill-opacity: 0.14;
  stroke: var(--c);
  stroke-opacity: 0.55;
  stroke-width: 1.25;
}

.tzbc .vc-pulse__shade {
  fill: var(--surface-1);
  opacity: 0.55;
  pointer-events: none;
}

/* d3's brush draws its own selection rect; these override its attributes. */
.tzbc .vc-pulse__brush .selection {
  fill: var(--c);
  fill-opacity: 0.1;
  stroke: var(--c);
  stroke-opacity: 0.6;
  rx: 9px;
}

.tzbc .vc-pulse__handle {
  fill: var(--ink-1);
  pointer-events: none;
}

.tzbc .vc-pulse__dates text {
  font: 400 9.5px/1 var(--font-sans);
  fill: var(--ink-4);
}

/* ------------------------------------------------------------- contour */

/* Fill only, no outline: the chart panel is already a bordered box and this
   well sat inside it as a second frame. */
.tzbc .vc-contour__well {
  fill: rgba(var(--wash-rgb), 0.022);
}

.tzbc .vc-contour__axis text,
.tzbc .vc-contour__dates text {
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.06em;
  fill: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.tzbc .vc-contour__dates text {
  fill: var(--ink-4);
}

.tzbc .vc-contour__other {
  fill: none;
  stroke: var(--c);
  stroke-width: 1.6;
  opacity: 0.62;
  transition: opacity 0.3s, stroke-width 0.3s;
}

/* Nothing picked: every bot carries the same weight as the one in front. */
.tzbc .vc-contour__other.is-equal {
  stroke-width: 2.25;
  opacity: 1;
}

.tzbc .vc-contour__line {
  fill: none;
  stroke: var(--tint);
  stroke-width: 2.25;
  stroke-linejoin: round;
}

.tzbc .vc-contour__hold {
  fill: none;
  stroke: var(--amber);
  stroke-width: 2;
  stroke-dasharray: 6 7;
  stroke-linecap: round;
}

.tzbc .vc-contour__band {
  fill: rgba(var(--wash-rgb), 0.05);
}

.tzbc .vc-contour__mark {
  fill: var(--tint);
  stroke: var(--surface-1);
  stroke-width: 2.5;
}

.tzbc .vc-contour__legend,
.tzbc .vc-contour__readout {
  display: flex;
  align-items: center;
  gap: 18px;
  pointer-events: none;
  white-space: nowrap;
}

.tzbc .vc-contour__key {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font: 500 12px/1 var(--font-sans);
  color: var(--ink-1);
}

.tzbc .vc-contour__sw {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 3px;
  background: var(--c);
}

.tzbc .vc-contour__sw.is-dash {
  width: 16px;
  height: 0;
  border-radius: 0;
  border-top: 2px dashed var(--amber);
  background: none;
}

.tzbc .vc-contour__cap {
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .vc-contour__val {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.tzbc .vc-contour__val b {
  font: 500 13px/1 var(--font-sans);
  color: var(--ink-1);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------ sparklines */

.tzbc .spark {
  overflow: visible;
}

.tzbc .spark__line {
  fill: none;
  stroke-width: 1.5;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.tzbc .spark__base {
  stroke: rgba(var(--wash-rgb), 0.14);
  stroke-dasharray: 2 3;
}

/* ----------------------------------------------------------- price chart */

.tzbc .pc {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 0;
}

.tzbc .pc__line {
  fill: none;
  stroke: var(--ink-1);
  stroke-width: 1.6;
  stroke-linejoin: round;
}

.tzbc .pc__area {
  fill: url(#pc-area);
}

.tzbc .pc .rc__cross circle {
  fill: var(--ink-1);
}

.tzbc .pc.is-empty::after {
  content: attr(data-empty);
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--ink-3);
  font-size: 13px;
}

/* ----------------------------------------------------------- pulse strip */

.tzbc .pulse {
  position: relative;
  height: 100%;
}

.tzbc .pulse svg {
  position: absolute;
  inset: 0;
  overflow: visible;
}

.tzbc .pulse__bar {
  fill: rgba(var(--wash-rgb), 0.35);
  transition: fill 0.15s;
}

.tzbc .pulse__bar.is-down {
  fill: rgba(var(--wash-rgb), 0.18);
}

.tzbc .pulse__bar.is-hot {
  fill: var(--ink-1);
}

.tzbc .pulse__mid {
  stroke: var(--line-1);
}

.tzbc .pulse__now {
  fill: var(--live);
}

.tzbc .pulse__hit {
  fill: transparent;
  cursor: crosshair;
}

.tzbc .pulse__band {
  fill: rgba(var(--wash-rgb), 0.045);
}

.tzbc .pulse__bracket {
  fill: none;
  stroke: rgba(var(--wash-rgb), 0.65);
  stroke-width: 1;
}

.tzbc .pulse .tip {
  min-width: 200px;
}

/* Aura's buy/sell markers (chart-variants.js drawMarks): below the line for
   a buy, above it for a sell. */
.tzbc .vc-aura__mark {
  stroke: var(--surface-1);
  stroke-width: 1.5;
  paint-order: stroke;
}
.tzbc .vc-aura__mark.is-buy { fill: var(--pos); }
.tzbc .vc-aura__mark.is-sell { fill: var(--neg); }


/* ============ battle.css ============ */
/* ==========================================================================
   BattleCharts — battle detail page
   ========================================================================== */

/* The first viewport is the chart: header + panel fill exactly one screen. */
.tzbc .fold {
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-height: calc(100svh - var(--nav-h));
  padding-block: 18px 22px;
}

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

.tzbc .bhead {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px 32px;
}

.tzbc .back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 14px;
  font: 500 13px/1 var(--font-sans);
  color: var(--ink-3);
  transition: color 0.15s;
}

.tzbc .back svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.3s var(--ease-out);
}

.tzbc .back:hover {
  color: var(--ink-1);
}

.tzbc .back:hover svg {
  transform: translateX(-3px);
}

.tzbc .bhead__title {
  display: flex;
  align-items: center;
  gap: 16px;
}

.tzbc .bhead h1 {
  display: flex;
  align-items: baseline;
  gap: 14px;
  font: 500 clamp(26px, 3vw, 36px)/1 var(--font-sans);
  letter-spacing: -0.03em;
  color: var(--ink-1);
  /* No `view-transition-name` — see the note in pages/arena.js. The card's
     title used to morph into this one on navigation; the zoom was removed
     at the user's request, and a name here with no partner on the arena
     side would animate as an element entering rather than do nothing. */
}

.tzbc .bhead h1 small {
  font: 500 12px/1 var(--font-mono);
  letter-spacing: 0.12em;
  color: var(--ink-3);
  /* The battle code beside a long name wrapped as "B-" / "0001". */
  white-space: nowrap;
}

.tzbc .bhead__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-top: 9px;
  font: 500 10.5px/1.2 var(--font-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* The admin's description (2026-10-26): a sentence under the meta labels. */
.tzbc .bhead__desc {
  margin-top: 10px;
  max-width: 72ch;
  font: 400 14px/1.5 var(--font-sans);
  color: var(--ink-2);
}

.tzbc .bhead__meta span + span::before {
  content: "\00b7";
  margin-inline-end: 14px;
  color: var(--ink-4);
}

.tzbc .bhead__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 18px;
}

.tzbc .bhead__badges {
  display: flex;
  gap: 8px;
}

.tzbc .params {
  display: flex;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-md);
  background: var(--surface-1);
}

.tzbc .param {
  min-width: 128px;
  padding: 11px 18px 12px;
  border-inline-start: 1px solid var(--line-1);
}

.tzbc .param:first-child {
  border-inline-start: 0;
}

.tzbc .param dt {
  font: 500 9.5px/1.2 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .param dd {
  margin-top: 7px;
  font: 500 16px/1 var(--font-mono);
  letter-spacing: -0.01em;
  color: var(--ink-1);
  white-space: nowrap;
}

.tzbc .param dd small {
  margin-inline-start: 6px;
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--ink-3);
}

/* ----------------------------------------------------------- chart panel */

.tzbc .chartpanel {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 640px;
  /* No `view-transition-name` — see `.bhead h1` above and the note in
     pages/arena.js. This was the other half of the card-to-panel zoom. */
}

.tzbc .chartpanel:fullscreen {
  min-height: 0;
  border-radius: 0;
  background: var(--surface-1);
}

.tzbc .chartpanel:fullscreen .kbar,
.tzbc .chartpanel:fullscreen .viewbar,
.tzbc .chartpanel:fullscreen .toolbar {
  background: var(--surface-1);
}

/* Metric tabs are rounded cards in a padded bar; the selected one is lifted and outlined. */
.tzbc .kbar {
  display: flex;
  align-items: stretch;
  gap: 8px;
  padding: 8px;
  border-bottom: 1px solid var(--line-1);
}

.tzbc .ktabs {
  flex: 1;
  display: flex;
  gap: 8px;
}

/* Each tab is an outlined card that reads as one option of a choice; the radio dot
   beside its label says which is picked, so selection never rests on fill alone. */
.tzbc .ktab {
  position: relative;
  flex: 1 1 0;
  max-width: 320px;
  display: grid;
  align-content: start;
  gap: 9px;
  min-width: 220px;
  padding: 12px 16px 11px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-md);
  text-align: start;
  transition: background-color 0.2s, border-color 0.2s;
}

.tzbc .ktab .eyebrow {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* radio: ring when unpicked, ring + inner dot when picked */
.tzbc .ktab .eyebrow::before {
  content: "";
  flex: none;
  width: 11px;
  height: 11px;
  border: 1px solid var(--ink-4);
  border-radius: 50%;
  transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
}

.tzbc .ktab:hover {
  border-color: var(--line-3);
  background: var(--surface-2);
}

.tzbc .ktab:hover .eyebrow {
  color: var(--ink-2);
}

.tzbc .ktab:hover .eyebrow::before {
  border-color: var(--ink-2);
}

.tzbc .ktab[aria-selected="true"] {
  border-color: var(--ink-3);
  background: var(--surface-2);
}

.tzbc .ktab[aria-selected="true"] .eyebrow {
  color: var(--ink-1);
}

.tzbc .ktab[aria-selected="true"] .eyebrow::before {
  border-color: var(--ink-1);
  background: var(--ink-1);
  box-shadow: inset 0 0 0 2px var(--surface-2);
}

.tzbc .ktab__value {
  font: 300 34px/1 var(--font-sans);
  letter-spacing: -0.03em;
  color: var(--ink-1);
  white-space: nowrap;
}

.tzbc .ktab__foot {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 22px;
  font: 500 10.5px/1 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}

.tzbc .ktab__foot b {
  font-weight: 500;
  color: var(--ink-1);
}

.tzbc .kstats {
  display: flex;
  margin-inline-start: auto;
}

.tzbc .kstat {
  display: grid;
  align-content: center;
  gap: 9px;
  min-width: 132px;
  padding: 6px 22px;
  border-inline-start: 1px solid var(--line-1);
}

.tzbc .kstat dt {
  font: 500 9.5px/1.2 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .kstat dd {
  font: 500 17px/1 var(--font-mono);
  letter-spacing: -0.01em;
  color: var(--ink-1);
  white-space: nowrap;
}

.tzbc .toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 20px 4px;
}

.tzbc .toolbar__right {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.tzbc .legend {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.tzbc .chip {
  --c: var(--ink-3);
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 36px;
  padding: 0 15px 0 6px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-pill);
  background: var(--surface-1);
  font: 500 12.5px/1 var(--font-sans);
  letter-spacing: 0.02em;
  color: var(--ink-1);
  transition: border-color 0.2s, background-color 0.2s, color 0.2s;
}

.tzbc .chip:hover {
  border-color: var(--line-3);
  background: var(--surface-2);
}

.tzbc .chip .avatar {
  --size: 22px;
  transition: filter 0.2s, opacity 0.2s;
}

.tzbc .chip__key {
  width: 22px;
  display: grid;
  place-items: center;
}

.tzbc .chip__key::before {
  content: "";
  width: 16px;
  height: 2px;
  border-radius: 1px;
  background: var(--bench);
}

.tzbc .chip[aria-pressed="false"] {
  color: var(--ink-3);
  border-style: dashed;
}

.tzbc .chip[aria-pressed="false"] .avatar {
  filter: grayscale(1);
  opacity: 0.4;
}

.tzbc .chip[aria-pressed="false"] .chip__key::before {
  opacity: 0.35;
}

.tzbc .chip.is-focus {
  border-color: var(--c);
  background: color-mix(in srgb, var(--c) 10%, var(--surface-1));
}

.tzbc .chip__sep {
  width: 1px;
  height: 22px;
  margin: 6px 4px;
  background: var(--line-2);
}

.tzbc .legend--small .chip {
  height: 32px;
  padding: 0 13px 0 6px;
}

.tzbc .legend--small .chip .avatar {
  --size: 18px;
}

.tzbc .chartbox {
  position: relative;
  flex: 1;
  min-height: 380px;
}

/* The left inset keeps the y figures off the panel's edge. Measured rather
   than guessed: at inset 0 the axis labels landed 1–5px from the border and
   the START pill sat flush against it on a wide screen. (user: "numbers
   should not touch the border".) A phone needs none of this — there the
   figures sit inside the plot, already clear of the edge. */
.tzbc .chartbox > .rc,
.tzbc .chartbox > .vc {
  position: absolute;
  inset: 10px 6px 0 10px;
  width: auto;
  height: auto;
}

/* ── THE RACE TAB'S ORIGINAL LOOK (embedded build, 2026-10-17) ──────────
   (user: "for the first one i want the old, initial chart that we had",
   with a screenshot of the original project; asked what to bring back, they
   chose the original look, with the AI bots and forex prices kept.)

   So with the Race design showing, the panel goes back to the original's
   pure black, and the chart itself to its Geist type with upper-case names
   on the line-end labels.

   ── THE BLACK PANEL IS EVERY DESIGN'S NOW (user, 2026-10-24: "black
      container looks good, so keep the conteinar black for all the
      charts") ───────────────────────────────────────────────────────────

   It was scoped to `[data-view="race"]`, so switching to Aura, Signal,
   Pulse or Contour dropped the panel back to the app's card colour
   (#0a0b10) and the container visibly changed under the reader on every
   switch. The surfaces now belong to `.chartpanel` itself.

   ONLY THE SURFACES MOVED. The Geist type and the upper-case names below
   are still the Race design's alone — they are its "original look", not
   the panel's, and nothing asked for them elsewhere.

   Everything in the chart that paints with `--surface-1` follows this on
   purpose: the hollow sell markers, Pulse's brush shades and the 2px ring
   that separates each logo from its line are all meant to read as "the
   panel showing through", so they track the panel rather than staying
   card-coloured on a black ground. */
.tzbc .chartpanel {
  --surface-1: #000000;
  --surface-2: #0e0e0e;
  --surface-3: #161616;
}

/* THE SAME GESTURE, MIRRORED (light mode, 2026-10-19).

   The override above is not "make it black" — it is "step this one panel
   away from the app's card colour, toward the extreme", which is what gave
   the Race design back its original look. Leaving it unscoped by theme
   would stamp a pure-black slab onto a cream page, which is the single
   loudest thing a half-done light mode does.

   So light steps toward ITS extreme instead: the panel is pure white and
   its raised steps are cooler and cleaner than the page's warm cream ramp,
   so the panel still separates from everything around it.

   Every design, for the same reason as the dark rule above — a panel that
   changed colour on a view switch in one theme only would be a fresh copy
   of the bug that rule just fixed. */
.tzbc[data-theme="light"] .chartpanel {
  --surface-1: #FFFFFF;
  --surface-2: #FBF9F5;
  --surface-3: #F3F0E9;
}

.tzbc .chartpanel[data-view="race"] .rc {
  --font-sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo, Consolas, monospace;
}

.tzbc .chartpanel[data-view="race"] .rc-tip__nm {
  text-transform: uppercase;
}

/* ── VIEW TABS (embedded build, 2026-10-17) ──────────────────────────
   Six views of the chart (ui/chart-variants.js): a .seg of tabs, each with
   a small drawing of its view, and a line on what the picked one shows. */
.tzbc .viewbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  padding: 14px 20px 0;
}

.tzbc .viewtab {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.tzbc .viewtab__icon {
  flex: none;
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.7;
  transition: opacity 0.15s;
}

.tzbc .viewtab:hover .viewtab__icon,
.tzbc .viewtab[aria-selected="true"] .viewtab__icon {
  opacity: 1;
}

/* ── NO BORDER INSIDE A BORDER (embedded build, 2026-10-18) ─────────────
   (user: "try not to put border inside border".)

   The panel already draws the only line this area needs. Anything sitting
   inside it — the metric cards, the segmented groups, the chart's own wells
   — says "I am a group" with a fill instead, so the eye counts one frame
   rather than three nested ones. Segmented groups OUTSIDE a panel (the
   arena's filters) keep their outline: there it is the only thing defining
   them. */
.tzbc .chartpanel .ktab {
  border-color: transparent;
}

.tzbc .chartpanel .ktab:hover,
.tzbc .chartpanel .ktab[aria-selected="true"] {
  border-color: transparent;
  background: rgba(var(--wash-rgb), 0.05);
}

.tzbc .panel .seg {
  border-color: transparent;
  background: rgba(var(--wash-rgb), 0.04);
}

/* ── THE SERIES PANEL (embedded build, 2026-10-18) ──────────────────────
   Everything that used to crowd the toolbar — the five bot chips, buy &
   hold, the Trades toggle — now lives in a panel under its own button. */
.tzbc .toolbar {
  position: relative;
  justify-content: flex-start;
  gap: 8px;
}

.tzbc .toolbar__right {
  margin-inline-start: auto;
}

.tzbc .seriesbtn,
.tzbc .zoomchip {
  gap: 8px;
}

/* The zoom chip states what the chart is showing and undoes it. */
.tzbc .zoomchip {
  border-color: var(--ink-3);
  color: var(--ink-1);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.tzbc .zoomchip::before {
  display: none;
}

.tzbc .zoomchip svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
}

/* (The pan cursors live with the other chart cursors, in chart.css.) */

/* The toggle's square indicator is for on/off; this button opens a panel. */
.tzbc .seriesbtn::before {
  display: none;
}

.tzbc .seriesbtn svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}

.tzbc .seriesbtn__count {
  min-width: 18px;
  padding: 2px 6px;
  border-radius: var(--radius-pill);
  background: rgba(var(--wash-rgb), 0.08);
  font: 500 10.5px/1.3 var(--font-mono);
  color: var(--ink-2);
}

.tzbc .seriesbtn.is-filtered {
  border-color: var(--ink-3);
  color: var(--ink-1);
}

.tzbc .seriesbtn.is-filtered .seriesbtn__count {
  background: var(--ink-1);
  color: var(--page);
}

.tzbc .seriespanel {
  position: absolute;
  z-index: 30;
  top: calc(100% + 6px);
  inset-inline-end: 0;
  width: min(330px, calc(100vw - 32px));
  /* Capped and scrollable: on a phone the full list ran off the bottom of
     the screen, so the last bots were unreachable without scrolling the page
     behind the panel. */
  max-height: min(62vh, 440px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 12px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-md);
  background: var(--surface-2);
  box-shadow: 0 26px 60px -20px var(--shadow-col);
}

.tzbc .seriespanel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

/* Inside the panel nothing draws its own outline — see the note above. */
.tzbc .seriespanel__head .linkbtn {
  height: 26px;
  padding: 0 10px;
  border-color: transparent;
  background: rgba(var(--wash-rgb), 0.06);
  font-size: 11.5px;
}

.tzbc .seriespanel__head .linkbtn:hover {
  background: rgba(var(--wash-rgb), 0.12);
}

.tzbc .seriespanel .legend {
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
}

/* In a column each chip is a full-width row, so the names line up. */
.tzbc .seriespanel .chip {
  justify-content: flex-start;
  width: 100%;
  height: 34px;
  border-color: transparent;
  background: none;
}

.tzbc .seriespanel .chip:hover {
  background: rgba(var(--wash-rgb), 0.05);
}

/* A hidden bot reads as hidden by its greyed logo and dimmed name (the base
   .chip rules), so it needs no dashed outline on top of that. */
.tzbc .seriespanel .chip[aria-pressed="false"] {
  border-color: transparent;
}

.tzbc .seriespanel .chip__sep {
  width: auto;
  height: 1px;
  margin: 6px 2px;
}

.tzbc .seriespanel__foot {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line-1);
}

.tzbc .seriespanel__foot .toggle {
  width: 100%;
  justify-content: flex-start;
  border-color: transparent;
  background: none;
}

.tzbc .seriespanel__foot .toggle:hover {
  border-color: transparent;
  background: rgba(var(--wash-rgb), 0.05);
}

/* A view that has no use for a control disables it (applyView in battle.js). */
.tzbc .chip:disabled,
.tzbc .toggle:disabled {
  opacity: 0.38;
  cursor: not-allowed;
}

.tzbc .chip:disabled:hover,
.tzbc .toggle:disabled:hover {
  border-color: var(--line-2);
  background: var(--surface-1);
}

.tzbc .toggle:disabled:hover {
  color: var(--ink-3);
}

.tzbc .toggle[aria-pressed="true"]:disabled:hover {
  color: var(--ink-1);
}

/* The metric tabs stay as read-outs under a view with its own measure, but
   drop the picked look, since picking one would change nothing. */
.tzbc .chartpanel.is-metric-fixed .ktab {
  cursor: default;
}

.tzbc .chartpanel.is-metric-fixed .ktab:hover,
.tzbc .chartpanel.is-metric-fixed .ktab[aria-selected="true"] {
  border-color: transparent;
  background: none;
}

.tzbc .chartpanel.is-metric-fixed .ktab .eyebrow,
.tzbc .chartpanel.is-metric-fixed .ktab:hover .eyebrow {
  color: var(--ink-3);
}

.tzbc .chartpanel.is-metric-fixed .ktab .eyebrow::before {
  visibility: hidden;
}

/* (.chartnote and its kbd styling went with the hint list — see battle.html.) */

/* ------------------------------------------------------------ leaderboard */

.tzbc .lb {
  margin-top: 8px;
}

.tzbc .lb__title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 16px;
}

.tzbc .lb__table td {
  height: 60px;
}

.tzbc .lb__table tbody tr {
  position: relative;
}

.tzbc .lb__table tbody tr.is-first {
  background: var(--surface-2);
}

.tzbc .lb__table tbody tr.is-hover,
.tzbc .lb__table tbody tr:hover {
  background: rgba(var(--wash-rgb), 0.035);
}

.tzbc .lb__table tbody tr.is-focus td:first-child {
  box-shadow: inset 2px 0 0 var(--c);
}

.tzbc .lb__table td.is-sorted {
  color: var(--ink-1);
}

.tzbc .lb__table td.is-sorted.is-pos { color: var(--pos); }
.tzbc .lb__table td.is-sorted.is-neg { color: var(--neg); }

.tzbc .lb__rank {
  width: 76px;
}

.tzbc .lb__rankno {
  font: 500 13px/1 var(--font-mono);
  color: var(--ink-3);
}

.tzbc tr.is-first .lb__rankno {
  color: var(--ink-1);
}

.tzbc .lb__rankchg {
  margin-inline-start: 7px;
  font-size: 9.5px;
}

.tzbc .lb__bot {
  display: inline-flex;
  align-items: center;
  gap: 13px;
  text-align: start;
}

.tzbc .lb__botname {
  display: grid;
  gap: 4px;
}

.tzbc .lb__botname b {
  font: 600 12.5px/1 var(--font-mono);
  letter-spacing: 0.1em;
  color: var(--ink-1);
}

.tzbc .lb__botname small {
  font: 400 12px/1 var(--font-sans);
  color: var(--ink-3);
}

.tzbc .lb__bot:hover b {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.tzbc .lb__trend {
  width: 120px;
}

.tzbc .lb__trend .spark {
  margin-inline-start: auto;
}

@keyframes flash-up {
  from { background-color: rgba(var(--pos-rgb), 0.22); }
  to { background-color: transparent; }
}

@keyframes flash-down {
  from { background-color: rgba(var(--neg-rgb), 0.2); }
  to { background-color: transparent; }
}

.tzbc td.flash-up { animation: flash-up 1.3s ease-out; }
.tzbc td.flash-down { animation: flash-down 1.3s ease-out; }

/* ------------------------------------------------------------------ info */

.tzbc .info {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: 20px;
  margin-top: 20px;
}

.tzbc .info > * {
  min-width: 0;
}

.tzbc .brief__list {
  display: grid;
  grid-template-columns: auto 1fr;
}

.tzbc .brief__list dt,
.tzbc .brief__list dd {
  padding: 11px 20px;
  border-bottom: 1px solid var(--line-1);
}

.tzbc .brief__list dt {
  font: 500 10px/1.4 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .brief__list dd {
  font: 500 12.5px/1.4 var(--font-mono);
  text-align: end;
  color: var(--ink-1);
  font-variant-numeric: tabular-nums;
}

.tzbc .brief__list dt:nth-last-of-type(1),
.tzbc .brief__list dd:nth-last-of-type(1) {
  border-bottom: 0;
}

.tzbc .market {
  display: flex;
  flex-direction: column;
}

.tzbc .market__body {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.tzbc .market__chart {
  position: relative;
  flex: 1;
  min-height: 250px;
  margin: 12px 8px 0 0;
}

.tzbc .market__stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-top: 1px solid var(--line-1);
}

.tzbc .mstat {
  padding: 14px 20px;
  border-inline-start: 1px solid var(--line-1);
}

.tzbc .mstat:nth-child(4n + 1) {
  border-inline-start: 0;
}

.tzbc .mstat:nth-child(n + 5) {
  border-top: 1px solid var(--line-1);
}

.tzbc .mstat dt {
  font: 500 9.5px/1.2 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .mstat dd {
  margin-top: 8px;
  font: 500 14px/1 var(--font-mono);
  color: var(--ink-1);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* --------------------------------------------------------------- dossiers */

.tzbc .dossiers,
.tzbc .tradelog {
  grid-column: 1 / -1;
}

/* Explicit column counts so the five bots never leave a single orphan on its own row. */
.tzbc .dossiers__grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px;
  padding: 14px;
}

@media (max-width: 1280px) {
  .tzbc .dossiers__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 900px) {
  .tzbc .dossiers__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 600px) {
  .tzbc .dossiers__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

.tzbc .dossier {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 22px 20px 20px;
  border: 1px solid var(--line-1);
  border-radius: var(--radius-md);
  background: var(--surface-2);
}

.tzbc .dossier__head {
  display: flex;
  align-items: center;
  gap: 13px;
}

.tzbc .dossier__name {
  display: grid;
  gap: 5px;
}

.tzbc .dossier__name b {
  font: 600 14px/1 var(--font-mono);
  letter-spacing: 0.12em;
  color: var(--ink-1);
}

.tzbc .dossier__name small {
  font: 400 12px/1 var(--font-sans);
  color: var(--ink-3);
}

.tzbc .dossier__place {
  margin-inline-start: auto;
  font: 300 30px/1 var(--font-sans);
  letter-spacing: -0.03em;
  color: var(--ink-3);
}

.tzbc .dossier__place.is-first {
  color: var(--ink-1);
}

.tzbc .dossier__tagline {
  font: 400 14px/1.45 var(--font-sans);
  color: var(--ink-2);
}

.tzbc .dossier__rules {
  display: grid;
  gap: 10px;
}

.tzbc .dossier__rules div {
  display: grid;
  gap: 3px;
}

.tzbc .dossier__rules dt {
  font: 500 9.5px/1.2 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .dossier__rules dd {
  font: 400 12.5px/1.45 var(--font-sans);
  color: var(--ink-2);
}

.tzbc .dossier__stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 14px;
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--line-1);
}

.tzbc .dossier__stats dt {
  font: 500 9.5px/1.2 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .dossier__stats dd {
  margin-top: 5px;
  font: 500 13px/1 var(--font-mono);
  color: var(--ink-1);
  font-variant-numeric: tabular-nums;
}

.tzbc .dossier__focus {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font: 500 12.5px/1 var(--font-sans);
  color: var(--ink-3);
  transition: color 0.15s;
}

.tzbc .dossier__focus:hover {
  color: var(--ink-1);
}

.tzbc .dossier__focus svg {
  width: 13px;
  height: 13px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transform: rotate(-90deg);
}

/* -------------------------------------------------------------- trade log */

.tzbc .tradelog__filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.tzbc .tradelog__table td {
  padding-block: 11px;
}

.tzbc .tlbot {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--ink-1);
  letter-spacing: 0.08em;
}

.tzbc .tlbot .avatar {
  --size: 18px;
}

.tzbc .side {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--ink-1);
}

.tzbc .side::before {
  content: "";
  width: 0;
  height: 0;
  border-inline-start: 4.5px solid transparent;
  border-inline-end: 4.5px solid transparent;
  border-bottom: 7px solid var(--ink-1);
}

.tzbc .side--sell {
  color: var(--ink-2);
}

.tzbc .side--sell::before {
  border-bottom: 0;
  border-top: 7px solid var(--ink-2);
}

.tzbc .signal {
  color: var(--ink-3);
  letter-spacing: 0.06em;
}

.tzbc .tradelog__table tr.is-new {
  animation: newrow 2.4s var(--ease-out);
}

@keyframes newrow {
  from { background-color: rgba(var(--wash-rgb), 0.09); }
  to { background-color: transparent; }
}

.tzbc .tradelog__more {
  display: flex;
  justify-content: center;
  padding: 18px;
}

.tzbc .tradelog__more[hidden] {
  display: none;
}

.tzbc .tradelog__empty td {
  padding: 40px 16px;
  text-align: center;
  color: var(--ink-3);
}

/* ------------------------------------------------------------- responsive */

@media (max-width: 1280px) {
  .tzbc .kstats {
    display: none;
  }
}

@media (max-width: 1100px) {
  .tzbc .info {
    grid-template-columns: minmax(0, 1fr);
  }

  .tzbc .params {
    flex-wrap: wrap;
  }
}

@media (max-width: 760px) {
  .tzbc .fold {
    min-height: 0;
  }

  .tzbc .chartpanel {
    min-height: 0;
  }

  .tzbc .chartbox {
    flex: none;
    height: 420px;
    min-height: 0;
  }

  /* ── PHONE CHART ROOM (embedded build, 2026-10-18) ─────────────────
     (user: "mobile view of battle charts is not correct, fix the
     responsiveness" / "the main large chart does not looks right".)

     The controls above the plot had grown to ~470px on a 390px-wide
     screen — taller than the chart itself — because the legend wrapped
     to three rows of 36px chips and the hint list added four more rows
     under it. The chart was the thing being squeezed, so the chrome
     around it is tightened and the plot gets the space back. */
  /* Taller, and the plot runs nearer the panel's edges: with the figures
     inside it and no activity strip, every pixel here is line. */
  .tzbc .chartbox {
    height: min(540px, 62vh);
  }

  /* The left inset stays until 480px, where the chart moves its figures
     inside the plot — below that it is the one giving them their clearance,
     and this breakpoint must not take it away early. */
  .tzbc .chartbox > .rc,
  .tzbc .chartbox > .vc {
    inset: 6px 2px 0 10px;
  }

  /* A narrower page gutter gives the chart ~12px more to draw in. */
  .tzbc .page-battle .wrap {
    padding-inline: 10px;
  }

  .tzbc .toolbar,
  .tzbc .viewbar,
  .tzbc .kbar {
    padding-inline: 12px;
  }

  .tzbc .toolbar {
    gap: 8px;
    padding-top: 10px;
  }

  .tzbc .toolbar__right {
    gap: 6px;
  }

  /* The chips live in the Series panel now, so they only need to fit it. */
  .tzbc .seriespanel {
    inset-inline-end: auto;
    inset-inline-start: 0;
    width: calc(100vw - 28px);
  }

  .tzbc .seriespanel .chip .avatar {
    --size: 20px;
  }

  /* The tabs name the view clearly enough without a heading over them. */
  .tzbc .viewbar {
    padding-top: 10px;
  }

  .tzbc #views-label {
    display: none;
  }

  .tzbc .ktabs {
    width: 100%;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .tzbc .ktab {
    flex: 0 0 auto;
    min-width: 236px;
    padding: 14px 16px;
  }

  .tzbc .ktab__value {
    font-size: 26px;
  }

  .tzbc .params {
    width: 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
  }

  .tzbc .param {
    border-inline-start: 0;
    border-top: 1px solid var(--line-1);
  }

  .tzbc .param:nth-child(even) {
    border-inline-start: 1px solid var(--line-1);
  }

  .tzbc .param:nth-child(-n + 2) {
    border-top: 0;
  }

  .tzbc .toolbar {
    padding-inline: 14px;
  }

  .tzbc .market__stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .tzbc .mstat:nth-child(odd) {
    border-inline-start: 0;
  }

  .tzbc .mstat:nth-child(n + 3) {
    border-top: 1px solid var(--line-1);
  }

  .tzbc #btn-full {
    display: none;
  }

  /* Six view tabs don't fit one row on a phone: two rows of three, names only. */
  .tzbc .viewtabs {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    width: 100%;
  }

  .tzbc .viewtab {
    justify-content: center;
    padding-inline: 6px;
  }

  .tzbc .viewtab__icon {
    display: none;
  }
}

/* Below 480px the chart draws its y figures inside the plot (see race-chart
   layout's `narrow`), so the panel gutter the wider layouts need is dead
   space here — the lines take it instead. */
@media (max-width: 480px) {
  .tzbc .chartbox > .rc,
  .tzbc .chartbox > .vc {
    inset: 6px 2px 0 0;
  }
}

/* ==========================================================================
   ONE SCREEN, TWO VIEWS (2026-10-27)
   (user: "show all the content in one screen within the view port itself".)
   The page is exactly one viewport tall and never scrolls: a one-line
   header, then either the overview (Chart | Table) or one model's trades.
   Only the tables scroll, inside their own panels. Plan:
   new-task/2026-10-27-battle-page-drilldown/PLAN.md (workspace root).
   Rules above that style the removed sections no longer match anything.
   ========================================================================== */

.tzbc .bp {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: var(--maxw);
  height: 100dvh;
  margin-inline: auto;
  padding: 28px var(--gutter) 16px;
  overflow: hidden;
}

.tzbc .bp-view {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}

.tzbc .bp-view[hidden],
.tzbc .bp-panel[hidden] {
  display: none;
}

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

.tzbc .bp-head .back {
  margin-bottom: 20px;
}

.tzbc .bp-head__row {
  display: flex;
  align-items: center;
  gap: 16px;
  min-width: 0;
}

.tzbc .bp-head__text {
  min-width: 0;
}

.tzbc .bp-head__title {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
}

.tzbc .bp-head__title h1 {
  font: 600 26px/1.15 var(--font-sans);
  letter-spacing: -0.02em;
  color: var(--ink-1);
}

.tzbc .bp-head__desc {
  max-width: 760px;
  margin-top: 8px;
  font: 400 13.5px/1.5 var(--font-sans);
  color: var(--ink-2);
}

.tzbc .bp-head__style {
  max-width: 760px;
  margin-top: 8px;
  font: 400 13.5px/1.5 var(--font-sans);
  color: var(--ink-2);
}

.tzbc .bp-head__style b {
  margin-inline-end: 6px;
  font-weight: 600;
  color: var(--ink-1);
}

/* The battle's terms in one row of labelled figures, split by hairlines. */
.tzbc .bp-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 0;
  margin-top: 22px;
  padding-block: 16px;
  border-block: 1px solid var(--line-1);
}

/* The rule sits AFTER each figure, so a figure that wraps onto a new row
   starts it clean instead of behind a stray hairline. */
.tzbc .bp-facts > div {
  margin-inline-end: 16px;
  padding-inline-end: 16px;
  border-inline-end: 1px solid var(--line-2);
}

.tzbc .bp-facts > div:last-child {
  margin-inline-end: 0;
  padding-inline-end: 0;
  border-inline-end: 0;
}

.tzbc .bp-facts dt {
  font: 600 9.5px/1 var(--font-sans);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .bp-facts dd {
  margin-top: 6px;
  font: 600 14px/1.2 var(--font-sans);
  color: var(--ink-1);
  white-space: nowrap;
}

.tzbc .bp-facts dd small {
  margin-inline-start: 6px;
  font: 400 12px/1 var(--font-sans);
  color: var(--ink-3);
}

/* ------------------------------------------------------------ view bars */

.tzbc .bp-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  margin: 18px 0 12px;
}

.tzbc .bp-bar__hint {
  margin-inline-start: auto;
  font: 400 12.5px/1.3 var(--font-sans);
  color: var(--ink-3);
}

/* ---------------------------------------------------------------- panels */

.tzbc .bp-panel {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

/* The chart panel had a 640px floor and the chart box 380px (and fixed
   heights on a phone); here they take whatever the viewport leaves. */
.tzbc .bp .chartpanel {
  min-height: 0;
}

.tzbc .bp .chartbox {
  flex: 1;
  height: auto;
  min-height: 0;
}

.tzbc .bp-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 10px 12px;
  border-top: 1px solid var(--line-1);
}

.tzbc .bp-chip {
  height: 32px;
  padding-inline-end: 12px;
  cursor: pointer;
}

.tzbc .bp-chip b {
  font: 600 11.5px/1 var(--font-mono);
}

.tzbc .bp-chip.is-hover {
  border-color: var(--c);
}

.tzbc .bp-chip b.is-pos { color: var(--pos); }
.tzbc .bp-chip b.is-neg { color: var(--neg); }

/* ---------------------------------------------------------------- tables */

.tzbc .bp-scroll {
  flex: 1;
  min-height: 0;
  overflow: auto;
  scrollbar-width: thin;
}

.tzbc .bp-table {
  min-width: 0;
}

.tzbc .bp-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface-1);
}

.tzbc #ov-rows tr {
  cursor: pointer;
}

.tzbc #ov-rows tr:hover,
.tzbc #ov-rows tr.is-hover,
.tzbc #ov-rows tr:focus-visible {
  background: rgba(var(--wash-rgb), 0.05);
  outline: none;
}

.tzbc .bp-who {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-sans);
}

.tzbc .bp-who b {
  font-weight: 600;
  color: var(--ink-1);
}

/* Rank on a ring; gold, silver and bronze for the top three. */
.tzbc .bp-rank {
  --m: var(--line-3);
  display: inline-grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border: 1.5px solid var(--m);
  border-radius: 50%;
  font: 700 11px/1 var(--font-sans);
  color: var(--ink-1);
}

.tzbc .bp-trend svg {
  display: block;
  margin-inline-start: auto;
}

.tzbc .bp-go svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tzbc #ov-rows tr:hover .bp-go svg {
  stroke: var(--ink-1);
}

/* Open column: what a model holds right now, its open P&L under it. */
.tzbc .bp-holding {
  display: inline-grid;
  gap: 4px;
  white-space: nowrap;
}

.tzbc .bp-holding small {
  font-size: 11px;
}

.tzbc .bp-holding small.is-pos { color: var(--pos); }
.tzbc .bp-holding small.is-neg { color: var(--neg); }

.tzbc .bp-flat {
  color: var(--ink-3);
}

/* Model view: open positions, above the trades. Sized to its rows (up to
   about four before it scrolls) so the trades keep the rest. */
.tzbc .bp-openpanel {
  flex: 0 0 auto;
  max-height: 34%;
  margin-bottom: 10px;
}

.tzbc .bp-openpanel__title {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0;
  padding: 12px 16px 4px;
  font: 600 12px/1.2 var(--font-sans);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.tzbc .bp-openpanel__title small {
  font: 500 12px/1 var(--font-mono);
  letter-spacing: 0;
  text-transform: none;
}

.tzbc .bp-openpanel__title small.is-pos { color: var(--pos); }
.tzbc .bp-openpanel__title small.is-neg { color: var(--neg); }

.tzbc .bp-openpanel__more {
  margin: 0;
  padding: 6px 16px 10px;
  font: 400 12px/1.3 var(--font-sans);
  color: var(--ink-3);
}

.tzbc .bp-empty td {
  padding: 32px 16px;
  text-align: center;
  font-family: var(--font-sans);
  color: var(--ink-3);
}

/* ----------------------------------------------------------- model view */

.tzbc .back--btn {
  margin-bottom: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.tzbc .bp-bar--model {
  gap: 10px 20px;
}

.tzbc .bp-model {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
}

.tzbc .bp-model h2 {
  font: 600 20px/1.1 var(--font-sans);
  letter-spacing: -0.02em;
  color: var(--ink-1);
}

.tzbc .bp-model__stats {
  display: flex;
  gap: 20px;
  margin-inline-start: 8px;
}

.tzbc .bp-model__stats dt {
  font: 600 9.5px/1 var(--font-sans);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .bp-model__stats dd {
  margin-top: 5px;
  font: 600 14px/1 var(--font-mono);
  color: var(--ink-1);
}

.tzbc .bp-model__stats dd.is-pos { color: var(--pos); }
.tzbc .bp-model__stats dd.is-neg { color: var(--neg); }

/* The model's own line takes about a third of the height; its trades the
   rest. */
.tzbc .bp-panel--mini {
  flex: 0 0 34%;
  min-height: 150px;
  margin-bottom: 10px;
}

.tzbc .bp-time {
  color: var(--ink-1);
}

.tzbc .bp-whybtn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 10px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-pill);
  background: transparent;
  font: 500 12px/1 var(--font-sans);
  color: var(--ink-2);
  cursor: pointer;
  transition: border-color 0.15s, color 0.15s;
}

.tzbc .bp-whybtn svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tzbc .bp-whybtn:hover,
.tzbc .bp-whybtn:focus-visible {
  border-color: #f5c542;
  color: #f5c542;
  outline: none;
}

.tzbc[data-theme="light"] .bp-whybtn:hover,
.tzbc[data-theme="light"] .bp-whybtn:focus-visible {
  border-color: #a87a0c;
  color: #a87a0c;
}

.tzbc .bp-auto {
  font: 400 12px/1 var(--font-sans);
  color: var(--ink-3);
}

/* ------------------------------------------------------- reasoning drawer */

.tzbc .bp-scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(0, 0, 0, 0.5);
  animation: bp-fade 0.2s;
}

.tzbc[data-theme="light"] .bp-scrim {
  background: rgba(15, 15, 15, 0.22);
}

.tzbc .bp-why {
  position: fixed;
  top: 0;
  inset-inline-end: 0;
  bottom: 0;
  z-index: 41;
  display: flex;
  flex-direction: column;
  width: min(440px, 92vw);
  background: var(--surface-2);
  box-shadow: -24px 0 60px -20px var(--shadow-col), -1px 0 0 var(--line-2);
  animation: bp-slide 0.28s var(--ease-out);
}

.tzbc .bp-scrim[hidden],
.tzbc .bp-why[hidden] {
  display: none;
}

.tzbc .bp-why__head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 20px 20px 16px;
  border-bottom: 1px solid var(--line-1);
}

.tzbc .bp-why__head > div {
  flex: 1;
  min-width: 0;
}

.tzbc .bp-why__head h3 {
  font: 600 16px/1.25 var(--font-sans);
  color: var(--ink-1);
}

.tzbc .bp-why__sub {
  margin-top: 6px;
  font: 500 12px/1.3 var(--font-mono);
  color: var(--ink-3);
}

.tzbc .bp-why__body {
  flex: 1;
  overflow: auto;
  padding: 18px 20px 24px;
}

.tzbc .bp-why__text {
  margin-top: 10px;
  font: 400 14px/1.65 var(--font-sans);
  color: var(--ink-1);
  white-space: pre-wrap;
}

/* The decision log (openDecisions in pages/battle.js). */
.tzbc .bp-decbtn {
  margin-inline-start: auto;
}

.tzbc .bp-linkbtn {
  margin-inline-start: 8px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: #f5c542;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.tzbc[data-theme="light"] .bp-linkbtn {
  color: #a87a0c;
}

.tzbc .bp-rounds {
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}

.tzbc .bp-round {
  padding: 14px 0;
  border-top: 1px solid var(--line-1);
}

.tzbc .bp-round .bp-why__text {
  margin-top: 6px;
  font-size: 13.5px;
}

.tzbc .bp-round .eyebrow {
  display: flex;
  align-items: center;
  gap: 8px;
}

.tzbc .bp-round__tag {
  padding: 2px 6px;
  border-radius: 4px;
  background: rgba(245, 197, 66, 0.14);
  color: #f5c542;
  font-weight: 600;
  letter-spacing: 0.04em;
}

.tzbc .bp-round__tag.is-neg {
  background: color-mix(in srgb, var(--neg) 14%, transparent);
  color: var(--neg);
}

.tzbc[data-theme="light"] .bp-round__tag:not(.is-neg) {
  color: #a87a0c;
}

.tzbc .bp-rounds__more {
  margin-top: 8px;
}

.tzbc .bp-why__wait,
.tzbc .bp-why__none {
  font: 400 13px/1.5 var(--font-sans);
  color: var(--ink-3);
}

@keyframes bp-fade { from { opacity: 0; } }
@keyframes bp-slide { from { transform: translateX(24px); opacity: 0; } }
@keyframes bp-rise { from { transform: translateY(24px); opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .tzbc .bp-scrim,
  .tzbc .bp-why { animation: none; }
}

/* ----------------------------------------------------------------- phone */

@media (max-width: 760px) {
  .tzbc .bp {
    padding-inline: 12px;
  }

  .tzbc .bp-bar__hint,
  .tzbc .bp-col--wide {
    display: none;
  }

  /* One row that scrolls sideways, so the chart keeps its height. */
  .tzbc .bp-facts {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .tzbc .bp-facts::-webkit-scrollbar {
    display: none;
  }

  .tzbc .bp-facts > div {
    flex: none;
    margin-inline-end: 14px;
    padding-inline-end: 14px;
  }

  .tzbc .bp-head__desc,
  .tzbc .bp-head__style {
    font-size: 12.5px;
  }

  .tzbc .bp-model__stats {
    margin-inline-start: 0;
    gap: 16px;
  }

  .tzbc .bp-panel--mini {
    flex-basis: 28%;
    min-height: 120px;
  }

  .tzbc .bp-table th,
  .tzbc .bp-table td {
    padding-inline: 10px;
  }

  /* The drawer becomes a bottom sheet. */
  .tzbc .bp-why {
    top: auto;
    inset-inline-start: 0;
    width: 100%;
    max-height: 75dvh;
    border-radius: 18px 18px 0 0;
    box-shadow: 0 -24px 60px -20px var(--shadow-col), 0 -1px 0 var(--line-2);
    animation-name: bp-rise;
  }
}

/* A phone keeps time, side, lots, price and the reasoning button, which
   drops its word and keeps its icon. */
@media (max-width: 480px) {
  .tzbc .bp-col--mid,
  .tzbc .bp-whybtn__label {
    display: none;
  }

  .tzbc .bp-whybtn {
    padding: 0 8px;
  }

  /* Rank, model, P&L and what it holds fit a 390px phone. */
  .tzbc #ov-table th,
  .tzbc #ov-rows td {
    padding-inline: 7px;
  }

  .tzbc #ov-table th:first-child,
  .tzbc #ov-rows td:first-child {
    padding-inline-end: 2px;
  }

  .tzbc #ov-rows .bp-who {
    gap: 7px;
  }

  .tzbc .bp-holding .side {
    gap: 4px;
    letter-spacing: 0.02em;
  }

  /* "Battle closing", "Stop loss": two short lines rather than off-screen. */
  .tzbc .bp-trades td:last-child {
    white-space: normal;
    line-height: 1.25;
  }
}

/* -------------------------------------------------------------- trips */

/* ── OPEN POSITIONS | TRADE HISTORY (2026-11-04) ───────────────────────────
   The model view's trades as two tabs (battle.html #md-trips). The tab bar
   is the same segmented control as the overview's Chart | Table. */
.tzbc .bp-trips__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line-1);
}

.tzbc .bp-trips__total {
  margin-left: auto;
  font: 500 12px/1 var(--font-mono);
  color: var(--ink-3);
}

.tzbc .bp-trips__total.is-pos { color: var(--pos); }
.tzbc .bp-trips__total.is-neg { color: var(--neg); }

.tzbc .bp-trips .bp-scroll:focus-visible {
  outline-offset: -2px;
}

.tzbc .bp-trips__more {
  display: flex;
  justify-content: center;
  padding: 12px 16px 16px;
}

.tzbc .bp-trips__more:empty {
  display: none;
}

.tzbc .bp-trips__morebtn[aria-disabled="true"] {
  cursor: progress;
  opacity: 0.7;
}

/* Why a trade closed: a quiet pill, tinted only where the reason is itself
   the result (a target reached, a stop hit). */
.tzbc .bp-reasoncell {
  white-space: nowrap;
}

.tzbc .bp-reason {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 9px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-pill);
  font: 500 11px/1 var(--font-sans);
  color: var(--ink-2);
  vertical-align: middle;
}

.tzbc .bp-reason--take_profit {
  color: var(--chip-pos-ink);
  background: rgba(var(--pos-rgb), 0.12);
  border-color: rgba(var(--pos-rgb), 0.3);
}

.tzbc .bp-reason--stop_loss,
.tzbc .bp-reason--stop_out {
  color: var(--chip-neg-ink);
  background: rgba(var(--neg-rgb), 0.12);
  border-color: rgba(var(--neg-rgb), 0.3);
}

.tzbc .bp-reason--ai_close,
.tzbc .bp-reason--trailing_stop {
  color: var(--ink-1);
}

.tzbc .bp-reason--manual_close,
.tzbc .bp-reason--battle_ended,
.tzbc .bp-reason--none {
  color: var(--ink-3);
}

.tzbc .bp-reasoncell .bp-whybtn,
.tzbc .bp-reasoncell .bp-exitsbtn {
  margin-left: 6px;
  vertical-align: middle;
}

/* "2 exits": opens the trade's exits under it. */
.tzbc .bp-exitsbtn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 24px;
  padding: 0 8px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  font: 500 11px/1 var(--font-sans);
  color: var(--ink-3);
  transition: color 0.15s, border-color 0.15s;
}

.tzbc .bp-exitsbtn:hover,
.tzbc .bp-exitsbtn:focus-visible {
  color: var(--ink-1);
  border-color: var(--line-2);
}

.tzbc .bp-exitsbtn svg {
  width: 12px;
  height: 12px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 0.2s var(--ease-out);
}

.tzbc .bp-exitsbtn[aria-expanded="true"] svg {
  transform: rotate(180deg);
}

/* The exits and the entry fee: a recessed block under their trade. */
.tzbc .bp-trip.is-open td {
  border-bottom-color: transparent;
}

.tzbc .bp-exit td {
  padding-block: 8px;
  font-size: 11.5px;
  color: var(--ink-3);
  background: rgba(var(--wash-rgb), 0.025);
}

.tzbc .bp-exit td.is-pos { color: var(--pos); }
.tzbc .bp-exit td.is-neg { color: var(--neg); }

.tzbc .bp-exit__label {
  font-family: var(--font-sans);
}

.tzbc .bp-exit .bp-reason {
  height: 20px;
  font-size: 10.5px;
}

/* ---------------------------------------------------- inline skeletons */

/* Rows and lines the page builds while a section loads (2026-11-04): the
   history's first page and "Load more", the open tab's two new columns,
   and the reasoning drawer. Each sized to what it stands in for. */
.tzbc .bp-skelrow td {
  padding-block: 15px;
}

.tzbc .bp-skelrow .skel {
  width: 72%;
  max-width: 96px;
  margin-left: auto;
}

.tzbc .bp-skelrow td.is-left .skel {
  margin-left: 0;
}

.tzbc .bp-skelcell {
  display: inline-block;
  width: 64px;
  height: 11px;
  vertical-align: middle;
}

.tzbc .bp-why__skel {
  display: grid;
  gap: 10px;
}

.tzbc .bp-why__skel .skel {
  height: 13px;
}

.tzbc .bp-why__skel .bp-why__skel-eyebrow {
  width: 46%;
  height: 10px;
  margin-bottom: 4px;
}

.tzbc .bp-why__skel .bp-why__skel-short {
  width: 62%;
}

/* ------------------------------------------------------------ boot skeleton */

/* ── THE BATTLE PAGE'S SKELETON (2026-11-04) ───────────────────────────────
   The boot shell in battle.html, laid out with this page's own classes (bp,
   bp-head, bp-facts, bp-bar, panel), so only the blocks are sized here.
   Three bodies; `data-boot-view` on <html> (set in <head>) shows the one
   this page will open on, the chart when it is missing. */
.tzbc .bc-skel__view {
  display: none;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}

.tzbc[data-boot-view="chart"] .bc-skel__view[data-skel="chart"],
.tzbc:not([data-boot-view]) .bc-skel__view[data-skel="chart"],
.tzbc[data-boot-view="table"] .bc-skel__view[data-skel="table"],
.tzbc[data-boot-view="model"] .bc-skel__view[data-skel="model"] {
  display: flex;
}

.tzbc .bc-skel__back { width: 92px; height: 13px; margin-bottom: 20px; }
.tzbc .bc-skel__icon { flex: none; width: 40px; height: 40px; border-radius: 50%; }
.tzbc .bc-skel__h1 { width: min(340px, 56vw); height: 30px; border-radius: 8px; }
.tzbc .bc-skel__chip { width: 64px; height: 22px; border-radius: var(--radius-pill); }
.tzbc .bc-skel__line { width: min(420px, 80%); height: 13px; margin-top: 10px; }
.tzbc .bc-skel__dt { width: 60px; height: 9.5px; }
.tzbc .bc-skel__dd { width: 84px; height: 17px; margin-top: 6px; }
.tzbc .bc-skel__seg { width: 150px; height: 36px; border-radius: var(--radius-sm); }
.tzbc .bc-skel__seg--wide { width: min(290px, 100%); }
.tzbc .bc-skel__legend { width: 112px; height: 32px; border-radius: var(--radius-pill); }
.tzbc .bc-skel__stat { width: 64px; height: 28px; }

.tzbc .bc-skel__plot {
  display: flex;
  flex: 1;
  min-height: 0;
  padding: 16px;
}

.tzbc .bc-skel__plot .skel {
  flex: 1;
  height: auto;
  border-radius: 10px;
}

.tzbc .bc-skel__thead {
  padding: 12px 16px;
  border-bottom: 1px solid var(--line-2);
}

.tzbc .bc-skel__thead .skel {
  width: 60%;
  height: 10px;
}

/* A table row: 13px padding round a 26px avatar, as the real one. */
.tzbc .bc-skel__row {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 52px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--line-1);
}

.tzbc .bc-skel__rank { flex: none; width: 24px; height: 24px; border-radius: 50%; }
.tzbc .bc-skel__avatar { flex: none; width: 26px; height: 26px; border-radius: 50%; }
.tzbc .bc-skel__avatar--lg { width: 36px; height: 36px; }
.tzbc .bc-skel__name { flex: 0 1 140px; height: 13px; }
.tzbc .bc-skel__fig { flex: 0 1 80px; height: 13px; margin-left: auto; }


/* ============ arena.css ============ */
/* ==========================================================================
   BattleCharts — arena (battle list) page
   ========================================================================== */

/* ------------------------------------------------------------------ hero */

.tzbc .hero {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
  align-items: end;
  gap: 40px 64px;
  padding-block: clamp(36px, 5vw, 64px) 36px;
}

.tzbc .hero h1 {
  margin-top: 22px;
  font: 500 clamp(38px, 4.2vw, 64px)/1 var(--font-sans);
  letter-spacing: -0.045em;
  color: var(--ink-1);
  text-wrap: balance;
}

.tzbc .hero h1 span {
  display: block;
  color: var(--ink-3);
}

.tzbc .hero__lede {
  max-width: 560px;
  margin-top: 26px;
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink-2);
}

.tzbc .hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 32px;
}

.tzbc .hero__kpis {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

.tzbc .kpi {
  display: grid;
  gap: 12px;
  padding: 22px 24px 24px;
  border-top: 1px solid var(--line-1);
}

.tzbc .kpi:nth-child(-n + 2) {
  border-top: 0;
}

.tzbc .kpi:nth-child(even) {
  border-inline-start: 1px solid var(--line-1);
}

.tzbc .kpi dt {
  display: flex;
  align-items: center;
  gap: 8px;
}

.tzbc .kpi dd {
  font: 300 clamp(30px, 3vw, 44px)/1 var(--font-sans);
  letter-spacing: -0.035em;
  color: var(--ink-1);
}

.tzbc .kpi__live {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--live);
  color: var(--live);
  animation: ping 1.8s var(--ease-out) infinite;
}

.tzbc .kpi small {
  display: block;
  margin-top: 8px;
  font: 500 10.5px/1.3 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ----------------------------------------------------------- pulse strip */

.tzbc .pulse-panel {
  padding: 16px 20px 12px;
}

.tzbc .pulse-panel__head {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
}

.tzbc .pulse-panel__strip {
  position: relative;
  height: 92px;
}

.tzbc .pulse-panel__axis {
  position: relative;
  height: 18px;
  margin-top: 8px;
  font: 500 10px/1 var(--font-mono);
  letter-spacing: 0.08em;
  color: var(--ink-3);
}

.tzbc .pulse-panel__axis span {
  position: absolute;
  top: 4px;
  transform: translateX(-50%);
  white-space: nowrap;
}

.tzbc .pulse-panel__axis span:first-child {
  transform: none;
}

.tzbc .pulse-panel__axis span.is-now {
  transform: translateX(-100%);
  color: var(--live);
}

/* ------------------------------------------------------------- arena intro */

/* What a battle is, for the whole page (2026-10-27). */
.tzbc .arena-intro {
  margin-top: 48px;
  max-width: 880px;
}

.tzbc .arena-intro__lede {
  max-width: 680px;
}

.tzbc .arena-intro__kicker {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  /* Sans, not mono (2026-10-27, user). */
  font: 600 12px/1 var(--font-sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #f5c542;
}

.tzbc .arena-intro__kicker .bsw {
  width: 18px;
  height: 18px;
  overflow: visible;
}

.tzbc .arena-intro__title {
  margin-top: 14px;
  font: 700 clamp(32px, 4.4vw, 52px)/1.02 var(--font-sans);
  letter-spacing: -0.035em;
  color: var(--ink-1);
}

.tzbc .arena-intro__title span {
  background: linear-gradient(100deg, #fff3b0 0%, #f5c542 45%, #cd7f32 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* "Season 1" beside the title: a gold pill in the title's own gold. */
.tzbc .arena-intro__season {
  display: inline-block;
  margin-left: 0.3em;
  padding: 0.5em 0.85em;
  border: 1px solid rgba(245, 197, 66, 0.45);
  border-radius: 999px;
  background: rgba(245, 197, 66, 0.1);
  color: #f5c542;
  font: 600 clamp(11px, 1.2vw, 14px)/1 var(--font-sans);
  font-style: normal;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  vertical-align: middle;
  white-space: nowrap;
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

/* A highlight that slides across the pill (2026-11-05, user: "a sliding highlight
   animation for the season 1 label"): one pass, then a pause, so it catches the eye
   without flickering. Off under reduced motion. */
.tzbc .arena-intro__season::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(105deg, transparent 30%, rgba(255, 243, 176, 0.45) 50%, transparent 70%);
  transform: translateX(-120%);
  animation: season-sweep 3.2s ease-in-out infinite;
  pointer-events: none;
}

@keyframes season-sweep {
  0% { transform: translateX(-120%); }
  45%, 100% { transform: translateX(120%); }
}

@media (prefers-reduced-motion: reduce) {
  .tzbc .arena-intro__season::after { animation: none; opacity: 0; }
}

.tzbc .arena-intro__lede {
  margin-top: 14px;
  font: 400 15px/1.6 var(--font-sans);
  color: var(--ink-2);
}

/* The rules: four columns divided by hairlines, icon over title over
   caption — no pills (2026-10-27). Two by two on a phone. */
.tzbc .arena-rules {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-top: 26px;
  padding: 0;
  list-style: none;
}

.tzbc .arena-rules li {
  display: grid;
  gap: 4px;
  padding: 2px 20px;
  border-inline-start: 1px solid var(--line-2);
}

.tzbc .arena-rules li:first-child {
  padding-inline-start: 0;
  border-inline-start: 0;
}

.tzbc .arena-rules svg {
  width: 22px;
  height: 22px;
  margin-bottom: 8px;
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tzbc .arena-rules b {
  font: 600 14px/1.2 var(--font-sans);
  color: var(--ink-1);
}

.tzbc .arena-rules span {
  font: 400 12.5px/1.35 var(--font-sans);
  color: var(--ink-3);
}

/* The prize: gold. */
.tzbc .arena-rules .is-prize svg { stroke: #f5c542; }
.tzbc .arena-rules .is-prize b { color: #f5c542; }

/* Four across needs ~720px; below that, two by two. */
@media (max-width: 760px) {
  .tzbc .arena-rules {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 20px;
  }

  .tzbc .arena-rules li:nth-child(odd) {
    padding-inline-start: 0;
    border-inline-start: 0;
  }
}

.tzbc[data-theme="light"] .arena-intro__kicker,
.tzbc[data-theme="light"] .arena-rules .is-prize b {
  color: #a87a0c;
}

.tzbc[data-theme="light"] .arena-rules .is-prize svg {
  stroke: #a87a0c;
}

.tzbc[data-theme="light"] .arena-intro__title span {
  background-image: linear-gradient(100deg, #c9971a 0%, #a87a0c 50%, #83501f 100%);
}

.tzbc[data-theme="light"] .arena-intro__season {
  color: #a87a0c;
  border-color: rgba(168, 122, 12, 0.4);
  background: rgba(201, 151, 26, 0.1);
}

.tzbc[data-theme="light"] .arena-intro__season::after {
  background: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.85) 50%, transparent 70%);
}

/* The fight card heading follows the intro, so it needs less air above. */
.tzbc .arena-intro + .battles .section-head {
  margin-top: 40px;
}

/* ---------------------------------------------------------------- sections */

.tzbc .section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px 24px;
  margin: 64px 0 20px;
}

.tzbc .section-title {
  font: 500 28px/1.1 var(--font-sans);
  letter-spacing: -0.03em;
  color: var(--ink-1);
}

.tzbc .section-sub {
  margin-top: 8px;
  /* Sans, sentence case (2026-10-27, user): it is a sentence, not a label. */
  font: 400 13px/1.3 var(--font-sans);
  color: var(--ink-3);
}

/* .section-hint went with the roster's "Hover a bot to trace it through every
   battle · click to pin" line. The hover-to-trace and click-to-pin behaviour
   it described is still there — only the caption was removed. */

/* ------------------------------------------------------------------ roster */

.tzbc .roster__grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 14px;
}

.tzbc .rtile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 20px 20px 18px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  text-align: start;
  transition: background-color 0.25s, border-color 0.25s;
}

.tzbc .rtile:hover,
.tzbc .rtile[aria-pressed="true"] {
  border-color: var(--line-3);
  background: var(--surface-2);
}

.tzbc .rtile__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.tzbc .rtile__rank {
  font: 500 12px/1 var(--font-mono);
  color: var(--ink-3);
}

.tzbc .rtile__lead {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: 600 9.5px/1 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--live);
}

.tzbc .rtile__lead::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  animation: blink 1.4s ease-in-out infinite;
}

.tzbc .rtile__id {
  display: flex;
  align-items: center;
  gap: 14px;
}

.tzbc .rtile__name {
  display: grid;
  gap: 6px;
}

.tzbc .rtile__name b {
  font: 600 15px/1 var(--font-mono);
  letter-spacing: 0.12em;
  color: var(--ink-1);
}

.tzbc .rtile__name small {
  font: 400 12.5px/1 var(--font-sans);
  color: var(--ink-3);
}

.tzbc .rtile__stats {
  display: grid;
  grid-template-columns: repeat(3, auto);
  justify-content: space-between;
  gap: 10px;
}

.tzbc .rtile__stats dt {
  font: 500 9.5px/1.2 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .rtile__stats dd {
  margin-top: 6px;
  font: 500 17px/1 var(--font-mono);
  color: var(--ink-1);
}

/* placements: a five-column micro histogram, 1st → 5th */
.tzbc .places {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 6px;
  align-items: end;
  margin-top: auto;
}

.tzbc .places__col {
  display: grid;
  justify-items: center;
  gap: 5px;
}

.tzbc .places__n {
  font: 500 10px/1 var(--font-mono);
  color: var(--ink-2);
}

.tzbc .places__bar {
  width: 100%;
  max-width: 24px;
  height: calc(4px + var(--h) * 34px);
  border-radius: 3px 3px 0 0;
  background: var(--c);
  opacity: calc(0.35 + var(--h) * 0.65);
  transform-origin: bottom;
  animation: grow 0.9s var(--ease-out) both;
  animation-delay: var(--delay, 0ms);
}

.tzbc .places__bar.is-zero {
  height: 2px;
  background: var(--line-2);
  opacity: 1;
}

.tzbc .places__lbl {
  font: 500 9px/1 var(--font-mono);
  letter-spacing: 0.08em;
  color: var(--ink-3);
}

@keyframes grow {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}

/* ----------------------------------------------------------------- filters */

.tzbc .filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 20px;
}

.tzbc .filters .search {
  margin-inline-start: auto;
}

.tzbc .filters .seg {
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}

.tzbc .filters .seg::-webkit-scrollbar {
  display: none;
}

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

.tzbc .grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 400px), 1fr));
  gap: 20px;
}

/* ── CENTRED LANE, SEVERAL CARDS A ROW (2026-10-27) ──────────────────────
   The lane was 680px with one card per row (2026-10-26, "3 lane approach");
   on a full-screen browser that left one narrow card with empty sides (user:
   "should have multiple cards in one row"). The lane now holds up to three
   420px+ cards; it still centres, and a phone still gets one per row. */
.tzbc .wrap--lane {
  max-width: calc(var(--lane, 1440px) + 2 * var(--gutter));
}

/* A card is at most 520px (2026-10-27, user: "there should be a max-width
   for the card"); with 1fr tracks it stretched to the full row between
   column counts (one card was ~800px at a 900px window). The column COUNT
   comes from the section's own width (container queries), not from the
   520px cap — auto-fill counts with the max track size, which dropped a
   1440px row to two cards. */
.tzbc .wrap--lane .battles {
  container-type: inline-size;
}

.tzbc .wrap--lane .grid {
  grid-template-columns: minmax(0, 520px);
  justify-content: start;
}

@container (min-width: 860px) {
  .tzbc .wrap--lane .grid { grid-template-columns: repeat(2, minmax(0, 520px)); }
}

@container (min-width: 1280px) {
  .tzbc .wrap--lane .grid { grid-template-columns: repeat(3, minmax(0, 520px)); }
}

/* One filter row in the lane. */
.tzbc .wrap--lane .filters {
  flex-wrap: nowrap;
}

/* ── ICON-ONLY SORT + SEARCH (2026-10-27) ──────────────────────────────── */
.tzbc .filters__tools {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-inline-start: auto;
}

.tzbc .filters .sortmenu__toggle,
.tzbc .filters .search--icon .search__toggle {
  width: 36px;
  height: 36px;
  /* Round (2026-10-27, user). */
  border-radius: 50%;
  background: var(--surface-1);
  box-shadow: inset 0 0 0 1px var(--line-2);
  color: var(--ink-2);
}

.tzbc .sortmenu {
  position: relative;
}

.tzbc .filters .sortmenu__toggle {
  display: grid;
  place-items: center;
  border: 0;
  cursor: pointer;
}

.tzbc .sortmenu__toggle svg,
.tzbc .search--icon .search__toggle svg {
  position: static;
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

.tzbc .filters .sortmenu__toggle:hover,
.tzbc .filters .sortmenu__toggle[aria-expanded="true"],
.tzbc .filters .search__toggle:hover {
  color: var(--ink-1);
  box-shadow: inset 0 0 0 1px var(--line-3);
}

.tzbc .filters .sortmenu__toggle:focus-visible,
.tzbc .filters .search__toggle:focus-visible {
  outline: 2px solid var(--line-3);
  outline-offset: 2px;
}

/* A sort other than "Most recent" is on. */
.tzbc .sortmenu.is-set::before {
  content: "";
  position: absolute;
  z-index: 1;
  top: 5px;
  inset-inline-end: 5px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #f5c542;
  pointer-events: none;
}

/* The custom sort list: a panel under the icon, right-aligned. */
.tzbc .sortmenu__panel {
  position: absolute;
  z-index: 30;
  top: calc(100% + 8px);
  inset-inline-end: 0;
  min-width: 200px;
  padding: 6px;
  border-radius: 14px;
  background: var(--surface-2);
  box-shadow: 0 0 0 1px var(--line-2), 0 18px 40px -12px var(--shadow-col);
  animation: sortmenu-in 0.16s var(--ease-out);
}

.tzbc .sortmenu__panel[hidden] {
  display: none;
}

@keyframes sortmenu-in {
  from { opacity: 0; transform: translateY(-4px); }
}

.tzbc .sortmenu__head {
  padding: 8px 10px 6px;
  font: 600 10px/1 var(--font-sans);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .sortmenu__list {
  margin: 0;
  padding: 0;
  list-style: none;
  outline: none;
}

.tzbc .sortmenu__list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 10px;
  border-radius: 8px;
  font: 500 13px/1.2 var(--font-sans);
  color: var(--ink-2);
  cursor: pointer;
  white-space: nowrap;
}

.tzbc .sortmenu__list li.is-active {
  background: rgba(var(--wash-rgb), 0.06);
  color: var(--ink-1);
}

.tzbc .sortmenu__list li[aria-selected="true"] {
  color: var(--ink-1);
}

/* The current order: a gold tick. */
.tzbc .sortmenu__list li[aria-selected="true"]::after {
  content: "";
  width: 9px;
  height: 5px;
  margin-top: -3px;
  border-inline-start: 2px solid #f5c542;
  border-bottom: 2px solid #f5c542;
  transform: rotate(-45deg);
}

@media (prefers-reduced-motion: reduce) {
  .tzbc .sortmenu__panel { animation: none; }
}

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

.tzbc .search--icon .search__toggle {
  display: grid;
  place-items: center;
  position: relative;
  z-index: 1;
  border: 0;
  cursor: pointer;
}

/* Folded: no field, only the icon. Open: the field slides out to the left
   and the icon sits inside its start. */
.tzbc .search--icon input {
  position: absolute;
  inset-inline-end: 0;
  box-sizing: border-box;
  width: 36px;
  padding: 0;
  /* Opens as a pill, so it grows out of the round icon. */
  border-radius: var(--radius-pill);
  opacity: 0;
  pointer-events: none;
  transition: width 0.25s var(--ease-out), opacity 0.15s;
}

.tzbc .search--icon.is-open {
  width: 240px;
}

.tzbc .search--icon.is-open input {
  width: 240px;
  padding: 0 12px 0 36px;
  opacity: 1;
  pointer-events: auto;
}

.tzbc .search--icon.is-open .search__toggle {
  margin-inline-end: auto;
  background: transparent;
  box-shadow: none;
}

@media (max-width: 640px) {
  .tzbc .wrap--lane .filters {
    flex-wrap: wrap;
  }

  .tzbc .search--icon.is-open,
  .tzbc .search--icon.is-open input {
    width: min(240px, calc(100vw - 2 * var(--gutter) - 44px));
  }

  /* "95% margin cap" ran into the next column's figure at phone width. */
  .tzbc .bcard__params dd small {
    display: none;
  }
}

.tzbc .bcard {
  position: relative;
  display: flex;
  flex-direction: column;
  /* No border (2026-10-27, user), so the fill has to set the card off the
     page on its own: --surface-1 (#0a0b10) is a hair off the #0a0a0a page
     and the card vanished. A soft top-lit gradient, two steps up. */
  background: linear-gradient(180deg, #16171f 0%, #0f1015 100%);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: transform 0.45s var(--ease-out), box-shadow 0.45s var(--ease-out);
}

.tzbc .bcard:hover,
.tzbc .bcard:focus-visible {
  transform: translateY(-3px);
  box-shadow: 0 30px 60px -30px var(--shadow-col);
  outline: none;
}

/* Light theme keeps its white card on the cream page. */
.tzbc[data-theme="light"] .bcard {
  background: var(--surface-1);
}

/* Keyboard focus still needs a visible ring now that there is no border. */
.tzbc .bcard:focus-visible {
  box-shadow: 0 30px 60px -30px var(--shadow-col), 0 0 0 2px var(--line-3);
}

.tzbc .bcard.is-entering {
  animation: rise 0.8s var(--ease-out) both;
  animation-delay: var(--delay, 0ms);
}

.tzbc .bcard__head {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px 20px 0;
}

.tzbc .bcard__title {
  min-width: 0;
}

.tzbc .bcard__title h3 {
  font: 500 20px/1.1 var(--font-sans);
  letter-spacing: -0.02em;
  color: var(--ink-1);
  /* A battle name can run to 128 characters (2026-10-26): two lines, then an
     ellipsis; the full name is in the title attribute. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

/* The admin's description: a sentence, so sans and sentence case rather than
   the mono label style of the line above it. Two lines, then an ellipsis;
   the full text is in the title attribute. */
.tzbc .bcard__title p.bcard__desc {
  margin-top: 8px;
  font: 400 12.5px/1.4 var(--font-sans);
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-2);
  white-space: normal;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.tzbc .bcard__title p {
  margin-top: 6px;
  font: 500 10.5px/1.2 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tzbc .bcard__badges {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 6px;
  margin-inline-start: auto;
}

.tzbc .bcard__chart {
  position: relative;
  /* Podium steps (2026-10-27): logo, name, P&L, then the 96px top step. */
  height: 202px;
  /* Even sides, matching the card head (20px), so the right-hand figures
     do not crowd the edge (2026-10-26, "card is not balanced"). */
  margin: 14px 20px 0;
}

.tzbc .bcard__params {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: 12px;
  border-top: 1px solid var(--line-1);
}

.tzbc .bcard__params div {
  /* Extra room below (2026-10-27): with no card border the figures sat
     right on the bottom edge. */
  padding: 14px 20px 20px;
  border-inline-start: 1px solid var(--line-1);
}

.tzbc .bcard__params div:first-child {
  border-inline-start: 0;
}

.tzbc .bcard__params dt {
  font: 500 9.5px/1.2 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .bcard__params dd {
  margin-top: 6px;
  font: 500 14px/1 var(--font-mono);
  color: var(--ink-1);
  white-space: nowrap;
}

.tzbc .bcard__params dd small {
  margin-inline-start: 4px;
  font-size: 10.5px;
  color: var(--ink-3);
}

.tzbc .bcard__models {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  padding: 12px 20px 14px;
  border-top: 1px solid var(--line-1);
}

.tzbc .bcard__models:empty {
  display: none;
}

/* The race at the foot of the card — ui/race-strip.js says what the positions
   mean. `--x` is a runner's place on the track, 0..1. */
.tzbc .bcard__race {
  --runner: 18px;
  padding: 12px 20px 16px;
  border-top: 1px solid var(--line-1);
}

.tzbc .bcard__race[hidden],
.tzbc .brace__lane[hidden] {
  display: none;
}

.tzbc .brace__caption {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
  font: 500 9.5px/1.2 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.tzbc .brace__now {
  color: var(--ink-1);
}

.tzbc .brace__track {
  display: flex;
  align-items: center;
  gap: 6px;
}

.tzbc .brace__lanes {
  flex: 1;
  min-width: 0;
  display: grid;
  gap: 4px;
  /* The finish line, right where the flag's pole stands. */
  border-inline-end: 1px dashed var(--line-3);
}

.tzbc .brace__lane {
  --x: 0;
  position: relative;
  height: var(--runner);
}

/* The road ahead, then the distance this model has covered in its colour. */
.tzbc .brace__lane::before {
  content: "";
  position: absolute;
  inset: 50% 0 auto;
  height: 2px;
  margin-top: -1px;
  background: var(--line-1);
}

.tzbc .brace__trail {
  position: absolute;
  inset-inline-start: 0;
  top: 50%;
  width: calc((100% - var(--runner)) * var(--x) + var(--runner) / 2);
  height: 2px;
  margin-top: -1px;
  border-radius: 1px;
  background: linear-gradient(90deg, transparent, var(--agent));
  transition: width 1.1s var(--ease-out);
}

.tzbc .brace__runner {
  position: absolute;
  top: 0;
  inset-inline-start: calc((100% - var(--runner)) * var(--x));
  display: block;
  height: var(--runner);
  transition: left 1.1s var(--ease-out);
}

.tzbc .brace__flag {
  flex: none;
  width: 16px;
  height: 18px;
}

.tzbc .brace__pole {
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 1.4;
  stroke-linecap: round;
}

.tzbc .brace__cloth { fill: var(--ink-1); }
.tzbc .brace__check { fill: var(--surface-1); }

.tzbc .bcard__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 20px 16px;
}

.tzbc .bcard__lead {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}

.tzbc .bcard__lead > div {
  display: grid;
  gap: 5px;
}

.tzbc .bcard__lead .eyebrow {
  font-size: 9.5px;
}

.tzbc .bcard__lead b {
  font: 600 13px/1 var(--font-mono);
  letter-spacing: 0.1em;
  color: var(--ink-1);
}

.tzbc .bcard__ranks {
  display: flex;
  align-items: center;
}

.tzbc .bcard__ranks li {
  margin-inline-start: -5px;
}

.tzbc .bcard__ranks li:first-child {
  margin-inline-start: 0;
}

.tzbc .bcard__ranks .avatar {
  --size: 22px;
  box-shadow: 0 0 0 2px var(--surface-1);
}

/* NO "OPEN BATTLE" PILL (2026-10-27; user: it "comes and covers the
   status"). The hover pill sat where the status badge is and hid it. The
   whole card is the link, and hover already lifts it and lights the border,
   so the status now stays in view on hover. */

/* -------------------------------------------------------------- responsive */

@media (max-width: 1180px) {
  .tzbc .roster__grid {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  }
}

@media (max-width: 960px) {
  .tzbc .hero {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .tzbc .pulse-panel__head span:last-child {
    display: none;
  }

  /* roster becomes a swipeable rail */
  .tzbc .roster__grid {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }

  .tzbc .roster__grid::-webkit-scrollbar {
    display: none;
  }

  .tzbc .rtile {
    flex: 0 0 80%;
    scroll-snap-align: start;
  }

  .tzbc .bcard__params div {
    padding-inline: 14px;
  }
}

/* ==========================================================================
   Card summary chart — EMBEDDED BUILD (TradeZee, 2026-10-17)

   Each battle card draws a summary (ui/summary-chart.js) instead of a
   miniature of the battle page's race. Every value is a token from base.css,
   so the chart follows the TradeZee palette with the rest of the page.
   ========================================================================== */

/* The variant tabs, in the Battles header. `.seg` is the page's own control,
   so they read as the same thing as the status and market filters. */
.tzbc .cardchart {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.tzbc .sc {
  position: relative;
  width: 100%;
  height: 100%;
}

/* Visible overflow: logos sit on the plot's edge in several variants and
   would otherwise be sliced by the SVG's box. */
.tzbc .sc__svg {
  display: block;
  overflow: visible;
}

/* Bot names in TradeZee's sans; every figure in its mono, tabular so digits
   line up down a column. */
.tzbc .sc-name {
  font: 500 10px/1 var(--font-sans);
  fill: var(--ink-2);
}

.tzbc .sc-val {
  font: 500 10.5px/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  fill: var(--ink-1);
}

/* Podium card (2026-10-26): the leader's name and return lead the card. */
.tzbc .sc-lead-name {
  font: 500 13px/1 var(--font-sans);
  fill: var(--ink-1);
}

/* Trades the model placed, under its money on the step (2026-10-27). */
.tzbc .sc-step-trades {
  font: 600 9.5px/1 var(--font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  fill: var(--ink-3);
}

.tzbc .sc-lead-pnl {
  /* Bold (2026-10-27, user: "the center one profit also put in bold"). */
  font: 700 26px/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  fill: var(--ink-1);
}

.tzbc .sc-lead-pnl.is-pos { fill: var(--pos); }
.tzbc .sc-lead-pnl.is-neg { fill: var(--neg); }

/* "TOP PERFORMER" pill on the leader row. */
.tzbc .sc-top rect { fill: rgba(250, 204, 21, 0.14); stroke: rgba(250, 204, 21, 0.35); stroke-width: 1; }
.tzbc .sc-top text {
  font: 600 9.5px/1 var(--font-mono);
  letter-spacing: 0.08em;
  fill: #facc15;
}

/* Nobody in profit: the same pill, neutral. */
.tzbc .sc-top.is-none rect { fill: transparent; stroke: var(--line-2); }
.tzbc .sc-top.is-none text { fill: var(--ink-3); }

/* Podium steps (2026-10-27): gold, silver and bronze blocks. Fills and
   strokes are set per medal from MEDALS in ui/summary-chart.js. */
.tzbc .sc-step { stroke-width: 1; stroke-opacity: 0.45; }

.tzbc .sc-medal circle { stroke-width: 1; }
.tzbc .sc-medal .sc-medal-inner { fill: none; stroke-opacity: 0.7; }

.tzbc .sc-medal-num {
  font-family: var(--font-sans);
  font-weight: 700;
  fill: #2a2112;
}

.tzbc .sc-step-ret {
  /* Bold (2026-10-27, user: "make the pnl percentage bold"). */
  font: 700 11.5px/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  fill: var(--ink-1);
}

.tzbc .sc-step-ret.is-pos { fill: var(--pos); }
.tzbc .sc-step-ret.is-neg { fill: var(--neg); }

/* Yellow on white is unreadable; amber-700 keeps it gold in light mode. */
.tzbc[data-theme="light"] .sc-top rect { fill: rgba(217, 119, 6, 0.1); stroke: rgba(180, 83, 9, 0.35); }
.tzbc[data-theme="light"] .sc-top text { fill: #b45309; }

/* The leader's 100%, behind every top-3 bar. */
.tzbc .sc-bar-track { fill: var(--line-2); opacity: 0.45; }

.tzbc .sc-val.is-pos { fill: var(--pos); }
.tzbc .sc-val.is-neg { fill: var(--neg); }
.tzbc .sc-val.is-flat { fill: var(--ink-3); }

.tzbc .sc-cap {
  font: 500 9.5px/1 var(--font-mono);
  letter-spacing: 0.02em;
  fill: var(--ink-3);
}

.tzbc .sc-axis {
  font: 500 9px/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  fill: var(--ink-3);
}

.tzbc .sc-zero { stroke: var(--line-3); stroke-width: 1; }
.tzbc .sc-grid { stroke: var(--grid); stroke-width: 1; }
.tzbc .sc-track { stroke: var(--line-2); stroke-width: 1.5; stroke-linecap: round; }

/* Buy & hold, as a reference rather than a competitor: dashed, neutral. */
.tzbc .sc-bench {
  stroke: var(--bench);
  stroke-width: 1;
  stroke-dasharray: 2 3;
}

.tzbc .sc-stem { stroke-width: 1; opacity: 0.5; }
.tzbc .sc-band-bg,
.tzbc .sc-track-bar { fill: var(--surface-3); }
.tzbc .sc-now { stroke: var(--live); stroke-width: 1.5; }

.tzbc .sc-bump {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Logo badge — the same plate + ring as .avatar and the race chart's tips. */
.tzbc .sc-badge {
  fill: var(--plate);
  stroke: var(--c);
  stroke-width: 1.5;
}

.tzbc .sc-logo { color: var(--plate-ink); }

/* Podium logos: a heavier ring, in the step's medal colour. */
.tzbc .sc-mark--medal .sc-badge { stroke-width: 2.25; }

.tzbc .sc-logo .is-stroke {
  fill: none;
  /* On the plate — see .avatar--bench in components.css. */
  stroke: var(--plate-ink-2);
  stroke-width: 2.4;
  stroke-linecap: round;
}

/* Hovering a bot in the roster dims the other four on every card. */
.tzbc .sc [data-agent] { transition: opacity 0.2s var(--ease-out); }
.tzbc .sc .is-dim { opacity: 0.18; }

/* ── Parked line-chart variants (rows, leader, duel, field) ─────────────
   Not shown on the cards today — the card chart is the bar chart "for now".
   Styled anyway so moving a variant from PARKED into VARIANTS in
   ui/summary-chart.js is the only change needed to bring it back. */
.tzbc .sc-base { stroke: var(--line-1); stroke-width: 1; }
.tzbc .sc-spark { fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.tzbc .sc-hero { fill: none; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.tzbc .sc-dot { stroke: var(--surface-1); stroke-width: 1.5; }
.tzbc .sc-area { stroke: none; }
.tzbc .sc-hold { fill: none; stroke: var(--bench); stroke-width: 1.2; stroke-dasharray: 3 3; }
.tzbc .sc-gap { fill: var(--ink-1); fill-opacity: 0.07; stroke: none; }
.tzbc .sc-envelope { fill: var(--ink-1); fill-opacity: 0.08; stroke: var(--line-2); stroke-width: 1; }
.tzbc .sc-median { fill: none; stroke: var(--ink-2); stroke-width: 1.4; }
.tzbc .sc-conn { fill: none; stroke: var(--line-2); stroke-width: 1; }

.tzbc .sc-end {
  font: 500 10px/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  fill: var(--ink-1);
}

.tzbc .sc-end.is-pos, .tzbc .sc-cap.is-pos { fill: var(--pos); }
.tzbc .sc-end.is-neg, .tzbc .sc-cap.is-neg { fill: var(--neg); }
.tzbc .sc-end.is-muted { fill: var(--ink-3); }

/* `field`: one path per bot, invisible until that bot is hovered in the
   roster. Listed with .is-dim so the general dimming rule can never make a
   hidden path half-visible. */
.tzbc .sc .sc-ghost,
.tzbc .sc .sc-ghost.is-dim { fill: none; stroke-width: 1.8; opacity: 0; }
.tzbc .sc .sc-ghost.is-hot { opacity: 1; }

/* The house-bot chip on the roster's first tile. TradeZee is pinned to the
   front of the roster while keeping its true rank number, so this says why
   that tile leads the row — without it, a 02 in first position reads as a
   broken sort. Quiet by design: it marks ownership, not a result, so it
   borrows the accent ring rather than the live pill's urgency. */
.tzbc .rtile__house {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 8px;
  border: 1px solid color-mix(in srgb, var(--c) 45%, transparent);
  border-radius: var(--radius-pill);
  font: 600 9.5px/1 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c);
}

@media (max-width: 640px) {
  /* Phone: the status badge takes its own row above the title, so the
     battle name gets the full card width instead of being cut to 2 words. */
  .tzbc .bcard__head {
    flex-wrap: wrap;
    row-gap: 12px;
  }

  .tzbc .bcard__badges {
    order: -1;
    flex-basis: 100%;
    justify-content: flex-start;
    margin-inline-start: 0;
  }

  .tzbc .bcard__title {
    flex: 1 1 0;
  }

  .tzbc .bcard__title h3 {
    font-size: 18px;
    -webkit-line-clamp: 3;
  }
}

/* ------------------------------------------------------------ boot skeleton */

/* ── THE ARENA'S SKELETON (2026-11-04) ─────────────────────────────────────
   The boot shell in index.html, laid out with this page's own classes
   (arena-intro, section-head, filters, grid, bcard), so only the blocks are
   sized here — each to the text or mark it stands in for. */
.tzbc .bc-skel__kicker { width: 190px; height: 12px; }
.tzbc .bc-skel__hero { width: min(520px, 86%); height: clamp(32px, 4.4vw, 52px); margin-top: 14px; border-radius: 10px; }
.tzbc .bc-skel__lede { width: min(680px, 100%); height: 14px; margin-top: 16px; }
.tzbc .bc-skel__lede--short { width: min(460px, 70%); margin-top: 10px; }
.tzbc .bc-skel__rule-icon { width: 22px; height: 22px; margin-bottom: 8px; border-radius: 6px; }
.tzbc .bc-skel__rule-b { width: min(120px, 90%); height: 14px; }
.tzbc .bc-skel__rule-s { width: min(150px, 100%); height: 11px; margin-top: 4px; }
.tzbc .bc-skel__title { width: 230px; height: 28px; border-radius: 8px; }
.tzbc .bc-skel__sub { width: 210px; height: 13px; margin-top: 10px; }
.tzbc .bc-skel__seg { width: min(300px, 100%); height: 36px; border-radius: var(--radius-sm); }

.tzbc .bc-skel__icon { flex: none; width: 40px; height: 40px; border-radius: 50%; }
.tzbc .bc-skel__h3 { width: 72%; height: 20px; }
.tzbc .bc-skel__sym { width: 38%; height: 10px; margin-top: 8px; }
.tzbc .bc-skel__chip { flex: none; width: 60px; height: 22px; border-radius: var(--radius-pill); }

/* The podium: second, first, third, each a medal over its step. */
.tzbc .bc-skel__podium {
  display: flex;
  align-items: flex-end;
  gap: 10px;
}

.tzbc .bc-skel__step {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.tzbc .bc-skel__step--1 { flex: 1.3; }
.tzbc .bc-skel__medal { width: 40px; height: 40px; border-radius: 50%; }
.tzbc .bc-skel__block { width: 100%; border-radius: 10px 10px 0 0; }
.tzbc .bc-skel__step--1 .bc-skel__block { height: 96px; }
.tzbc .bc-skel__step--2 .bc-skel__block { height: 78px; }
.tzbc .bc-skel__step--3 .bc-skel__block { height: 66px; }

.tzbc .bc-skel__dt { width: 52px; height: 9.5px; }
.tzbc .bc-skel__dd { width: 74px; height: 16px; margin-top: 8px; }
.tzbc .bc-skel__dot { width: 24px; height: 24px; border-radius: 50%; }

