/* ==========================================================================
   NITRATE — STREAM TO A SCREEN.  Pairs with stream.js.
   Owned by the stream agent.  Every colour comes from tokens.css; nothing is
   defined locally, so the vault and the light table both work for free.

   ---- why it looks like this -----------------------------------------------
   The picker is a PATCH BAY, not a modal: a hairline panel that opens against
   the button, lists the screens in the house as rows of hard facts, and closes.
   Nothing is rounded, nothing is shaded, nothing floats on a gradient — the
   only depth cue is a hairline and a flat panel colour, which is how every
   other surface in NITRATE separates itself from the ground.

   Accent discipline: --accent means "primary action / needs attention", so it
   is spent in exactly four places — the STREAM button itself, the scan CTA
   when no scan has ever run, the in-flight progress bar, and a failed cast.
   The device rows are ink and rule; a list of five orange rows would say
   "all five of these need you", which is false.

   The unavailable rows are dimmed but NEVER hidden and never truncated: the
   reason line is the whole point of the row.  A screen missing from a list is
   a bug report; a screen that says why it cannot be used is an instruction.

   Selector hooks are documented at the top of stream.js.
   ========================================================================== */

/* --------------------------------------------------------------- the button */

.nstream-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 28px;
  padding: 0 12px;
  background: var(--accent);
  color: var(--accent-ink);
  border: var(--hair) solid var(--accent);
  border-radius: 0;
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
  user-select: none;
  cursor: pointer;
  /* colour only — never size, so the button can never shift the grid */
  transition: background-color .12s linear, color .12s linear;
}

.nstream-btn:hover {
  outline: var(--hair) solid var(--accent);   /* halo, not a border: no reflow */
  outline-offset: 2px;
}

/* accent-on-accent would swallow the global ring: hold it off with a gap */
.nstream-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  box-shadow: 0 0 0 2px var(--ground);
}

.nstream-btn:active { transform: translateY(1px); }

.nstream-glyph { flex: 0 0 auto; display: block; }
.nstream-glyph rect,
.nstream-glyph path[fill="none"] { stroke-width: 1; }
.nstream-label { display: block; }

/* the disclosure is open: the button holds its pressed state */
.nstream-btn[aria-expanded="true"] {
  outline: var(--hair) solid var(--accent);
  outline-offset: 2px;
}

/* quiet variant — dense lists, where a filled orange button per row is noise */
.nstream-btn.is-quiet {
  background: transparent;
  color: var(--ink-2);
  border-color: var(--rule);
}
.nstream-btn.is-quiet .nstream-glyph { color: var(--accent); }
.nstream-btn.is-quiet:hover,
.nstream-btn.is-quiet:focus-visible {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
.nstream-btn.is-quiet:hover .nstream-glyph,
.nstream-btn.is-quiet:focus-visible .nstream-glyph { color: inherit; }

/* block variant — sheet footer / poster overlay */
.nstream-btn.is-block {
  display: flex;
  width: 100%;
  height: 34px;
  justify-content: center;
}

/* no ratingKey: rendered dead, not hidden */
.nstream-btn[aria-disabled="true"] {
  background: transparent;
  color: var(--muted);
  border-color: var(--rule);
  cursor: not-allowed;
}
.nstream-btn[aria-disabled="true"] .nstream-glyph { opacity: .45; }

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

.nstream-root { position: relative; z-index: 900; }

/* A click-catcher, not a wash.  The picker often opens on top of a sheet that
   already dims the page; a second scrim would double-dim it. */
.nstream-scrim {
  position: fixed;
  inset: 0;
  background: transparent;
  z-index: 900;
}

.nstream-panel {
  position: fixed;
  z-index: 901;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  color: var(--ink);
  border: var(--hair) solid var(--rule);
  border-radius: 0;
  font-family: var(--font-ui);
  font-size: var(--size-dense);
  overflow: hidden;
  /* one flat shadow so the panel reads as lifted off the ground without a
     gradient; it is the ground colour, not black, so it stays warm */
  box-shadow: 0 0 0 var(--hair) var(--ground), 0 10px 28px -12px rgba(0, 0, 0, .55);
}

.nstream-panel:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }

/* --- head ---------------------------------------------------------------- */

.nstream-head {
  display: flex;
  align-items: flex-start;
  gap: var(--gap);
  padding: 10px var(--pad) 9px;
  border-bottom: var(--hair) solid var(--rule);
  background: var(--panel-2);
}

.nstream-head-t { min-width: 0; flex: 1 1 auto; }

