/* Chroma Noir — the films index
   ---------------------------------------------------------------------------
   A POSTER WALL. Until 1.14.0 this was a typeset list of thirteen titles in a
   fixed-height scroll box, with the film you pointed at playing full-bleed
   behind the type. That was drawn for eleven films. There are twenty-six, they
   arrive faster than the design does, and about eleven of them were on screen
   — the rest behind a scrollbar most visitors never touched.

   So every film shows a face, and the full-bleed preview is given up to pay
   for it: with pictures across the whole frame there is no left-hand column of
   type left to protect, so the directional scrim becomes a flat one and the
   preview moves INSIDE the tile it belongs to.

   Gold is still spent once per thing: the hairline that sweeps along the
   bottom edge of a still on approach, the padlock on a film that will not
   open, and the dot where a portal-gated film's number would be. Everything
   else is four greys.
*/

:root{
  --ink:#f4f3f1; --dim:#9a9894; --faint:#6a6764; --gold:#c9a14a;
  --rule:rgba(244,243,241,.14);
  /* The value .find:focus has always fallen back to, now written down once so
     the form fields below can share it. Nothing that existed changes. */
  --rule2:rgba(244,243,241,.34);
  --sans:'Inter Tight',-apple-system,'Segoe UI',sans-serif;
  --serif:'Fraunces',Georgia,serif;
  /* 16px at 390px, which is the gutter the wall was drawn to. */
  --pad:clamp(16px,4vw,56px);
  /* The mock said 1400px, which was drawn for a list in one column. A wall of
     215px tiles at 1400 is five across in the middle of a 2560px monitor with
     a third of the screen black on either side — a strip, not a wall. */
  --wide:1760px;
  --ease:cubic-bezier(.22,.61,.36,1);

  /* ---- the on-picture fullscreen control ---------------------------------
     Sizes and insets as custom properties, which are Chrome 49 and so safe on
     the television. BREAKPOINTS cannot be tokens — a custom property is
     illegal in a media-query condition and there is no preprocessor here — so
     the numbers stay literal and the comment block above the device classes
     lists them instead. */
  --pfs-size:36px;          /* visual box, fine pointer */
  --pfs-size-touch:48px;
  --pfs-size-tv:56px;
  --pfs-icon:18px;
  --pfs-icon-touch:22px;
  --pfs-icon-tv:26px;
  --pfs-inset:12px;         /* from the picture's top and right edges */
  --pfs-inset-touch:10px;
  --pfs-inset-tv:24px;
  /* .55 and not .45, and it is measured rather than chosen: the icon over a
     .45 plate on a blown-out white frame is 3,03:1, which has no margin at
     all on the 3:1 floor for a control. At .55 it is 4,27:1. */
  --pfs-plate:rgba(0,0,0,.55);
  --pfs-plate-on:rgba(0,0,0,.72);
  --pfs-edge:rgba(244,243,241,.22);
  --pfs-edge-on:rgba(244,243,241,.42);

  /* Chrome timing, shared by the control and the landscape band: they are ONE
     chrome and must never disagree. --chrome-hide is a JS constant (CHROME_HIDE
     in films.js) and is mirrored here only for the record. */
  --chrome-hide:2600ms;
  --chrome-in:140ms;
  --chrome-out:240ms;

  /* A real spacing scale, FOR NEW RULES ONLY. The literals already in this
     file each carry their own written reasoning; replacing them with tokens
     would be churn with a regression risk and no visible gain. */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px;
  --s5:24px; --s6:32px; --s7:48px; --s8:64px;
  color-scheme:dark;
}
*{box-sizing:border-box}
/* THE PAGE SCROLLS NOW. It used to be a fixed-height flex column with a list
   scrolling inside it, so `overflow:hidden` on the body was load-bearing.
   A wall is as tall as the library, and the window's own scrollbar is the only
   honest indicator of how much there is. */
body{margin:0;background:#000;color:var(--ink);font-family:var(--sans);
     font-synthesis:none;-webkit-font-smoothing:antialiased}
[hidden]{display:none !important}

/* ---- the ground -----------------------------------------------------------
   No photograph. The stills are in the tiles now, and a second copy of one of
   them behind the grid would compete with all twenty-six. What is left is one
   soft key light at the top of an otherwise black page — the flat scrim from
   the approved mock, and the whole of the noir the wall keeps. */
.scrim--flat{position:fixed;top:0;right:0;bottom:0;left:0;z-index:0;pointer-events:none;
  background:linear-gradient(rgba(244,243,241,.035) 0%,rgba(0,0,0,0) 38%)}

/* THE SAFE AREA, written as a pair every time: a plain value on the line
   before and the env() version after it. env() is Chrome 69 for this spelling
   and the television is 79, but an unsupported env() drops the WHOLE
   declaration — and a dropped padding is a layout touching the frame. The
   pair costs one line and cannot fail. */
.page{position:relative;z-index:2;max-width:var(--wide);margin:0 auto;
      padding:0 var(--pad) clamp(44px,9vh,96px);
      padding-left:calc(var(--pad) + env(safe-area-inset-left));
      padding-right:calc(var(--pad) + env(safe-area-inset-right));
      padding-bottom:calc(clamp(44px,9vh,96px) + env(safe-area-inset-bottom))}

/* ---- chrome --------------------------------------------------------------- */
/* The vertical margins on the children give a wrapped bar its row rhythm
   without flex gap; the padding is reduced by the same 5px so the bar sits
   where it always did. */
.bar{display:flex;flex-wrap:wrap;align-items:center;padding:17px 0;
     padding-top:calc(17px + env(safe-area-inset-top))}
.bar > *{margin:5px 0}
.bar > * + *{margin-left:18px}
.link{display:inline-flex;align-items:center;border:0;padding:0;background:none;
      font:inherit;font-size:14px;font-weight:500;color:var(--dim);text-decoration:none;
      cursor:pointer;transition:color .25s}
/* The arrow's distance from the word, and the nudge it takes on approach. Was
   a flex gap, which the television does not have. */
.link > span{margin-right:10px;transition:margin-right .25s}
.link:hover{color:var(--ink)}
.link:hover > span{margin-right:15px}
.link:focus-visible{outline:2px solid var(--gold);outline-offset:4px}
.bar__gap{flex:1 1 auto}

/* The search field. Absent until there are enough films to need it — at eleven
   titles a search box is furniture. */
/* 2px, not the legacy 999px pill. It was the only FIELD on the subdomain
   still wearing it — .veil__in, .field, .film__title and .icell__cap are all
   2px — so this is an inconsistency inside the field family, not a change to
   the button family. .cbtn and .wbtn stay pills. */
.find{width:min(260px,34vw);padding:7px 12px;border:1px solid var(--rule);
      border-radius:2px;background:rgba(0,0,0,.5);color:var(--ink);font:inherit;
      font-size:13px;transition:border-color .25s,width .3s}
/* 34vw OF A 390px PHONE IS 132px, which is about nine characters of a 16px
   field — and the bar has already wrapped it onto a row of its own, where it
   sat in the left third with two thirds of the row empty beside it. A
   flex-basis of 100% can never share a line, so the field is alone on its row
   by construction and may start at the gutter: the 18px that .bar > * + *
   gives it is removed with it, which is also what stops a 100% basis plus a
   margin overflowing the page. Only under 520px, where it has in fact
   wrapped. */
@media (max-width:520px){
  .find{flex:0 0 100%;width:auto;margin-left:0}
}
.find::placeholder{color:var(--faint)}
.find:focus{outline:none;border-color:var(--rule2)}
.find:focus-visible{outline:2px solid var(--gold);outline-offset:2px}

/* ---- the rail --------------------------------------------------------------
   Filter on the left, sort on the right, ONE LINE THAT NEVER WRAPS. Chips that
   reflow onto a second line move the wall down the page every time a count
   changes; a line that scrolls sideways inside its own box does not move
   anything. The scrollbar is 4px and only appears where it is needed. */
/* A GRID RATHER THAN A WRAPPING FLEX ROW, because grid gap works on the wall
   TV and flex gap does not (Chrome 66 against Chrome 84). It also removes the
   guesswork: below 860px the filters take one line and the sort takes the next,
   deterministically, instead of wrapping at whatever width the chips happen to
   add up to. */
.railwrap{display:grid;grid-template-columns:minmax(0,1fr);row-gap:10px;
  padding-bottom:clamp(20px,3.2vh,38px)}
@media (min-width:860px){
  .railwrap{grid-template-columns:minmax(0,1fr) auto;column-gap:24px;align-items:center}
}
.rail{display:flex;flex-wrap:nowrap;align-items:center;min-width:0;
  overflow-x:auto;padding-bottom:2px;
  scrollbar-width:thin;scrollbar-color:rgba(244,243,241,.16) transparent}
/* Margin, not gap: see .tile__dark. */
.rail > * + *{margin-left:6px}
.rail::-webkit-scrollbar{height:4px}
.rail::-webkit-scrollbar-thumb{background:rgba(244,243,241,.16)}
/* --dim at rest. These are 9,5-10,5px controls and --faint is about 3,7:1 on
   black — a size and a contrast agreeing with each other in the wrong
   direction. Quiet is done with the hairline box and the tracking. */
.chip{display:inline-flex;align-items:baseline;padding:5px 10px;white-space:nowrap;
  border:1px solid var(--rule);border-radius:2px;background:none;
  font:inherit;font-size:10.5px;font-weight:500;letter-spacing:.11em;text-transform:uppercase;
  color:var(--dim);cursor:pointer;
  transition:color .22s,border-color .22s,background-color .22s}
.chip:hover{color:var(--ink);border-color:var(--rule2)}
.chip[aria-pressed="true"]{color:var(--ink);border-color:var(--rule2);
  background:rgba(244,243,241,.05)}
.chip:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.chip__n{font-size:9.5px;letter-spacing:.04em;color:var(--dim);margin-left:7px;
  font-variant-numeric:tabular-nums}
.chip[aria-pressed="true"] .chip__n{color:var(--ink)}
.rail__div{flex:0 0 1px;align-self:stretch;background:var(--rule);margin:0 8px}
.rail__k{font-size:9.5px;font-weight:500;letter-spacing:.24em;text-transform:uppercase;
  color:var(--dim);white-space:nowrap;margin-right:3px}
.railright{display:flex;flex-wrap:wrap;align-items:center}
.railright > * + *{margin-left:16px}
/* Play all and Shuffle sit before Sort, because they act on what the sort and
   the filters have already decided. Same box as .tbtn so the right-hand end of
   the rail reads as one row of controls rather than two kinds. */
.playbox{display:inline-flex;align-items:baseline}
.playbox > * + *{margin-left:9px}
.sortbox{display:inline-flex;align-items:baseline}
.sortbox > * + *{margin-left:9px}
.tbtn{border:0;padding:0;background:none;font:inherit;cursor:pointer;
  font-size:10.5px;font-weight:500;letter-spacing:.11em;text-transform:uppercase;
  color:var(--dim);transition:color .22s;white-space:nowrap}
.tbtn:hover{color:var(--ink)}
.tbtn[aria-pressed="true"]{color:var(--ink)}
.tbtn:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.tsep{color:var(--rule2);font-size:11px}

