/* ==========================================================================
   NITRATE — THE BROADCAST CHRONOLOGY.  Pairs with cour.js.  Nothing else.

   Anime is the only kind in this catalogue that is filed by COUR — the
   Winter / Spring / Summer / Fall quarter a show premiered in.  Films have a
   year, series have a year; only these 51 have a quarter that means something
   to the people who made them.  So this block is a real time axis, 1984 to
   2026, with every title's run drawn on it in proportion.

   ------------------------------------------------------------------- SHAPE
   One row per title, sorted by premiere, oldest at the top.  Because the rows
   are sorted and the axis is linear, the posters fall as a STAIRCASE from top
   left to bottom right, and the slope of that staircase is the premiere rate:
   flat where the shelf went years without adding a decade, steep where four
   shows premiered in one year.  That slope is the finding; everything else on
   the page is there to let you read it.

   ------------------------------------------------------------------ COLOUR
   Every value is a token from tokens.css and none are redefined here.
   Safety orange has exactly TWO meanings in this block and no others:
       1  THE ROW YOU ARE INSPECTING  (hover, focus)
       2  A DATE THE DATA COULD NOT GIVE US  (the hatched band)
   It is never a heading, never a highlight, never decoration.

   Artwork is content, not interface, so it is allowed to be coloured — but it
   is held at reduced saturation and opacity at rest so that fifty backdrops do
   not turn a film lab into a games shelf.  Bringing a row to full colour is
   what INSPECTING it does; that is the light table gesture, and it is the only
   thing on the page that gets to be bright.

   ---------------------------------------------------------------- GEOMETRY
   Hairlines, no radius anywhere, tabular figures on every number.  The block
   takes the host's gutter (--pad-x) and claims no outer margin, so the page
   keeps deciding where this sits.

   The plot has a floor width.  Below it the plot scrolls inside its own box —
   the BODY never scrolls sideways — because forty years squeezed into 360px
   puts a whole decade inside eight pixels and stops being readable.
   ========================================================================== */

.ncr {
  display: block;
  position: relative;
  padding: 0 var(--pad-x, 0px);
  margin: 0;

  /* row rhythm — 44px is also the smallest thing a thumb can reliably hit,
     so the visual row and the tap target are the same object everywhere */
  --ncr-row: 44px;
  --ncr-bar: 30px;          /* the run bar, centred in the row       */
  --ncr-po-w: 24px;         /* poster tile at the premiere           */
  --ncr-axis: 30px;

  /* how much of the artwork is allowed through at rest.  Light ground needs
     the tint heavier and the photograph lighter; dark ground the reverse. */
  --ncr-tint-a: .30;
  --ncr-art-a: .34;
}
:root[data-theme="dark"] .ncr { --ncr-tint-a: .36; --ncr-art-a: .46; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ncr { --ncr-tint-a: .36; --ncr-art-a: .46; }
}

/* 🔴 2026-08-12, John, on a shot of this chart: "you have many blank space
   here."  He is right and the block already knew why — its own caption says
   "most of this shelf is newer than the axis it is drawn on".

   WHAT WAS CHECKED FIRST, so nobody re-checks it: the axis ALREADY begins
   where the data does.  `analyse()` sets t0 from the earliest anchor on the
   shelf, which is Fist of the North Star in 1984 — there is no padding to
   trim.  Cutting the axis short would delete the oldest six titles from the
   chart, and BREAKING it (a squiggle through the quiet 1990s) would destroy
   the one thing this block promises in its lede: "the distances between the
   marks are true, so the empty stretches are as real as the crowded ones."
   The horizontal emptiness IS the finding; it is a picture of a shelf bought
   mostly in the last ten years.  It stays.

   What did NOT earn its space is the VERTICAL pitch.  At 44px a row, fifty-one
   rows are 2,244px — two and a half screens — so the staircase this whole
   block is built to show (see SHAPE, above) can never be seen as a staircase;
   you scroll down a wall of grid one row at a time and it just reads as
   blank.  The same true geometry drawn at 32px is 1,632px, and the slope
   becomes legible in a screen and a half.  Nothing about the data changed —
   only how much paper it is printed on.

   ⚠️ WHY THIS IS BEHIND A MEDIA QUERY AND NOT JUST A SMALLER NUMBER.  The 44px
   above is not a taste; the comment on it says the row IS the tap target, and
   a row opens the title sheet.  This block is `mobile: false` in landing.js so
   a phone never builds it, but a touch laptop or a tablet over 760px does —
   and MOBILE_SPEC §10.3 is explicit that "is this a finger?" is a HOVER test,
   never a width.  So the tight pitch is given to pointers only, and every
   touch device keeps its 44px thumb target at every width. */
