/* ==========================================================================
   NITRATE — THE PROJECTOR.  Stylesheet for watch.js.
   Owned by the player agent.  Owns exactly: watch.js + watch.css.

   THE FILM LAB RULES, KEPT
     · Colours come only from tokens.css.  Nothing is redefined here.
     · Safety orange is the ONLY saturated colour and it means exactly one
       thing: THIS IS WHAT IS SELECTED / THIS NEEDS ATTENTION.  It is on the
       played portion of the seek bar, on the current track's mark, on the one
       primary action of a card, and on nothing else.
     · No border-radius anywhere — with ONE declared exception, the leader
       dial.  See THE LEADER below; a projector's sweep is round because the
       shutter is round, and that is a different thing from a soft-cornered box.
     · Every number — the clock, a size, a resolution — is mono and tabular.
     · The picture itself sits on true black, not on --ground.  A projected
       image has no paper behind it, and a warm grey letterbox would tint
       every frame it surrounds.  The CHROME is the lab; the GATE is black.

   WHY THE CHROME IS DARK IN BOTH THEMES
   The light theme is "the light table" — for inspecting a catalogue.  A film
   is not inspected, it is watched, and a light surround next to a dark frame
   is what makes a room's projector look broken.  So the player's own surfaces
   are drawn from a fixed near-black scale rather than from --panel, in BOTH
   themes, exactly as every cinema-grade player does.  The theme is not
   ignored: every card that asks a QUESTION — resume, which print, a failure —
   is drawn on --panel in the theme's own colours, because that is reading,
   not watching.

   ⭐ AND THEREFORE THE CHROME CARRIES ITS OWN ORANGE.
   --accent is #f0790d in the vault and #b34d00 on the light table.  The light
   table's is a deep burnt orange chosen to sit on PAPER; on this player's
   near-black chrome it measures about 2.9:1 and reads as mud, which is
   exactly what the light-theme control bar used to look like.  --nwx-accent
   is the vault's orange, fixed, and it is what every mark drawn ON THE DARK
   CHROME uses: the played bar, the current track, a menu head, the leader.
   --accent itself is still what the CARDS use, because a card is on the
   theme's own paper and there the token is right.  One rule:
   dark chrome → --nwx-accent, theme paper → --accent.

   LAYERING.  The estate's sheet is z-index 60 and the coming-soon dossier is
   60.  The player sits at 300, over all of it, and its menus and cards stack
   inside that one layer.

   THE PHONE IS THE POINT.  Everything below 640px: the control bar keeps a
   44px minimum on every target, the menus become bottom sheets you can reach
   with a thumb, and the top bar sheds everything but the title and the two
   controls that matter.  Nothing scrolls sideways at 390px.
   ========================================================================== */

.nwx-root {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  flex-direction: column;
  background: #000;
  color: #ece5da;
  font-family: var(--font-ui);
  font-size: var(--size-dense);
  /* the player's own near-black scale — deliberately theme-independent */
  --nwx-chrome: rgba(9, 8, 8, .88);
  --nwx-line: rgba(236, 229, 218, .22);
  --nwx-dim: rgba(236, 229, 218, .62);
  --nwx-idle: rgba(236, 229, 218, .30);
  /* the vault's orange and severities, fixed — see the header */
  --nwx-accent: #f0790d;
  --nwx-warn: #d8a441;
  --nwx-ok: #78b571;
  --nwx-crit: #d1594a;
  overscroll-behavior: contain;
  touch-action: manipulation;
}

/* --- the gate ------------------------------------------------------------ */
.nwx-stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  background: #000;
  overflow: hidden;
}
.nwx-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
  display: block;
}
/* ✅ OVERLAY_20260825 — CONFIRMED FIXED BY JOHN, 2026-08-25, Windows Chrome, IN FULLSCREEN.
   *"ok subs appear in full screen"*.  This is the confirmation the 08-19 comment asked for and
   never got.  ⛔ Do not undo either half of it without a Windows viewer re-testing IN FULLSCREEN.

   TWO CHANGES CARRIED IT, SHIPPED IN THAT ORDER, AND THE ORDER IS THE EVIDENCE:
     ROUND 1 — a de-promoting filter on the <video> (this rule).  ALONE IT WAS NOT ENOUGH:
               John retested and still lost the subtitles in fullscreen.
     ROUND 2 — retiring the 08-19 `will-change: transform; transform: translateZ(0)` from
               .nwx-cues (see the retirement note in that rule below).  WITH BOTH, IT WORKS.
   ⭐ So the 08-19 "fix" was very likely the CAUSE all along: promoting the cue layer took it
   out of Chromium's overlap test, so Chrome saw an unoccluded video and handed it to a
   hardware overlay.  Six days of the bug were spent inside its own remedy.

   THE SUBTITLE-VANISHES-WITH-THE-SEEK-BAR BUG, SECOND ATTEMPT.
   John reported it 2026-08-19 and AGAIN on 08-25, both times on Windows Chrome:
   the cue only renders while the control bar is up.

   ⛔ DO NOT GO LOOKING AT Z-INDEX AGAIN.  /root/probes/subprobe.js measured it on
   08-19 and EXCLUDED occluded / off-screen / not-drawn by direct measurement — the
   line was painted on 34/34 samples with the bar hidden.  That ground is closed.

   WHAT THE 08-19 FIX GOT WRONG.  It promoted .nwx-cues (below, z-index 4) to its own
   compositor layer with will-change + translateZ(0), reasoning that a promoted layer
   stays out of the region Chrome punches through for a hardware video overlay.  But
   if the <video> is the thing sitting ON the DirectComposition overlay plane, then
   promoting the layer ABOVE it changes nothing — you have to stop the VIDEO being
   promoted.  That was never tried.  It shipped unverified and the bug survived.

   WHY A FILTER IS THE LEVER.  Chromium will only hand a video quad to a DComp overlay
   when it is a plain, axis-aligned, unclipped, fully-opaque quad.  A filter forces the
   video through a render surface, so there is no promotable quad left and the page
   composites normally — subtitles included.  ⛔ opacity < 1 does NOT work here: the
   DComp path supports opacity ON overlays, and it would also fight
   `.nwx-root.is-switching .nwx-video { opacity:.55 }` further down.  ⛔ will-change /
   translateZ(0) on the video is BACKWARDS — that promotes it and makes an overlay MORE
   likely.  ⛔ border-radius/clip-path would work but clip the picture and break the
   house no-rounded-corners rule at the top of this file.

   1.0001, NOT 1.  An identity filter risks being folded away before it ever builds a
   render surface.  1.0001 cannot move an 8-bit sample (255 -> 255.03, 128 -> 128.01),
   so it is arithmetically invisible and structurally guaranteed to be a real filter.

   ⭐ SCOPED WITH :has(track), AND THAT IS DELIBERATE.  De-promotion costs a GPU copy
   per frame and changes the colour path for HDR/10-bit, so a film with no subtitles
   should keep its overlay.  ensureTrack() does video.appendChild(t) (watch.js:5866),
   so this is true exactly when a subtitle is loaded — and it does NOT flicker per line,
   because the <track> persists while only .nwx-cues empties between cues.
   ⛔ KEEP THIS AS ITS OWN RULE.  Merged into a selector list, an engine without :has()
   would drop the whole list; alone, it degrades to exactly today's behaviour.

   ⚠️ The PICTURE control already sets video.style.filter inline (watch.js:1778) — and
   for the default look "As printed" it assigns '' , which REMOVES the declaration and
   lets this rule through.  Any other look sets its own filter and de-promotes anyway.
   The two paths cannot collide: both end in a filter.

   🔴 VERIFY ON WINDOWS BEFORE BELIEVING IT.  A Linux box is software-composited and
   CANNOT reproduce this.  Shipping an unverified guess is exactly how the 08-19 fix
   survived six days pretending to be a fix. */
.nwx-video { filter: brightness(1.0001); }
/* 🔴 ROUND 2, 2026-08-25 — the :has(track) scoping is GONE ON PURPOSE.  Round 1 shipped
   `.nwx-video:has(track)` and John still lost the subtitles IN FULLSCREEN.  Scoping was a
   power optimisation, and it was also a second thing that could be wrong: if the selector
   were not matching, the symptom is identical to the filter not working.  Unconditional
   removes that ambiguity.  ⭐ Re-narrow it ONLY after a Windows viewer confirms the fix. */
.nwx-root:not(.is-live) .nwx-stage { cursor: none; }

/* --- subtitles ----------------------------------------------------------
   Drawn by watch.js, not by the browser's cue box: the native box sits where
   the control bar sits, cannot be themed, and renders differently in every
   engine.  Raising it when the controls come up is the whole reason. */
/* SUBFACE_20260819 — z-index was 3, the bottom of this stage's stack: above the
   picture and below EVERYTHING else, including .nwx-centre's full-inset leader
   frame at 4.  5 puts it with the top bar and the skip mark, still under the
   control bar at 6 and under every menu (7), card (8) and cast panel (9), so a
   subtitle can never be painted over something being read.
   ⛔ AND DELIBERATELY NOT ABOVE THE BAR.  A line drawn over the clock and the
   seek rule is its own defect; the cue does not out-stack the bar, it stays out
   of the bar's way — which is what the rule below is for, and why that rule has
   to be keyed on the same thing the BAR is keyed on. */
