/* ============================================================
   HEDGE — five columns, one story, read left to right.

   The prompt, what it predicted, the name under the pointer, and the
   reasoning behind it. Each column narrows the last one, so the page is
   a sentence rather than a set of panels: a question, an answer, a
   subject, a because.

   NOTHING ON THIS PAGE SCROLLS AS A PAGE. The window is the frame and
   each column scrolls inside it, because the four readings have to stay
   level with each other — a dashboard where the evidence has scrolled
   away from the claim is four pages stacked sideways.

   The whole sheet is built out of the site's own tokens: ground plus
   rgba(var(--tone), a). The two colours it adds — up and down — are the
   only new pigment on the site, and they exist because a forecast that
   does not say which way it points is not a forecast.
   ============================================================ */

:root[data-page="hedge"] {
  /* The rail, at Drop's width exactly. The two tools are the same site
     and the rail is the same piece of furniture doing the same job; a
     sidebar that stood at 254 on one page and 213 on the next would read
     as the window having resized between them, which is the one thing it
     did not do. So it does NOT flex — the reading columns absorb a narrow
     window instead, and past the point where they can, the deck scrolls. */
  --rail-w: 254px;
  --hx-head: 51px;            /* every column's header band, one height */
  --hx-pad: clamp(13px, 1.1vw, 18px);   /* the columns' own inset */

  /* DIRECTION. Green is the site's --live, which already means "this is
     current" elsewhere; here it also means "up", and the two readings do
     not collide because nothing on this page is live in the other sense.
     The down colour is warm rather than the alarm red of --flag: a
     forecast to the downside is a call, not a fault. */
  --up: var(--live);
  --down: #e8563f;
  --up-wash: rgba(53, 192, 90, 0.14);
  --down-wash: rgba(232, 86, 63, 0.14);

  /* a panel lifted off the ground — the breakdown cards, the chips */
  --hx-panel: rgba(var(--tone), 0.045);
  --hx-panel-hi: rgba(var(--tone), 0.075);
}

/* The light theme does not get the same two pigments. Green on white at
   the dark theme's value reads as a highlighter, and the warm red goes
   muddy — so both step down in luminance and up in saturation, which is
   the same move --accent already makes across the flip. */
:root[data-page="hedge"][data-theme="light"] {
  --down: #cc3f26;
  --up-wash: rgba(31, 156, 71, 0.13);
  --down-wash: rgba(204, 63, 38, 0.12);
}

:root[data-page="hedge"],
:root[data-page="hedge"] body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

/* The band, not a dissolve — the same rule Models and Drop follow, and
   for the same reason: nothing scrolls under this chrome, so a soft edge
   would read as the header being unfinished rather than as the page
   passing beneath it. */
:root[data-page="hedge"] .nav::before {
  height: var(--nav-h);
  border-bottom: 1px solid var(--hair);
}

/* ---------------------------------------------------------------
   1. THE FRAME
   --------------------------------------------------------------- */

.hedge {
  position: fixed; inset: var(--nav-h) 0 0 0;
  display: grid;
  /* THE PROMPT LIES DOWN. It is the one part of this page that is not a
     live reading: the question, read once, referred back to, and
     identical for every row beneath it. The other three answer it, and
     they answer it about a different name every time you press a row —
     so they are the ones that have to stay side by side, and the
     question is the one that can be a band.

         ┌──────┬────────────────────────────────┐
         │      │  Prompt                        │
         │ Rail ├───────────┬─────────┬──────────┤
         │      │ Predictions│  Name  │ Breakdown│
         └──────┴───────────┴─────────┴──────────┘

     The rail is untouched, running the full height down the left exactly
     as it does on Drop. The three readings share the rest evenly, the way
     the design draws them.

     254 + 240 + 280 + 240 = 1014, so the whole arrangement holds down to
     about a 1024 window before anything scrolls sideways — and when it
     does, the rail stays pinned (position: sticky) so the run switcher is
     never the thing that scrolled away.

     No markup moves for any of this: the columns are laid into named
     areas, and the hairline each one draws down its own left edge lands
     in the right place without being told which row it is in. */
  /* The three columns do NOT share the surplus. Predictions is a list of
     fixed-width figures and Breakdown is a measure of prose — both stop
     being better past a point, and a run of text 900px wide is harder to
     read than the same text at 375. The name column is the one that gains
     from room: its chart is the only thing here that draws more of itself
     when given more. So the outer two are capped and the middle takes
     everything left over. */
  /* THREE columns now, not five. The desk used to be a rail, a prompt
     band and three readings side by side; the prompt was the only part of
     it that was not a live reading, and a band across the top was the
     wrong shape for a document, so it moved into Compass and took the run
     list with it. What is left is the shape of the question: WHICH DAY
     (rail) → WHICH NAMES (the board) → THIS NAME (the sheet).

     The sheet takes the surplus, because it is the only column here whose
     content improves with room — the board is a list of fixed-width
     figures and the rail is a list of dates. */
  grid-template-columns:
    var(--rail-w)
    minmax(320px, 0.85fr)   /* the board */
    minmax(420px, 1.4fr);   /* the sheet */
  grid-template-rows: minmax(0, 1fr);
  grid-template-areas: "rail list sheet";
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  scrollbar-color: var(--hair) transparent;
}

.hx-rail    { grid-area: rail; }
.hx-list    { grid-area: list; }
.hx-detail  { grid-area: sheet; }
.hx-library { grid-area: lib; }
.hx-compass { grid-area: lib; }
.hx-metrics { grid-area: lib; }

/* ---- the other view -----------------------------------------------------
   The library is not something you consult while looking at a run — it is
   the other thing you can be looking at. So it takes the whole room to
   the right of the rail rather than floating over it, and the rail is the
   switcher, exactly as it is on Drop.

   The desk's four areas are dropped from the template while it is up, and
   the columns that would have filled them are taken out of the grid
   entirely — a grid item whose named area does not exist gets
   auto-placed, which would push the library out of its own row. */
.hedge:not([data-view="desk"]) {
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
  grid-template-areas: "rail lib";
}
.hedge:not([data-view="desk"]) .hx-list,
.hedge:not([data-view="desk"]) .hx-detail { display: none; }
.hx-library[hidden] { display: none; }
.hedge[data-view="library"] .hx-library { display: flex; }
.hedge::-webkit-scrollbar { height: 8px; }
.hedge::-webkit-scrollbar-thumb {
  background: var(--hair); border-radius: 4px;
  border: 2px solid transparent; background-clip: content-box;
}

/* [hidden] loses to a display declaration, and .hx-col sets one. Without
   this, a hidden view is still a grid ITEM: its named area does not exist
   in the desk template, so it gets auto-placed and silently adds an
   implicit column — three views hidden behind the desk were adding two.
   The columns were 254 389 640 0 81 instead of 254 389 640. */
.hx-col[hidden] { display: none; }

.hx-col {
  position: relative;
  min-width: 0; min-height: 0;
  display: flex; flex-direction: column;
  scroll-snap-align: start;
}
/* The rules between columns are drawn by the columns themselves rather
   than by a border, because they are the entrance: each one wipes down
   from the nav before the column beside it fills in. A border cannot be
   animated from nothing without moving the layout. */
.hx-col + .hx-col::before {
  content: ""; position: absolute; z-index: 3;
  left: 0; top: 0; bottom: 0; width: 1px;
  background: var(--hair);
  transform-origin: top;
}

/* the rail holds its ground while the deck slides under it */
/* Placement, and nothing else: the rail is a sticky column in the deck and
   paints its own ground so the readings slide under it. Its rhythm is the
   sidebar's, unmodified — see styles/sidebar.css. */
.hx-rail { position: sticky; left: 0; z-index: 4; background: var(--ink); }

/* ---- every column's head ------------------------------------------------
   One height across all five, and NO rule under it. A hairline under each
   header drew a second horizontal line a few pixels below the nav's own,
   which read as the chrome being two bands deep — and it cut each column's
   label away from the thing the label names.

   Without the rule, the label has to belong to its content by proximity
   instead, so every column's body starts close underneath it (the small
   padding-top figures below). The band keeps its height: the five labels
   sit on one line across the window, and that line is the alignment the
   page is built on.

   The exception is Breakdown, at the end of the row — see .hx-brief. */
.hx-head {
  flex: none;
  height: var(--hx-head);
  display: flex; align-items: center; gap: 10px;
  padding: 0 var(--hx-pad);
}
/* Drop's own figures: the brand 20px in from the rail's edge, the
   controls 16 from the right. That 20 is also where every run name below
   lands (10 on .hx-runs, 10 inside the row), so the label and the list it
   heads share one left edge — which is the thing that was wrong when this
   header carried the columns' own inset instead. */

/* Breakdown keeps the rule, because its column is the only one whose
   content is a stack of bordered cards: with no line of its own the
   header read as the first card's lid. The line gives it a floor, and
   the cards start below it. */