@media (hover: hover) and (pointer: fine) {
  .ncr { --ncr-row: 32px; --ncr-bar: 22px; --ncr-po-w: 18px; }
}

/* --- section furniture ---------------------------------------------------- */
.ncr-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  padding-bottom: 8px;
  margin-bottom: 12px;
  border-bottom: var(--hair) solid var(--rule);
}
.ncr-h {
  font-family: var(--font-marquee, var(--font-display));
  font-size: clamp(20px, 2.4vw, 28px);
  font-weight: 700;
  letter-spacing: .005em;
  text-transform: uppercase;
  line-height: 1;
  flex: 0 0 auto;
}
.ncr-note {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--muted);
  text-transform: uppercase;
  margin-left: auto;
  text-align: right;
}
.ncr-lede {
  max-width: 78ch;
  color: var(--ink-2);
  font-size: var(--size-dense);
  margin: 0 0 14px;
}

/* --- legend --------------------------------------------------------------- */
.ncr-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 12px;
}
.ncr-key { display: inline-flex; align-items: center; gap: 7px; }
.ncr-swatch {
  width: 26px; height: 10px;
  background: var(--rule);
  flex: 0 0 auto;
  position: relative;
}
.ncr-swatch.is-run { background: var(--ink-2); opacity: .45; }
.ncr-swatch.is-live {
  background: var(--ink-2); opacity: .45;
  -webkit-mask-image: linear-gradient(90deg, #000 55%, rgba(0,0,0,.15) 100%);
          mask-image: linear-gradient(90deg, #000 55%, rgba(0,0,0,.15) 100%);
}
.ncr-swatch.is-unknown {
  background: repeating-linear-gradient(
    135deg, transparent 0 4px, var(--accent) 4px 5px);
  opacity: .8;
}

/* --- the scroller --------------------------------------------------------- */
/* The ONLY thing on this page allowed to scroll sideways.  overscroll-behavior
   keeps a horizontal flick from chaining out to the document. */
.ncr-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  border-top: var(--hair) solid var(--rule);
  border-bottom: var(--hair) solid var(--rule);
}
.ncr-plot {
  position: relative;
  min-width: 760px;          /* the floor: below this a decade is 18px */
}

/* --- axis ----------------------------------------------------------------- */
.ncr-axis {
  position: relative;
  height: var(--ncr-axis);
  flex: 0 0 auto;
}
.ncr-axis-top { border-bottom: var(--hair) solid var(--rule); }
.ncr-axis-bot { border-top: var(--hair) solid var(--rule); }

.ncr-tick {
  position: absolute;
  bottom: 0;
  width: 0;
  border-left: var(--hair) solid var(--rule);
  height: 5px;
}
.ncr-axis-bot .ncr-tick { bottom: auto; top: 0; }
.ncr-tick.is-five { height: 9px; }
.ncr-tick.is-ten  { height: 14px; border-left-color: var(--muted); }

.ncr-yr {
  position: absolute;
  bottom: 8px;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--ink-2);
  white-space: nowrap;
  pointer-events: none;
}
.ncr-axis-bot .ncr-yr { bottom: auto; top: 10px; color: var(--muted); }

/* --- the body: rules behind, rows in front -------------------------------- */
.ncr-body { position: relative; }
.ncr-rules {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}
.ncr-rule {
  position: absolute;
  top: 0; bottom: 0;
  width: 0;
  border-left: var(--hair) solid var(--rule);
  opacity: .55;
}
.ncr-rule.is-half { opacity: .28; }