.nwx-cues {
  position: absolute;
  left: 0; right: 0;
  bottom: 7%;
  padding: 0 6%;
  text-align: center;
  pointer-events: none;
  transition: bottom .18s ease;
  /* COMPOSITE_20260819 — TWO CHANGES, BOTH FROM THE INDEPENDENT PROBE.

     1. z-index 5 -> 4, TO REMOVE A SILENT TIE.  At 5 this sat level with
        .nwx-top and .nwx-skip, and which of the three won was decided by
        nothing but the order of appendChild() in the constructor.  Moving one
        line of unrelated JS would have started painting subtitles over the top
        bar and over SKIP INTRO, with no CSS change to blame it on.  The probe
        also measured that the 3->5 raise changed NOTHING: across four states,
        in both builds, no element at z 4 ever painted over the line.  So the
        raise bought no behaviour and cost a tie.  4 keeps it above the picture
        and below every control.  (.nwx-centre is also 4, but it is display:none
        except while buffering and paints no background of its own.)

     2. A COMPOSITOR LAYER OF ITS OWN, which is the actual suspect for John's
        report.  The probe excluded off-screen, occluded and not-drawn by direct
        measurement — the line was painted on 34/34 samples with the bar hidden.
        What it could NOT test is Windows DirectComposition: Chrome promotes the
        <video> to a hardware overlay plane, the cue layer is punched through it,
        and the bar's own opacity transition forces a normal composite again.
        That produces exactly what was reported — "the seek bar appears and then
        the subs appear" — and it cannot be reproduced on a software-composited
        Linux box.  Promoting this layer permanently keeps it out of the punched
        region.  ⚠️ UNPROVEN BY MEASUREMENT HERE, on purpose: it is cheap, it is
        reversible, and only a Windows viewer can confirm it.  If John reports it
        fixed, this comment becomes the record of why. */
  z-index: 4;
  /* 🔴 THE 08-19 PROMOTION IS RETIRED HERE — 2026-08-25.  It was `will-change: transform;
     transform: translateZ(0)`, added on the theory that a permanently promoted cue layer
     stays out of the region Chrome punches through for a hardware video overlay.  It did
     not work: the same symptom was reported again on 08-25, and again on 08-25 AFTER the
     video was given a de-promoting filter (OVERLAY_20260825 above), this time explicitly
     IN FULLSCREEN, which is where Chrome promotes video to an overlay most eagerly.
     ⭐ AND IT MAY HAVE BEEN THE CAUSE, NOT THE CURE.  Chromium decides overlay eligibility
     by testing what is drawn ON TOP of the video quad.  A layer promoted to its own
     compositing layer can fall outside that test — so the promotion intended to lift the
     cue clear of the overlay is exactly the thing that could let Chrome believe nothing
     overlaps the video and promote it.  Between cues .nwx-cues paints nothing at all,
     which makes the video look unoccluded; the control bar fading IN is a large, plainly
     overlapping paint, which forces de-promotion — and that is precisely the reported
     symptom, "the bar appears and then the subs appear".
     ⛔ Do not re-add a compositor promotion here without a Windows viewer proving it. */
}
/* ⚠️ THE BAR'S OWN HEIGHT, NOT A NUMBER THAT WAS TRUE ONCE.  92px was measured
   against a control row that no longer exists; the phone tiers were already
   fixed to read --nwx-barh (watch.js publishes it from the element, on every
   rotate and whenever a control appears or disappears) and this one was left
   behind, so on a desktop with the chapter and version controls up the last
   line of a two-line subtitle sat behind the seek rule.

   🔴 SUBFACE_20260819 — AND IT WAS KEYED ON ONE CLASS WHILE THE BAR IS KEYED ON
   TWO.  The bar is raised to full opacity by .is-live (the auto-hide) OR by
   .is-paused — see PAUSED / SWITCHING further down — and this rule read only
   .is-live.  So {the chrome has faded, then the picture stops without a pointer
   ever touching the page} put a 95%-black scrim at z-index 6 directly over a
   subtitle at 5, and the line vanished with the seek bar sitting on top of it.
   The two states that raise the bar are now the two states that raise the cue:
   one fact, one pair of selectors, and the layer can no longer disagree with
   itself.  ⚠️ Today that state is only ever entered for an instant, because
   watch.js happens to call show() from its `pause` handler — the layer was
   correct by side effect, which is not the same as being correct. */
.nwx-root.is-live .nwx-cues,
.nwx-root.is-paused .nwx-cues { bottom: calc(7% + var(--nwx-barh, 92px)); }
/* A CINEMA SUBTITLE IS NOT A CAPTION BOX — SUBFACE_20260819, and now it is not
   drawn as one either.  John, 2026-08-19: *"i also dont like the black block
   subs background, can you make it transparrent? so only show the subs with
   nice easy reading font and a bit effect to make it easy to read"*.

   THE PLATE IS OFF BY DEFAULT AND THE TYPE CARRIES ITSELF.
   The plate existed for one reason: a white frame.  A soft drop shadow cannot
   hold white type against snow, a sky or a wall, so the answer used to be a
   66%-black slab under every line — legible on any frame and a slab across the
   bottom of every other frame in the film.  What actually solves the white
   frame is the treatment burned-in subtitles have used for as long as there
   have been burned-in subtitles: A HARD OUTLINE.  Eight offsets of solid black
   at a fixed radius draw a ~1.3px ring around every glyph at full size, which
   is opaque where it counts and invisible on a dark frame, and one soft cast
   under it separates the line from a busy mid-grey.  White type inside a black
   ring reads over snow, over an explosion and over a white wall, which is the
   whole job the plate was doing, without covering a square inch of the picture.

   ⭐ THE OUTLINE IS IN em, NOT px, ON PURPOSE.  --nwx-cue-scale multiplies the
   size across a 0.82–1.34 range and the phone tier sets a size of its own; a
   px ring would be a heavy blot at the smallest step and a hairline at the
   largest.  In em it is the same ring at every size on every device.

   ⭐ THE FACE IS DECLARED HERE AND IS NOT var(--font-ui).  The UI stack is
   tuned for 11–14px read at desk distance; a subtitle is read at ~27px, across
   a room, in motion, over a moving picture.  This one leads with each
   platform's own system face — Segoe UI on John's Windows, SF on Apple, Roboto
   on Android — because those are the only ones that ship a REAL 600: with an
   outline around it, semibold is right and bold is not, since a 700 face plus
   a ring closes up the counters of a, e and s at exactly the moment they have
   to be told apart.  Helvetica/Arial/Liberation Sans are the honest fallbacks
   after them, metric-compatible with each other and present on everything
   else.  ⚠️ The tracking is .012em rather than .004: the ring adds ink to both
   sidebearings of every glyph, and at the old value outlined letters touched.

   ⛔ THE PLATE IS NOT REMOVED, ONLY DEFAULTED OFF.  --nwx-cue-plate still
   draws it at any alpha the viewer picks, the outline stays under it, and
   SUBTITLE APPEARANCE still offers all four steps.

   ⭐ AND TWO OF ITS NUMBERS BELONG TO THE VIEWER, NOT TO THIS FILE.
   Most of this library is original-language audio with English subtitles, so
   for a great many of these films the subtitle is not an accessory to the
   picture — it is how the film is followed.  One size set once against a desk
   monitor cannot also be right for a handset at arm's length in a lit room,
   and the plate that keeps type legible over a snowfield is the same plate
   that covers the bottom of a night scene.  watch.js publishes:

     --nwx-cue-scale   a MULTIPLIER on the size, never a replacement — the
                       clamp still gives a phone its floor and a projector its
                       ceiling, so no setting can be illegible on the other
                       device the same viewer owns
     --nwx-cue-plate   the alpha of the plate, 0 for none — and 0 is now what
                       an untouched browser gets

   Everything else about how a subtitle is drawn — the face, the weight, the
   outline, the tracking, the placement — stays here, decided once. */
.nwx-cue {
  display: inline-block;
  max-width: 100%;
  margin: 2px 0;
  padding: 1px 9px;
  background: rgba(0, 0, 0, var(--nwx-cue-plate, 0));
  color: #fff;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, "Liberation Sans", sans-serif;
  font-size: calc(clamp(15px, 2.35vw, 27px) * var(--nwx-cue-scale, 1));
  font-weight: 600;
  line-height: 1.34;
  letter-spacing: .012em;
  /* Eight solid offsets = the ring.  The ninth is the cast under it, which is
     what lifts a line off a busy mid-grey rather than off a bright one.  The
     tenth is a 1px floor: the ring is in em, so at the Smaller step on a narrow
     window it is barely half a pixel, and this is the one part of the treatment
     that must not thin out with the type.  ⛔ No max() and no calc() anywhere
     in here on purpose — an engine that fails to parse one length drops the
     WHOLE declaration, and with the plate off that leaves white type on a white
     frame with nothing at all behind it. */
  text-shadow:
     .048em 0     0 #000, -.048em 0     0 #000,
     0      .048em 0 #000,  0     -.048em 0 #000,
     .034em .034em 0 #000, -.034em .034em 0 #000,
     .034em -.034em 0 #000, -.034em -.034em 0 #000,
     0 .028em .07em rgba(0, 0, 0, .78),
     0 0 1px rgba(0, 0, 0, .92);
}
.nwx-cue i, .nwx-cue em { font-style: italic; }
.nwx-cue b, .nwx-cue strong { font-weight: 800; }

/* --- the skip mark -------------------------------------------------------
   SKIP INTRO / SKIP CREDITS.  It is on the PICTURE and not in the control
   bar, because it belongs to a moment of the film rather than to the
   transport: it exists for the ninety seconds an opening runs and then it is
   gone.  ⭐ AND IT IS NOT GATED ON .is-live.  A viewer who has let the chrome
   fade is exactly the viewer sitting through a title sequence, and a control
   that must be revealed before it can be pressed costs two gestures for a
   thing that should cost one.  It rides above the bar by the bar's own
   measured height, the same number the subtitles clear it by.

   THE ORANGE IS SPENT ON A FLAG, NOT ON A PILL.  Same idiom as the ticket
   kicker on every card in this file: three millimetres of accent against a
   hairline frame, and no filled button anywhere. */
