/* THE OPTION CHAIN — the one surface where density is the point.
 *
 * Every other section of this app spent 2026-08-07 gaining air, because the
 * references (Glider, Warp, Apple) all read as products rather than terminals.
 * This one goes the other way ON PURPOSE and the exception is narrow: a chain
 * is a lookup table you scan with your eyes, and a Deribit user reads forty
 * strikes at a glance. Air between strikes is not calm here, it is scrolling.
 * So: 13px on the dense scale (--t-dense, which §55 defined for exactly this
 * — "9+ column tabular surfaces ONLY"), tight rows, mono figures.
 *
 * TOKENS ONLY. Not one colour is authored here; every value comes from
 * instrument.css's tokens (--bg --s1 --s2 --ink --ink2 --ink3 --line --line2
 * --accent, and --pos/--neg for direction). A palette pass is mid-flight in
 * that file and this stylesheet must move with it, not against it.
 *
 * LOADED LAST, and only ever selecting inside .chv. instrument.css normalises
 * `body table td`, `body th` and `body td` with !important; those land on this
 * table too, and the two places this file fights back (cell padding, cell
 * font-size) are scoped hard enough to win rather than by raising the whole
 * file's specificity.
 */

/* ── SHELL ─────────────────────────────────────────────────────────────── */

.chv { display: flex; flex-direction: column; gap: 14px; }

.chv-status {
  color: var(--ink2); font-size: var(--t-sm, 15px); padding: 40px 0;
  text-align: center;
}
.chv-status.bad { color: var(--neg); }

/* ── CONTEXT LINE ──────────────────────────────────────────────────────── */

.chv-ctx {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  font-size: var(--t-sm, 15px); color: var(--ink2);
}
.chv-lead { color: var(--ink3); }
.chv-sel {
  font: inherit; font-weight: 600; color: var(--ink);
  background: var(--s2); border: 1px solid var(--line2); border-radius: 8px;
  padding: 4px 8px; cursor: pointer;
}
.chv-sel:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* ENHANCED: the marked listbox from grid.js has taken over, so the native
   control collapses to nothing. It stays in the DOM and stays settable — it is
   the source of truth the picker writes back through — but it must not paint a
   second, differently-styled control beside the one the reader sees. .chv-sel's
   own padding/border survive .cs-native's generic hide, which is why this is
   scoped here rather than left to the shared rule. */
.chv-sel.cs-native {
  width: 0 !important; height: 0 !important;
  padding: 0 !important; border: 0 !important;
  opacity: 0 !important; pointer-events: none !important;
  position: absolute !important;
}
.chv-spotv { color: var(--ink2); }
.chv-spotv b {
  font-weight: 600; color: var(--ink);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
}
.chv-dot, .chv-meta { color: var(--ink3); font-size: var(--t-xs, 11px); }

/* ── EXPIRY RAIL ───────────────────────────────────────────────────────── */
/* One axis of the chain. Horizontal and scrollable rather than a dropdown:
   the set of expiries is itself information — where the market has listed and
   where it has not — and a closed <select> hides that behind a click. */