/* --- rows ----------------------------------------------------------------- */
.ncr-rows {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
  z-index: 1;
}
.ncr-row {
  position: relative;
  height: var(--ncr-row);
  cursor: pointer;
  /* a hairline per row would be 51 lines of noise; every fourth is enough to
     keep the eye on a line across forty years */
}
.ncr-row::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  border-bottom: var(--hair) solid var(--rule);
  opacity: .28;
  pointer-events: none;
}
.ncr-row:last-child::after { opacity: 0; }

/* the run bar */
.ncr-bar {
  position: absolute;
  top: 50%;
  height: var(--ncr-bar);
  margin-top: calc(var(--ncr-bar) / -2);
  overflow: hidden;
  background: var(--panel-2);
  outline: var(--hair) solid var(--rule);
  outline-offset: -1px;
}
.ncr-tint {
  position: absolute;
  inset: 0;
  background: var(--t, var(--rule));
  opacity: var(--ncr-tint-a);
}
.ncr-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: var(--ncr-art-a);
  filter: saturate(.45) contrast(.92);
  transition: opacity .16s linear, filter .16s linear;
}

/* a show still on the air has no right edge — the bar fades out instead of
   stopping, because "last episode so far" is not "the end" */
.ncr-bar.is-live {
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 26px), rgba(0,0,0,.1) 100%);
          mask-image: linear-gradient(90deg, #000 calc(100% - 26px), rgba(0,0,0,.1) 100%);
}
.ncr-bar.is-live.is-stub { -webkit-mask-image: none; mask-image: none; }

/* the premiere edge is the one hard fact in the row; it gets a hard edge */
.ncr-pin {
  position: absolute;
  top: 50%;
  height: var(--ncr-bar);
  margin-top: calc(var(--ncr-bar) / -2);
  width: 2px;
  background: var(--ink-2);
  opacity: .8;
}

/* a start the data could not give us */
.ncr-fog {
  position: absolute;
  top: 50%;
  height: var(--ncr-bar);
  margin-top: calc(var(--ncr-bar) / -2);
  background: repeating-linear-gradient(
    135deg, transparent 0 4px, var(--accent) 4px 5px);
  opacity: .55;
  pointer-events: none;
}

/* poster tile, pinned at the premiere */
.ncr-po {
  position: absolute;
  top: 50%;
  width: var(--ncr-po-w);
  height: calc(var(--ncr-po-w) * 1.5);
  margin-top: calc(var(--ncr-po-w) * -0.75);
  object-fit: cover;
  background: var(--panel-2);
  outline: var(--hair) solid var(--rule);
  outline-offset: -1px;
  z-index: 2;
  filter: saturate(.7);
  transition: filter .16s linear, transform .16s linear;
}

/* the name and the cour, adjacent to the bar on whichever side has room */
.ncr-lab {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  display: flex;
  align-items: baseline;
  gap: 7px;
  z-index: 2;
  pointer-events: none;
  max-width: 100%;
}
.ncr-t {
  font-size: 12.5px;
  color: var(--ink);
  line-height: 1.2;
}
.ncr-c {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  letter-spacing: .05em;
  color: var(--muted);
  text-transform: uppercase;
  flex: 0 0 auto;
}
.ncr-c.is-unknown { color: var(--accent); }

/* --- inspecting ----------------------------------------------------------- */
.ncr-row.is-on .ncr-art { opacity: .92; filter: saturate(1) contrast(1); }
.ncr-row.is-on .ncr-po  { filter: saturate(1); transform: scale(1.06); }
.ncr-row.is-on .ncr-bar { outline-color: var(--accent); }
.ncr-row.is-on .ncr-pin { background: var(--accent); opacity: 1; width: 3px; }
.ncr-row.is-on .ncr-t   { color: var(--ink); }
/* The inspected row gets a SCAN LINE, not a box: two hairlines running the
   full width of the chart so the eye can hold one title across forty years.
   A closed rectangle would read as a selected cell in a table, which this is
   not, and forty years of orange border is too much orange. */
.ncr-row.is-on::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0; bottom: 0;
  border-top: var(--hair) solid var(--accent);
  border-bottom: var(--hair) solid var(--accent);
  opacity: .5;
  pointer-events: none;
}
/* the whole strip dims a shade so the inspected row separates without moving */
.ncr-rows.is-dimmed .ncr-row:not(.is-on) { opacity: .58; }
.ncr-rows { transition: none; }
.ncr-row { transition: opacity .14s linear; }

