/* The news view.
 *
 * Its own sheet rather than another two hundred rules in panel.css, which is already sixty
 * kilobytes and holds four different views. Linked from both documents: the panel renders the
 * feed, and the shell needs the same tokens for the widget card's preview.
 *
 * THE ROW IS THE DESIGN and it is built out of exactly four things - a mark, a name, a sentence
 * and the markets underneath it. Everything else on screen is chrome that gets out of the way:
 * the head is one line, the filters live behind two buttons, and nothing animates except a
 * headline arriving, which fades once and then holds still.
 *
 * DENSITY IS A SETTING because a feed in a quarter-height cell and a feed filling a monitor are
 * different problems. `data-density="compact"` tightens the vertical rhythm and drops the pill
 * row's own gap; it changes no colours and no sizes that carry meaning.
 */

/* THE VIEW INSIDE A FLOATING WINDOW. `.nw-root` is absolute and pinned to its host's edges, so the
   host has to be a positioned box with a size of its own - the window frame supplies the size, this
   supplies the positioning context. Overflow hidden because the frame is already rounded and a
   scrolling list would otherwise square off its bottom corners. */
.nw-winbody {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

.nw-root {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  color: var(--ink);
  min-height: 0;
}

/* ------------------------------------------------------------------- head */

.nw-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 10px 0 12px;
  height: var(--h-bar, 32px);
  flex: 0 0 auto;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}

.nw-title { display: flex; align-items: center; gap: 7px; min-width: 0; flex: 0 0 auto; }

.nw-name {
  font-family: var(--ui-display);
  font-weight: var(--w-semi);
  font-size: var(--t-md);
  letter-spacing: var(--tr-tight);
  color: var(--ink);
}

/* The live mark. A dot that is on when the stream is connected and grey when it is not, which is
   the same grammar the chart's LIVE badge uses. It does not pulse: a feed that blinks at you
   while you read it is the tell of a dashboard that has nothing to say. */
.nw-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink-faint);
  flex: 0 0 auto;
}
.nw-dot.on { background: var(--buy-hi); }