.chv-exps {
  display: flex; gap: 6px; overflow-x: auto; overflow-y: hidden;
  padding-bottom: 4px; scrollbar-width: thin;
}
.chv-exp {
  flex: 0 0 auto; display: flex; flex-direction: column; align-items: center;
  gap: 1px; padding: 6px 11px; cursor: pointer;
  background: transparent; border: 1px solid var(--line);
  border-radius: 8px; color: var(--ink2);
}
.chv-exp:hover { border-color: var(--line2); color: var(--ink); }
.chv-exp.on {
  background: var(--accent); border-color: var(--accent); color: var(--bg);
}
.chv-exp.on .chv-exp-t { color: var(--bg); opacity: .72; }
.chv-exp:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.chv-exp-d {
  font-size: var(--t-dense, 13px); font-weight: 600; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.chv-exp-t { font-size: var(--t-xs, 11px); color: var(--ink3); }

/* ── SOURCE BAR — the firm/indicative firewall ─────────────────────────── */

.chv-srcbar {
  display: flex; flex-direction: column; gap: 7px;
  border-top: 1px solid var(--line); padding-top: 11px;
}
.chv-srcgrp { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.chv-srclab {
  font-size: var(--t-xs, 11px); text-transform: uppercase;
  letter-spacing: .07em; color: var(--ink3); margin-right: 2px;
}
.chv-srcsep {
  width: 1px; height: 16px; background: var(--line2); margin: 0 6px;
}
.chv-src, .chv-vpin {
  cursor: pointer; border-radius: 999px; font-size: var(--t-dense, 13px);
  padding: 4px 11px; background: transparent;
  border: 1px solid var(--line); color: var(--ink2);
}
.chv-vpin { font-size: var(--t-xs, 11px); padding: 3px 9px; }
.chv-src:hover, .chv-vpin:hover { border-color: var(--line2); color: var(--ink); }
.chv-src:focus-visible, .chv-vpin:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.chv-src.on, .chv-vpin.on {
  background: var(--accent); border-color: var(--accent); color: var(--bg);
  font-weight: 600;
}
.chv-src-n {
  margin-left: 6px; font-size: var(--t-xs, 11px); color: var(--ink3);
  font-variant-numeric: tabular-nums;
}
.chv-src.on .chv-src-n { color: var(--bg); opacity: .7; }
/* The sentence under the control is NOT decoration. It is the difference
   between a resting offer and a price somebody will quote if you ask, which
   is the distinction this app has got wrong twice. It is always on screen. */
.chv-srcwhat {
  margin: 0; font-size: var(--t-xs, 11px); line-height: 1.55;
  color: var(--ink3); max-width: 78ch;
}
/* Shown only where a pinned venue publishes nothing at all. It is the one
   place on this surface where an absence needs a sentence, because a grid of
   nothing but em dashes reads as a dead market unless it is named. */
.chv-blind {
  margin: 0; font-size: var(--t-xs, 11px); line-height: 1.55;
  color: var(--ink2); max-width: 78ch;
  border-left: 2px solid var(--accent); padding-left: 9px;
}
.chv-blind b { font-weight: 600; color: var(--ink); }

/* ── LAYOUT: chain left, cross-venue dock right ────────────────────────── */

.chv-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@media (min-width: 1180px) {
  .chv-body { grid-template-columns: minmax(0, 1fr) 330px; align-items: start; }
  /* A sticky box taller than its scrollport can never be read to the end —
     it has nowhere to scroll to. Six venues plus two ranking sentences
     measured 700px against a 643px stage, and Hypercall (the sixth line) was
     unreachable. It scrolls itself instead. */
  .chv-dock { position: sticky; top: 8px; overflow: auto; scrollbar-width: thin; }
}

/* ── THE GRID ──────────────────────────────────────────────────────────── */
/* A bounded, self-scrolling instrument. Two reasons, both measured rather
   than stylistic: (1) it lets the view open CENTRED ON SPOT, which is the
   whole point of a chain and impossible if the page scrolls instead;
   (2) overflow-x lives here, so a 9-column table can never push the document
   sideways at 390px — the page body never scrolls horizontally. */
/* The max-height here is a FALLBACK for the first paint only. chain.js
   measures main.stage and sets the real one, because the shell is
   body{height:100dvh;overflow:hidden} with an in-flow 208px footer, so the
   visible stage is 643px at 1440x900 — a vh guess overshot it by 211px and
   the last third of the grid sat behind the command band with its sticky
   header stranded off-screen. Measured, not assumed. */
.chv-wrap {
  overflow: auto; max-height: 420px;
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--s1); scrollbar-width: thin;
  overscroll-behavior: contain;
}
/* border-collapse: SEPARATE, and it is not a preference.
   Under `collapse` a browser paints the collapsed border/background model at
   the TABLE level, and a sticky <th> loses to body cells no matter what
   z-index it declares. Measured on the rendered page rather than assumed: at
   1440 the header read "CALLS | 58,000 | PUTS" — the 58,000 and 59,000 strike
   rows were showing THROUGH the sticky header's strike column while the
   header's own "Strike" label was invisible underneath them. With `separate`
   the cell backgrounds paint per-cell and the header is opaque.
   Consequence, and the reason the row rule moved: a <tr> border is never
   painted under `separate`, so the row hairline lives on the cells. */
.chv-t {
  width: 100%; border-collapse: separate; border-spacing: 0;
  table-layout: fixed; min-width: 560px;
}

/* Sticky head. OPAQUE on purpose: the panel behind it is glass (§62), so a
   translucent header would show forty strikes sliding through the column
   names. --s2 is the raised surface token and it is fully opaque, and it
   needs !important because instrument.css §5 pins `body th` to --bg.

   z-index 30 IS NOT ARBITRARY, and finding out why cost a rendered-pixel
   check that three DOM assertions had already passed. style.css:685 styles
   the BARE ELEMENT — `th { position: sticky; top: -1px; z-index: var(--z-sticky) }`
   with --z-sticky: 20 — so EVERY <th> in this app is sticky, including the
   strike cells in my own tbody. They were sticking to the top of the
   scroller at z-index 20 and painting straight over this header: measured at
   1440, the header read "CALLS | 62,500 | PUTS" with its own "Strike" label
   invisible beneath a body row. The two rules below undo that for the body
   spine and put the real header above what is left. */
.chv-t thead th {
  position: sticky; background: var(--s2) !important; z-index: 30;
}
body .chv .chv-t tbody th.chv-k {
  position: static; top: auto; z-index: auto;
}
/* The second header row sticks BELOW the first, so the offset has to equal
   the first row's rendered height exactly. Pinned rather than left to the
   font: measured at 28px, and a 24px guess left the Calls/Puts row four
   pixels of itself showing under the column names. */
.chv-t thead tr.chv-side th {
  top: 0; height: 28px; box-sizing: border-box;
  padding-top: 4px !important; padding-bottom: 4px !important;
}
.chv-t thead tr:last-child th { top: 28px; }

body .chv .chv-t th.chv-h {
  font-size: var(--t-xs, 11px) !important;
  font-weight: 400; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink3); text-align: right;
  padding: 6px 8px !important;   /* §69 ladder: was 5px 9px */
  border-bottom: 1px solid var(--line);
}
body .chv .chv-t th.chv-sideh {
  height: 24px; text-align: center; letter-spacing: .16em; color: var(--ink2);
  border-bottom: 1px solid var(--line2);
}
body .chv .chv-t th.chv-kh { text-align: center; color: var(--ink2); }