.ncr-row:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* --- the readout ---------------------------------------------------------- */
.ncr-tip {
  position: absolute;
  z-index: 6;
  width: 250px;
  background: var(--panel);
  border: var(--hair) solid var(--rule);
  padding: 9px 11px 10px;
  pointer-events: none;
  box-shadow: 0 6px 18px rgba(0,0,0,.28);
}
.ncr-tip[hidden] { display: none; }
.ncr-tip-t {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.25;
  margin: 0 0 1px;
}
.ncr-tip-c {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 7px;
}
.ncr-tip-g {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 10px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
}
.ncr-tip-k { color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.ncr-tip-v { color: var(--ink-2); text-align: right; }
.ncr-tip-w {
  margin: 7px 0 0;
  padding-top: 6px;
  border-top: var(--hair) solid var(--rule);
  font-size: 11px;
  line-height: 1.35;
  color: var(--muted);
}
.ncr-tip-w.is-warn { color: var(--accent); }

/* --- the load strip ------------------------------------------------------- */
.ncr-load {
  position: relative;
  border-top: var(--hair) solid var(--rule);
  padding-top: 2px;
}
.ncr-load svg { display: block; width: 100%; height: 62px; }
.ncr-load-fill { fill: var(--ink-2); opacity: .18; }
.ncr-load-line { fill: none; stroke: var(--ink-2); stroke-width: 1.25; }
.ncr-load-lab {
  position: absolute;
  top: 4px; left: 6px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
  pointer-events: none;
}
.ncr-load-peak {
  position: absolute;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  color: var(--ink-2);
  background: var(--ground);
  padding: 0 4px;
  transform: translateX(-50%);
  white-space: nowrap;
  pointer-events: none;
}

/* --- scroll affordance ---------------------------------------------------- */
/* Only ever shown when the plot is wider than the screen.  On a phone the
   reader is looking at the chart through a window about a third its width, so
   two thirds of the rows are legitimately blank — those shows had not started
   yet.  Without something to say so, that reads as a broken chart.  This strip
   carries the WHOLE distribution: one tick per premiere across the full span,
   with the visible window drawn over it.  It is a readout first and a control
   second, and it never appears on a desktop where the chart already fits. */
.ncr-map { margin: 8px 0 0; }
.ncr-map[hidden] { display: none; }
.ncr-map-track {
  position: relative;
  height: 22px;
  background: var(--panel);
  border: var(--hair) solid var(--rule);
  cursor: ew-resize;
  touch-action: none;
  /* the visual strip is 22px; the hit area is 44 */
  padding: 0;
  margin: 11px 0;
}
.ncr-map-track::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: -11px; bottom: -11px;
}
.ncr-map-tick {
  position: absolute;
  top: 4px; bottom: 4px;
  width: 0;
  border-left: var(--hair) solid var(--ink-2);
  opacity: .75;
}
.ncr-map-tick.is-unknown { border-left-color: var(--accent); }
.ncr-map-win {
  position: absolute;
  top: -1px; bottom: -1px;
  border: var(--hair) solid var(--accent);
  background: var(--accent);
  opacity: .16;
  pointer-events: none;
}
.ncr-map-win-b {
  position: absolute;
  top: -1px; bottom: -1px;
  border-left: var(--hair) solid var(--accent);
  border-right: var(--hair) solid var(--accent);
  pointer-events: none;
}

.ncr-hint {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}
.ncr-hint b { color: var(--ink-2); font-weight: inherit; }
.ncr-hint[hidden] { display: none; }