.nw-status {
  font-size: var(--t-xs);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.nw-cats {
  display: flex;
  align-items: center;
  gap: 3px;
  min-width: 0;
  flex: 1 1 auto;
  overflow-x: auto;
  scrollbar-width: none;
  /* A CUT CHIP MUST READ AS "THERE IS MORE", NOT AS BROKEN.
   *
   * This strip has always scrolled, but with the scrollbar hidden a narrow header simply ended
   * mid-word - "Mac" where Macro should be - which looks like a layout that failed rather than one
   * that scrolls. The fade is the standard tell. It sits over empty background whenever the chips
   * fit, because the strip grows to fill the row, so it costs nothing in the common case. */
  mask-image: linear-gradient(to right, #000 calc(100% - 16px), transparent);
}
.nw-cats::-webkit-scrollbar { display: none; }

/* A category filter: the system's quiet role and the system's latch, at the dense height. Only
   what is local to this strip is stated here. */
.nw-chip { flex: 0 0 auto; }

.nw-tools { display: flex; align-items: center; gap: 4px; margin-left: auto; flex: 0 0 auto; }

/* The hairline, the corner, the ground and the focus are the field role - controls.css - carried
   by the wrapper here because this field sets its glyph BESIDE the text rather than behind it. */
.nw-searchwrap {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 8px;
  color: var(--ink-faint);
  max-width: 200px;
  /* Searching is occasional and the category chips are the filter people actually use, so when the
     header runs out of room this is what gives way - down to a field still wide enough to read a
     word or two of what was typed in it. */
  min-width: 116px;
}
.nw-searchwrap:focus-within { color: var(--ink-dim); }

.nw-search {
  font: inherit;
  font-size: var(--t-sm);
  color: var(--ink);
  background: transparent;
  border: 0;
  outline: none;
  width: 130px;
  min-width: 0;
}
.nw-search::placeholder { color: var(--ink-faint); }

.nw-tool { position: relative; padding: 0 7px; height: 24px; }
.nw-tool.on { color: var(--ink); }
.nw-tool.open { background: var(--sel); color: var(--ink); }

.nw-toolcount {
  font-size: var(--t-2xs);
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
  margin-left: 4px;
}
.nw-tool.on .nw-toolcount { color: var(--ink-dim); }

/* -------------------------------------------------------------- symbol bar */

.nw-symbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-bottom: 1px solid var(--line);
  background: var(--panel-2);
  font-size: var(--t-sm);
  flex: 0 0 auto;
}
.nw-symbar[hidden] { display: none; }

.nw-symlabel { color: var(--ink-faint); }

.nw-symchip {
  font-weight: var(--w-medium);
  letter-spacing: var(--tr-ticker);
  color: var(--ink);
  background: var(--panel-3);
  border: 1px solid var(--line-2);
  border-radius: 999px;
  padding: 1px 8px;
}

.nw-sympx { font-variant-numeric: tabular-nums; color: var(--ink); }

.nw-symopen {
  font: inherit;
  font-size: var(--t-sm);
  color: var(--ink-dim);
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: var(--r);
  height: 20px;
  padding: 0 8px;
  cursor: pointer;
}
.nw-symopen:hover { color: var(--ink); border-color: var(--ink-faint); }

.nw-symx {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  margin-left: auto;
  color: var(--ink-faint);
  background: transparent;
  border: 0;
  border-radius: var(--r);
  cursor: pointer;
}
.nw-symx:hover { color: var(--ink); background: var(--sel); }

/* ----------------------------------------------------------------- panels */

.nw-panel {
  flex: 0 0 auto;
  /* THE PANEL IS THE ONE SCROLLING THING IN HERE.
   *
   * It holds three sections now - what the feed shows, what it shouts about, where it reads from -
   * and 46% of the view left that a sliver you had to scroll three times to cross. */
  max-height: 72%;
  overflow-y: auto;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  border-bottom: 1px solid var(--line);
  background: var(--panel-2);
}
/* NO SECTION GIVES UP ITS HEIGHT. A flex column whose content overflows shrinks whichever child
   it is allowed to, and the source list - the one child with an overflow of its own, so the one
   with a min-height of zero - was collapsing to a single pixel while holding twenty rows of
   thirty-four. Twenty sources, none of them on screen, between a heading and a Show-more link. */
.nw-panel > * { flex: 0 0 auto; }
.nw-panel[hidden] { display: none; }

.nw-prow { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.nw-phead { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }

.nw-plabel {
  font-size: var(--t-sm);
  color: var(--ink-dim);
}

.nw-pgroup {
  margin-top: 2px;
}

.nw-pnote { font-size: var(--t-sm); color: var(--ink-faint); line-height: var(--lh-ui); }

.nw-plink {
  font: inherit;
  font-size: var(--t-sm);
  color: var(--ink-dim);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  align-self: flex-start;
  text-decoration: underline;
  text-decoration-color: var(--line-2);
  text-underline-offset: 3px;
}
.nw-plink:hover:not(:disabled) { color: var(--ink); }
.nw-plink:disabled { color: var(--ink-faint); cursor: default; text-decoration: none; }

.nw-seg { display: inline-flex; flex-wrap: wrap; border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }

/* A segment inside one frame: the members carry no frame of their own, only the rule between
   them. Face, hover and latch are the system's. */
.nw-segbtn {
  border: 0;
  border-right: 1px solid var(--line);
  border-radius: 0;
}
.nw-segbtn:last-child { border-right: 0; }

.nw-switch {
  width: 34px;
  height: 18px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: var(--track);
  position: relative;
  cursor: pointer;
  padding: 0;
  flex: 0 0 auto;
}
.nw-switch.on { background: color-mix(in srgb, var(--buy) 55%, transparent); border-color: var(--buy); }

.nw-knob {
  position: absolute;
  top: 1px;
  left: 1px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--ink-dim);
  transition: transform var(--t-tap) var(--ease), background var(--t-tap) var(--ease);
}
.nw-switch.on .nw-knob { transform: translateX(16px); background: var(--ink); }

.nw-srcs { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 4px; }

/* A source row is a field carrying a value - it is on or it is off - so it wears the system's
   field and the system's latch. What is local: it is a ROW, so its contents sit left rather than
   centred, and it is allowed to be narrower than its text. */
.nw-srcbtn {
  display: flex;
  justify-content: flex-start;
  gap: 7px;
  padding: 0 var(--c-pad-sm);
  text-align: left;
  min-width: 0;
}

.nw-srcmark { width: 14px; height: 14px; border-radius: var(--r-sm); flex: 0 0 auto; opacity: .55; }
.nw-srcbtn.on .nw-srcmark { opacity: 1; }

/* THE NAME NEVER LOSES TO THE NOTE. "Wat... rate limited by X (all accou" was a real row: the
   health note is a fixed string and the name is the thing being described, so the note is what
   truncates. Its full text is on the button's own tooltip either way. */
.nw-srcname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 1 1 auto; }

