/*htm-theme:start*/
/* ---------------------------------------------------------------------------
   layout.css - the site's LEFT RAIL, and the one trap that keeps breaking it.

   Every other stylesheet here is scoped to a page (.htm-browse, .htm-w2w,
   .htm-app). This one is not, because the rule it enforces is site-wide: the
   header, the footer, the site title, every card grid and every page heading
   start on the same 1240px rail.

   THE TRAP, which has now been found on eight surfaces and will be found again.

   A constrained block layout caps `> *` at the GLOBAL contentSize (760px) and
   centres each child with `margin-left/right:auto !important`. So a container
   WIDER than 760px does not left-align its contents, it strands them in the
   middle of itself. It looks exactly like a text-align bug, and text-align is
   never involved. It is invisible below 760px viewport width, so a phone check
   passes every time.

   Two idioms fix it and both are already in this theme:

     the container is too narrow  ->  max-width:var(--wp--style--global--wide-size)
                                      (browse.css, app-pages.css, what-to-watch.css)
     the children are too narrow  ->  "contentSize":"1240px" on the GROUP

   Note which one you need. Widening a container whose children are still capped
   renders WORSE than the bug: the one narrow child goes flush left and
   everything else stays centred.

   No !important is needed to widen something to the full available width: once
   max-width equals the width available, the auto margins compute to 0 by
   themselves. It IS needed to left-align something NARROWER than its container,
   because core marks those margins !important - see .htm-lede in home.css.
   --------------------------------------------------------------------------- */

/* PAGES: prose keeps its reading measure but starts on the rail.

   The page templates now put the TITLE on the 1240px rail, which is right - it
   lines up with the site title above it and with any card grid below it. That
   would orphan a prose page the other way round, though: /contact/ has no grid,
   so its form and copy stayed in a 760px column centred 240px to the right of
   its own heading. Left-aligning the column fixes that without giving anybody a
   150-character line to read.

   Scoped to body.page, which WordPress puts on pages and NOT on posts. A review
   is deliberately excluded: single.html is a centred editorial column under a
   full-width backdrop, and it is the one place that reads as intentional.

   Doubling is not needed here because body.page adds a class and an element to
   the selector; !important is, because core's margins carry it. */
body.page .entry-content.is-layout-constrained
  > :where(:not(.alignleft):not(.alignright):not(.alignfull)){
  margin-inline:0 !important}

/* /lists/ takes the wide measure, like /browse/ and /apps/ before it.

   Its index is a row of three cards, and the page-app template it runs on
   declares wp:post-content at contentSize 760 with no wideSize. So the group
   holding the row is capped at 760 however wide it declares its own children,
   and three cards sat across 760px of a 1240px page. Same escape hatch, same
   reason, as browse.css and app-pages.css - the fourth surface to need it.

   Note this widens the CONTAINER only. The row also needs htm-evencols
   (home.css) so cards with different amounts of copy end level, and
   build_list_pages.py sets both classes together. */
.entry-content.is-layout-constrained > .htm-lists{
  max-width:var(--wp--style--global--wide-size);
  width:100%}

/* ARCHIVE LEDES: measure, since the header group is now 1240 wide.

   wp:term-description is the tag-archive blurb ("The top tier of the Founder's
   Favorites..."). Widening the header group to the rail is right for the h1 and
   wrong for this: it would run the full 1240px, about 150 characters a line.

   Doubled class AND !important, for the reason home.css:127 sets out at length:
   core's `.wp-container-<hash> > :where(...)` scores one class, :where()
   contributes nothing, and core's layout CSS prints after this stylesheet - so
   a single class ties and loses the tie. */
.wp-block-term-description.wp-block-term-description{
  max-width:68ch;
  margin-inline:0 !important}
/* ---------------------------------------------------------------------------
   forms.css - text inputs, textareas and selects.

   Unscoped, like layout.css and for the same reason: these controls appear on
   four unrelated surfaces and had never been styled on any of them.

   WordPress and Jetpack both ship a browser-default control - white fill, black
   text, a #8c8f94 hairline, square corners - and this is a black site. The
   SUBMIT buttons were themed all along, because they are wp-block-button and
   inherit the gold pill from theme.json, so every form read as a stack of white
   boxes with a finished-looking gold button underneath. That mismatch is what
   made it look broken rather than merely plain.

   Four surfaces, one rule set:
     /contact/                Jetpack Grunion fields (.grunion-field)
     the header search        wp:search in parts/header.html
     /?s=                     wp:search in templates/search.html
     the 404                  wp:search in templates/404.html

   Attribute selectors rather than a bare `input`, so checkboxes, radios and
   file inputs keep their native look - restyling those is a much larger job
   and none of them appear on this site today.

   -webkit-appearance:none is load-bearing on iOS, which otherwise imposes its
   own inset shadow and corner radius on text inputs and ignores most of this.
   --------------------------------------------------------------------------- */

main input[type="text"],
main input[type="email"],
main input[type="url"],
main input[type="tel"],
main input[type="number"],
main input[type="search"],
main input[type="password"],
main input[type="date"],
main textarea,
main select,
.wp-block-search__input{
  background:var(--wp--preset--color--surface);
  color:var(--wp--preset--color--contrast);
  border:1px solid var(--wp--preset--color--line);
  border-radius:12px;
  padding:.7rem .9rem;
  font-family:inherit;
  font-size:1rem;
  line-height:1.4;
  box-shadow:none;
  -webkit-appearance:none;
  appearance:none}

/* The search field keeps the pill it is drawn inside. theme.json already sets
   border.radius 999px on the wp:search WRAPPER; the input inside it was square,
   which is what put a hard corner inside a round pill in the header. */
.wp-block-search__input{border-radius:999px}

main textarea{min-height:9rem;resize:vertical}

/* Placeholders default to a browser grey that is nearly invisible here, and
   Firefox additionally applies its own opacity. */
main input::placeholder,
main textarea::placeholder,
.wp-block-search__input::placeholder{
  color:var(--wp--preset--color--muted);
  opacity:1}

/* A visible focus ring is the accessibility half of this. Removing the UA
   outline without replacing it would leave keyboard users with no indication of
   where they are, so the ring is a real one: gold border plus a soft halo, the
   same gold the chips and card hovers use. */
main input[type="text"]:focus,
main input[type="email"]:focus,
main input[type="url"]:focus,
main input[type="tel"]:focus,
main input[type="number"]:focus,
main input[type="search"]:focus,
main input[type="password"]:focus,
main input[type="date"]:focus,
main textarea:focus,
main select:focus,
.wp-block-search__input:focus{
  outline:none;
  border-color:var(--wp--preset--color--gold);
  box-shadow:0 0 0 3px rgba(232,200,106,.22)}

/* Jetpack's own field wrapper adds a bottom margin only on some fields, so the
   contact form's rhythm was uneven down the column. */
.grunion-field-wrap{margin:0 0 var(--wp--preset--spacing--30)}

/* CARD META: one line, always.

   Not a form rule, but it belongs with the other "a component the theme never
   claimed" fixes and there is nowhere better until a cards.css exists.

   wp:post-terms prints every genre a film carries. Four of them wrap to a
   second line at card width, which pushes that card's TITLE 23px below its
   neighbours' - on three of every four rows measured on a person archive, and
   on every archive, search and listing page. A row of cards whose titles do not
   share a baseline reads as a mistake.

   -webkit-line-clamp rather than white-space:nowrap, and that is not a
   preference. The separator Gutenberg emits between terms carries
   `white-space: pre-wrap` of its own, which re-enables wrapping INSIDE a nowrap
   parent, so nowrap computes correctly and does nothing at all - verified in
   the browser before this was written. line-clamp ignores it and gives a real
   ellipsis. Prefixed properties are correct here; the unprefixed line-clamp is
   not yet what browsers implement.

   Scoped to post-template so it only touches CARDS. The kicker on a review
   itself is the same block at 720px, where it fits and must not be truncated. */
.wp-block-post-template .wp-block-post-terms{
  display:-webkit-box;
  -webkit-box-orient:vertical;
  -webkit-line-clamp:1;
  overflow:hidden}