/* ---- what is narrowing the wall --------------------------------------------
   The utility register, not the lede's: this is a readout of the controls
   directly above it, so it is Inter Tight at the rail's own scale rather than
   Fraunces italic. Hidden whenever nothing is narrowed, which is most of the
   time — see paintState().

   MARGINS, NOT GAP. Flex gap is Chrome 84 and the wall TV is 79, so the row
   rhythm comes from the children exactly as it does on .bar and .cinema__foot.
   No gold: this file spends it on the sweep, the padlock and the gated dot,
   and a fourth use stops it being an accent. */
.state{display:flex;flex-wrap:wrap;align-items:baseline;
       margin:0 0 clamp(10px,1.6vh,18px);
       font-size:11px;letter-spacing:.06em;color:var(--dim)}
.state > *{margin:3px 0}
/* The count is the sentence's subject, so it is the one thing in --ink. */
.state__n{color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap}
.state__bits{display:flex;flex-wrap:wrap;align-items:baseline;min-width:0}
.state__bits > *{margin:3px 0}
.state__bit{color:var(--ink)}
.state__sep{color:var(--rule2);margin:0 8px}
.state__clear{margin-left:14px}

.lede{margin:0 0 clamp(14px,2.4vh,30px);font-family:var(--serif);font-style:italic;
      font-weight:300;font-size:clamp(15px,1.6vw,19px);color:var(--faint);
      min-height:1.3em}

/* ---- the featured film -----------------------------------------------------
   ONE frame, above the rail, 21:9 so it cannot eat the first row of tiles. It
   is the one place on the wall that gets the full-bleed treatment back — and
   the reason it can is that there is only ever one of it.

   THE STILL, NOT THE FILM, at rest. These are 4K at about 20 Mbps with no
   smaller renditions, so autoplaying the hero would spend twenty megabits on
   somebody who has not asked for anything yet. It drifts instead, and the film
   starts on the same 450ms rest the tiles use. */
.feat{position:relative;margin-bottom:clamp(24px,4vh,48px)}
/* A CEILING IN VIEWPORT UNITS, on top of the ratio. 21:9 of a 1760px measure
   is 706px, and with the bar and the rail above it that puts the first row of
   tiles at about 880px — the wall's own first line, below the fold on a
   1080-high laptop. The cap brings it to 562px there and 416px on a 1280x800
   screen, and costs nothing: the still is object-fit:cover inside a box with
   overflow hidden, so a capped frame is a wider crop of the same picture,
   which on a cinematic band is not a loss.

   THE RATIO IS A PADDING BOX AND NOTHING ELSE — no `aspect-ratio`, on purpose,
   and this is the second time this property has caught us. A box with
   `aspect-ratio` and a `max-height` honours the RATIO rather than the width:
   the height is capped and the WIDTH is then derived back from it, so the
   frame came out 561 x 1310 inside a 1648px measure and left 338px of black
   down its right-hand side. A percentage padding is always a percentage of
   the WIDTH, so the box fills the measure whatever the cap does to its height,
   and `overflow:hidden` crops the picture instead of narrowing the frame.
   It is also what Chrome 79 was going to use anyway. */
.feat__frame{position:relative;display:block;width:100%;overflow:hidden;
  /* THE PLAIN CEILING FIRST. Without it a browser with no svh drops the whole
     declaration and the hero falls back to 42,857% of the measure — 754px on
     the television's 1760px wall. */
  max-height:620px;
  max-height:min(52svh,620px);
  border:1px solid var(--rule);border-radius:2px;background:#050505}
.feat__frame::before{content:"";display:block;padding-top:42.857%}
/* object-position 35% from the top, not the middle. A capped 21:9 crop of a
   16:9 frame throws away a quarter of its height, and taking it evenly off top
   and bottom cuts faces at the forehead — the subject of a film still is
   almost always in the upper half. */
.feat__img{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;
  object-fit:cover;object-position:center 35%;display:block;
  filter:grayscale(1) contrast(1.06) brightness(.72);
  transform:scale(1.06);
  transition:filter .8s ease;
  animation:featDrift 38s ease-in-out infinite alternate}
@keyframes featDrift{
  from{transform:scale(1.06) translate3d(-1.2%,-0.8%,0)}
  to{transform:scale(1.11) translate3d(1.2%,0.8%,0)}
}
.feat:hover .feat__img,.feat.is-live .feat__img{filter:grayscale(0) contrast(1) brightness(.9)}
.feat__vid{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;
  object-fit:cover;object-position:center 35%;display:block;
  opacity:0;transition:opacity .6s ease}
.feat__vid.on{opacity:1}
/* Directional, and only as dark as the type needs: this must still read as a
   picture, so it releases hard past the measure of the title. */
.feat__wash{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;pointer-events:none;
  background:linear-gradient(94deg,rgba(0,0,0,.74) 0%,rgba(0,0,0,.42) 40%,
                             rgba(0,0,0,.04) 70%,rgba(0,0,0,.18) 100%),
             linear-gradient(rgba(0,0,0,0) 48%,rgba(0,0,0,.6) 100%)}
.feat__dark{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  background:#070707}
.feat__dark > * + *{margin-top:11px}
.feat__say{position:absolute;z-index:3;
  left:clamp(16px,3.4vw,54px);right:clamp(16px,3.4vw,54px);
  bottom:clamp(16px,3.4vh,46px);max-width:44ch}
.feat__k{margin:0;font-size:9.5px;font-weight:500;letter-spacing:.26em;
  text-transform:uppercase;color:var(--dim)}
.feat__t{margin:10px 0 0;font-family:var(--serif);font-weight:300;
  font-size:clamp(26px,4.2vw,54px);line-height:1.02;letter-spacing:-.025em;color:var(--ink)}
.feat__d{margin:11px 0 0;font-family:var(--serif);font-style:italic;font-weight:300;
  font-size:clamp(14px,1.5vw,18px);line-height:1.4;color:var(--dim)}
.feat__m{display:flex;flex-wrap:wrap;align-items:center;margin-top:clamp(14px,2vh,20px)}
.feat__m > * + *{margin-left:12px}

/* OVERLAID TYPE ON A PHONE leaves the title two words to a line over the
   busiest part of the picture. The words come out from under the frame
   instead, and the frame goes back to 16:9 so it is not a letterbox slot. */
@media (max-width:720px){
  .feat__frame::before{padding-top:56.25%}
  .feat__wash{background:linear-gradient(rgba(0,0,0,0) 40%,rgba(0,0,0,.5) 100%)}
  .feat__say{position:static;max-width:none;margin-top:14px}
  /* TRACKING OPENS AS SIZE FALLS. -.025em is drawn for 54px; on a 300-weight
     serif the same negative ratio closes the counters at 30, and at 390px
     wide that was eleven characters to a line over three lines. */
  .feat__t{font-size:clamp(26px,7.2vw,34px);letter-spacing:-.018em;line-height:1.06}
  /* --faint is 3,74:1 — it clears the 3:1 LARGE-text floor, and at 19px on a
     desktop this italic lede is large text. At 15px on a phone it is not, so
     here it has to be --dim (6,88:1). */
  .lede{color:var(--dim)}
}

/* ---- a collection ----------------------------------------------------------
   Only in the owner's running order, and only when a collection has actually
   been named. Name, rule and count: enough to be a landmark, not enough to be
   a heading competing with twenty-six titles. */
.sec{padding-top:clamp(22px,3.4vh,42px)}
.sec:first-child{padding-top:0}
.sec__h{display:flex;align-items:center;margin-bottom:12px}
.sec__h > * + *{margin-left:14px}
/* A collection name is the owner's text and can be any length. nowrap keeps it
   on the heading's one line; min-width:0 with the ellipsis is what stops a long
   one from pushing the whole page sideways on a 390px phone, since a nowrap
   flex item's default min-width is its own content. */
.sec__n{margin:0;font-size:9.5px;font-weight:500;letter-spacing:.26em;
  text-transform:uppercase;color:var(--dim);white-space:nowrap;
  min-width:0;overflow:hidden;text-overflow:ellipsis}
.sec__r{flex:1 1 auto;height:1px;background:var(--rule)}
.sec__c{font-size:9.5px;color:var(--dim);font-variant-numeric:tabular-nums;flex:0 0 auto}

/* ---- the wall --------------------------------------------------------------
   min(215px,100%) rather than a bare 215px: auto-fill cannot make a track
   narrower than its minimum, so on a window under about 250px the grid would
   be wider than the page and the whole document would scroll sideways. With
   the min() the single column simply fills whatever room there is, which is
   also exactly what is wanted on a 390px phone. */
.wall{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(215px,100%),1fr));
  gap:clamp(20px,2.6vw,34px) clamp(14px,1.8vw,24px)}

/* TWO ACROSS ON A PHONE. One column of twenty-nine tiles is about 8.400px of
   scroll for a page whose name is "the wall". Explicit columns rather than a
   lower minmax, for the same reason .railwrap is a grid: deterministic beats
   whatever the tracks happen to add up to. Above 483px auto-fill already
   resolves to two, so this changes nothing in 483-520 — it fixes 320-483. */
@media (max-width:520px){
  .wall{grid-template-columns:repeat(2,minmax(0,1fr))}
  /* The tile caption's phone size is NOT here. A media query adds no
     specificity, and .tile__t's own rule is further down this file — written
     here it lost to it and measured 16,5px on a 390px phone. It is in its own
     block directly after that rule instead. */
}

.tile__a{display:block;width:100%;text-align:left;text-decoration:none;color:inherit}
/* .is-on IS NOT DECORATION, it is the television's focus ring. :focus-visible
   does not exist before Chrome 86 and the wall TV runs Chrome 79, where a
   selector containing it is thrown away whole — so a remote would walk an
   unmarked grid with nothing at all to say where it was. The class is set by
   the page in focusTile() and in the focus handler, and every rule below that
   answers focus answers it too. */
/* THE RING NEEDS A COMPANION OVER A PICTURE. Gold is 8,72:1 on black, but
   these rings sit over a STILL, and gold on a blown-out frame can fall under
   3:1. The dark halo costs nothing on black and saves the ring on white.
   Two rules, never one list — Chrome 79 drops a list containing
   :focus-visible, which would take the .is-on fallback down with it. */
.tile__a:focus-visible{outline:2px solid var(--gold);outline-offset:3px;
  box-shadow:0 0 0 4px rgba(0,0,0,.65)}
.tile__a.is-on{outline:2px solid var(--gold);outline-offset:3px;
  box-shadow:0 0 0 4px rgba(0,0,0,.65)}

/* The still carries everything: the ratio, the hairline, the clipping. The
   image is never given a size of its own, so a frame of any dimension fills the
   box without distortion.

   THE RATIO IS A PADDING BOX FIRST. aspect-ratio arrived in Chrome 88 and the
   wall TV is Chrome 79, where the box would have no height at all and the whole
   grid would collapse into a column of captions. The old trick holds it up
   everywhere; @supports hands the modern property to browsers that have it. */
.tile__still{display:block;position:relative;overflow:hidden;
  border:1px solid var(--rule);border-radius:2px;background:#050505;
  transition:border-color .3s}
