/* Streamify — the row grammar.
 *
 * Five slots read left to right: state · identity · context · number · action.
 * Every row renders all five cells even when a slot is empty, and every cell is
 * pinned to its own grid column, so hiding one can never re-seat the cells that
 * follow it. That is the whole reason this lives in hand-written CSS: the
 * collapse steps are *container* queries, because what constrains a row is the
 * width of the list it sits in, not the width of the viewport — and Tailwind 3.4
 * cannot express a container query without a plugin.
 *
 * Loaded after app.css and NOT processed by Tailwind.
 */

:root {
  --sf-row-template: minmax(0, 104px) minmax(200px, 1fr) minmax(0, 168px) minmax(0, 104px) 176px;
  --sf-row-template-narrow: minmax(0, 96px) minmax(140px, 1fr) 0px 0px 176px;
  --sf-onair-template: minmax(240px, 1fr) minmax(0, 200px) minmax(0, 128px) 200px;
  --sf-onair-template-narrow: minmax(180px, 1fr) 0px minmax(0, 116px) 180px;

  /* Media carries neither a state cell nor a number — the identity's usage
     line is the state — and its action column holds two buttons instead of
     one. That column is 240px exactly and cannot become anything else: 64px
     Delete (`w-16`) + 8px gap + 168px Create solo stream (`w-[168px]`), three
     numbers written in the template. Headroom over it buys nothing, and the
     narrow step has none to spare — the media list's content box is 635px
     inside a 1280px window, where the identity is what is left after the
     action, the row's 2 × 20px padding and four 16px gaps.
     The identity's floor is the widest line the meta's own grammar can print:
     `1024 MB · 12 h 45 m · uploaded 30 Sep 2026`, 42 monospace characters at
     7.2px = 302.4px, rounded to 304. `1.3 GB · 2 h · uploaded 26 Jul 2026`
     (252px measured) was one sample of that grammar, not its worst case, and
     the rows that print a `4 h 15 m` duration were truncated by it. The floor
     only binds in the wide step; the narrow step keeps the original 260px,
     which is inert above the 620px single-column step and is there so the
     track can never force the row wider than its list. */
  --sf-media-template: 0px minmax(304px, 1fr) minmax(0, 190px) 0px 240px;
  --sf-media-template-narrow: 0px minmax(260px, 1fr) 0px 0px 240px;

  --sf-row-pad-x: 12px;
  --sf-row-pad-y-compact: 12px;
  --sf-row-pad-y-comfortable: 16px;
  --sf-row-gap: 16px;
}

/* ---------------------------------------------------------------- list ---- */

.sf-list {
  container-type: inline-size;
  /* The row carries its own horizontal padding and the list is pulled out by
     the same amount, so the hover surface is co-extensive with the divider. */
  margin-inline: calc(var(--sf-row-pad-x) * -1);
  --row-template: var(--sf-row-template);
  --row-template-narrow: var(--sf-row-template-narrow);
  --row-pad-y: var(--sf-row-pad-y-compact);
  --row-min-height: 60px;
}

/* A list that sits in a card body carries the card's own padding on its rows.
   Its card is `padded=false` — the body *is* the card's border box — so there
   is no parent padding to bleed out of, and pulling out anyway put the list
   20px past the card on each side, out of sight only because the card clips. */
.sf-list[data-pad="card"] {
  --sf-row-pad-x: 20px;
  margin-inline: 0;
}

.sf-list[data-density="comfortable"] {
  --row-pad-y: var(--sf-row-pad-y-comfortable);
  --row-min-height: 72px;
}

.sf-list[data-template="media"] {
  --row-template: var(--sf-media-template);
  --row-template-narrow: var(--sf-media-template-narrow);
}

.sf-list[data-template="onair"] {
  --row-template: var(--sf-onair-template);
  --row-template-narrow: var(--sf-onair-template-narrow);
  --row-pad-y: var(--sf-row-pad-y-comfortable);
  --row-min-height: 88px;
  --sf-row-gap: 24px;
}

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

.sf-rowhead {
  display: grid;
  grid-template-columns: var(--row-template);
  gap: var(--sf-row-gap);
  align-items: center;
  padding: 0 var(--sf-row-pad-x) 12px;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 11px;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: rgb(var(--c-subtle));
}

.sf-rowhead > * { min-width: 0; }

/* ----------------------------------------------------------------- row ---- */

.sf-row {
  display: grid;
  grid-template-columns: var(--row-template);
  gap: var(--sf-row-gap);
  align-items: center;
  width: 100%;
  min-height: var(--row-min-height);
  box-sizing: border-box;
  padding: var(--row-pad-y) var(--sf-row-pad-x);
  text-align: left;
  border-top: 1px solid rgb(var(--c-line));
  transition: background-color 100ms linear, border-color 100ms linear, color 100ms linear;
}