/* --muted at 9.5px on --panel-2 measures 3.62:1 in the light table, so the
   kicker is ink-2 (6.70:1).  Measured, not eyeballed. */
.nstream-kicker {
  display: block;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.nstream-subject {
  margin-top: 2px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 14px;
  letter-spacing: -.02em;
  line-height: 1.15;
  /* two lines then ellipsis: a 90-character film title must not push the
     device list off the bottom of the screen */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.nstream-close {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  color: var(--muted);
  background: transparent;
  border: var(--hair) solid transparent;
}
.nstream-close:hover { color: var(--ink); outline: var(--hair) solid var(--rule); }
.nstream-x path { stroke-width: 1.4; }

/* --- body ---------------------------------------------------------------- */

.nstream-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.nstream-note {
  margin: 0;
  padding: 14px var(--pad);
  color: var(--ink-2);
  line-height: 1.5;
}
.nstream-note.nstream-bad { color: var(--crit); }

/* Footnotes from the scan itself (devices.py `notes`, rejected hosts).  They
   are diagnostics, not choices, so they sit a clear step below the rows —
   small, muted, and never mistakable for a screen you could pick. */
.nstream-sub {
  margin: 0;
  padding: 9px var(--pad) 11px;
  color: var(--muted);
  font-size: 10.5px;
  line-height: 1.5;
}

/* the one place a scan is the primary action: nothing has ever looked */
.nstream-cta {
  display: block;
  width: calc(100% - var(--pad) * 2);
  margin: 0 var(--pad) 14px;
  height: 32px;
  background: var(--accent);
  color: var(--accent-ink);
  border: var(--hair) solid var(--accent);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.nstream-cta:hover { outline: var(--hair) solid var(--accent); outline-offset: 2px; }

/* --- device rows --------------------------------------------------------- */

.nstream-list { display: block; }

.nstream-dev {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  width: 100%;
  padding: 10px var(--pad);
  text-align: left;
  background: transparent;
  border: 0;
  /* hairline dividers, never zebra stripes */
  border-bottom: var(--hair) solid var(--rule);
  color: var(--ink);
  font: inherit;
  transition: background-color .1s linear;
}

.nstream-dev:hover:not(:disabled) { background: var(--panel-2); }
.nstream-dev:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.nstream-chev {
  flex: 0 0 auto;
  margin-top: 3px;
  color: var(--accent);           /* the one orange pixel per usable row */
}
.nstream-chev path { stroke-width: 1.4; }

.nstream-dev-c { min-width: 0; flex: 1 1 auto; display: block; }

.nstream-dev-top {
  display: flex;
  align-items: baseline;
  gap: 8px;
  justify-content: space-between;
}

/* The name identifies the screen a film is about to start on, so it wraps
   rather than clipping.  A truncated "[TV] Samsung 7 Series (5…" is exactly
   the character you cannot afford to lose when there are two Samsungs. */
.nstream-dev-n {
  font-weight: 700;
  letter-spacing: -.01em;
  min-width: 0;
  overflow-wrap: anywhere;
}

.nstream-tag {
  flex: 0 0 auto;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .14em;
  color: var(--muted);
  white-space: nowrap;
}

/* Every fact on this line came off the scan, so it wraps rather than
   ellipsing.  Clipping it hid "not answering · last seen 2 h ago" behind a
   "…" in testing — the single most important thing that line ever says. */
.nstream-dev-m {
  display: block;
  margin-top: 2px;
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;   /* addresses line up down the column */
  overflow-wrap: anywhere;
}

/* the reason a row cannot be used — wraps in full, never truncated */
.nstream-dev-r {
  display: block;
  margin-top: 5px;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--warn);
  white-space: normal;
}

.nstream-dev.is-out {
  cursor: not-allowed;
  color: var(--muted);
}
.nstream-dev.is-out .nstream-chev { visibility: hidden; }
.nstream-dev.is-out .nstream-dev-n { font-weight: 600; }

.nstream-dev.is-cold .nstream-dev-m { color: var(--warn); }

/* the row a cast was fired at */
.nstream-dev.is-target {
  background: var(--panel-2);
  box-shadow: inset 2px 0 0 var(--accent);
}
.nstream-dev:disabled:not(.is-out):not(.is-target) { opacity: .5; }

/* --- status: progress, then the stage ------------------------------------ */

/* THE STATE LIVES IN THE EDGE RULE, NOT IN THE TEXT.
   --crit on --panel-2 measures 3.98:1 in the vault and --ok 3.61:1 in the light
   table; at 12.5px bold neither is WCAG "large", so colouring the headline
   would have shipped two failing contrast pairs.  A 3px rule is a graphical
   object (3:1 floor, both themes clear it) and carries the same meaning
   louder, so the words stay at full ink. */
.nstream-status {
  flex: 0 0 auto;
  padding: 11px var(--pad) 12px;
  border-top: var(--hair) solid var(--rule);
  border-left: 3px solid var(--accent);     /* pending */
  background: var(--panel-2);
}

.nstream-status[data-ok="true"]  { border-left-color: var(--ok); }
.nstream-status[data-ok="false"] { border-left-color: var(--crit); }
/* "busy" is somebody else's cast in flight, not a failure */
.nstream-status[data-stage="busy"] { border-left-color: var(--warn); }

.nstream-st-top {
  display: flex;
  align-items: baseline;
  gap: var(--gap);
  justify-content: space-between;
}

.nstream-st-h {
  margin: 0;
  flex: 1 1 auto;
  font-weight: 700;
  line-height: 1.4;
}

.nstream-clock {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;   /* the clock must not jitter its width */
}

.nstream-st-d {
  margin: 5px 0 0;
  color: var(--ink-2);
  line-height: 1.5;
}

/* The next step — cast.py says what went wrong, this says what to press.
   It borrows the panel's own kicker idiom rather than a second vertical rule:
   the status block already has one at its edge, and two rules 16px apart read
   as fuss rather than structure. */
.nstream-st-fix {
  margin: 8px 0 0;
  color: var(--ink);
  font-weight: 600;
  line-height: 1.45;
}

.nstream-fix-k {
  display: block;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.nstream-st-code {
  margin: 7px 0 0;
  font-size: 10px;
  letter-spacing: .04em;
  color: var(--ink-2);
  text-transform: none;
}

/* the wait bar.  Indeterminate on purpose: /api/cast reports once, at the end,
   so a bar that claimed a percentage would be inventing one. */
.nstream-bar {
  margin-top: 9px;
  height: 2px;
  background: var(--rule);
  overflow: hidden;
}
.nstream-bar-i {
  width: 36%;
  height: 100%;
  background: var(--accent);
  animation: nstream-slide 1.15s linear infinite;
}
@keyframes nstream-slide {
  from { transform: translateX(-100%); }
  to   { transform: translateX(278%); }
}

.nstream-actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.nstream-mini {
  height: 24px;
  padding: 0 10px;
  background: transparent;
  color: var(--ink-2);
  border: var(--hair) solid var(--rule);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.nstream-mini:hover:not(:disabled) { color: var(--ink); outline: var(--hair) solid var(--rule); }
.nstream-mini:disabled { color: var(--muted); cursor: progress; }

/* screen-reader channel: the progress sentences are announced, not the clock */
.nstream-live {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- foot ---------------------------------------------------------------- */

.nstream-foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--gap);
  justify-content: space-between;
  padding: 8px var(--pad);
  border-top: var(--hair) solid var(--rule);
}

.nstream-foot-n {
  font-size: 10.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nstream-scan {
  flex: 0 0 auto;
  height: 24px;
  padding: 0 10px;
  background: transparent;
  color: var(--ink-2);
  border: var(--hair) solid var(--rule);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.nstream-scan:hover:not(:disabled) { color: var(--ink); outline: var(--hair) solid var(--rule); }
.nstream-scan:disabled { color: var(--muted); cursor: progress; }

/* when nothing has been scanned yet the footer button is redundant with the
   big CTA in the body — keep it, but let the CTA carry the weight */
.nstream-panel[data-view="unscanned"] .nstream-scan { display: none; }

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

@media (prefers-reduced-motion: reduce) {
  .nstream-btn,
  .nstream-dev { transition: none; }
  .nstream-btn:active { transform: none; }
  /* the bar stops travelling; it stays as a static accent rule so "waiting"
     is still visible without anything moving.  The elapsed clock keeps
     counting — that is information, not decoration. */
  .nstream-bar-i { animation: none; width: 100%; opacity: .5; }
}

/* --- forced colours -------------------------------------------------------- */

@media (forced-colors: active) {
  .nstream-btn {
    border: 1px solid ButtonText;
    forced-color-adjust: none;
    background: ButtonFace;
    color: ButtonText;
  }
  .nstream-btn:hover,
  .nstream-btn:focus-visible { background: Highlight; color: HighlightText; }
  .nstream-panel { border: 1px solid CanvasText; background: Canvas; }
  .nstream-dev { border-bottom: 1px solid CanvasText; }
  .nstream-dev.is-out { color: GrayText; }
  .nstream-bar-i { background: Highlight; }
}