.tile__still::before{content:"";display:block;padding-top:56.25%}
@supports (aspect-ratio:16/9){
  .tile__still{aspect-ratio:16/9}
  .tile__still::before{display:none}
}
.tile__a:hover .tile__still{border-color:var(--rule2)}
/* Longhand rather than inset, for the same Chrome 79 reason. */
.tile__img{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;
  object-fit:cover;display:block;
  filter:grayscale(1) contrast(1.06) brightness(.78);
  transition:filter .45s ease,transform .45s var(--ease);transform:scale(1.005)}
/* EVERY PAYOFF RULE IS WRITTEN TWICE, and it is not duplication for its own
   sake. A selector LIST is dropped whole when one selector in it cannot be
   parsed, and Chrome 79 cannot parse :focus-visible — so putting .is-on in the
   same list as the fallback it is meant to BE takes the fallback down with the
   thing it was covering for. The pair is: pointer and modern focus in one
   rule, the page's own class in its own. */
.tile__a:hover .tile__img,.tile__a:focus-visible .tile__img{
  filter:grayscale(0) contrast(1) brightness(1);transform:scale(1.03)}
.tile__a.is-on .tile__img{
  filter:grayscale(0) contrast(1) brightness(1);transform:scale(1.03)}

/* The preview, over the still inside the same box. It fades in only once it is
   genuinely playing, so a slow connection shows the still rather than black. */
.tile__vid{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;
  object-fit:cover;display:block;opacity:0;transition:opacity .45s ease}
.tile__vid.on{opacity:1}

/* THE ONE GOLD MARK ON A TILE. It sweeps rather than appears, which is the same
   gesture the old list's underline made — the only piece of that page's
   choreography the wall keeps.

   z-index because the preview is APPENDED AFTER these two, and among
   positioned siblings with no z-index the last one in the markup wins. Without
   it the film would paint straight over its own gold edge the moment it faded
   in — and the edge is the thing saying the tile answered you. */
.tile__edge{position:absolute;left:0;right:0;bottom:0;height:1px;z-index:2;
  background:var(--gold);
  transform:scaleX(0);transform-origin:left;transition:transform .5s var(--ease)}
.tile__a:hover .tile__edge,.tile__a:focus-visible .tile__edge{transform:scaleX(1)}
.tile__a.is-on .tile__edge{transform:scaleX(1)}

/* Fills while a preview loads, so resting on a tile says something is happening
   rather than nothing for half a second. Under the gold edge, deliberately: one
   is progress, the other is the answer. */
.tile__wait{position:absolute;left:0;bottom:0;height:1px;width:0;z-index:2;
  background:rgba(244,243,241,.5);transition:width .45s linear}
.tile__a.loading .tile__wait{width:100%}

/* NEW SINCE YOUR LAST VISIT. The top-left corner of the still, which is the
   one corner of a tile that was carrying nothing: the gold hairline sweeps
   along the BOTTOM edge, the loading bar is under it, the rating badge and the
   padlock-beside-it are in the caption row below the picture, and the large
   padlock is centred inside the dark still. Nothing to collide with, and
   nothing in the tile's layout moves — it is positioned inside a box whose
   height is already fixed by the 16:9 ratio.

   z-index 3 because it is appended LAST and must beat both the gold edge and
   the loading bar (2) as well as the dark still and the preview, which are
   positioned siblings with no z-index of their own.

   THE WORDS ARE IN THE LINK'S aria-label, not here. A link with an aria-label
   has none of its contents read out, so this copy is aria-hidden and
   markNewOn() in films.js adds "new since your last visit" to the label.

   Gold, which is spent once per thing on this page — and this is a new thing.
   Over a .82 plate it measures 5,5:1 on a blown-out white frame and 8,5:1 on a
   dark one. */
.nu{position:absolute;top:0;left:0;z-index:3;
  padding:4px 7px 5px 8px;
  background:rgba(0,0,0,.82);
  border-right:1px solid var(--rule);border-bottom:1px solid var(--rule);
  border-bottom-right-radius:2px;
  font-size:9px;font-weight:500;letter-spacing:.2em;
  text-transform:uppercase;color:var(--gold);
  font-variant-numeric:tabular-nums}
@supports ((-webkit-backdrop-filter:blur(4px)) or (backdrop-filter:blur(4px))){
  .nu{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}
}

/* A TILE WITH NO PICTURE, and there are three honest reasons for one: the film
   is 18+ and this browser was sent no poster, it is 16+ and nobody has said
   they are old enough yet, or it simply has no frame on file. Each says which,
   and none of them is a broken image. */
/* MARGIN, NOT GAP. Flexbox gap is Chrome 84 and the wall TV is Chrome 79,
   where every flex gap on this page silently becomes zero — the padlock would
   sit on top of "18+". Grid gap is Chrome 66 and is left alone. */