/* ROWS. The tight row is the whole density argument: as many strikes in one
   screen as the stage will carry. The hairline is on the CELLS because
   border-collapse is `separate` above — a <tr> border would simply not paint. */
.chv-r > * {
  border-bottom: 1px solid color-mix(in srgb, var(--line) 45%, transparent);
}
/* !important on every background that has to beat instrument.css §5's
   `body th { background: var(--bg) !important }` — the strike spine is a th. */
.chv-r:hover td, .chv-r:hover th {
  background: color-mix(in srgb, var(--accent) 7%, var(--s2)) !important;
  cursor: pointer;
}

body .chv .chv-t td.chv-c {
  font-size: var(--t-dense, 13px) !important;
  padding: 4px 8px !important;   /* §69 ladder: was 3px 9px */
  text-align: right; color: var(--ink);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body .chv .chv-t th.chv-k {
  font-size: var(--t-dense, 13px) !important;
  padding: 4px 12px !important;   /* §69 ladder: was 3px 10px */
  text-align: center; font-weight: 600; color: var(--ink) !important;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  /* !important against instrument.css §5, which pins every `th` in the app to
     --bg and --ink3. The strike spine is the axis of the whole grid; it is
     not chrome and it does not read as chrome. */
  background: var(--s2) !important;
  border-left: 1px solid var(--line); border-right: 1px solid var(--line);
  white-space: nowrap; text-transform: none; letter-spacing: 0;
}

/* ABSENCE. The two glyphs are the product's core claim made visible, and they
   are deliberately DIFFERENT WEIGHTS of nothing:
     —  we can see this contract and nobody is quoting that side
     ·  the selected venues do not list it at all
   Neither is ever a 0, and neither is ever styled like a number. */
body .chv .chv-t td.chv-na { color: var(--ink3); }
body .chv .chv-t td.chv-void { color: var(--ink3); opacity: .38; }
.chv-dv em.chv-na { font-style: normal; color: var(--ink3); }

/* IV is one venue's own mark IV. Dimmer than a price because it is not one. */
body .chv .chv-t td.chv-iv { color: var(--ink2); }

/* The three-letter venue tag beside a consolidated price. Small, dim, and
   only drawn when more than one venue in the class lists the contract —
   otherwise it is a stutter. */
/* THE VENUE MARK BESIDE A PRICE.
   The code it replaces was a cipher: "BY", "DV", "OK" all need a legend before
   a price means anything, and the derived 3-letter form printed "Der" for both
   Derive and Deribit. A logo is recognised, not decoded.

   SMALL ON PURPOSE — 13px, which is under the 15px data step, so it reads as
   an attribution on the figure rather than competing with it. The figures stay
   the loudest thing in the row. Vertically centred against the digits and
   given a fixed box so the numeric column keeps a clean right edge.

   NOT dimmed with opacity: these are 32px raster marks scaled down, and
   fading them turns the darker ones to mud. They are already quiet at 13px. */
/* The reserved slot on an untagged priced cell. Same width + gap as a mark,
   so the digits in a column keep one right edge whether or not the price
   carries an attribution. */
.chv-vm-slot {
  display: inline-block; width: 13px; height: 1px;
  margin-left: 6px; vertical-align: -2px;
}

.chv-vm {
  width: 13px; height: 13px;
  margin-left: 6px;
  vertical-align: -2px;
  flex: 0 0 auto;
  border-radius: 4px;
}
/* The <defs> carrier. It must stay in the layout tree — display:none on an
   <svg> makes its <symbol> references fail to resolve in some engines — so it
   is collapsed to nothing instead of hidden. */
.chv-sprite {
  position: absolute; width: 0; height: 0;
  overflow: hidden; pointer-events: none;
}

/* IN THE MONEY. A wash, not a colour: jade/rose are DIRECTION in this app and
   moneyness is not a direction. --s2 over the row is the same device the
   coverage matrix uses for "we have this". */
body .chv .chv-t td.itm { background: var(--s2); }

/* NEAR THE MONEY. The row the eye should land on, marked by weight rather
   than by a second accent. */
.chv-r.atm th.chv-k { color: var(--accent) !important; }
.chv-r.on td.chv-c, .chv-r.on th.chv-k {
  background: color-mix(in srgb, var(--accent) 15%, var(--s1)) !important;
}
.chv-r.on th.chv-k { box-shadow: inset 0 0 0 1px var(--accent); }

/* SPOT. The accent means "where you are" (§61) and on a chain that is
   literally what the index price is. One hairline, one number, no chrome. */
body .chv .chv-t tr.chv-spot td {
  padding: 3px 9px !important; background: transparent;
  border-top: 1px solid var(--accent); border-bottom: 1px solid var(--accent);
  text-align: center; color: var(--accent);
  font-size: var(--t-xs, 11px) !important;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
}
.chv-spot-l {
  text-transform: uppercase; letter-spacing: .12em; margin-right: 8px;
  opacity: .8;
}
.chv-spot b { font-weight: 600; }
.chv-spot-n { margin-left: 10px; color: var(--ink3); letter-spacing: 0; }

.chv-empty {
  margin: 0; padding: 28px 16px; text-align: center; color: var(--ink3);
  font-size: var(--t-sm, 15px); border: 1px solid var(--line);
  border-radius: 12px; line-height: 1.6;
}

/* ── THE DOCK — one contract, every venue ──────────────────────────────── */

.chv-dock {
  border: 1px solid var(--line); border-radius: 12px;
  background: var(--s1); padding: 14px 15px 13px;
  display: flex; flex-direction: column; gap: 9px;
}
.chv-dock h3 {
  margin: 0; font-size: var(--t-dense, 13px); font-weight: 600; color: var(--ink);
  letter-spacing: .01em; line-height: 1.45;
}
.chv-dock-idle p {
  margin: 0; font-size: var(--t-xs, 11px); line-height: 1.65; color: var(--ink3);
}

/* THE TWO SENTENCES NEVER SHARE A SUPERLATIVE. The firm one is a statement;
   the indicative one is a caveat that explicitly refuses to replace it, even
   when its number is better. That refusal is the whole design. */
.chv-best {
  margin: 0; font-size: var(--t-xs, 11px); line-height: 1.6; color: var(--ink2);
  border-left: 2px solid var(--accent); padding-left: 9px;
}
.chv-best b {
  font-weight: 600; color: var(--ink);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
}
.chv-best-none { border-left-color: var(--line2); }
.chv-best-none b { color: var(--ink2); font-family: inherit; }
.chv-bestq {
  margin: -4px 0 0; font-size: var(--t-xs, 11px); line-height: 1.6;
  color: var(--ink3); border-left: 2px dotted var(--line2); padding-left: 9px;
}

.chv-dvs { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 1px; }
.chv-dv {
  display: grid; grid-template-columns: 1fr auto; gap: 1px 8px;
  padding: 6px 0; border-top: 1px solid var(--line);
  font-size: var(--t-xs, 11px);
}
.chv-dv-n { color: var(--ink); font-weight: 600; }
.chv-dv-c {
  color: var(--ink3); text-transform: uppercase; letter-spacing: .07em;
  font-size: 9px; align-self: center; text-align: right;
}
/* Firm gets the only lit label in the list. Not a colour code — one weight of
   emphasis, so "resting" is the thing that stands out on a scan. */
.chv-dv-firm .chv-dv-c { color: var(--ink2); }
.chv-dv-off { opacity: .55; }
.chv-dv-x { grid-column: 1 / -1; color: var(--ink3); }
.chv-dv-px {
  grid-column: 1 / -1; display: flex; gap: 12px; flex-wrap: wrap;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.chv-dv-p i {
  font-style: normal; color: var(--ink3); margin-right: 4px;
  font-family: system-ui, sans-serif;
}
.chv-dnote {
  margin: 2px 0 0; font-size: 10px; line-height: 1.6; color: var(--ink3);
  border-top: 1px solid var(--line); padding-top: 8px;
}

/* ── FOOTNOTE / LEGEND ─────────────────────────────────────────────────── */

.chv-foot {
  margin: 0; display: flex; flex-wrap: wrap; gap: 6px 20px;
  font-size: var(--t-xs, 11px); color: var(--ink3); line-height: 1.6;
  border-top: 1px solid var(--line); padding-top: 10px;
}
.chv-lg b {
  color: var(--ink2); font-weight: 600; margin-right: 5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.chv-lg-itm {
  display: inline-block; width: 16px; height: 10px; vertical-align: -1px;
  background: var(--s2); border: 1px solid var(--line2); border-radius: 2px;
}

/* ── NARROW ────────────────────────────────────────────────────────────── */
/* THE COLUMNS DO NOT CHANGE AND THAT IS DELIBERATE. The obvious phone move is
   to hide the IV columns, and it is wrong twice over: the header's Calls/Puts
   cells carry colspan, so dropping two body columns leaves the spans claiming
   columns that no longer exist and the whole grid slips out of alignment; and
   a chain that shows different columns on a phone is not the instrument the
   reader recognises, which is the only reason this view exists.
   So the table keeps its shape and scrolls INSIDE .chv-wrap. The wrap owns
   overflow, so the document itself never scrolls sideways at any width — the
   thing actually being guarded. Deribit's own chain does exactly this. */
@media (max-width: 720px) {
  .chv-t { min-width: 470px; }
  /* §69 ladder, phone tier. */
  body .chv .chv-t td.chv-c { padding: 4px 4px !important; }
  body .chv .chv-t th.chv-k { padding: 4px 6px !important; }
  body .chv .chv-t th.chv-h { padding: 6px 4px !important; }
  .chv-wrap { max-height: 62vh; }
  .chv-srcsep { display: none; }
  /* THE VENUE CODE STAYS ON A PHONE. It used to be display:none, which meant
     no price on a narrow screen could be attributed to a venue at all — in the
     one view whose entire premise is comparing venues. The block above argues
     exactly this about the IV columns ("a chain that shows different columns
     on a phone is not the instrument the reader recognises"); the same
     reasoning applies here, and the table already scrolls inside .chv-wrap so
     width is not the constraint. Two characters instead of three pays for it. */
  .chv-vm, .chv-vm-slot { margin-left: 4px; width: 12px; }
  .chv-vm { height: 12px; }
  .chv-foot { gap: 4px 14px; }
}

/* The settlement hour, shown ONLY on chips that share a calendar date with
   another expiry. Venues do not all settle at the same time — Delta is 12:00
   UTC against everyone else's 08:00 — so five August dates carried two
   different contracts behind two identically-labelled chips. */
.chv-exp-h {
  opacity: .8;
  font-variant-numeric: tabular-nums;
}
.chv-exp.on .chv-exp-h { opacity: .85; }