.nwx-skip {
  position: absolute;
  right: 14px;
  bottom: calc(var(--nwx-barh, 92px) + 14px);
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 0 15px 0 12px;
  background: rgba(9, 8, 8, .93);
  border: var(--hair) solid var(--nwx-line);
  color: #ece5da;
}
.nwx-skip::before {
  content: "";
  flex: 0 0 3px;
  width: 3px;
  height: 14px;
  background: var(--nwx-accent);
}
.nwx-skip-label {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .18em;
  font-weight: 700;
  text-transform: uppercase;
}
.nwx-skip:hover { border-color: var(--nwx-accent); color: #fff; }

/* --- the top bar ---------------------------------------------------------
   ⚠️ THE SCRIM HAS TO BE SOLID WHERE THE TYPE IS.  A film is very often a
   pale desert or a white sky across its top third, and the old scrim had
   faded to nothing by the title's own baseline — the name of the film
   disappeared into the frame it was naming.  The band is now held near
   opaque down past the metadata line and only then released, which costs
   nothing and means the header is legible on any frame ever shown. */
.nwx-top {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 5;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px 30px;
  background: linear-gradient(to bottom,
    rgba(0, 0, 0, .90) 0%,
    rgba(0, 0, 0, .84) 42%,
    rgba(0, 0, 0, .58) 70%,
    rgba(0, 0, 0, 0) 100%);
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity .18s ease, transform .18s ease;
  pointer-events: none;
}
.nwx-root.is-live .nwx-top { opacity: 1; transform: none; pointer-events: auto; }
.nwx-topbits { min-width: 0; flex: 1 1 auto; }
/* NOT accent.  "NITRATE PROJECTOR" is neither selected nor in need of
   attention, and an orange that means nothing is an orange that stops meaning
   anything.  It is a plate on a machine: small, tracked, and quiet. */
.nwx-eyebrow {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .18em;
  font-weight: 700;
  color: rgba(236, 229, 218, .42);
}
.nwx-title {
  font-family: var(--font-marquee);
  font-size: 26px;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -.01em;
  text-transform: uppercase;
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* RUN_20260829 — the episode's own name, on the picture.  It reads in the
   house's ink, not the dim technical grey of the print facts under it: which
   episode is playing is the fact the viewer came for, and the dimensions are
   the footnote.  ⛔ Never drawn for a film (paintHead hides it). */
.nwx-ep {
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: .04em;
  color: #ece5da;
  margin-top: 5px;
}
.nwx-sub {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  letter-spacing: .02em;
  color: var(--nwx-dim);
  margin-top: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nwx-close {
  flex: 0 0 auto;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 0 12px;
  background: var(--nwx-chrome);
  border: var(--hair) solid var(--nwx-line);
  color: #ece5da;
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.nwx-close .nwx-btn-label { color: #ece5da; font-size: 10px; letter-spacing: .16em; }
.nwx-close-x { font-size: 13px; line-height: 1; }
.nwx-close:hover { border-color: var(--nwx-accent); color: #fff; }

/* --- the control bar -----------------------------------------------------
   A film can be a wall of magenta behind the controls.  The dark band has to
   be SOLID where the controls actually sit and only then fade, or a bright
   frame eats the clock. */
.nwx-bar {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 6;
  padding: 30px 14px 10px;
  background: linear-gradient(to top,
    rgba(0, 0, 0, .95) 0%, rgba(0, 0, 0, .92) 62%, rgba(0, 0, 0, 0) 100%);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .18s ease, transform .18s ease;
  pointer-events: none;
}
.nwx-root.is-live .nwx-bar { opacity: 1; transform: none; pointer-events: auto; }

.nwx-row {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 2px;
}
.nwx-spacer { flex: 1 1 auto; min-width: 6px; }

/* --- sliders -------------------------------------------------------------
   Hand-built: <input type=range> cannot draw a buffered fill, cannot lose its
   radius in every engine, and cannot have a 44px hit area over a 3px track.

   ⭐ THE SEEK BAR IS A MEASURING SCALE, NOT A PROGRESS BAR.  At rest it is a
   hairline rule the width of the film; the ticks that cut it are chapters,
   and they OVERSHOOT the rule at both ends the way the graduations on any lab
   rule do.  Press it and the rule thickens into something with a grip.  It is
   inset to the bar's own margin rather than bleeding off both screen edges,
   so 0:00 and the end sit above the controls that read them. */
.nwx-slider {
  position: relative;
  display: block;
  width: 100%;
  padding: 14px 0 12px;
  cursor: pointer;
  touch-action: none;
}
.nwx-track {
  position: relative;
  height: 3px;
  background: rgba(236, 229, 218, .16);
  overflow: visible;
  transition: height .1s ease;
}
.nwx-buffered {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: rgba(236, 229, 218, .32);
}
.nwx-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--nwx-accent);
}
/* A NEEDLE, NOT A BALL.  Nothing in this house is round, and a projector's
   position is read off a hairline against a scale. */
.nwx-knob {
  position: absolute;
  top: 50%;
  left: 0;
  width: 3px;
  height: 15px;
  margin-left: -1px;
  background: var(--nwx-accent);
  transform: translateY(-50%) scaleY(0);
  transform-origin: center;
  transition: transform .12s ease;
}
.nwx-slider:hover .nwx-knob,
.nwx-slider.is-drag .nwx-knob,
.nwx-slider:focus-visible .nwx-knob { transform: translateY(-50%) scaleY(1); }
.nwx-slider.is-drag .nwx-track,
.nwx-slider:hover .nwx-track { height: 7px; }
.nwx-slider:focus-visible { outline: 2px solid var(--nwx-accent); outline-offset: 3px; }

/* Chapter marks.  Hairlines cut THROUGH the bar rather than sitting on it: a
   chapter is a division of the film, and a division is a cut, not a dot.  They
   are drawn over the buffered fill and under the knob, so the knob is never
   lost among them, and they are non-interactive — the bar underneath is still
   the thing you press, and it already reaches wherever you point. */
.nwx-marks {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
/* Engraved, not painted.  The bar has three grounds — unplayed (a dark rule),
   buffered (a lighter one) and played (the accent) — and no single colour reads
   on all three: a dark mark disappears into the unplayed rule, a light one
   disappears into the buffered fill.  A light hairline with a dark one against
   it is legible on any of them, which is the whole reason for the shadow.
   The 2px overshoot at each end is what turns a divided bar into a scale. */
.nwx-mark {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 1px;
  margin-left: -1px;
  background: rgba(236, 229, 218, .62);
  box-shadow: -1px 0 0 rgba(12, 10, 9, .9);
}

/* ⭐ THE READING GLASS.  Where the pointer is pointing, in FILM time, with the
   chapter it lands in — read out of the same chapter list the ticks are drawn
   from, so it costs the house nothing and can never disagree with the bar.
   This is the one thing a viewer does constantly that the player could not
   answer before: "what is under my finger?"  It is drawn by watch.js.

   TRICKPLAY_20260819 — AND NOW IT CARRIES THE FRAME AS WELL.  The glass is a
   COLUMN: the still on top, the time and the chapter on a line beneath it.  The
   padding that used to sit on the glass itself has moved to .nwx-lens-txt, so
   a glass with no picture — which is every film the house has not made sheets
   for, and that is most of them — measures and draws exactly as it did before.
   Nothing here is conditional on a width or a media query: .has-shot is set by
   watch.js only once an Image has actually loaded, which is what makes a broken
   tile unreachable rather than merely unlikely. */
.nwx-lens {
  position: absolute;
  left: 0;
  bottom: 100%;
  margin-bottom: 3px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  background: rgba(9, 8, 8, .96);
  border: var(--hair) solid var(--nwx-line);
  border-bottom: 2px solid var(--nwx-accent);
  color: #ece5da;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity .1s ease;
}
.nwx-slider.is-lens .nwx-lens { opacity: 1; }
.nwx-lens-txt {
  display: flex;
  align-items: baseline;
  gap: 9px;
  min-width: 0;
  max-width: min(340px, 62vw);
  padding: 4px 9px;
}
/* THE FRAME IS THE PICTURE, NOT A THUMBNAIL OF ONE.  It is flush to the glass's
   own rule on three sides — a still off a strip of film has no mount around it
   — and it sits on TRUE BLACK for the same reason the gate does: a warm grey
   behind a projected frame tints it.  Its size, its background-size and its
   background-position are written by watch.js from the manifest, because those
   three numbers ARE the sprite arithmetic and only one place may hold it.
   No border-radius: this is a frame, and frames are square. */
.nwx-lens-shot {
  display: none;
  width: 160px;
  height: 90px;
  background-color: #000;
  background-repeat: no-repeat;
  border-bottom: var(--hair) solid var(--nwx-line);
}
.nwx-lens.has-shot .nwx-lens-shot { display: block; }
/* with a frame above it the width is the frame's, set inline — the text line
   fills it and a long chapter name ellipsises under the picture */
.nwx-lens.has-shot .nwx-lens-txt { max-width: none; }
.nwx-lens-t {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  letter-spacing: .02em;
}
.nwx-lens-c {
  min-width: 0;
  font-size: 11px;
  color: var(--nwx-dim);
  overflow: hidden;
  text-overflow: ellipsis;
}
.nwx-lens-c:empty { display: none; }
/* 🔴 THE HAND IS ON THE BAR.  Three pixels above the track is the right place
   for a mouse and the worst possible place for a thumb, which covers the bar
   and everything within a knuckle of it.  On a drag the glass is lifted clear;
   this is the whole reason the old code could argue itself into hiding the
   thing rather than moving it.  watch.js sets .is-touch on the press, so a
   mouse never pays this offset. */
.nwx-lens.is-touch { margin-bottom: 44px; }

/* VOLUME IS NOT AN ALARM.  It was drawn in safety orange, full width, which
   made the least important control the loudest object in the bar and spent
   the one colour that is supposed to mean something.  It is a plain cream
   rule now; orange stays for the film's own position and for the track that
   is actually on. */
.nwx-volslider { width: 76px; flex: 0 0 76px; }
.nwx-volslider .nwx-fill,
.nwx-volslider .nwx-knob { background: rgba(236, 229, 218, .82); }
.nwx-volslider:focus-visible { outline-color: rgba(236, 229, 218, .82); }
.nwx-volslider .nwx-lens { display: none; }

/* --- buttons -------------------------------------------------------------
   ⭐ THE VALUE IS THE INFORMATION; THE LABEL IS ONLY ITS NOUN.  These five
   controls used to be five identical shouted words with the answer whispered
   beside them, so the bar read AUDIO SUBS CHAPTER VERSION CAST — a menu bar —
   when what a projectionist wants at a glance is eng · eng · 4/20 · off,
   which is the state of the print.  Swapping the weights turns a row of
   buttons into a status strip you can press.  The accessible name is on
   aria-label and does not move. */
.nwx-btn {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  gap: 6px;
  padding: 13px 9px;
  background: transparent;
  border: var(--hair) solid transparent;
  color: #ece5da;
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
}
/* an author `display` beats the UA's [hidden] rule, so say it here or the
   VERSION control is drawn for a title that has only one print */
.nwx-btn[hidden], .nwx-root [hidden] { display: none !important; }
.nwx-btn:hover:not(:disabled) { border-color: var(--nwx-line); }
.nwx-btn:disabled { color: var(--nwx-idle); cursor: default; }
.nwx-btn:disabled .nwx-btn-val,
.nwx-btn:disabled .nwx-btn-label { color: var(--nwx-idle); }
.nwx-glyph { font-size: 18px; line-height: 1; align-self: center; }

.nwx-btn-label {
  font-size: 9.5px;
  letter-spacing: .16em;
  font-weight: 600;
  color: var(--nwx-dim);
  transition: color .12s ease;
}
.nwx-btn-val {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  letter-spacing: .01em;
  text-transform: none;
  color: #ece5da;
}
.nwx-btn-val:empty { display: none; }
/* A control with no state to report has nothing to whisper beside: its noun IS
   the content, so it is set at reading size rather than as a caption to a
   value that is not there.  CAST before a screen is chosen is the only one. */
.nwx-btn:has(.nwx-btn-val:empty) .nwx-btn-label { font-size: 10.5px; color: #ece5da; }
.nwx-btn:hover:not(:disabled) .nwx-btn-label { color: #ece5da; }
/* "on" is carried by the ANSWER, not by the whole control: subtitles being on
   is a fact about the value "English", not about the word SUBS. */
.nwx-btn.is-on .nwx-btn-val { color: var(--nwx-accent); }
.nwx-btn[aria-expanded="true"] { border-color: var(--nwx-accent); }
.nwx-btn[aria-expanded="true"] .nwx-btn-label { color: var(--nwx-accent); }
.nwx-play { min-width: 46px; padding: 0 8px; }
.nwx-mute, .nwx-fs, .nwx-pip { padding: 0 8px; }

/* ⛔ THE FLOATING-WINDOW MARK IS DRAWN, NOT TYPED.  ▶ ⏸ ✕ ⤡ are in every font
   a browser has ever shipped; the dingbat squares this control would need
   (U+274F / U+2750) are not, and a control that renders as a tofu box is worse
   than no control.  So it is two rectangles: the frame, and the small picture
   in the corner of it — which is exactly what the thing does. */
.nwx-pip .nwx-glyph {
  position: relative;
  width: 17px;
  height: 13px;
  border: 1.5px solid currentColor;
  font-size: 0;
}
.nwx-pip .nwx-glyph::after {
  content: "";
  position: absolute;
  right: 1.5px;
  bottom: 1.5px;
  width: 8px;
  height: 6px;
  background: currentColor;
}
/* while the film IS out there, the mark is the one thing that has been chosen */
.nwx-pip.is-on { color: var(--nwx-accent); }

/* THE CLOCK.  The elapsed figure is the one number a viewer reads a hundred
   times in an evening, so it is the largest thing in the row; what remains is
   a check on it and sits back. */
.nwx-time {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--nwx-dim);
  padding: 0 8px 0 4px;
}
.nwx-t-now { color: #ece5da; font-size: 14px; letter-spacing: .01em; }
.nwx-t-sep { color: var(--nwx-idle); font-size: 11px; }
.nwx-t-left { font-size: 12px; }

.nwx-vol { display: inline-flex; align-items: center; gap: 2px; }

/* the transient status word: a track change, a nudge, a handoff */
.nwx-switch {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .14em;
  color: var(--nwx-accent);
  white-space: nowrap;
  opacity: 0;
  transition: opacity .16s ease;
  max-width: 42vw;
  overflow: hidden;
  text-overflow: ellipsis;
  padding-right: 6px;
}
.nwx-switch.is-on { opacity: 1; }

/* ==========================================================================
   THE CENTRE PLATE — and THE LEADER.

   ⭐ THE ONE BOLD THING IN THIS PLAYER, AND IT IS BOLD IN ONE PLACE ONLY.
   Everything a viewer waits for here — a print being read, a print being
   re-encoded, a track being switched, a film handed to a television — was
   announced by three small blocks marching left to right.  That is the
   generic loading widget of every web page ever built and it says nothing.

   What actually preceded a film for ninety years is the ACADEMY LEADER: a
   circle with a crosshair through it and a sweep going round, counting down
   the seconds until the picture starts.  It is the most recognisable object
   in projection, it belongs to this subject and to no other, and — the part
   that makes it honest rather than decorative — the number inside it is the
   REAL elapsed seconds of this wait, published by watch.js, not a fake
   progress bar inching toward a finish it cannot predict.  The sweep advances
   one twelfth per second, mechanically, in steps: it is a clock, and a clock
   that ticks is telling the truth.

   THE ONE ROUND THING IN THE HOUSE, DECLARED.  "border-radius: 0 — nothing is
   rounded" is a rule against soft-cornered boxes, the idiom of the consumer
   app this catalogue is deliberately not.  A leader dial is not a rounded
   box; it is round because the shutter it descends from is round.  It is the
   only circle here, it is drawn as a hairline, and it is never a filled pill.
   ========================================================================== */
.nwx-centre {
  position: absolute;
  inset: 0;
  z-index: 4;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
  pointer-events: none;
}
.nwx-centre.is-on { display: flex; }
.nwx-plate {
  position: relative;
  max-width: 470px;
  min-height: 88px;
  padding: 17px 20px 17px 96px;   /* the left channel belongs to the leader */
  background: var(--nwx-chrome);
  border: var(--hair) solid var(--nwx-line);
  text-align: left;
}
.nwx-plate-h {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 18px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .2em;
  font-weight: 700;
  color: var(--nwx-accent);
}
.nwx-plate-p {
  margin: 9px 0 0;
  color: var(--nwx-dim);
  line-height: 1.55;
  font-size: 12.5px;
}

/* the dial itself */
.nwx-dots {
  position: absolute;
  left: 20px;
  top: 17px;
  width: 56px;
  height: 56px;
  flex: 0 0 auto;
  color: var(--nwx-accent);
  border: var(--hair) solid currentColor;
  border-radius: 50%;             /* declared exception — see above */
  opacity: .8;
  /* the crosshair, as two background layers so both pseudo-elements stay free */
  background:
    linear-gradient(currentColor, currentColor) 50% 0 / 1px 100% no-repeat,
    linear-gradient(currentColor, currentColor) 0 50% / 100% 1px no-repeat;
  animation: none;                /* the old march is gone */
}
/* the crosshair running out past the dial, as it does on a real leader */
.nwx-dots::after {
  content: "";
  position: absolute;
  left: -9px; right: -9px;
  top: 50%;
  height: 1px;
  margin-top: -1px;
  background: currentColor;
  opacity: .45;
}
/* the sweep: one twelfth per second, stepped, never gliding */
.nwx-dots::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: 50%;
  background: conic-gradient(from -90deg,
    currentColor 0 30deg, transparent 30deg 360deg);
  opacity: .3;
  animation: nwx-sweep 12s steps(12, end) infinite;
}
@keyframes nwx-sweep { to { transform: rotate(360deg); } }

/* THE READING, dead centre of the dial.  watch.js puts the elapsed seconds in
   .nwx-plate-extra > .nwx-plate-clock and nothing else has ever gone in there;
   :has() keeps this composition from mangling anything that later does — the
   rule simply does not apply, and the figure sits under the text as before. */
.nwx-plate-extra { margin-top: 11px; }
.nwx-plate-extra:has(> .nwx-plate-clock:only-child) {
  position: absolute;
  left: 20px;
  top: 17px;
  width: 56px;
  height: 56px;
  margin: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
}
.nwx-plate-clock {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  color: var(--nwx-dim);
  letter-spacing: .06em;
}
/* The crosshair runs through the middle of the dial, which is where the
   reading has to sit — so the reading carries its own clear field and knocks
   the lines out behind it, exactly as the number does on a printed leader. */
.nwx-plate-extra:has(> .nwx-plate-clock:only-child) .nwx-plate-clock {
  padding: 2px 5px;
  background: #100e0d;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--nwx-accent);
}

/* ==========================================================================
   CARDS: resume, which print, every failure.
   THESE ARE READING, NOT WATCHING.  They are drawn in the theme's own colours
   on --panel, because a question deserves the light table.

   ⛔ NOT A MODAL WITH AN ACCENT BAR ON TOP.  The catalogue's own rule (see
   landing.css) is "no cards, no accent bars, no gradients"; a 3px orange strip
   across the head of a dark box is the house style of every web app and of
   none of this one.  What a lab actually hands you is a TICKET: a hairline
   frame, a stamped kicker at the head with a flag beside it, a rule under the
   stamp, and then the reading.  The orange is spent on the flag — three
   millimetres of it — instead of on 560 pixels of trim.
   ========================================================================== */
.nwx-gate {
  position: absolute;
  inset: 0;
  z-index: 8;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, .66);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.nwx-gate.is-on { display: flex; }

.nwx-card {
  width: min(560px, 100%);
  max-height: 100%;
  overflow-y: auto;
  padding: 0 0 18px;
  background: var(--panel);
  color: var(--ink);
  border: var(--hair) solid var(--rule);
  box-shadow: 0 26px 64px -26px rgba(0, 0, 0, .78);
}
/* the stamp line */
.nwx-card-k {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 11px 20px 10px;
  border-bottom: var(--hair) solid var(--rule);
  background: var(--panel-2);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .2em;
  font-weight: 700;
  color: var(--accent);
}
.nwx-card-k::before {
  content: "";
  flex: 0 0 3px;
  width: 3px;
  height: 12px;
  background: var(--accent);
}
/* ── THE HOUSE IS ASKING ───────────────────────────
   RUN_20260829.  Nothing is wrong: the house holds two prints, or a position,
   or the next episode, and it wants an answer.  ⛔ NOT safety-orange — that
   colour means "needs attention" here and it was being spent three times a
   night on a healthy sitting.  The kicker takes the house's own line colour
   and the flag is a hairline rule, so the card still reads as the house
   speaking without reading as an alarm. */
.nwx-card.is-ask .nwx-card-k { color: var(--nwx-dim, var(--muted)); }
.nwx-card.is-ask .nwx-card-k::before { background: var(--nwx-line, var(--rule)); }
.nwx-card.is-bad .nwx-card-k { color: var(--crit); }
.nwx-card.is-bad .nwx-card-k::before { background: var(--crit); }

/* ── STOPPED BY THE HOUSE ────────────────────────────────────────────────
   An admin ended this stream from the Screener.  Not an error and not styled
   as one: nothing broke, somebody decided.  The kicker takes the warning
   colour rather than the critical one, and the admin's own words are set as a
   QUOTATION — attributed, indented, in the reading face — because they came
   from a person and the rest of this card came from a machine.
   🔴 The text inside .nwx-card-said-p is written with textContent by
   stoppedByHouse(); nothing here or there ever interpolates it into markup. */
.nwx-card.is-stop .nwx-card-k { color: var(--warn, var(--accent)); }
.nwx-card.is-stop .nwx-card-k::before { background: var(--warn, var(--accent)); }
.nwx-card-said {
  margin: 0 20px 14px;
  padding: 12px 14px;
  background: var(--panel-2);
  border-left: 2px solid var(--warn, var(--accent));
}
.nwx-card-said-k {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-3, var(--ink-2));
  margin-bottom: 6px;
}
.nwx-card-said-p {
  margin: 0;
  color: var(--ink);
  font-size: 15px;
  line-height: 1.5;
  /* admin-typed, so it may be one long unbroken string */
  overflow-wrap: anywhere;
}

.nwx-card-h {
  font-family: var(--font-marquee);
  font-size: clamp(24px, 4vw, 34px);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: -.02em;
  line-height: 1.03;
  margin: 16px 20px 11px;
}
.nwx-card-p {
  margin: 0 20px .7em;
  color: var(--ink-2);
  line-height: 1.55;
  font-size: 13px;
}

/* ⭐ THE HOUSE'S OWN WORDS, QUARANTINED RATHER THAN SHOUTED.
   Every failure here names the URL, the HTTP code and the backend's verbatim
   reason — the rarest and best thing about this player, and it is not being
   softened.  What changes is that the finding is set apart as EVIDENCE, with
   a rule down its edge and its own ground, instead of running into the
   reassurance that follows it as one undifferentiated wall of grey.  watch.js
   always puts the machine's account first and the human's second; the rule
   follows that order. */
.nwx-card.is-bad .nwx-card-p {
  padding-left: 12px;
  border-left: var(--hair) solid var(--rule);
}
.nwx-card.is-bad .nwx-card-p:first-of-type {
  border-left: 2px solid var(--crit);
  color: var(--ink);
  background: var(--panel-2);
  padding: 10px 12px;
  margin-bottom: 12px;
}

.nwx-card-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 16px 20px 0;
  padding-top: 15px;
  border-top: var(--hair) solid var(--rule);
}
.nwx-act {
  min-height: 44px;
  padding: 0 16px;
  background: var(--ground);
  color: var(--ink);
  border: var(--hair) solid var(--rule);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.nwx-act:hover { border-color: var(--accent); }
.nwx-act.is-primary {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
.nwx-act.is-primary:hover { filter: brightness(1.08); }

/* the "which print" list, inside a card.  ONE block with hairline divisions,
   never a stack of separate boxes — the house rules out zebra and rules out
   floating tiles, and a list of prints is a ledger. */
.nwx-list {
  display: flex;
  flex-direction: column;
  margin: 4px 20px 0;
  border: var(--hair) solid var(--rule);
}
/* ⭐ THE VERDICT COMES FIRST.  A row used to read: the film's own name and
   year (which the headline above has already said), then the spec, then — in
   the smallest, palest type on the card — "DIRECT PLAY, nothing is touched"
   against "TRANSCODE, the picture has to be re-encoded".  That last line is
   the ONLY thing on the row a person is actually choosing between, and it was
   the footnote.  The three lines are re-ordered here rather than in watch.js:
   one button, one accessible name, the DOM untouched, and the eye gets them in
   the order the decision needs — what it will cost, what it is, what it is
   called. */
.nwx-listrow {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 100%;
  min-height: 44px;
  padding: 12px 13px;
  text-align: left;
  background: var(--ground);
  border: 0;
  border-bottom: var(--hair) solid var(--rule);
  color: var(--ink);
}
.nwx-list .nwx-listrow:last-child { border-bottom: 0; }
.nwx-listrow:hover { background: var(--panel-2); }
.nwx-listrow-n {
  order: 1;
  display: block;
  margin: 0 0 8px;
  padding-left: 10px;
  border-left: 2px solid var(--rule);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink);
}
.nwx-listrow-m {
  order: 2;
  display: block;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  letter-spacing: .03em;
  color: var(--ink-2);
}
.nwx-listrow-h {
  order: 3;
  display: block;
  margin-top: 4px;
  font-weight: 400;
  font-size: 11px;
  line-height: 1.35;
  color: var(--muted);
}
.nwx-listrow:hover .nwx-listrow-n { border-left-color: var(--accent); }

/* ==========================================================================
   MENUS: audio, subtitles, print, cast, route.
   ⭐ ONE FAMILY, AND THE FAMILY IS THE CATALOGUE'S.  These panels grew one at
   a time and read as six different products.  They now share exactly one
   structure, and it is the one every other page of NITRATE uses: a small
   tracked caption, a hairline that runs the FULL width to both margins, and
   then the ledger.  Nothing else inside a menu is allowed to be loud.
   ========================================================================== */
.nwx-menuhost { position: absolute; inset: 0; z-index: 7; pointer-events: none; }
.nwx-menuhost.is-on { pointer-events: auto; }
.nwx-menu {
  position: absolute;
  width: min(348px, calc(100vw - 24px));
  max-height: min(62vh, 460px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 0 4px;
  background: rgba(10, 9, 9, .975);
  border: var(--hair) solid var(--nwx-line);
  box-shadow: 0 18px 44px -18px rgba(0, 0, 0, .9);
}
.nwx-menu-h {
  padding: 10px 14px 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .2em;
  font-weight: 700;
  color: var(--nwx-accent);
  border-bottom: var(--hair) solid var(--nwx-line);
}
/* ⚠️ A SECOND CAPTION INSIDE ONE MENU, AND IT MUST NOT STICK.  .nwx-menu-h is
   pinned under the DONE bar in a sheet so a viewer nine rows into thirty-nine
   subtitle tracks can still see which menu they are in — and two pinned
   captions come to rest on the same 44px line and overlap.  A SECTION caption
   is a different job: it divides one short list, so it scrolls with the rows
   it heads.  Same voice, one step quieter — the accent in a menu means "this
   is what is chosen", and spending it on a divider spends it on nothing. */
.nwx-menu-h2 {
  padding: 13px 14px 6px;
  border-top: var(--hair) solid var(--nwx-line);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .2em;
  font-weight: 700;
  color: var(--nwx-dim);
}
.nwx-menu-note {
  padding: 9px 14px;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--nwx-dim);
  border-bottom: var(--hair) solid var(--nwx-line);
}
/* the caption's own note belongs to the caption, so the rule that separates
   "what this menu is" from "what you can choose" is the one under the note */
.nwx-menu-h:has(+ .nwx-menu-note) { border-bottom: 0; padding-bottom: 4px; }
.nwx-menu-warn {
  margin: 0;
  padding: 9px 14px 9px 12px;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--nwx-warn);
  border-left: 2px solid var(--nwx-warn);
  border-bottom: var(--hair) solid var(--nwx-line);
  background: rgba(216, 164, 65, .07);
}
.nwx-menu-rule {
  height: 0;
  margin: 6px 0;
  border-top: var(--hair) solid var(--nwx-line);
}

/* ⭐ THE SAMPLE LINE IN THE SUBTITLE APPEARANCE MENU — and why it is not on
   black.  The plate exists for the frames that are NOT black: a white sky, a
   snowfield, a desert.  A sample against the gate's own near-black would make
   "no plate" and "solid plate" look identical and the control would be a
   guess.  So the strip runs from one extreme to the other and the choice is
   judged against both at once.  It is the REAL .nwx-cue rule inside it —
   watch.js writes no styles of its own here — so what a viewer sets is
   literally what the film will show. */
.nwx-cuedemo {
  padding: 16px 12px;
  text-align: center;
  background: linear-gradient(100deg,
    #0b0a0a 0%, #0b0a0a 30%, #6f6b66 60%, #ddd8d0 100%);
  border-bottom: var(--hair) solid var(--nwx-line);
}

.nwx-opt {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  min-height: 44px;
  padding: 10px 14px;
  text-align: left;
  background: transparent;
  border: 0;
  border-left: 2px solid transparent;
  color: #ece5da;
}
/* hairline divisions, never zebra — a track list is a ledger like every other
   list in this catalogue, and two tracks that share a language ("English AAC
   stereo" over "English AC3 5.1") ran into one another without them */
.nwx-opt + .nwx-opt { border-top: var(--hair) solid rgba(236, 229, 218, .12); }
.nwx-opt:hover:not(:disabled) { background: rgba(236, 229, 218, .07); }
.nwx-opt:disabled { color: var(--nwx-idle); cursor: default; }
.nwx-opt.is-current { border-left-color: var(--nwx-accent); }
/* ⛔ THE BULLET WAS ROUND.  watch.js writes a "●" into this span for the track
   that is on — the one literally round object in a house whose first rule is
   that nothing is.  The glyph is suppressed and a square gate mark drawn in
   its place; the accessible state was never the glyph's job (aria-checked
   carries it), so nothing is lost but the circle. */
.nwx-opt-mark {
  flex: 0 0 10px;
  width: 10px;
  font-size: 0;
  line-height: 1.5;
  color: var(--nwx-accent);
}
.nwx-opt.is-current .nwx-opt-mark::before {
  content: "";
  display: block;
  width: 7px;
  height: 7px;
  margin-top: 6px;
  background: var(--nwx-accent);
}
.nwx-opt-txt { min-width: 0; flex: 1 1 auto; }
.nwx-opt-main { display: block; font-size: 13px; line-height: 1.35; }
.nwx-opt.is-current .nwx-opt-main { color: var(--nwx-accent); font-weight: 700; }
.nwx-opt-meta {
  display: block;
  margin-top: 3px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 10.5px;
  letter-spacing: .05em;
  color: var(--nwx-dim);
}
.nwx-opt-note {
  display: block;
  margin-top: 5px;
  font-size: 11px;
  line-height: 1.45;
  color: var(--nwx-dim);
}

/* THE HONEST ANNOTATIONS.  A row here says three different kinds of true
   thing and they must not look like one another:
     · cost — choosing this will make the house work        (amber, ruled)
     · good — this one is verified right                    (green, ruled)
     · note — this is simply how it behaves                 (grey, unruled)
   ⚠️ .nwx-opt-good had no rule in this stylesheet at all: the one strongly
   REASSURING thing a subtitle row can say — that the file's hash matches the
   print — was rendering as unstyled body grey, indistinguishable from the
   plain notes it is the opposite of. */
.nwx-opt-cost,
.nwx-opt-good {
  display: block;
  margin-top: 6px;
  padding-left: 9px;
  font-size: 11px;
  line-height: 1.45;
}
.nwx-opt-cost {
  border-left: 2px solid var(--nwx-warn);
  color: var(--nwx-warn);
}
.nwx-opt-good {
  border-left: 2px solid var(--nwx-ok);
  color: var(--nwx-ok);
}
/* armed = the second press really will charge the house a re-encode */
.nwx-opt.is-armed .nwx-opt-cost { color: var(--nwx-crit); border-left-color: var(--nwx-crit); }
.nwx-opt.is-armed { background: rgba(209, 89, 74, .12); }

/* cast rows: the screen's real state, never a guess */
.nwx-target .nwx-opt-meta::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 7px;
  vertical-align: baseline;
  background: var(--nwx-idle);
}
.nwx-target.is-up .nwx-opt-meta::before { background: var(--nwx-ok); }
.nwx-target.is-off .nwx-opt-meta::before { background: var(--nwx-crit); }
.nwx-target.is-unknown .nwx-opt-meta::before { background: var(--nwx-warn); }
.nwx-target.is-bad .nwx-opt-note { color: var(--nwx-crit); }

/* --- where watchcast.js's own picker hangs -------------------------------
   watchcast.js owns that panel; this player owns only WHERE it lands.  Its
   `.wcast` is position:absolute against a page this dialog covers entirely,
   so without a positioned host it would be stranded behind the picture.  The
   host is a bottom-right flex frame between the two bars — the same place
   this player's own menus open — and the ONE property overridden on their
   panel is `position`, so it participates in that frame.  No colour, no type,
   no spacing of theirs is touched. */
.nwx-casthost {
  position: absolute;
  left: 10px; right: 10px; top: 66px; bottom: 96px;
  z-index: 9;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  pointer-events: none;
}
.nwx-casthost[hidden] { display: none; }
.nwx-casthost > * {
  position: relative !important;
  pointer-events: auto;
  max-height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* --- the route card ------------------------------------------------------
   The one place the two roads are described side by side.  Neither is drawn
   as the lesser: same size, same weight, same border. */
.nwx-ask {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, .7);
  overflow-y: auto;
  overscroll-behavior: contain;
  font-family: var(--font-ui);
  font-size: var(--size-dense);
}
.nwx-card.is-ask { width: min(680px, 100%); }
.nwx-roads {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin: 12px 20px 4px;
}
.nwx-road {
  /* a <button> centres its content vertically; the two roads must start at
     the same line or the shorter one looks like an afterthought */
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  min-height: 44px;
  padding: 13px 14px 15px;
  text-align: left;
  background: var(--ground);
  color: var(--ink);
  border: var(--hair) solid var(--rule);
}
.nwx-road:hover:not(:disabled) { outline: var(--hair) solid var(--accent); outline-offset: -2px; }
.nwx-road:disabled { color: var(--muted); background: var(--panel-2); cursor: default; }
.nwx-road-h {
  display: block;
  font-family: var(--font-marquee);
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -.01em;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.nwx-road:not(:disabled) .nwx-road-h { color: var(--accent); }
.nwx-road-p {
  display: block;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-2);
  margin-bottom: 5px;
  padding-left: 10px;
  border-left: var(--hair) solid var(--rule);
}
.nwx-road-no {
  display: block;
  margin-top: 8px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.45;
  color: var(--crit);
}
.nwx-remember {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 12px 20px 0;
  padding: 10px 12px;
  background: var(--panel-2);
  border: var(--hair) solid var(--rule);
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--ink-2);
  cursor: pointer;
  min-height: 44px;
}
.nwx-remember input {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  accent-color: var(--accent);
}

/* --- focus ---------------------------------------------------------------
   A tool has a visible focus ring on every control, on any frame of any film. */
.nwx-root :focus-visible,
.nwx-ask :focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
/* inside the dark chrome the orange ring can sit on near-black; a second,
   inner light ring keeps it visible on a bright frame of the film too */
.nwx-root .nwx-btn:focus-visible,
.nwx-root .nwx-opt:focus-visible,
.nwx-root .nwx-close:focus-visible {
  outline: 2px solid var(--nwx-accent);
  outline-offset: -2px;
  box-shadow: inset 0 0 0 3px rgba(0, 0, 0, .8);
}
/* inside a ledger the ring is INSET: an outset ring on a bordered row draws a
   second rectangle around the first and the whole list looks broken. */
.nwx-listrow:focus-visible,
.nwx-road:focus-visible,
.nwx-act:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* --- paused / switching -------------------------------------------------- */
.nwx-root.is-paused .nwx-top,
.nwx-root.is-paused .nwx-bar { opacity: 1; transform: none; pointer-events: auto; }
/* SEEKBLANK_20260905 — the transition belongs to the ELEMENT, not to the
   switching state: declared inside the rule it faded DOWN over 160 ms and
   snapped back instantly, and that asymmetry is half of what reads as a
   flicker when a seek dims and undims the picture. */
.nwx-video { transition: opacity .16s ease; }
.nwx-root.is-switching .nwx-video { opacity: .55; }

/* THE TRANSPORT BELONGS TO A FILM THAT IS ACTUALLY RUNNING.  This rule is last
   on purpose: it has to beat .is-paused, which is true whenever a card is up.
   A play button and a seek bar under a "which print?" question are controls
   for something that has not started — the exact kind of control that claims
   more than it can do.
   ⭐ "casting" is a film that is actually running: on the television. The bar
   is the one set of controls for it — see THE TELEVISION AS THE PLAYBACK
   SESSION in watch.js. */
.nwx-root:not([data-phase="playing"]):not([data-phase="casting"]) .nwx-bar {
  opacity: 0;
  pointer-events: none;
}

/* --- casting -------------------------------------------------------------
   There is no picture in this tab to dim or get out of the way of: the stage
   is a plate saying where the film is, and the chrome stays up. */
.nwx-root[data-phase="casting"] .nwx-video { display: none; }
.nwx-root[data-phase="casting"] .nwx-plate { max-width: 52ch; }
/* the CAST control carries the screen it is on */
.nwx-cast.is-on .nwx-btn-val { color: var(--nwx-accent); }
/* 🔴 `display: inline-flex` on .nwx-btn beats the [hidden] attribute, so a
   control this player has decided not to draw would otherwise stay on screen.
   A regular viewer's CAST button is hidden until the BROWSER says it has a
   screen to offer — see THE BROWSER'S PICKER in watch.js — and that decision
   has to survive contact with the stylesheet. */
.nwx-btn[hidden] { display: none; }

/* ==========================================================================
   THE PHONE — AND THE THREE DIFFERENT QUESTIONS IT ASKS.

   🔴 A PHONE IN LANDSCAPE IS 844 OR 932 CSS px WIDE.  Every width test says
   "desktop" there — and landscape is not an edge case for a player, it is the
   NORMAL STATE of one: it is the orientation a film is actually watched in.
   The old single `max-width: 640px` block therefore handed a viewer
   desktop-sized hit targets at the exact moment the handset was in two hands
   in front of their face.  Measured before this rewrite, at 844x390: the seek
   bar was a 23px strip, the volume slider was a 23px drag target, the position
   needle was invisible (it only appeared on :hover), and the track menus were
   still anchored dropdowns whose rows ran 280px BELOW the bottom of the
   screen — the audio menu could not be opened at all once one had been left
   open.  None of that is visible from a width.

   So the questions are asked separately, and each is asked with the query that
   actually answers it:

     IS THIS A FINGER?     @media (hover: none)
                           True on every phone and tablet, in BOTH orientations,
                           false for every mouse, and — the whole point — it
                           DOES NOT CHANGE WHEN THE HANDSET TURNS.  Every SIZE,
                           and every affordance that a desktop reveals on hover,
                           is decided here.  This block is LAST in the file so it
                           beats both of the others at equal specificity.
     IS THE WINDOW NARROW? @media (max-width: 760px) / (max-width: 430px)
                           MOBILE_SPEC's two tiers, and nothing else: what is
                           DROPPED, what gets smaller, what stops fitting on one
                           line.  A layout question, not a touch question.
     IS THE WINDOW SHORT?  @media (max-height: 460px) and (orientation: landscape)
                           A phone on its side has 390px of height and the chrome
                           must not eat the picture.

   Folded per the spec: the old 640 tier is now 760, the old 400 tier is now
   430.  ⛔ No third width, and no fourth query.
   ========================================================================== */
@media (max-width: 760px) {
  .nwx-top { padding: 10px 10px 26px; gap: 8px; }
  .nwx-title { font-size: 19px; }
  .nwx-sub { font-size: 10px; }
  .nwx-eyebrow { font-size: 9px; }
  .nwx-close { min-width: 44px; padding: 0 10px; }
  .nwx-close .nwx-btn-label { display: none; }

  .nwx-bar { padding: 24px 6px 6px; }
  .nwx-row { gap: 0; }
  /* the clock loses its remaining half before it loses its elapsed half */
  .nwx-t-sep, .nwx-t-left { display: none; }
  .nwx-time { padding: 0 4px; }
  .nwx-t-now { font-size: 13px; }
  /* ⭐ ON A PHONE THE ANSWER GOES UNDER THE NOUN.  BARVAL_20260819.
     The desktop bar is a status strip — noun quiet, answer loud — and at 390px
     the answer does not fit BESIDE its noun: AUDIO English SUBS English
     CHAPTER 4/20 CAST overruns the row and the words collide.  Measured, at
     390×844 with a finger on a film with real values: forced inline, ALL FOUR
     controls clip.  This block used to conclude from that that the phone keeps
     the WORD YOU TAP and drops the answer — but inline-or-hidden were not the
     only two choices.  Stacked under its noun, nothing clips, and the whole
     cost is FIVE PIXELS of bar height (122 → 127).
     🔴 AND THAT MATTERED, because the phone is the device this player is
     mostly watched on, and it was the one device that could not tell you which
     audio track or which subtitle was on without opening a menu to find out.
     A status strip that will not say the status is a menu bar.
     The mute button still goes: the volume slider is already gone here and a
     phone has hardware keys for exactly this, so it is the one control on the
     bar that a phone has no use for.
     ⚠️ THE STACK IS A WIDTH DECISION AND STAYS ONE.  Turn the same phone on
     its side and there IS room beside the noun, so at 844px the inline strip —
     and the mute button — come straight back, which is right: inline is the
     fastest way to read the state of the print when it fits. */
  .nwx-btn.nwx-menubtn {
    flex-direction: column;
    align-items: center;
    gap: 1px;
  }
  /* ⛔ :not(:empty) or CAST-before-a-screen gets a blank line under its noun —
     .nwx-btn-val:empty is only equal specificity to this and loses on order. */
  .nwx-btn.nwx-menubtn .nwx-btn-val:not(:empty) {
    display: block;
    font-size: 9px;
    line-height: 1.1;
  }
  .nwx-mute { display: none; }
  /* ⚠️ 4px, NOT 6.  Measured at 390px with a screen on the LAN, i.e. with CAST
     drawn: at 6px the row needs 383px of a 378px track and the widest answers
     — English, auto, 1/13 — overhang their own buttons by 3px.  Two pixels of
     gutter per side is what pays for them.  The 44px target is untouched: it
     is min-width/min-height, not padding. */
  .nwx-btn { padding: 13px 4px; gap: 4px; }
  /* The noun keeps its phone size — that is still a width decision — but it
     goes back to being a CAPTION.  It was set bright here because it was the
     only thing left; with the answer under it the desk's hierarchy is true
     again, and two bright lines in one control is two things shouting. */
  .nwx-btn-label { font-size: 9.5px; letter-spacing: .08em; }
  .nwx-btn:has(.nwx-btn-val:empty) .nwx-btn-label { font-size: 9.5px; letter-spacing: .08em; color: #ece5da; }
  /* ⛔ AND THE NOUN NO LONGER CARRIES "ON".  It was orange here to stand in for
     a value that was not drawn; the value is drawn now and the base rule
     already paints IT — see "on is carried by the ANSWER".  Orange on both
     would be the same fact said twice, in the one colour this player reserves
     for saying a fact once.  aria-expanded stays: an OPEN MENU is a different
     signal from an ON track, and it is the button that is open. */
  .nwx-btn[aria-expanded="true"] .nwx-btn-label { color: var(--nwx-accent); }
  .nwx-slider { padding: 16px 0 12px; }

  .nwx-cue { font-size: calc(15px * var(--nwx-cue-scale, 1)); padding: 1px 7px; }

  .nwx-gate, .nwx-ask { padding: 10px; align-items: flex-start; }
  .nwx-card-k { padding: 10px 14px 9px; }
  .nwx-card-h { font-size: 22px; margin: 13px 14px 9px; }
  .nwx-card-p { margin-left: 14px; margin-right: 14px; }
  .nwx-list { margin-left: 14px; margin-right: 14px; }
  .nwx-card-acts { margin: 14px 14px 0; gap: 6px; }
  .nwx-act { flex: 1 1 auto; padding: 0 10px; font-size: 10px; letter-spacing: .1em; }
  .nwx-roads { grid-template-columns: 1fr; margin-left: 14px; margin-right: 14px; }
  .nwx-remember { margin-left: 14px; margin-right: 14px; }
  .nwx-road-h { font-size: 18px; }

  /* the leader is the same instrument, one size down */
  .nwx-plate { min-height: 76px; padding: 15px 16px 15px 78px; }
  .nwx-dots,
  .nwx-plate-extra:has(> .nwx-plate-clock:only-child) { left: 16px; top: 15px; width: 46px; height: 46px; }
  .nwx-plate-extra:has(> .nwx-plate-clock:only-child) .nwx-plate-clock { font-size: 14px; }
}

/* NARROW (spec's second tier, folded up from the old 400): shed the version
   control before anything that matters. */
@media (max-width: 430px) {
  .nwx-ver { display: none; }
  /* ⚠️ AND THE FLOATING WINDOW GOES WITH IT — a WIDTH decision, like the mute
     button above.  At 390px the row is already play · clock · AUDIO · SUBS ·
     CHAPTER · CAST · fullscreen, and one more 44px target is what makes it
     overrun; nothing in this player is allowed to scroll sideways at 390.
     Turn the same handset on its side and there is room, so it comes straight
     back — which is also the orientation a film is actually watched in. */
  .nwx-pip { display: none; }
  .nwx-btn-label { font-size: 8.5px; letter-spacing: .05em; }
  /* the mark keeps its 44px, but not its desk margins */
  .nwx-skip { right: 10px; padding: 0 12px 0 10px; }
  .nwx-skip-label { font-size: 10px; letter-spacing: .14em; }
}

/* ==========================================================================
   THE MENUS AS SHEETS — driven by a CLASS, not by a width.

   ⭐ WHICH ONE A MENU IS, IS A JS DECISION, AND THERE IS ONE OF IT.
   watch.js sets `.is-sheet` when the panel should be a bottom sheet — that is
   `(hover: none)` OR NITRATE.isMobile(), re-evaluated on every viewport
   crossing — and only anchors the panel to its button when it is not.  Keying
   this on a media query as well is how the old code ended up needing
   `!important` on five properties: the stylesheet was making the panel a sheet
   while the script was still writing `right:` and `bottom:` onto it as an
   anchored dropdown, and the two had to be settled by force.  One decision,
   one owner, no !important.
   ========================================================================== */
.nwx-menu.is-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  top: auto;
  width: 100%;
  max-height: 72vh;
  /* fully opaque as a sheet: it sits ON the control bar, and at 97% the
     buttons underneath ghost through the rows */
  background: #0b0a0a;
  padding-bottom: max(12px, var(--safe-b, 0px));
  padding-left: var(--safe-l, 0px);
  padding-right: var(--safe-r, 0px);
  border-left: 0;
  border-right: 0;
  border-bottom: 0;
}

/* ⭐ THE WAY OUT, WHERE THE THUMB ALREADY IS.
   On a desktop a menu is dismissed by pointing somewhere else, which a mouse
   does for free.  On a phone "somewhere else" is the film — you have to tap
   the picture to put a menu away, which is both undiscoverable and the exact
   gesture that means "show me the controls".  So a sheet carries its own way
   out, pinned to the top edge where a thumb reaching up the screen meets it
   first, and it says DONE rather than CLOSE: this player already has a Close
   and that one ends the film, on the television too.  Two controls that do
   different things must never share a word. */
.nwx-sheet-done {
  position: sticky;
  top: 0;
  z-index: 2;
  display: none;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  width: 100%;
  min-height: 44px;
  padding: 0 14px;
  background: #0b0a0a;
  border: 0;
  border-bottom: var(--hair) solid var(--nwx-line);
  color: var(--nwx-dim);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .2em;
  font-weight: 700;
  text-transform: uppercase;
}
.nwx-menu.is-sheet .nwx-sheet-done { display: flex; }
.nwx-sheet-x { font-size: 13px; line-height: 1; letter-spacing: 0; }
/* the caption rides up with it, so a viewer nine rows into thirty-nine
   subtitle tracks can still see which menu they are in */
.nwx-menu.is-sheet .nwx-menu-h { position: sticky; top: 44px; z-index: 1; background: #0b0a0a; }

/* ==========================================================================
   IS THE WINDOW SHORT?  A phone on its side has 390px of height in total, and
   the two bars are drawn over the picture — so what shrinks here is the
   VERTICAL rhythm and nothing else.  ⛔ Not the hit areas: the block below
   this one puts those back to 44px, on purpose, and it comes after.
   ========================================================================== */
@media (max-height: 460px) and (orientation: landscape) {
  .nwx-top { padding: 6px 10px 20px; }
  .nwx-title { font-size: 15px; }
  .nwx-sub { display: none; }
  .nwx-bar { padding: 12px 10px 4px; }
  .nwx-slider { padding: 11px 0 9px; }
  .nwx-plate { min-height: 0; padding: 12px 16px 12px 72px; }
  .nwx-dots,
  .nwx-plate-extra:has(> .nwx-plate-clock:only-child) { left: 14px; top: 12px; width: 44px; height: 44px; }
  /* a sheet on a 390px-tall screen can afford more of it than one on 844 */
  .nwx-menu.is-sheet { max-height: 86vh; }
}

/* ==========================================================================
   IS THIS A FINGER?   ⭐ THE BLOCK THE PLAYER LIVES OR DIES BY.

   Everything here is a SIZE or a hover-only affordance, and every one of them
   was previously decided by a width — which meant it was decided wrongly the
   moment the handset turned.  `(hover: none)` is true on a phone in portrait
   and in landscape, on a tablet, and on nothing with a mouse.  It is LAST in
   this file so that at equal specificity it wins over both the width tier and
   the short tier above.
   ========================================================================== */
@media (hover: none) {
  /* 🔴 44px OF SEEK BAR, IN BOTH ORIENTATIONS.
     The visible rule stays a 3px hairline — it is a measuring scale, not a
     progress bar — but what a thumb has to hit is the padding around it.  It
     was 31px in portrait and 23px in landscape; a fingertip is 44. */
  .nwx-slider { padding: 20px 0 21px; }
  /* ⛔ AND THE NEEDLE CANNOT BE A HOVER STATE.  It appears on :hover, on drag
     and on focus — a phone has none of those until the thumb is already down,
     so the one mark that says WHERE YOU ARE was invisible for the whole film.
     It is simply always drawn here. */
  .nwx-knob { transform: translateY(-50%) scaleY(1); }
  /* volume is a mute toggle on a phone: a 76px slider is not a thumb control,
     and the handset's own keys already do this better.  The mute BUTTON is a
     width decision and lives in the 760 block — in landscape it comes back. */
  .nwx-volslider { display: none; }
  /* 🔴 THE READING GLASS IS NOT A POINTER'S INSTRUMENT ANY MORE — TRICKPLAY_
     20260819.  It used to be hidden here, and watch.js refused to build it at
     all on a coarse pointer, on the reasoning that a thumb covers the readout
     it would be reading.  That is true of a readout 3px above the bar and it is
     an argument for MOVING it, not for deleting it: the handset is the device
     this player is mostly watched on, and it was the one device whose scrub bar
     said nothing at all about where it was going to land.
     It is built on every device now, shown while the bar is being DRAGGED
     rather than on a hover a phone cannot have, and lifted clear of the hand by
     .nwx-lens.is-touch above.  The only thing kept from the old rule is the
     44px of seek bar below, which is what makes the drag catchable at all. */

  .nwx-opt { min-height: 48px; padding: 12px 14px; }
  .nwx-act, .nwx-listrow, .nwx-road, .nwx-close, .nwx-btn { min-height: 44px; }

  /* THE NOTCH, THE ROUNDED CORNERS AND THE HOME INDICATOR.  In landscape —
     which is when this player is actually used — the insets are on the LEFT
     and RIGHT, and they are ~44px on a modern iPhone: without this the Close
     button sits under the camera housing and the seek bar's 0:00 end sits
     under the corner radius.  env() is 0 everywhere else, so these cost
     nothing on any other device. */
  .nwx-top {
    padding-top: max(10px, var(--safe-t, 0px));
    padding-left: max(10px, var(--safe-l, 0px));
    padding-right: max(10px, var(--safe-r, 0px));
  }
  .nwx-bar {
    padding-left: max(6px, var(--safe-l, 0px));
    padding-right: max(6px, var(--safe-r, 0px));
    padding-bottom: max(6px, var(--safe-b, 0px));
  }
  .nwx-cues {
    padding-left: max(4%, var(--safe-l, 0px));
    padding-right: max(4%, var(--safe-r, 0px));
  }
  /* the skip mark sits on the right, which in landscape — the orientation this
     player is used in — is exactly where the corner radius and the home
     indicator's inset are */
  .nwx-skip {
    right: max(10px, var(--safe-r, 0px));
    bottom: calc(var(--nwx-barh, 104px) + 10px);
  }

  /* ⭐ THE ONE-LINE ANSWER, MOVED RATHER THAN DELETED.
     `.nwx-switch` is where this player says SUBTITLES → ENG, MUTED, +10s,
     VOLUME 40%, FULLSCREEN USES THE SYSTEM PLAYER HERE, THE SCREEN REFUSED
     THAT.  It was `display: none` on a phone — and a phone is precisely where
     it is needed most, because the same tier also hides the value beside every
     button, so a subtitle change had NO visible confirmation of any kind: the
     sheet closed and nothing else happened.  It is not deleted here, it is
     moved: out of the button row, where it collided, and up into the control
     bar's own gradient above the seek rule, where there is nothing but shadow
     and the full width of the screen to be legible against. */
  .nwx-switch {
    display: block;
    position: absolute;
    left: max(6px, var(--safe-l, 0px));
    right: max(6px, var(--safe-r, 0px));
    top: 3px;
    max-width: none;
    padding: 0;
    text-align: center;
    pointer-events: none;
    text-shadow: 0 1px 4px rgba(0, 0, 0, .95), 0 0 2px rgba(0, 0, 0, .9);
  }

  /* ⚠️ THE CUES CLEAR THE BAR BY THE BAR'S OWN HEIGHT, NOT BY A GUESS.
     The old numbers (78px, 64px) were measured against a bar whose seek strip
     was 23-31px tall; at a real 44px they are wrong in every orientation, and
     a subtitle behind the control bar is a subtitle that is not there.
     watch.js publishes --nwx-barh from the element itself.
     ⚠️ SUBFACE_20260819 — .is-paused raises the bar here too, so it raises the
     cues here too.  The desktop rule carried the same fault; see it for why. */
  .nwx-cues { bottom: 8%; }
  .nwx-root.is-live .nwx-cues,
  .nwx-root.is-paused .nwx-cues { bottom: calc(5% + var(--nwx-barh, 104px)); }

  /* the cast panel is thumb-height too, centred rather than hugging a corner
     that does not exist on a phone, and clear of the bar it must not cover */
  .nwx-casthost {
    left: max(6px, var(--safe-l, 0px));
    right: max(6px, var(--safe-r, 0px));
    top: 56px;
    bottom: calc(var(--nwx-barh, 104px) + 8px);
    justify-content: center;
  }
}

/* ==========================================================================
   MOTION.  tokens.css already reduces every duration to nothing under
   prefers-reduced-motion; these rules make sure what is LEFT still reads.
   The leader stops with its sweep at twelve o'clock — a dial standing still is
   a legible object, and the number inside it is the reading either way.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .nwx-top, .nwx-bar { transform: none; }
  .nwx-knob { transform: translateY(-50%) scaleY(1); }
  .nwx-dots::before { animation: none; }
  .nwx-cues { transition: none; }
}
.nwx-root.is-still .nwx-knob { transform: translateY(-50%) scaleY(1); }
.nwx-root.is-still .nwx-dots::before { animation: none; }

/* ==========================================================================
   PRINT / FORCED COLOURS.  A player has nothing to print, but a forced-colour
   mode must not lose the one thing that carries meaning: which track is on.
   ========================================================================== */
@media (forced-colors: active) {
  .nwx-opt.is-current { border-left-color: Highlight; }
  .nwx-opt.is-current .nwx-opt-mark::before { background: Highlight; }
  .nwx-fill, .nwx-knob { background: Highlight; }
  .nwx-target .nwx-opt-meta::before { border: 1px solid CanvasText; }
  .nwx-dots { border-color: CanvasText; }
  .nwx-card-k::before { background: CanvasText; }
}

/* -----------------------------------------------------------------------
   STATS_20260821 — what the stream is doing.  A reader, not a control, so it
   is deliberately quiet: it sits out of the way of the picture, never takes a
   pointer event, and is drawn in the same monospaced voice the projector head
   uses so it reads as instrumentation rather than as part of the film.
   ----------------------------------------------------------------------- */
.nwx-stats {
  position: absolute;
  top: 4.6rem; right: 1.1rem;
  z-index: 6;
  pointer-events: none;                 /* never steals a click from the film */
  min-width: 15rem;
  padding: .7rem .85rem;
  background: rgba(8, 9, 11, .82);
  border: 1px solid rgba(255, 255, 255, .13);
  font: 400 11px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .04em;
  color: #e8e5df;
}
.nwx-stat { display: flex; gap: 1rem; justify-content: space-between; }
.nwx-stat-k {
  color: #8b8880; text-transform: uppercase; letter-spacing: .13em; font-size: 10px;
}
.nwx-stat-v { color: #e8e5df; text-align: right; font-variant-numeric: tabular-nums; }
/* the road, in the house's own words — wraps, so it gets its own block */
.nwx-stat-why {
  margin-top: .55rem; padding-top: .5rem;
  border-top: 1px solid rgba(255, 255, 255, .11);
  color: #b3afa7; font-size: 10.5px; line-height: 1.5;
  letter-spacing: .01em; max-width: 22rem; text-transform: none;
}

/* STINGER_20260829 -- the STAY line sits above the skip control, in the same
   ink, with the safety-orange bar because it asks for attention: the film is
   not over.  It exists only inside a credits window the house knows is
   followed by a scene (see readMarkers in watch.js). */
.nwx-stay {
  position: absolute;
  right: 14px;
  bottom: calc(var(--nwx-barh, 92px) + 14px + 54px);
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 15px 8px 12px;
  background: rgba(9, 8, 8, .93);
  border: var(--hair) solid var(--nwx-line);
  color: #ece5da;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .18em;
  font-weight: 700;
  text-transform: uppercase;
}
.nwx-stay::before {
  content: "";
  flex: 0 0 3px;
  width: 3px;
  height: 14px;
  background: var(--nwx-accent);
}
/* ROAD_20260829 -- the card at the end of the picture.
   ⛔ `.nwx-endroad`, NOT `.nwx-road`: that name is the road-chooser BUTTON above
   (:1377), and this block used to redefine it -- both roads ended up absolutely
   positioned at one corner and the card kept a zero-height hole where they had
   been.  ⭐ Two base rules for one class in this file is always a bug. */
.nwx-endroad {
  position: absolute;
  left: 14px;
  bottom: calc(var(--nwx-barh, 92px) + 14px);
  z-index: 5;
  max-width: min(440px, calc(100% - 28px));
  padding: 12px 16px 12px;
  background: rgba(9, 8, 8, .93);
  border: var(--hair) solid var(--nwx-line);
  color: #ece5da;
  cursor: pointer;
}
.nwx-endroad-h {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .2em;
  font-weight: 700;
  margin-bottom: 8px;
  color: var(--nwx-accent);
}

/* RUN_20260829 — the still of the episode the up-next card is offering.
   Native size, hairline framed, never stretched: /episode-thumb/ holds 480×270
   and upscaling it onto a 1080p stage would read as a defect. It sits above the
   card's own sentence, so the picture is the first thing read. */
.nwx-next-still {
  margin: 0 0 12px;
  line-height: 0;
  border: var(--hair) solid var(--nwx-line);
  background: #0b0a0a;
  max-width: 480px;
}
.nwx-next-still img { display: block; width: 100%; height: auto; }
@media (max-height: 560px) { .nwx-next-still { display: none; } }

/* ═══════════════════════════════════════════════════════════════════════
   THE RUN — RUN_20260829.  The season this episode belongs to, drawn as a run
   of frames under the film's identity.  ⛔ Not a progress bar and not a
   playlist: one mark per episode the shelf holds, the one playing lit, the
   ones this viewer finished here filled, and a MISSING frame where the shelf
   skipped an episode — the fact no other player states.
   It lives inside .nwx-topbits, so it fades with the chrome for free. */
.nwx-run { margin-top: 9px; max-width: 620px; }
.nwx-run-ticks {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 3px;
  margin-bottom: 5px;
}
/* a frame: a small upright rectangle, the shape of a strip of film */
.nwx-run-t {
  width: 9px;
  height: 14px;
  padding: 0;
  border: var(--hair) solid rgba(236, 229, 218, .38);
  background: transparent;
  cursor: pointer;
  font: inherit;
  line-height: 0;
}
.nwx-run-t:hover { border-color: #ece5da; }
/* seen here — the viewer's OWN record, never Plex's */
.nwx-run-t.is-part { background: rgba(236, 229, 218, .34); }
.nwx-run-t.is-done { background: rgba(236, 229, 218, .72); border-color: rgba(236, 229, 218, .72); }
/* the one running: the only place the accent is spent on this strip */
.nwx-run-t.is-here {
  background: var(--nwx-accent);
  border-color: var(--nwx-accent);
  height: 18px;
}
/* a gap is an ABSENCE, so it is drawn as one: no border, no fill, a hairline
   floor where a frame should have been */
.nwx-run-t.is-gap {
  border: 0;
  border-bottom: var(--hair) solid rgba(236, 229, 218, .30);
  height: 8px;
  cursor: default;
}
.nwx-run-line {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .13em;
  color: rgba(236, 229, 218, .55);
}
.nwx-run-t:focus-visible { outline: var(--hair) solid var(--nwx-accent); outline-offset: 2px; }
/* the phone keeps the line and sheds the frames: at 390px a 26-episode season
   is four wrapped rows of taps nobody aimed for */
@media (max-width: 560px) { .nwx-run-ticks { display: none; } }
@media (max-height: 460px) { .nwx-run { display: none; } }