.tile__dark{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;
  flex-direction:column;align-items:center;justify-content:center;
  background:#070707}
.tile__dark > * + *{margin-top:9px}
/* text-indent cancels the trailing letter-space. Tracking adds a gap AFTER the
   last character as well as between them, so a centred word sits half a
   letter-space to the left of where it looks like it should. */
.tile__18{font-size:11px;font-weight:500;letter-spacing:.26em;text-indent:.26em;
  color:var(--dim);font-variant-numeric:tabular-nums}
.tile__none{font-size:9.5px;font-weight:500;letter-spacing:.22em;text-indent:.22em;
  text-transform:uppercase;color:var(--dim)}

.tile__t{display:block;font-family:var(--serif);font-weight:300;font-size:16.5px;
  line-height:1.18;letter-spacing:-.01em;color:var(--dim);margin-top:11px;
  overflow-wrap:break-word;transition:color .3s}
.tile__a:hover .tile__t,.tile__a:focus-visible .tile__t{color:var(--ink)}
.tile__a.is-on .tile__t{color:var(--ink)}
/* AT TWO ACROSS ON A PHONE the measure is 172px at 390. 16,5px Fraunces is
   about sixteen characters a line there; 15px keeps a two-word title on one
   line more often and the rows stay closer to level. It has to sit AFTER the
   rule above: a media query adds no specificity, so the same selector later
   in the file wins wherever it is written. */
@media (max-width:520px){
  .tile__t{font-size:15px;line-height:1.2;margin-top:9px}
}
.tile__m{display:flex;align-items:baseline;margin-top:7px}
.tile__m > * + *{margin-left:9px}
.tile__no{font-size:9.5px;letter-spacing:.2em;color:var(--dim);
  font-variant-numeric:tabular-nums;transition:color .35s}
.tile__a:hover .tile__no,.tile__a:focus-visible .tile__no{color:var(--gold)}
.tile__a.is-on .tile__no{color:var(--gold)}
/* A locked tile's gold is already spent on the padlock, and a second mark would
   promise something the press does not deliver. */
.tile__a.is-locked:hover .tile__no,.tile__a.is-locked:focus-visible .tile__no{color:var(--dim)}
.tile__a.is-locked.is-on .tile__no{color:var(--dim)}
.tile__sp{flex:1 1 auto}

/* ---- a film that has not arrived yet ---------------------------------------
   A DASHED FRAME, in the film's own place in the running order. Not a link and
   not focusable: there is nothing behind it to press, and a tile that takes
   the keyboard and then does nothing is worse than one that never takes it.
   The dashes are the whole signal — everything else about the tile is the same
   shape as its neighbours, because it IS one of them, a week early. */
.soon{display:block;width:100%;text-align:left}
.soon .tile__still{border-style:dashed;border-color:rgba(244,243,241,.2)}
.soon__k{font-size:9.5px;font-weight:500;letter-spacing:.24em;text-transform:uppercase;
  color:var(--dim)}
.soon__d{font-size:12.5px;color:var(--ink);font-variant-numeric:tabular-nums}
/* The only moving gold on the wall, and it has earned it: a number that is
   visibly running down is the difference between an announcement and a date. */
.soon__c{font-size:15px;color:var(--gold);font-variant-numeric:tabular-nums;
  letter-spacing:.06em}
.soon .tile__t{color:var(--dim)}
.soon .tile__no,.soon .len{color:var(--faint)}

/* A portal-gated film wears a dot where its number would be. Not a padlock: a
   padlock says "you cannot", and by the time these are visible you can. */
.tile__a.gated .tile__no{font-size:0}
.tile__a.gated .tile__no::before{content:"";display:block;width:5px;height:5px;
  border-radius:50%;background:var(--gold);opacity:.85}

/* ---- the rating badge and the running time --------------------------------
   --dim at rest rather than --faint. At ten pixels this is the smallest type on
   the page and it is the one label somebody may need before they press
   anything; --faint is about 3,7:1 on black, which is a size and a contrast
   that agree with each other in the wrong direction. Restraint here is the
   hairline box and the tracking, not the grey. */
.badge{font-size:9px;font-weight:500;letter-spacing:.1em;padding:2px 5px;
  display:inline-flex;align-items:center;white-space:nowrap;
  border:1px solid var(--rule);border-radius:2px;color:var(--dim);
  font-variant-numeric:tabular-nums;transition:color .3s,border-color .3s}
.badge .lock{margin-right:5px}
.tile__a:hover .badge,.tile__a:focus-visible .badge{color:var(--ink);border-color:var(--rule2)}
.tile__a.is-on .badge{color:var(--ink);border-color:var(--rule2)}
.len{font-size:12px;color:var(--dim);font-variant-numeric:tabular-nums}
/* The padlock, at two sizes: beside the rating on the tile's own line, and
   large in the middle of the dark still. Gold in both — it is the mark for a
   film that will not open when pressed. */
.lock{display:inline-flex;color:var(--gold);flex:0 0 auto}
.lock--lg{color:var(--gold);opacity:.92}

.note{margin:0 0 18px;font-size:13px;line-height:1.6;color:var(--gold)}

.none{margin:22px 0 0;font-family:var(--serif);font-style:italic;font-weight:300;
      font-size:clamp(16px,1.8vw,20px);color:var(--faint)}

/* ---- the gate ------------------------------------------------------------- */
/* One quiet line. It does not advertise and it does not hide: someone who is
   meant to know already knows, and everyone else reads a sentence and moves on. */
.gate{margin:clamp(20px,3.5vh,44px) 0 0;padding-top:clamp(14px,2vh,22px);
      border-top:1px solid var(--rule)}
.gate__say{margin:0;font-family:var(--serif);font-style:italic;font-weight:300;
           font-size:clamp(14px,1.4vw,17px);color:var(--faint);
           text-shadow:0 1px 10px rgba(0,0,0,.95)}
.gate__link{color:var(--dim);text-decoration:underline;text-underline-offset:.2em;
            text-decoration-thickness:1px;transition:color .25s}
.gate__link:hover{color:var(--gold)}
.gate__link:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

/* ---- the cinema ----------------------------------------------------------- */
/* Longhand offsets, not the `inset` shorthand: that is Chrome 87 and the wall
   TV is Chrome 79, where a fixed element with no offsets at all sits at its
   static position and the player stops being an overlay. The grid `gap` below
   is fine — grid gap is Chrome 66; it is FLEX gap that is Chrome 84. */
/* ONE COLUMN, EXPLICITLY minmax(0,1fr), and this is a measured bug fix rather
   than tidying. The implicit column is `auto`, which is max-content sized —
   and in the portrait block below the <video> is laid out STATICALLY with
   aspect-ratio and a max-height, so its preferred width (56svh x 16/9 = 839px
   on a 390x844 phone) grew the column past the window. Measured before the
   fix at 390x844: the stage, the picture, the caption row and the buttons
   were all 492px wide in a 390px window, with the picture 114px off the right
   edge and Close at x 442-504 — entirely off screen, so a film opened on a
   phone held upright could not be closed except with the hardware back
   gesture. max-width:100% could not save it: the percentage resolves against
   the very column the content had already widened. */
.cinema{position:fixed;top:0;right:0;bottom:0;left:0;z-index:60;
        display:grid;grid-template-rows:1fr auto;grid-template-columns:minmax(0,1fr);
        gap:clamp(10px,1.8vh,24px);
        background:rgba(0,0,0,.94);backdrop-filter:blur(18px);
        padding:clamp(16px,3.2vh,44px) clamp(14px,3vw,40px);
        /* position:fixed over the whole viewport is exactly where the insets
           bite. Plain value first, env() after — see .page. */
        padding:calc(clamp(16px,3.2vh,44px) + env(safe-area-inset-top))
                calc(clamp(14px,3vw,40px) + env(safe-area-inset-right))
                calc(clamp(16px,3.2vh,44px) + env(safe-area-inset-bottom))
                calc(clamp(14px,3vw,40px) + env(safe-area-inset-left))}

/* ---- the landscape band ---------------------------------------------------
   DISPLAY:NONE EVERYWHERE ELSE, and it has to be a display rule rather than
   the `hidden` attribute: [hidden] is !important on this page and a media
   query could not take it back. It also keeps the band out of .cinema's grid,
   which has exactly two rows and would otherwise grow a third. Everything
   that paints it is in the short-landscape block near the bottom. */
.cinema__top{display:none}

/* ---- the one transient line -----------------------------------------------
   The swipe hint, and the reason a film cannot go fullscreen. It is pinned to
   the top of the CINEMA rather than to the picture, so it is the same line in
   the same place at every size; the band pushes it down in landscape and
   nowhere else.
   z-index 7, above the band (5) and the control (6): it is the only thing on
   screen that is there to be read, and it is gone in a few seconds.
   Longhand offsets, no `inset`. */
.cinema__hint{position:absolute;top:12px;left:50%;z-index:7;
  transform:translateX(-50%);
  margin:0;max-width:calc(100% - 32px);
  padding:7px 14px;border:1px solid var(--rule);border-radius:2px;
  background:rgba(0,0,0,.72);
  font-size:11px;font-weight:500;letter-spacing:.06em;line-height:1.4;
  color:var(--ink);text-align:center}
@supports ((-webkit-backdrop-filter:blur(6px)) or (backdrop-filter:blur(6px))){
  .cinema__hint{-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
}
.is-tv .cinema__hint{font-size:17px;padding:10px 20px}

/* The film is POSITIONED against this box rather than laid out inside it, and
   that is deliberate. Laid out as an ordinary centred item, the video took its
   width from max-width and its height from the aspect ratio, and max-height:100%
   resolved to nothing at all -- a percentage needs a containing block with a
   definite height, and the 1fr track does not give the stage one. A 3840x2160
   film therefore came out 1395px tall inside a 1031px stage and painted straight
   over its own controls, the title and the description.

   Absolute positioning gives those percentages a definite box to resolve
   against. Four zero offsets with auto margins and auto dimensions then centre
   the film in the stage and, whatever its shape, it cannot escape it: measured
   at 16:9, 9:16, 21:9 and 4:3, the box keeps its exact ratio and stays inside.
   Longhand rather than `inset`, which is Chrome 87 and would leave the film at
   its static position on the wall TV. */
.cinema__stage{position:relative;min-height:0}

/* ---- the ambient glow -------------------------------------------------------
   A 32x18 canvas painted from the playing film about nine times a second, then
   blown up and blurred until it is not a picture any more, only the light the
   picture is throwing. Thirty-two pixels wide is not a compromise: the blur
   would destroy anything finer, and at that size the copy costs nothing.

   It sits BEHIND the film and is inert — no pointer, no tab stop, nothing to
   read. Off under reduced motion, off on the television (see films.js), and
   off in fullscreen, where the film already fills the wall it would be
   lighting. Opacity is the whole of the four-step control. */
/* THE GLOW SHARES THE PICTURE'S BOX, and it has to be JavaScript that says
   where that is. The stage is the whole 1fr track; the film is letterboxed
   inside it, a different shape and often hundreds of pixels narrower. Insetting
   the canvas by a percentage of the STAGE — which is what this did — put most
   of the blur outside the picture, so on a 1920 screen the halo appeared as two
   soft patches below the frame's lower corners instead of around all four
   edges. ambFit() writes left/top/width/height from the video's own rectangle;
   scale(1.08) is what then pushes it past the edges evenly.

   The blur is written by ambFit() too, because it has to scale with the
   picture: 70px around an 880px mock is a halo, and around a 390px phone it is
   fog. */
.amb{position:absolute;top:0;left:0;z-index:0;
  width:0;height:0;pointer-events:none;
  filter:blur(70px) saturate(1.8) brightness(1.5);transform:scale(1.08);
  opacity:0;transition:opacity .6s ease}
/* RAISED AGAINST REAL FOOTAGE. The mock bled seeded gradients, which are far
   brighter than an average frame of a graded film — at .55 the old Medium was
   invisible on a pink-and-gold shot that should have lit the whole page. The
   brightness in the filter above does the rest of the work, and it does it
   MULTIPLICATIVELY, which is exactly the behaviour wanted: a colourful frame
   lifts a long way and a dark one barely moves, so Medium is perceptible on
   one and still quiet on the other. */
.is-amb1 .amb{opacity:.42}
.is-amb2 .amb{opacity:.72}
.is-amb3 .amb{opacity:1}
/* Nothing between the glow and the viewport may clip it. The stage is a grid
   item and grid items do not clip by default, but this says so out loud
   because a later overflow:hidden here would silently cut the halo off at the
   film's own edges and look like the blur had stopped working. */
.cinema__stage{overflow:visible}

/* ---- our own fullscreen -----------------------------------------------------
   THE STAGE GOES FULLSCREEN, not the film. Native video fullscreen paints the
   <video> and nothing else, so a watermark that is a sibling of it disappears
   at exactly the moment a recording is most likely — see fsToggle() in
   films.js, which is what the .pfs button below calls.
   Fullscreening the stage keeps the film, the mark and the glow together.
   Where the stage cannot go fullscreen — iOS, which has element fullscreen
   for a <video> and nothing else — the film goes on its own and the mark
   travels with it as a text-track cue instead; see mark.js.

   Two rules, not a selector list: an unparseable pseudo-class takes the whole
   list with it, and these two spellings are not supported by the same
   browsers. */
.cinema__stage:fullscreen{background:#000;display:flex;align-items:center;justify-content:center}
.cinema__stage:fullscreen video{position:static;margin:auto;width:auto;height:auto;
  max-width:100%;max-height:100%}
.cinema__stage:-webkit-full-screen{background:#000;display:flex;align-items:center;justify-content:center}
.cinema__stage:-webkit-full-screen video{position:static;margin:auto;width:auto;height:auto;
  max-width:100%;max-height:100%}
/* The film sits above its own glow. It also loses its drop shadow: the shadow
   was there to lift the frame off a flat black ground, and the glow does that
   job now with the film's own light. Two of them at once reads as a smudge. */
.cinema__stage video{z-index:1}
.cinema__stage video{position:absolute;top:0;right:0;bottom:0;left:0;
                     margin:auto;width:auto;height:auto;
                     max-width:100%;max-height:100%;
                     /* On a tall screen, stop short of the edges: a film sized
                        to the last pixel reads as a fullscreen that failed
                        rather than as a framed piece. A ceiling only -- where
                        room is short the stage still decides, so this never
                        makes a small window smaller. The plain 100% above is
                        the fallback for anything without svh or min(). */
                     max-height:min(100%,76svh);
                     aspect-ratio:16/9;background:#000;display:block}

/* ---- the one control on the picture ---------------------------------------
   TOP-RIGHT OF THE PICTURE'S RECTANGLE — not the stage's, not the viewport's.
   Bottom-right belongs to the native control bar, whose height differs per
   engine and which this page already concedes it cannot measure (see
   controlsBand() in films.js). Top-right is empty in every engine's own
   controls.

   It is a child of .cinema__stage because the STAGE is what goes fullscreen,
   and only a descendant of the fullscreen element is painted — a control in
   the caption row cannot offer the exit half of its own job.

   UNVERIFIED, needs a device test: some Chrome-on-Android builds have put a
   cast chip at a video's top right. disablePictureInPicture is set and
   controlsList strips download and playback rate, so the overflow menu is
   minimal; if it collides the mitigation is right:64px under
   (hover:none) and (max-width:900px).

   z-index 4: above the glow (0), the film (1) and the mark box (3).
   Longhand offsets, never `inset` — Chrome 87 against the TV's Chrome 79. */
.pfs__box{position:absolute;top:0;left:0;width:0;height:0;
  z-index:4;pointer-events:none}

.pfs{position:absolute;
  top:var(--pfs-inset);right:var(--pfs-inset);
  width:var(--pfs-size);height:var(--pfs-size);
  display:flex;align-items:center;justify-content:center;
  padding:0;border:1px solid var(--pfs-edge);border-radius:2px;
  background:var(--pfs-plate);color:var(--ink);
  cursor:pointer;pointer-events:auto;
  -webkit-appearance:none;appearance:none;
  transition:opacity var(--chrome-in) var(--ease),
             background-color .2s var(--ease),
             border-color .2s var(--ease),
             transform .2s var(--ease)}
/* Enrichment only. The plate carries the measured contrast on its own, so a
   browser without the blur loses nothing it needed. */
@supports ((-webkit-backdrop-filter:blur(6px)) or (backdrop-filter:blur(6px))){
  .pfs{-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
}
.pfs__i{width:var(--pfs-icon);height:var(--pfs-icon);display:block;
  fill:none;stroke:currentColor;stroke-width:1.5;
  stroke-linecap:square;stroke-linejoin:miter;
  /* The second line of defence across a blown-out frame; the plate does the
     measured work. */
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.6))}
.pfs__i--out{display:none}
.pfs[aria-pressed="true"] .pfs__i--in{display:none}
.pfs[aria-pressed="true"] .pfs__i--out{display:block}
/* 36px visual, 44px target. A ::after on the button itself, so it can never
   overlap a sibling — there is none inside .pfs__box. */
.pfs::after{content:"";position:absolute;top:-4px;right:-4px;bottom:-4px;left:-4px}

/* The payoff is written INSIDE a hover query, deliberately. This stylesheet
   currently defines hover unconditionally and then undoes it in seven rules
   under (pointer:coarse); photos.css inherited a bug from one of those undos
   by copying it. The existing ones work and are documented — new code simply
   stops adding to the list. */
@media (hover:hover) and (pointer:fine){
  .pfs:hover{background:var(--pfs-plate-on);border-color:var(--pfs-edge-on)}
}
.pfs:active{transform:scale(.94)}
/* TWO RULES, never one list: Chrome 79 cannot parse :focus-visible and drops
   the whole selector list with it, and the television reaches this button
   with its remote and needs a ring. */
.pfs:focus-visible{outline:2px solid var(--gold);outline-offset:3px;
  box-shadow:0 0 0 4px rgba(0,0,0,.65)}
.pfs:focus{outline:2px solid var(--gold);outline-offset:3px;
  box-shadow:0 0 0 4px rgba(0,0,0,.65)}

/* SAFARI IGNORES controlsList ENTIRELY — it is Chromium-only — so the one
   browser where the film is handed to a system player is also the one that
   keeps its own fullscreen button. This WebKit shadow pseudo-element has
   historically hidden it.
   UNVERIFIED on current Safari, and it needs a device test on the owner's
   iPhone: modern WebKit rebuilt its media-controls shadow tree and this may
   now do nothing. If it does nothing, the duplicate is ACCEPTED on iOS Safari
   alone — two buttons that do the identical thing is a redundancy, not the
   relocation that was the complaint, and the alternative is a full custom
   control bar, which costs the AirPlay route picker. */
video::-webkit-media-controls-fullscreen-button{display:none}

/* ---- the chrome state ----
   ONE class on .cinema governs the control and, in landscape, the band: they
   are one chrome and must never disagree. pointer-events:none while hidden is
   load-bearing — a tap has to land on the film and bring the chrome back, not
   on an invisible button. */
.cinema.is-bare .pfs{opacity:0;pointer-events:none;
  transition:opacity var(--chrome-out) var(--ease)}

/* ---- where this viewer stopped last time -----------------------------------
   THE OFFER TO RESUME, at the left end of the picture's own rectangle. Its own
   box, the same rectangle .pfs__box holds and written by the same pfsFit() from
   one measurement — being inside the stage is what makes it survive fullscreen.

   Z-INDEX 2, AND THAT IS THE WHOLE REASON IT IS NOT A SECOND CHILD OF
   .pfs__box: 2 is above the glow (0) and the film (1) and BELOW the mark's box
   (3), where .pfs__box is 4 and above it. The mark's top-left slot is [6%, 8%]
   — this corner — and measured at 390x844, 844x390 and 1920x1070 the two boxes
   really do meet. The mark is 13% ink and must not be covered by anything, so
   it crosses this plate instead: 13% ink over a .82 plate still reads, and the
   plate's own text stays at 4,9:1 where the ghost passes through it. */
.rsm__box{position:absolute;top:0;left:0;width:0;height:0;
  z-index:2;pointer-events:none}

/* IT IS NOT PART OF THE CHROME, deliberately. The chrome fades after 2.600ms
   and an offer that disappears in two and a half seconds is not an offer — so
   it is left out of .is-bare and keeps a life of its own (RESUME_SHOW_MS in
   films.js). .cinema__hint, the page's other transient line, is exempt for
   the same reason.

   A .cbtn's pill on a plate: the same shape, weight and hover as Previous and
   Next, because it is the same kind of thing — but those sit on a black page
   and this one sits on an unknown frame, so it carries its own ground. --ink
   at rest rather than .cbtn's --dim: over a .82 plate on a blown-out white
   frame --dim measures 4,8:1 and --ink 8,3:1, and this is the one control on
   the picture that has words in it.

   Longhand offsets, no `inset`; no flex `gap`. Chrome 79. */
.rsm{position:absolute;
  top:var(--pfs-inset);left:var(--pfs-inset);
  z-index:5;pointer-events:auto;cursor:pointer;
  /* Never into the fullscreen control's corner, however long the title of the
     time is. 120px clears the largest control (56px) and its largest inset
     (24px) with room to spare. */
  max-width:calc(100% - 120px);
  overflow:hidden;white-space:nowrap;text-overflow:ellipsis;
  margin:0;padding:9px 16px;
  border:1px solid var(--pfs-edge);border-radius:999px;
  background:rgba(0,0,0,.82);
  font:inherit;font-size:12px;font-weight:500;line-height:1;
  color:var(--ink);
  -webkit-appearance:none;appearance:none;
  transition:color .2s var(--ease),background-color .2s var(--ease),
             border-color .2s var(--ease),transform .2s var(--ease)}
/* Enrichment only, exactly as on .pfs: the plate carries the measured contrast
   on its own, so a browser without the blur loses nothing it needed. */
@supports ((-webkit-backdrop-filter:blur(6px)) or (backdrop-filter:blur(6px))){
  .rsm{-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
}
/* 30px visual, 44px target. A ::after on the button itself, so it can never
   overlap a sibling — .pfs is at the far end of the box. */
.rsm::after{content:"";position:absolute;top:-7px;right:-7px;bottom:-7px;left:-7px}
/* Inside a hover query, as every new rule in this file is: the sheet defines
   hover unconditionally in its older rules and then undoes it seven times
   under (pointer:coarse), and new code stops adding to that list. */
@media (hover:hover) and (pointer:fine){
  .rsm:hover{color:var(--gold);border-color:var(--gold);background:rgba(0,0,0,.9)}
}
.rsm:active{transform:scale(.97)}
/* TWO RULES, never one list: Chrome 79 cannot parse :focus-visible and drops
   the whole selector list with it — and the television is the one screen that
   reaches this button by focus alone. */
.rsm:focus-visible{outline:2px solid var(--gold);outline-offset:3px;
  box-shadow:0 0 0 4px rgba(0,0,0,.65)}
.rsm:focus{outline:2px solid var(--gold);outline-offset:3px;
  box-shadow:0 0 0 4px rgba(0,0,0,.65)}

/* ---- the watermark's second carrier ----------------------------------------
   A TEXT-TRACK CUE IS PAINTED BY THE PLAYER, inside the video surface, so it
   survives native video fullscreen — where the DOM overlay, being a sibling
   of the <video>, keeps a layout box and paints nothing. mark.js shows
   exactly one of the two at a time; see its header.

   FONT-SIZE, and why this value. The UA's own default for a cue is 5% of the
   VIDEO's height, which is enormous at fullscreen and clipped the name. A
   percentage here resolves against that default, so 50% is 2,5% of the
   picture's height — on a 16:9 film that is 1,4% of its width, which is
   exactly what mark.js gives the DOM overlay (max(11px, width * 0.014)). It
   is the only unit that tracks the PICTURE at both sizes: 1.6vh reads
   correctly at fullscreen but is a fraction of the VIEWPORT in a windowed
   player, where the picture may be a third of it. The plain 14px first is the
   usual fallback discipline — if a browser will not take the percentage it
   gets a small mark rather than the 5% default. */
video::cue{font-size:14px;font-size:50%;
  color:rgba(244,243,241,.55);background:rgba(0,0,0,0);
  font-family:'Inter Tight',system-ui,sans-serif;
  text-shadow:0 1px 2px rgba(0,0,0,.8)}

/* Margins rather than flex gap, for the television. The vertical half is on
   every child so a wrapped foot keeps its rhythm; the padding-top absorbs the
   5px the first row gains. */
.cinema__foot{display:flex;flex-wrap:wrap;align-items:baseline;
              padding-top:clamp(7px,2vw,17px)}
.cinema__foot > *{margin:5px 0}
.cinema__foot > * + *{margin-left:22px}
/* THE IDENTITY, in one item. It exists so the foot can become a grid above
   860px without the three spans each needing a cell. The geometry below
   reproduces exactly what they had as direct children: the 5px vertical
   margins stay on the SPANS and the wrapper takes none, so the row is not a
   pixel taller than it was. Shorthand first, then the gap — the other way
   round `margin:5px 0` silently zeroes margin-left and the number, the title
   and the running time run into each other. */
.cinema__foot > .cinema__id{margin-top:0;margin-bottom:0}
.cinema__id{display:flex;flex-wrap:wrap;align-items:baseline;min-width:0}
.cinema__id > *{margin:5px 0}
.cinema__id > * + *{margin-left:22px}
/* --dim, not --faint. --faint is 3,74:1 on black, which fails AA for small
   text, and these are 11px and 12px. The file already moves --faint to --dim
   wherever a line has to be read; these two were missed. */
.cinema__no{font-size:11px;letter-spacing:.2em;color:var(--dim)}
.cinema__title{font-family:var(--serif);font-weight:300;font-size:clamp(19px,2.3vw,28px);
               letter-spacing:-.01em;color:var(--ink)}
.cinema__len{font-size:12px;color:var(--dim);font-variant-numeric:tabular-nums}
/* THE RUNG AN ADAPTIVE FILM IS PLAYING AT — one word, "1080p", and only while
   there is one. The same 11px and the same --dim as the number at the head of
   the row, tracked a little tighter so it reads as a measurement rather than
   as a third label; --dim and not --faint for the reason given above. Shown
   and hidden by paintQuality() with the `hidden` attribute, which is
   !important on this page, and left out of the landscape band on purpose. No
   rule under .is-tv: the television is never handed a ladder, so a size for it
   here would be a line nothing can reach. */
.cinema__q{font-size:11px;letter-spacing:.14em;color:var(--dim);
           font-variant-numeric:tabular-nums}
/* flex-basis:100% was meant to put the description on a row of its own, and it
   never did on a wide screen: a flex line is broken on the HYPOTHETICAL main
   size, which is the basis already clamped by max-width. 66ch is about 496px,
   that fits beside the buttons, so the description sat jammed against the right
   edge next to Close instead of below the title. An empty full-width item ends
   the line before it, which keeps both the break and the 66ch measure -- a
   min-width:100% on the paragraph would force the row but throw the measure
   away, and setting it in the grid would cost the foot its wrapping on a phone. */
.cinema__break{flex-basis:100%;height:0;margin:0}
.cinema__desc{flex-basis:100%;margin:0;max-width:66ch;font-size:13px;line-height:1.6;
              color:var(--dim)}
/* The two full-width items opt out of the horizontal rhythm above, which is
   for the things that sit side by side. The vertical 5px they keep: the pair
   of them is what reproduces the row gap the flex `gap` used to draw. */
.cinema__foot > .cinema__break{margin-left:0}
.cinema__foot > .cinema__desc{margin-left:0}
/* Written as a child selector so it OUTWEIGHS the 22px above. `.cinema__acts`
   alone is one class against one class and one child combinator, and it lost —
   which sent Close, Next and Previous back into the middle of the row. */
.cinema__foot > .cinema__acts{margin-left:auto}
.cinema__acts{display:flex}
.cinema__acts > * + *{margin-left:6px}
.cbtn{border:1px solid var(--rule);border-radius:999px;background:none;color:var(--dim);
      font:inherit;font-size:12px;font-weight:500;padding:7px 15px;cursor:pointer;
      transition:color .2s,border-color .2s}
.cbtn:hover:not(:disabled){color:var(--gold);border-color:var(--gold)}
.cbtn:disabled{opacity:.3;cursor:default}
.cbtn:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
/* Two modifiers, for the dialogs below. The filled one is the same ink-on-black
   inversion the Studio's primary button uses, so the two admin-adjacent
   surfaces on this subdomain agree about what "the button you meant" looks
   like. Both keep .cbtn's box, so the 44px touch target applies to them too. */
.cbtn--solid{border-color:var(--ink);background:var(--ink);color:#000}
.cbtn--solid:hover:not(:disabled){background:var(--gold);border-color:var(--gold);color:#000}
/* --dim, not --faint. This is the DISMISS control of a modal — the way out of
   a form somebody may not want to fill in — and --faint measures about 3,7:1
   on black at 12px. Quiet is done by dropping the border, not by going grey
   enough to be hard to find. */
.cbtn--quiet{border-color:transparent;color:var(--dim)}
.cbtn--quiet:hover:not(:disabled){border-color:transparent;color:var(--ink)}

/* ---- the ambient control ---------------------------------------------------
   Four steps in the player's own control row, built like the Studio's
   three-way visibility control: the pressed one is the only one that is
   legible at a glance, because the question is "how much" and not "what are
   the options". */
.ambset{display:inline-flex;align-items:center;border:1px solid var(--rule);
  border-radius:999px;overflow:hidden}
.ambset__k{padding:0 10px;font-size:10px;font-weight:500;letter-spacing:.16em;
  text-transform:uppercase;color:var(--faint);white-space:nowrap}
.ambb{border:0;padding:7px 11px;background:none;color:var(--faint);font:inherit;
  font-size:11px;font-weight:500;letter-spacing:.06em;cursor:pointer;
  transition:color .2s,background-color .2s}
.ambb:hover{color:var(--ink)}
.ambb[aria-pressed="true"]{background:rgba(244,243,241,.1);color:var(--ink)}
.ambb:focus-visible{outline:2px solid var(--gold);outline-offset:-2px}

/* ---- the queue --------------------------------------------------------------
   Only ever on screen during Play all. A hairline of real progress, then the
   three films after this one — and the ones that are NOT in the queue, named
   and struck through. A queue that quietly skips ten films is a queue that
   looks broken; one that says which ten and why is a queue with an invitation
   in it. */
.prog{position:relative;height:1px;background:var(--rule);margin:2px 0 16px;overflow:hidden}
.prog__i{position:absolute;top:0;left:0;bottom:0;width:0;background:var(--gold)}
.queue{margin-top:clamp(16px,2.4vh,26px);border-top:1px solid var(--rule);padding-top:14px}
.queue__k{margin:0 0 10px;font-size:9.5px;font-weight:500;letter-spacing:.24em;
  text-transform:uppercase;color:var(--dim)}
.queue__l{margin:0;padding:0;list-style:none}
.queue__l li{display:flex;align-items:baseline;padding:7px 0;
  border-bottom:1px solid var(--rule);font-size:13px;color:var(--dim)}
.queue__l li > * + *{margin-left:12px}
.queue__no{font-size:9.5px;letter-spacing:.2em;color:var(--dim);
  font-variant-numeric:tabular-nums}
.queue__t{font-family:var(--serif);font-weight:300;font-size:16px;color:var(--ink);
  min-width:0;overflow-wrap:break-word}
.queue__sp{flex:1 1 auto}
.queue__l li.is-skip .queue__t{color:var(--dim);text-decoration:line-through;
  text-decoration-color:rgba(244,243,241,.3)}
.queue__why{font-size:11px;letter-spacing:.06em;color:var(--dim);white-space:nowrap}
.queue__note{margin:12px 0 0;font-family:var(--serif);font-style:italic;font-weight:300;
  font-size:14px;color:var(--dim)}

/* ---- the two age dialogs ---------------------------------------------------
   Same construction as the cinema: a fixed overlay div toggled with `hidden`,
   the element itself as the backdrop and the box as its child.

   z-index 70, ABOVE the cinema's 60, because a pass that runs out mid-film has
   to be able to raise the form over a player that is already on screen. In
   practice the film is put away first — two things that both answer Escape
   must never be on screen together — but the stacking has to be right for the
   frame in between.

   flex with margin:auto rather than place-items:center. A grid-centred box
   taller than the window is cut off at the TOP, where the heading is, and this
   one is four fields tall on a phone in landscape. */
.veil{position:fixed;top:0;right:0;bottom:0;left:0;z-index:70;
      display:flex;align-items:center;
      justify-content:center;padding:20px;overflow-y:auto;overscroll-behavior:contain;
      /* The plain 20px above is the fallback; see .page. */
      padding:calc(20px + env(safe-area-inset-top)) calc(20px + env(safe-area-inset-right))
              calc(20px + env(safe-area-inset-bottom)) calc(20px + env(safe-area-inset-left));
      background:rgba(0,0,0,.92);backdrop-filter:blur(14px);
      animation:veilIn .2s ease-out}
@keyframes veilIn{from{opacity:0}to{opacity:1}}

.veil__box{width:min(420px,100%);margin:auto;padding:clamp(22px,3vw,30px);
           border:1px solid var(--rule);border-left:2px solid var(--gold);
           background:#0a0a0a;text-align:left}
.veil__box--tight{width:min(380px,100%)}
.veil__title{margin:0 0 10px;font-family:var(--serif);font-weight:300;
             font-size:clamp(22px,2.6vw,29px);letter-spacing:-.015em;color:var(--ink)}
.veil__say{margin:0 0 20px;font-size:13px;line-height:1.6;color:var(--dim)}
.veil__box--tight .veil__say{margin-bottom:24px}
/* Gold, like every other message on this subdomain that is trying to tell you
   something went wrong. Red would be a fourth colour on a page with three. */
.veil__bad{margin:0 0 16px;font-size:13px;line-height:1.55;color:var(--gold)}

.veil__field{margin:0 0 14px}
.veil__label{display:block;margin:0 0 5px;font-size:11px;font-weight:500;
             letter-spacing:.2em;text-transform:uppercase;color:var(--dim)}
.veil__in{width:100%;padding:9px 12px;border:1px solid var(--rule2);border-radius:2px;
          background:#000;color:var(--ink);font:inherit;font-size:14px}
.veil__in:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
.veil__in[aria-invalid="true"]{border-color:var(--gold)}
.veil__err{margin:5px 0 0;font-size:12px;line-height:1.5;color:var(--gold)}

.veil__tick{display:flex;align-items:flex-start;margin:18px 0 22px;
            font-size:12px;line-height:1.55;color:var(--dim);cursor:pointer}
/* margin-right rather than the container's gap: flex gap is Chrome 84 and the
   television would have put the tick box hard against the sentence. */
.veil__tick input{flex:none;width:16px;height:16px;margin:1px 10px 0 0;accent-color:var(--gold)}
.veil__tick input:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
/* The server's own sentence, of unknown length and possibly carrying a long
   unbroken address in it. */
.veil__consent{min-width:0;overflow-wrap:anywhere}

.veil__read{margin:-12px 0 20px}
.veil__acts{display:flex;flex-wrap:wrap;align-items:center;margin-bottom:-10px}
.veil__acts > *{margin:0 10px 10px 0}

/* Chrome's autofill paints its own near-white background over a dark field.
   The inset shadow is the only way to override it and -webkit-text-fill-color
   the only way to set the text colour — the same two rules the Studio carries,
   for the same reason. This page never had a form long enough to need them. */
.veil__in:-webkit-autofill,
.veil__in:-webkit-autofill:focus{
  -webkit-box-shadow:0 0 0 40px #000 inset;
  -webkit-text-fill-color:var(--ink)}

.sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
    clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---- the device classes -----------------------------------------------------
   One layout, bent where a device actually differs. Nothing below is keyed to
   a device NAME: the questions are can the pointer hover, is the screen narrow
   and upright, how short is it, and is the type being read from across a room.

   THE WHOLE REGISTER, because a breakpoint cannot be a custom property — a
   media-query condition will not take one and there is no preprocessor — so
   the only way to keep the numbers honest is to list them in one place:

     (max-width:520px)                                phone portrait: wall 2-up,
                                                      phone type scale
     (max-width:720px)                                narrow hero
     (max-width:720px) and (orientation:portrait)     the player: picture at the
                                                      top, words under it
     (max-height:560px) and (orientation:landscape)   NEW. a phone held sideways
                                                      and any short window: the
                                                      picture takes the window
     (min-width:860px)                                the rail splits; the
                                                      caption becomes a grid
     (min-width:1900px)                               --wide:2040px
     (pointer:coarse)                                 targets, hover undo, type
                                                      floor, 16px inputs
     (hover:hover) and (pointer:fine)                 NEW, for new rules only:
                                                      hover payoffs
     (hover:none)                                     the press payoff
     (prefers-reduced-motion:reduce)                  motion off
     .is-tv                                           from the UA. SIZE ONLY.

   WHAT IS KEYED TO WHAT. Capability — (pointer:coarse) / (hover:none) —
   whenever the question is about INPUT: target sizes, sticky hover payoffs,
   the 16px input floor (an iPad at 1024px wide is still iOS Safari and still
   zooms), whether long-press is a gesture. Width and height whenever the
   question is about ROOM: column counts, type scale, whether the caption sits
   under the picture or over it. The user agent for nothing but .is-tv, and
   there for nothing but size.
   -------------------------------------------------------------------------- */

/* ---- a touch screen ------------------------------------------------------ */
@media (pointer:coarse){
  /* 32px high is a mouse target. A finger needs 44, which is the figure both
     Apple and Google publish and the one three pills sitting side by side in a
     row were failing on a phone. The rail's controls are smaller because they
     sit on their own line with nothing above or below to mis-hit. */
  .cbtn{padding:12px 18px;font-size:13px;min-height:44px}
  .chip,.tbtn{min-height:34px}
  .chip{padding-top:0;padding-bottom:0;align-items:center}
  /* HOVER STYLING STICKS AFTER A TAP on a touch screen, leaving a tile looking
     chosen long after the finger has gone. On the wall this matters more than
     it did on the list: a tile keeps its still in full colour and its gold
     edge drawn, which reads as "this one is playing". */
  .tile__a:hover .tile__img{filter:grayscale(1) contrast(1.06) brightness(.78);transform:scale(1.005)}
  .tile__a:hover .tile__edge{transform:scaleX(0)}
  .tile__a:hover .tile__no{color:var(--dim)}
  .tile__a:hover .tile__t{color:var(--dim)}
  .tile__a:hover .badge{color:var(--dim);border-color:var(--rule)}
  /* ...but focus is set by a key or by the page, never by a finger, so the
     focus half of each pair above survives untouched. */

  /* THE 16px INPUT FLOOR. iOS Safari zooms the page whenever a focused input's
     computed size is under 16px, and it does not zoom back out — so
     registering for an 18+ film zoomed the page three times and left it
     zoomed over a modal. Keyed to the pointer and not to a width, because an
     iPad at 1024px wide is still iOS Safari. */
  .veil__in,.find{font-size:16px}
  .veil__in{padding:11px 12px}
  .find{padding:9px 14px}

  /* A BIGGER TARGET, NOT A BIGGER CHIP. 34px visual plus 5px top and bottom
     is 44px of target with no pixel of the design moved. The rail's own
     separation goes 6px -> 10px first, so two neighbouring extenders can
     never overlap. */
  .rail > * + *{margin-left:10px}
  .chip,.tbtn{position:relative}
  .chip::after,.tbtn::after{content:"";position:absolute;
    top:-5px;right:0;bottom:-5px;left:0}
  .playbox > * + *,.sortbox > * + *{margin-left:14px}

  /* A TYPE FLOOR, keyed to coarse rather than to width: the reason is
     sub-pixel rendering plus the finger, and a 390px desktop window needs
     neither. 9px and 9,5px Inter Tight uppercase at .1-.26em tracking,
     antialiased and unhinted, is legible-but-fuzzy on a phone. 11px for
     anything read BEFORE pressing (the rating), 10px for counters. */
  .badge{font-size:11px;padding:3px 6px}
  .chip{font-size:11px}
  .chip__n{font-size:10px}
  .tbtn{font-size:11px}
  .rail__k,.sec__n,.soon__k{font-size:10px}
  .tile__no{font-size:10px}
  .cinema__no{font-size:11px}
  /* The state line is read before anything is pressed and it carries the one
     control that undoes a narrowing, so it takes the 11px floor and a point
     over it — it is a sentence rather than a counter. .state__clear is a .tbtn
     and already has both the 34px height and the ±5px extender above. */
  .state{font-size:12px}

  /* The control grows for a finger and keeps its corner. */
  .pfs{top:var(--pfs-inset-touch);right:var(--pfs-inset-touch);
    width:var(--pfs-size-touch);height:var(--pfs-size-touch)}
  .pfs__i{width:var(--pfs-icon-touch);height:var(--pfs-icon-touch)}
  /* 48px is already past the 44px floor, and the extender would only overhang
     the picture's own edge. */
  .pfs::after{display:none}

  /* The resume offer keeps the control's corner inset and takes the 11px
     floor. 11px type and 11px of padding is 35px of visual box, and the ±7px
     extender above takes the target to 49px. */
  .rsm{top:var(--pfs-inset-touch);left:var(--pfs-inset-touch);
    font-size:11px;padding:11px 16px}

  /* At two tiles across on a phone the still is about 172px wide; 9px with
     .2em of tracking is legible there but is the smallest thing on the tile,
     and this is the one label that is the whole reason the tile looks
     different from its neighbours. */
  .nu{font-size:10px;padding:5px 8px 6px 9px}
}

/* ---- a finger, where a pointer would have hovered -------------------------
   NOTHING PREVIEWS ON TOUCH, and that is the decision rather than an
   omission: the preview streams the film itself, the masters run about
   20 Mbit/s at 4K with no smaller renditions, and autoplaying that on a phone
   on cellular is the single most expensive thing this site could do —
   films.js refuses it for exactly that reason. But a finger got NO answer at
   all until the film opened, so the hover payoff arrives on the press
   instead: the same two gestures, colour returning and the gold hairline
   drawing, on :active rather than on approach. */
@media (hover:none){
  .tile__a:active .tile__img{
    filter:grayscale(0) contrast(1) brightness(1);transform:scale(1.015);
    transition:filter 160ms var(--ease),transform 160ms var(--ease)}
  .tile__a:active .tile__edge{transform:scaleX(1);
    transition:transform 180ms var(--ease)}
  .tile__a:active .tile__t{color:var(--ink)}
  /* A locked tile's gold is already spent on the padlock. */
  .tile__a.is-locked:active .tile__edge{transform:scaleX(0)}

  /* A long press on a tile offers "Download linked file" / "Save image" on
     both iOS and Android. Friction rather than protection — mark.js says the
     same about itself — but it is the one place the site invites a gesture
     and then looks careless. */
  .tile__a,.tile__img,.feat__img{
    -webkit-touch-callout:none;-webkit-user-select:none;user-select:none}
}

/* ---- a phone held upright ------------------------------------------------ */
/* A 16:9 film in a portrait window is limited by WIDTH, so it can never be more
   than a fifth of the height -- and centred in a full-height stage it sat as a
   stamp in a sea of black with the caption pinned to the bottom of the screen,
   half a thousand pixels away from the film it describes. Every phone video
   page in the world puts the film at the top and the words directly under it,
   for this exact reason. */
@media (max-width:720px) and (orientation:portrait){
  .cinema{grid-template-rows:auto auto;align-content:start;
          padding:clamp(12px,2vh,20px) clamp(12px,3vw,20px)}
  /* Back into the flow. The absolute positioning upstairs exists to solve a
     percentage that cannot resolve against a 1fr track; here the film is capped
     in svh, which is a real length and needs no containing block to resolve
     against, so the simpler layout is also the correct one.
     POSITION:RELATIVE, NOT STATIC. The watermark box and the ambient canvas
     are absolutely positioned children measured against this element — with
     `static` their containing block became `.cinema` instead, and the mark
     landed a dozen or so pixels out, with the top-row slots straddling the
     edge of the picture. It costs nothing: a relatively positioned box with no
     offsets sits exactly where a static one does. */
  .cinema__stage{position:relative}
  /* THE PLAIN vh FIRST. Without it a browser with no svh drops the whole
     declaration and the film gets no ceiling at all. photos.css already
     writes the pair correctly; this block did not. */
  .cinema__stage video{position:static;margin:0 auto;display:block;
                       width:auto;height:auto;max-width:100%;
                       max-height:56vh;max-height:56svh}
  /* THE SHORTHAND FIRST, THEN THE GAP — and the order is the whole rule.
     These two selectors have the same specificity, so the later one wins;
     with them the other way round `margin:4px 0` set margin-left back to 0
     and the counter, the title and the running time ran into each other on
     a phone. Measured at 390x844: 0px between them. The base rules above
     (lines ~526) have always had this order; only the portrait block had it
     reversed. Found while building the photographs wall, which copied the
     block and inherited the bug. */
  .cinema__foot > *{margin:4px 0}
  .cinema__foot > * + *{margin-left:14px}
  /* The identity row keeps the same rhythm now that it is one item. Shorthand
     first, then the gap — the rule above explains why the order is the whole
     thing. */
  .cinema__foot > .cinema__id{margin-top:0;margin-bottom:0}
  .cinema__id > *{margin:4px 0}
  .cinema__id > * + *{margin-left:14px}
  .cinema__foot > .cinema__acts{margin-left:0;width:100%}
  .cbtn{flex:1 1 auto;text-align:center}
  /* CLOSE TAKES ITS NATURAL WIDTH, at the far right with clear space before
     it. flex:1 1 auto next to Next, 6px apart, means a mis-hit on a 118px
     pill closes the film somebody is watching. */
  .cinema__acts > * + *{margin-left:10px}
  .cinema__acts #cClose{flex:0 0 auto;margin-left:auto}
}

/* ---- a phone held sideways, and any short window --------------------------
   THE CLASS THAT DID NOT EXIST. The only phone block above is
   (max-width:720px) and (orientation:portrait), so a phone in landscape —
   about 844x390, and the way this site is mostly watched — fell into the
   DESKTOP branch. Measured there at 844x390: 16px of padding top and bottom,
   a 248px-tall picture and a 100px caption row under it, so the film was
   33,1% of the screen.

   Keyed on HEIGHT, because what is scarce in landscape is the height and
   max-width cannot see it. 560px clears every phone in landscape (iPhone SE
   320 · 15 Pro Max 430 · 16 Pro Max 440 · Pixel 8 Pro 448) and excludes every
   tablet (iPad mini 744 · iPad Pro 11" 834 · iPad Pro 13" 1024). It also
   catches a short desktop window, where the same layout is the right one —
   which is the test of a good breakpoint.
   -------------------------------------------------------------------------- */
@media (max-height:560px) and (orientation:landscape){
  /* The grid and its gap go away: there is one thing on this screen. */
  .cinema{display:block;padding:0;background:#000}

  .cinema__stage{position:absolute;top:0;right:0;bottom:0;left:0;
    overflow:visible}
  /* THE 76svh CEILING IS REMOVED HERE, AND ONLY HERE. Its reason — "a film
     sized to the last pixel reads as a fullscreen that failed" — is an
     argument about a window with room to spare. In a 390px-tall window there
     is none, and the ceiling is what makes it look broken. */
  .cinema__stage video{position:absolute;top:0;right:0;bottom:0;left:0;
    margin:auto;width:auto;height:auto;max-width:100%;max-height:100%}

  /* The band. One composition: the way out on the left, the film's identity
     beside it, and the fullscreen control on the right — positioned by .pfs
     against the picture, which here IS the screen. */
  .cinema__top{position:absolute;top:0;right:0;left:0;z-index:5;
    display:flex;flex-wrap:nowrap;align-items:center;
    padding:10px 14px 22px;
    padding-top:calc(10px + env(safe-area-inset-top));
    padding-left:calc(14px + env(safe-area-inset-left));
    padding-right:calc(72px + env(safe-area-inset-right)); /* pfsFit() rewrites this */
    background:linear-gradient(rgba(0,0,0,.82) 0%,rgba(0,0,0,.54) 58%,rgba(0,0,0,0) 100%);
    pointer-events:none;
    transition:opacity var(--chrome-in) var(--ease)}
  .cinema__top > *{pointer-events:auto}
  .cinema__top > * + *{margin-left:var(--s4)}
  /* THE PROGRESS BAR IS THE FIRST CHILD AND IS ABSOLUTELY POSITIONED, so it
     adds nothing to the row — but `* + *` still matches the button after it
     and pushed Close 16px further in than the padding intends. */
  .cinema__top > .ctop__back{margin-left:0}

  /* THE CONTROL PAINTS ABOVE THE BAND. .cinema__stage is position:absolute
     with z-index:auto here, so it is not a stacking context and .pfs__box (4)
     competed directly with the band (5) inside .cinema — the band won, and
     its .82 gradient went over the icon. Composited at 844x390 that put the
     one control this whole pass was built around at about 1,3:1 while leaving
     it clickable: invisible, in the orientation the site is mostly watched
     in. Raised rather than dropping the band, because the gradient under the
     button is what gives the icon its contrast. */
  .pfs__box{z-index:6}

  /* AND THE RESUME OFFER COMES OUT FROM UNDER THE BAND. Measured at 844x390:
     the band is 44px of button inside 10px/22px of padding, and the offer at
     the picture's own 10px inset landed squarely on the film's title and
     beside Close. It is pushed below the band here rather than raised above
     it, because the band is one composition — the way out, the identity, the
     control — and an offer sitting inside that row would read as a fourth
     member of it.

     84px clears the band at every safe-area inset this orientation produces,
     and it also threads the mark: at 390px of picture height the offer then
     spans 21,5% to 30,5%, between the mark's 8% row and its 38% one. */
  .rsm{top:calc(84px + env(safe-area-inset-top))}

  .ctop__back{flex:0 0 auto;display:inline-flex;align-items:center;
    min-height:44px;padding:0 4px;border:0;background:none;cursor:pointer;
    font:inherit;font-size:13px;font-weight:500;color:var(--ink)}
  .ctop__back > span{margin-right:9px}
  /* Two rules, never one list — Chrome 79 drops a list containing
     :focus-visible. */
  .ctop__back:focus{outline:2px solid var(--gold);outline-offset:2px}
  .ctop__back:focus-visible{outline:2px solid var(--gold);outline-offset:2px}

  .ctop__id{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;
    overflow:hidden}
  .ctop__id > * + *{margin-left:var(--s3)}
  /* --ink at .82, NOT --dim. Measured: --dim over the gradient's .54 point
     composited on a bright frame is 1,65:1. */
  .ctop__no{flex:0 0 auto;font-size:11px;letter-spacing:.2em;color:var(--ink);
    opacity:.82;font-variant-numeric:tabular-nums}
  .ctop__t{min-width:0;font-family:var(--serif);font-weight:300;font-size:17px;
    letter-spacing:-.01em;color:var(--ink);white-space:nowrap;
    overflow:hidden;text-overflow:ellipsis}
  .ctop__len{flex:0 0 auto;font-size:12px;color:var(--ink);opacity:.82;
    font-variant-numeric:tabular-nums}

  /* The transient line clears the band rather than crossing it. */
  .cinema__hint{top:84px}

  /* THE QUEUE'S PROGRESS, and only the queue's — showQueueBar() keeps this
     element `hidden` unless one is running, exactly as its twin inside
     .queue is. Pinned to the very top edge where the gradient is darkest:
     gold on rgba(0,0,0,.82) over a white frame is 5,64:1, where the .54
     point gives 1,97:1 and fails the 3:1 floor. */
  .prog--top{position:absolute;top:0;right:0;left:0;height:2px;margin:0;
    background:rgba(244,243,241,.18)}

  /* WHAT IS HIDDEN HERE, and it is a removal rather than an oversight:
     - the description: 13px/1.6 prose over a film in a 390px-tall window;
     - the queue list: four titles and their reasons;
     - the ambient control: the glow is off in fullscreen anyway and this
       state is a fullscreen in all but name.
     All three are present in portrait and on the desktop. */
  .cinema__foot,.queue,.ambset{display:none}

  /* Both bands and the control are ONE chrome and hide together. */
  .cinema.is-bare .cinema__top{opacity:0;pointer-events:none;
    transition:opacity var(--chrome-out) var(--ease)}
}

/* ---- a window with room: the caption becomes a grid ------------------------
   .cinema__foot was a flex row doing a grid's job: six kinds of thing held
   together by margin-left:22px plus two documented hacks — .cinema__break,
   and a child-combinator rewrite of .cinema__acts to win a specificity fight.
   A grid row break is not a hack, so above 860 both go. Grid `gap` is
   Chrome 66, so the television is safe; it is FLEX gap that is Chrome 84.
   Below 860 the flex layout is untouched. */
@media (min-width:860px){
  .cinema__foot{display:grid;
    grid-template-columns:minmax(0,1fr) auto;
    column-gap:var(--s6);row-gap:10px;align-items:baseline}
  .cinema__id{grid-column:1;grid-row:1}
  .cinema__acts{grid-column:2;grid-row:1;margin-left:0}
  .cinema__desc{grid-column:1;grid-row:2;margin-left:0;max-width:66ch}
  /* Kept in the DOM and switched off, so there is no HTML change and the
     flex layout below 860 is intact. */
  .cinema__break{display:none}
}

/* 1.760px leaves a third of a 2560px monitor black — 400px of gutter either
   side plus the pad. Eight 215px tiles and seven 24px gaps is 1.888px, which
   fits 2.040 with the pad: 8-up instead of 6-up. Nothing below 1900 moves. */
@media (min-width:1900px){
  :root{--wide:2040px}
}

/* ---- a television -------------------------------------------------------- */
/* Set from the user agent, which is a guess, and therefore used for NOTHING BUT
   SIZE -- see IS_TV in films.js. At three metres, 11px is not small type, it is
   an absence of type: the numbers, the running times and the bar disappear
   entirely while the titles stay readable.

   The padding is for overscan. A television may crop several per cent of every
   edge, and anything flush to the frame is simply not on the screen. */
.is-tv body{font-size:18px}
.is-tv .page{padding-left:clamp(40px,4vw,72px);padding-right:clamp(40px,4vw,72px);
             padding-bottom:clamp(40px,5vh,64px)}
.is-tv .bar{padding-top:clamp(28px,3.5vh,44px);padding-bottom:clamp(10px,1.5vh,18px)}
.is-tv .link{font-size:20px}
.is-tv .lede{font-size:24px}
.is-tv .cinema__no{font-size:16px}
.is-tv .len,.is-tv .cinema__len{font-size:17px}
.is-tv .gate__say{font-size:21px}
.is-tv .cinema__desc{font-size:19px;max-width:none}
.is-tv .cbtn{font-size:17px;padding:10px 22px}
/* FEWER, BIGGER TILES. At three metres a 215px tile is a postage stamp and its
   16,5px caption is not type at all. Four across the 1760px measure instead of
   six, with the caption scaled to match. */
.is-tv .wall{grid-template-columns:repeat(auto-fill,minmax(min(360px,100%),1fr))}
.is-tv .tile__t{font-size:26px;margin-top:14px}
.is-tv .tile__no{font-size:15px}
.is-tv .tile__18{font-size:19px}
.is-tv .tile__none{font-size:15px}
.is-tv .sec__n{font-size:15px}
.is-tv .sec__c{font-size:14px}
.is-tv .chip,.is-tv .tbtn,.is-tv .rail__k{font-size:15px}
.is-tv .chip__n{font-size:14px}
.is-tv .state{font-size:16px}
.is-tv .feat__k{font-size:14px}
.is-tv .feat__d{font-size:22px}
.is-tv .soon__k{font-size:14px}
.is-tv .soon__d{font-size:17px}
.is-tv .soon__c{font-size:22px}
.is-tv .queue__k{font-size:14px}
.is-tv .queue__t{font-size:21px}
.is-tv .queue__why,.is-tv .queue__no{font-size:15px}
.is-tv .queue__note{font-size:19px}
.is-tv .ambb,.is-tv .ambset__k{font-size:15px}
/* A rating nobody can read from the sofa is a rating that is not there. The
   dialogs get the same treatment: a television can reach the 18+ form with its
   remote, and a form is the worst possible place for 11px type. */
.is-tv .badge{font-size:14px;padding:3px 8px}
.is-tv .veil__box{width:min(620px,100%)}
.is-tv .veil__say,.is-tv .veil__tick,.is-tv .veil__bad{font-size:18px}
.is-tv .veil__label{font-size:14px}
.is-tv .veil__in{font-size:19px;padding:12px 14px}
.is-tv .veil__err{font-size:16px}
/* A remote has no pointer: the focus ring is the only thing telling anyone
   where they are, so it is drawn to be seen from the sofa. */
.is-tv .tile__a:focus-visible,.is-tv .cbtn:focus-visible,.is-tv .link:focus-visible,
.is-tv .chip:focus-visible,.is-tv .tbtn:focus-visible{
  outline:3px solid var(--gold);outline-offset:5px}
/* The one that actually fires on the television, whose browser predates
   :focus-visible. Its own rule, because a selector list is dropped whole when
   one selector in it cannot be parsed. */
.is-tv .tile__a.is-on{outline:3px solid var(--gold);outline-offset:5px}
/* ...AND THE SAME TRAP ON THE RAIL, which had no .is-on twin. The rule above
   this one is four :focus-visible selectors in a list, so Chrome 79 cannot
   parse it and drops all four — meaning that until 1.21.0 a chip, a sort
   button, Play all and the new Surprise me and Clear had NO focus ring at all
   on the television, which is the only screen navigated entirely by focus.
   Plain :focus, in rules of their own, scoped to .is-tv so that no other
   screen gains a ring after a mouse click. The mechanism is the one
   .is-tv .pfs:focus below already uses. */
.is-tv .chip:focus{outline:3px solid var(--gold);outline-offset:4px}
.is-tv .tbtn:focus{outline:3px solid var(--gold);outline-offset:4px}
.is-tv .link:focus{outline:3px solid var(--gold);outline-offset:5px}
.is-tv .find:focus{outline:3px solid var(--gold);outline-offset:3px}
/* The control, at three metres. Size only, like everything else hanging off
   .is-tv — the behaviour is identical to every other screen. */
.is-tv .pfs{top:var(--pfs-inset-tv);right:var(--pfs-inset-tv);
  width:var(--pfs-size-tv);height:var(--pfs-size-tv)}
.is-tv .pfs__i{width:var(--pfs-icon-tv);height:var(--pfs-icon-tv)}
.is-tv .pfs:focus{outline:3px solid var(--gold);outline-offset:5px}
.is-tv .pfs:focus-visible{outline:3px solid var(--gold);outline-offset:5px}
.is-tv .ctop__t{font-size:21px}
/* The resume offer at three metres. It is the ONE new control a remote has to
   be able to find, and films.js hands it the focus on a television for exactly
   that reason — so the ring is the whole affordance and is drawn to be seen
   from the sofa. Two rules again, never one list. */
.is-tv .rsm{top:var(--pfs-inset-tv);left:var(--pfs-inset-tv);
  font-size:17px;padding:13px 24px}
.is-tv .rsm:focus{outline:3px solid var(--gold);outline-offset:5px}
.is-tv .rsm:focus-visible{outline:3px solid var(--gold);outline-offset:5px}
/* 9px is not type at three metres, and this is the marker that says which
   films arrived since the owner last sat down. */
.is-tv .nu{font-size:14px;padding:6px 11px 7px 13px;letter-spacing:.18em}

@media (prefers-reduced-motion:reduce){
  /* The preview never starts at all under this (see STILL_ONLY in films.js);
     these only cover the still and the marks around it. .link > span is the
     arrow that slides away from the word on approach — it used to be a flex
     gap and was covered by the old `.find` line here; now it is a margin and
     needs naming. */
  .tile__img,.tile__vid,.tile__edge,.tile__wait,.tile__t,.tile__no,.badge,.find,.chip,.tbtn,
  .link,.link > span,.feat__img,.feat__vid,.amb{transition:none}
  /* The hero's slow drift is the one piece of unprompted motion on the page,
     so it is the first thing to go. The ambient glow is switched off in
     films.js rather than here, because it also has to stop the canvas loop
     that feeds it — a transparent element still being painted nine times a
     second is motion nobody can see and a laptop can hear. */
  .feat__img{animation:none;transform:scale(1.06)}
  .link:hover > span{margin-right:10px}
  /* Two rules, not one list: Chrome 79 drops a list containing
     :focus-visible, and that would take the .is-on line with it. */
  .tile__a:hover .tile__img,.tile__a:focus-visible .tile__img{transform:scale(1.005)}
  .tile__a.is-on .tile__img{transform:scale(1.005)}
  .veil{animation:none}
  .tile__a:active .tile__img,.tile__a:active .tile__edge{transition:none}
  /* THE FALLBACK FOR "IT FADES AWAY" IS "IT IS ALWAYS THERE", not "it snaps
     away" — the same philosophy as STILL_ONLY, where the preview never starts
     at all rather than starting without a transition. films.js also never
     arms the timer under this, so these are belt to that braces. */
  .pfs,.cinema__top{transition:none}
  .cinema.is-bare .pfs{opacity:1;pointer-events:auto}
  .cinema.is-bare .cinema__top{opacity:1;pointer-events:auto}
}