.hx-brief .hx-head { border-bottom: 1px solid var(--hair); }
.hx-label {
  flex: 1; min-width: 0;
  font-family: var(--sans); font-size: 14px;
  color: var(--t-second);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
/* The ticker, quietly. It used to be the loudest thing in this header
   because it was the column's subject; the subject is now the first line
   of the column itself, at the size of the price, so the symbol goes back
   to being what it is — a filing code. Grey, and it takes the slack so
   the exchange and Refresh hold the far end. */
.hx-head .hx-sym {
  flex: 1; min-width: 0;
  color: var(--t-dim); font-size: 13px;
  letter-spacing: 0.02em;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.hx-head .hx-ex {
  flex: none;
  color: var(--t-faint); font-size: 12px;
  font-family: var(--mono); letter-spacing: 0.04em;
}
.hx-head .hx-sub {
  flex: 1; min-width: 0;
  color: var(--t-dim); font-size: 13px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}

/* the small square controls that live in a header */
.hx-ic {
  width: 28px; height: 28px; flex: none;
  display: grid; place-items: center;
  border-radius: 8px;
  color: var(--t-second);
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.hx-ic:hover { color: var(--t-primary); background: rgba(var(--tone), 0.08); }
.hx-ic svg {
  width: 16px; height: 16px;
  fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
}
.hx-ic[data-spin] svg { animation: hx-spin 620ms var(--ease-io); }
@keyframes hx-spin { to { transform: rotate(360deg); } }

/* a word used as a control — Refresh, Read more */
.hx-word {
  flex: none;
  font-family: var(--sans); font-size: 13px;
  color: var(--t-dim);
  transition: color var(--fast) var(--ease);
}
.hx-word:hover { color: var(--t-primary); }
/* mid-flight: the word dims and stops answering the pointer, so a second
   press cannot queue a second request behind the first */
.hx-word[data-busy] { color: var(--t-faint); pointer-events: none; }

.hx-body {
  flex: 1; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: thin; scrollbar-color: transparent transparent;
}
/* The scrollbar arrives with the pointer. Four permanent gutters across
   a five-column instrument is four vertical lines competing with the
   four this page draws on purpose. */
.hx-body:hover { scrollbar-color: var(--hair) transparent; }
.hx-body::-webkit-scrollbar { width: 8px; }
.hx-body::-webkit-scrollbar-thumb {
  background: transparent; border-radius: 4px;
  border: 2px solid transparent; background-clip: content-box;
}
.hx-body:hover::-webkit-scrollbar-thumb { background: var(--hair); }

/* ---------------------------------------------------------------
   2. THE RAIL
   --------------------------------------------------------------- */
/* The rail is the shared sidebar — brand line, search, the block of views,
   the list, the footer — and all of that lives in styles/sidebar.css now,
   under .sb. Drop's aside is the same markup under the same names, which
   is the point: they were the same component written twice, a pixel apart
   on the section heading and identical everywhere else.

   What is left here is what only Hedge's copy needs. */

/* .hx-label still heads Compass, Library and Metrics — three views inside
   this tool, which take no mark and are not the sidebar. */
.hx-label[hidden] { display: none; }

/* The makers' block, above the list and outside its scroll — Drop's
   .side-new, at Drop's own inset, doing the same job. */
.hx-new { flex: none; padding: 2px 10px 6px; display: flex; flex-direction: column; gap: 2px; }

.hx-runs { padding: 2px 10px 20px; }
.hx-sec + .hx-sec {
  border-top: 1px solid var(--hair-soft);
  margin-top: 10px; padding-top: 10px;
}
.hx-sec-name {
  padding: 4px 10px 6px;
  font-family: var(--sans); font-size: 12.5px;
  color: var(--t-dim);
}

/* one run. The same row Drop's sidebar draws, because it is the same
   object doing the same job — a thing you are standing in, or one you
   could be. */
.hx-run {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 34px; padding: 0 10px;
  border-radius: 9px;
  font-family: var(--sans); font-size: 14px;
  text-align: left; color: var(--t-second);
  user-select: none; -webkit-user-select: none;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.hx-run:hover { background: rgba(var(--tone), 0.07); color: var(--t-primary); }
.hx-run[aria-current="true"] { background: rgba(var(--tone), 0.12); color: var(--t-primary); }
.hx-run:focus-visible { outline: none; box-shadow: inset 0 0 0 1px rgba(var(--tone), 0.4); }
.hx-run[aria-current="true"]:focus-visible { box-shadow: none; }
.hx-run-name { min-width: 0; flex: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }

/* a run still filling. The dot is the whole of the status: it is the one
   thing on this page that says the model is mid-sentence. */
.hx-run-dot {
  width: 5px; height: 5px; flex: none; border-radius: 50%;
  background: var(--up);
  animation: hx-pulse 1.4s var(--ease-io) infinite;
}
@keyframes hx-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

#calls .hx-empty, #movers .hx-empty { padding: 20px var(--hx-pad); }
.hx-empty { padding: 10px; font-family: var(--sans); font-size: 12.5px; color: var(--t-dim); }

.hx-ico {
  width: 16px; height: 16px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.4;
  stroke-linecap: round; stroke-linejoin: round;
}

/* ---------------------------------------------------------------
   3. THE PROMPT
   --------------------------------------------------------------- */

.hx-prompt-body { padding: 4px var(--hx-pad) 40px; }
/* The way past the clamp. A three-line band with no door on it is a
   document you cannot read — see §9. */
.hx-ask-more { display: block; }

.hx-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.hx-tag {
  padding: 4px 10px; border-radius: 999px;
  background: var(--chip);
  font-family: var(--sans); font-size: 12px; color: var(--t-second);
}

.hx-prompt-title {
  font-family: var(--sans); font-size: 17px; line-height: 1.35;
  letter-spacing: -0.01em; color: var(--t-primary);
  margin-bottom: 14px;
}

/* The prompt itself. It is a document, so it is set as one — 13.5px,
   1.62 leading, the site's second tone — and the structure inside it is
   said by rhythm rather than by weight. Headings step to the primary
   tone and take air above them; nothing here is bold, because a prompt
   full of bold headings reads as a specification rather than as the
   thing somebody actually typed. */
.hx-edit {
  display: block; width: 100%;
  min-height: min(62vh, 780px);
  padding: 0; resize: vertical;
  background: none; color: var(--t-primary);
  font-family: var(--sans); font-size: 13.5px; line-height: 1.62;
}
.hx-edit:focus-visible { outline: none; }

.hx-doc { font-family: var(--sans); font-size: 13.5px; line-height: 1.62; color: var(--t-second); }
.hx-doc p { margin: 0 0 10px; }
.hx-doc .hx-h { color: var(--t-primary); margin: 20px 0 8px; }
.hx-doc .hx-n {
  color: var(--t-primary); margin: 16px 0 6px;
  display: flex; gap: 8px;
}
.hx-doc .hx-n i { font-style: normal; color: var(--t-dim); }
.hx-doc ul { margin: 0 0 12px; }
.hx-doc li { position: relative; padding-left: 20px; }
.hx-doc li::before {
  content: ""; position: absolute;
  left: 7px; top: 0.72em;
  width: 3px; height: 3px; border-radius: 50%;
  background: var(--t-faint);
}

/* ---------------------------------------------------------------
   4. THE PREDICTIONS
   --------------------------------------------------------------- */

/* The week strip lived here — seven chips and a marker sliding behind
   them. It is a list in the rail now (see .sb-item), and its rules went
   with it rather than being left to be inherited by accident: .hx-date was
   a 52px chip holding a 19px number, and the session rows that took the
   same name came out four times the height they should have been. */

/* ---- what the day shows -------------------------------------------------
   Two readings of one day: what was called, and what the market did. A
   strip of words rather than a control — the one in force is said by the
   primary tone and the other by the dim one, which is the same way the
   range under the chart says which span it is on. No underline, no pill:
   the words are short and there are two of them, and a rule under one of
   a pair is furniture for a decision nobody needs help making. */
.hx-tabs {
  flex: none;
  display: flex; align-items: center; gap: 18px;
  padding: 14px var(--hx-pad);
  border-bottom: 1px solid var(--hair);
}
.hx-tab {
  font-family: var(--sans); font-size: 14px;
  color: var(--t-dim);
  transition: color var(--fast) var(--ease);
}
.hx-tab:hover { color: var(--t-second); }
.hx-tab[aria-selected="true"] { color: var(--t-primary); }
.hx-tab:focus-visible { outline: none; box-shadow: 0 0 0 1px rgba(var(--tone), 0.4); border-radius: 4px; }

/* ---- what the market did ------------------------------------------------
   One row per name the day was called on: where it opened, where it is
   (or where it closed), and the move between them. The same three-cell
   measure the call above it uses, so the two tabs read as two columns of
   one table rather than two different documents. */
/* ONE ROW, TWO USES. A call and a result are the same sentence about the
   same name — two figures, the move between them, and a word at each end
   saying what the figures are — so they are one layout and not two that
   happen to resemble each other. The call adds a press and a selection;
   nothing else about it differs. */
.hx-move-row,
.hx-call {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: 4px 10px;
  padding: 14px var(--hx-pad) 16px;
  border-bottom: 1px solid var(--hair-soft);
}
.hx-move-row:last-child { border-bottom: 0; }
.hx-move-t {
  font-family: var(--mono); font-size: var(--mono-size);
  letter-spacing: var(--mono-track); text-transform: uppercase;
  color: var(--t-second);
  transition: color var(--fast) var(--ease);
}
.hx-move-state {
  justify-self: end;
  min-width: 0;
  text-align: right;
  font-family: var(--mono); font-size: var(--mono-size);
  letter-spacing: var(--mono-track); text-transform: uppercase;
  color: var(--t-dim);
  transition: color var(--fast) var(--ease);
}
/* ONE LINE, both kinds. The row is a fixed three-band shape and a
   catalyst that wrapped grew it by a whole line, so a list of eight
   calls stopped being a list of eight equal things. Given as much of the
   row as the ticker can spare, and cut with an ellipsis past that. */
.hx-move-state {
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.hx-move-figs {
  grid-column: 1 / -1;
  display: flex; align-items: baseline; gap: 10px;
}
.hx-move-px { font-family: var(--sans); font-size: 19px; color: var(--t-primary); font-variant-numeric: tabular-nums; }
.hx-move-arrow { width: 22px; height: 12px; flex: none; fill: none; stroke: var(--t-dim); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.hx-move-pct {
  margin-left: auto;
  font-family: var(--sans); font-size: 15px;
  font-variant-numeric: tabular-nums;
}
.hx-move-row[data-dir="up"] .hx-move-pct { color: var(--up); }
.hx-move-row[data-dir="down"] .hx-move-pct { color: var(--down); }
.hx-move-row[data-dir="flat"] .hx-move-pct { color: var(--t-dim); }

.hx-move-cap {
  grid-column: 1 / -1;
  display: flex; gap: 10px;
  font-family: var(--sans); font-size: 12px; color: var(--t-dim);
}
.hx-move-cap span:last-child { margin-left: auto; }

/* ---- the month, and the day's two counts -------------------------------
   The heading over the strip. It names the month rather than the day
   because the day is already said, in white, three inches below it — and
   a row that repeated it was answering a question the strip had just
   answered better. The counts ride at the far end of the same line: they
   belong to the chosen day, and the chosen day is what the strip is for. */
/* The day's tally moved into the rail's rows as a signed net. */

/* while a run is filling, the tally says so instead of counting */
.hx-fill {
  flex: none; padding: 0 var(--hx-pad) 12px;
  font-family: var(--mono); font-size: var(--mono-size);
  letter-spacing: var(--mono-track); text-transform: uppercase;
  color: var(--t-dim);
  display: flex; align-items: center; gap: 8px;
}
.hx-fill[hidden] { display: none; }
.hx-fill i {
  width: 5px; height: 5px; border-radius: 50%; background: var(--up);
  animation: hx-pulse 1.4s var(--ease-io) infinite;
}
/* The dot is a live indicator. Over a session that has closed there is
   nothing arriving for it to indicate, and a pulse there is an animation
   lying about a fact — so the line keeps the words and drops the dot. */
.hx-fill[data-still] i { display: none; }

/* ---- a call ------------------------------------------------------------
   Three cells: where the band floors, where it ceilings, and the move
   between them. The arrow is not decoration — it tilts with the call, so
   direction is legible before any number is read.

   The row is a button spanning the column edge to edge, because a list
   of cards with margins would put the selection's fill in a box and the
   selection is a state of the ROW. */
/* the layout is shared above; this is only what makes it a control */
.hx-call {
  position: relative;
  width: 100%;
  text-align: left;
  transition: background var(--fast) var(--ease);
}

.hx-call:focus-visible { outline: none; box-shadow: inset 0 0 0 1px rgba(var(--tone), 0.35); }

/* THE SELECTION USED TO WIPE IN FROM THE LEFT — a ::before at inset 0,
   scaled from zero on the x-axis, carrying the same fill. It was written
   for a row that ran the full width of the column with square corners, and
   it survived the row being inset and given a 14px radius. So the current
   row painted its fill TWICE: once rounded, by the element, and once
   square, by a pseudo-element sitting on top at exactly the same colour.
   The seam where the square overhung the curve is what you could see.

   Gone, along with the stacking it needed and the three text rules that
   styled cells this row no longer has. The fill is on the element, where a
   radius applies to it.
*/

/* TWO ROWS, not three cells with their own stacks: the figures and the
   arrow share the top row, the captions and the move share the bottom
   one. That is the whole fix for the arrow sitting high — it is a grid
   item on the same row as the numbers now, centred against them, rather
   than a column of its own guessing at their height with a padding.
   The move lands level with Min and Max for the same reason. */
.hx-band {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  column-gap: 14px; row-gap: 10px;
}
.hx-fig {
  font-family: var(--sans);
  font-size: clamp(20px, 1.95vw, 28px);
  line-height: 1.05;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--t-primary);
  white-space: nowrap;
}
.hx-cap { font-family: var(--sans); font-size: 12px; color: var(--t-dim); }

/* The arrow carries the weight of the type it stands between. Drawn at a
   hairline it read as a stray rule between two numbers; at 2 it is a
   mark, which is what it is — the one thing on the row saying that these
   two figures are a journey rather than a pair.

   It does NOT lean with the call any more. Direction is the percentage's
   job and the percentage is already coloured; a tilted arrow was a second
   voice saying the same thing a third of a degree less clearly. */
.hx-arrow {
  width: clamp(24px, 1.7vw, 34px); height: auto;
  fill: none; stroke: var(--t-second); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: stroke var(--fast) var(--ease);
}
.hx-call:hover .hx-arrow, .hx-call[aria-current="true"] .hx-arrow { stroke: var(--t-primary); }
.hx-move {
  justify-self: center;
  /* Lifted a few pixels off its own row. Min and Max belong to the
     figures above them; the move belongs to the ARROW, and sat exactly
     level with the captions it read as a third caption. Four pixels is
     enough to group it upward without breaking the line the row is on —
     a transform, so it takes no layout with it. */
  transform: translateY(-4px);
  font-family: var(--sans); font-size: 12.5px;
  font-variant-numeric: tabular-nums;
}
.hx-call[data-dir="up"] .hx-move { color: var(--up); }
.hx-call[data-dir="down"] .hx-move { color: var(--down); }

/* ---------------------------------------------------------------
   5. THE NAME
   --------------------------------------------------------------- */

.hx-quote { padding: 0 var(--hx-pad) 22px; }

/* THE NAME AND THE PRICE, at one size. They are the two facts this
   column exists to state, and setting the price larger than the company
   it belongs to says the number matters and the company does not — which
   is exactly backwards on a page about why a name is going to move.

   32px is the figure: large enough to be the first thing read at a
   glance across three columns, small enough that a long company name —
   "Advanced Micro Devices" — still gets a line to itself before the
   ellipsis, which 44 did not. The clamp lets it give way on a narrow
   column so a four-digit price with decimals stays on one line. */
.hx-co,
.hx-px {
  font-family: var(--sans);
  font-size: clamp(24px, 2.2vw, 32px);
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -0.03em;
  color: var(--t-primary);
}
.hx-co {
  /* the company can be long; the price never wraps */
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.hx-px {
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
}
.hx-delta {
  display: flex; align-items: center; gap: 8px;
  margin-top: 14px;
  font-family: var(--sans); font-size: 13.5px;
  font-variant-numeric: tabular-nums;
  color: var(--t-dim);
}
.hx-delta b { font-weight: 400; }
.hx-delta[data-dir="up"] .hx-pct, .hx-delta[data-dir="up"] .hx-abs { color: var(--up); }
.hx-delta[data-dir="down"] .hx-pct, .hx-delta[data-dir="down"] .hx-abs { color: var(--down); }
.hx-caret { width: 11px; height: 11px; flex: none; fill: currentColor; }
.hx-delta[data-dir="up"] .hx-caret { color: var(--up); }
.hx-delta[data-dir="down"] .hx-caret { color: var(--down); transform: rotate(180deg); }

/* ---- the chart ---------------------------------------------------------
   One session, drawn as one line. It carries no axes and no gridlines on
   purpose: the numbers under it are the axis, and a chart this small with
   a scale on it is a chart with less line in it.

   It DRAWS rather than appearing — left to right, once, at the speed a
   session would have taken. No glow under the stroke; the area beneath is
   a flat wash of the same hue, which is what gives the line a floor
   without giving it a halo. */
.hx-chart { margin-top: 26px; height: clamp(150px, 15vh, 190px); }
.hx-chart svg { width: 100%; height: 100%; overflow: visible; }
.hx-line {
  fill: none; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
  stroke: var(--down);
}
.hx-chart[data-dir="up"] .hx-line { stroke: var(--up); }
.hx-area { stroke: none; fill: url(#hx-fade-down); }
.hx-chart[data-dir="up"] .hx-area { fill: url(#hx-fade-up); }
.hx-chart[data-draw] .hx-line { animation: hx-draw 900ms var(--ease-io) both; }
.hx-chart[data-draw] .hx-area { animation: hx-wash 900ms var(--ease-io) both; }
@keyframes hx-draw { from { stroke-dashoffset: var(--len); } to { stroke-dashoffset: 0; } }
@keyframes hx-wash { from { opacity: 0; } to { opacity: 1; } }

/* ---- how far back ------------------------------------------------------
   Seven words under the line. They are not chips and not tabs: a range is
   a setting, and the one in force is said by a fill the width of the word
   rather than by a bar under a row of them — there is no row to underline
   when the widths differ this much.

   Mono, because they are labels rather than reading, and because 1D and
   YTD have to sit on the same rhythm at different lengths. */
.hx-range {
  /* Spread across the full measure, not bunched at the left with dead
     room after 5Y. The row is a scale — it runs the width of the thing it
     scales, and the ends of it are the ends of the chart. */
  display: flex; justify-content: space-between; align-items: center;
  gap: 4px;
  margin-top: 16px;
}
.hx-range-b {
  padding: 5px 4px;
  /* Sans, not the mono the rest of this page's small print is set in.
     These are not labels over data — they are the one row you press, and
     a monospaced 1D beside a monospaced YTD sets three characters in the
     width of two and reads as a table of contents. */
  font-family: var(--sans); font-size: 13px;
  letter-spacing: 0.01em;
  color: var(--t-dim);
  transition: color var(--fast) var(--ease);
}
.hx-range-b:hover { color: var(--t-second); }
/* The chosen one takes the LINE'S colour rather than a fill. Nothing on
   this page is filled except the day in the week strip, and a second
   filled pill four inches below it reads as a second selection of the
   same kind. Colour ties the range to the chart it drew. */
.hx-range-b[aria-pressed="true"] { color: var(--up); }
.hx-quote[data-dir="down"] .hx-range-b[aria-pressed="true"] { color: var(--down); }
.hx-range-b:focus-visible { outline: none; box-shadow: 0 0 0 1px rgba(var(--tone), 0.4); border-radius: 5px; }

/* ---- the scrub ----------------------------------------------------------
   A rule through the chart, the time above it, and the line dimmed past
   it. No tag on the line: the price is already at the top of the column
   at 32px, and hovering makes THAT read the moment — so there is one
   place to look rather than two, one of them small and moving. */

/* room for the stamp to stand in, above the frame */
.hx-chart-wrap { position: relative; padding-top: 22px; }

.hx-stamp {
  position: absolute; top: 0; left: 0;
  transform: translateX(-50%);
  font-family: var(--sans); font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--t-second);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 120ms linear;
}
.hx-chart-wrap[data-live] .hx-stamp { opacity: 1; }

.hx-cross {
  stroke: rgba(var(--tone), 0.35);
  stroke-width: 1;
  opacity: 0;
  transition: opacity 120ms linear;
}
.hx-chart[data-live] .hx-cross { opacity: 1; }

/* The line goes quiet while a moment is being read, and the part up to
   the end of that DAY is drawn back over it at full strength. Cutting on
   the day rather than at the pointer is what makes the lit part a unit of
   trading instead of an arbitrary slice through one. */
.hx-line { transition: opacity 120ms linear; }
.hx-chart[data-live] .hx-line { opacity: 0.38; }
.hx-lit {
  fill: none; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
  stroke: var(--down);
  pointer-events: none;
}
.hx-chart[data-dir="up"] .hx-lit { stroke: var(--up); }

.hx-dot { fill: var(--ink); stroke-width: 1.6; stroke: var(--down); opacity: 0; }
.hx-chart[data-dir="up"] .hx-dot { stroke: var(--up); }
.hx-chart[data-live] .hx-dot { opacity: 1; }

/* ---- the numbers under it ---------------------------------------------- */
.hx-stats {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: 22px;
  padding: 16px var(--hx-pad) 18px;
  border-top: 1px solid var(--hair);
}
.hx-stat {
  display: flex; align-items: baseline; gap: 10px;
  min-height: 25px;
  font-family: var(--sans); font-size: 13px;
}
.hx-stat dt { flex: 1; min-width: 0; color: var(--t-second); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.hx-stat dd { margin: 0; color: var(--t-primary); font-variant-numeric: tabular-nums; }
.hx-stat dd[data-dir="up"] { color: var(--up); }
.hx-stat dd[data-dir="down"] { color: var(--down); }
.hx-all-row { grid-column: 2; }
.hx-all-row dd { margin: 0; }
.hx-all {
  width: 100%;
  display: flex; align-items: center; justify-content: space-between;
  min-height: 25px;
  font-family: var(--sans); font-size: 13px; color: var(--t-second);
  transition: color var(--fast) var(--ease);
}
.hx-all:hover { color: var(--t-primary); }
.hx-all svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }

/* ---- the news ----------------------------------------------------------- */
.hx-news { border-top: 1px solid var(--hair); padding: 16px var(--hx-pad) 40px; }
.hx-news-head { font-family: var(--sans); font-size: 14px; color: var(--t-second); margin-bottom: 6px; }
.hx-item { display: block; width: 100%; text-align: left; padding: 14px 0; border-bottom: 1px solid var(--hair-soft); }
.hx-item:last-child { border-bottom: 0; }
.hx-item-top { display: flex; align-items: baseline; gap: 10px; margin-bottom: 8px; }
.hx-item-src { font-family: var(--sans); font-size: 13.5px; color: var(--t-primary); }
.hx-item-ago { font-family: var(--mono); font-size: var(--mono-size); letter-spacing: var(--mono-track); color: var(--t-dim); }
.hx-item-head {
  font-family: var(--sans); font-size: 13.5px; line-height: 1.45;
  color: var(--t-second); margin-bottom: 10px;
  transition: color var(--fast) var(--ease);
}
.hx-item:hover .hx-item-head { color: var(--t-primary); }
.hx-item-tag {
  display: inline-flex; align-items: baseline; gap: 8px;
  font-family: var(--sans); font-size: 12.5px;
  font-variant-numeric: tabular-nums;
}
.hx-item-tag b { font-weight: 400; color: var(--t-second); }
.hx-item-tag span { color: var(--up); }

/* ---------------------------------------------------------------
   6. THE BREAKDOWN
   --------------------------------------------------------------- */

.hx-brief-body { padding: 0 0 40px; display: flex; flex-direction: column; }

/* SECTIONS, not cards. Three bordered panels stacked in a column drew
   three lids and three floors to say what two lines already say — and a
   card is a promise that the whole of it does something, which here is
   untrue: only Read more answers a press.

   So each one is a band running the full width of the column, divided
   from the next by the same hairline the headers use. The column reads
   as one document with three parts, which is what it is. No hover fill,
   for the same reason there is no card: nothing here is a target except
   the word that says it is. */
.hx-card {
  padding: 16px var(--hx-pad) 18px;
  border-bottom: 1px solid var(--hair-soft);
}
/* the last band has the column's own end below it, and needs no floor */
.hx-card:last-child { border-bottom: 0; }
.hx-card-top { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.hx-card-name { flex: 1; min-width: 0; font-family: var(--sans); font-size: 13.5px; color: var(--t-second); }
.hx-card-title { font-family: var(--sans); font-size: 17px; letter-spacing: -0.01em; color: var(--t-primary); margin-bottom: 4px; }
.hx-card-when { font-family: var(--sans); font-size: 12.5px; color: var(--t-dim); margin-bottom: 10px; }

/* The body is clamped to five lines closed and runs free open. Clamping
   is what makes the column a summary rather than three essays — and the
   line count, rather than a pixel height, is what keeps every card
   ending on a whole line instead of through the middle of one. */
.hx-card-body {
  font-family: var(--sans); font-size: 13px; line-height: 1.62;
  color: var(--t-second);
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 5; line-clamp: 5;
  overflow: hidden;
}
.hx-card[data-open] .hx-card-body { -webkit-line-clamp: unset; line-clamp: unset; display: block; }
.hx-card-body p + p { margin-top: 10px; }

/* ---------------------------------------------------------------
   6b. THE RUN MENU, AND A ROW MID-RENAME
   --------------------------------------------------------------- */
/* Drop's own menu, because this is Drop's own rail. The recipe is the
   one wall.css sets out: the menu carries its own GROUND and then the
   tone step on top — ink under a wash rather than a hand-mixed grey — so
   the whole thing flips with the theme instead of being a dark panel
   that survives the light one by luck. Held just short of opaque and
   blurred, which is what makes it read as glass over the page rather
   than a hole cut in it. */
.hx-menu {
  position: fixed; z-index: 70;
  min-width: 172px;
  padding: 6px;
  border-radius: 12px;
  background:
    linear-gradient(rgba(var(--tone), 0.1), rgba(var(--tone), 0.1)),
    rgba(var(--ink-tone), 0.82);
  backdrop-filter: blur(18px) saturate(1.4);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
.hx-menu[hidden] { display: none; }
/* Where the blur cannot be had, the surface closes up instead: a
   translucent menu with nothing softening what is behind it is the
   unreadable case this rule exists to prevent. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .hx-menu {
    background:
      linear-gradient(rgba(var(--tone), 0.1), rgba(var(--tone), 0.1)),
      rgb(var(--ink-tone));
  }
}
.hx-opt {
  padding: 9px 12px;
  border-radius: 8px;
  font-family: var(--sans); font-size: 14px;
  color: var(--t-second);
  cursor: pointer;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.hx-opt:hover, .hx-opt:focus-visible { background: var(--btn-bg); color: var(--t-primary); outline: none; }

/* ---- a row that has become a field --------------------------------------
   The seat the row leaves behind while it is being renamed — same height,
   same inset, so the list does not jump as the name turns into a field.

   The field is the row's REPLACEMENT rather than something pushed inside
   it: the row is a button, and a text input inside a button is a control
   inside a control — invalid markup, and a field the pointer has to
   fight the button for.

   Three of the site's loudest defaults would land on it at once, because
   it opens focused with the whole name selected: the browser's own inset
   border, the white focus ring standing off the rail, and ::selection
   inverting the name into a white block. Each is right somewhere else.
   None belongs on a row whose state is already being said by the fact
   that it has become a field — so all three are answered from the
   inside, in the page's own tone. */
.hx-run--edit { cursor: default; }
.hx-rename {
  width: 100%; min-width: 0;
  padding: 2px 6px; margin: 0 -6px;
  border-radius: 6px;
  background: rgba(var(--tone), 0.1);
  font: inherit; color: var(--t-primary);
  user-select: text; -webkit-user-select: text;
}
.hx-rename:focus, .hx-rename:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px rgba(var(--tone), 0.4);
}
.hx-rename::selection { background: rgba(var(--tone), 0.3); color: var(--t-primary); }

/* ---------------------------------------------------------------
   6c. THE LIBRARY
   --------------------------------------------------------------- */
/* A library is BROWSED rather than read down: a wall of things you scan
   for the one you recognise, rather than a column you go through in
   order. So it takes the width and lays them side by side, and the cards
   size themselves — auto-fill, so the number across follows the window
   instead of a breakpoint deciding it. */
.hx-lib-find {
  flex: 0 1 240px; min-width: 0;
  height: 30px;
}

.hx-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
  align-content: start;
  gap: 14px;
  padding: 18px var(--hx-pad) 40px;
}

/* One prompt. Title, then enough of the text to recognise it by, then
   what it has produced — a card that said only its name would be a list
   with more space around it. */
.hx-lib {
  display: flex; flex-direction: column;
  min-height: 200px;
  padding: 16px;
  border: 1px solid var(--hair-soft);
  border-radius: 14px;
  background: var(--hx-panel);
  text-align: left;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.hx-lib:hover { background: var(--hx-panel-hi); border-color: var(--hair); }
.hx-lib:focus-within { border-color: var(--chip-hi); }

.hx-lib-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 10px; }
.hx-lib-tag {
  padding: 3px 8px; border-radius: 999px;
  background: var(--chip);
  font-family: var(--sans); font-size: 11px; color: var(--t-second);
}
/* The title is the door, and it is a button so a keyboard has one stop
   per card rather than none. The rest of the card is clickable too — a
   pointer should not have to find the four words that are the link. */
.hx-lib-title {
  display: block; width: 100%; text-align: left;
  font-family: var(--sans); font-size: 15px; line-height: 1.3;
  letter-spacing: -0.01em; color: var(--t-primary);
  margin-bottom: 8px;
}
.hx-lib { cursor: pointer; }
.hx-lib-title:focus-visible { outline: none; }
/* Four lines closed, and the whole thing open. The clamp is what keeps
   the grid a grid — one card running to its full length would set the
   height of every card in its row. */
.hx-lib-body {
  flex: 1;
  font-family: var(--sans); font-size: 12.5px; line-height: 1.55;
  color: var(--t-second);
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 4; line-clamp: 4;
  overflow: hidden;
}
.hx-lib-foot {
  display: flex; align-items: center; gap: 10px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--hair-soft);
}
.hx-lib-when {
  flex: 1; min-width: 0;
  font-family: var(--sans); font-size: 12px; color: var(--t-dim);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
/* The one verb on the card. Held quiet until the card is under the
   pointer — a wall of cards each wearing a filled button reads as a wall
   of buttons, and the thing being chosen is the prompt. */
.hx-lib-go {
  flex: none;
  padding: 5px 12px; border-radius: 999px;
  background: rgba(var(--tone), 0.1);
  font-family: var(--sans); font-size: 12.5px;
  color: var(--t-second);
  opacity: 0;
  transition: opacity var(--fast) var(--ease), background var(--fast) var(--ease),
              color var(--fast) var(--ease);
}
.hx-lib:hover .hx-lib-go,
.hx-lib-go:focus-visible { opacity: 1; }
.hx-lib-go:hover { background: var(--paper); color: var(--ink); }

.hx-lib-empty {
  grid-column: 1 / -1;
  padding: 24px 4px;
  font-family: var(--sans); font-size: 13px; color: var(--t-dim);
}

/* A pointer is not the only way in: without this the verb is invisible
   to a keyboard until it is focused, which is one press too late. */
@media (hover: none) {
  .hx-lib-go { opacity: 1; }
}

/* ---- one prompt, read ---------------------------------------------------
   The grid is for finding; this is for reading. So the card's four-line
   clamp is not lifted in place — a card that grows to two thousand words
   is a card that has stopped being one — and the prompt gets the room
   instead, set as the document it is, with the way back where the search
   used to be.

   It is capped and centred. The area is as wide as three columns, and a
   prompt set across all of it would be a measure nobody finishes a line
   of; the shelf uses the width, the document uses a measure. */
.hx-one {
  max-width: 760px;
  margin: 0 auto;
  padding: 30px var(--hx-pad) 60px;
}
.hx-one-title {
  font-family: var(--sans); font-size: 24px; line-height: 1.2;
  letter-spacing: -0.02em; color: var(--t-primary);
  margin-bottom: 8px;
}
.hx-one-when {
  font-family: var(--sans); font-size: 13px; color: var(--t-dim);
  margin-bottom: 22px;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--hair-soft);
}
.hx-one .hx-doc { font-size: 14px; }

/* the header's two faces */
.hx-back { margin-bottom: 0; flex: none; }
.hx-back .back-arrow { stroke-linecap: round; }
.hx-library[data-mode="grid"] .hx-back,
.hx-library[data-mode="grid"] .hx-one-go,
.hx-library[data-mode="grid"] .hx-one { display: none; }
/* These three labels are PAGE names, not column names. The desk's own
   headers — Prompt, Predictions, Breakdown — are quiet category markers
   over the thing they head, and belong at the second tone because the
   column beneath them is what you are reading. Compass, Metrics and the
   Library each head a view with nothing else at the top of it, so the
   label IS the title, and it takes the site's own column-title role:
   20px, primary, and the tracking that goes with it. */
.hx-library .hx-label,
.hx-compass .hx-label,
.hx-metrics .hx-label {
  font-size: var(--title);
  letter-spacing: -0.015em;
  color: var(--t-primary);
}

/* ---- the full-window views' inset -------------------------------------
   Compass, Metrics and the Library are PAGES, not columns: each fills the
   window on its own rather than standing one of five in a row, so they
   take a page's margin instead of the columns' tighter --hx-pad. One
   figure across all three — 24 down both sides, and 24 above the title —
   because a visitor moving between them is moving between views of the
   same instrument, and an inset that changes on the way says they are
   three different pieces of software.

   The header stops being a fixed band here and becomes the top of a
   document, which is why the height gives way to its content while
   keeping the band's old height as a floor. */
.hx-library .hx-head,
.hx-compass .hx-head,
.hx-metrics .hx-head {
  height: auto;
  min-height: var(--hx-head);
  padding: 24px 24px 0;
}
/* the inline inset only: what each view puts above and below its own
   first line is its own rhythm, and the cards, the prompt and the tables
   do not want the same one */
.hx-library .hx-cards,
.hx-library .hx-one { padding-inline: 24px; }
/* Compass and Metrics take the same figure in their own rules further
   down — a padding shorthand declared after this one would win, and two
   declarations quietly fighting over one edge is how an inset drifts. */

.hx-library[data-mode="one"] .hx-lib-find,
.hx-library[data-mode="one"] .hx-label,
.hx-library[data-mode="one"] .hx-cards { display: none; }
/* With the label gone there is nothing flexing between the controls, so
   the FIRST verb takes the slack and the pair holds the far end together. */
.hx-one-go { margin-left: 0; }
/* One verb again, so it takes the slack itself and holds the far end.
   #library-new sat beside it until the button was removed. */
#library-run { margin-left: auto; }

/* ---- what a model handed back ------------------------------------------- */
.hx-lib-paste { flex: none; }
.hx-library[data-mode="one"] .hx-lib-paste { display: none; }

.hx-paste {
  display: block; width: 100%;
  min-height: 200px; resize: vertical;
  margin-top: 4px; padding: 12px 14px;
  border-radius: 12px;
  background: rgba(var(--tone), 0.06);
  box-shadow: inset 0 0 0 1px var(--hair);
  /* Mono, and tracking off: what goes in here is JSON, and a proportional
     face turns a shape you are meant to be able to check at a glance into
     prose. */
  font-family: var(--mono); font-size: 12px; letter-spacing: 0;
  line-height: 1.5; color: var(--t-primary);
}
.hx-paste::placeholder { color: var(--t-faint); }
.hx-paste:focus-visible { outline: none; box-shadow: inset 0 0 0 1px rgba(var(--tone), 0.4); }

.hx-paste-err {
  margin: 12px 0 0;
  font-family: var(--sans); font-size: 12.5px; color: var(--warn);
}
.hx-paste-err[hidden] { display: none; }

.hx-paste-go {
  width: 100%; height: 44px;
  margin-top: 16px;
  border-radius: 999px;
  background: var(--paper); color: var(--ink);
  font-family: var(--sans); font-size: 14px;
  transition: opacity var(--fast) var(--ease);
}
.hx-paste-go:hover { opacity: 0.87; }
.hx-paste-go[data-busy] { opacity: 0.5; pointer-events: none; }

/* ---------------------------------------------------------------
   7. THE CONNECTOR SHEET
   --------------------------------------------------------------- */

.hx-sheet {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center;
  padding: 24px;
  background: rgba(var(--ink-tone), 0.72);
  opacity: 0;
  transition: opacity 200ms var(--ease);
}
.hx-sheet[hidden] { display: none; }
.hx-sheet[data-on] { opacity: 1; }
.hx-sheet-card {
  width: min(520px, 100%);
  max-height: min(640px, 86vh);
  display: flex; flex-direction: column;
  border: 1px solid var(--hair);
  border-radius: 20px;
  background: var(--ink);
  padding: 24px;
  transform: translateY(8px) scale(0.985);
  transition: transform 260ms var(--ease-soft);
}
.hx-sheet[data-on] .hx-sheet-card { transform: none; }
.hx-sheet-top { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.hx-sheet-title { flex: 1; font-family: var(--sans); font-size: 17px; color: var(--t-primary); }
.hx-sheet-say { font-family: var(--sans); font-size: 13px; line-height: 1.62; color: var(--t-second); margin-bottom: 16px; }
.hx-sheet-say b { font-weight: 400; color: var(--t-primary); }
.hx-endpoint {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 10px;
  background: rgba(var(--tone), 0.07);
  margin-bottom: 18px;
}
.hx-endpoint code {
  flex: 1; min-width: 0;
  font-family: var(--mono); font-size: 12px; letter-spacing: 0;
  color: var(--t-second);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.hx-tools {
  overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--hair) transparent;
  mask-image: linear-gradient(to bottom, #000 calc(100% - 26px), transparent);
}
.hx-tool { padding: 10px 0; border-top: 1px solid var(--hair-soft); }
.hx-tool code {
  font-family: var(--mono); font-size: 12px; letter-spacing: 0;
  color: var(--t-primary);
}
.hx-tool p { margin: 4px 0 0; font-family: var(--sans); font-size: 12.5px; line-height: 1.5; color: var(--t-dim); }

/* ---------------------------------------------------------------
   8. THE ENTRANCE
   --------------------------------------------------------------- */
/* Five columns arriving as five columns: each rule wipes down from the
   nav, and its column's contents rise into place a beat behind it. The
   stagger runs left to right because that is the reading order the page
   is built on — the instrument assembles in the direction you will use
   it, rather than fading up as one slab.

   Nothing here moves layout: a transform and an opacity per column.

   THE RAIL IS NOT PART OF IT. Everything to the right of it is a reading
   that arrives — the day's calls, a name's detail — and watching those
   assemble is watching the instrument come up. The rail is not a reading.
   It is the furniture the readings arrive into: the same three views and
   the same week of sessions every time the page loads, in the same places.
   Fading it up says a list of destinations is news, and it costs the one
   thing that column is for, which is being able to press Compass the
   instant you can see it. Drop's sidebar has never animated in, and these
   two rails are meant to be one component. */
.hedge[data-in] .hx-col + .hx-col::before {
  animation: hx-rule 460ms var(--ease-soft) both;
  animation-delay: calc(var(--i) * 70ms);
}
.hedge[data-in] .hx-col:not(.hx-rail) > * {
  animation: hx-rise 560ms var(--ease-soft) both;
  animation-delay: calc(var(--i) * 70ms + 90ms);
}
@keyframes hx-rule { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes hx-rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* A call arriving from the model mid-run. Same rise, one row at a time,
   written per row as --d — this is the motion the MCP fill produces, so
   it is the motion the mock has to produce too. */
.hx-call[data-new] { animation: hx-rise 420ms var(--ease-soft) both; animation-delay: var(--d, 0ms); }

/* A column whose subject just changed. Not the entrance again — that
   would re-stagger the whole instrument for a click inside one part of
   it — but the same rise, short, so the eye is told which two columns
   answered the row it pressed. */
.hx-swap { animation: hx-rise 340ms var(--ease-soft) both; }

@media (prefers-reduced-motion: reduce) {
  .hedge[data-in] .hx-col + .hx-col::before,
  .hedge[data-in] .hx-col > *,
  .hx-call[data-new],
  .hx-swap { animation: none; }
  .hx-chart[data-draw] .hx-line, .hx-chart[data-draw] .hx-area { animation: none; }
}

/* ---------------------------------------------------------------
   9. THE BAND
   --------------------------------------------------------------- */
/* The band needs a floor of its own. Every other rule on this page is
   vertical; this is the one horizontal edge the layout invents, and
   without it the prompt and the three columns read as one long column
   that changed its mind. */
.hx-ask { border-bottom: 1px solid var(--hair); }
/* and it is not a card in the deck — snapping to it would scroll the
   three readings off to land on a band that is already fully visible */
.hx-ask { scroll-snap-align: none; }

/* THREE LINES, and the rest behind a word. A band is a glance: enough of
   the question to know which one it is, which is what the first sentence
   of a prompt is for. The clamp counts LINES rather than taking a height,
   so the band always ends on a whole line however wide the window is. */
.hx-ask .hx-body { overflow: hidden; }
.hx-ask .hx-doc {
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 3; line-clamp: 3;
  overflow: hidden;
}
.hx-ask .hx-prompt-body { padding-bottom: 18px; }

/* Opened — or being edited, which is the same need. The band takes a
   share of the window and scrolls inside it rather than growing until it
   has pushed the three readings off the bottom. */
.hx-ask[data-open] .hx-doc { display: block; }
.hx-ask[data-open] .hx-body { overflow-y: auto; max-height: 46vh; }
.hx-ask .hx-edit { min-height: 32vh; }

/* ---- narrower than the band ---------------------------------------------
   Below about 1024 the three readings no longer fit beside the rail and
   the deck starts scrolling sideways. That costs the prompt band two
   things, because the band is as wide as all three columns put together:
   its controls sit at the far right, where they scroll out of the
   window, and its text sets to a measure wider than the window it is
   being read in.

   Both are answered by giving the band a left edge to live on. */
@media (max-width: 1023px) {
  /* The controls come back to the label rather than holding the band's
     far corner — a corner that is now off-screen. */
  .hx-ask .hx-label { flex: none; }

  /* And the text stops at a measure you can read without pushing the
     page sideways. This is a cap, not a width: the band is still as wide
     as the three columns beneath it, the sentence inside it is not. */
  .hx-ask .hx-prompt-title,
  .hx-ask .hx-doc { max-width: 68ch; }
}

/* ---------------------------------------------------------------
   10. NARROWER — the deck
   --------------------------------------------------------------- */
@media (max-width: 900px) {
  /* The rail stops holding its ground and joins the deck. Pinned, it
     would eat a third of a window this size for a column of single
     words; hidden, it would take the run switcher with it and leave no
     way back to the other runs at all. Standing in the deck it is
     neither — the first card in a row you push along, one swipe to the
     left of where you started. Its width does not change: see the note
     on --rail-w. */
  .hx-rail { position: static; }
}


/* The Breakdown's drag handle and its rules went with the column it
   resized. See scripts/hedge.js for what its leftover markup cost. */

/* ---- the ledger: what was predicted, beside what happened ---------------
   The accountability layer. It sits under the three brief cards because it
   answers a later question than they do: they say why the call was made,
   this says whether it was any good.

   The pair splits on the COLUMN's width, not the window's — a container
   query, because this module has to read correctly both in a 375px rail
   and in a wide detail sheet, and the viewport tells it nothing useful
   about which one it is in. */
.hx-ledger {
  container-type: inline-size;
  padding: var(--hx-pad) var(--hx-pad) calc(var(--hx-pad) * 2);
  border-top: 1px solid var(--hair);
}

.hx-led-head {
  display: flex; align-items: baseline; gap: 8px;
  margin-bottom: 18px;
}
.hx-led-date { font-family: var(--sans); font-size: 13px; color: var(--t-second); }
.hx-led-word { font-family: var(--mono); font-size: 11px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--t-dim); }

/* ---- the lifecycle ------------------------------------------------------
   Four steps, one of them current, and the contrast does the explaining:
   finished is white, current is white on a raised ground, still-to-come is
   dim enough that you do not read it as a claim about anything yet. No
   progress bar — a bar implies a proportion, and "Called → Live" is not
   forty per cent of anything. */
.hx-life {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 4px; margin: 0 0 20px; padding: 0; list-style: none;
}
.hx-life-step {
  display: flex; flex-direction: column; gap: 7px;
  padding: 10px 10px 11px;
  border-radius: 12px;
  min-width: 0;
}
/* only the current step gets a ground. Giving every step one would make
   four boxes and no answer to "where are we". */
.hx-life-step[data-state="now"] {
  background: rgba(var(--tone), 0.055);
}

.hx-life-dot {
  display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: 50%;
  font-family: var(--sans); font-size: 12.5px; line-height: 1;
  background: rgba(var(--tone), 0.07);
  color: var(--t-dim);
}
.hx-life-step[data-state="done"] .hx-life-dot {
  background: var(--paper); color: var(--ink);
}
.hx-life-step[data-state="now"] .hx-life-dot {
  background: rgba(var(--tone), 0.16); color: var(--paper);
}

.hx-life-name { font-family: var(--sans); font-size: 14px; color: var(--t-dim); }
/* Wraps rather than truncates. Four steps in a 375px column gives each
   about ninety pixels, and "Aug 5, 6:30 PM" wants more — an ellipsis there
   would throw away the half of the stamp that says WHEN. */
.hx-life-at   { font-family: var(--sans); font-size: 11.5px; color: var(--t-dim);
  opacity: 0.72; line-height: 1.3; }
.hx-life-step[data-state="done"] .hx-life-name,
.hx-life-step[data-state="now"]  .hx-life-name { color: var(--paper); }
.hx-life-step[data-state="ahead"] .hx-life-name,
.hx-life-step[data-state="ahead"] .hx-life-at { opacity: 0.45; }

/* ---- the pair ----------------------------------------------------------
   A matched pair, not two widgets: the same ground, the same field order,
   one hairline between them. The eye compares by moving sideways one row
   at a time, which only works if row three on the left and row three on
   the right are the same question. */
.hx-led-pair {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 1px;
  background: var(--hair);          /* the hairline IS the gap */
  border: 1px solid var(--hair);
  border-radius: 14px;
  overflow: hidden;
}
@container (min-width: 560px) {
  .hx-led-pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.hx-led-card {
  background: rgba(var(--tone), 0.028);
  padding: 16px var(--hx-pad) 18px;
  min-width: 0;
}
.hx-led-label {
  margin: 0 0 10px;
  font-family: var(--sans); font-size: 13px; font-weight: 400;
  color: var(--t-second);
}
.hx-led-figure {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  font-size: clamp(22px, 2vw, 28px); font-weight: 400; line-height: 1.1;
  margin-bottom: 16px;
}
.hx-led-pct { font-size: 14px; color: var(--t-second); }
.hx-led-pct[data-dir="up"]   { color: var(--up); }
.hx-led-pct[data-dir="down"] { color: var(--down); }

/* Before the bell there is no outcome, and the card says which — it does
   not print zeroes that look like results. §15. */
.hx-led-card[data-pending] { opacity: 0.6; }
.hx-led-wait { font-size: 14px; color: var(--t-dim); }

.hx-led-fields { margin: 0; display: grid; gap: 0; }
.hx-led-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline; gap: 12px;
  padding: 7px 0;
  border-top: 1px solid rgba(var(--tone), 0.06);
}
.hx-led-row:first-child { border-top: 0; }
.hx-led-row dt { font-family: var(--sans); font-size: 13px; color: var(--t-dim); }
.hx-led-row dd { margin: 0; font-family: var(--sans); font-size: 13px;
  color: var(--paper); text-align: right; }
/* Scoring words stay neutral. Only a level the price actually broke takes
   a colour, and it takes the DOWNSIDE colour because that is what it means
   financially — not because the desk lost a point. "Not reached" gets
   nothing: a forecast that did not get there is a statement about the
   forecast, not a bearish event, and colouring it orange would turn this
   card into the scoreboard §17 says it must not become. */
.hx-led-row dd[data-t="broke"] { color: var(--down); }

/* ============================================================
   THE SHELL, second pass — rail nav, the board, the sheet.
   ============================================================ */

/* ---- the rail's three places -------------------------------------------- */
/* The rail's nav and its section heading are defined once, on Drop's
   measurements, at the foot of this file. */

/* ---- the sessions ------------------------------------------------------- */
/* The session rows are defined once, on Drop's measurements, at the foot
   of this file. */

/* ---- the board --------------------------------------------------------- */
.hx-list-top {
  display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
  padding: 18px var(--hx-pad) 14px;
}
.hx-list-date {
  margin: 0; font-family: var(--sans);
  font-size: clamp(19px, 1.5vw, 23px); font-weight: 400; line-height: 1.15;
  color: var(--paper);
}
/* A pill, because it is a control and the things around it are not. The
   key is white and the word "Sort by" is not: what changes is worth
   reading, the label is worth having. */
.hx-sort {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 12px 7px 14px;
  border-radius: 999px;
  background: rgba(var(--tone), 0.055);
  font-family: var(--sans); font-size: 13px;
  color: var(--t-dim); cursor: pointer;
  transition: background 120ms ease;
}
/* Actual ranks the market, and the market's order is not the reader's to
   change — so the pill leaves rather than sitting there inert. The rule is
   needed because .hx-sort sets a display of its own, which out-specifies
   the browser's [hidden]. */
.hx-sort[hidden] { display: none; }
.hx-sort:hover { background: rgba(var(--tone), 0.09); }
.hx-sort-key { color: var(--paper); }
.hx-sort svg { width: 13px; height: 13px; fill: none;
  stroke: var(--t-dim); stroke-width: 1.5; stroke-linecap: round; }

/* ---- the tiers --------------------------------------------------------- */
.hx-tier-name {
  padding: 16px var(--hx-pad) 8px;
  font-family: var(--sans); font-size: 13px; color: var(--t-dim);
}
/* A rank is a position in a list, so it is set as one: small, dim, and
   outside the row's own content. It is not a badge — a filled circle per
   row would put nine loud objects down the column and the loudest thing
   on a forecast board should be the forecast. */
.hx-rank {
  font-family: var(--sans); font-size: 11.5px; color: var(--t-dim);
  min-width: 14px; text-align: right;
}

/* ---- the sheet --------------------------------------------------------- */
.hx-detail { padding: 12px 12px 12px 0; min-width: 0; }
.hx-detail-card {
  height: 100%; min-height: 0;
  display: flex; flex-direction: column;
  overflow-y: auto; overflow-x: hidden;
  border: 1px solid var(--hair);
  border-radius: 20px;
  /* the background is --sheet, set once further down — this rule and the
     wide one below carried their own alphas for months with the later
     rule quietly overriding both. */
  container-type: inline-size;
  scrollbar-width: thin;
  scrollbar-color: var(--hair) transparent;
}
.hx-detail-head {
  display: flex; align-items: center; gap: 10px;
  padding: 16px var(--hx-pad) 0;
}
/* The card scrolls, so the hairline under the header would scroll with it
   and stop meaning "the header ends here". There is no hairline. */
.hx-detail-head .hx-sym { flex: 1; }

/* Catalyst and Metrics, side by side once the card is wide enough to hold
   two measures. Same container query family as the ledger below it, and
   the same reason: what matters is the CARD's width. */
.hx-two {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 1px; background: var(--hair);
  border-top: 1px solid var(--hair);
  margin-top: 4px;
}
@container (min-width: 560px) {
  .hx-two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.hx-panel { background: var(--ground, transparent); padding: 16px var(--hx-pad) 20px;
  min-width: 0; }
.hx-panel-top {
  display: flex; align-items: baseline; gap: 8px; margin-bottom: 14px;
}
.hx-panel-name { margin: 0; font-family: var(--sans); font-size: 13px;
  font-weight: 400; color: var(--t-second); }
.hx-panel-when { font-family: var(--sans); font-size: 12px; color: var(--t-dim); }
.hx-panel-top .hx-word { margin-left: auto; }
.hx-panel-title {
  font-family: var(--sans); font-size: 15px; line-height: 1.35;
  color: var(--paper); margin-bottom: 10px;
}
.hx-panel-body { font-family: var(--sans); font-size: 13.5px; line-height: 1.55;
  color: var(--t-second); }
.hx-panel-body p { margin: 0 0 10px; }
.hx-panel-body p:last-child { margin-bottom: 0; }

/* the metrics panel's rows — the same two-column measure the ledger uses,
   because they are the same kind of reading */
.hx-mrow {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline; gap: 12px; padding: 7px 0;
  border-top: 1px solid rgba(var(--tone), 0.06);
}
.hx-mrow:first-child { border-top: 0; }
.hx-mrow dt { font-family: var(--sans); font-size: 13px; color: var(--t-dim); }
.hx-mrow dd { margin: 0; font-family: var(--sans); font-size: 13px;
  color: var(--paper); text-align: right; }

/* The tier badge lived here, a ring beside the company name. It is out of
   the header: the board already bands every call under an A / B / C
   heading, so the letter was the same fact said twice — once where it
   groups things and once where it decorates one. */

/* ---- Compass ----------------------------------------------------------- */
.hx-compass-in {
  /* 24 down the sides, with this view's own rhythm above and below —
     the page inset every full-window view shares (see §the full-window
     views' inset) */
  display: grid; gap: 28px; padding: var(--hx-pad) 24px;
  grid-template-columns: minmax(0, 1fr);
  max-width: 1180px;
}
@container (min-width: 900px) { .hx-compass-in { grid-template-columns: 280px minmax(0, 1fr); } }
.hx-compass { container-type: inline-size; }
.hx-block-name { margin: 0 0 10px; font-family: var(--sans); font-size: 13px;
  font-weight: 400; color: var(--t-dim); }
.hx-prompt-block { max-width: 760px; }

/* ---- Metrics ----------------------------------------------------------- */
.hx-metrics-in { padding: var(--hx-pad) 24px; max-width: 900px; }

/* The rank sits in the row's first column, on the ticker's line, and the
   two figure rows below span both — so a two-column row becomes a
   three-column one without the figures re-wrapping. */
.hx-call { grid-template-columns: auto auto minmax(0, 1fr); }
.hx-call .hx-move-figs,
.hx-call .hx-move-cap { grid-column: 1 / -1; }
.hx-tier + .hx-tier .hx-tier-name { border-top: 1px solid var(--hair); }
.hx-mblock { margin-bottom: 28px; }
.hx-n { margin-left: 8px; font-size: 11.5px; color: var(--t-dim); }

/* ============================================================
   THE BOARD, as the design draws it.

   The row was a ticker with a catalyst headline beside it and the figures
   underneath. The design puts the COMPANY first and the ticker under it,
   the move and the band together on the right, and the confidence alone
   at the end — which is a different claim about what a row is for. The old
   row was about the event; this one is about the call. The event is one
   press away, in the sheet, where there is room to say it properly.

   No rules between rows. The selection is a filled shape, so a hairline
   under every row would put a line through the middle of it.
   ============================================================ */
.hx-call {
  display: grid;
  grid-template-columns: 16px 36px minmax(0, 1fr) auto auto;
  align-items: center;
  column-gap: 14px; row-gap: 0;
  width: 100%;
  padding: 11px 14px 11px 8px;
  margin: 0 calc(var(--hx-pad) - 14px);
  width: calc(100% - (var(--hx-pad) - 14px) * 2);
  border: 0; border-radius: 14px;
  background: none;
  text-align: left;
  transition: background 130ms var(--ease);
}
/* The same lift the rail's rows take. It was 0.04 against their 0.07, so
   the board felt less responsive than the sidebar for no reason anybody
   chose — the two lists are the same kind of list and a pointer over
   either should get the same answer. */
.hx-call:hover { background: rgba(var(--tone), 0.07); }
.hx-call[aria-current="true"] { background: rgba(var(--tone), 0.075); }

/* A MOVER IS A ROW, NOT A BUTTON. Every other row on this board opens a
   name in the sheet and can, because the desk holds a forecast, a chart
   and a catalyst for it. It holds none of those for a stock it never
   called, so the market rows keep the geometry and give up the lift — a
   hover that promises a press leading nowhere is worse than no hover. */
.hx-call[data-static] { cursor: default; }
.hx-call[data-static]:hover { background: none; }

.hx-rank { font-family: var(--sans); font-size: 12px; color: var(--t-dim);
  text-align: right; align-self: center; }

/* A logo slot. It is empty because there is no logo — a letter or a
   generated glyph in here would be decoration standing where a fact
   goes, and nine of them down the column would look like data. */
.hx-logo {
  width: 36px; height: 36px; border-radius: 50%;
  background: rgba(var(--tone), 0.11);
}

.hx-who { display: grid; gap: 2px; min-width: 0; }
.hx-who-name {
  font-family: var(--sans); font-size: 15px; line-height: 1.25;
  color: var(--paper);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hx-who-t {
  font-family: var(--mono); font-size: 11.5px;
  letter-spacing: var(--mono-track); text-transform: uppercase;
  color: var(--t-dim);
}

.hx-fig { display: grid; gap: 3px; justify-items: start; min-width: 0; }
.hx-fig-pct { font-family: var(--sans); font-size: 14.5px; color: var(--t-second); }
.hx-call[data-dir="up"]   .hx-fig-pct { color: var(--up); }
.hx-call[data-dir="down"] .hx-fig-pct { color: var(--down); }
.hx-fig-band {
  font-family: var(--sans); font-size: 13px; color: var(--t-second);
  white-space: nowrap;
}
.hx-fig-band i { font-style: normal; color: var(--t-dim); padding: 0 2px; }

.hx-conf { font-family: var(--sans); font-size: 14px; color: var(--paper);
  justify-self: end; }

/* The tier label sits on the rows' own left edge, not on the column's. */
.hx-tier-name { padding-left: calc(var(--hx-pad) + 8px); }
.hx-tier + .hx-tier .hx-tier-name { border-top: 0; padding-top: 22px; }

/* ---- the tabs: the active one is a shape, not just a brighter word ----- */
.hx-list > .hx-head { padding-bottom: 0; }
.hx-list .hx-tabs { gap: 4px; }
.hx-list .hx-tab {
  padding: 7px 14px; border-radius: 999px;
  background: none; color: var(--t-dim);
  transition: background 130ms var(--ease), color 130ms var(--ease);
}
.hx-list .hx-tab[aria-selected="true"] {
  background: rgba(var(--tone), 0.075); color: var(--paper);
}
.hx-list .hx-tab::after { display: none; }   /* the underline it used to carry */

/* ---- the sort pill: no chevron. It opens a menu, and the menu is the
   disclosure — a caret pointing at a list that is about to cover it is
   drawing the same information twice. */
.hx-sort svg { display: none; }

/* ============================================================
   THE SHEET, to the design's proportions.
   ============================================================ */

/* The design's own split: at 1680 the board is 614 and the sheet 808,
   which is 0.76 to 1. It was 0.61 to 1, so the sheet was carrying a
   hundred pixels the board should have had. */
/* The board is capped. It is a list of fixed-width figures and a name —
   past a point the extra width goes into the gap between the name and its
   percentage, which makes the row harder to read across, not easier. The
   sheet takes everything beyond it. */
.hedge[data-view="desk"] {
  grid-template-columns:
    var(--rail-w)
    minmax(320px, 520px)
    minmax(420px, 1fr);
}

.hx-detail { padding: 16px 16px 16px 4px; }
.hx-detail-card { border-radius: 26px; }
.hx-detail-head {
  padding: 20px var(--hx-sheet-pad) 0;
  gap: 0;
}
.hx-detail-head .hx-word { margin-left: auto; }
.hx-at {
  margin-left: 8px;
  font-family: var(--sans); font-size: 13px; color: var(--t-dim);
}

/* The sheet is wider than a column, so it gets a wider gutter. A measure
   set at a column's padding inside a card twice its width reads as text
   pushed against a wall. */
.hx-detail-card { --hx-pad: var(--hx-sheet-pad); }
.hedge { --hx-sheet-pad: clamp(18px, 1.5vw, 28px); }

/* ---- the name, the price, the mark ------------------------------------- */
/* Both at 32, flat. They were two clamps that disagreed with each other,
   so the name and the price — which are the two things being looked at —
   were never quite the same size at any width. */
.hx-detail-card .hx-co,
.hx-detail-card .hx-px { font-size: 32px; }

/* the disc, not the caret */
.hx-caret { width: 17px; height: 17px; }
.hx-quote[data-dir="up"]   .hx-caret circle { fill: var(--up); }
.hx-quote[data-dir="down"] .hx-caret circle { fill: var(--down); }
.hx-caret circle { fill: var(--t-dim); }
.hx-caret-arrow {
  fill: none; stroke: var(--ink); stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
/* the arrow points the way the price went */
.hx-quote[data-dir="up"] .hx-caret-arrow { transform: rotate(180deg); transform-origin: 50% 50%; }

/* ---- the chart: a line, no fill ---------------------------------------- */
/* The design draws the line alone. The gradient beneath it was carrying no
   information the line did not already have, and on a card whose ground is
   already lifted it read as a second surface. */
.hx-area { display: none; }

/* ---- the panels -------------------------------------------------------- */
.hx-panel { padding: 20px var(--hx-sheet-pad) 24px; }
.hx-panel-title { font-size: 15px; line-height: 1.4; margin-bottom: 12px; }
.hx-panel-when { margin-left: 2px; }

/* the sympathy line: another name that moved with this one */
.hx-peer {
  display: inline-flex; align-items: baseline; gap: 6px;
  margin-top: 14px;
  font-family: var(--mono); font-size: var(--mono-size);
  letter-spacing: var(--mono-track); text-transform: uppercase;
  color: var(--t-dim); text-decoration: none;
}
.hx-peer span { font-family: var(--sans); font-size: 13px; letter-spacing: 0; }
.hx-peer span[data-dir="up"]   { color: var(--up); }
.hx-peer span[data-dir="down"] { color: var(--down); }
.hx-peer:hover { color: var(--t-second); }

/* the ledger sits inside the card, so it takes the card's gutter too */
.hx-ledger { padding: var(--hx-sheet-pad) var(--hx-sheet-pad) calc(var(--hx-sheet-pad) * 1.6); }

/* ---- last of the pixel pass -------------------------------------------- */
/* The board's date is the page's title here, so it takes the site's own
   title role rather than a column label's size. */
.hx-list-date { font-size: clamp(21px, 1.72vw, 26px); letter-spacing: -0.015em; }
.hx-list-top { gap: 14px; padding: 20px var(--hx-pad) 10px; }

/* Row pitch: the design's rows sit on an eighty-pixel rhythm at its own
   width, which is a little more air than the list had. */
.hx-call { padding-top: 13px; padding-bottom: 13px; }

/* The figures need a column of their own wide enough for the band, or the
   percentage above it wraps and the row grows a third line. */
.hx-fig { min-width: 138px; }
.hx-call { column-gap: 16px; }

/* News, now the last thing in the sheet, gets the card's own gutter and a
   rule above it — it is a different kind of reading from the record. */
/* News sat four pixels under its own seam while every other section in the
   card sits about twenty under theirs — a leftover from when News was
   inside the quote column and had no rule above it to clear. It takes the
   card's gutter top and bottom now, which is what the record above it
   takes, so the two read as sections of one document. */
.hx-news { padding: var(--hx-sheet-pad); border-top: 1px solid var(--hair); }
.hx-news-head { padding-left: 0; padding-right: 0; }


/* ============================================================
   THE RAIL, on Drop's measurements.

   This is the same furniture on the next page along, so it is the same
   furniture: 34px rows, 14px sans, a 9px radius, 10px of inset, 2px
   between them, and the section heading at 13px in the dim tone. Those
   numbers are .side-item and .side-head in wall.css, not a house style
   remembered approximately — a sidebar that is nearly Drop's is worse
   than one that is obviously not, because the difference reads as a
   mistake rather than as a decision.

   What Hedge adds is the figure at the end of a row. Everything else
   about the row is Drop's.
   ============================================================ */
/* No rule between the views and Daily moves. Drop draws none between New
   group and Recent — the space is the separation — and a line here made
   the three views read as a header band bolted above the list rather than
   as the first group in it. Both are .sb-group / .sb-sec now, so neither
   can grow one without the other. */
/* the rows of Daily moves: .sb-item, in a .sb-sec under a .sb-head, which
   is why the heading now lands on the same 20px as every date under it.
   It used to be stated as 21 — ten from the list's inset and eleven
   composed out of Drop's pressable label — and the two columns were a
   pixel apart on the one thing this rail and Drop's have in common. */
/* The figure at the far end of a row is .sb-fig, and its SHAPE is the
   component's. Its meaning is not, so its colour is here.

   Colour only where the figure is a SCORE. An open day's figure is a
   count of what is waiting, so it stays neutral whichever row it is on —
   a green 8 there would read as "up eight" when it means "eight pending".
   Zero is neutral too: as many right as wrong is not a win or a loss. */
.sb-fig[data-kind="net"][data-dir="up"]   { color: var(--up); }
.sb-fig[data-kind="net"][data-dir="down"] { color: var(--down); }
/* dirOf() calls zero "up" — it is written for a price change, where the
   flat case does not arise. A score of zero does arise, and it is not a
   win, so the row sets 'flat' itself rather than borrowing that default. */

/* ============================================================
   THE BOARD'S SPACING — one inset, one rhythm.

   Everything in this column lines up on ONE left edge, and the rows are
   spaced rather than stacked. Both were wrong: the tab row was indented
   twice, because .hx-tabs carries its own horizontal padding and sits
   inside .hx-head which carries the same again, so the pill started 30px
   in where every label below it started at 15. And the rows had no gap at
   all — a leftover of removing the hairlines between them, which took the
   separation away without putting anything back.
   ============================================================ */
.hx-list { --hx-board: 20px; }

/* the tab row: one indent, and the pill is the design's 30 rather than 35 */
.hx-list > .hx-head { padding: 0 var(--hx-board); height: auto; min-height: 0; }
.hx-list .hx-tabs {
  padding: 13px 0 0;
  border-bottom: 0;            /* the design draws no rule under the tabs */
  gap: 6px;
}
.hx-list .hx-tab {
  padding: 6px 13px;
  font-size: 13.5px;
  line-height: 1.28;
}

/* the heading block */
.hx-list-top { padding: 28px var(--hx-board) 0; gap: 17px; }
.hx-sort { padding: 6px 13px 6px 15px; }

/* the tier: a label, then rows on a twenty-pixel rhythm. The gap belongs
   on the group rather than on the row, so the last row in a tier does not
   carry a trailing margin into the next label's own spacing. */
.hx-tier { display: flex; flex-direction: column; gap: 12px; }
.hx-tier-name {
  padding: 26px var(--hx-board) 0;
  /* the label sits on the row's TEXT, not on the row's fill — the fill is
     a highlight and starts a few pixels outside what it highlights */
  padding-left: calc(var(--hx-board) + 8px);
}
.hx-tier + .hx-tier .hx-tier-name { padding-top: 38px; }

/* Tighter gaps than the first pass. The band string is the widest thing in
   the row and it does not compress, so every pixel the gutters give up
   goes to the name — which is the part a reader scans. */
.hx-call { column-gap: 12px; }
.hx-fig { min-width: 130px; }

/* the row: sixty tall, its fill inset to the column's own edge */
.hx-call {
  min-height: 60px;
  padding: 0 14px 0 8px;
  margin: 0 var(--hx-board);
  width: calc(100% - var(--hx-board) * 2);
}
#calls, #moves { padding-bottom: 24px; }

/* ============================================================
   THE RANK, as a pill on the corner.

   It was a digit in the row's first column, which spent sixteen pixels of
   every row on a number nobody reads twice and pushed the logo and the
   name in by the same amount. On the corner it costs the row nothing: the
   space it occupies is the gap that was already there between rows.

   It straddles the fill's edge, so half of it sits on the row and half on
   the column behind. That is the reason it is OPAQUE rather than a tone
   wash — a translucent pill over two different grounds is a pill in two
   different greys with a seam down the middle. Ground first, then the
   wash on top of it, both from tokens, so it flips with the theme.
   ============================================================ */
.hx-call { position: relative; }
.hx-call { grid-template-columns: 36px minmax(0, 1fr) auto auto; }
.hx-call { padding-left: 14px; }

.hx-rank {
  position: absolute; z-index: 2;
  top: -7px; left: -11px;
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 50%;
  /* opaque: ground, then the step above it */
  background-color: var(--ink);
  background-image: linear-gradient(rgba(var(--tone), 0.13), rgba(var(--tone), 0.13));
  font-family: var(--sans); font-size: 12px; line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--t-second);
  text-align: center;
}
/* on the row you are standing in, the pill takes the same lift the fill
   does — otherwise it reads as a hole punched in the highlight */
.hx-call[aria-current="true"] .hx-rank {
  background-image: linear-gradient(rgba(var(--tone), 0.20), rgba(var(--tone), 0.20));
  color: var(--t-primary);
}

/* With the rank out of the row, the tier label lines up on the FILL's own
   left edge rather than on the text inside it. */
.hx-tier-name { padding-left: var(--hx-board); }

/* ============================================================
   THE SHEET AS A CARD, not a column.

   The rule down its left edge was the last thing making it read as the
   fourth column of a table. It is a card sitting on the page — it has its
   own border and its own ground — and a hairline outside that border was
   a second edge four pixels from the first.

   The ground goes up. It was 0.035 of the tone, which is a step you can
   only see if you are looking for it; the design's card is plainly lifted
   off the page, and a card that has to be inferred is not doing the one
   job a card has.
   ============================================================ */
.hx-detail::before { display: none; }
.hx-detail-card { background: rgba(var(--tone), 0.07); }

/* The panels inside it sit ON that ground rather than declaring their own,
   so the card reads as one surface with rules across it. */
.hx-panel { background: none; }
.hx-two { background: var(--hair); }

/* ---- the record: TWO cards ---------------------------------------------
   They were one box split by a hairline, which says "two columns of one
   table". They are two cards with air between them, which says "two
   documents about the same thing" — and that is the truer description: the
   forecast was written before the session and the outcome after it, by
   different processes, from different facts. The pairing is in their
   matched field order, not in a shared border. */
.hx-led-pair {
  gap: 16px;
  background: none;
  border: 0;
  border-radius: 0;
  overflow: visible;
}
.hx-led-card {
  background: rgba(var(--tone), 0.055);
  border-radius: 16px;
  padding: 18px 20px 20px;
}

/* ---- the card's ground, and the catalyst's clamp ------------------------
   The sheet is paper, and which colour paper is depends on the theme —
   #212121 on black, white on the off-white ground. That was written here
   as rgba(var(--tone), 0.129) on the reasoning that an alpha flips where a
   hex cannot, which is true of a LINE and false of a SURFACE: the tone is
   the opposite of the ground by definition, so an alpha of it always
   pushes a surface AWAY from the light, and in light mode the sheet came
   out darker than the page it sits on. The direction lives in the token
   now (see --sheet in tokens.css). */
.hx-detail-card { background: var(--sheet); }
/* the record's cards read as a step ABOVE that: 0.055 over 0.129
   composites to 0.177, which is #2d2d2d against #212121. */

/* The catalyst runs to three hundred words and the panel beside it is seven
   short rows. Unclamped, the two-up was a column of prose with a list
   stranded at the top of it — so the prose is clamped to the depth of its
   neighbour and the word in the header opens it. The clamp is scoped to
   the PROSE: .hx-panel-body is also the Metrics list, and a line-clamped
   list of rows loses rows. */
.hx-panel-prose {
  display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 7; line-clamp: 7;
  overflow: hidden;
}
.hx-panel[data-open] .hx-panel-prose {
  -webkit-line-clamp: unset; line-clamp: unset; display: block;
}
.hx-panel-prose p + p { margin-top: 10px; }

/* ============================================================
   THE CARD'S EDGE, AND ITS SEAMS.

   The outer border goes. With the ground lifted to #212121 the card is
   already legible as a card, and a hairline around a filled shape is a
   second boundary a few pixels outside the first one.

   And the rules INSIDE it stop running edge to edge. A full-bleed rule
   cuts the card in half; an inset one separates two sections within a
   card, which is what these actually do. Every one of them now stops
   where the content stops, on the card's own gutter.

   Drawn as an inset background stripe rather than a border, because a
   border cannot be shortened — and the alternative, a pseudo-element per
   section, is four more boxes to keep in the right stacking order.
   ============================================================ */
.hx-detail-card { border: 0; }

.hx-detail-card .hx-stats,
.hx-detail-card .hx-two,
.hx-detail-card .hx-ledger,
.hx-detail-card .hx-news,
.hx-detail-card .hx-card {
  border-top: 0;
  border-bottom: 0;
  background-image: linear-gradient(var(--hair), var(--hair));
  background-repeat: no-repeat;
  background-position: top center;
  background-size: calc(100% - var(--hx-sheet-pad) * 2) 1px;
}
/* Every section in the card keeps its seam. An earlier line here dropped
   it from the first .hx-card, which I had reasoned about as if it sat
   directly under the quote — it does not. The first card is About, and the
   thing above it is the prediction record, which is the boundary in the
   sheet that most needs saying. */

/* ---- the panels' own divider -------------------------------------------
   This was a one-pixel gap with .hx-two coloured behind it, which is a
   neat trick and was quietly wrong: the panels had been given
   `background: none` in the same pass, so the hairline colour was showing
   through BOTH of them and the whole band was painting a step lighter
   than the card it sits in. The divider is a border on the second panel
   now, and the band is the card's ground again. */
.hx-two { gap: 0; background: none; }
.hx-panel { background: none; }
.hx-panel + .hx-panel { border-top: 1px solid var(--hair); }
@container (min-width: 560px) {
  .hx-panel + .hx-panel { border-top: 0; border-left: 1px solid var(--hair); }
}

/* ============================================================
   THE SHEET'S ENTRANCE.

   The entrance animates `.hx-col > *`, and the sheet has exactly one
   child: the card. So the card rose as a single block — six sections
   arriving in perfect unison, which reads as one big thing moving rather
   than as a document assembling. Every other column has several children
   and got the effect for free.

   So the sections are staggered inside it, sixty milliseconds apart, on
   top of the column's own delay. The card itself only fades: it is the
   surface the sections arrive ON, and a surface that travels while its
   contents also travel moves everything twice.
   ============================================================ */
.hedge[data-in] .hx-detail > * {
  animation-name: hx-fade;
  animation-duration: 420ms;
}
@keyframes hx-fade { from { opacity: 0; } to { opacity: 1; } }

/* There WAS a rule here nulling the animation on the card's direct
   children, from when the entrance animated them. It animates the sections
   now, and .hx-two is both — a section AND a direct child of the card — so
   the rule was silently cancelling the panels' entrance on first load and
   nowhere else. Nothing animates the wrappers any more, so it is gone
   rather than narrowed. */

/* The stagger index used to be assigned here, one rule per section, under
   [data-in]. Both halves of that were wrong: a fixed index cannot know
   which sections are actually on screen, and [data-in] is only true once.
   The render assigns --s inline now, counting the visible ones. */

@media (prefers-reduced-motion: reduce) {
  .hedge[data-in] .hx-detail > *,
  .hedge[data-in] .hx-detail-card :is(.hx-quote, .hx-stats, .hx-panel, .hx-ledger, .hx-card, .hx-news) {
    animation: none;
  }
}

/* ---- held until reached ------------------------------------------------
   A section below the card's fold is held at opacity zero and released by
   the observer in hedge.js when it is scrolled to. The transition lives on
   the section itself rather than on the held state, so removing the
   attribute is what plays it.

   The entrance animation is excluded from held sections deliberately: an
   animation with `both` fill overrides a plain declaration, so a section
   that was both animating and held would have the animation win and the
   hold do nothing. The attribute is set during the render, before styles
   are computed, so :not([data-hold]) resolves correctly on the first pass. */
.hx-detail-card :is(.hx-quote, .hx-stats, .hx-panel, .hx-ledger, .hx-card, .hx-news) {
  transition: opacity 460ms var(--ease-soft), transform 460ms var(--ease-soft);
}
.hx-detail-card [data-hold] { opacity: 0; transform: translateY(10px); }

/* THE ENTRANCE IS NOT ONLY THE FIRST ONE. It used to be scoped to
   [data-in], which meant it played on load and never again — switching
   names fell back to .hx-swap, one flat rise on some of the sections and
   nothing on the rest. The stagger is driven by an attribute the render
   sets instead, so it plays whenever the sheet is rebuilt: on load, on a
   new pick, on a new day, on a new run.

   It restarts because the sections are NEW ELEMENTS each render — the
   sheet is rebuilt from innerHTML, so there is no animation to retrigger,
   only one to start. */
.hx-detail-card [data-enter] {
  animation: hx-rise 520ms var(--ease-soft) both;
  animation-delay: calc(var(--s, 0) * 60ms);
}
/* on the very first paint the column's own delay leads it */
.hedge[data-in] .hx-detail-card [data-enter] {
  animation-delay: calc(var(--i) * 70ms + 140ms + var(--s, 0) * 60ms);
}

@media (prefers-reduced-motion: reduce) {
  .hx-detail-card :is(.hx-quote, .hx-stats, .hx-panel, .hx-ledger, .hx-card, .hx-news) {
    transition: none;
  }
  .hx-detail-card [data-hold] { opacity: 1; transform: none; }
  .hx-detail-card [data-enter] { animation: none; }
}

/* The calibration verb sits at the far end of the record's own header,
   where Read more sits on every card in this sheet. */
.hx-led-head { gap: 8px; }
.hx-led-cal { margin-left: auto; }

/* ---- the calibration ----------------------------------------------------
   Hits and misses as two short lists rather than one prose block, because
   the whole point of the review is that they are countable — and because
   a reader scanning a closed call wants "what went wrong" before "why". */
.hx-rev-sets { display: grid; gap: 14px; margin: 12px 0 14px; }
@container (min-width: 560px) {
  .hx-rev-sets { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
}
.hx-rev-name {
  font-family: var(--sans); font-size: 12px; color: var(--t-dim);
  margin-bottom: 6px;
}
.hx-rev-list { margin: 0; padding-left: 16px; }
.hx-rev-list li {
  font-family: var(--sans); font-size: 13px; line-height: 1.5;
  color: var(--t-second); margin-bottom: 4px;
}
/* A miss takes the downside colour on its MARKER only, never its text. The
   sentence is a finding and reads as one; the bullet is the tally. */
.hx-rev-set[data-t="miss"] .hx-rev-list li::marker { color: var(--down); }
.hx-rev-set[data-t="hit"]  .hx-rev-list li::marker { color: var(--up); }

/* The lesson is the one line that changes what happens next, so it stays
   out of the clamp — a conclusion you have to press a button to reach is
   a conclusion nobody reads. */
.hx-rev-lesson {
  margin: 14px 0 0;
  padding-top: 12px;
  border-top: 1px solid rgba(var(--tone), 0.08);
  font-family: var(--sans); font-size: 13px; line-height: 1.55;
  color: var(--t-primary);
}

/* The rename seat in the RAIL keeps the row's own padding and height —
   which is the whole point of borrowing .sb-item. Zeroing it, as a first
   pass did, ran the field edge to edge and lost the four pixels of inset
   that make Drop's look like a name becoming editable rather than a box
   dropped into a list. */
.sb-item.hx-run--edit { display: flex; align-items: center; }