.nw-srcnote {
  margin-left: auto;
  font-size: var(--t-2xs);
  color: var(--ink-faint);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 44%;
  flex: 0 1 auto;
}
.nw-srcnote.bad { color: var(--sell-hi); }
.nw-srcnote.warn { color: #c9a227; }

.nw-trigs { display: flex; flex-direction: column; gap: 5px; }
.nw-trig { display: flex; align-items: center; gap: 6px; }

.nw-triginput {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: var(--t-sm);
  color: var(--ink);
  background: var(--panel-3);
  border: 1px solid var(--line);
  border-radius: var(--r);
  height: 24px;
  padding: 0 8px;
  outline: none;
}
.nw-triginput:focus { border-color: var(--line-2); }
.nw-triginput::placeholder { color: var(--ink-faint); }

.nw-trigx {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  color: var(--ink-faint);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r);
  cursor: pointer;
  flex: 0 0 auto;
}
.nw-trigx:hover { color: var(--sell-hi); border-color: var(--line-2); }

/* ------------------------------------------------------------------- list */

.nw-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
}

.nw-stack { display: flex; flex-direction: column; }

.nw-empty { padding: 22px 16px; color: var(--ink-faint); font-size: var(--t-md); }

.nw-older {
  padding: 0;
  text-align: center;
  color: var(--ink-faint);
  font-size: var(--t-xs);
  height: 0;
  overflow: hidden;
}
.nw-older.on { height: auto; padding: 12px 0 16px; }

/* ------------------------------------------------------------------- rows */

.nw-row {
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: 9px;
  /* TIGHT, deliberately. The first cut of this had ten pixels of padding and three of gap between
     every part, and beside the reference tool it read airy - the owner's word was sloppy. A wire
     is scanned, and scanning wants the rows close enough that the eye travels down them without
     stopping. This is the rhythm that fits fourteen stories in the height that used to hold ten,
     with the headline still the loudest thing in the row. */
  padding: 7px 14px 8px;
  border-bottom: 1px solid var(--line);
  border-left: 2px solid transparent;
  outline: none;
}
.nw-row.opens { cursor: pointer; }
.nw-row:hover { background: var(--panel-2); }
.nw-row.sel { background: var(--panel-2); border-left-color: var(--line-2); }

/* A keyword the reader asked to be told about. One rule down the left edge and a warmer ground:
   it must be findable while scrolling past and must not turn the row into a banner. */
