/* The athlete's page.

   Flat and editorial like the rest of the network: rules rather than boxes,
   type doing the work, 2px between frames. Built around the stage -- an earlier
   pass led with a portrait and put the tape in a grid of thumbnails, which made
   a page about an athlete's film into a contact sheet.

   Every class is prefixed .nst-preview so this sheet can load beside both the
   front page's stylesheet and the directory's without colliding with either.
   Tokens come from whichever of those loaded first -- but only where that page
   defines them. The panel is opened from four pages now, and --r-pill was set
   by none of them, so "Enter their app" rendered as a pill on the directory
   and a hard rectangle on Ask NIL. The fallbacks below are what this panel
   needs to look like itself; a host that sets a token still wins. */
.nst-preview {
  --r-pill: var(--nst-r-pill, 999px);
}

/* Flat, not a panel. This sat inset from every edge with a rule around it and
   the page showing through behind -- a card of an athlete rather than their
   page. The sheet takes the whole window: no margin to float in, no border to
   read as a frame, and the film gets the width that padding was spending. */
.nst-preview { position: fixed; inset: 0; z-index: 95; display: block; padding: 0; }
.nst-preview[hidden] { display: none; }
.nst-preview__scrim { position: absolute; inset: 0; background: rgba(6, 6, 8, .93); backdrop-filter: blur(3px); }
.nst-preview__box {
  position: relative; width: 100%; height: 100%; max-height: none; overflow: auto;
  background: var(--panel, #0b0b0e); border: 0;
}
.nst-preview__wash {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(1100px 700px at 82% -6%, rgba(255,74,21,.07), transparent 62%);
}
.nst-preview__inner { position: relative; z-index: 1; }
.nst-locked { overflow: hidden; }
.nst-preview__glass { background: none; box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none; }

/* --- title bar ------------------------------------------------------------ */

.nst-preview__bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 15px var(--gutter, 32px); border-bottom: 1px solid var(--line, #1c1c20); }
/* The address, and the way to it. Underlined on the approach rather than at
   rest: a rule under it at all times competes with the athlete's name a line
   below, and this is a quiet thing until somebody reaches for it. */
.nst-preview__stamp {
  font-family: var(--mono); font-size: 10px; letter-spacing: .18em;
  color: var(--dim, #6d6d76); text-decoration: none;
  transition: color .18s ease;
}
.nst-preview__stamp[href] { cursor: pointer; }
.nst-preview__stamp[href]:hover { color: var(--orange, #ff4a15); text-decoration: underline; text-underline-offset: 3px; }
.nst-preview__stamp:focus { outline: none; }
.nst-preview__stamp:focus-visible { outline: 2px solid var(--orange, #ff4a15); outline-offset: 3px; }
.nst-preview__nav { display: flex; align-items: center; gap: 16px; }
.nst-preview__step { font-family: var(--cond); font-size: 13px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted, #a4a4ac); background: none; border: 0; padding: 4px 2px; cursor: pointer; }
.nst-preview__step:hover { color: var(--text, #f4f4f2); }
.nst-preview__step:disabled { opacity: .3; cursor: default; }
.nst-preview__step--close { color: var(--text, #f4f4f2); }
.nst-preview__step--close:hover { color: var(--orange, #ff4a15); }
.nst-preview__split { width: 1px; height: 18px; background: var(--line-strong, #26262c); }

/* --- the stage ------------------------------------------------------------ */

.nst-preview__film { display: grid; grid-template-columns: minmax(0, 1fr) 340px; }
.nst-preview__film[hidden] { display: none; }
.nst-preview__stage { position: relative; min-width: 0; border-right: 1px solid var(--line, #1c1c20); }
/* Tall enough to actually watch. The clip fills it; portrait video is centred
   on its own blurred backdrop rather than pillarboxed against flat black. */
/* Flex, not grid: a grid item's default min-height is its content, so a tall
   still refused to shrink and overflowed the stage instead of fitting it. */
/* Sized off the window now the sheet fills it. A flat 560px was measured
   against a panel that stopped at 94vh; against the whole screen it left the
   stage short on a tall display and overhanging on a laptop. */
/* The screen takes the whole stage.

   It was a fixed clamp(360px, 62vh, 720px) with the caption and the transport
   in a band underneath, so a landscape clip sat letterboxed in the middle of
   the frame while a third of the panel was flat black holding two lines of
   type. The copy goes onto the picture instead -- where it already sits in the
   cinema and on the hero -- and the clip gets the room back. */
.nst-preview__stage { display: flex; flex-direction: column; }
.nst-preview__screen {
  position: relative; flex: 1 1 auto; min-height: clamp(360px, 62vh, 720px);
  background: #000; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
/* Native video and stills keep their shape and are centred; an iframe cannot
   be measured from here, so it takes the whole stage rather than collapsing to
   its own tiny intrinsic size. */
/* Fit, never fill. `height: 100%` cropped a 16:9 clip's sides in a tall box;
   `height: auto` let a 1080x1350 still overflow it. Both dimensions are capped
   and the aspect ratio is kept, so the whole frame is always visible and the
   blurred still behind covers what it does not reach. */
.nst-preview__screen video:not(.nst-preview__screen-back),
.nst-preview__screen img:not(.nst-preview__screen-back) { position: relative; z-index: 1; max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; display: block; border: 0; }
.nst-preview__screen > video:not(.nst-preview__screen-back),
.nst-preview__screen > img:not(.nst-preview__screen-back) { min-width: 0; min-height: 0; }
.nst-preview__screen iframe { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; display: block; border: 0; }
/* Blown out and blurred behind, so a 9:16 clip sits in its own colour instead
   of two black bars. Either the clip itself, mirrored, or its poster where the
   footage cannot be copied -- an embed's frame is another origin's, and some
   moments never imported a thumbnail at all. The rules above exclude this by
   class, or the fit that keeps the clip in front whole would shrink the wash to
   the same rectangle and defeat it. */
.nst-preview__screen-back { position: absolute; inset: -8%; z-index: 0; width: 116%; height: 116%; object-fit: cover; filter: blur(38px) saturate(160%) brightness(.42); pointer-events: none; }
.nst-preview__screen-play { position: absolute; inset: 0; z-index: 2; display: grid; place-items: center; background: none; border: 0; cursor: pointer; }
.nst-preview__screen-play span { width: 74px; height: 74px; border-radius: 50%; background: var(--orange, #ff4a15); color: var(--ink, #08080a); display: grid; place-items: center; font-size: 26px; padding-left: 5px; }
.nst-preview__screen-play:hover span { filter: brightness(1.1); }

/* Laid on the clip, not under it. Its own wash rather than a solid band, so
   the bottom of the picture reads through it. */
.nst-preview__now {
  position: absolute; inset: auto 0 0 0; z-index: 3;
  padding: 56px var(--gutter, 32px) 18px;
  /* Deep enough to carry a headline and a scrub bar over whatever the clip is
     doing. A lighter wash left the transport reading against grass and sky --
     the time codes and the track vanished into the picture. */
  background: linear-gradient(transparent, rgba(6,6,10,.62) 26%, rgba(6,6,10,.95) 62%, rgba(6,6,10,.98));
  pointer-events: none;
}
.nst-preview__now > * { pointer-events: auto; }
/* Stated, not inherited: this copy is on a photograph now, so it does not turn
   with the panel's theme -- daylight was painting it near-black on the frame. */
:root[data-theme="light"] .nst-preview__now .nst-preview__now-title { color: #f4f4f2 !important; }
:root[data-theme="light"] .nst-preview__now .nst-preview__now-meta { color: #c8c8d0 !important; }
.nst-preview__now-head { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.nst-preview__now-flag { font-family: var(--mono); font-size: 9px; letter-spacing: .18em; color: var(--orange, #ff4a15); text-transform: uppercase; }
.nst-preview__now-meta { font-family: var(--mono); font-size: 10px; color: var(--dim, #6d6d76); }
.nst-preview__now-title { font-family: var(--cond); font-size: clamp(26px, 2.6vw, 40px); font-weight: 700; text-transform: uppercase; line-height: 1.02; padding-top: 8px; text-wrap: balance; }

/* The transport. Its own bar rather than the browser's: a YouTube embed has no
   native controls at all, and most of the network's film is YouTube. */
.nst-preview__transport { display: grid; grid-template-columns: auto auto minmax(80px, 1fr) auto auto; align-items: center; gap: 12px; padding-top: 16px; }
.nst-preview__transport[hidden] { display: none; }
.nst-preview__tp-play, .nst-preview__tp-sound {
  width: 32px; height: 32px; display: grid; place-items: center; padding: 0;
  border: 1px solid var(--line, #1c1c20); border-radius: 50%;
  background: none; color: var(--text, #f4f4f6); cursor: pointer;
}
.nst-preview__tp-play:hover, .nst-preview__tp-sound:hover { border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15); }
.nst-preview__tp-play svg, .nst-preview__tp-sound svg { width: 17px; height: 17px; display: block; }
.nst-preview__tp-time { font-family: var(--mono); font-size: 10px; color: var(--dim, #6d6d76); font-variant-numeric: tabular-nums; }
/* Four pixels of line, with the hit area reaching well past it -- a 4px target
   is not one anybody can hit. */
.nst-preview__tp-track { position: relative; height: 4px; border-radius: 2px; background: var(--hatch, #17171b); cursor: pointer; touch-action: none; }
.nst-preview__tp-track::before { content: ""; position: absolute; inset: -12px 0; }
.nst-preview__tp-track:focus-visible { outline: 2px solid var(--orange, #ff4a15); outline-offset: 4px; }
.nst-preview__tp-fill { height: 100%; width: 0; border-radius: 2px; background: var(--orange, #ff4a15); transition: width .3s linear; }

/* What is coming, once the clip is nearly done. */
.nst-preview__upnext { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding-top: 12px; font-family: var(--mono); font-size: 10px; letter-spacing: .12em; text-transform: uppercase; }
.nst-preview__upnext[hidden] { display: none; }
.nst-preview__upnext-label { color: var(--orange, #ff4a15); }
.nst-preview__upnext-title { color: var(--text, #f4f4f6); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 44ch; }
.nst-preview__upnext-count { color: var(--dim, #6d6d76); font-variant-numeric: tabular-nums; }
.nst-preview__upnext-go, .nst-preview__upnext-stop {
  font: inherit; letter-spacing: inherit; text-transform: inherit; cursor: pointer;
  padding: 4px 10px; border-radius: var(--r-pill); border: 1px solid var(--line, #1c1c20);
  background: none; color: var(--text, #f4f4f6);
}
.nst-preview__upnext-go { border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15); }
.nst-preview__upnext-go:hover { background: var(--orange, #ff4a15); color: var(--ink, #08080a); }
.nst-preview__upnext-stop:hover { border-color: var(--dim, #6d6d76); }

/* The queue: everything else they have, scrolling beside the stage. */
/* Both columns are the same fixed height and the queue scrolls inside its
   share. Left to grow, twelve clips stretched the row and left a black band
   under the video as tall as the queue. */
.nst-preview__queue { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
/* The row holds the screen and the copy under it, so it tracks the screen's
   own height rather than restating a number that has to be kept in step. */
.nst-preview__film { grid-auto-rows: calc(clamp(360px, 62vh, 720px) + 180px); }
.nst-preview__queue-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; padding: 16px var(--gutter, 32px) 12px; font-family: var(--mono); font-size: 9px; letter-spacing: .18em; color: var(--orange, #ff4a15); }
.nst-preview__queue-head span:last-child { color: var(--dim, #6d6d76); }
/* The list takes whatever the head and the filters leave, so a third row of
   pills shortens the scroll rather than pushing it off the bottom. */
.nst-preview__queue-list { flex: 1; min-height: 0; overflow-y: auto; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px 10px; padding: 4px 12px 14px; align-content: start; }
/* A bigger frame. At 104x60 the thumbnail was too small to tell one clip from
   another -- a face, a jersey and a scoreboard all read as a dark smear -- and
   the queue is how the reader chooses what to watch. 4:3 rather than a fixed
   height, so a portrait clip is not letterboxed into a strip. */
/* Two across, the way the front page lays its rail out. As a list of wide rows
   this showed four of an athlete's moments before the fold and read as a
   sidebar of links; in pairs the same column holds eight, and each one is a
   frame you can see rather than a thumbnail beside a headline. */
.nst-preview__q { display: block; padding: 0; cursor: pointer; border-left: 0; transition: transform .22s ease; }
.nst-preview__q:hover { background: none; transform: translateY(-2px); }
.nst-preview__q.is-on { background: none; }
/* The mark of what is playing moves onto the frame itself: there is no longer a
   row edge to carry it. */
.nst-preview__q.is-on .nst-preview__q-shot { outline: 2px solid var(--orange, #ff4a15); outline-offset: -2px; }
/* 4:5, as on the front page. Most of what athletes post is shot upright, and a
   4:3 crop of a portrait clip is mostly the middle of somebody. */
.nst-preview__q-shot { position: relative; aspect-ratio: 4 / 5; background: var(--hatch); overflow: hidden; border-radius: 3px; }

/* Ten rows, then five at a time. Set as a full-width row rather than a chip so
   it reads as the end of the list rather than as another clip in it. */
.nst-preview__more {
  display: block; width: 100%; padding: 14px var(--gutter, 32px);
  background: none; border: 0; border-top: 1px solid rgba(255,255,255,.07);
  color: var(--orange, #ff4a15); font-family: var(--mono); font-size: 10px;
  letter-spacing: .16em; text-align: left; cursor: pointer;
}
.nst-preview__more:hover { background: rgba(255,74,21,.06); }
.nst-preview__q-shot img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Top right, on its own plate -- the same place the front page's rail puts it.
   Bottom-left is where a portrait clip's subject usually is. */
.nst-preview__q-time { position: absolute; right: 6px; top: 6px; bottom: auto; padding: 2px 5px; border-radius: 3px; background: rgba(8,8,10,.86); font-family: var(--mono); font-size: 10px; letter-spacing: .03em; color: var(--text, #f4f4f2); }
.nst-preview__q-text { min-width: 0; padding: 6px 1px 0; }
/* One line, cut with an ellipsis. Wrapping made a cell as tall as its own
   title, so "Full game highlights vs North Lenoir" beside "Turnover in game"
   left the two frames of a pair at different heights and every row under them
   ragged. One line each and the grid holds its shape whatever the titles say. */
.nst-preview__q-title { font-family: var(--cond); font-size: 13px; font-weight: 600; text-transform: uppercase; line-height: 1.12; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.nst-preview__q.is-on .nst-preview__q-title { color: var(--orange, #ff4a15); }
.nst-preview__q-meta { font-family: var(--mono); font-size: 9px; color: var(--dim, #6d6d76); padding-top: 4px; }

/* One line, scrolled sideways. Wrapping put six sections on three rows and
   took a fifth of the queue's height to do it. */
.nst-preview__pills { display: flex; gap: 6px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding: 11px var(--gutter, 32px) 12px; border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__pills::-webkit-scrollbar { display: none; }
.nst-preview__pill { flex: 0 0 auto; font-family: var(--mono); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; padding: 7px 11px; color: var(--dim, #6d6d76); border: 1px solid var(--line, #1c1c20); background: none; cursor: pointer; white-space: nowrap; }
.nst-preview__pill:hover { color: var(--text, #f4f4f2); border-color: var(--line-strong, #26262c); }
.nst-preview__pill.is-on { background: var(--text, #f4f4f2); color: var(--ink, #08080a); border-color: var(--text, #f4f4f2); }

/* --- who this is ---------------------------------------------------------- */

.nst-preview__id { display: flex; align-items: center; gap: 40px; flex-wrap: wrap; padding: 26px var(--gutter, 32px); border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__who { display: flex; align-items: center; gap: 18px; min-width: 0; flex: 1; }
.nst-preview__face { position: relative; width: 84px; height: 84px; flex-shrink: 0; background: var(--hatch); overflow: hidden; display: block; }
.nst-preview__face img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.nst-preview__names { min-width: 0; }
.nst-preview__kicker { display: block; font-family: var(--mono); font-size: 10px; letter-spacing: .2em; color: var(--orange, #ff4a15); text-transform: uppercase; }
.nst-preview__name { margin: 0; font-family: var(--cond); font-size: clamp(34px, 3.6vw, 60px); font-weight: 700; text-transform: uppercase; line-height: .92; padding-top: 6px; text-wrap: balance; }
/* The verified marks ride with the name rather than over the portrait. */
.nst-preview__tags { display: none; }
.nst-preview__tag[hidden] { display: none; }

.nst-preview__stats { display: flex; flex-wrap: wrap; gap: 30px; }
.nst-preview__stat-value { font-family: var(--cond); font-size: 40px; font-weight: 700; line-height: 1; }
.nst-preview__stat--lead .nst-preview__stat-value { color: var(--orange, #ff4a15); }
.nst-preview__stat-label { font-family: var(--mono); font-size: 9px; letter-spacing: .16em; color: var(--dim, #6d6d76); padding-top: 5px; text-transform: uppercase; }

.nst-preview__actions { display: flex; gap: 8px; flex-wrap: wrap; }
.nst-preview__btn { font-family: var(--cond); font-size: 15px; letter-spacing: .16em; text-transform: uppercase; font-weight: 600; border: 1px solid var(--line-strong, #26262c); background: none; color: var(--muted, #a4a4ac); padding: 15px 22px; cursor: pointer; }
.nst-preview__btn:hover { border-color: var(--text, #f4f4f2); color: var(--text, #f4f4f2); }
.nst-preview__btn--go { background: var(--orange, #ff4a15); border-color: var(--orange, #ff4a15); color: var(--ink, #08080a); padding: 15px 26px; }
.nst-preview__btn--go:hover { color: var(--ink, #08080a); filter: brightness(1.08); }
.nst-preview__btn[hidden] { display: none; }

.nst-preview__lede { margin: 0; font-size: 17px; line-height: 1.5; color: var(--muted, #a4a4ac); padding: 0 var(--gutter, 32px) 26px; max-width: 760px; text-wrap: pretty; }
.nst-preview__lede:empty { display: none; }

/* --- section heads -------------------------------------------------------- */

.nst-preview__section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 18px; flex-wrap: wrap; padding: 26px var(--gutter, 32px) 12px; border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__section-head[hidden] { display: none; }
.nst-preview__label { font-family: var(--mono); font-size: 10px; letter-spacing: .2em; color: var(--orange, #ff4a15); }
.nst-preview__note { font-family: var(--mono); font-size: 10px; letter-spacing: .06em; color: var(--dim, #6d6d76); }

/* Figures on a rule, not boxes. Bordered cards read as buttons and fought the
   flat sheet everything else sits on; a divider between columns says the same
   thing without drawing five rectangles. */
.nst-preview__socials { display: flex; flex-wrap: wrap; padding: 0 var(--gutter, 32px) 28px; }
.nst-preview__socials:empty { display: none; }
.nst-preview__social { display: block; padding: 2px 34px 2px 0; margin-right: 34px; min-width: 0; border-right: 1px solid var(--line, #1c1c20); }
.nst-preview__social:last-child { border-right: 0; margin-right: 0; padding-right: 0; }
.nst-preview__social-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.nst-preview__social-net { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 9px; letter-spacing: .18em; color: var(--orange, #ff4a15); }
.nst-preview__social-mark { width: 13px; height: 13px; flex-shrink: 0; }
.nst-preview__social-state { font-family: var(--mono); font-size: 9px; color: var(--faint, #4a4a52); flex-shrink: 0; }
.nst-preview__social-count { font-family: var(--cond); font-size: 30px; font-weight: 700; line-height: 1.05; padding-top: 8px; }
.nst-preview__social-foot { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; padding-top: 4px; }
.nst-preview__social-handle { font-family: var(--mono); font-size: 11px; color: var(--dim, #6d6d76); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* No follower count is stored yet, so with nothing above it the handle is the
   cell and is set to carry rather than sitting under an empty space. */
.nst-preview__social-handle--lead { font-family: var(--cond); font-size: 21px; font-weight: 600; letter-spacing: 0; color: var(--text, #f4f4f2); padding-top: 8px; }
.nst-preview__social:hover .nst-preview__social-handle { color: var(--text, #f4f4f2); }
.nst-preview__social-delta { font-family: var(--mono); font-size: 10px; color: #5ee6a8; flex-shrink: 0; }

/* --- offers and their words ----------------------------------------------- */

.nst-preview__split-row { display: grid; grid-template-columns: 1fr 1fr; border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__panel { padding: 26px var(--gutter, 32px); min-width: 0; }
/* Only when something follows it. A panel left alone by its hidden neighbour
   kept a rule down its right edge with nothing on the other side. */
.nst-preview__panel:first-child:not(:last-child) { border-right: 1px solid var(--line, #1c1c20); }
.nst-preview__split-row:has(.nst-preview__panel[hidden]) .nst-preview__panel { border-right: 0; }
.nst-preview__panel[hidden] { display: none; }
.nst-preview__split-row:has(.nst-preview__panel[hidden]) { grid-template-columns: 1fr; }
.nst-preview__panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding-bottom: 16px; }
.nst-preview__when { font-family: var(--mono); font-size: 10px; color: var(--dim, #6d6d76); }

.nst-preview__offer { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 12px 0; border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__offer:last-child { border-bottom: 1px solid var(--line, #1c1c20); }
.nst-preview__offer-school { font-family: var(--cond); font-size: 24px; font-weight: 600; text-transform: uppercase; line-height: 1.05; }
.nst-preview__offer--more .nst-preview__offer-school { color: var(--muted, #a4a4ac); }
.nst-preview__offer-date { flex-shrink: 0; font-family: var(--mono); font-size: 9px; letter-spacing: .14em; color: var(--ink, #08080a); background: var(--orange, #ff4a15); padding: 5px 9px; font-weight: 700; }
.nst-preview__offer--more .nst-preview__offer-date { color: var(--dim, #6d6d76); background: none; padding: 0; font-weight: 400; }

/* Several captions, the first set large and the rest following it, so the
   panel fills rather than leaving one short line over a half-page of black. */
.nst-preview__quote { margin: 0; }
.nst-preview__quote:empty { display: none; }
.nst-preview__said { display: block; padding: 14px 0; border-top: 1px solid var(--line, #1c1c20); cursor: pointer; }
.nst-preview__said:first-child { border-top: 0; padding-top: 0; }
.nst-preview__said-text { display: block; font-family: var(--cond); font-size: 22px; font-weight: 500; line-height: 1.2; color: var(--muted, #a4a4ac); text-wrap: pretty; transition: color .18s ease; }
.nst-preview__said--lead .nst-preview__said-text { font-size: clamp(26px, 2.2vw, 34px); color: var(--text, #f4f4f2); }
.nst-preview__said:hover .nst-preview__said-text { color: var(--orange, #ff4a15); }
.nst-preview__said-when { display: block; font-family: var(--mono); font-size: 9px; letter-spacing: .14em; color: var(--faint, #4a4a52); padding-top: 7px; }
.nst-preview__quote:empty { display: none; }
.nst-preview__strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 2px; }
.nst-preview__strip:empty { display: none; }
.nst-preview__frame { position: relative; height: 96px; background: var(--hatch); overflow: hidden; cursor: pointer; }
.nst-preview__frame img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.nst-preview__frame::after { content: ""; position: absolute; inset: 0; background: linear-gradient(#0000 45%, rgba(8,8,10,.85)); }
.nst-preview__frame:hover img { opacity: .82; }
.nst-preview__frame-tag { position: absolute; left: 9px; bottom: 8px; z-index: 2; font-family: var(--mono); font-size: 9px; letter-spacing: .12em; color: var(--text, #f4f4f2); text-shadow: 0 1px 6px rgba(8,8,10,.9); }

.nst-preview__talk { border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__talk[hidden] { display: none; }
.nst-preview__comments { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 0 40px; }
.nst-preview__comment { border-top: 1px solid var(--line, #1c1c20); padding: 14px 0 16px; min-width: 0; }
.nst-preview__comment-text { font-size: 16px; line-height: 1.45; color: var(--muted, #a4a4ac); text-wrap: pretty; }
.nst-preview__comment-by { font-family: var(--mono); font-size: 9px; letter-spacing: .12em; color: var(--faint, #4a4a52); padding-top: 8px; }

.nst-preview__foot { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 17px var(--gutter, 32px); border-top: 1px solid var(--line, #1c1c20); font-family: var(--mono); font-size: 10px; letter-spacing: .16em; color: var(--dim, #6d6d76); text-transform: uppercase; }
.nst-preview__place { margin-left: auto; color: var(--faint, #4a4a52); }

/* --- reflow --------------------------------------------------------------- */

@media (max-width: 1100px) {
  /* No inset here either. The sheet is flat at every width now, and a panel
     that floats on a narrow screen wastes the little room there is. */
  .nst-preview { padding: 0; }
  .nst-preview__film { grid-template-columns: 1fr; }
  .nst-preview__stage { border-right: 0; }
  .nst-preview__screen { height: 46vh; }
  .nst-preview__queue { border-top: 1px solid var(--line, #1c1c20); }
  .nst-preview__queue-list { max-height: 300px; }
  .nst-preview__split-row { grid-template-columns: 1fr; }
  .nst-preview__panel:first-child { border-right: 0; border-bottom: 1px solid var(--line, #1c1c20); }
}

@media (max-width: 700px) {
  .nst-preview { padding: 0; }
  .nst-preview__box { max-height: 100vh; border: 0; }
  .nst-preview__screen { height: 38vh; }

  /* Who this is, before their film.

     In source order the identity band sits after the stage and the queue,
     which is right on a wide screen -- the queue is a column beside the clip,
     so the name still reads high on the page. Stacked on a phone it put 1300
     points of stage and queue above the athlete's own name: the panel opened
     on a photo with no name, no stats and no way into their app until you
     scrolled past all of it.

     This lives here rather than in the phone sheet because the phone sheet is
     loaded by the network page alone. The same panel opens from Ask NIL, which
     loads only this file -- so the reordering never reached it and the two
     pages showed the same athlete two different ways.

     Every child is numbered. An unordered flex item defaults to 0, so naming
     only the ones that move sends the rest to the top. */
  .nst-preview__inner { display: flex; flex-direction: column; }
  .nst-preview__bar { order: 1; }
  .nst-preview__id { order: 2; }
  .nst-preview__lede { order: 3; }
  .nst-preview__film { order: 4; }
  .nst-preview__section-head { order: 5; }
  .nst-preview__socials { order: 6; }
  .nst-preview__split-row { order: 7; }
  .nst-preview__talk { order: 8; }
  .nst-preview__foot { order: 9; }

  /* Three bands stacked -- face and name, then the figures, then the two ways
     in. Left as a row the portrait and the stats split the width and the
     kicker broke across three lines, pushing the name down. */
  .nst-preview__id {
    flex-direction: column; align-items: stretch;
    padding-top: 18px; padding-bottom: 18px;
    border-top: 0; border-bottom: 1px solid var(--line, #1c1c20);
  }
  .nst-preview__who { flex: 0 0 auto; gap: 14px; }
  .nst-preview__name { font-size: 26px; }
  .nst-preview__kicker { font-size: 9px; letter-spacing: .12em; line-height: 1.5; }

  .nst-preview__id { gap: 22px; }
  .nst-preview__face { width: 60px; height: 60px; }
  .nst-preview__stats { gap: 22px; }
  .nst-preview__stat-value { font-size: 32px; }
  .nst-preview__strip { grid-template-columns: repeat(2, 1fr); }
  .nst-preview__actions .nst-preview__btn { flex: 1; text-align: center; }
}

/* --- shape -----------------------------------------------------------------

   The dialog follows the page's own radius tokens rather than carrying a scale
   of its own -- if --r changes, this changes with it and the sheet cannot drift
   out of step with the cards behind it.

   What it does add is a shape for the surfaces the base sheet never rounded,
   because they only exist here: the sheet itself, the film, the queue rows and
   the athlete's portrait. */

/* Square, now the sheet meets the window on all four sides. A rounded corner
   against the edge of the screen reads as a card sitting on the page, which is
   the thing this stopped being. */
.nst-preview__box { border-radius: 0; }
/* The film is a frame inside that sheet rather than the sheet itself, so it
   takes a corner. It reaches the window on the left only; rounding all four
   keeps the shape consistent whichever side is against an edge, and the copy
   laid on it now needs a frame to sit inside rather than a hard rectangle. */
.nst-preview__screen { border-radius: 16px; }

.nst-preview__face { border-radius: var(--r-sm); }
.nst-preview__q-shot { border-radius: var(--r-sm); }
/* The left edge stays square -- it carries the orange bar marking what is
   playing, and a radius there clips it to a sliver. */
/* The frame carries the shape now; the cell around it has no edge of its own. */
.nst-preview__q { border-radius: 0; }
.nst-preview__q-time { border-radius: 3px; padding: 1px 4px; background: rgba(8,8,10,.72); }
.nst-preview__pill { border-radius: var(--r-pill); }
.nst-preview__strip img, .nst-preview__strip > * { border-radius: var(--r-sm); }

/* Both actions are pills -- the same shape the header's buttons use, which is
   what marks a thing on this page as something you press. */
.nst-preview__btn { border-radius: var(--r-pill); }

/* Same drawn icons as the player bar -- see the note in
   nilsportstech-network-v2.css. Type-sized here, since both sit beside a label
   rather than alone in a round button. */
.nst-preview__step svg, .nst-preview__btn svg {
  width: 1em; height: 1em; flex: 0 0 auto;
}
.nst-preview__step, .nst-preview__btn { display: inline-flex; align-items: center; gap: .5em; }
.nst-preview__step--close { justify-content: center; }

/* --- the panel on a phone --------------------------------------------------

   These rules used to live in nilsportstech-network-v2-mobile.css, which only
   the network page loads. The panel is a shared partial -- Ask NIL and the NIL
   apps directory open the same markup -- so on those two pages it rendered
   with none of this: the raw "PREVIEW · APP #1 ON NILSPORTSTECH" stamp still
   showing, a full-width slab where the pill buttons belong, and no Play their
   year beside it. Moving them next to the component they style means any page
   that includes the partial gets the phone treatment for free.

   They stay last in the file so they still win on order over the 700px block
   above, which is the arrangement they were written against. */
/* --- the athlete's page ----------------------------------------------------

   Opened over whatever view you were on. Its desktop styles are in
   nilsportstech-athlete-preview.css, which loads before this file -- so these
   rules win on order, the same arrangement the directory uses.

   The 1100px block already stacks the stage and the queue into one column. What
   it does not undo is the row height they were given for sitting side by side,
   which is what left a screen's worth of black under the clip. */

@media (max-width: 760px) {
  /* 660px per row is a side-by-side measure: stacked, the stage needs only what
     the clip and its title come to, and the queue only its rows. Fixed rows put
     218px of dead black under each. */
  .nst-preview__film { grid-auto-rows: auto; }
  .nst-preview__stage { min-height: 0; }
  /* The clip sizes to the screen it is on rather than a share of the viewport,
     and the queue below it is reachable without a long scroll past nothing. */
  .nst-preview__screen { height: min(52vh, 360px); }
  .nst-preview__queue-list { max-height: none; }
  /* The sheet fills the screen here, so its corners have nothing to round
     against -- a radius on a full-bleed surface leaves four lit slivers where
     the page shows through. The rows and controls inside keep theirs. */
  .nst-preview__box { border-radius: 0; }
  .nst-preview__screen { border-radius: 0; }

  /* Top bar. "PREVIEW · APP #109 ON NILSPORTSTECH" wrapped to two lines and
     pushed the controls into each other, so the stamp goes -- the dialog is
     plainly a preview from what is in it -- and the steps become three even
     targets on one line. */
  /* Three labels stretched across a line read as a row of tabs, and the browser
     drew a focus ring around whichever was last pressed. Two groups instead:
     Prev and Next as one paired control on the left -- they do the same kind of
     thing in opposite directions -- and Close on the right, which is the only
     one that leaves. */
  /* Clear of the status bar. The 700px block in the athlete sheet sets
     "padding: 0" on the dialog and caps the box at 100vh, so the whole thing is
     pinned flush to the top of the screen -- padding inside the bar could not
     move it down, because the bar's own top edge was already under the clock.
     The room has to come from the container. */
  .nst-preview { padding-top: env(safe-area-inset-top); }
  .nst-preview__box { max-height: calc(100svh - env(safe-area-inset-top)); }
  .nst-preview__bar {
    gap: 10px; padding: 8px var(--gutter, 16px);
    background: rgba(8,8,10,.72); backdrop-filter: blur(12px);
  }
  .nst-preview__stamp { display: none; }
  /* No gap: the pair only reads as one control if its halves actually touch.
     Close is pushed away by its own auto margin instead. */
  .nst-preview__nav { width: 100%; gap: 0; justify-content: flex-start; }
  /* Prev and Next share one outline, split by a hairline. */
  .nst-preview__step {
    flex: 0 0 auto; min-height: 36px; display: inline-flex;
    align-items: center; justify-content: center; gap: 6px;
    padding: 0 14px; white-space: nowrap;
    font-size: 11px; letter-spacing: .12em;
    border: 1px solid var(--line-strong, #26262c);
    border-radius: var(--r-pill); background: rgba(244,244,242,.04);
    /* The label is named rather than left to --muted: the pair sits on the
       panel's own bar, which turns with the theme, so the ink has to turn with
       it. It did not, and PREV and NEXT were grey on grey in daylight. */
    color: var(--muted, #a4a4ac);
  }
  .nst-preview__step svg { width: 13px; height: 13px; }
  /* The pair reads as one control: adjoining edges square, outer ends round. */
  [data-preview-prev] { border-radius: var(--r-pill) 0 0 var(--r-pill); border-right-width: 0; }
  [data-preview-next] { border-radius: 0 var(--r-pill) var(--r-pill) 0; }
  .nst-preview__step--close {
    border-radius: var(--r-pill); border-color: transparent;
    background: rgba(244,244,242,.08); color: var(--text, #f4f4f2);
    width: 36px; padding: 0; margin-left: auto;
  }
  /* An icon alone -- "Close" beside an X is the same word twice. */
  .nst-preview__step--close span { display: none; }
  .nst-preview__step--close svg { width: 15px; height: 15px; }
  /* Pressed state only for keyboards; a tap should not leave a ring behind. */
  .nst-preview__step:focus { outline: none; }
  .nst-preview__step:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
  .nst-preview__split { display: none; }

  /* Whose page this is comes before their film.

     In source order the identity band sits after the stage and the queue, which
     on a wide screen is fine -- the queue is a column beside the clip, so the
     name is still high on the page. Stacked, that put it below a clip and every
     row of the queue: you scrolled two screens to find out who you were looking
     at. Ordering here rather than in the markup keeps the desktop sequence,
     where the band reads correctly as a caption under the stage.

     Every child is numbered. An unordered flex item defaults to 0, so naming
     only the ones that move would send the rest to the top. */
  .nst-preview__inner { display: flex; flex-direction: column; }
  .nst-preview__bar { order: 1; }
  .nst-preview__id { order: 2; }
  .nst-preview__lede { order: 3; }
  .nst-preview__film { order: 4; }
  .nst-preview__section-head { order: 5; }
  .nst-preview__socials { order: 6; }
  .nst-preview__split-row { order: 7; }
  .nst-preview__talk { order: 8; }
  .nst-preview__foot { order: 9; }

  /* Three bands stacked -- face and name, then the figures, then the two ways
     in. Left as a row, the portrait and the stat block split the width between
     them and the kicker broke across three lines ("BASKETBALL · ✓ / VERIFIED ·
     / POSTED 14H AGO"), pushing the name down. */
  .nst-preview__id {
    flex-direction: column; align-items: stretch; gap: 16px;
    padding-top: 18px; padding-bottom: 18px;
    /* Its top rule separated it from the stage above; now it opens the sheet. */
    border-top: 0; border-bottom: 1px solid var(--line, #1c1c20);
  }
  .nst-preview__who { flex: 0 0 auto; gap: 14px; }
  .nst-preview__name { font-size: 26px; }
  .nst-preview__face { width: 52px; height: 52px; flex: 0 0 auto; }
  /* The whole line, so it breaks once at most. */
  .nst-preview__kicker { font-size: 9px; letter-spacing: .12em; line-height: 1.5; }
  .nst-preview__stats { gap: 18px; flex-wrap: wrap; }
  .nst-preview__stat-value { font-size: 26px; }
  .nst-preview__actions { width: 100%; gap: 8px; }
  /* "Enter <name>'s app" is as long as the athlete's name, so the label wraps
     inside the button whatever the width. Smaller type and tighter tracking
     keep both on one line. */
  .nst-preview__actions .nst-preview__btn {
    flex: 1; text-align: center; min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 12px 14px; font-size: 12px; letter-spacing: .08em;
  }

  /* Panel heads: label on its own line, the note under it. Side by side both
     wrapped -- "WHAT PEOPLE ARE SAYING" over two lines with "15 UNDER THEIR
     FILM · FROM THE POST" over two more, for a four-line head above one comment.
     Same shape as the front page's section heads. */
  .nst-preview__panel-head, .nst-preview__section-head {
    display: grid; grid-template-columns: 1fr; gap: 3px;
  }
  .nst-preview__note, .nst-preview__when { font-size: 9px; letter-spacing: .12em; }

  .nst-preview__now-title { font-size: 20px; }
  .nst-preview__lede { font-size: 15px; }
  .nst-preview__strip { grid-template-columns: repeat(2, 1fr); }
  /* The last line is a warning that the next tap leaves the network, so it gets
     its own line rather than being pushed to the right of the URL. */
  .nst-preview__foot { gap: 6px; padding: 14px var(--gutter, 16px); }
  .nst-preview__place { margin-left: 0; }
}

/* --- their film, one clip a screen ---------------------------------------- */

/* Over the panel rather than inside it. A moment in the grid used to swap the
   small stage further up the sheet, so tapping a clip changed something the
   reader had already scrolled past and nothing appeared to happen. */
.nst-preview__cinema {
  position: fixed; inset: 0; z-index: 97; background: var(--ink, #08080a);
}
.nst-preview__cinema[hidden] { display: none; }
.nst-preview__cinema-close {
  position: absolute; top: calc(12px + env(safe-area-inset-top)); right: 14px; z-index: 2;
  width: 36px; height: 36px; display: grid; place-items: center; padding: 0;
  border-radius: 50%; cursor: pointer;
  /* Not var(--text): the disc is a fixed dark glass whatever the theme does, so
     the chevron on it has to be light whatever the theme does too. Inheriting
     the page's ink turned it near-black on that disc in daylight -- the button
     was still there and still worked, but nothing could be seen on it. */
  color: #f4f4f2;
  background: rgba(8,8,10,.55); border: 1px solid rgba(255,255,255,.16);
}
.nst-preview__cinema-close svg { width: 19px; height: 19px; display: block; }
.nst-preview__cinema-close:hover { border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15); }

/* The run itself. Snapped so a swipe lands on a clip rather than between two,
   and mandatory so it cannot rest halfway. */
.nst-preview__reel {
  height: 100%; overflow-y: auto; overscroll-behavior-y: contain;
  scroll-snap-type: y mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
}
.nst-preview__reel::-webkit-scrollbar { display: none; }

.nst-preview__panel-clip {
  position: relative; height: 100%; scroll-snap-align: start; scroll-snap-stop: always;
  display: flex; align-items: center; justify-content: center; background: #000;
}
.nst-preview__clip-frame { position: absolute; inset: 0; overflow: hidden; }
/* The clip keeps its own shape -- a reel is not cropped to fill a phone -- and
   a blurred, overscaled copy of its own poster fills what is left, so the black
   bands either side become part of the frame rather than a hole in it. */
.nst-preview__clip-frame::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: var(--clip-wash, none) center / cover no-repeat;
  filter: blur(38px) saturate(140%) brightness(.5);
  transform: scale(1.3);
}
.nst-preview__clip-frame video:not(.nst-preview__clip-mirror),
.nst-preview__clip-frame iframe {
  position: relative; z-index: 1;
  width: 100%; height: 100%; object-fit: contain; display: block; border: 0;
}
/* The poster, OVER the clip rather than beside it.

   It shared `position: relative` with the video and came first in the frame,
   so the two stacked in document order and the still took the space -- the
   clip mounted, played and drove the transport underneath a frozen frame,
   while the blurred mirror behind it moved. That reads as a video that will
   not play, which is the one thing it is not.

   Faded out once the clip is actually rendering, so a slow file still shows
   its poster rather than black. */
.nst-preview__clip-still {
  position: absolute; inset: 0; z-index: 2;
  width: 100%; height: 100%; object-fit: contain; display: block; border: 0;
  transition: opacity 220ms ease;
}
.nst-preview__clip-frame.is-playing .nst-preview__clip-still {
  opacity: 0;
  pointer-events: none;
}
/* The copy behind it, covering rather than fitting -- filling the bands is its
   whole job, so it is the one thing here that crops. */
.nst-preview__clip-mirror {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover; display: block; border: 0;
  filter: blur(34px) saturate(140%) brightness(.52);
  transform: scale(1.2); pointer-events: none;
}

/* The reel's own controls, on the clip. */
.nst-preview__clip-bar {
  position: absolute; inset: auto 0 0 0; z-index: 3;
  display: flex; align-items: center; gap: 12px;
  padding: 14px var(--gutter, 20px) calc(16px + env(safe-area-inset-bottom));
  background: linear-gradient(transparent, rgba(6,6,10,.92));
}
.nst-preview__clip-btn {
  flex: 0 0 auto; width: 34px; height: 34px; border: 0; border-radius: 50%;
  background: rgba(244,244,242,.14); color: var(--text, #f4f4f2);
  display: grid; place-items: center; cursor: pointer;
}
.nst-preview__clip-btn svg { width: 15px; height: 15px; display: block; }
.nst-preview__clip-time {
  flex: 0 0 auto; font-family: var(--mono, monospace); font-size: 10px;
  letter-spacing: .06em; color: var(--muted, #a4a4ac); min-width: 62px;
}
.nst-preview__clip-track {
  position: relative; flex: 1 1 auto; height: 3px; cursor: pointer;
  background: rgba(244,244,242,.2); border-radius: 999px;
}
/* A 3px line is not a thumb target; the hit area reaches past it. */
.nst-preview__clip-track::before { content: ""; position: absolute; inset: -12px 0; }
.nst-preview__clip-track > span {
  display: block; height: 100%; width: 0;
  background: var(--orange, #ff4a15); border-radius: 999px;
}

/* Whose clip it is on the left, the way into their app on the right -- the
   same row the feed carries, spanning the overlay so the button has an edge to
   sit against rather than being pressed up beside the name. */
.nst-preview__clip-by {
  display: flex; align-items: center; gap: 14px;
  width: 100%; padding-top: 14px;
}
/* Round, and its picture fills it. The shared .nst-avatar rules are on the
   directory's sheet, which this layer sits over rather than inside -- so the
   face was an empty square. */
.nst-preview__clip-face {
  position: relative; width: 54px; height: 54px; flex: 0 0 auto;
  border-radius: 50%; overflow: hidden; background: #1b1b22;
  display: grid; place-items: center;
  font-family: var(--cond, sans-serif); font-size: 24px; font-weight: 700;
  color: var(--muted, #a4a4ac);
}
.nst-preview__clip-face img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.nst-preview__clip-who { min-width: 0; }
.nst-preview__clip-name {
  font-family: var(--cond, sans-serif); font-size: 19px; font-weight: 700;
  text-transform: uppercase; line-height: 1.05;
}
.nst-preview__clip-sport {
  font-family: var(--mono, monospace); font-size: 10px; letter-spacing: .12em;
  color: #a4a4ac; text-transform: uppercase; padding-top: 2px;
}
.nst-preview__clip-app {
  flex: 0 0 auto; margin-left: auto;
  /* The size the network's own feed settled on. Bigger, it reads as a banner
     laid across somebody's film rather than a way into their app. */
  font-family: var(--cond, sans-serif); font-size: 12px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase;
  background: var(--orange, #ff4a15); color: #0a0a0a;
  border: 0; border-radius: 999px; padding: 10px 18px;
  text-decoration: none; white-space: nowrap;
}

/* The clip's own details laid on it, so the picture keeps the whole screen. */
.nst-preview__clip-body {
  position: absolute; inset: auto 0 0 0; z-index: 2;
  display: flex; flex-direction: column; align-items: flex-start;
  /* Clear of the transport below it. */
  padding: 110px var(--gutter, 20px) calc(92px + env(safe-area-inset-bottom));
  background: linear-gradient(#0000, rgba(6, 6, 10, .55) 38%, rgba(6, 6, 10, .93));
  pointer-events: none;
}
/* The wash is see-through to the cursor; what sits in it is not. */
.nst-preview__clip-body > * { pointer-events: auto; }
/* The same stack the network's feed lays on a clip, at the same weights. */
.nst-preview__clip-flag {
  font-family: var(--mono, monospace); font-size: 11px; letter-spacing: .1em;
  color: #c8c8d0; text-transform: uppercase;
}
.nst-preview__clip-title {
  margin: 0; font-family: var(--cond, sans-serif); font-weight: 700;
  line-height: 1; text-transform: uppercase;
  /* The same ramp the feed uses, so the two read at one size on a phone and
     scale together on anything wider. */
  font-size: clamp(26px, 4.2vw, 52px);
  text-shadow: 0 2px 24px rgba(6, 6, 10, .8); max-width: 22ch;
  padding-top: 9px;
}
.nst-preview__clip-said {
  font-size: 13px; line-height: 1.45; color: var(--muted, #a4a4ac);
  padding-top: 9px; max-width: 52ch;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}

/* The way from the stage into their film. The grid below opens full screen, so
   the clip already playing at the top of the sheet has to as well -- it is the
   obvious thing to reach for. A corner control rather than the whole frame:
   the transport underneath owns play, pause and scrub. */
.nst-preview__screen-full {
  position: absolute; right: 12px; bottom: 12px; z-index: 3;
  width: 36px; height: 36px; display: grid; place-items: center; padding: 0;
  border-radius: 50%; cursor: pointer; color: var(--text, #f4f4f2);
  background: rgba(8,8,10,.6); border: 1px solid rgba(255,255,255,.18);
  transition: border-color .18s ease, color .18s ease, background .18s ease;
}
.nst-preview__screen-full svg { width: 18px; height: 18px; display: block; }
.nst-preview__screen-full:hover {
  border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15);
  background: rgba(8,8,10,.8);
}

/* What follows, and how long until it takes over. Sits above the transport
   rather than beside it -- the bar is already five controls wide on a phone. */
.nst-preview__clip-next {
  position: absolute; inset: auto 0 calc(58px + env(safe-area-inset-bottom)) 0; z-index: 4;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 0 var(--gutter, 20px);
  font-family: var(--mono, monospace); font-size: 9px; letter-spacing: .12em;
}
.nst-preview__clip-next[hidden] { display: none; }
.nst-preview__clip-nextlabel { color: var(--dim, #6d6d76); }
.nst-preview__clip-nexttitle {
  flex: 1; min-width: 0; color: var(--text, #f4f4f2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nst-preview__clip-nextcount { color: var(--orange, #ff4a15); font-variant-numeric: tabular-nums; }
.nst-preview__clip-nextgo, .nst-preview__clip-nextstop {
  font: inherit; letter-spacing: inherit; cursor: pointer; white-space: nowrap;
  padding: 5px 10px; border-radius: 999px; background: none;
  color: var(--text, #f4f4f2); border: 1px solid rgba(255,255,255,.18);
}
.nst-preview__clip-nextgo { border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15); }

/* A post that lives somewhere else, in the reel.

   X renders its own embed, so the frame is theirs -- centred in the panel at a
   readable width rather than stretched to fill a phone screen, and scrolling
   inside itself for a long thread. */
.nst-preview__clip-post {
  position: absolute; z-index: 1;
  /* Centred rather than top-aligned: X sizes the frame to the post, so a short
     one otherwise hangs off the top of the panel with black beneath it. */
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 100%; max-width: 560px;
  /* Sized to the post, not the panel -- see the note in the watch sheet. */
  height: auto; max-height: 92%;
  border: 0; display: block;
  background: transparent;
}

/* Everything else with a link keeps its picture, and this is the way through.
   Sits above the poster rather than replacing it: the article's own image is
   what makes the tile worth looking at. */
.nst-preview__clip-out {
  position: absolute; left: 50%; top: 50%; z-index: 2;
  transform: translate(-50%, -50%);
  font-family: var(--cond, sans-serif); font-size: 13px; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; text-decoration: none;
  padding: 12px 24px; border-radius: 999px;
  color: var(--text, #f4f4f2); background: rgba(8,8,10,.62);
  border: 1px solid rgba(255,255,255,.22);
  transition: border-color .18s ease, color .18s ease, background .18s ease;
}
.nst-preview__clip-out:hover {
  border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15);
  background: rgba(8,8,10,.8);
}

/* The panel follows the page.

   It was pinned dark in both themes, on the reasoning that it is a screen with
   film in it. But it is mostly page: a name, the figures, a grid of moments and
   the way into the athlete's app, with one clip playing at the top. In daylight
   it was the one black sheet on a white site.

   Two things still have to be stated, because neither depends on the theme.

   The panel inherits its ink from whatever it opens over, and that is not
   always a token -- Ask carries no data-theme at all, so it inherited the
   browser's own default black onto a dark surface. It names its own text
   colour from the tokens instead, which the theme then repaints.

   And the copy that sits on the clip stays light, the way the hero's does: the
   film is its own background and does not turn with the page. */
.nst-preview { color: var(--text); }
/* Only what is genuinely printed on the film. The now-strip sits under the
   clip on the panel's own surface, so its date belongs to the page -- listing
   it here put JUL 16 in white on a white sheet. */
:root[data-theme="light"] .nst-preview :is(
  .nst-preview__clip-title, .nst-preview__clip-said, .nst-preview__clip-flag
) { color: #f4f4f2; }
/* The cinema is a fixed black stage over everything -- it does not turn with
   the page, so nothing printed on it may either. Setting the palette on the
   layer rather than naming each line: the headline carries no colour of its
   own and inherits, the byline and the meta row read --muted and --dim, and in
   daylight all of them came down to the page's near-black on that black stage.
   The athlete's name and the headline were there and could not be read. */
:root[data-theme="light"] .nst-preview__cinema {
  color: #f4f4f2;
  --text: #f4f4f2;
  --muted: #d8d8d4;
  --dim: #b4b4b0;
  --label: #c8c8c4;
}
:root[data-theme="light"] .nst-preview__cinema :is(
  .nst-preview__clip-title, .nst-preview__clip-said,
  .nst-preview__clip-flag, .nst-preview__clip-who
) { color: #f4f4f2; }
:root[data-theme="light"] .nst-preview__cinema .nst-preview__clip-said { color: #d8d8d4; }
.

   Flat and editorial like the rest of the network: rules rather than boxes,
   type doing the work, 2px between frames. Built around the stage -- an earlier
   pass led with a portrait and put the tape in a grid of thumbnails, which made
   a page about an athlete's film into a contact sheet.

   Every class is prefixed .nst-preview so this sheet can load beside both the
   front page's stylesheet and the directory's without colliding with either.
   Tokens come from whichever of those loaded first -- but only where that page
   defines them. The panel is opened from four pages now, and --r-pill was set
   by none of them, so "Enter their app" rendered as a pill on the directory
   and a hard rectangle on Ask NIL. The fallbacks below are what this panel
   needs to look like itself; a host that sets a token still wins. */
.nst-preview {
  --r-pill: var(--nst-r-pill, 999px);
}

/* Flat, not a panel. This sat inset from every edge with a rule around it and
   the page showing through behind -- a card of an athlete rather than their
   page. The sheet takes the whole window: no margin to float in, no border to
   read as a frame, and the film gets the width that padding was spending. */
.nst-preview { position: fixed; inset: 0; z-index: 95; display: block; padding: 0; }
.nst-preview[hidden] { display: none; }
.nst-preview__scrim { position: absolute; inset: 0; background: rgba(6, 6, 8, .93); backdrop-filter: blur(3px); }
.nst-preview__box {
  position: relative; width: 100%; height: 100%; max-height: none; overflow: auto;
  background: var(--panel, #0b0b0e); border: 0;
}
.nst-preview__wash {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(1100px 700px at 82% -6%, rgba(255,74,21,.07), transparent 62%);
}
.nst-preview__inner { position: relative; z-index: 1; }
.nst-locked { overflow: hidden; }
.nst-preview__glass { background: none; box-shadow: none; backdrop-filter: none; -webkit-backdrop-filter: none; }

/* --- title bar ------------------------------------------------------------ */

.nst-preview__bar { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 15px var(--gutter, 32px); border-bottom: 1px solid var(--line, #1c1c20); }
/* The address, and the way to it. Underlined on the approach rather than at
   rest: a rule under it at all times competes with the athlete's name a line
   below, and this is a quiet thing until somebody reaches for it. */
.nst-preview__stamp {
  font-family: var(--mono); font-size: 10px; letter-spacing: .18em;
  color: var(--dim, #6d6d76); text-decoration: none;
  transition: color .18s ease;
}
.nst-preview__stamp[href] { cursor: pointer; }
.nst-preview__stamp[href]:hover { color: var(--orange, #ff4a15); text-decoration: underline; text-underline-offset: 3px; }
.nst-preview__stamp:focus { outline: none; }
.nst-preview__stamp:focus-visible { outline: 2px solid var(--orange, #ff4a15); outline-offset: 3px; }
.nst-preview__nav { display: flex; align-items: center; gap: 16px; }
.nst-preview__step { font-family: var(--cond); font-size: 13px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted, #a4a4ac); background: none; border: 0; padding: 4px 2px; cursor: pointer; }
.nst-preview__step:hover { color: var(--text, #f4f4f2); }
.nst-preview__step:disabled { opacity: .3; cursor: default; }
.nst-preview__step--close { color: var(--text, #f4f4f2); }
.nst-preview__step--close:hover { color: var(--orange, #ff4a15); }
.nst-preview__split { width: 1px; height: 18px; background: var(--line-strong, #26262c); }

/* --- the stage ------------------------------------------------------------ */

.nst-preview__film { display: grid; grid-template-columns: minmax(0, 1fr) 340px; }
.nst-preview__film[hidden] { display: none; }
.nst-preview__stage { position: relative; min-width: 0; border-right: 1px solid var(--line, #1c1c20); }
/* Tall enough to actually watch. The clip fills it; portrait video is centred
   on its own blurred backdrop rather than pillarboxed against flat black. */
/* Flex, not grid: a grid item's default min-height is its content, so a tall
   still refused to shrink and overflowed the stage instead of fitting it. */
/* Sized off the window now the sheet fills it. A flat 560px was measured
   against a panel that stopped at 94vh; against the whole screen it left the
   stage short on a tall display and overhanging on a laptop. */
/* The screen takes the whole stage.

   It was a fixed clamp(360px, 62vh, 720px) with the caption and the transport
   in a band underneath, so a landscape clip sat letterboxed in the middle of
   the frame while a third of the panel was flat black holding two lines of
   type. The copy goes onto the picture instead -- where it already sits in the
   cinema and on the hero -- and the clip gets the room back. */
.nst-preview__stage { display: flex; flex-direction: column; }
.nst-preview__screen {
  position: relative; flex: 1 1 auto; min-height: clamp(360px, 62vh, 720px);
  background: #000; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
/* Native video and stills keep their shape and are centred; an iframe cannot
   be measured from here, so it takes the whole stage rather than collapsing to
   its own tiny intrinsic size. */
/* Fit, never fill. `height: 100%` cropped a 16:9 clip's sides in a tall box;
   `height: auto` let a 1080x1350 still overflow it. Both dimensions are capped
   and the aspect ratio is kept, so the whole frame is always visible and the
   blurred still behind covers what it does not reach. */
.nst-preview__screen video:not(.nst-preview__screen-back),
.nst-preview__screen img:not(.nst-preview__screen-back) { position: relative; z-index: 1; max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; display: block; border: 0; }
.nst-preview__screen > video:not(.nst-preview__screen-back),
.nst-preview__screen > img:not(.nst-preview__screen-back) { min-width: 0; min-height: 0; }
.nst-preview__screen iframe { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; display: block; border: 0; }
/* Blown out and blurred behind, so a 9:16 clip sits in its own colour instead
   of two black bars. Either the clip itself, mirrored, or its poster where the
   footage cannot be copied -- an embed's frame is another origin's, and some
   moments never imported a thumbnail at all. The rules above exclude this by
   class, or the fit that keeps the clip in front whole would shrink the wash to
   the same rectangle and defeat it. */
.nst-preview__screen-back { position: absolute; inset: -8%; z-index: 0; width: 116%; height: 116%; object-fit: cover; filter: blur(38px) saturate(160%) brightness(.42); pointer-events: none; }
.nst-preview__screen-play { position: absolute; inset: 0; z-index: 2; display: grid; place-items: center; background: none; border: 0; cursor: pointer; }
.nst-preview__screen-play span { width: 74px; height: 74px; border-radius: 50%; background: var(--orange, #ff4a15); color: var(--ink, #08080a); display: grid; place-items: center; font-size: 26px; padding-left: 5px; }
.nst-preview__screen-play:hover span { filter: brightness(1.1); }

/* Laid on the clip, not under it. Its own wash rather than a solid band, so
   the bottom of the picture reads through it. */
.nst-preview__now {
  position: absolute; inset: auto 0 0 0; z-index: 3;
  padding: 56px var(--gutter, 32px) 18px;
  /* Deep enough to carry a headline and a scrub bar over whatever the clip is
     doing. A lighter wash left the transport reading against grass and sky --
     the time codes and the track vanished into the picture. */
  background: linear-gradient(transparent, rgba(6,6,10,.62) 26%, rgba(6,6,10,.95) 62%, rgba(6,6,10,.98));
  pointer-events: none;
}
.nst-preview__now > * { pointer-events: auto; }
/* Stated, not inherited: this copy is on a photograph now, so it does not turn
   with the panel's theme -- daylight was painting it near-black on the frame. */
:root[data-theme="light"] .nst-preview__now .nst-preview__now-title { color: #f4f4f2 !important; }
:root[data-theme="light"] .nst-preview__now .nst-preview__now-meta { color: #c8c8d0 !important; }
.nst-preview__now-head { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.nst-preview__now-flag { font-family: var(--mono); font-size: 9px; letter-spacing: .18em; color: var(--orange, #ff4a15); text-transform: uppercase; }
.nst-preview__now-meta { font-family: var(--mono); font-size: 10px; color: var(--dim, #6d6d76); }
.nst-preview__now-title { font-family: var(--cond); font-size: clamp(26px, 2.6vw, 40px); font-weight: 700; text-transform: uppercase; line-height: 1.02; padding-top: 8px; text-wrap: balance; }

/* The transport. Its own bar rather than the browser's: a YouTube embed has no
   native controls at all, and most of the network's film is YouTube. */
.nst-preview__transport { display: grid; grid-template-columns: auto auto minmax(80px, 1fr) auto auto; align-items: center; gap: 12px; padding-top: 16px; }
.nst-preview__transport[hidden] { display: none; }
.nst-preview__tp-play, .nst-preview__tp-sound {
  width: 32px; height: 32px; display: grid; place-items: center; padding: 0;
  border: 1px solid var(--line, #1c1c20); border-radius: 50%;
  background: none; color: var(--text, #f4f4f6); cursor: pointer;
}
.nst-preview__tp-play:hover, .nst-preview__tp-sound:hover { border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15); }
.nst-preview__tp-play svg, .nst-preview__tp-sound svg { width: 17px; height: 17px; display: block; }
.nst-preview__tp-time { font-family: var(--mono); font-size: 10px; color: var(--dim, #6d6d76); font-variant-numeric: tabular-nums; }
/* Four pixels of line, with the hit area reaching well past it -- a 4px target
   is not one anybody can hit. */
.nst-preview__tp-track { position: relative; height: 4px; border-radius: 2px; background: var(--hatch, #17171b); cursor: pointer; touch-action: none; }
.nst-preview__tp-track::before { content: ""; position: absolute; inset: -12px 0; }
.nst-preview__tp-track:focus-visible { outline: 2px solid var(--orange, #ff4a15); outline-offset: 4px; }
.nst-preview__tp-fill { height: 100%; width: 0; border-radius: 2px; background: var(--orange, #ff4a15); transition: width .3s linear; }

/* What is coming, once the clip is nearly done. */
.nst-preview__upnext { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding-top: 12px; font-family: var(--mono); font-size: 10px; letter-spacing: .12em; text-transform: uppercase; }
.nst-preview__upnext[hidden] { display: none; }
.nst-preview__upnext-label { color: var(--orange, #ff4a15); }
.nst-preview__upnext-title { color: var(--text, #f4f4f6); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 44ch; }
.nst-preview__upnext-count { color: var(--dim, #6d6d76); font-variant-numeric: tabular-nums; }
.nst-preview__upnext-go, .nst-preview__upnext-stop {
  font: inherit; letter-spacing: inherit; text-transform: inherit; cursor: pointer;
  padding: 4px 10px; border-radius: var(--r-pill); border: 1px solid var(--line, #1c1c20);
  background: none; color: var(--text, #f4f4f6);
}
.nst-preview__upnext-go { border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15); }
.nst-preview__upnext-go:hover { background: var(--orange, #ff4a15); color: var(--ink, #08080a); }
.nst-preview__upnext-stop:hover { border-color: var(--dim, #6d6d76); }

/* The queue: everything else they have, scrolling beside the stage. */
/* Both columns are the same fixed height and the queue scrolls inside its
   share. Left to grow, twelve clips stretched the row and left a black band
   under the video as tall as the queue. */
.nst-preview__queue { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
/* The row holds the screen and the copy under it, so it tracks the screen's
   own height rather than restating a number that has to be kept in step. */
.nst-preview__film { grid-auto-rows: calc(clamp(360px, 62vh, 720px) + 180px); }
.nst-preview__queue-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; padding: 16px var(--gutter, 32px) 12px; font-family: var(--mono); font-size: 9px; letter-spacing: .18em; color: var(--orange, #ff4a15); }
.nst-preview__queue-head span:last-child { color: var(--dim, #6d6d76); }
/* The list takes whatever the head and the filters leave, so a third row of
   pills shortens the scroll rather than pushing it off the bottom. */
.nst-preview__queue-list { flex: 1; min-height: 0; overflow-y: auto; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px 10px; padding: 4px 12px 14px; align-content: start; }
/* A bigger frame. At 104x60 the thumbnail was too small to tell one clip from
   another -- a face, a jersey and a scoreboard all read as a dark smear -- and
   the queue is how the reader chooses what to watch. 4:3 rather than a fixed
   height, so a portrait clip is not letterboxed into a strip. */
/* Two across, the way the front page lays its rail out. As a list of wide rows
   this showed four of an athlete's moments before the fold and read as a
   sidebar of links; in pairs the same column holds eight, and each one is a
   frame you can see rather than a thumbnail beside a headline. */
.nst-preview__q { display: block; padding: 0; cursor: pointer; border-left: 0; transition: transform .22s ease; }
.nst-preview__q:hover { background: none; transform: translateY(-2px); }
.nst-preview__q.is-on { background: none; }
/* The mark of what is playing moves onto the frame itself: there is no longer a
   row edge to carry it. */
.nst-preview__q.is-on .nst-preview__q-shot { outline: 2px solid var(--orange, #ff4a15); outline-offset: -2px; }
/* 4:5, as on the front page. Most of what athletes post is shot upright, and a
   4:3 crop of a portrait clip is mostly the middle of somebody. */
.nst-preview__q-shot { position: relative; aspect-ratio: 4 / 5; background: var(--hatch); overflow: hidden; border-radius: 3px; }

/* Ten rows, then five at a time. Set as a full-width row rather than a chip so
   it reads as the end of the list rather than as another clip in it. */
.nst-preview__more {
  display: block; width: 100%; padding: 14px var(--gutter, 32px);
  background: none; border: 0; border-top: 1px solid rgba(255,255,255,.07);
  color: var(--orange, #ff4a15); font-family: var(--mono); font-size: 10px;
  letter-spacing: .16em; text-align: left; cursor: pointer;
}
.nst-preview__more:hover { background: rgba(255,74,21,.06); }
.nst-preview__q-shot img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* Top right, on its own plate -- the same place the front page's rail puts it.
   Bottom-left is where a portrait clip's subject usually is. */
.nst-preview__q-time { position: absolute; right: 6px; top: 6px; bottom: auto; padding: 2px 5px; border-radius: 3px; background: rgba(8,8,10,.86); font-family: var(--mono); font-size: 10px; letter-spacing: .03em; color: var(--text, #f4f4f2); }
.nst-preview__q-text { min-width: 0; padding: 6px 1px 0; }
/* One line, cut with an ellipsis. Wrapping made a cell as tall as its own
   title, so "Full game highlights vs North Lenoir" beside "Turnover in game"
   left the two frames of a pair at different heights and every row under them
   ragged. One line each and the grid holds its shape whatever the titles say. */
.nst-preview__q-title { font-family: var(--cond); font-size: 13px; font-weight: 600; text-transform: uppercase; line-height: 1.12; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.nst-preview__q.is-on .nst-preview__q-title { color: var(--orange, #ff4a15); }
.nst-preview__q-meta { font-family: var(--mono); font-size: 9px; color: var(--dim, #6d6d76); padding-top: 4px; }

/* One line, scrolled sideways. Wrapping put six sections on three rows and
   took a fifth of the queue's height to do it. */
.nst-preview__pills { display: flex; gap: 6px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; padding: 11px var(--gutter, 32px) 12px; border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__pills::-webkit-scrollbar { display: none; }
.nst-preview__pill { flex: 0 0 auto; font-family: var(--mono); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; padding: 7px 11px; color: var(--dim, #6d6d76); border: 1px solid var(--line, #1c1c20); background: none; cursor: pointer; white-space: nowrap; }
.nst-preview__pill:hover { color: var(--text, #f4f4f2); border-color: var(--line-strong, #26262c); }
.nst-preview__pill.is-on { background: var(--text, #f4f4f2); color: var(--ink, #08080a); border-color: var(--text, #f4f4f2); }

/* --- who this is ---------------------------------------------------------- */

.nst-preview__id { display: flex; align-items: center; gap: 40px; flex-wrap: wrap; padding: 26px var(--gutter, 32px); border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__who { display: flex; align-items: center; gap: 18px; min-width: 0; flex: 1; }
.nst-preview__face { position: relative; width: 84px; height: 84px; flex-shrink: 0; background: var(--hatch); overflow: hidden; display: block; }
.nst-preview__face img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.nst-preview__names { min-width: 0; }
.nst-preview__kicker { display: block; font-family: var(--mono); font-size: 10px; letter-spacing: .2em; color: var(--orange, #ff4a15); text-transform: uppercase; }
.nst-preview__name { margin: 0; font-family: var(--cond); font-size: clamp(34px, 3.6vw, 60px); font-weight: 700; text-transform: uppercase; line-height: .92; padding-top: 6px; text-wrap: balance; }
/* The verified marks ride with the name rather than over the portrait. */
.nst-preview__tags { display: none; }
.nst-preview__tag[hidden] { display: none; }

.nst-preview__stats { display: flex; flex-wrap: wrap; gap: 30px; }
.nst-preview__stat-value { font-family: var(--cond); font-size: 40px; font-weight: 700; line-height: 1; }
.nst-preview__stat--lead .nst-preview__stat-value { color: var(--orange, #ff4a15); }
.nst-preview__stat-label { font-family: var(--mono); font-size: 9px; letter-spacing: .16em; color: var(--dim, #6d6d76); padding-top: 5px; text-transform: uppercase; }

.nst-preview__actions { display: flex; gap: 8px; flex-wrap: wrap; }
.nst-preview__btn { font-family: var(--cond); font-size: 15px; letter-spacing: .16em; text-transform: uppercase; font-weight: 600; border: 1px solid var(--line-strong, #26262c); background: none; color: var(--muted, #a4a4ac); padding: 15px 22px; cursor: pointer; }
.nst-preview__btn:hover { border-color: var(--text, #f4f4f2); color: var(--text, #f4f4f2); }
.nst-preview__btn--go { background: var(--orange, #ff4a15); border-color: var(--orange, #ff4a15); color: var(--ink, #08080a); padding: 15px 26px; }
.nst-preview__btn--go:hover { color: var(--ink, #08080a); filter: brightness(1.08); }
.nst-preview__btn[hidden] { display: none; }

.nst-preview__lede { margin: 0; font-size: 17px; line-height: 1.5; color: var(--muted, #a4a4ac); padding: 0 var(--gutter, 32px) 26px; max-width: 760px; text-wrap: pretty; }
.nst-preview__lede:empty { display: none; }

/* --- section heads -------------------------------------------------------- */

.nst-preview__section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 18px; flex-wrap: wrap; padding: 26px var(--gutter, 32px) 12px; border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__section-head[hidden] { display: none; }
.nst-preview__label { font-family: var(--mono); font-size: 10px; letter-spacing: .2em; color: var(--orange, #ff4a15); }
.nst-preview__note { font-family: var(--mono); font-size: 10px; letter-spacing: .06em; color: var(--dim, #6d6d76); }

/* Figures on a rule, not boxes. Bordered cards read as buttons and fought the
   flat sheet everything else sits on; a divider between columns says the same
   thing without drawing five rectangles. */
.nst-preview__socials { display: flex; flex-wrap: wrap; padding: 0 var(--gutter, 32px) 28px; }
.nst-preview__socials:empty { display: none; }
.nst-preview__social { display: block; padding: 2px 34px 2px 0; margin-right: 34px; min-width: 0; border-right: 1px solid var(--line, #1c1c20); }
.nst-preview__social:last-child { border-right: 0; margin-right: 0; padding-right: 0; }
.nst-preview__social-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.nst-preview__social-net { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 9px; letter-spacing: .18em; color: var(--orange, #ff4a15); }
.nst-preview__social-mark { width: 13px; height: 13px; flex-shrink: 0; }
.nst-preview__social-state { font-family: var(--mono); font-size: 9px; color: var(--faint, #4a4a52); flex-shrink: 0; }
.nst-preview__social-count { font-family: var(--cond); font-size: 30px; font-weight: 700; line-height: 1.05; padding-top: 8px; }
.nst-preview__social-foot { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; padding-top: 4px; }
.nst-preview__social-handle { font-family: var(--mono); font-size: 11px; color: var(--dim, #6d6d76); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* No follower count is stored yet, so with nothing above it the handle is the
   cell and is set to carry rather than sitting under an empty space. */
.nst-preview__social-handle--lead { font-family: var(--cond); font-size: 21px; font-weight: 600; letter-spacing: 0; color: var(--text, #f4f4f2); padding-top: 8px; }
.nst-preview__social:hover .nst-preview__social-handle { color: var(--text, #f4f4f2); }
.nst-preview__social-delta { font-family: var(--mono); font-size: 10px; color: #5ee6a8; flex-shrink: 0; }

/* --- offers and their words ----------------------------------------------- */

.nst-preview__split-row { display: grid; grid-template-columns: 1fr 1fr; border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__panel { padding: 26px var(--gutter, 32px); min-width: 0; }
/* Only when something follows it. A panel left alone by its hidden neighbour
   kept a rule down its right edge with nothing on the other side. */
.nst-preview__panel:first-child:not(:last-child) { border-right: 1px solid var(--line, #1c1c20); }
.nst-preview__split-row:has(.nst-preview__panel[hidden]) .nst-preview__panel { border-right: 0; }
.nst-preview__panel[hidden] { display: none; }
.nst-preview__split-row:has(.nst-preview__panel[hidden]) { grid-template-columns: 1fr; }
.nst-preview__panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding-bottom: 16px; }
.nst-preview__when { font-family: var(--mono); font-size: 10px; color: var(--dim, #6d6d76); }

.nst-preview__offer { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 12px 0; border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__offer:last-child { border-bottom: 1px solid var(--line, #1c1c20); }
.nst-preview__offer-school { font-family: var(--cond); font-size: 24px; font-weight: 600; text-transform: uppercase; line-height: 1.05; }
.nst-preview__offer--more .nst-preview__offer-school { color: var(--muted, #a4a4ac); }
.nst-preview__offer-date { flex-shrink: 0; font-family: var(--mono); font-size: 9px; letter-spacing: .14em; color: var(--ink, #08080a); background: var(--orange, #ff4a15); padding: 5px 9px; font-weight: 700; }
.nst-preview__offer--more .nst-preview__offer-date { color: var(--dim, #6d6d76); background: none; padding: 0; font-weight: 400; }

/* Several captions, the first set large and the rest following it, so the
   panel fills rather than leaving one short line over a half-page of black. */
.nst-preview__quote { margin: 0; }
.nst-preview__quote:empty { display: none; }
.nst-preview__said { display: block; padding: 14px 0; border-top: 1px solid var(--line, #1c1c20); cursor: pointer; }
.nst-preview__said:first-child { border-top: 0; padding-top: 0; }
.nst-preview__said-text { display: block; font-family: var(--cond); font-size: 22px; font-weight: 500; line-height: 1.2; color: var(--muted, #a4a4ac); text-wrap: pretty; transition: color .18s ease; }
.nst-preview__said--lead .nst-preview__said-text { font-size: clamp(26px, 2.2vw, 34px); color: var(--text, #f4f4f2); }
.nst-preview__said:hover .nst-preview__said-text { color: var(--orange, #ff4a15); }
.nst-preview__said-when { display: block; font-family: var(--mono); font-size: 9px; letter-spacing: .14em; color: var(--faint, #4a4a52); padding-top: 7px; }
.nst-preview__quote:empty { display: none; }
.nst-preview__strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 2px; }
.nst-preview__strip:empty { display: none; }
.nst-preview__frame { position: relative; height: 96px; background: var(--hatch); overflow: hidden; cursor: pointer; }
.nst-preview__frame img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.nst-preview__frame::after { content: ""; position: absolute; inset: 0; background: linear-gradient(#0000 45%, rgba(8,8,10,.85)); }
.nst-preview__frame:hover img { opacity: .82; }
.nst-preview__frame-tag { position: absolute; left: 9px; bottom: 8px; z-index: 2; font-family: var(--mono); font-size: 9px; letter-spacing: .12em; color: var(--text, #f4f4f2); text-shadow: 0 1px 6px rgba(8,8,10,.9); }

.nst-preview__talk { border-top: 1px solid var(--line, #1c1c20); }
.nst-preview__talk[hidden] { display: none; }
.nst-preview__comments { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 0 40px; }
.nst-preview__comment { border-top: 1px solid var(--line, #1c1c20); padding: 14px 0 16px; min-width: 0; }
.nst-preview__comment-text { font-size: 16px; line-height: 1.45; color: var(--muted, #a4a4ac); text-wrap: pretty; }
.nst-preview__comment-by { font-family: var(--mono); font-size: 9px; letter-spacing: .12em; color: var(--faint, #4a4a52); padding-top: 8px; }

.nst-preview__foot { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; padding: 17px var(--gutter, 32px); border-top: 1px solid var(--line, #1c1c20); font-family: var(--mono); font-size: 10px; letter-spacing: .16em; color: var(--dim, #6d6d76); text-transform: uppercase; }
.nst-preview__place { margin-left: auto; color: var(--faint, #4a4a52); }

/* --- reflow --------------------------------------------------------------- */

@media (max-width: 1100px) {
  /* No inset here either. The sheet is flat at every width now, and a panel
     that floats on a narrow screen wastes the little room there is. */
  .nst-preview { padding: 0; }
  .nst-preview__film { grid-template-columns: 1fr; }
  .nst-preview__stage { border-right: 0; }
  .nst-preview__screen { height: 46vh; }
  .nst-preview__queue { border-top: 1px solid var(--line, #1c1c20); }
  .nst-preview__queue-list { max-height: 300px; }
  .nst-preview__split-row { grid-template-columns: 1fr; }
  .nst-preview__panel:first-child { border-right: 0; border-bottom: 1px solid var(--line, #1c1c20); }
}

@media (max-width: 700px) {
  .nst-preview { padding: 0; }
  .nst-preview__box { max-height: 100vh; border: 0; }
  .nst-preview__screen { height: 38vh; }

  /* Who this is, before their film.

     In source order the identity band sits after the stage and the queue,
     which is right on a wide screen -- the queue is a column beside the clip,
     so the name still reads high on the page. Stacked on a phone it put 1300
     points of stage and queue above the athlete's own name: the panel opened
     on a photo with no name, no stats and no way into their app until you
     scrolled past all of it.

     This lives here rather than in the phone sheet because the phone sheet is
     loaded by the network page alone. The same panel opens from Ask NIL, which
     loads only this file -- so the reordering never reached it and the two
     pages showed the same athlete two different ways.

     Every child is numbered. An unordered flex item defaults to 0, so naming
     only the ones that move sends the rest to the top. */
  .nst-preview__inner { display: flex; flex-direction: column; }
  .nst-preview__bar { order: 1; }
  .nst-preview__id { order: 2; }
  .nst-preview__lede { order: 3; }
  .nst-preview__film { order: 4; }
  .nst-preview__section-head { order: 5; }
  .nst-preview__socials { order: 6; }
  .nst-preview__split-row { order: 7; }
  .nst-preview__talk { order: 8; }
  .nst-preview__foot { order: 9; }

  /* Three bands stacked -- face and name, then the figures, then the two ways
     in. Left as a row the portrait and the stats split the width and the
     kicker broke across three lines, pushing the name down. */
  .nst-preview__id {
    flex-direction: column; align-items: stretch;
    padding-top: 18px; padding-bottom: 18px;
    border-top: 0; border-bottom: 1px solid var(--line, #1c1c20);
  }
  .nst-preview__who { flex: 0 0 auto; gap: 14px; }
  .nst-preview__name { font-size: 26px; }
  .nst-preview__kicker { font-size: 9px; letter-spacing: .12em; line-height: 1.5; }

  .nst-preview__id { gap: 22px; }
  .nst-preview__face { width: 60px; height: 60px; }
  .nst-preview__stats { gap: 22px; }
  .nst-preview__stat-value { font-size: 32px; }
  .nst-preview__strip { grid-template-columns: repeat(2, 1fr); }
  .nst-preview__actions .nst-preview__btn { flex: 1; text-align: center; }
}

/* --- shape -----------------------------------------------------------------

   The dialog follows the page's own radius tokens rather than carrying a scale
   of its own -- if --r changes, this changes with it and the sheet cannot drift
   out of step with the cards behind it.

   What it does add is a shape for the surfaces the base sheet never rounded,
   because they only exist here: the sheet itself, the film, the queue rows and
   the athlete's portrait. */

/* Square, now the sheet meets the window on all four sides. A rounded corner
   against the edge of the screen reads as a card sitting on the page, which is
   the thing this stopped being. */
.nst-preview__box { border-radius: 0; }
/* The film is a frame inside that sheet rather than the sheet itself, so it
   takes a corner. It reaches the window on the left only; rounding all four
   keeps the shape consistent whichever side is against an edge, and the copy
   laid on it now needs a frame to sit inside rather than a hard rectangle. */
.nst-preview__screen { border-radius: 16px; }

.nst-preview__face { border-radius: var(--r-sm); }
.nst-preview__q-shot { border-radius: var(--r-sm); }
/* The left edge stays square -- it carries the orange bar marking what is
   playing, and a radius there clips it to a sliver. */
/* The frame carries the shape now; the cell around it has no edge of its own. */
.nst-preview__q { border-radius: 0; }
.nst-preview__q-time { border-radius: 3px; padding: 1px 4px; background: rgba(8,8,10,.72); }
.nst-preview__pill { border-radius: var(--r-pill); }
.nst-preview__strip img, .nst-preview__strip > * { border-radius: var(--r-sm); }

/* Both actions are pills -- the same shape the header's buttons use, which is
   what marks a thing on this page as something you press. */
.nst-preview__btn { border-radius: var(--r-pill); }

/* Same drawn icons as the player bar -- see the note in
   nilsportstech-network-v2.css. Type-sized here, since both sit beside a label
   rather than alone in a round button. */
.nst-preview__step svg, .nst-preview__btn svg {
  width: 1em; height: 1em; flex: 0 0 auto;
}
.nst-preview__step, .nst-preview__btn { display: inline-flex; align-items: center; gap: .5em; }
.nst-preview__step--close { justify-content: center; }

/* --- the panel on a phone --------------------------------------------------

   These rules used to live in nilsportstech-network-v2-mobile.css, which only
   the network page loads. The panel is a shared partial -- Ask NIL and the NIL
   apps directory open the same markup -- so on those two pages it rendered
   with none of this: the raw "PREVIEW · APP #1 ON NILSPORTSTECH" stamp still
   showing, a full-width slab where the pill buttons belong, and no Play their
   year beside it. Moving them next to the component they style means any page
   that includes the partial gets the phone treatment for free.

   They stay last in the file so they still win on order over the 700px block
   above, which is the arrangement they were written against. */
/* --- the athlete's page ----------------------------------------------------

   Opened over whatever view you were on. Its desktop styles are in
   nilsportstech-athlete-preview.css, which loads before this file -- so these
   rules win on order, the same arrangement the directory uses.

   The 1100px block already stacks the stage and the queue into one column. What
   it does not undo is the row height they were given for sitting side by side,
   which is what left a screen's worth of black under the clip. */

@media (max-width: 760px) {
  /* 660px per row is a side-by-side measure: stacked, the stage needs only what
     the clip and its title come to, and the queue only its rows. Fixed rows put
     218px of dead black under each. */
  .nst-preview__film { grid-auto-rows: auto; }
  .nst-preview__stage { min-height: 0; }
  /* The clip sizes to the screen it is on rather than a share of the viewport,
     and the queue below it is reachable without a long scroll past nothing. */
  .nst-preview__screen { height: min(52vh, 360px); }
  .nst-preview__queue-list { max-height: none; }
  /* The sheet fills the screen here, so its corners have nothing to round
     against -- a radius on a full-bleed surface leaves four lit slivers where
     the page shows through. The rows and controls inside keep theirs. */
  .nst-preview__box { border-radius: 0; }
  .nst-preview__screen { border-radius: 0; }

  /* Top bar. "PREVIEW · APP #109 ON NILSPORTSTECH" wrapped to two lines and
     pushed the controls into each other, so the stamp goes -- the dialog is
     plainly a preview from what is in it -- and the steps become three even
     targets on one line. */
  /* Three labels stretched across a line read as a row of tabs, and the browser
     drew a focus ring around whichever was last pressed. Two groups instead:
     Prev and Next as one paired control on the left -- they do the same kind of
     thing in opposite directions -- and Close on the right, which is the only
     one that leaves. */
  /* Clear of the status bar. The 700px block in the athlete sheet sets
     "padding: 0" on the dialog and caps the box at 100vh, so the whole thing is
     pinned flush to the top of the screen -- padding inside the bar could not
     move it down, because the bar's own top edge was already under the clock.
     The room has to come from the container. */
  .nst-preview { padding-top: env(safe-area-inset-top); }
  .nst-preview__box { max-height: calc(100svh - env(safe-area-inset-top)); }
  .nst-preview__bar {
    gap: 10px; padding: 8px var(--gutter, 16px);
    background: rgba(8,8,10,.72); backdrop-filter: blur(12px);
  }
  .nst-preview__stamp { display: none; }
  /* No gap: the pair only reads as one control if its halves actually touch.
     Close is pushed away by its own auto margin instead. */
  .nst-preview__nav { width: 100%; gap: 0; justify-content: flex-start; }
  /* Prev and Next share one outline, split by a hairline. */
  .nst-preview__step {
    flex: 0 0 auto; min-height: 36px; display: inline-flex;
    align-items: center; justify-content: center; gap: 6px;
    padding: 0 14px; white-space: nowrap;
    font-size: 11px; letter-spacing: .12em;
    border: 1px solid var(--line-strong, #26262c);
    border-radius: var(--r-pill); background: rgba(244,244,242,.04);
    /* The label is named rather than left to --muted: the pair sits on the
       panel's own bar, which turns with the theme, so the ink has to turn with
       it. It did not, and PREV and NEXT were grey on grey in daylight. */
    color: var(--muted, #a4a4ac);
  }
  .nst-preview__step svg { width: 13px; height: 13px; }
  /* The pair reads as one control: adjoining edges square, outer ends round. */
  [data-preview-prev] { border-radius: var(--r-pill) 0 0 var(--r-pill); border-right-width: 0; }
  [data-preview-next] { border-radius: 0 var(--r-pill) var(--r-pill) 0; }
  .nst-preview__step--close {
    border-radius: var(--r-pill); border-color: transparent;
    background: rgba(244,244,242,.08); color: var(--text, #f4f4f2);
    width: 36px; padding: 0; margin-left: auto;
  }
  /* An icon alone -- "Close" beside an X is the same word twice. */
  .nst-preview__step--close span { display: none; }
  .nst-preview__step--close svg { width: 15px; height: 15px; }
  /* Pressed state only for keyboards; a tap should not leave a ring behind. */
  .nst-preview__step:focus { outline: none; }
  .nst-preview__step:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
  .nst-preview__split { display: none; }

  /* Whose page this is comes before their film.

     In source order the identity band sits after the stage and the queue, which
     on a wide screen is fine -- the queue is a column beside the clip, so the
     name is still high on the page. Stacked, that put it below a clip and every
     row of the queue: you scrolled two screens to find out who you were looking
     at. Ordering here rather than in the markup keeps the desktop sequence,
     where the band reads correctly as a caption under the stage.

     Every child is numbered. An unordered flex item defaults to 0, so naming
     only the ones that move would send the rest to the top. */
  .nst-preview__inner { display: flex; flex-direction: column; }
  .nst-preview__bar { order: 1; }
  .nst-preview__id { order: 2; }
  .nst-preview__lede { order: 3; }
  .nst-preview__film { order: 4; }
  .nst-preview__section-head { order: 5; }
  .nst-preview__socials { order: 6; }
  .nst-preview__split-row { order: 7; }
  .nst-preview__talk { order: 8; }
  .nst-preview__foot { order: 9; }

  /* Three bands stacked -- face and name, then the figures, then the two ways
     in. Left as a row, the portrait and the stat block split the width between
     them and the kicker broke across three lines ("BASKETBALL · ✓ / VERIFIED ·
     / POSTED 14H AGO"), pushing the name down. */
  .nst-preview__id {
    flex-direction: column; align-items: stretch; gap: 16px;
    padding-top: 18px; padding-bottom: 18px;
    /* Its top rule separated it from the stage above; now it opens the sheet. */
    border-top: 0; border-bottom: 1px solid var(--line, #1c1c20);
  }
  .nst-preview__who { flex: 0 0 auto; gap: 14px; }
  .nst-preview__name { font-size: 26px; }
  .nst-preview__face { width: 52px; height: 52px; flex: 0 0 auto; }
  /* The whole line, so it breaks once at most. */
  .nst-preview__kicker { font-size: 9px; letter-spacing: .12em; line-height: 1.5; }
  .nst-preview__stats { gap: 18px; flex-wrap: wrap; }
  .nst-preview__stat-value { font-size: 26px; }
  .nst-preview__actions { width: 100%; gap: 8px; }
  /* "Enter <name>'s app" is as long as the athlete's name, so the label wraps
     inside the button whatever the width. Smaller type and tighter tracking
     keep both on one line. */
  .nst-preview__actions .nst-preview__btn {
    flex: 1; text-align: center; min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 12px 14px; font-size: 12px; letter-spacing: .08em;
  }

  /* Panel heads: label on its own line, the note under it. Side by side both
     wrapped -- "WHAT PEOPLE ARE SAYING" over two lines with "15 UNDER THEIR
     FILM · FROM THE POST" over two more, for a four-line head above one comment.
     Same shape as the front page's section heads. */
  .nst-preview__panel-head, .nst-preview__section-head {
    display: grid; grid-template-columns: 1fr; gap: 3px;
  }
  .nst-preview__note, .nst-preview__when { font-size: 9px; letter-spacing: .12em; }

  .nst-preview__now-title { font-size: 20px; }
  .nst-preview__lede { font-size: 15px; }
  .nst-preview__strip { grid-template-columns: repeat(2, 1fr); }
  /* The last line is a warning that the next tap leaves the network, so it gets
     its own line rather than being pushed to the right of the URL. */
  .nst-preview__foot { gap: 6px; padding: 14px var(--gutter, 16px); }
  .nst-preview__place { margin-left: 0; }
}

/* --- their film, one clip a screen ---------------------------------------- */

/* Over the panel rather than inside it. A moment in the grid used to swap the
   small stage further up the sheet, so tapping a clip changed something the
   reader had already scrolled past and nothing appeared to happen. */
.nst-preview__cinema {
  position: fixed; inset: 0; z-index: 97; background: var(--ink, #08080a);
}
.nst-preview__cinema[hidden] { display: none; }
.nst-preview__cinema-close {
  position: absolute; top: calc(12px + env(safe-area-inset-top)); right: 14px; z-index: 2;
  width: 36px; height: 36px; display: grid; place-items: center; padding: 0;
  border-radius: 50%; cursor: pointer;
  /* Not var(--text): the disc is a fixed dark glass whatever the theme does, so
     the chevron on it has to be light whatever the theme does too. Inheriting
     the page's ink turned it near-black on that disc in daylight -- the button
     was still there and still worked, but nothing could be seen on it. */
  color: #f4f4f2;
  background: rgba(8,8,10,.55); border: 1px solid rgba(255,255,255,.16);
}
.nst-preview__cinema-close svg { width: 19px; height: 19px; display: block; }
.nst-preview__cinema-close:hover { border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15); }

/* The run itself. Snapped so a swipe lands on a clip rather than between two,
   and mandatory so it cannot rest halfway. */
.nst-preview__reel {
  height: 100%; overflow-y: auto; overscroll-behavior-y: contain;
  scroll-snap-type: y mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
}
.nst-preview__reel::-webkit-scrollbar { display: none; }

.nst-preview__panel-clip {
  position: relative; height: 100%; scroll-snap-align: start; scroll-snap-stop: always;
  display: flex; align-items: center; justify-content: center; background: #000;
}
.nst-preview__clip-frame { position: absolute; inset: 0; overflow: hidden; }
/* The clip keeps its own shape -- a reel is not cropped to fill a phone -- and
   a blurred, overscaled copy of its own poster fills what is left, so the black
   bands either side become part of the frame rather than a hole in it. */
.nst-preview__clip-frame::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: var(--clip-wash, none) center / cover no-repeat;
  filter: blur(38px) saturate(140%) brightness(.5);
  transform: scale(1.3);
}
.nst-preview__clip-frame video:not(.nst-preview__clip-mirror),
.nst-preview__clip-frame iframe {
  position: relative; z-index: 1;
  width: 100%; height: 100%; object-fit: contain; display: block; border: 0;
}
/* The poster, OVER the clip rather than beside it.

   It shared `position: relative` with the video and came first in the frame,
   so the two stacked in document order and the still took the space -- the
   clip mounted, played and drove the transport underneath a frozen frame,
   while the blurred mirror behind it moved. That reads as a video that will
   not play, which is the one thing it is not.

   Faded out once the clip is actually rendering, so a slow file still shows
   its poster rather than black. */
.nst-preview__clip-still {
  position: absolute; inset: 0; z-index: 2;
  width: 100%; height: 100%; object-fit: contain; display: block; border: 0;
  transition: opacity 220ms ease;
}
.nst-preview__clip-frame.is-playing .nst-preview__clip-still {
  opacity: 0;
  pointer-events: none;
}
/* The copy behind it, covering rather than fitting -- filling the bands is its
   whole job, so it is the one thing here that crops. */
.nst-preview__clip-mirror {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; object-fit: cover; display: block; border: 0;
  filter: blur(34px) saturate(140%) brightness(.52);
  transform: scale(1.2); pointer-events: none;
}

/* The reel's own controls, on the clip. */
.nst-preview__clip-bar {
  position: absolute; inset: auto 0 0 0; z-index: 3;
  display: flex; align-items: center; gap: 12px;
  padding: 14px var(--gutter, 20px) calc(16px + env(safe-area-inset-bottom));
  background: linear-gradient(transparent, rgba(6,6,10,.92));
}
.nst-preview__clip-btn {
  flex: 0 0 auto; width: 34px; height: 34px; border: 0; border-radius: 50%;
  background: rgba(244,244,242,.14); color: var(--text, #f4f4f2);
  display: grid; place-items: center; cursor: pointer;
}
.nst-preview__clip-btn svg { width: 15px; height: 15px; display: block; }
.nst-preview__clip-time {
  flex: 0 0 auto; font-family: var(--mono, monospace); font-size: 10px;
  letter-spacing: .06em; color: var(--muted, #a4a4ac); min-width: 62px;
}
.nst-preview__clip-track {
  position: relative; flex: 1 1 auto; height: 3px; cursor: pointer;
  background: rgba(244,244,242,.2); border-radius: 999px;
}
/* A 3px line is not a thumb target; the hit area reaches past it. */
.nst-preview__clip-track::before { content: ""; position: absolute; inset: -12px 0; }
.nst-preview__clip-track > span {
  display: block; height: 100%; width: 0;
  background: var(--orange, #ff4a15); border-radius: 999px;
}

/* Whose clip it is on the left, the way into their app on the right -- the
   same row the feed carries, spanning the overlay so the button has an edge to
   sit against rather than being pressed up beside the name. */
.nst-preview__clip-by {
  display: flex; align-items: center; gap: 14px;
  width: 100%; padding-top: 14px;
}
/* Round, and its picture fills it. The shared .nst-avatar rules are on the
   directory's sheet, which this layer sits over rather than inside -- so the
   face was an empty square. */
.nst-preview__clip-face {
  position: relative; width: 54px; height: 54px; flex: 0 0 auto;
  border-radius: 50%; overflow: hidden; background: #1b1b22;
  display: grid; place-items: center;
  font-family: var(--cond, sans-serif); font-size: 24px; font-weight: 700;
  color: var(--muted, #a4a4ac);
}
.nst-preview__clip-face img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
.nst-preview__clip-who { min-width: 0; }
.nst-preview__clip-name {
  font-family: var(--cond, sans-serif); font-size: 19px; font-weight: 700;
  text-transform: uppercase; line-height: 1.05;
}
.nst-preview__clip-sport {
  font-family: var(--mono, monospace); font-size: 10px; letter-spacing: .12em;
  color: #a4a4ac; text-transform: uppercase; padding-top: 2px;
}
.nst-preview__clip-app {
  flex: 0 0 auto; margin-left: auto;
  /* The size the network's own feed settled on. Bigger, it reads as a banner
     laid across somebody's film rather than a way into their app. */
  font-family: var(--cond, sans-serif); font-size: 12px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase;
  background: var(--orange, #ff4a15); color: #0a0a0a;
  border: 0; border-radius: 999px; padding: 10px 18px;
  text-decoration: none; white-space: nowrap;
}

/* The clip's own details laid on it, so the picture keeps the whole screen. */
.nst-preview__clip-body {
  position: absolute; inset: auto 0 0 0; z-index: 2;
  display: flex; flex-direction: column; align-items: flex-start;
  /* Clear of the transport below it. */
  padding: 110px var(--gutter, 20px) calc(92px + env(safe-area-inset-bottom));
  background: linear-gradient(#0000, rgba(6, 6, 10, .55) 38%, rgba(6, 6, 10, .93));
  pointer-events: none;
}
/* The wash is see-through to the cursor; what sits in it is not. */
.nst-preview__clip-body > * { pointer-events: auto; }
/* The same stack the network's feed lays on a clip, at the same weights. */
.nst-preview__clip-flag {
  font-family: var(--mono, monospace); font-size: 11px; letter-spacing: .1em;
  color: #c8c8d0; text-transform: uppercase;
}
.nst-preview__clip-title {
  margin: 0; font-family: var(--cond, sans-serif); font-weight: 700;
  line-height: 1; text-transform: uppercase;
  /* The same ramp the feed uses, so the two read at one size on a phone and
     scale together on anything wider. */
  font-size: clamp(26px, 4.2vw, 52px);
  text-shadow: 0 2px 24px rgba(6, 6, 10, .8); max-width: 22ch;
  padding-top: 9px;
}
.nst-preview__clip-said {
  font-size: 13px; line-height: 1.45; color: var(--muted, #a4a4ac);
  padding-top: 9px; max-width: 52ch;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}

/* The way from the stage into their film. The grid below opens full screen, so
   the clip already playing at the top of the sheet has to as well -- it is the
   obvious thing to reach for. A corner control rather than the whole frame:
   the transport underneath owns play, pause and scrub. */
.nst-preview__screen-full {
  position: absolute; right: 12px; bottom: 12px; z-index: 3;
  width: 36px; height: 36px; display: grid; place-items: center; padding: 0;
  border-radius: 50%; cursor: pointer; color: var(--text, #f4f4f2);
  background: rgba(8,8,10,.6); border: 1px solid rgba(255,255,255,.18);
  transition: border-color .18s ease, color .18s ease, background .18s ease;
}
.nst-preview__screen-full svg { width: 18px; height: 18px; display: block; }
.nst-preview__screen-full:hover {
  border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15);
  background: rgba(8,8,10,.8);
}

/* What follows, and how long until it takes over. Sits above the transport
   rather than beside it -- the bar is already five controls wide on a phone. */
.nst-preview__clip-next {
  position: absolute; inset: auto 0 calc(58px + env(safe-area-inset-bottom)) 0; z-index: 4;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 0 var(--gutter, 20px);
  font-family: var(--mono, monospace); font-size: 9px; letter-spacing: .12em;
}
.nst-preview__clip-next[hidden] { display: none; }
.nst-preview__clip-nextlabel { color: var(--dim, #6d6d76); }
.nst-preview__clip-nexttitle {
  flex: 1; min-width: 0; color: var(--text, #f4f4f2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nst-preview__clip-nextcount { color: var(--orange, #ff4a15); font-variant-numeric: tabular-nums; }
.nst-preview__clip-nextgo, .nst-preview__clip-nextstop {
  font: inherit; letter-spacing: inherit; cursor: pointer; white-space: nowrap;
  padding: 5px 10px; border-radius: 999px; background: none;
  color: var(--text, #f4f4f2); border: 1px solid rgba(255,255,255,.18);
}
.nst-preview__clip-nextgo { border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15); }

/* A post that lives somewhere else, in the reel.

   X renders its own embed, so the frame is theirs -- centred in the panel at a
   readable width rather than stretched to fill a phone screen, and scrolling
   inside itself for a long thread. */
.nst-preview__clip-post {
  position: absolute; z-index: 1;
  /* Centred rather than top-aligned: X sizes the frame to the post, so a short
     one otherwise hangs off the top of the panel with black beneath it. */
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 100%; max-width: 560px;
  /* Sized to the post, not the panel -- see the note in the watch sheet. */
  height: auto; max-height: 92%;
  border: 0; display: block;
  background: transparent;
}

/* Everything else with a link keeps its picture, and this is the way through.
   Sits above the poster rather than replacing it: the article's own image is
   what makes the tile worth looking at. */
.nst-preview__clip-out {
  position: absolute; left: 50%; top: 50%; z-index: 2;
  transform: translate(-50%, -50%);
  font-family: var(--cond, sans-serif); font-size: 13px; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; text-decoration: none;
  padding: 12px 24px; border-radius: 999px;
  color: var(--text, #f4f4f2); background: rgba(8,8,10,.62);
  border: 1px solid rgba(255,255,255,.22);
  transition: border-color .18s ease, color .18s ease, background .18s ease;
}
.nst-preview__clip-out:hover {
  border-color: var(--orange, #ff4a15); color: var(--orange, #ff4a15);
  background: rgba(8,8,10,.8);
}

/* --- the panel's own chrome, in daylight ---------------------------------

   The bar is hard-coded rgba(8,8,10,.72) -- near-black glass -- in both themes,
   and Prev, Next and Close are drawn on it with white ink at 4-8%. None of it
   turns with the page, so in daylight the panel opened with a dark band across
   the top and grey-on-grey controls inside it. The band and its contents move
   together here: the glass takes the page's own white, and the pills take page
   ink over it. */
:root[data-theme="light"] .nst-preview__bar {
  background: rgba(255,255,255,.82);
  border-bottom-color: rgba(8,8,10,.10);
}
:root[data-theme="light"] .nst-preview__step {
  background: rgba(8,8,10,.05);
  border-color: rgba(8,8,10,.16);
  color: #55555e;
}
:root[data-theme="light"] .nst-preview__step:hover { color: #16161a; }
:root[data-theme="light"] .nst-preview__step--close {
  background: rgba(8,8,10,.08);
  border-color: transparent;
  color: #16161a;
}
:root[data-theme="light"] .nst-preview__step:disabled { opacity: .35; }