/* Genre display faces. Generated by build_genre_fonts.py, do not edit. */
@font-face{font-family:'Rye';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/rye/v17/r05XGLJT86YzEZ7tfumh4g.woff2) format('woff2');}
@font-face{font-family:'Creepster';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/creepster/v13/AlZy_zVUqJz4yMrniH4Rcn35fh4Dog.woff2) format('woff2');}
@font-face{font-family:'Tangerine';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/tangerine/v18/Iurd6Y5j_oScZZow4VO5srNZi5FNym499g.woff2) format('woff2');}
@font-face{font-family:'Anton';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/anton/v27/1Ptgg87LROyAm3Kz-C8CSKlv.woff2) format('woff2');}
@font-face{font-family:'DynaPuff';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/dynapuff/v9/z7N5dRvsZDIVHbYPMhZJ3HQ83UaSu4uhr7-ZFeoYkgAr1x8RS8gp2Y_hSDk90n59Vw.woff2) format('woff2');}
@font-face{font-family:'Limelight';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/limelight/v21/XLYkIZL7aopJVbZJHDuoOulHjHUmTQ.woff2) format('woff2');}
@font-face{font-family:'Orbitron';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/orbitron/v35/yMJMMIlzdpvBhQQL_SC3X9yhF25-T1ny_CmBoWgzfDAlp7lk.woff2) format('woff2');}
@font-face{font-family:'Fredoka';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/fredoka/v17/X7nP4b87HvSqjb_WIi2yDCRwoQ_k7367_B-i2yQag0-mac3OLyX8EemKttxNbikt.woff2) format('woff2');}
@font-face{font-family:'Bebas Neue';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/bebasneue/v16/JTUSjIg69CK48gW7PXoo9WlhyyTh89Y.woff2) format('woff2');}
@font-face{font-family:'Trade Winds';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/tradewinds/v18/AYCPpXPpYNIIT7h8-QenM0Jt5vOt5o_H.woff2) format('woff2');}
@font-face{font-family:'Special Elite';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/specialelite/v20/XLYgIZbkc4JPUL5CVArUVL0ntnAOSFNuQsI.woff2) format('woff2');}
@font-face{font-family:'MedievalSharp';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/medievalsharp/v28/EvOJzAlL3oU5AQl2mP5KdgptMqhwMinUPDg.woff2) format('woff2');}
@font-face{font-family:'Permanent Marker';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/permanentmarker/v16/Fh4uPib9Iyv2ucM6pGQMWimMp004La2Cf5b6jlg.woff2) format('woff2');}
@font-face{font-family:'Old Standard TT';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/oldstandardtt/v22/MwQrbh3o1vLImiwAVvYawgcf2eVWEX-tS1ZfTc4PlA.woff2) format('woff2');}
@font-face{font-family:'Mystery Quest';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/mysteryquest/v21/-nF6OG414u0E6k0wynSGlujRLwYvDt1T39A.woff2) format('woff2');}
@font-face{font-family:'Black Ops One';font-style:normal;font-weight:400;font-display:swap;src:url(https://fonts.gstatic.com/s/blackopsone/v21/qWcsB6-ypo7xBdr6Xshe96H3aDvbtxsis4I.woff2) format('woff2');}
@font-face{font-family:'News Cycle';font-style:normal;font-weight:700;font-display:swap;src:url(https://fonts.gstatic.com/s/newscycle/v26/CSR54z1Qlv-GDxkbKVQ_dFsvWNReuc4nG2o.woff2) format('woff2');}
@font-face{font-family:'Nunito';font-style:normal;font-weight:600;font-display:swap;src:url(https://fonts.gstatic.com/s/nunito/v32/XRXI3I6Li01BKofiOc5wtlZ2di8HDGUmdTQ3j6zbXWjgeg.woff2) format('woff2');}
/* Falling posters. Generated by build_poster_rain.py, do not edit. */
.htm-rain{position:fixed;inset:0;z-index:0;overflow:hidden;pointer-events:none;
  contain:strict}
/* Every layer of the site sits above the rain. */
.wp-site-blocks{position:relative;z-index:1}
/* Blur and desaturation do the heavy lifting, not opacity alone.
   At a flat 0.22 with sharp artwork, titles and faces stayed legible enough to
   compete with the headings sitting on top of them. Out of focus, the layer
   reads as atmosphere: you register "movie posters" without trying to read one.
   The filter is static, so it composites once per image rather than per frame. */
.htm-drop{position:absolute;top:0;width:150px;height:225px;border-radius:10px;
  object-fit:cover;opacity:0;will-change:transform;
  filter:blur(1.8px) saturate(.8);
  animation-name:htm-fall;animation-timing-function:linear;
  animation-iteration-count:infinite}
@keyframes htm-fall{
  0%{opacity:0;transform:translate3d(0,-40vh,0) scale(var(--s)) rotate(0deg)}
  12%{opacity:.30}
  88%{opacity:.30}
  100%{opacity:0;
    transform:translate3d(var(--dx),125vh,0) scale(var(--s)) rotate(var(--rot))}}
/* A drop that is a silhouette rather than a poster. Only the things the
   poster aspect gets wrong are overridden: it is square, it has no artwork to
   crop or round off, it takes its colour from the season rather than from an
   image, and it wants less blur, because 1.8px on a flat shape is mush where
   on a poster it is the whole effect.

   --htm-spook-accent is defined on the root in spook.css, NOT under body.home
   with the rest of the palette, because these fall on every page. The literal
   is the same value and is here so a missing stylesheet gives orange
   silhouettes rather than black ones on a black page. */
.htm-drop-icon{width:92px;height:92px;border-radius:0;
  fill:currentColor;color:var(--htm-spook-accent,#ff9f45);
  filter:blur(1.2px)}

/* Layout for the no-script fallback only. The shuffled drops carry the same
   values inline and never take an index class, so these never apply to them.
   The fallback is posters only: with scripting off there is nothing to build
   the silhouettes, and a <noscript> full of <use> would be inert markup. */
.htm-drop-0{left:50.02%;animation-duration:74.12s;animation-delay:-50.17s;--s:0.995;--dx:-29.1px;--rot:-2.9deg;--y:71.8vh}
.htm-drop-1{left:71.39%;animation-duration:91.12s;animation-delay:-13.1s;--s:0.57;--dx:-6.5px;--rot:0.8deg;--y:48.5vh}
.htm-drop-2{left:35.87%;animation-duration:80.47s;animation-delay:-58.73s;--s:0.559;--dx:35.3px;--rot:-0.5deg;--y:14.2vh}
.htm-drop-3{left:39.17%;animation-duration:85.78s;animation-delay:-63.28s;--s:0.576;--dx:-12.3px;--rot:5.6deg;--y:24.5vh}
.htm-drop-4{left:50.98%;animation-duration:102.41s;animation-delay:-30.35s;--s:0.921;--dx:-29.8px;--rot:-3.9deg;--y:55.6vh}
.htm-drop-5{left:91.86%;animation-duration:77.87s;animation-delay:-14.13s;--s:0.56;--dx:-12.6px;--rot:5.0deg;--y:19.8vh}
.htm-drop-6{left:24.68%;animation-duration:72.08s;animation-delay:-34.47s;--s:1.131;--dx:35.3px;--rot:7.5deg;--y:5.2vh}
.htm-drop-7{left:43.27%;animation-duration:66.44s;animation-delay:-25.94s;--s:0.851;--dx:-29.8px;--rot:-1.6deg;--y:74.3vh}
.htm-drop-8{left:9.96%;animation-duration:77.97s;animation-delay:-58.68s;--s:0.693;--dx:-32.7px;--rot:-6.9deg;--y:75.8vh}
.htm-drop-9{left:94.3%;animation-duration:82.01s;animation-delay:-50.41s;--s:0.779;--dx:35.8px;--rot:0.5deg;--y:28.5vh}
.htm-drop-10{left:11.4%;animation-duration:96.77s;animation-delay:-50.11s;--s:0.999;--dx:5.3px;--rot:-5.5deg;--y:15.9vh}
.htm-drop-11{left:40.34%;animation-duration:76.89s;animation-delay:-8.85s;--s:0.611;--dx:-9.7px;--rot:7.4deg;--y:34.5vh}
.htm-drop-12{left:53.89%;animation-duration:77.69s;animation-delay:-6.56s;--s:0.802;--dx:-1.4px;--rot:0.2deg;--y:12.5vh}
.htm-drop-13{left:64.02%;animation-duration:60.31s;animation-delay:-10.74s;--s:1.122;--dx:31.5px;--rot:-6.6deg;--y:32.5vh}
.htm-drop-14{left:26.13%;animation-duration:75.24s;animation-delay:-44.11s;--s:1.055;--dx:17.3px;--rot:6.3deg;--y:75.4vh}
.htm-drop-15{left:44.06%;animation-duration:85.3s;animation-delay:-15.77s;--s:1.038;--dx:11.3px;--rot:-5.4deg;--y:4.4vh}
.htm-drop-16{left:30.24%;animation-duration:100.53s;animation-delay:-37.33s;--s:0.911;--dx:-20.0px;--rot:-3.2deg;--y:18.5vh}
.htm-drop-17{left:56.05%;animation-duration:95.01s;animation-delay:-31.43s;--s:1.137;--dx:-28.1px;--rot:4.5deg;--y:59.8vh}
.htm-drop-18{left:10.52%;animation-duration:78.18s;animation-delay:-17.91s;--s:0.906;--dx:-28.8px;--rot:-7.3deg;--y:9.5vh}
.htm-drop-19{left:72.55%;animation-duration:77.56s;animation-delay:-24.46s;--s:0.974;--dx:-13.6px;--rot:0.1deg;--y:19.4vh}
.htm-drop-20{left:53.56%;animation-duration:86.17s;animation-delay:-27.3s;--s:1.075;--dx:12.0px;--rot:1.5deg;--y:73.1vh}
.htm-drop-21{left:17.07%;animation-duration:77.9s;animation-delay:-67.11s;--s:0.703;--dx:31.3px;--rot:-3.1deg;--y:47.8vh}
.htm-drop-22{left:55.77%;animation-duration:72.11s;animation-delay:-2.43s;--s:1.064;--dx:-11.4px;--rot:0.6deg;--y:84.3vh}
.htm-drop-23{left:75.12%;animation-duration:69.53s;animation-delay:-45.37s;--s:0.91;--dx:-35.0px;--rot:7.1deg;--y:60.4vh}

/* Phones. Smaller drops, because a 150px poster is a fifth of the width there
   and stops reading as a distant background. The script independently builds
   fewer of them; this rule also trims the no-script fallback to the same count,
   so the two paths agree. */
@media (max-width:781px){
  .htm-drop{width:110px;height:165px}
  .htm-drop-icon{width:68px;height:68px}
  .htm-drop-10,
  .htm-drop-11,
  .htm-drop-12,
  .htm-drop-13,
  .htm-drop-14,
  .htm-drop-15,
  .htm-drop-16,
  .htm-drop-17,
  .htm-drop-18,
  .htm-drop-19,
  .htm-drop-20,
  .htm-drop-21,
  .htm-drop-22,
  .htm-drop-23{display:none}
}

/* Still, for anyone who asked for less motion. Not hidden: the request is for
   less movement, and answering it by deleting the site's one piece of scenery
   reads as a punishment. Frozen, the layer is what a single frame of the rain
   already looks like, so those visitors get the same wallpaper with none of the
   travel. An accessibility guarantee rather than a performance tradeoff, so it
   holds at every width.

   Each drop rests at its own `--y`. Without one they would all sit at top:0 in
   a row across the header, since every bit of vertical travel lives in the
   keyframes. The var() fallbacks are load-bearing and not belt-and-braces: a
   translate3d() naming even one undefined custom property is invalid at
   computed-value time, which drops the whole transform and puts every poster
   back in that row. will-change:auto hands back compositor memory that buys
   nothing once nothing moves. */
@media (prefers-reduced-motion: reduce){
  .htm-drop{animation:none;opacity:.30;will-change:auto;
    transform:translate3d(var(--dx,0px),var(--y,0vh),0)
              scale(var(--s,1)) rotate(var(--rot,0deg))}}
.htm-browse{--htm-gold:#e8b64c;--htm-line:rgba(232,182,76,.28)}
.htm-browse section{margin:0 0 3rem}
.htm-browse h2{margin:0 0 .35rem;font-size:1.6rem}
/* Provenance label above a section heading. Only "By verdict" wears one: it is
   wholly ours, and it is where the gold-pill vocabulary in tags.css gets
   anchored. Same typography as the era-card kicker further down, because it is
   doing the same job one level up. */
.htm-browse .htm-kicker{display:block;margin:0 0 .2rem;font-size:.78rem;
  letter-spacing:.12em;text-transform:uppercase;color:var(--htm-gold);opacity:.85}
.htm-browse .htm-sub{margin:0 0 1.1rem;opacity:.72;font-size:.95rem}
.htm-browse ul{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.6rem}
.htm-browse li{margin:0}
/* The chip itself now lives in tags.css, unscoped. It is no longer a browse-page
   object: php/htm-tags.php draws the same pill in the "Also filed under" panel
   on every review, and the two surfaces have to be styled from one rule or they
   drift. Only the era-card override below is still genuinely about this page. */
/* Verdict cards. Each one carries its own emoji and its own accent, which is
   the same trick the genre tiles use: four identical bordered boxes make the
   reader read four labels, where four colored faces are sorted before they are
   read. --v-accent is set per card in build_browse_page.py. */
.htm-browse .htm-verdicts{display:grid;gap:1rem;
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
/* color is pinned because the theme paints every content link gold. Gold body
   copy under a green or grey heading reads as a mistake, and the accent stops
   meaning anything once everything on the card is wearing it. */
.htm-browse a.htm-verdict{display:flex;flex-direction:column;color:#d9dade;
  padding:1.35rem 1.4rem 1.2rem;text-decoration:none !important;border-radius:14px;
  border:1px solid var(--htm-line);background:
    radial-gradient(120% 140% at 0% 0%, color-mix(in srgb, var(--v-accent) 18%, transparent) 0%, transparent 62%),
    #0e0e10;
  transition:border-color .18s ease, transform .18s ease}
.htm-browse a.htm-verdict:hover{border-color:var(--v-accent);transform:translateY(-3px)}
.htm-browse .htm-verdict-face{font-size:2.4rem;line-height:1;margin-bottom:.75rem}
.htm-browse .htm-verdict-name{display:block;font-size:1.25rem;line-height:1.2;
  color:var(--v-accent)}
.htm-browse .htm-verdict-blurb{display:block;margin-top:.4rem;font-size:.95rem;
  line-height:1.4;opacity:.78}
/* margin-top:auto pins the count to the bottom of the card, so a one-line
   blurb and a two-line blurb still line their counts up across the row. */
.htm-browse .htm-verdict-count{display:block;margin-top:auto;padding-top:.9rem;
  font-size:.78rem;letter-spacing:.09em;text-transform:uppercase;opacity:.5}
/* On a phone, four stacked full-height cards is a lot of scrolling for four
   words of information. Turning each one on its side puts the face beside the
   type and roughly halves the section. */
@media (max-width:600px){
  .htm-browse .htm-verdicts{gap:.7rem}
  .htm-browse a.htm-verdict{display:grid;grid-template-columns:auto 1fr;
    column-gap:1rem;align-items:center;padding:1rem 1.15rem}
  .htm-browse .htm-verdict-face{font-size:2rem;margin:0;
    grid-column:1;grid-row:1 / span 3;align-self:center}
  .htm-browse .htm-verdict-name{grid-column:2}
  .htm-browse .htm-verdict-blurb{grid-column:2;margin-top:.2rem}
  .htm-browse .htm-verdict-count{grid-column:2;margin-top:.45rem;padding-top:0}
}

/* wpautop injects an empty <p> alongside any block-level element in page
   content, and inside a grid that empty paragraph is a real, sized column: the
   era row rendered as three cards and a hole. The group card has to be a <div>
   because it contains links and so cannot be an <a> itself, which is enough to
   trigger it. An empty paragraph is never content, so drop it everywhere here
   rather than chase whichever grid it lands in next. */
.htm-browse p:empty{display:none}

/* Eras. Same card language as the verdicts above, because they do the same job:
   a handful of wide entry points rather than a row of interchangeable pills. */
.htm-browse .htm-eras{display:grid;gap:.9rem;
  grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}
.htm-browse .htm-era{display:block;padding:1.15rem 1.25rem;border-radius:12px;
  border:1px solid var(--htm-line);text-decoration:none !important}
.htm-browse a.htm-era:hover{border-color:var(--htm-gold)}
.htm-browse .htm-era-kicker{display:block;font-size:.78rem;letter-spacing:.12em;
  text-transform:uppercase;opacity:.55}
.htm-browse .htm-era-name{display:block;font-size:1.9rem;line-height:1.1;
  margin:.3rem 0 .25rem}
.htm-browse .htm-era-count{display:block;font-size:.9rem;opacity:.72}
.htm-browse .htm-era-links{margin:.9rem 0 0;gap:.4rem}
.htm-browse .htm-era-links .htm-chip{padding:.32rem .7rem;font-size:.88rem}
.htm-browse .htm-letter{margin:1.4rem 0 .5rem;font-size:1rem;letter-spacing:.14em;
  text-transform:uppercase;opacity:.6;border-bottom:1px solid var(--htm-line);
  padding-bottom:.3rem}
/* The chip's own phone override moved to tags.css with the rest of it. */

/* Genre tiles. Deliberately large: each genre is set in its own display face,
   and a display face at chip size reads as a rendering glitch rather than a
   choice. --htm-genre-size is the base the per-font multiplier scales from,
   mirroring sizeMultipliers in GenreFontProvider.swift. */
.htm-browse .htm-genres{--htm-genre-size:2.6rem;display:grid;gap:1rem;
  grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}
.htm-browse a.htm-genre{display:flex;flex-direction:column;justify-content:flex-end;
  min-height:170px;padding:1.5rem 1.6rem;border-radius:16px;text-decoration:none !important;
  border:1px solid var(--htm-line);background:
    radial-gradient(120% 140% at 0% 100%, color-mix(in srgb, var(--g-accent) 16%, transparent) 0%, transparent 60%),
    #0e0e10;
  transition:border-color .18s ease, transform .18s ease}
.htm-browse a.htm-genre:hover{border-color:var(--g-accent);transform:translateY(-3px)}
/* A name never breaks inside a word. It used to: overflow-wrap:anywhere turned
   an overflow into "Documentar / y", which reads as a rendering fault rather
   than a wrap. Instead each tile is its own query container and caps the type
   size against its own width, so a long single word shrinks just enough to fit
   and everything short keeps its full size.

   --g-em is the width of the name's longest WORD expressed in em for its own
   display face, so `100cqi / --g-em` is exactly the size at which that word
   fills the tile. Measuring the longest word rather than the whole string is
   what lets "Science Fiction" keep wrapping at its space, which looks
   deliberate, while "Documentary" is held on one line.

   The first font-size is a fallback: a browser without container-query units
   drops the second declaration and keeps this one, rather than ending up with
   no size at all. The .98 is headroom: the cap alone would size the word to
   fill the box exactly, and subpixel rounding at that point can still tip it
   onto a second line. */
.htm-browse a.htm-genre{container-type:inline-size}
.htm-browse .htm-genre-name{color:var(--g-accent);line-height:1;display:block;
  overflow-wrap:normal;hyphens:none;
  font-size:calc(var(--htm-genre-size) * var(--g-mult,1));
  font-size:min(calc(var(--htm-genre-size) * var(--g-mult,1)),
                calc(100cqi / var(--g-em,4) * .98))}
.htm-browse .htm-genre-count{margin-top:.7rem;font-size:.85rem;letter-spacing:.08em;
  text-transform:uppercase;opacity:.55}
/* Required, not defensive. The rule above sets display:flex as an author
   declaration, which outranks the UA stylesheet's [hidden]{display:none}, so
   without this the hidden attribute is inert and the genre reel shows all
   eighteen tiles instead of six. Same reason a.htm-person carries one. */
.htm-browse a.htm-genre[hidden]{display:none}
/* The reel above the A-Z fold. Six tiles sit in the open and the script swaps
   which six on every visit; the grid itself is the same one the fold uses, so
   there is nothing to restyle. The bottom margin is what separates the reel
   from the fold's summary. */
.htm-browse #htm-genre-reel{margin-bottom:2rem}
@media (max-width:600px){
  .htm-browse .htm-genres{--htm-genre-size:2.1rem;grid-template-columns:1fr 1fr;gap:.7rem}
  .htm-browse a.htm-genre{min-height:130px;padding:1.1rem}
}

/* The highlight reel: six faces sitting in the open above the folded index,
   reshuffled by the page script on every visit. Same card as the index below,
   so there is nothing to restyle here beyond the track. */
.htm-browse .htm-reel{display:grid;gap:1.2rem;margin:0 0 2rem;
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}
@media (max-width:600px){
  .htm-browse .htm-reel{grid-template-columns:repeat(3,1fr);gap:.7rem}
}

/* Age ratings, as the certificate box every poster and trailer has trained the
   reader to recognize, plus the traffic-light color the real box never had.
   The code is aria-hidden because the official name next to it already says
   it, and "G" read aloud on its own is noise. --r-accent is per card. */
.htm-browse .htm-ratings{display:grid;gap:.9rem;
  grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.htm-browse a.htm-rating{display:flex;align-items:center;gap:1.1rem;color:#d9dade;
  padding:1.1rem 1.25rem;text-decoration:none !important;border-radius:14px;
  border:1px solid var(--htm-line);background:
    linear-gradient(100deg, color-mix(in srgb, var(--r-accent) 14%, transparent) 0%, transparent 55%),
    #0e0e10;
  transition:border-color .18s ease, transform .18s ease}
.htm-browse a.htm-rating:hover{border-color:var(--r-accent);transform:translateY(-3px)}
.htm-browse .htm-rating-box{flex:none;display:grid;place-items:center;
  /* One width for every code, so PG-13 does not shove its card's text a
     centimetre right of the R card's. */
  min-width:92px;padding:.5rem .55rem;border-radius:8px;
  border:3px solid var(--r-accent);color:var(--r-accent);
  font-weight:800;font-size:1.5rem;line-height:1.05;letter-spacing:.01em;
  background:color-mix(in srgb, var(--r-accent) 12%, transparent)}
.htm-browse .htm-rating-text{display:block;min-width:0}
.htm-browse .htm-rating-name{display:block;font-size:1.05rem;font-weight:600;
  line-height:1.25;color:#f1f1f4}
.htm-browse .htm-rating-blurb{display:block;margin-top:.25rem;font-size:.92rem;
  line-height:1.4;opacity:.75}
.htm-browse .htm-rating-count{display:block;margin-top:.5rem;font-size:.76rem;
  letter-spacing:.09em;text-transform:uppercase;opacity:.5}
@media (max-width:600px){
  .htm-browse .htm-ratings{grid-template-columns:1fr}
  .htm-browse .htm-rating-box{min-width:76px;font-size:1.25rem}
}

/* People. Portraits large enough to recognize a face at a glance. */
.htm-browse .htm-people-search{margin:0 0 1.4rem;display:flex;flex-wrap:wrap;
  align-items:center;gap:1rem}
.htm-browse .htm-people-search input{flex:1 1 320px;max-width:460px;
  padding:.85rem 1.15rem;border-radius:999px;border:1px solid var(--htm-line);
  background:#0e0e10;color:inherit;font:inherit;font-size:1rem}
.htm-browse .htm-people-search input:focus{outline:2px solid var(--htm-gold);
  outline-offset:2px;border-color:var(--htm-gold)}
.htm-browse .htm-people-count{margin:0;font-size:.85rem;letter-spacing:.08em;
  text-transform:uppercase;opacity:.55}
.htm-browse .htm-people{display:grid;gap:1.2rem;
  grid-template-columns:repeat(auto-fill,minmax(170px,1fr))}
.htm-browse a.htm-person{display:block;text-decoration:none !important;
  border-radius:14px;transition:transform .18s ease}
.htm-browse a.htm-person:hover{transform:translateY(-4px)}
.htm-browse a.htm-person[hidden]{display:none}
.htm-browse .htm-person-photo{display:block;position:relative;aspect-ratio:2/3;
  border-radius:14px;overflow:hidden;border:1px solid var(--htm-line);
  background:#17171a}
.htm-browse .htm-person-photo img{width:100%;height:100%;object-fit:cover;display:block}
.htm-browse a.htm-person:hover .htm-person-photo{border-color:var(--htm-gold)}
.htm-browse .htm-person-initials{position:absolute;inset:0;display:flex;
  align-items:center;justify-content:center;font-size:2.2rem;font-weight:600;
  color:var(--htm-gold);opacity:.5}
.htm-browse .htm-person-name{display:block;margin-top:.7rem;font-size:1.05rem;
  font-weight:600;line-height:1.25}
.htm-browse .htm-person-meta{display:block;margin-top:.2rem;font-size:.82rem;opacity:.55}
@media (max-width:600px){
  .htm-browse .htm-people{grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:.9rem}
}

/* Break the Browse page out of the constrained content column.
   A block theme caps `.is-layout-constrained > *` at contentSize (760px), which
   left the genre grid at two columns and the person grid at four. This page is
   an index, not prose, so it gets the full wide measure. */
.entry-content.is-layout-constrained > .htm-browse{
  max-width:var(--wp--style--global--wide-size);
  width:100%}

/* And the page TITLE with it, or the fix above orphans it.

   page.html wraps wp:post-title in its own constrained group, so the h1 is
   capped at contentSize and centred. On an ordinary page that is right: a 760px
   title over 760px of prose. It is wrong here and only here, because the rule
   above moved the content out to 1240px and left "Browse Reviews" sitting 240px
   to the right of everything underneath it.

   So this is scoped to the page rather than fixed in page.html, where it would
   drag /contact/ - genuine prose on the same template - out of alignment with
   its own body copy. :has() rather than a page-id, which would not survive the
   page being recreated.

   No !important, for the same reason the rule above needs none: once max-width
   equals the width actually available, core's auto margins compute to 0. */
body:has(.htm-browse) .wp-block-post-title{
  max-width:var(--wp--style--global--wide-size);
  width:100%}

/* ---------------------------------------------------------------
   Post carousels. Three of them on the homepage: "Newest reviews", "New
   releases" and "Founder's Favorites".

   A horizontal scroll-snap rail rather than a JS slider. No library, no
   autoplay stealing focus, no broken state if scripts fail. Trackpad, touch,
   shift+wheel and keyboard all work by default because it is just a
   scroll container.

   The block editor emits a grid for the post template, so the grid is
   overridden to a single flowing row here rather than fought in markup. That
   override is also the whole point on a phone, where core's grid collapses to
   one column and the section's height becomes its perPage: New releases was
   2,127px of a 10,123px page at 390px before it became a rail.
   --------------------------------------------------------------- */
.htm-rail .wp-block-post-template{
  display:flex !important;
  grid-template-columns:none !important;
  overflow-x:auto;
  scroll-snap-type:x mandatory;
  gap:1.5rem;
  padding:.25rem .25rem 1.25rem;
  margin:0;
  scrollbar-width:thin;
  scrollbar-color:rgba(232,200,106,.5) transparent}
.htm-rail .wp-block-post-template > li{
  flex:0 0 clamp(260px, 30vw, 360px);
  scroll-snap-align:start}

/* New releases and Founder's Favorites carry a title-only card: no category
   line, no excerpt. They read wrong at the review rail's width and would show
   only about three across where they used to show four, so they take a
   narrower basis and keep the density they had as grids. The phone rule below
   overrides both, because at 390px there is only ever one card plus a peek. */
.htm-rail-compact .wp-block-post-template > li{
  flex-basis:clamp(200px, 22vw, 260px)}
.htm-rail .wp-block-post-template::-webkit-scrollbar{height:8px}
.htm-rail .wp-block-post-template::-webkit-scrollbar-thumb{
  background:rgba(232,200,106,.45);border-radius:999px}
.htm-rail .wp-block-post-template::-webkit-scrollbar-track{background:transparent}

/* Fade the right edge so it reads as "there is more", which a flat cut-off
   does not. */
.htm-rail{position:relative}
.htm-rail::after{content:"";position:absolute;top:0;right:0;bottom:1.25rem;
  width:64px;pointer-events:none;
  background:linear-gradient(90deg, rgba(0,0,0,0), #000 85%)}
@media (max-width:600px){
  .htm-rail .wp-block-post-template > li{flex-basis:78vw}
  .htm-rail::after{width:32px}
}

/* ---------------------------------------------------------------
   Collapsible sections.

   Native <details>, so there is no JavaScript to load, keyboard and screen
   reader behavior come for free, and find-in-page can open a closed section in
   modern browsers.
   --------------------------------------------------------------- */
.htm-browse .htm-fold{border:0}
.htm-browse .htm-fold > summary{list-style:none;cursor:pointer;
  display:flex;flex-wrap:wrap;align-items:baseline;gap:.35rem 1rem;
  padding:.9rem 0;border-bottom:1px solid var(--htm-line)}
.htm-browse .htm-fold > summary::-webkit-details-marker{display:none}
/* h3 as well as h2: the people fold sits under a section that already owns the
   h2, so its summary carries an h3 rather than a second one. It should still
   read at the same weight as the other section headings. */
.htm-browse .htm-fold > summary h2,
.htm-browse .htm-fold > summary h3{margin:0;font-size:1.6rem}
.htm-browse .htm-fold > summary .htm-sub{margin:0}
.htm-browse .htm-fold > summary::after{content:"";margin-left:auto;flex:none;
  width:.7rem;height:.7rem;align-self:center;
  border-right:2px solid var(--htm-gold);border-bottom:2px solid var(--htm-gold);
  transform:rotate(45deg);transition:transform .2s ease}
.htm-browse .htm-fold[open] > summary::after{transform:rotate(-135deg)}
.htm-browse .htm-fold > summary:hover h2,
.htm-browse .htm-fold > summary:hover h3{color:var(--htm-gold)}
.htm-browse .htm-fold-body{padding-top:1.6rem}

/* "Show everyone" toggle, styled as a link rather than a button so it does not
   compete with the real calls to action. */
.htm-browse .htm-people-more{margin:1.6rem 0 0;text-align:center}
.htm-browse .htm-linkbtn{background:none;border:1px solid var(--htm-line);
  color:inherit;font:inherit;font-size:.9rem;cursor:pointer;
  padding:.7rem 1.4rem;border-radius:999px}
.htm-browse .htm-linkbtn:hover{border-color:var(--htm-gold);color:var(--htm-gold)}
.htm-browse .htm-people-more[hidden]{display:none}

/* Carousel arrows, injected by the front-page script. */
.htm-rail-nav{display:flex;gap:.5rem}
.htm-rail-nav button{width:40px;height:40px;border-radius:999px;cursor:pointer;
  border:1px solid var(--htm-line);background:#0e0e10;color:#e8c86a;
  font-size:1.1rem;line-height:1;display:grid;place-items:center}
.htm-rail-nav button:hover:not(:disabled){border-color:#e8c86a;background:#17171a}
.htm-rail-nav button:disabled{opacity:.3;cursor:default}
/* The New releases and Founder's Favorites heads are verticalAlignment
   "bottom", so their flex row aligns on the text baseline, which a 40px round
   button does not sit on. Same one-line fix home.css already applies to the
   birthday shelf's head. Harmless on the reviews head, which is centred. */
.htm-rail-head .htm-rail-nav{align-self:center}

/* The head is justifyContent "space-between" and was written when it held TWO
   children: the heading, and a "See all N" link hard right. The arrows are a
   THIRD, injected by the front-page script after load, and space-between spreads
   three children evenly - so "See all" stopped being right-aligned and came to
   rest in the dead centre of the row, which is where it has been on Newest
   reviews and New releases ever since.

   An auto margin absorbs the free space before justify-content gets to
   distribute any, so this puts the heading hard left and leaves "See all" and
   the arrows together on the right, which is what the two-child version looked
   like. Founder's Favorites, whose rail is short enough that the script adds no
   arrows, is unaffected either way.

   Exactly the fix, and the reason, that home.css already applies to the
   birthday shelf's head - see .htm-bd-head .htm-rail-nav. Below 600px the
   arrows are display:none and the head is back to two children, so nothing
   about this changes on a phone. */
.htm-rail-head > h2{margin-right:auto}
@media (max-width:600px){.htm-rail-nav{display:none}}

/* The year row under the era cards.

   Only the newest decade is broken up, because only that card is too big: it
   carries 71% of the library. See year_row() for why COLLECTION_MIN_COUNT does
   not apply to these chips.

   Scoped inside .htm-browse like the rest of this file, so --htm-line and
   --htm-gold resolve. They are declared on .htm-browse and nowhere else, and an
   unresolved var() does not fall back, it invalidates the whole declaration. */
.htm-browse .htm-year-row{margin-top:1.1rem}
.htm-browse .htm-year-label{margin:0 0 .6rem;
  font-size:.8rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--wp--preset--color--muted)}
.htm-browse .htm-year-row > ul{list-style:none;margin:0;padding:0;
  display:flex;flex-wrap:wrap;gap:.6rem}
.htm-browse .htm-year-row > ul > li{margin:0}
/* Years are four digits and all the same width, so they get the tighter chip
   the era-card links already use rather than the full-size collection pill. */
.htm-browse .htm-year-row .htm-chip{padding:.32rem .7rem;font-size:.88rem}
/* ===============================================================
   /apps/ and its 15 child pages.

   These pages were ported as plain prose (tools/port_app_pages.py kept the
   words and dropped every container), so there was no design to repair, only
   content to design. This is that design: hero, real device screenshots, stat
   strip, feature grid, pull quotes, launch strip, privacy panel.

   Ships through the design system, NOT in a <style> block in page content.
   KSES on this host strips individual declarations out of inline styles while
   leaving the rule behind, which reads as a layout bug rather than a
   permissions one. Same reason accents are classes here and never an inline
   `style="--app-accent:..."`.
   =============================================================== */

/* ---------------------------------------------------------------
   Root, width, accents.
   --------------------------------------------------------------- */

/* A block theme caps `.is-layout-constrained > *` at contentSize (760px).
   These are landing pages, not prose, so they take the full wide measure.
   Same escape hatch the Browse page uses. */
.entry-content.is-layout-constrained > .htm-app,
.entry-content.is-layout-constrained > .htm-apps{
  max-width:var(--wp--style--global--wide-size);
  width:100%}

/* Fallback only. These pages use the `page-app` template, which has no
   post-title block, so normally there is nothing here to hide. This catches the
   case where a page loses its template assignment (editing and saving it in
   wp-admin can do that) and falls back to `page`, which would print a second,
   unstyled copy of the title the designed hero already carries.
   Kept as CSS rather than relied on: hiding leaves the heading in the markup,
   which is why the template does the real work. */
main:has(.htm-app) > .wp-block-group:first-child,
main:has(.htm-apps) > .wp-block-group:first-child{display:none}

/* The poster rain is the site's signature, and it earns its keep behind a front
   page that is mostly headline and space. These pages are the opposite: real
   screenshots, card grids and long feature copy, all of which the rain shows
   through and competes with. Dimmed rather than removed, so the identity
   survives and the content wins.

   Dimmed on the container, not on `.htm-drop`: the drop's opacity is driven by
   the htm-fall keyframes, and an animated property beats a static declaration,
   so setting it there does nothing at all. */
body:has(.htm-app) .htm-rain,
body:has(.htm-apps) .htm-rain{opacity:.4}

/* WordPress sets border-box on its own blocks, but these pages carry a lot of
   hand-authored markup inside Custom HTML blocks, which falls back to the
   browser default of content-box. That is not a cosmetic difference: a feature
   card asking for min-height 250px rendered at 316px once padding and border
   were added on top, so every card in a short row had about 130px of dead space
   under its text. It also made `.htm-shot` overflow its own gallery item by the
   width of the phone's bezel. */
.htm-app,
.htm-apps,
.htm-app *,
.htm-apps *{box-sizing:border-box}

.htm-app,
.htm-apps{
  --app-accent:#e8c86a;
  --app-glow:color-mix(in srgb, var(--app-accent) 13%, transparent);
  --app-wash:color-mix(in srgb, var(--app-accent) 8%, transparent);
  --app-edge:color-mix(in srgb, var(--app-accent) 34%, transparent);
  --app-surface:#0e0e10;
  --app-line:#2a2a2f;
  --app-radius:20px}

/* Per-app accents, carried over from the static site's body themes. Gold stays
   the shared identity (buttons, links, header, footer); these only tint the
   eyebrow, the feature bars, the quote rails and the glow. */
.htm-app.is-gold,       .is-gold      {--app-accent:#e8c86a}
.htm-app.is-teal,       .is-teal      {--app-accent:#3fbfae}
.htm-app.is-coral,      .is-coral     {--app-accent:#f2887a}
.htm-app.is-green,      .is-green     {--app-accent:#21b366}
.htm-app.is-terracotta, .is-terracotta{--app-accent:#dd9166}
/* Added for Almanac and How to Music. The first five were one per app and all
   five were taken, so a sixth app added to apps.json would have rendered with
   --app-accent unset and no error anywhere. Both values are the canonical
   tokens from the :root block in HTM Site/docs/styles.css. */
.htm-app.is-blue,       .is-blue      {--app-accent:#6f8bf0}
.htm-app.is-rose,       .is-rose      {--app-accent:#e578a0}
/* Added for Movie Night, 2026-09-16. Its own identity is studio gold on a plum
   night, but the plum itself (#29143D in the app's Theme.swift) is a GROUND, far
   too dark to tint an eyebrow or a feature bar on a #0b0b0d page. This is the
   icon's glowPlum, #8a4bc2, lifted into the same luminance band as --blue and
   --rose so it reads as an accent rather than disappearing. */
.htm-app.is-plum,       .is-plum      {--app-accent:#a86fe0}

.htm-app > * + *{margin-top:clamp(3.5rem, 7vw, 6.5rem)}

.htm-eyebrow{
  margin:0 0 1rem;
  color:var(--app-accent);
  font-size:.8rem;
  font-weight:700;
  letter-spacing:.16em;
  text-transform:uppercase}

/* ---------------------------------------------------------------
   Hero.
   --------------------------------------------------------------- */

.htm-app-hero{
  position:relative;
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(280px,380px);
  gap:clamp(2rem, 5vw, 5rem);
  align-items:center;
  padding:clamp(1rem, 3vw, 3rem) 0 clamp(1rem, 2vw, 2rem)}

/* The glow the old site got from four stacked gradients on <body>. Scoped to
   the hero so it cannot leak onto the rest of the site's pages.

   The horizontal insets are 0, not negative. Bleeding the glow sideways put its
   right edge past the viewport at every width below about 1400px, and an
   absolutely positioned box still counts toward scrollWidth: the page grew a
   horizontal scrollbar and could be dragged sideways, taking real content off
   screen. The bleed is kept vertically, where the page scrolls anyway. */
.htm-app-hero::before{
  content:"";
  position:absolute;
  inset:-14% 0 -20% 0;
  z-index:0;
  pointer-events:none;
  background:
    radial-gradient(58% 62% at 78% 8%, var(--app-glow), transparent 62%),
    radial-gradient(46% 52% at 4% 4%, rgba(232,200,106,.05), transparent 60%)}

.htm-app-hero > *{position:relative;z-index:1}

.htm-app-hero h1{
  margin:0 0 1rem;
  font-size:clamp(2.7rem, 6.4vw, 4.8rem);
  line-height:1.02;
  letter-spacing:-.03em}

.htm-app-tagline{
  margin:0 0 1.4rem;
  color:var(--app-accent);
  font-size:clamp(1.1rem, 2vw, 1.4rem);
  font-weight:600;
  line-height:1.25}

.htm-app-lede{
  margin:0 0 2rem;
  max-width:34em;
  font-size:clamp(1.08rem, 1.6vw, 1.3rem);
  line-height:1.6}

.htm-app-actions{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:.9rem 1.4rem;
  margin:0 0 2.4rem}

/* ---------------------------------------------------------------
   Stat strip. A <dl>, so the number and its label stay associated.
   --------------------------------------------------------------- */

.htm-app-stats{
  display:grid;
  grid-template-columns:repeat(3, minmax(0,1fr));
  gap:.9rem;
  margin:0;
  max-width:640px}

.htm-app-stats > div{
  border:1px solid var(--app-line);
  border-radius:14px;
  padding:1.1rem 1.2rem;
  background:var(--app-surface)}

.htm-app-stats dt{
  margin:0;
  color:var(--app-accent);
  font-size:clamp(1.15rem, 2.2vw, 1.6rem);
  font-weight:700;
  line-height:1.1;
  letter-spacing:-.01em}

.htm-app-stats dd{
  margin:.4rem 0 0;
  color:var(--wp--preset--color--muted);
  font-size:.9rem;
  line-height:1.35}

/* ---------------------------------------------------------------
   Device frame.

   The old site's `.phone-frame` was a fake app screen built out of divs, which
   is exactly why the port had to throw it away. Same frame, rebuilt to hold a
   real 1320x2868 simulator capture.
   --------------------------------------------------------------- */

.htm-shot{
  position:relative;
  width:min(100%, 340px);
  margin-inline:auto;
  border:11px solid #050506;
  border-radius:52px;
  background:#050506;
  box-shadow:0 30px 70px rgba(0,0,0,.65), 0 0 0 1px var(--app-edge)}

/* Volume and power buttons. */
.htm-shot::before,
.htm-shot::after{
  content:"";
  position:absolute;
  width:3px;
  background:#050506;
  border-radius:3px}
.htm-shot::before{left:-14px;  top:19%; height:13%}
.htm-shot::after {right:-14px; top:26%; height:15%}

.htm-shot-screen{
  position:relative;
  margin:0;
  overflow:hidden;
  border-radius:42px;
  background:#0a090c;
  line-height:0}

.htm-shot-screen img{
  display:block;
  width:100%;
  height:auto;
  border-radius:42px}

/* Dynamic Island, drawn over the capture. A simulator screenshot is the
   framebuffer, so the cutout is not in the image.
   The inner hairline matters: every app here is dark, so a pure-black pill on
   a black status bar is invisible and the frame reads as a flat slab rather
   than a current iPhone. */
.htm-shot-screen::after{
  content:"";
  position:absolute;
  top:2.3%;
  left:50%;
  z-index:2;
  width:33%;
  aspect-ratio:88/27;
  transform:translateX(-50%);
  border-radius:999px;
  background:#000;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.10)}

/* Fallback screen for an app with no capture yet: the poster wall from the old
   site's Movie Canvas mockup, which is a fair likeness of what it renders. */
.htm-shot-posters{
  display:grid;
  grid-template-columns:repeat(3, minmax(0,1fr));
  gap:9px;
  aspect-ratio:1320/2868;
  align-content:start;
  /* Top inset clears the Dynamic Island; centred, the first row ran under it
     and the pill read as a hole punched in a poster. Percentage padding
     resolves against WIDTH even for the top edge, and the island's bottom sits
     at about 15% of the width down, so this is 19% of width, not of height. */
  padding:19% 14px 14px;
  background:
    radial-gradient(120% 60% at 50% 0%, color-mix(in srgb, var(--app-accent) 20%, transparent), transparent 62%),
    linear-gradient(160deg, #1a1414, #12100f 60%, #0a090c)}

.htm-shot-posters span{
  aspect-ratio:2/3;
  border-radius:6px;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.06)}
.htm-shot-posters span:nth-child(9n+1){background:linear-gradient(160deg,#e5a24a,#a6631f)}
.htm-shot-posters span:nth-child(9n+2){background:linear-gradient(160deg,#3f6f8f,#14212c)}
.htm-shot-posters span:nth-child(9n+3){background:linear-gradient(160deg,#ec6a5a,#7a2417)}
.htm-shot-posters span:nth-child(9n+4){background:linear-gradient(160deg,#3fbfae,#14403a)}
.htm-shot-posters span:nth-child(9n+5){background:linear-gradient(160deg,#f0cf7c,#b7822a)}
.htm-shot-posters span:nth-child(9n+6){background:linear-gradient(160deg,#6f8bf0,#26305e)}
.htm-shot-posters span:nth-child(9n+7){background:linear-gradient(160deg,#e578a0,#6e2340)}
.htm-shot-posters span:nth-child(9n+8){background:linear-gradient(160deg,#2c2a33,#15141a)}
.htm-shot-posters span:nth-child(9n+9){background:linear-gradient(160deg,#c98a3a,#5e3a12)}

/* ---------------------------------------------------------------
   Screenshot gallery.

   A scroll-snap rail rather than a JS carousel: trackpad, touch, shift+wheel
   and keyboard all work by default because it is only a scroll container.
   Same mechanics as the homepage review rail, scoped separately so the two
   never fight.
   --------------------------------------------------------------- */

.htm-app-gallery{position:relative}

.htm-app-rail{
  display:flex;
  gap:clamp(1.5rem, 3vw, 2.5rem);
  overflow-x:auto;
  scroll-snap-type:x mandatory;
  padding:.5rem .25rem 1.5rem;
  margin:0;
  list-style:none;
  scrollbar-width:thin;
  scrollbar-color:color-mix(in srgb, var(--app-accent) 50%, transparent) transparent}

.htm-app-rail::-webkit-scrollbar{height:8px}
.htm-app-rail::-webkit-scrollbar-thumb{
  background:color-mix(in srgb, var(--app-accent) 45%, transparent);
  border-radius:999px}
.htm-app-rail::-webkit-scrollbar-track{background:transparent}

.htm-app-rail > .htm-shot-item{
  flex:0 0 clamp(230px, 24vw, 300px);
  scroll-snap-align:start;
  margin:0}

.htm-shot-item .htm-shot{width:100%}

.htm-shot-caption{
  margin:1.1rem 0 0;
  color:var(--wp--preset--color--muted);
  font-size:.95rem;
  line-height:1.4;
  text-align:center}

/* "there is more to the right", which a flat cut-off does not say. */
.htm-app-gallery::after{
  content:"";
  position:absolute;
  top:0;
  right:0;
  bottom:1.5rem;
  width:72px;
  pointer-events:none;
  background:linear-gradient(90deg, rgba(0,0,0,0), #000 85%)}

/* ---------------------------------------------------------------
   Section headings.
   --------------------------------------------------------------- */

.htm-section-head{
  max-width:820px;
  margin:0 0 clamp(1.8rem, 3vw, 2.8rem)}

.htm-section-head h2{
  margin:0;
  font-size:clamp(1.9rem, 3.6vw, 3rem);
  line-height:1.08;
  letter-spacing:-.025em}

.htm-section-head em{color:var(--app-accent);font-style:italic}

/* ---------------------------------------------------------------
   Feature grid.
   --------------------------------------------------------------- */

.htm-app-features{
  display:grid;
  grid-template-columns:repeat(3, minmax(0,1fr));
  gap:1.1rem}

.htm-feature{
  display:flex;
  flex-direction:column;
  min-height:250px;
  border:1px solid var(--app-line);
  border-radius:18px;
  padding:clamp(1.5rem, 2.4vw, 2rem);
  background:var(--app-surface);
  transition:border-color .18s ease, transform .18s ease}

.htm-feature:hover{border-color:var(--app-edge);transform:translateY(-3px)}

/* Fixed gap, not `margin-bottom:auto`. Pushing the text to the bottom of a
   250px card left a ~140px hole under the bar on every short card. */
.htm-feature .htm-mark{
  display:block;
  width:48px;
  height:6px;
  margin:0 0 1.75rem;
  border-radius:8px;
  background:var(--app-accent)}

.htm-feature h3{
  margin:0 0 .6rem;
  font-size:1.25rem;
  line-height:1.25;
  letter-spacing:-.01em}

.htm-feature p{
  margin:0;
  color:var(--wp--preset--color--muted);
  font-size:1rem;
  line-height:1.55}

/* Feature fold. One row is shown, the rest sit behind a native <details>.
   Styled as a quiet pill rather than a button so it does not compete with the
   real call to action further down the page. */
.htm-app-fold{margin:1.1rem 0 0}

.htm-app-fold > summary{
  list-style:none;
  cursor:pointer;
  display:flex;
  align-items:center;
  justify-content:center;
  gap:.6rem;
  width:fit-content;
  margin-inline:auto;
  padding:.75rem 1.5rem;
  border:1px solid var(--app-line);
  border-radius:999px;
  color:var(--wp--preset--color--muted);
  font-size:.95rem;
  font-weight:600;
  transition:border-color .18s ease, color .18s ease}

.htm-app-fold > summary::-webkit-details-marker{display:none}

.htm-app-fold > summary:hover{
  border-color:var(--app-accent);
  color:var(--wp--preset--color--contrast)}

.htm-app-fold > summary::after{
  content:"";
  flex:none;
  width:.55rem;
  height:.55rem;
  margin-top:-.2rem;
  border-right:2px solid var(--app-accent);
  border-bottom:2px solid var(--app-accent);
  transform:rotate(45deg);
  transition:transform .2s ease}

.htm-app-fold[open] > summary::after{
  transform:rotate(-135deg);
  margin-top:.2rem}

/* Only one of the two labels is ever shown, so the summary reads correctly in
   both states without any script. */
.htm-app-fold[open] .htm-fold-shut,
.htm-app-fold:not([open]) .htm-fold-open{display:none}

.htm-app-fold .htm-fold-body{margin-top:1.1rem}

/* ---------------------------------------------------------------
   Pull quotes.
   --------------------------------------------------------------- */

.htm-app-quotes{
  display:grid;
  grid-template-columns:minmax(0,.92fr) minmax(320px,1.08fr);
  gap:clamp(2rem, 4vw, 3.5rem);
  align-items:start}

.htm-app-quotes .htm-section-head{margin-bottom:0}

.htm-quote-stack{display:grid;gap:1rem;margin:0}

.htm-quote-stack figure{
  margin:0;
  border:1px solid var(--app-line);
  border-left:6px solid var(--app-accent);
  border-radius:14px;
  padding:clamp(1.3rem, 2.2vw, 1.8rem);
  background:var(--app-surface)}

.htm-quote-stack figure:nth-child(2){
  border-left-color:color-mix(in srgb, var(--app-accent) 55%, #ffffff)}
.htm-quote-stack figure:nth-child(3){
  border-left-color:color-mix(in srgb, var(--app-accent) 45%, #2a2a2f)}

.htm-quote-stack blockquote{
  margin:0 0 .8rem;
  padding:0;
  border:0;
  color:var(--wp--preset--color--contrast);
  font-size:clamp(1.25rem, 2.2vw, 1.7rem);
  font-weight:500;
  line-height:1.2;
  letter-spacing:-.015em}

.htm-quote-stack figcaption{
  margin:0;
  color:var(--wp--preset--color--muted);
  font-size:.9rem;
  font-weight:600;
  letter-spacing:.04em;
  text-transform:uppercase}

/* ---------------------------------------------------------------
   Launch strip and closing panel.
   --------------------------------------------------------------- */

.htm-app-cta,
.htm-app-panel{
  display:grid;
  grid-template-columns:minmax(0,1.05fr) minmax(260px,.95fr);
  gap:clamp(1.5rem, 3vw, 3rem);
  align-items:center;
  border:1px solid var(--app-line);
  border-radius:var(--app-radius);
  padding:clamp(1.8rem, 4vw, 3.2rem);
  background:
    radial-gradient(110% 130% at 100% 0%, var(--app-glow), transparent 58%),
    var(--app-surface)}

.htm-app-cta h2,
.htm-app-panel h2{
  margin:0;
  font-size:clamp(1.6rem, 3vw, 2.5rem);
  line-height:1.1;
  letter-spacing:-.02em}

.htm-app-cta p,
.htm-app-panel p{
  margin:.9rem 0 0;
  color:var(--wp--preset--color--muted);
  font-size:1.05rem;
  line-height:1.6}

/* Colour repeated, not inherited: `.htm-app-cta p` above is a tag selector and
   beats the single class on `.htm-eyebrow`, which turned these two eyebrows
   muted grey while every other one on the page was gold. */
.htm-app-cta .htm-eyebrow,
.htm-app-panel .htm-eyebrow{margin-bottom:.7rem;color:var(--app-accent)}

.htm-app-panel{align-items:start}
.htm-app-panel > div:last-child > :first-child{margin-top:0}

/* ---------------------------------------------------------------
   /apps/ index.
   --------------------------------------------------------------- */

.htm-apps-hero{
  max-width:900px;
  padding:clamp(1rem, 3vw, 2.5rem) 0 clamp(2rem, 4vw, 3rem)}

.htm-apps-hero h1{
  margin:0 0 1.2rem;
  font-size:clamp(2.4rem, 5.4vw, 4.2rem);
  line-height:1.03;
  letter-spacing:-.03em}

.htm-apps-hero p{
  margin:0;
  font-size:clamp(1.08rem, 1.7vw, 1.35rem);
  line-height:1.55}

.htm-apps-grid{
  display:grid;
  grid-template-columns:repeat(2, minmax(0,1fr));
  gap:1.4rem}

.htm-apps-card{
  display:flex;
  flex-direction:column;
  border:1px solid var(--app-line);
  border-top:5px solid var(--app-accent);
  border-radius:18px;
  padding:clamp(1.6rem, 3vw, 2.4rem);
  background:var(--app-surface);
  box-shadow:0 18px 44px rgba(0,0,0,.4)}

.htm-apps-card-head{
  display:flex;
  align-items:flex-start;
  gap:1.2rem;
  margin:0 0 1.4rem}

/* Four of the five app icons are gold artwork on a black tile, so on a #0e0e10
   card they read as nothing at all: the icon is there, it just has no edge, and
   each one ends up looking the size of its own glyph rather than the size of
   the tile. A 1px rgba(255,255,255,.14) ring was not enough. A white plate is,
   and it matches the homepage strip.

   Padding on the <img> rather than a wrapper: border-radius on a replaced
   element clips the image to the PADDING box, so 24px outside minus 2px of
   padding rounds the icon itself at 22px, concentric with the plate. 22px on a
   96px icon is 23%, about the proportion an iOS icon already has. */
.htm-apps-card-head img{
  flex:none;
  box-sizing:border-box;
  width:100px;
  height:100px;
  padding:2px;
  background:#fff;
  border-radius:24px;
  box-shadow:0 12px 28px rgba(0,0,0,.5)}

.htm-apps-card-head h2{
  margin:0 0 .3rem;
  font-size:clamp(1.5rem, 2.6vw, 2rem);
  line-height:1.1;
  letter-spacing:-.02em}

/* The icon is now a link, so it is the flex item and carries the sizing the
   img used to. Without this the icon stretches to the head's full height. */
.htm-apps-card-head > .htm-apps-card-link{
  flex:none;
  display:block;
  border-radius:24px}

/* Named explicitly rather than left to inherit: a bare `a` colour from the
   theme wins over the h2 it sits inside, which is the same one-level-up
   specificity trap that turned two of the eyebrows grey. */
.htm-apps-card-head h2 .htm-apps-card-link{
  color:inherit;
  text-decoration:none}

.htm-apps-card-head h2 .htm-apps-card-link:hover,
.htm-apps-card-head h2 .htm-apps-card-link:focus-visible{
  color:var(--wp--preset--color--gold)}

.htm-apps-card-head .htm-apps-card-link:focus-visible{
  outline:2px solid var(--wp--preset--color--gold);
  outline-offset:4px;
  border-radius:6px}

.htm-apps-card-tag{
  margin:0;
  color:var(--wp--preset--color--muted);
  font-size:.98rem;
  line-height:1.35}

.htm-status{
  display:inline-flex;
  align-items:center;
  gap:.45rem;
  margin:.7rem 0 0;
  border-radius:999px;
  padding:.25rem .7rem;
  font-size:.72rem;
  font-weight:700;
  letter-spacing:.08em;
  text-transform:uppercase}

.htm-status::before{
  content:"";
  width:7px;
  height:7px;
  border-radius:50%;
  background:currentColor}

.htm-status.is-live{
  border:1px solid rgba(33,179,102,.4);
  background:rgba(33,179,102,.12);
  color:#7fe8ab}

.htm-status.is-soon{
  border:1px solid var(--app-line);
  background:#17171a;
  color:var(--wp--preset--color--muted)}

.htm-apps-card > p{
  margin:0 0 1.2rem;
  color:var(--wp--preset--color--muted);
  font-size:1.03rem;
  line-height:1.55}

.htm-apps-card ul{
  margin:0 0 1.8rem;
  padding-left:1.15rem;
  color:var(--wp--preset--color--muted);
  font-size:.98rem}

.htm-apps-card li + li{margin-top:.5rem}

.htm-apps-card .htm-app-actions{margin:auto 0 0}

/* ---------------------------------------------------------------
   Support and privacy pages.
   --------------------------------------------------------------- */

/* Columns rather than a grid. These four cards have wildly different heights
   (a two-line Contact card next to a six-question FAQ), and a two-column grid
   is row-based, so the short one left a card-and-a-half of empty space under
   itself. Columns flow instead of aligning, which closes the hole. */
.htm-app-support{
  column-count:2;
  column-gap:1.2rem}

.htm-app-support > .htm-card{
  break-inside:avoid;
  margin:0 0 1.2rem}

.htm-card{
  border:1px solid var(--app-line);
  border-radius:18px;
  padding:clamp(1.5rem, 2.6vw, 2.2rem);
  background:var(--app-surface)}

.htm-card.is-featured{
  border-color:var(--app-edge);
  background:
    linear-gradient(135deg, var(--app-wash), transparent 60%),
    #17171a}

.htm-card h2{
  margin:0 0 1rem;
  font-size:1.4rem;
  line-height:1.2;
  letter-spacing:-.015em}

.htm-card p,
.htm-card li{
  color:var(--wp--preset--color--muted);
  font-size:1rem;
  line-height:1.6}

.htm-card > p:last-child,
.htm-card > ul:last-child{margin-bottom:0}

.htm-faq{margin:0}
.htm-faq dt{
  margin:1.4rem 0 0;
  color:var(--wp--preset--color--contrast);
  font-weight:600;
  font-size:1.02rem;
  line-height:1.35}
.htm-faq dt:first-child{margin-top:0}
.htm-faq dd{
  margin:.5rem 0 0;
  color:var(--wp--preset--color--muted);
  font-size:1rem;
  line-height:1.6}

/* Legal pages stay at a reading measure even though the wrapper is wide. */
.htm-app-legal{
  max-width:900px;
  margin-inline:auto}

.htm-app-legal .htm-card h2{
  margin-top:2.2rem;
  font-size:1.25rem}
.htm-app-legal .htm-card > :first-child{margin-top:0}

.htm-app-legal .htm-card p{margin:0 0 1rem}

/* Both secondary pages open with a smaller hero than a landing page. */
.htm-page-head{
  max-width:820px;
  padding:clamp(1rem, 3vw, 2.5rem) 0 clamp(1.5rem, 3vw, 2.5rem)}

.htm-page-head h1{
  margin:0 0 1rem;
  font-size:clamp(2.2rem, 5vw, 3.8rem);
  line-height:1.05;
  letter-spacing:-.03em}

.htm-page-head p{
  margin:0;
  font-size:clamp(1.05rem, 1.6vw, 1.25rem);
  line-height:1.55}

/* ---------------------------------------------------------------
   Shared bits.
   --------------------------------------------------------------- */

/* The theme underlines content links on hover, which on a whole-card link
   underlines the card. More specific than anything scoped here, hence the
   !important, same as the Browse page. */
.htm-apps-card a.htm-linkish,
.htm-app a.htm-linkish{
  color:var(--wp--preset--color--gold);
  font-weight:600;
  text-decoration:none !important}
.htm-apps-card a.htm-linkish:hover,
.htm-app a.htm-linkish:hover{
  color:var(--wp--preset--color--contrast);
  text-decoration:underline !important}

/* Buttons come from the theme's button element (gold pill), so only the
   spacing inside these rows is set here. */
.htm-app .wp-block-buttons,
.htm-apps .wp-block-buttons{margin:0}

/* ---------------------------------------------------------------
   Narrow screens.
   --------------------------------------------------------------- */

@media (max-width:880px){
  .htm-app-hero{grid-template-columns:1fr;gap:2.5rem}
  .htm-app-hero .htm-shot{margin-inline:0}
  .htm-app-features{grid-template-columns:repeat(2, minmax(0,1fr))}
  .htm-app-quotes{grid-template-columns:1fr}
  .htm-app-cta,
  .htm-app-panel{grid-template-columns:1fr;align-items:start}
  .htm-apps-grid{grid-template-columns:1fr}
  .htm-app-support{grid-template-columns:1fr}
}

@media (max-width:600px){
  .htm-app > * + *{margin-top:3rem}
  .htm-app-features{grid-template-columns:1fr}
  .htm-feature{min-height:0}
  .htm-app-stats{gap:.5rem}
  .htm-app-stats > div{padding:.85rem .9rem}
  .htm-app-stats dd{font-size:.8rem}
  .htm-shot{border-width:9px;border-radius:44px}
  .htm-shot-screen,
  .htm-shot-screen img{border-radius:36px}
  .htm-app-rail > .htm-shot-item{flex-basis:74vw}
  .htm-app-gallery::after{width:32px}
  .htm-apps-card-head{gap:.9rem}
  /* Same 2px plate margin as the desktop rule, so an 80px plate holds a 76px
     icon. The link radius follows the plate or the focus ring cuts it. */
  .htm-apps-card-head img{width:80px;height:80px;border-radius:20px}
  .htm-apps-card-head > .htm-apps-card-link{border-radius:20px}
}

@media (prefers-reduced-motion:reduce){
  .htm-feature{transition:none}
  .htm-feature:hover{transform:none}
  .htm-app-fold > summary,
  .htm-app-fold > summary::after{transition:none}
}
/* Front page: the hero, and the four rating cards under it. */

/* The hero cover carries white text over whatever backdrop the newest review
   happens to have, so it needs darkness somewhere. It used to get that from the
   vertical fade alone, which had to be heavy enough to hold text at the vertical
   middle of the frame and therefore blacked out the artwork everywhere: 61% of
   the poster was gone by the halfway line.

   The text only occupies the left 800px of a 1216px cover, so the darkness
   belongs there. A left-weighted scrim carries the type, the vertical fade drops
   to a fraction of its old strength, and the right of the frame stays bright.

   Both scrims were eased by about a third on 2026-08-05: the pair still
   multiplied to 62% black at the top left, 86% at mid height and 97% along the
   bottom band, and the artwork read as washed out. Combined coverage now runs
   42% top left, 66% at mid height and 84% under the title, which the text-shadow
   below tops up. The two layers are pure black, so they composite as
   1-(1-a)(1-b): easing one alone leaves the other carrying its full share, which
   is why the vertical fade in theme.json moved at the same time.

   z-index 0, not something above the text. Core stacks the cover's children as
   image 0, then overlay and inner container at 1, so 0 puts the scrim over the
   image (later in tree order at the same level) and under both the gradient and
   the type. Raising the inner container instead does not work: core's rule is
   prefixed `body:not(.editor-styles-wrapper)`, so it outranks anything scoped to
   .htm-hero and the scrim ends up greying out its own title. Both scrims are
   pure black, so compositing under the gradient rather than over it looks
   identical. */
.htm-hero::after{content:"";position:absolute;inset:0;z-index:0;
  pointer-events:none;border-radius:inherit;
  background:linear-gradient(90deg, rgba(0,0,0,.42) 0%, rgba(0,0,0,.28) 38%, rgba(0,0,0,0) 74%)}

.htm-hero .wp-block-post-title a,
.htm-hero .wp-block-post-excerpt{text-shadow:0 2px 18px rgba(0,0,0,.75)}

/* On a phone the text spans the full width, so a left-weighted scrim would leave
   the end of every line unshielded. This one must never reach zero, which is why
   it was eased proportionally rather than given the desktop scrim's fade-out.

   Still 781px, and still live: it carries the 601-781px band, between the phone
   layout below and the desktop one above. */
@media (max-width:781px){
  .htm-hero::after{
    background:linear-gradient(90deg, rgba(0,0,0,.40) 0%, rgba(0,0,0,.34) 60%, rgba(0,0,0,.24) 100%)}
}

/* PHONES: the card stops being a cropped frame.

   Scrims were never the mobile problem, geometry was. The cover is pinned to
   min-height:520px at every width, and the featured image is a 16:9 TMDb
   backdrop that core fills the frame with using object-fit:cover and a dead
   centre object-position (no focal point is set in the block attrs). On a 390px
   phone the card is 327x520 once the page padding is off, ratio 0.63 against
   the source's 1.78, so the image scales to about 926px wide and you see 327 of
   it: 35% of the frame, from the middle, at a 2.8x blow-up. Faces and any sense
   of the scene fall outside the crop, and it gets worse the narrower the phone
   (32% at 360).

   So below the breakpoint the backdrop becomes a full-width 16:9 band at the
   top of the card and the text sits under it on `surface`. Nothing is cropped
   at all: measured, 99-100% of the frame survives at every width this rule
   covers. Overall height is about what it was, because the band is only as tall
   as 16:9 makes it: 185px of band plus the panel is 515px at a 390 viewport,
   against the old flat 520.

   Desktop keeps the cropped-frame design above, where it works: the box is
   1240x520 (2.38) and the crop only trims the top and bottom.

   600px, NOT the theme's usual 781. Measured across the range, the crop stops
   being the problem well before the stacking breakpoint: the card shows 35% of
   the frame at a 390px viewport, 40% at 430, 58% at 600 and 78% at 781, where
   the old design is fine. Restructuring up there also costs more than it buys,
   because the band scales with the card: at 781 it is 718x405, which pushes the
   hero to 705px tall against 520 at 782, a 185px jump across one pixel of
   viewport. Every phone in portrait is under 600. */
@media (max-width:600px){
  /* min-height and padding are INLINE on the div, from the block's
     minHeight:520 and its two spacing presets, so !important is the only way a
     stylesheet reaches them. That is why these two carry it and nothing else
     here does. Padding moves to the inner container below, because the image
     band has to run edge to edge.

     No overflow:hidden: core already sets it on .wp-block-cover, which is what
     keeps the inline 18px radius clipping the image's top corners now that the
     image is a real in-flow child rather than an absolute fill. */
  .htm-hero{
    min-height:0 !important;
    padding:0 !important;
    display:block;
    background-color:var(--wp--preset--color--surface)}

  /* Core ships this img absolute, inset 0, height 100%. Taking it into flow in
     a 16:9 box makes its object-fit:cover a no-op: the box now matches the
     source, so the whole backdrop survives. The hairline is what stops a
     dark-bottomed frame from bleeding into the panel underneath it.

     The element selector is load-bearing: core's rule is
     `.wp-block-cover .wp-block-cover__image-background` at (0,2,0), so a
     two-class selector alone would tie and lose on order. */
  .htm-hero img.wp-block-cover__image-background{
    position:static;
    width:100%;
    height:auto;
    aspect-ratio:16/9;
    border-bottom:1px solid var(--wp--preset--color--line)}

  /* Both scrims exist to hold white text over artwork, and no text sits over
     the artwork any more, so all they do now is cost image. Hiding the span
     rather than re-stopping its gradient also disposes of the overlay colour
     that has-background-dim-100 puts there. */
  .htm-hero .wp-block-cover__background{display:none}
  .htm-hero::after{display:none}

  .htm-hero .wp-block-cover__inner-container{
    padding:var(--wp--preset--spacing--40) var(--wp--preset--spacing--40)
            var(--wp--preset--spacing--50)}

  .htm-hero .wp-block-post-title a,
  .htm-hero .wp-block-post-excerpt{text-shadow:none}
}

/* The emoji is the whole point of the card, so it is set large and given its own
   line. WordPress swaps emoji for Twemoji images sized in em, which is why this
   is a font-size and not a width. */
.htm-face{line-height:1}

/* Section ledes.

   Every section group on the front page now carries a 1240px contentSize, so a
   heading and the card row under it start at the same left edge instead of the
   heading sitting 240px inside its own cards. That is right for headings and
   grids and wrong for prose: these three paragraphs would run to about 150
   characters a line.

   Capping the measure is only half of it. The same core rule also centres every
   child with `margin-left/right: auto`, so a narrower paragraph would sit
   centred under a left-aligned heading, which looks more broken than the long
   line does. Killing the auto margins is what keeps it on the rail.

   Hence the doubled class and the !important, which are both load-bearing. Core
   emits `.wp-container-<hash> > :where(:not(.alignleft):not(.alignright):not(
   .alignfull))`, and :where() contributes nothing, so that scores one class,
   exactly what a single `.htm-lede` scores. A tie goes to whichever is printed
   last, and core's layout CSS ships in `core-block-supports-inline-css`, which
   the page prints after this file's `global-styles-inline-css`. So core wins
   every tie here and both declarations were silently dropped.

   Doubling the class to two classes settles max-width, because core's is a
   normal declaration. It is not enough for the margins on its own: core marks
   those !important, and !important beats a normal declaration at any
   specificity, so the override has to be !important AND outrank it. Verified on
   staging both ways round. */
.htm-lede.htm-lede{max-width:68ch;margin-inline:0 !important}

/* Both four-card rows on this page ("Our rating system" and "Find something to
   watch") hold copy of wildly different lengths, from three words to eleven, so
   left to themselves they end in four different places and read as a mistake
   rather than a set. Columns already stretch; it is the card inside each one
   that sizes to its text. */
.htm-evencols .wp-block-column{display:flex}
.htm-evencols .wp-block-column > .wp-block-group{flex:1}

/* build_featured_collections.py lays its cards out three to a row and pads a
   short last row with empty columns, so a row of one or two keeps the card
   width of the rows above instead of stretching a lone card across 1240px.
   Below core's stacking breakpoint every column becomes full width, and each of
   those placeholders would then contribute a block gap of nothing. Six featured
   collections divide evenly and never hit this, which is exactly why it would
   go unnoticed the first time somebody features a seventh. */
@media (max-width: 781px){
  .htm-evencols .wp-block-column:empty{display:none}
}

/* CAST AND CREW BIRTHDAYS, generated by build_birthdays.py.

   Shares the seasonal slot: a season wins when one is running and this fills the
   rest of the year, which is 360 days of it. That sharing is why none of these
   rules may touch the --htm-season-* custom properties the shelf above uses.
   Those are a per-season palette that only exists while a season is active, so
   here they would resolve to nothing and take the colour with them. Base tokens
   only. */
.htm-birthdays{margin-top:var(--wp--preset--spacing--60)}
/* The section ships hidden and the resolver clears the attribute. Stated
   explicitly because any later rule that sets display on .htm-birthdays would
   otherwise beat the UA sheet and reveal all 146 cards on every day of the
   year. */
.htm-birthdays[hidden]{display:none}

.htm-bd-inner{border:1px solid var(--wp--preset--color--line);border-radius:18px;
  background:var(--wp--preset--color--surface);
  padding:var(--wp--preset--spacing--50)}

.htm-bd-head{display:flex;flex-wrap:wrap;align-items:baseline;
  justify-content:space-between;gap:.5rem 1.5rem}
.htm-bd-title{margin:0;font-size:clamp(1.4rem,1.1rem + 1.2vw,2rem);
  line-height:1.15}
.htm-bd-blurb{margin:0;color:var(--wp--preset--color--muted);font-size:.95rem}

.htm-bd-rail{display:flex;gap:1.25rem;list-style:none;padding:0 0 .5rem;
  margin:var(--wp--preset--spacing--40) 0 0;
  overflow-x:auto;scroll-snap-type:x proximity;
  scrollbar-width:thin;
  scrollbar-color:var(--wp--preset--color--line) transparent}
.htm-bd-rail::-webkit-scrollbar{height:8px}
.htm-bd-rail::-webkit-scrollbar-thumb{background:var(--wp--preset--color--line);
  border-radius:4px}
.htm-bd-rail::-webkit-scrollbar-track{background:transparent}

/* A fixed width, not a min. The rail holds anywhere from 3 to 15 people
   depending on the day, and letting the cards size to their names would make
   the row re-flow into a different shape every morning. */
.htm-bd-card{margin:0;flex:0 0 auto;width:110px;scroll-snap-align:start}
.htm-bd-card[hidden]{display:none}
.htm-bd-card a{display:block;text-decoration:none;color:inherit;text-align:center;
  transition:transform .15s ease}
.htm-bd-card a:hover,
.htm-bd-card a:focus-visible{transform:translateY(-3px)}
.htm-bd-card a:focus-visible{outline:2px solid var(--wp--preset--color--gold);
  outline-offset:6px;border-radius:12px}

/* Explicit dimensions hold the rail's height before any portrait has decoded,
   and on production they are what Photon reads to decide what to serve. The
   same reasoning as the seasonal shelf's posters. */
.htm-bd-face{display:block;width:96px;height:96px;margin:0 auto;
  border-radius:999px;object-fit:cover;object-position:50% 20%;
  background:var(--wp--preset--color--surface-raised);
  box-shadow:0 6px 16px rgba(0,0,0,.45)}
/* object-position sits above centre on purpose: TMDb profile shots are portrait
   crops, so a dead-centre circular mask cuts the chin and keeps the chest. */
.htm-bd-face--none{box-shadow:none;
  border:1px dashed var(--wp--preset--color--line)}

.htm-bd-name{display:block;margin-top:.55rem;font-size:.82rem;line-height:1.25;
  font-weight:600}
.htm-bd-meta{display:block;margin-top:.15rem;font-size:.72rem;
  color:var(--wp--preset--color--muted)}
.htm-bd-date{display:block}
.htm-bd-films{display:block;opacity:.75}

/* Today gets the gold, so a rail that spans two and a half weeks still answers
   "who is it actually today" at a glance. */
.htm-bd-card[data-today] .htm-bd-name{color:var(--wp--preset--color--gold)}
.htm-bd-card[data-today] .htm-bd-face{box-shadow:0 0 0 2px var(--wp--preset--color--gold),
  0 6px 16px rgba(0,0,0,.45)}
.htm-bd-card[data-today] .htm-bd-date::after{content:" (today)"}

/* The resolver opens the rail with today in the middle rather than at the
   oldest card, because the window runs oldest first and today's people would
   otherwise start off the right edge. The rail snaps on proximity, so without
   this the centred position gets pulled back to the nearest snap-align:start
   edge, up to half a card away. Making the card the rail rests on its own
   centre snap point turns snapping into an ally instead of a fight.

   data-anchor is the stand-in the resolver marks on the next person up when
   nobody was born today, which is most days. */
.htm-bd-card[data-today],
.htm-bd-card[data-anchor]{scroll-snap-align:center}

/* Arrows, injected by the resolver and styled by .htm-rail-nav in browse.css,
   which is the same pair the reviews rail uses. Only their placement is local:
   margin-left:auto absorbs the head's free space so the title and blurb stay
   together on the left instead of being spread apart by a third child, and
   align-self overrides the head's baseline alignment, which a 40px round button
   does not sit on. */
.htm-bd-head .htm-rail-nav{margin-left:auto;align-self:center}

@media (max-width: 781px){
  .htm-bd-inner{padding:var(--wp--preset--spacing--40)}
  .htm-bd-card{width:96px}
  .htm-bd-face{width:80px;height:80px}
}

/* The apps card.

   The heading is the link to /apps/ and each icon is the link to that app's own
   page, so the section offers both altitudes without a second button competing
   with the real one below it. The heading link therefore has to keep looking
   like a heading: it inherits its size and colour and only picks up gold on
   hover, which is how every other inline link on the site behaves. */
.htm-apps-head a{color:inherit;text-decoration:none;
  transition:color .15s ease}
.htm-apps-head a:hover,
.htm-apps-head a:focus-visible{color:var(--wp--preset--color--gold)}

/* Icons rather than a list of names: five marks a reader may already recognise
   from their home screen read faster than five product names, and they carry
   the section without turning it into a second hero. */
.htm-appstrip{display:flex;flex-wrap:wrap;gap:1.75rem;
  list-style:none;padding:0;
  margin:var(--wp--preset--spacing--40) 0 0}
.htm-appstrip-item{margin:0}
.htm-appstrip a{display:flex;flex-direction:column;align-items:center;gap:.55rem;
  width:5.5rem;text-decoration:none;color:var(--wp--preset--color--muted);
  transition:transform .15s ease, color .15s ease}
/* A white plate, not a hairline. Four of the five icons are gold artwork on a
   near-black tile, so on the section's near-black surface their edges vanish
   and each one reads as the size of its own gold glyph rather than the size of
   the tile: the book fills its square, the "HTM" circle sits small inside one.
   A 1px #2a2a2f line was not enough to bring the edge back. White gives all
   five the same outline at the same size.

   Padding on the <img> needs no markup change. border-radius on a replaced
   element clips the image to the PADDING box, so 20px outside minus 2px of
   padding leaves the icon itself rounded at 18px, concentric with the plate.
   18px on a 76px icon is 24%, near enough to the ~22% an iOS icon already has
   that the corner still looks like the one on the home screen. */
.htm-appstrip img{display:block;box-sizing:border-box;
  width:80px;height:80px;padding:2px;border:0;
  background:#fff;border-radius:20px;
  box-shadow:0 8px 20px rgba(0,0,0,.5)}
.htm-appstrip span{font-size:.8rem;line-height:1.25;text-align:center}
.htm-appstrip a:hover,
.htm-appstrip a:focus-visible{transform:translateY(-2px);
  color:var(--wp--preset--color--gold)}
.htm-appstrip a:focus-visible{outline:2px solid var(--wp--preset--color--gold);
  outline-offset:6px;border-radius:8px}

/* Footer socials. `is-style-logos-only` drops the coloured pill and paints the
   glyph in the current colour, which is what lets a muted grey mark sit quietly
   next to the text links instead of becoming the loudest thing in the footer.
   Gold on hover matches every other link on the site.

   The colour is set on the <li>, not on the anchor. Core styles the anchor
   `color:currentColor` at a specificity of five classes, so an anchor rule here
   would lose; the anchor inherits from the list item instead. Core's own
   per-service colours are wrapped in :where() and carry no specificity, so
   these two selectors are enough. */
.htm-social.wp-block-social-links{margin-bottom:0}

.htm-social .wp-social-link{
  color:var(--wp--preset--color--muted);
  transition:transform .15s ease, color .15s ease}

.htm-social .wp-social-link:hover,
.htm-social .wp-social-link:focus-within{
  color:var(--wp--preset--color--gold);
  transform:translateY(-2px)}

.htm-social .wp-block-social-link-anchor:focus-visible{
  outline:2px solid var(--wp--preset--color--gold);
  outline-offset:4px;
  border-radius:4px}
/* ---------------------------------------------------------------------------
   Tag provenance: is this our opinion, or is it a fact about the film?

   Two surfaces draw the same two groups and have to be indistinguishable:
   /browse/#collections, built by tools/build_browse_page.py, and the "Also
   filed under" panel on every review, built by php/htm-tags.php. So this file
   is NOT scoped to .htm-browse the way browse.css is. The chip lives here,
   unscoped, and browse.css keeps only what is genuinely about that page (the
   smaller chips inside an era card).

   Colours come from the theme.json presets, never from browse.css's
   --htm-gold / --htm-line. Those are declared on .htm-browse and simply do not
   resolve on a review page, and an unresolved var() does not fall back: the
   whole declaration is invalid at computed-value time and border-color reverts
   to currentColor, which on a gold link would paint a gold border on exactly
   the chips that must not have one. It would look perfectly fine on /browse/,
   which is where you would check first.
   --------------------------------------------------------------------------- */

/* The base pill: a fact about the film. Hairline, muted, quiet.

   text-decoration is !important because the theme underlines every content link
   on hover and that rule beats anything reasonable here; this was already true
   when the rule lived in browse.css.

   text-transform and letter-spacing are reset explicitly because the panel this
   replaces inherited both from styles.blocks["core/post-terms"] in theme.json,
   and uppercase renders "FOUNDER'S FAVORITE". */
a.htm-chip{display:inline-flex;align-items:baseline;gap:.45rem;
  padding:.5rem .9rem;border:1px solid var(--wp--preset--color--line);
  border-radius:999px;color:var(--wp--preset--color--muted);
  font-size:var(--wp--preset--font-size--small);
  text-transform:none;letter-spacing:normal;
  text-decoration:none !important;line-height:1.2}
a.htm-chip:hover{border-color:var(--wp--preset--color--gold);
  color:var(--wp--preset--color--contrast)}
a.htm-chip .htm-count{font-size:.8em;opacity:.6}

/* Ours: literally elements.button from theme.json - gold fill, black text,
   999px, weight 600. That is the point. The site has one visual language for
   "this is us speaking", and a tag we applied on purpose belongs in it.
   Black on #e8c86a is 12.9:1, the same as every button already on the site. */
a.htm-chip--ours{background:var(--wp--preset--color--gold);
  border-color:var(--wp--preset--color--gold);
  color:var(--wp--preset--color--base);font-weight:600}
/* Mirrors elements.button:hover (white fill, black text) rather than the link
   hover, so a gold pill never turns gold-on-gold against browse.css's slightly
   different --htm-gold. */
a.htm-chip--ours:hover{background:var(--wp--preset--color--contrast);
  border-color:var(--wp--preset--color--contrast);
  color:var(--wp--preset--color--base)}
/* The theme's focus ring is a gold outline, which on a gold pill reads as a
   thicker pill rather than as focus. */
a.htm-chip--ours:focus,
a.htm-chip--ours:focus-visible{outline-color:var(--wp--preset--color--contrast)}
a.htm-chip--ours .htm-count{opacity:.7}

/* The two groups. Two-class selectors throughout: the label is an h3 competing
   with elements.h3's 1.375rem, and the theme paints every heading white. */
.htm-tagset .htm-taggroup + .htm-taggroup{margin-top:1.4rem}
.htm-tagset .htm-taggroup-label{margin:0 0 .7rem;
  font-size:.8rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--wp--preset--color--muted)}
.htm-tagset .htm-taggroup > ul{list-style:none;margin:0;padding:0;
  display:flex;flex-wrap:wrap;gap:.6rem}
.htm-tagset .htm-taggroup > ul > li{margin:0}
/* No opacity here. Muted at .78rem is already quiet, and dimming it further put
   the one line that credits TMDb underneath the poster-rain layer on /browse/,
   where it was effectively unreadable. */
.htm-tagset .htm-tagnote{margin:.75rem 0 0;font-size:.78rem;
  color:var(--wp--preset--color--muted)}

/* Belt and braces, the same shape as htm_seo_sitemap_entry(). php/htm-tags.php
   already drops every machine tag before it renders, and that is the real
   mechanism. But this markup replaces the core/post-terms wrapper, so
   styles.blocks["core/post-terms"].css in theme.json - the rule that has hidden
   tmdb- links until now - no longer matches it. If the PHP filter ever
   regresses, 433 review pages should not each grow a tmdb-<id> link. */
.htm-tagset a[href*="/tag/tmdb-"],
.htm-tagset a[href*="/tag/htm-"]{display:none}

@media (max-width:600px){
  a.htm-chip{padding:.42rem .75rem;font-size:.92rem}
}

/* The genre-by-verdict groups on /browse/#genre-verdict.

   The chips in these groups are the ordinary hairline pill, because under a
   heading that is the verdict a chip's own text is a genre, and a genre is
   TMDb's. What carries the editorial half is the heading, and it borrows the
   language the page has just finished teaching one section above: the face and
   the accent colour from VERDICT_DESIGN in build_browse_page.py.

   That swap is why this section is not a wall of gold. Forty-four solid pills
   in one block outshouted everything else on the page; Collections is twice the
   size and runs ten gold against thirty-five hairline.

   Two-class selectors for the same reason the rules above use them: the label
   is an h3 competing with elements.h3, and the theme paints every heading
   white, so a single class loses. --v-accent is set inline per group. */
.htm-tagset .htm-facetgroup-label{display:flex;align-items:center;gap:.45rem;
  color:var(--v-accent, var(--wp--preset--color--gold))}
/* Sized off the label rather than the root so it tracks the .8rem heading, and
   line-height 1 so an emoji's own leading does not push the row taller than the
   text beside it. */
.htm-tagset .htm-facetgroup-face{font-size:1.35em;line-height:1}
/* Groups here are rows of one-word chips rather than the long prose names in
   Collections, so they sit closer together without running into each other. */
.htm-tagset .htm-facetgroup + .htm-facetgroup{margin-top:1.1rem}

/* The reveal under the genre-by-verdict groups.

   li[hidden] is spelled out rather than left to the UA rule, and that is not
   defensive. theme/browse.css already documents the same trap on
   a.htm-genre[hidden]: an author `display` on the element outranks the UA
   sheet's [hidden]{display:none}, so a hidden item goes on rendering. Nothing
   sets display on these <li>s today, which is exactly the kind of thing a later
   layout change breaks silently. */
.htm-tagset .htm-taggroup > ul > li[hidden]{display:none}
.htm-facet-more{margin:1.1rem 0 0}
/* ---------------------------------------------------------------------------
   Where to watch: the streaming panel php/htm-watch.php appends to a review.

   Both halves have to be deployed for this to look right, and the order is
   deliberate: ship this file first. CSS with no panel to paint is a no-op,
   whereas the mu-plugin with no CSS renders a bare bulleted list of provider
   names underneath every review on the site.

   Colours come from the theme.json presets, never from browse.css's
   --htm-gold / --htm-line. Those are declared on .htm-browse only, and an
   unresolved var() does not fall back: the whole declaration is invalid at
   computed-value time. Same trap tags.css documents at length, and the same
   reason this file is unscoped.

   The panel sits inside the 720px constrained post-content, directly above the
   "Also filed under" card. It borrows that card's shape on purpose - surface
   fill, hairline, 14px radius, uppercase muted heading - so a review ends in
   one visual language rather than two. What separates them is that the tiles
   here carry artwork and that one carries text.
   --------------------------------------------------------------------------- */

.htm-watch{margin-top:var(--wp--preset--spacing--60);
  padding:var(--wp--preset--spacing--40);
  background:var(--wp--preset--color--surface);
  border:1px solid var(--wp--preset--color--line);border-radius:14px}

/* Matches the "Also filed under" h2 in theme/templates/single.html exactly.
   Written out rather than shared because that one is a block attribute set in
   the template and there is no class to hang a shared rule on. */
.htm-watch__heading{margin:0 0 var(--wp--preset--spacing--30);
  font-size:.8rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--wp--preset--color--muted)}

/* list-style and padding are reset explicitly: this is a <ul> inside
   post-content, where the theme's content styles give lists a disc and an
   indent, and inheriting either would put a bullet beside every logo. */
.htm-watch__list{display:flex;flex-wrap:wrap;gap:var(--wp--preset--spacing--30);
  margin:0;padding:0;list-style:none}

/* 6rem is sized off the longest tier label, "Rent or buy", which has to sit on
   one line: wrapped to "Rent or / buy" it makes that tile a line taller than
   its neighbours and the whole row loses its baseline. */
.htm-watch__item{display:flex;flex-direction:column;align-items:center;
  gap:.35rem;width:6rem;text-align:center}

/* Fixed box with object-fit rather than height:auto. Provider logos are not a
   consistent aspect ratio - some are square marks, some are wordmarks - and
   letting them size themselves makes the row jump by a line whenever a wide one
   appears. The dimensions are also on the <img> element so the space is
   reserved before the logo loads. */
.htm-watch__logo{width:44px;height:44px;object-fit:contain;
  border-radius:10px;background:var(--wp--preset--color--base)}

.htm-watch__name{font-size:.78rem;line-height:1.25;
  color:var(--wp--preset--color--contrast)}

/* margin-top:auto is what keeps the tier labels on one baseline across the row.
   Provider names wrap to different depths - "Starz Apple TV channel" and
   "Google Play Movies" take two lines where "FXNow" takes one - so without this
   the labels stagger by a line and the row reads ragged. The items are already
   stretched to the tallest in their row, since the list never overrides the
   default align-items:stretch, so pushing the last child down lands every label
   on the row's bottom edge whatever the name above it did.

   A min-height on the name would fix the two-line case and break again on
   three, which "Paramount Plus Essential" reaches at this width. This does not
   care how deep the wrap goes.

   Not visible in the markup, which is why it took a screenshot to find. */
.htm-watch__tier{margin-top:auto;padding-top:.15rem;
  font-size:.7rem;letter-spacing:.04em;text-transform:uppercase;
  color:var(--wp--preset--color--muted)}

.htm-watch__note{margin:var(--wp--preset--spacing--30) 0 0;
  font-size:var(--wp--preset--font-size--small);
  color:var(--wp--preset--color--muted)}

/* The one link in the panel. Gold on hover like every other link here, but
   resting in muted so a line of small print does not read as a call to action
   louder than the verdict above it. */
.htm-watch__link{color:var(--wp--preset--color--muted);
  text-decoration:underline;text-underline-offset:.2em}
.htm-watch__link:hover{color:var(--wp--preset--color--gold)}

/* Phones: the tiles are already narrow enough to wrap three or four to a row at
   320px, so only the padding needs to come in. */
@media (max-width:600px){
  .htm-watch{padding:var(--wp--preset--spacing--30)}
  .htm-watch__item{width:5.25rem}
  .htm-watch__tier{letter-spacing:0}
}
/* ---------------------------------------------------------------------------
   The app card php/htm-appcta.php appends to a review, under "Where to watch".

   Same deploy order as watch.css and for the same reason: ship this file first.
   CSS with no card to paint is a no-op; the mu-plugin with no CSS renders a
   naked heading, a sentence and a bare link under every review on the site.

   Colours come from theme.json presets, never from browse.css's --htm-gold /
   --htm-line. Those are declared on .htm-browse only, and an unresolved var()
   does not fall back - the whole declaration is invalid at computed-value time.
   Same trap tags.css and watch.css both document.

   It deliberately borrows .htm-watch's shape: surface fill, hairline, 14px
   radius, uppercase muted heading. A review already ends in three stacked
   panels (watch, this, "Also filed under") and they should read as one family
   rather than three separate pitches. The only thing that sets this one apart
   is the icon and that its link is a real call to action rather than small
   print, which is the one place it is allowed to be louder.
   --------------------------------------------------------------------------- */

.htm-appcta{margin-top:var(--wp--preset--spacing--60);
  padding:var(--wp--preset--spacing--40);
  background:var(--wp--preset--color--surface);
  border:1px solid var(--wp--preset--color--line);border-radius:14px}

/* Matches the "Also filed under" h2 in theme/templates/single.html and
   .htm-watch__heading exactly. Written out rather than shared for the same
   reason watch.css gives: the original is a block attribute set in the
   template, so there is no class to hang a shared rule on. */
.htm-appcta__heading{margin:0 0 var(--wp--preset--spacing--30);
  font-size:.8rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--wp--preset--color--muted)}

/* align-items:center rather than flex-start: the icon is 44px and the text
   block is usually two lines at reading width, so centring is what keeps the
   icon optically level with the sentence instead of riding above it. */
.htm-appcta__body{display:flex;align-items:center;
  gap:var(--wp--preset--spacing--30)}

/* Dimensions are on the <img> element too, so the row does not reflow when the
   icon loads. flex-shrink:0 because the sentence beside it is long enough to
   squeeze a flex item that is allowed to shrink. */
.htm-appcta__icon{width:44px;height:44px;flex-shrink:0;
  border-radius:10px;background:var(--wp--preset--color--base)}

.htm-appcta__text{margin:0;font-size:var(--wp--preset--font-size--small);
  line-height:1.45;color:var(--wp--preset--color--contrast)}

/* The app name carries the weight, not the whole sentence. */
.htm-appcta__name{font-weight:600}

/* Gold at rest, unlike .htm-watch__link which sits muted on purpose. That one
   is small print under a panel the reader came for; this one IS the ask, and a
   call to action that only appears on hover is not a call to action.

   display:block, NOT inline-block. This shipped as inline-block first and the
   link ran straight on from the full stop with no gap - "...you have
   rated.See it on the App Store" - because an inline-block does not start a
   line and margin-top does nothing to an inline box. Caught on a screenshot,
   invisible in the markup. block is what puts the ask on its own line and lets
   the margin apply. */
.htm-appcta__link{display:block;margin-top:.35rem;
  color:var(--wp--preset--color--gold);
  text-decoration:underline;text-underline-offset:.2em}
.htm-appcta__link:hover{color:var(--wp--preset--color--contrast)}

/* Phones: the icon and text stay side by side - stacking them makes the card
   taller than the watch panel above it and it stops reading as a footnote to
   the review. Only the padding comes in. */
@media (max-width:600px){
  .htm-appcta{padding:var(--wp--preset--spacing--30)}
  .htm-appcta__body{gap:var(--wp--preset--spacing--20)}
}
/* ---------------------------------------------------------------------------
   /what-to-watch/, generated by tools/build_what_to_watch.py.

   Ship this file BEFORE the page, same order watch.css and tags.css use. CSS
   with no page to paint is a no-op; the page with no CSS is a wall of unstyled
   buttons and a bulleted list of backdrops.

   Colours come from theme.json presets, never from browse.css's --htm-gold /
   --htm-line. Those are declared on .htm-browse only, and an unresolved var()
   does not fall back: the whole declaration is invalid at computed-value time.
   The trap tags.css, watch.css and appcta.css all document.

   Scoped under .htm-w2w because this is page content rather than a template
   part, and page content is the one place a stray global rule would follow the
   reader onto 457 reviews.
   --------------------------------------------------------------------------- */

/* Break the panel out of the constrained content column, the same escape hatch
   browse.css and app-pages.css already carry.

   The group is emitted as align:wide, which reads like it should already be
   1240px. It is not. page-app.html gives post-content a contentSize and no
   wideSize, and core computes `wide = wideSize ?: contentSize`, so alignwide
   resolves to 760px with nothing anywhere reporting a problem: the panel simply
   renders as a narrow centred column under a 1240px header and footer, and the
   results grid drops to two columns.

   Only half the fix. The other half is the contentSize on the group itself in
   build_what_to_watch.py, without which this rule widens the div and leaves
   every child stranded centred inside it. */
.entry-content.is-layout-constrained > .htm-w2w{
  max-width:var(--wp--style--global--wide-size);
  width:100%}

.htm-w2w__h1{margin:0 0 var(--wp--preset--spacing--20);
  font-size:clamp(2rem,6vw,3rem);line-height:1.05;letter-spacing:-0.02em}

/* The doubled class and the !important are both load-bearing, for exactly the
   reason home.css:127 sets out for .htm-lede. 34em is the right measure for
   this sentence and the wrong measure to be CENTRED at: core's constrained
   layout hands every child `margin-left/right:auto !important` as well as the
   cap, so a narrower paragraph sat 91px inside a left-aligned h1 and chip row.
   Capping the measure without killing the margins looks more broken than not
   capping it at all.

   Core's selector is `.is-layout-constrained > :where(...)`, and :where()
   contributes nothing, so a single .htm-w2w__lede ties it on specificity and
   loses the tie: core's layout CSS prints in core-block-supports-inline-css,
   after this file's global-styles-inline-css. Doubling settles max-width.
   It does not settle the margins on its own, because core marks those
   !important, so this has to be !important AND outrank it. */
.htm-w2w__lede.htm-w2w__lede{margin:0 0 var(--wp--preset--spacing--50);
  max-width:34em;margin-inline:0 !important;
  color:var(--wp--preset--color--muted)}

/* Each control is one wrapping row. Not a scroller: there are 28 chips across
   two rows and a horizontal scroller hides its own overflow on a phone, which
   is exactly where most of these visits are. Wrapping is honest about how many
   options there are. */
.htm-w2w__row{display:flex;flex-wrap:wrap;gap:.5rem;
  margin:0 0 var(--wp--preset--spacing--30)}

/* aria-pressed carries the state, so the selected style hangs off the same
   attribute a screen reader reads. No separate class to keep in sync. */
.htm-w2w__chip{appearance:none;cursor:pointer;
  padding:.4rem .85rem;border-radius:999px;
  border:1px solid var(--wp--preset--color--line);
  background:var(--wp--preset--color--surface);
  color:var(--wp--preset--color--contrast);
  font-size:.85rem;line-height:1.2;font-family:inherit}
.htm-w2w__chip:hover{border-color:var(--wp--preset--color--gold)}
.htm-w2w__chip[aria-pressed="true"]{
  background:var(--wp--preset--color--gold);
  border-color:var(--wp--preset--color--gold);
  color:var(--wp--preset--color--base);font-weight:600}

/* auto-fit rather than a fixed column count: this page has no idea how wide the
   content area is on a given device, and 16:9 art below about 260px stops being
   readable as a film still. */
.htm-w2w__grid{display:grid;gap:var(--wp--preset--spacing--40);
  grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  margin:var(--wp--preset--spacing--40) 0 0;padding:0;list-style:none}

.htm-w2w__card{margin:0}

.htm-w2w__link{display:block;text-decoration:none;color:inherit;
  border:1px solid var(--wp--preset--color--line);border-radius:14px;
  overflow:hidden;background:var(--wp--preset--color--surface)}
.htm-w2w__link:hover{border-color:var(--wp--preset--color--gold)}

/* aspect-ratio with object-fit, and the dimensions are on the <img> too, so a
   row does not reflow as the backdrops arrive. TMDb backdrops are consistently
   16:9, unlike the provider logos watch.css has to cope with. */
.htm-w2w__art{display:block;width:100%;aspect-ratio:16/9;object-fit:cover;
  background:var(--wp--preset--color--base)}

.htm-w2w__meta{display:block;padding:var(--wp--preset--spacing--30)}

.htm-w2w__verdict{display:block;margin-bottom:.2rem;
  font-size:.7rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  color:var(--wp--preset--color--gold)}

.htm-w2w__title{display:block;font-size:1rem;line-height:1.3}

.htm-w2w__empty{margin:var(--wp--preset--spacing--30) 0 0;
  color:var(--wp--preset--color--muted);
  font-size:var(--wp--preset--font-size--small)}

.htm-w2w__actions{margin:var(--wp--preset--spacing--40) 0 0}

.htm-w2w__more{appearance:none;cursor:pointer;
  padding:.6rem 1.2rem;border-radius:999px;
  border:1px solid var(--wp--preset--color--line);
  background:transparent;color:var(--wp--preset--color--contrast);
  font-size:.9rem;font-family:inherit}
.htm-w2w__more:hover{border-color:var(--wp--preset--color--gold);
  color:var(--wp--preset--color--gold)}

@media (max-width:600px){
  .htm-w2w__row{gap:.4rem}
  .htm-w2w__chip{padding:.35rem .7rem;font-size:.8rem}
  .htm-w2w__grid{gap:var(--wp--preset--spacing--30)}
}
/* Seasonal decor: the moon, its clouds, and the witch who flies past.

   Hand written, unlike seasons.css and season-shelf.html beside it. The markup
   this styles is generated (build_seasons.py writes theme/spook-scene.html for
   any season carrying a `decor` key, and push_theme substitutes it into
   parts/header.html), but the drawing is artwork rather than data and there is
   nothing in it for a generator to decide.

   TWO THINGS HERE ARE DELIBERATELY UNLIKE EVERY OTHER SEASONAL RULE.

   1. There is no `body.home`. Every rule in seasons.css is scoped to the
      homepage, which is what keeps a palette off review pages and /browse/.
      This layer is scoped to the season attribute alone, so it reaches every
      page of the site. That is the whole point of it: the palette is a
      homepage treatment, the weather is the site. A review page in October
      keeps its own gold and gets the moon.

   2. It is `display:none` until a season declares it. All eight seasons ship
      in one edge-cached page and a resolver reveals one, so this markup is
      present all year and must cost nothing for the 334 days it is not
      wanted. Nothing here fetches anything: the moon is a gradient, the clouds
      are blurred boxes, and the silhouettes are inline paths. There is no
      image request in this file, which is also what keeps the artwork out of
      the media library and therefore out of the per-host media map.

   Motion follows the rule poster-rain.css set: reduced motion FREEZES this
   layer, it does not delete it. A visitor who asked for less movement gets the
   moon, the clouds and a witch holding still, which is what one frame of this
   already looks like. Deleting the scenery would answer a request about motion
   by taking away the thing itself. */

/* The accent, defined on the root rather than under body.home, because the
   falling silhouettes in poster-rain.css need it on every page too. Halloween
   is the only season with decor today; a second one adds its own line. */
:root[data-htm-season="halloween"]{--htm-spook-accent:#ff9f45}

/* The sprite sheet the falling silhouettes draw from. It ships on every page
   all year and is never rendered: a <symbol> only draws where a <use> points
   at it. Not display:none, which some engines have treated as a reason to stop
   resolving references into it. The svg carries width and height 0 as
   attributes as well, so it stays invisible even if this stylesheet does not
   arrive. */
.htm-spook-defs{position:absolute;width:0;height:0;overflow:hidden}

/* Same stacking contract as .htm-rain, and it must stay the same: the site
   sits at z-index 1 on .wp-site-blocks and everything decorative sits at 0.
   This block is substituted AFTER the rain in parts/header.html, so with equal
   z-index the moon paints over the falling drops, which is the order a sky
   wants. Do not introduce a third z-index to express that. */
.htm-spook{display:none;position:fixed;inset:0;z-index:0;overflow:hidden;
  pointer-events:none;contain:strict}
[data-htm-season="halloween"] .htm-spook{display:block}

/* ---- the moon ------------------------------------------------------------

   One element and two pseudo-elements. The gradient is off-centre so the lit
   side reads as a direction rather than a flat disc, and the two shadows are
   the difference between "a moon" and "a circle". The outer box-shadow is the
   halo; it is wide and very weak on purpose, because the layer sits behind
   body copy and anything brighter starts competing with it for attention. */
.htm-spook-moon{position:absolute;top:6vh;right:5vw;
  width:clamp(78px,9vw,132px);aspect-ratio:1;border-radius:50%;opacity:.55;
  background:radial-gradient(circle at 36% 32%,
    #fff8e6 0%,#f6e4b4 42%,#e6c887 72%,#cfa85f 100%);
  box-shadow:0 0 42px 14px rgba(255,214,140,.18),
             0 0 120px 40px rgba(255,180,90,.10)}
.htm-spook-moon::before,
.htm-spook-moon::after{content:"";position:absolute;border-radius:50%;
  background:rgba(150,116,62,.30)}
.htm-spook-moon::before{width:23%;height:23%;top:24%;left:21%}
.htm-spook-moon::after{width:15%;height:15%;top:57%;left:53%}

/* ---- the clouds ----------------------------------------------------------

   A rounded box with two round lumps on it, blurred hard. Three of them cross
   the moon's band at different heights and speeds, which is what stops the
   parallax reading as one sheet sliding past.

   They animate `transform` only, so the whole layer stays on the compositor
   and none of this touches layout. The durations are long enough (78s to 134s)
   that a cloud is never the thing you notice; you notice that the moon keeps
   changing. Negative delays start each one mid-crossing so nothing has to be
   waited for on a first paint. */
.htm-spook-cloud{position:absolute;border-radius:100px;
  background:rgba(226,216,202,.11);filter:blur(9px);will-change:transform;
  animation-name:htm-spook-drift;animation-timing-function:linear;
  animation-iteration-count:infinite}
.htm-spook-cloud::before,
.htm-spook-cloud::after{content:"";position:absolute;border-radius:50%;
  background:inherit}
.htm-spook-cloud::before{width:34%;height:230%;left:16%;bottom:10%}
.htm-spook-cloud::after{width:26%;height:180%;left:53%;bottom:4%}

.htm-spook-cloud-a{top:7vh;width:46vw;height:5.2vh;
  animation-duration:96s;animation-delay:-12s}
.htm-spook-cloud-b{top:12vh;width:62vw;height:4vh;opacity:.7;
  animation-duration:134s;animation-delay:-70s}
.htm-spook-cloud-c{top:3vh;width:34vw;height:3.2vh;opacity:.55;
  animation-duration:78s;animation-delay:-40s}

@keyframes htm-spook-drift{
  from{transform:translate3d(-70vw,0,0)}
  to{transform:translate3d(170vw,0,0)}}

/* ---- the witch -----------------------------------------------------------

   She crosses about once a minute rather than continuously, which is the
   entire design: a witch permanently on screen is wallpaper, and a witch you
   catch out of the corner of your eye is a surprise you can have twice.

   The timing is one animation, not a script. A 78s cycle that is opaque for
   12% of itself gives a 9-second crossing and about 69 seconds of nothing,
   and it costs no JavaScript, no timer running on a tab nobody is looking at,
   and nothing for push_theme's inline-script checks to have an opinion about.

   Two elements because there are two motions: the wrapper carries the crossing
   and the fade, the svg inside carries a slow bob on its own shorter cycle, so
   she rides rather than sliding along a rail. Nesting them is what lets both
   run as plain transforms. */
.htm-spook-witch{position:absolute;top:15vh;left:0;
  width:clamp(88px,11vw,168px);opacity:0;will-change:transform;
  animation:htm-spook-fly 78s linear infinite}
.htm-spook-witch svg{display:block;width:100%;height:auto;
  fill:var(--htm-spook-accent,#ff9f45);
  animation:htm-spook-bob 5.2s ease-in-out infinite}

@keyframes htm-spook-fly{
  0%{opacity:0;transform:translate3d(-24vw,0,0)}
  1.2%{opacity:.52}
  10.8%{opacity:.52}
  12%{opacity:0;transform:translate3d(118vw,0,0)}
  100%{opacity:0;transform:translate3d(118vw,0,0)}}

@keyframes htm-spook-bob{
  0%,100%{transform:translate3d(0,0,0)}
  50%{transform:translate3d(0,-2.6vh,0)}}

/* Phones. The moon stops scaling with the viewport and takes a fixed size,
   because 9vw of a phone is a dot; the middle cloud goes, because three
   overlapping blurs across a narrow column is haze rather than sky. The witch
   stays: she is the one thing here anybody will mention. */
@media (max-width:781px){
  .htm-spook-moon{top:4vh;right:6vw;width:74px}
  .htm-spook-cloud-b{display:none}
  .htm-spook-witch{top:12vh;width:104px}
}

/* Frozen, not hidden. Each animated element needs an explicit resting
   transform here, and the var() fallbacks in poster-rain.css are the reason
   why: a transform naming even one undefined custom property is invalid at
   computed-value time and is dropped whole, which would pile everything at its
   untransformed origin. The witch rests part way across rather than off the
   edge, so this reads as a silhouette somebody placed and not as a bug.
   will-change:auto hands back compositor memory that buys nothing once nothing
   moves. */
@media (prefers-reduced-motion:reduce){
  .htm-spook-cloud{animation:none;will-change:auto;
    transform:translate3d(24vw,0,0)}
  .htm-spook-cloud-b{transform:translate3d(-8vw,0,0)}
  .htm-spook-cloud-c{transform:translate3d(56vw,0,0)}
  .htm-spook-witch{animation:none;will-change:auto;opacity:.52;
    transform:translate3d(58vw,0,0)}
  .htm-spook-witch svg{animation:none;transform:none}
}
/* Seasonal overlays. Generated by build_seasons.py, do not edit.

   Scoped to `body.home` throughout, which is what keeps a season on the
   homepage and off review pages, archives and /browse/. The attribute lives on
   <html> because the resolver runs before <body> is styled; the .home test is
   what limits its reach.

   Redefining the gold preset is the whole trick. theme.json compiles link
   colour, button background, the hero kicker and every .has-gold-color rule to
   var(--wp--preset--color--gold), so one declaration per season moves all of
   them at once. The preset is defined by core on :root (0,1,0) and body
   (0,0,1); `[data-htm-season] body.home` is (0,2,1) and outranks both. */

/* Christmas */
[data-htm-season="christmas"] body.home{
  --wp--preset--color--gold:#ff6b6b;
  --wp--preset--color--gold-deep:#2fa86b;
  --htm-season-accent:#ff6b6b;
  --htm-season-deep:#2fa86b;
  --htm-season-soft:rgba(255,107,107,.10)}

/* Halloween */
[data-htm-season="halloween"] body.home{
  --wp--preset--color--gold:#ff9f45;
  --wp--preset--color--gold-deep:#e2660b;
  --htm-season-accent:#ff9f45;
  --htm-season-deep:#e2660b;
  --htm-season-soft:rgba(255,159,69,.10)}

/* Thanksgiving */
[data-htm-season="thanksgiving"] body.home{
  --wp--preset--color--gold:#f0a868;
  --wp--preset--color--gold-deep:#c2703a;
  --htm-season-accent:#f0a868;
  --htm-season-deep:#c2703a;
  --htm-season-soft:rgba(240,168,104,.10)}

/* Valentine's Day */
[data-htm-season="valentines"] body.home{
  --wp--preset--color--gold:#ff7a9c;
  --wp--preset--color--gold-deep:#d81b60;
  --htm-season-accent:#ff7a9c;
  --htm-season-deep:#d81b60;
  --htm-season-soft:rgba(255,122,156,.10)}

/* New Year */
[data-htm-season="new-year"] body.home{
  --wp--preset--color--gold:#f7e07a;
  --wp--preset--color--gold-deep:#c9a227;
  --htm-season-accent:#f7e07a;
  --htm-season-deep:#c9a227;
  --htm-season-soft:rgba(247,224,122,.10)}

/* Independence Day */
[data-htm-season="july-fourth"] body.home{
  --wp--preset--color--gold:#7fb2ff;
  --wp--preset--color--gold-deep:#e2564d;
  --htm-season-accent:#7fb2ff;
  --htm-season-deep:#e2564d;
  --htm-season-soft:rgba(127,178,255,.10)}

/* Mother's Day */
[data-htm-season="mothers-day"] body.home{
  --wp--preset--color--gold:#e0a8e8;
  --wp--preset--color--gold-deep:#a45bb0;
  --htm-season-accent:#e0a8e8;
  --htm-season-deep:#a45bb0;
  --htm-season-soft:rgba(224,168,232,.10)}

/* Father's Day */
[data-htm-season="fathers-day"] body.home{
  --wp--preset--color--gold:#7fa8d8;
  --wp--preset--color--gold-deep:#41648f;
  --htm-season-accent:#7fa8d8;
  --htm-season-deep:#41648f;
  --htm-season-soft:rgba(127,168,216,.10)}

[data-htm-season="christmas"] body.home .htm-season[data-season="christmas"],
[data-htm-season="halloween"] body.home .htm-season[data-season="halloween"],
[data-htm-season="thanksgiving"] body.home .htm-season[data-season="thanksgiving"],
[data-htm-season="valentines"] body.home .htm-season[data-season="valentines"],
[data-htm-season="new-year"] body.home .htm-season[data-season="new-year"],
[data-htm-season="july-fourth"] body.home .htm-season[data-season="july-fourth"],
[data-htm-season="mothers-day"] body.home .htm-season[data-season="mothers-day"],
[data-htm-season="fathers-day"] body.home .htm-season[data-season="fathers-day"]{display:block}

/* The shelf itself. One band, a heading, and a scroll-snap rail of posters,
   deliberately the same interaction as the "Newest reviews" rail below it so
   the page does not grow a second way of moving sideways. */
.htm-season{display:none;margin-top:var(--wp--preset--spacing--70)}

.htm-season-inner{border:1px solid var(--htm-season-deep);border-radius:18px;
  background:var(--htm-season-soft);
  padding:var(--wp--preset--spacing--50)}

.htm-season-head{display:flex;flex-wrap:wrap;align-items:baseline;
  justify-content:space-between;gap:.75rem 1.5rem}

.htm-season-title{margin:0;font-size:clamp(1.4rem,1.1rem + 1.2vw,2rem);
  font-weight:600;line-height:1.15;color:var(--wp--preset--color--contrast)}

/* Sized in em so it tracks the heading. WordPress swaps emoji for Twemoji
   images sized in em, which is why this is a font-size and not a width, the
   same reason .htm-face is set that way in home.css. */
.htm-season-emoji{font-style:normal;margin-right:.5rem;font-size:1.1em;
  line-height:1}

.htm-season-blurb{margin:.5rem 0 0;color:var(--wp--preset--color--muted);
  font-size:1.05rem;max-width:60ch}

/* One or two links. A column so the second one does not have to invent a
   separator, right-aligned so it stays tucked against the shelf's own edge
   next to the heading it belongs to. */
.htm-season-all{margin:0;font-size:.9rem;white-space:nowrap;display:flex;
  flex-direction:column;align-items:flex-end;gap:.35rem}
/* The arrow lives here rather than in seasons.json so the config holds a label
   somebody would say out loud, not a label with punctuation baked into it.
   It is the literal character, NOT a CSS escape, and that is not a style
   preference. This whole block is a Python string inside a generator, so a CSS
   escape would have to survive Python's own quoting first, and Python reads a
   backslash followed by digits as OCTAL. The first attempt wrote two control
   bytes into seasons.css and rendered as a currency symbol beside some loose
   digits. There is no escaping problem to have if there is no escape. */
.htm-season-cta::after{content:"→";margin-left:.35em}

/* Scroll-snap rather than a JS slider: no library, no autoplay, keyboard and
   trackpad both work, and it degrades to a plain scrollable row. */
.htm-season-rail{display:flex;gap:1rem;list-style:none;padding:0 0 .5rem;
  margin:var(--wp--preset--spacing--40) 0 0;
  overflow-x:auto;scroll-snap-type:x mandatory;
  scrollbar-width:thin;
  scrollbar-color:var(--htm-season-deep) transparent}
.htm-season-rail::-webkit-scrollbar{height:8px}
.htm-season-rail::-webkit-scrollbar-thumb{background:var(--htm-season-deep);
  border-radius:4px}

.htm-season-card{margin:0;flex:0 0 auto;width:150px;scroll-snap-align:start}
/* Explicit, not left to the UA rule. .htm-season-card sets no display of its
   own today so [hidden] would win anyway, but every card on the bench depends
   on this and a later `display:` on that class would silently reveal the whole
   tag. */
.htm-season-card[hidden]{display:none}
.htm-season-card a{display:block;text-decoration:none;color:inherit;
  transition:transform .15s ease}
.htm-season-card a:hover,
.htm-season-card a:focus-visible{transform:translateY(-3px)}
.htm-season-card a:focus-visible{outline:2px solid var(--htm-season-accent);
  outline-offset:6px;border-radius:12px}

/* Explicit dimensions, and they are load-bearing twice over: they hold the
   rail's height before any poster has decoded, and on production they are what
   Photon reads to decide what to serve. */
.htm-season-card img{display:block;width:150px;height:225px;border-radius:10px;
  object-fit:cover;background:var(--wp--preset--color--surface-raised);
  box-shadow:0 8px 20px rgba(0,0,0,.5)}

.htm-season-name{display:block;margin-top:.55rem;font-size:.82rem;
  line-height:1.3;color:var(--wp--preset--color--muted)}
.htm-season-card a:hover .htm-season-name,
.htm-season-card a:focus-visible .htm-season-name{
  color:var(--htm-season-accent)}
.htm-season-verdict{font-style:normal;margin-right:.3rem}

@media (max-width:781px){
  .htm-season-inner{padding:var(--wp--preset--spacing--40)}
  /* The head has wrapped by here, so the links sit under the blurb rather
     than beside it and right-aligning them would strand them mid-air. */
  .htm-season-all{align-items:flex-start}
  .htm-season-card{width:120px}
  .htm-season-card img{width:120px;height:180px}
}
/*htm-theme:end*/