.sf-row > * { min-width: 0; }

/* Cells are pinned by position, never by source order. */
.sf-row > *:nth-child(1) { grid-column: 1; }
.sf-row > *:nth-child(2) { grid-column: 2; }
.sf-row > *:nth-child(3) { grid-column: 3; }
.sf-row > *:nth-child(4) { grid-column: 4; }
.sf-row > *:nth-child(5) { grid-column: 5; }

.sf-cell-context { font-size: 12px; color: rgb(var(--c-muted)); }

.sf-cell-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
}

/* The copy of the number/channel rendered inside the identity cell; it only
   appears once the real cells have been dropped. */
.sf-inline-context { display: none; }

/* -------------------------------------------------------- collapse: 1000 -- */

@container (max-width: 1000px) {
  .sf-rowhead { grid-template-columns: var(--row-template-narrow); }
  .sf-rowhead > *:nth-child(3) { display: none; }

  .sf-row {
    grid-template-columns: var(--row-template-narrow);
    align-items: start;
  }

  /* The context cell MOVES under the identity instead of disappearing: it can
     hold a control, and a hidden control is a removed control. Written as a
     child selector so it outweighs the nth-child pinning above, which would
     otherwise hold the cell in a column that is now zero wide. */
  .sf-row > .sf-cell-context {
    grid-column: 2;
    grid-row: 2;
    margin-top: 8px;
  }

  .sf-optional { display: none !important; }
  .sf-inline-context { display: block; }
}

/* ------------------------------------------------- media re-widens: 838 -- */

/* The media row's wide template needs 838px of list — 304 + 190 + 240, four
   16px gaps and the row's own 2 × 20px padding — not the 1000px the five-slot
   generic row needs. Sharing that step collapsed media 200px early and left
   `--sf-media-template` unreachable below a 1920px window, so media re-widens
   the moment it fits and its context cell — a control, never a string — goes
   back to its own column.
   The step is the number the arithmetic above produces, and it is measured on
   the *content* box, which is why it is never rounded down: at 800–801 the old
   802 step's predecessor let the wide template in one track short, with the
   context squeezed under its declared 190px. It moved from 802 to 838 when the
   identity's floor was re-derived from the meta's grammar rather than from one
   sample of it (see the floor above) and the action track stopped keeping 8px
   it can never spend.
   What this step cannot do is reach a 1440px window: the list is 742px there
   (measured), 96px under the budget, and nothing left is for sale — the
   identity's floor is now the widest line it can print, and the action track
   is its two buttons to the pixel. The wide row first fits at a ~1600px
   window; below that the checkbox sits under the identity, which is a layout,
   not a failure. Every width the wide row does reach prints the meta in
   full. */
@container (min-width: 838px) {
  .sf-list[data-template="media"] .sf-row {
    grid-template-columns: var(--sf-media-template);
    align-items: center;
  }

  .sf-list[data-template="media"] .sf-row > .sf-cell-context {
    grid-column: 3;
    grid-row: 1;
    margin-top: 0;
  }
}

/* --------------------------------------------------------- collapse: 620 -- */

@container (max-width: 620px) {
  .sf-rowhead { display: none; }

  .sf-row { grid-template-columns: 1fr; }
  /* `grid-row` is reset too: the narrow step pinned the context cell to row 2,
     and leaving that in a single-column grid would push the identity below it. */
  .sf-row > * { grid-column: 1 !important; grid-row: auto !important; }

  /* One column turns a slot the row leaves empty — media renders no state cell
     (D33) — into a 0px grid row that still takes a `--sf-row-gap` after it, a
     dead 16px band above the identity of every row. The cell is only there to
     hold a column, and there are no columns here. */
  .sf-row > *:empty { display: none; }

  .sf-cell-actions {
    justify-content: flex-start;
    margin-top: 12px;
  }
}

/* --------------------------------------------------------------- fallback -- */

@supports not (container-type: inline-size) {
  @media (max-width: 1100px) {
    .sf-rowhead { grid-template-columns: var(--row-template-narrow); }
    .sf-rowhead > *:nth-child(3) { display: none; }

    .sf-row {
      grid-template-columns: var(--row-template-narrow);
      align-items: start;
    }

    .sf-row > .sf-cell-context {
      grid-column: 2;
      grid-row: 2;
      margin-top: 8px;
    }

    .sf-optional { display: none !important; }
    .sf-inline-context { display: block; }
  }
}