.nw-row.hit { border-left-color: #c9a227; background: color-mix(in srgb, #c9a227 6%, transparent); }
.nw-row.hit:hover { background: color-mix(in srgb, #c9a227 10%, transparent); }

/* The rest of a squawk line. Text, not a chevron: a triangle that rotates is the decoration every
   template ships, and this has to sit under a headline without competing with it. Dim until wanted,
   the same as every other quiet control here. */
.nw-more {
  font: inherit;
  font-size: var(--t-sm);
  color: var(--ink-dim);
  background: transparent;
  border: 0;
  padding: 2px 0 0;
  cursor: pointer;
  align-self: flex-start;
}
.nw-more:hover { color: var(--ink); text-decoration: underline; }

/* Open, the cap comes off. The clamp is what keeps a four line headline from owning the screen;
   a row somebody has just asked to read in full is the one case where that is not wanted. */
.nw-row.open .nw-title-line { -webkit-line-clamp: unset; }

/* A price that just moved: NOTHING happens to it now (owner 20u) - the number is plain text in
   the default type, white, and the only event is the value itself changing. The old roll, the
   cell tint and the direction colour are all gone; the rule below only keeps the pill's padding
   so the row does not shift. */
.nw-pill-px {
  border-radius: var(--r-sm);
  padding: 0 2px;
  margin: 0 -2px;
}

/* THE SOURCE LIST: one row per source, alphabetical, with a switch on the right.
 *
 * It replaced a grid of chips grouped by how each source is READ, which is a fact about the
 * plumbing rather than something a reader knows - looking for Watcher Guru meant knowing it comes
 * from Telegram. A single scannable column is what every settings panel worth copying does.
 *
 * IT SCROLLS ON ITS OWN. Forty-odd sources under a filter popup pushed the keyword triggers and
 * the category chips off the bottom of the screen, so the list gets its own height and its own
 * scrollbar and everything above it stays reachable.
 */
.nw-srclist {
  display: flex;
  flex-direction: column;
  /* No scroll of its own. A list that scrolls inside a panel that scrolls is two wheels under one
     pointer, and it was also what let this collapse - see the rule above. The panel carries it. */
  /* The rule between rows, not around them: a box around a list inside a popup is one frame too
     many, and the popup already has an edge. */
  border-top: 1px solid var(--line);
}

.nw-srcrow {
  display: grid;
  grid-template-columns: 18px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 7px 2px;
  border-bottom: 1px solid var(--line);
}
/* Hover belongs to the ROW, because the whole row is the thing you are aiming at even though the
   switch is what you press. No transform, no lift: a list that moves under the cursor is the
   cheapest trick there is. */
.nw-srcrow:hover { background: var(--panel-2); }

.nw-srcrow .nw-srcmark {
  width: 18px;
  height: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.nw-srcrow .nw-srcmark img { width: 18px; height: 18px; border-radius: var(--r-sm); }

.nw-srcname { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.nw-srctitle {
  font-size: var(--t-md);
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Under the name, never beside it: beside the name it reads as the switch's label, which is how
   "off" next to a source you had just switched on came to look like a broken control. */
.nw-srcwhy { font-size: var(--t-sm); color: var(--ink-faint); line-height: var(--lh-ui); }
.nw-srcwhy.bad { color: var(--sell-hi); }
.nw-srcwhy.warn { color: #c9a227; }

/* A source this install does not poll is not a control. It is dimmed, it says so in words, and it
   carries a static label where the switch would be - because a live switch over a source that
   cannot produce a row is the same lie in the other direction. */
.nw-srcrow.dark .nw-srctitle { color: var(--ink-dim); }
/* The line under the list. A link, not a button with a face: it reveals rows rather than doing
   anything, and the panel already has enough surfaces in it. */
.nw-srcmore { margin-top: 8px; align-self: flex-start; }

.nw-srcoff {
  font-size: var(--t-sm);
  color: var(--ink-faint);
  text-transform: uppercase;
  letter-spacing: var(--tr-micro);
  padding-right: 4px;
}

/* A headline arriving. THE MOTION IS THE SIGNAL, and it is the only signal.
 *
 * THE MOVEMENT IS NOT HERE. The list slides down by exactly the height of what arrived, in one
 * compositor transform - see arrive() in news-view.js.
 *
 * There used to be a green wash on the new row underneath that slide, fading over three seconds.
 * The owner's word for the result was cheap, and he was describing something this project had
 * already learned once: the reference feed he asked this to match has NO coloured row grounds at
 * all, colour lives on the numbers, and a washed row was the single thing that made our own flows
 * feed read as generated. A row that arrives green is a template's idea of new.
 *
 * So an arrival is now one movement and nothing else: the list glides, the row fades up with it on
 * the same curve and the same clock, and when it stops there is simply a feed with a new top line -
 * which is what a wire looks like. Being newest is already said by being first.
 */

/* EXCEPT when motion is off, where the movement cannot be the signal because there is no movement.
   A reader who has turned it down gets the quiet ground instead - the one case the wash is right,
   because it is now carrying the whole message rather than decorating a slide it was competing
   with. Background only: `.hit` owns the left edge, and repainting that rule would take a keyword
   match's gold away for a few seconds and hand it back, a flicker on the one row a reader asked
   to be told about. */
@media (prefers-reduced-motion: reduce) {
  .nw-row.fresh { animation: nw-arrive 2s cubic-bezier(.33, 1, .68, 1) 1; }
  @keyframes nw-arrive {
    0% { background: color-mix(in srgb, var(--buy) 10%, transparent); }
    30% { background: color-mix(in srgb, var(--buy) 7%, transparent); }
    100% { background: transparent; }
  }
}

.nw-mark {
  width: 16px;
  height: 16px;
  margin-top: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
}
.nw-mark img { width: 16px; height: 16px; border-radius: var(--r-sm); object-fit: cover; display: block; }

.nw-mono {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: var(--r-sm);
  background: var(--panel-3);
  border: 1px solid var(--line-2);
  color: var(--ink-dim);
  /* type-exempt: a monogram inside a 16px chip is glyph sizing, not type - it is measured
     against the circle it sits in, and a rung of the interface scale would burst it. */
  font-size: 7.5px;
  font-weight: var(--w-bold);
  letter-spacing: var(--tr-ticker);
}
.nw-mono.sm { width: 14px; height: 14px; font-size: 7px; /* type-exempt: see above */ }

.nw-body { min-width: 0; display: flex; flex-direction: column; gap: 1px; }

.nw-meta { display: flex; align-items: baseline; gap: 8px; min-width: 0; line-height: var(--lh-tight); }

/* The attribution, at the size of the timestamp beside it on the same line. It was 11px against
   the age's 10 - two quiet labels on one line, a pixel apart, which reads as an oversight rather
   than a distinction. */
.nw-src {
  font-size: var(--t-xs);
  color: var(--ink-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nw-age {
  margin-left: auto;
  font-size: var(--t-xs);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  flex: 0 0 auto;
}

/* THE HEADLINE, BY THE TYPE SYSTEM'S OWN RULES.
 *
 * This was 600 with negative tracking at 12px, and style.css explicitly rules out both. `--w-semi`
 * is defined as the weight for something that LABELS other content - "NOT every name in a list...
 * twelve semibold rows in a column emphasise nothing" - and a headline is not a label for its row,
 * it IS the row. A hundred of them in a column was a wall of bold with no hierarchy in it, which
 * is what "AI sloppy" was describing. `--tr-tight` is documented as "--t-lg and above, where the
 * face's own spacing is too open"; at 12px the face is already right, and closing it further is
 * what made the text read muddy rather than crisp.
 *
 * So the headline takes the workhorse 500 at the face's own spacing, and stays the loudest thing
 * in the row through COLOUR against dimmed 10px metadata - which is how a wire does it, and it
 * costs no density. */
.nw-title-line {
  margin: 0;
  font-family: var(--ui-display);
  font-size: var(--t-md);
  font-weight: var(--w-medium);
  line-height: var(--lh-ui);
  letter-spacing: var(--tr-none);
  color: var(--ink);
  /* Four lines is a squawk paragraph; past that the row is a page. */
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.nw-title-text { white-space: normal; }

.nw-hit {
  background: color-mix(in srgb, var(--focus) 30%, transparent);
  color: inherit;
  border-radius: 2px;
  padding: 0 1px;
}

.nw-pills { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }

.nw-pill {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  font: inherit;
  font-size: var(--t-xs);
  color: var(--ink-dim);
  background: var(--panel-3);
  border: 1px solid var(--line);
  border-radius: 999px;
  height: 17px;
  padding: 0 7px;
  cursor: pointer;
  white-space: nowrap;
}
.nw-pill:hover { border-color: var(--line-2); color: var(--ink); }

/* A pill the story IMPLIED rather than named - "Red Sea" meaning crude - is drawn quieter, so a
   reader can tell a claim from an inference without reading the tooltip.
 *
 * IT USED TO DROP THE GROUND ENTIRELY, and two pills side by side on the same row then had two
 * different shapes - one filled, one an outline - which reads as an unfinished control rather than
 * as a distinction anybody could name. His words: one has a grey and one has a line around it.
 *
 * Same ground, same border, same height for every pill. The distinction survives where it belongs,
 * in the weight of the text: an inferred symbol is dimmer than a named one, which is the difference
 * between a claim and a guess said quietly rather than said with a different chip. */
.nw-pill.soft { background: var(--panel-3); }

/* The venue's own mark, at the size a pill can carry one: big enough to be recognised, small
   enough that the row is still a line of text with a chip on it rather than a card. */
.nw-pill-logo {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  display: block;
  align-self: center;
  flex: 0 0 auto;
}

.nw-pill-sym { font-weight: var(--w-semi); letter-spacing: var(--tr-ticker); color: var(--ink); }
.nw-pill.soft .nw-pill-sym { color: var(--ink-dim); font-weight: var(--w-semi); }

.nw-pill-pct { font-variant-numeric: tabular-nums; font-weight: var(--w-semi); color: var(--ink); }

/* THE NUMBER IS THE SYMBOL'S SIZE. Both inherit --t-xs, but the symbol carried the semibold
   while the price ran regular - and at eleven pixels regular reads a step smaller, which read as
   "the number is smaller than the ticker". Same weight, same look, one typography. */
.nw-pill-px { font-variant-numeric: tabular-nums; font-weight: var(--w-semi); color: var(--ink); }
.nw-pill-px.dim { color: var(--ink-faint); }

/* ------------------------------------------------------------------- jump */

.nw-jump {
  position: absolute;
  top: 42px;
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font: inherit;
  font-size: var(--t-sm);
  color: var(--ink);
  background: var(--panel-3);
  border: 1px solid var(--line-2);
  border-radius: 999px;
  height: 24px;
  padding: 0 12px;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .35);
  z-index: 3;
}
.nw-jump:hover { border-color: var(--ink-faint); }
.nw-jump[hidden] { display: none; }

/* ---------------------------------------------------------------- density */

.nw-root[data-density="compact"] .nw-row { padding: 4px 12px 5px; gap: 8px; }
.nw-root[data-density="compact"] .nw-title-line { font-size: var(--t-md); line-height: var(--lh-ui); -webkit-line-clamp: 3; }
.nw-root[data-density="compact"] .nw-pills { margin-top: 3px; }
.nw-root[data-density="compact"] .nw-body { gap: 0; }

/* ----------------------------------------------------------------- narrow
 *
 * A news feed in a quarter of a split grid is a real layout, not an edge case - it is the layout
 * this was asked for. Under 420px the search box gives up its width first, then the category
 * chips scroll, and the row itself never changes shape: mark, name, sentence, markets, in that
 * order, at every width. */
@media (max-width: 520px) {
  .nw-search { width: 90px; }
  .nw-status { display: none; }
}

@media (max-width: 420px) {
  .nw-head { gap: 6px; padding: 0 6px 0 8px; }
  .nw-searchwrap { display: none; }
  .nw-row { padding: 9px 10px; }
  /* The five category chips are the control this view is used through, so at phone width they get
     the space instead of the title: the tab strip directly above already says News, and a chip
     cut off mid-word ("Ma...") reads as a layout that gave up. */
  .nw-name { display: none; }
  .nw-chip { padding: 0 6px; font-size: var(--t-xs); }
}

/* NO FLOATING WINDOW ON A PHONE.
 *
 * lib/window.js turns every window into a bottom sheet under 640px, and a news feed in a sheet
 * opens at the 160px minimum with no grip to pull it taller - strictly worse than the full-height
 * view the control was pressed from. A window is a desktop idea: it earns its place by letting one
 * feed sit beside a chart, and there is no beside on a phone.
 *
 * In CSS rather than in the render, because the toolbar is built once and the viewport is not: a
 * button decided at render time survives the window being dragged narrow. */
@media (max-width: 640px) {
  .nw-windowbtn { display: none; }
}

/* THE FEED FILLS ITS WINDOW.
 *
 * `.nw-root` is `position: absolute; inset: 0` because every other place it is mounted is a panel
 * that already has a size. Dropped into the generic window frame it had nothing to resolve
 * against: the body scrolled, the wrapper collapsed to zero height, and the window drew a perfect
 * title bar over 150 rows that were all in the DOM and none of them on screen.
 *
 * The window is the box; the feed scrolls inside itself, so the frame's own scrolling is turned
 * off rather than left to fight it. */
.win.news-win .win-body { overflow: hidden; }
.win.news-win .nw-winbody { position: relative; height: 100%; min-height: 0; }

/* A ROLLING NUMBER. See lib/odometer.js for why the strips are built per move.
 *
 * The column is one line tall with the overflow hidden, so a strip of digits inside it shows
 * exactly one at a time. Everything that moves is a transform on the strip - no width, no top,
 * nothing that can reflow the row it sits in.
 *
 * Tabular figures are not decoration here: a 1 narrower than a 7 would make the pill change width
 * mid-roll, and a row of pills would breathe every time a price ticked. */
.od {
  display: inline-flex;
  align-items: baseline;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
/* The odometer's per-digit columns (.od-c/.od-s/.od-l) are gone - numbers are plain text now
   (owner 20u). Only the shared .od inline-flex base above remains, for baseline alignment. */

/* THE CALENDAR. See lib/day-picker.js for why this is drawn rather than asked of the platform.
 *
 * The box, the hairline and the shadow are the menu's - showPanelAt puts this inside .ctxmenu, so
 * the calendar cannot drift from every other dropdown in the product. What is here is only what is
 * local to a month grid. */
.ctxpanel { padding: 8px; }

.dp { width: 232px; user-select: none; }

.dp-head {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 6px;
}
/* The month is the panel's one title, so it takes the weight a title takes and the arrows stay
   quiet either side of it. */
.dp-month {
  flex: 1 1 auto;
  text-align: center;
  font-size: var(--t-sm);
  font-weight: var(--w-medium);
  color: var(--ink);
}
.dp-nav { width: 22px; height: 22px; padding: 0; display: flex; align-items: center; justify-content: center; }
.dp-nav:disabled { opacity: .35; pointer-events: none; }

/* SEVEN COLUMNS, ONE LATTICE. The weekday heads and the days share the same grid so a column of
   Tuesdays is a straight line - two grids with their own gaps drift by a pixel and the whole month
   reads hand-placed. */
.dp-dows, .dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
/* Where it sits and how much room it takes - what it is SET in belongs to the micro-label rule in
   style.css, which this joins. */
.dp-dow { text-align: center; padding-bottom: 3px; }

.dp-day {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: var(--t-sm);
  font-variant-numeric: tabular-nums;
  height: 28px;
  border-radius: var(--r-sm);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.dp-day:hover { background: var(--panel-2); }
.dp-day:focus-visible { outline: 1px solid var(--focus); outline-offset: -1px; }

/* The days either side of this month. Present so every week is a whole row, and unreadable on
   purpose so they are never mistaken for days you can pick. */
.dp-out { color: var(--ink-faint); opacity: .3; pointer-events: none; }

/* Inside the archive but with nothing filed. Dimmed, not blocked: the day files are UTC and a
   reader's own day straddles two of them, so this is a hint rather than a claim. */
.dp-quiet { color: var(--ink-dim); }

/* Outside the archive entirely - before the feed existed, or in the future. */
.dp-none { color: var(--ink-faint); opacity: .28; cursor: default; }
.dp-none:hover { background: transparent; }

/* TODAY IS UNDERLINED, NOT FILLED. A filled today and a filled selection are two solid blocks in
   one grid, and the reader has to work out which is which; the day being READ is the one that
   needs to shout. */
.dp-today { position: relative; font-weight: var(--w-medium); }
.dp-today::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: 4px;
  width: 10px;
  height: 1px;
  transform: translateX(-50%);
  background: var(--ink-dim);
}
.dp-sel { background: var(--sel); color: var(--ink); font-weight: var(--w-medium); }
.dp-sel::after { background: var(--ink); }
.dp-kb { box-shadow: inset 0 0 0 1px var(--line-2); }

.dp-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 7px;
  padding-top: 7px;
  border-top: 1px solid var(--line);
}
.dp-live { height: 22px; padding: 0 8px; font-size: var(--t-xs); }
.dp-span {
  margin-left: auto;
  font-size: var(--t-2xs);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

/* ==================================================================== CALM
 *
 * HIS ASK: the feed was overwhelming - too much per row to read, logos and tickers
 * everywhere, type hard on the eyes. This block re-voices the row as a PAGE rather
 * than a tape: the source mark column goes away (the source still says its name in
 * the meta line), the headline gets bigger and slower to read, the separator fades,
 * and a pill becomes a quiet word - symbol only, no logo, no price, no percent. The
 * price lives in the chart one click away; the feed's job is the headline. */

/* One column. The mark chip is the row's noisiest square centimetre and it carried
   no information the meta line does not already carry. */
.nw-row,
.nw-root[data-density] .nw-row {
  grid-template-columns: 1fr;
  padding: 10px 16px 11px !important;
  gap: 0;
  /* The rule between rows was a full line; at half strength the rows group by
     whitespace alone, which is how a reader pages rather than scans a table. */
  border-bottom-color: color-mix(in srgb, var(--line) 45%, transparent);
}
.nw-mark { display: none; }

/* WHO SAID IT AND WHEN, on one quiet line: the source in the dim ink, the age
   fainter still. Nothing else above the headline. */
.nw-meta { gap: 7px; margin-bottom: 3px; }
.nw-src { color: var(--ink-faint); letter-spacing: .015em; }

/* THE HEADLINE IS THE ROW. Bigger, wider leading, normal tracking - the face's
   own spacing at a reading size, not a compressed label. Three lines, not four:
   a headline that runs longer than that is a story, and stories open. */
.nw-title-line,
.nw-root[data-density] .nw-title-line {
  font-size: var(--t-lg) !important;
  line-height: 1.45 !important;
  -webkit-line-clamp: 3 !important;
  letter-spacing: .005em;
  color: var(--ink);
}

/* THE PILL IS A TAG, not a ticker. Logo out, price out, percent out: a pill reads
   as a word - BTC - in the dim ink, underlined by nothing, and it is still a
   button that opens the chart. Everything the numbers said, the chart says better. */
.nw-pills,
.nw-root[data-density] .nw-pills { margin-top: 7px; gap: 10px; }
.nw-pill,
.nw-root[data-density] .nw-pill {
  background: transparent;
  border: 0;
  height: auto;
  padding: 0;
  gap: 0;
  color: var(--ink-faint);
}
.nw-pill:hover { color: var(--ink); background: transparent; border: 0; }
.nw-pill-logo { display: none !important; }
/* THE NUMBERS ARE A CHOICE, not a default. The calm feed reads the symbol alone; the Market-pills
   setting brings the price and the day's % back, and when it does they arrive at text size in the
   dim ink the pill already speaks - the old ticker's information without the old ticker's shout. */
.nw-root[data-pill='plain'] .nw-pill-px,
.nw-root[data-pill='plain'] .nw-pill-pct { display: none !important; }
.nw-root:not([data-pill='plain']) .nw-pill-px,
.nw-root:not([data-pill='plain']) .nw-pill-pct {
  display: inline !important;
  /* SAME TYPE AS THE SYMBOL (owner: "why arent the numbers same typography and size as the
     asset like BRENTOIL? its smaller numbers"). The old --t-sm here shrank the number a step
     below the word beside it; inherit the pill's size and carry the symbol's weight, so a pill
     reads as one run of type. */
  font-size: inherit;
  font-weight: var(--w-medium);
}
.nw-pill-sym,
.nw-root[data-density] .nw-pill-sym {
  font-weight: var(--w-medium);
  letter-spacing: .03em;
  color: inherit;
}

/* THE TICKER, SIZED TO THE SENTENCE. The calm pill kept its shape - one dim word, no logo, no
   numbers - but the headline grew a rung and the word beside it stayed small, which read as a
   footnote rather than a tag. The pill now takes the headline's own size, so a row reads at one
   voice from edge to edge. */

.nw-pill,
.nw-root[data-density] .nw-pill {
  font-size: var(--t-lg);
  height: auto;
  align-items: baseline;
}