/* --- caption -------------------------------------------------------------- */
.ncr-cap-txt {
  margin: 16px 0 0;
}
.ncr-cap-txt p {
  margin: 0 0 .8em;
  font-size: var(--size-dense);
  color: var(--ink-2);
}
.ncr-cap-txt p:last-child { margin-bottom: 0; }
.ncr-cap-txt b { color: var(--ink); font-weight: 600; }
.ncr-fig {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

/* --- loading / empty ------------------------------------------------------ */
.ncr-wait {
  padding: 26px 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
.ncr-bararea {
  display: block;
  height: 3px;
  background: var(--panel-2);
  margin-top: 9px;
  max-width: 320px;
}
.ncr-bararea i { display: block; height: 100%; background: var(--accent); width: 0; }

/* --- narrow ---------------------------------------------------------------
   Was 700; folded to the house mobile tier, 760 (MOBILE_SPEC §1). */
@media (max-width: 760px) {
  .ncr { --ncr-row: 44px; --ncr-bar: 26px; --ncr-po-w: 20px; }
  .ncr-cap-cols, .ncr-cap-more { columns: 1; }
  .ncr-note { margin-left: 0; text-align: left; width: 100%; }
  .ncr-tip { width: 210px; }

  /* 🔴 THE SCAN CONTROL WAS BELOW THE THING IT SCANS.  The plot has a 760px
     floor, so on a 390px screen you are looking through half of a forty-year
     axis — and the axis opens in 1984, where this shelf has two titles, so
     the first screen of the chart is empty grid and the reader has no way to
     know that.  The mini-map answers that (it carries every premiere over the
     whole span and drags the view), but it was appended AFTER the scroller,
     which on a phone is 2,300px of rows further down: a control you have to
     scroll past the entire problem to find is not a control.  cour.js now
     mounts it ABOVE the scroller on a phone; this is the matching spacing so
     it reads as the chart's own header rather than as a loose strip. */
  .ncr-map { margin: 0 0 2px; }
  .ncr-map + .ncr-scroll { border-top: var(--hair) solid var(--rule); }
}

/* --- motion --------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .ncr-art, .ncr-po, .ncr-row { transition: none; }
  .ncr-row.is-on .ncr-po { transform: none; }
  .ncr-scroll { scroll-behavior: auto; }
}

/* The caption states the finding; the working folds away. It filled two thirds
   of a screen as open prose, which is a paper, not a caption.

   🔴 2026-08-12 — AND THEN IT WAS ONE COLUMN WITH A HOLE BESIDE IT.  Folding
   the working away fixed the length and left the shape: a 78ch measure is
   558px, so on the 1304px plot this block is drawn at, 746px of the caption's
   own row was empty.  John, on a shot of exactly this: "you have many blank
   space here."

   The measure was never the problem — 78ch is right for reading, and widening
   the paragraph to 1304px would only trade a void for an unreadable line.  So
   the prose is SET IN COLUMNS at that measure instead, the way the paper this
   page imitates would set it.  COLUMN-WIDTH, not column-count: the browser
   fits as many columns of a readable measure as the width allows, which is
   three at 1304px, two at about 1000px and one below ~700px, with no
   breakpoint of my invention anywhere (MOBILE_SPEC §1 — do not add a 25th).

   ⚠️ `break-inside: avoid` is deliberately NOT set here.  With three
   paragraphs of very unequal length it forces the tallest one to set the
   column height and leaves the last column empty — a new void where the old
   one was.  Prose that runs on across a column boundary is what newsprint
   does; `orphans`/`widows` keep it from stranding a single line. */
/* 2026-08-12: the 330/34 written here is now the house caption grid — John
   pointed at the same void a third time on NEW PRINTS, so the measure moved
   to tokens.css and four more blocks were set on it.  Same numbers, one
   definition; see the note above --cap-col for the whole argument. */
.ncr-cap-cols {
  columns: var(--cap-col);  /* ≈ the old 78ch measure, as a WIDTH not a count */
  column-gap: var(--cap-gap);
  orphans: 2;
  widows: 2;
}
.ncr-cap-det { margin-top: 10px; }
.ncr-cap-sum {
  cursor: pointer; list-style: none;
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted);
  padding: 10px 0; min-height: 44px; display: flex; align-items: center;
}
.ncr-cap-sum::-webkit-details-marker { display: none; }
.ncr-cap-sum::before { content: '+ '; color: var(--accent); }
.ncr-cap-det[open] .ncr-cap-sum::before { content: '\2212 '; }
.ncr-cap-sum:hover { color: var(--ink); }
/* the folded working sets the same way — one idiom, and the 900px query it
   needed as a column-COUNT fallback goes away with it */
.ncr-cap-more { columns: var(--cap-col); column-gap: var(--cap-gap); orphans: 2; widows: 2; }
