/* ReelTalk stylesheet. Grindhouse / midnight-movie visual identity (M6
   artwork, R60): layered near-black browns, dirty-cream text, and red used as
   theatrical lighting. Typography carries most of the identity — Bebas Neue for
   titles/section headings and the lit red controls, Oswald for metadata and
   small headings, Archivo for body/reviews and the header's own text, Monoton
   only for the neon wordmark, Kaushan Script only for the footer sign-off. The
   owner-supplied poster texture fades inward from the outer edges;
   content panels and body copy stay clean. */

:root {
  /* Palette — near-black browns + dirty cream + theatrical red. Values per the
     owner's brief / mockup reference (adapted, not copied). */
  --black:    #090807;  /* page background */
  --black-2:  #11100e;  /* deeper alt background */
  --panel:    #141210;  /* raised panel (cards, dropdowns) */
  --panel-2:  #1b1713;  /* raised panel / hover */
  --cream:        #e9dfcb;  /* body text */
  --cream-muted:  #b8aa91;  /* secondary text */
  --white:        #ffffff;  /* post prose, dates and header links (owner pass, 2026-10-04) */
  --red:        #d42b26;  /* primary red — fills, display headings */
  --red-bright: #ff4138;  /* neon/bright red — active, glow, key highlights */
  --red-dark:   #721713;  /* dark red — deep fills, shadows */
  --amber:   #e0a52b;  /* amber accent + focus */
  --mustard: #c79836;  /* mustard */
  --teal:    #43868a;  /* teal tertiary */
  --gold:    #f1b51a;  /* star ratings */
  --line:    #5a432c;  /* thin amber/brown borders */
  --steel:   #5c5852;  /* dirty steel gray — search trim (mockup) */
  --avatar-ring: #d9c3b3;  /* worn cream bezel around an avatar disc */
  --neon-rim: #ff6a5b;  /* hot glass edge on a lit red control (button, step disc) */

  /* Worn crimson fill for lit red controls: an original mottled tile (generated
     for this project) painted over a dark-to-darker red gradient, so the fill is
     uneven like lacquered metal instead of flat paint. */
  --neon-mottle: url("../images/button-mottle.720f44b16379.png");

  /* Typography roles. */
  --display: "Bebas Neue", sans-serif;  /* film titles, section headings, lit red controls */
  --ui:      "Oswald", sans-serif;      /* metadata, tabs, genre pills, small headings */
  --body:    "Archivo", sans-serif;     /* body text + reviews */
  --script:  "Kaushan Script", cursive;  /* the footer sign-off only — neon signage */

  /* Semantic roles — the rest of this sheet references these. */
  --bg: var(--black);
  --fg: var(--cream);
  --muted: var(--cream-muted);
  --accent: #e0554a;   /* theatrical red for focus rings, field borders, watchlist */
  /* Anchor text, resting and hovered (owner pass, 2026-10-05). Split out of
     --accent on purpose: the focus ring and the field borders keep the old
     muted #e0554a, while link text moves to the core of the solid-red
     clapperboard so the two read as the same red. Measured off
     applaud-solid-red.png at alpha>=200, where the mode is fc0a13.
     Hover deliberately equals resting: the old hover went brighter than the
     resting colour, and once resting moved to #fc0a13 a hover back down to
     --accent would have read as de-emphasis. */
  --link: #fc0a13;
  --border: var(--line);
  --error: #ff5a3c;
  --surface: var(--panel);
  --surface-2: var(--panel-2);
  --field: #0d0b09;    /* inset form field, a hair darker than the page */

  /* Aliases kept for existing fill/border rules. */
  --blood-red: var(--red);
  --brown: var(--line);
}

/* Self-hosted SIL OFL fonts (no CDN, no build step — R6). Each font's OFL.txt
   sits alongside it under static/fonts/. */
@font-face {
  font-family: "Monoton";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/monoton.c6856aa207b4.woff2") format("woff2");
}

@font-face {
  font-family: "Bebas Neue";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/bebas-neue.5853435d21b1.woff2") format("woff2");
}

@font-face {
  font-family: "Oswald";
  font-style: normal;
  font-weight: 200 700;
  font-display: swap;
  src: url("../fonts/oswald.22c3b00d2e65.woff2") format("woff2");
}

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("../fonts/archivo.cd56e2ec63d7.woff2") format("woff2");
}

@font-face {
  font-family: "Kaushan Script";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/kaushan-script.4648267a9594.woff2") format("woff2");
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: var(--body);
  line-height: 1.55;
  color: var(--fg);
  min-height: 100vh;
  background-color: var(--black);
}

a {
  color: var(--link);
}

.container {
  max-width: 40rem;
  margin: 0 auto;
  padding: 1rem 1rem 3rem;
}

/* Marquee band (M6 artwork B, R61): a wide strip spanning the viewport —
   top row logo / search / profile, nav row below. The header's inner
   container is wider than the 40rem page column (which stays until
   sub-increment C). No own background since the owner texture pass: it shows
   the site-wide grunge like the rest of the page; a worn chrome rail closes
   the band (see the rail rules in the texture section). */
.site-header {
  position: relative;
  border-bottom: 3px solid var(--black-2);
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.45);
}

.site-header .container {
  max-width: 72rem;
}

.header-top {
  display: grid;
  grid-template-columns: 1fr minmax(0, 34rem) 1fr;
  align-items: center;
  /* Wide column gap keeps clear air between the wordmark and the search box. */
  gap: 1.25rem 4rem;
  padding-top: 0.9rem;
  padding-bottom: 0.4rem;
}

/* Wordmark — Monoton neon-tube treatment (M6 artwork, R60; relit per R68). */
.brand {
  font-family: "Monoton", sans-serif;
  font-weight: 400;
  /* Sized against MOCKUP.png proportions (owner review of M6 increment 5). */
  font-size: 3.6rem;
  letter-spacing: 0.02em;
  /* Fill is the filament, the stroke over it is the red glass: painting the stroke
     last carves red back into each Monoton bar and leaves a narrow white-hot core,
     which is what made the mockup's wordmark read as lit (a flat fill capped at
     luminance 193 with nothing above 200 read as paint). The stroke is in em, not px:
     the brand steps down to 2.2rem under 40rem, where a fixed 1px edge swallows the
     bars whole and the wordmark goes dark red (measured max lum 171 — worse than the
     flat fill it replaced). */
  color: #fff4ee;
  -webkit-text-stroke: 0.0174em var(--red);
  text-decoration: none;
  text-shadow:
    0 0 2px #fff,
    0 0 5px var(--red-bright),
    0 0 12px var(--red-bright),
    0 0 26px var(--red),
    0 0 48px rgba(255, 40, 25, 0.7),
    0 0 80px rgba(255, 30, 20, 0.35);
}

.header-user {
  /* Pinned to the last column (R80): with the search box gone for anonymous
     visitors this row has only two children, and auto-placement would drop the
     handle into the 34rem middle column, rendering "Log in" centered. */
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 1.1rem;
}

.header-user a {
  color: var(--white);
  text-decoration: none;
  font-size: 0.88rem;
}

.header-user a:hover {
  color: var(--link);
}

/* The signed-in handle is the only item on this side — kept lit like a
   marquee name, going neon-red on hover. The avatar rides inside the same link
   so the corner stays one tab stop, with the reference's ~12px disc-to-name gap. */
.header-user .user-name {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--white);
}

.header-user .user-name:hover {
  color: var(--link);
}

/* Nav row under the marquee, centered under the search box; the active page
   gets the red underline (R61). */
.nav-inner {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.35rem 1.9rem;
  padding-top: 0;
  padding-bottom: 0.7rem;
}

.site-nav a {
  color: var(--white);
  text-decoration: none;
  font-size: 0.88rem;
  letter-spacing: 0.02em;
  padding: 0.2rem 0.1rem;
  position: relative;
  border-bottom: 2px solid transparent;
}

/* Hover takes the lit-red the rest of the site already uses for "interactive"
   (owner decision, 2026-10-04). With the resting colour now white, the old
   brighter-cream hover would have been no feedback at all. */
.site-nav a:hover {
  color: var(--link);
}

.site-nav a.active {
  color: var(--white);
  text-shadow: 0 0 10px rgba(255, 65, 56, 0.5);
}

/* The active-page marker is a lit neon tube, not a painted rule (R67): the mockup's
   indicator measures a white-hot core inside saturated red with ~10px of bloom, and
   a border can carry neither, so it is a positioned bar — gradient cross-section for
   the glass, layered shadows for the light. The transparent 2px border above stays so
   nav metrics are untouched. */
.site-nav a.active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -3px;
  height: 3px;
  background: linear-gradient(
    to bottom,
    var(--red) 0 1px,
    #fff 1px 2px,
    var(--red-bright) 2px
  );
  box-shadow:
    0 0 3px rgba(255, 120, 100, 0.95),
    0 0 9px rgba(255, 65, 56, 0.9),
    0 0 20px rgba(255, 45, 32, 0.6),
    0 0 40px rgba(255, 30, 20, 0.4);
}

/* Log out reads as nav text, not a button (owner review of M6 increment 5). */
.site-nav form.inline button {
  border: none;
  padding: 0.2rem 0.1rem;
  box-shadow: none;
  color: var(--white);
  font-size: 0.88rem;
  letter-spacing: 0.02em;
}

/* Log out is a <button> styled as nav text, so it takes the anchor hover red
   too — the owner's call on 2026-10-05: two different reds side by side in
   one nav row reads as a mistake, not as two kinds of thing. */
.site-nav form.inline button:hover {
  color: var(--link);
}

/* Narrow screens: the search box drops to its own full-width line so the
   suggest dropdown keeps its shape; the wordmark steps down and the wide
   logo/search gap collapses so the top row never overflows. */
@media (max-width: 40rem) {
  .header-top {
    grid-template-columns: 1fr auto;
    row-gap: 0.6rem;
    column-gap: 1rem;
  }

  .brand {
    font-size: 2.2rem;
  }

  .global-search {
    grid-column: 1 / -1;
    order: 3;
  }

  /* Two columns here, so the handle's last column is 2, not 3 — the base pin
     would open an implicit third track and leave a gap on the right. */
  .header-user {
    grid-column: 2;
    /* The corner truncates instead of widening the grid. Its min-content (a
       long handle is one unbreakable word) used to push the whole header past
       the viewport, and the search row spanning 1 / -1 inherited the overflow:
       measured 399px of content in a 375px viewport. min-width:0 lets the
       track shrink; the text inside each corner link carries the ellipsis. */
    min-width: 0;
  }

  .header-user a {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .header-user .user-handle {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

h1 {
  font-size: 1.6rem;
  margin: 1.5rem 0 1rem;
}

form p {
  margin: 0 0 0.25rem;
}

form label {
  display: block;
  font-weight: 600;
  margin-bottom: 0.25rem;
}

.find-form {
  display: grid;
  gap: 0.75rem;
  justify-items: start;
}

input[type="text"],
input[type="email"],
input[type="password"] {
  width: 100%;
  padding: 0.45rem 0.6rem;
  font: inherit;
  color: inherit;
  background: var(--field);
  border: 1px solid var(--brown);
  border-radius: 4px;
}

input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 0;
  border-color: var(--accent);
}

button,
.btn {
  display: inline-block;
  margin-top: 1rem;
  padding: 0.5rem 1.1rem;
  font: inherit;
  font-weight: 600;
  color: var(--cream);
  background: var(--blood-red);
  border: none;
  border-radius: 4px;
  cursor: pointer;
  /* An anchor dressed as a control must not keep the link's underline: the
     browser default applies to <a> and nothing here overrode it, so every
     <a class="btn"> (Edit profile, Edit, Sign up) read as underlined text
     while its <button class="btn"> siblings did not — same control, two
     looks. Set on the shared rule so the tag stops mattering. */
  text-decoration: none;
}

button:hover {
  filter: brightness(1.1);
}

/* Small inline form (header log-out button). */
form.inline {
  display: inline;
  margin: 0;
}

form.inline button {
  margin: 0;
  padding: 0.25rem 0.7rem;
  font-size: 0.9rem;
  background: none;
  color: var(--muted);
  border: 1px solid var(--border);
  box-shadow: none;
}

form.inline button:hover {
  color: var(--accent);
  border-color: var(--accent);
  filter: none;
  box-shadow: none;
}

ul.messages {
  list-style: none;
  padding: 0;
  margin: 1rem 0;
}

ul.messages li {
  padding: 0.5rem 0.75rem;
  border-radius: 4px;
  margin-bottom: 0.5rem;
  background: var(--surface);
  border: 1px solid var(--border);
}

ul.messages li.error {
  background: rgba(212, 43, 38, 0.2);
  border-color: var(--red);
  color: #e9a58f;
}

ul.errorlist {
  color: var(--error);
  font-size: 0.9rem;
  margin: 0.25rem 0 0;
  padding-left: 1.2rem;
}

/* --- Film page (M1 increment 5) ------------------------------------------ */

.muted {
  color: var(--muted);
}

.film {
  display: flex;
  gap: 1.25rem;
  margin-top: 1.5rem;
}

.film-poster img,
.poster-placeholder {
  width: 10rem;
  height: 15rem;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid var(--border);
}

.poster-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
  color: var(--muted);
  font-size: 0.85rem;
}

.film-meta h1 {
  margin-top: 0;
}

.meta-list div {
  display: flex;
  gap: 0.5rem;
  margin: 0.15rem 0;
}

.meta-list dt {
  font-weight: 600;
  min-width: 6rem;
  color: var(--muted);
}

.meta-list dd {
  margin: 0;
}

/* Narrow screens (owner pass, 2026-09-20): side by side, the 6rem label column
   left the value only 74px at a 390px viewport, so the cast wrapped to thirteen
   lines down the right edge. The poster and title become a centred plate and each
   field stacks label-over-value across the full column. Scoped to `.film` so the
   About page's short meta-list keeps the two-column shape it reads fine in. */
@media (max-width: 40rem) {
  .film {
    flex-direction: column;
    gap: 1.15rem;
  }

  .film-poster {
    align-self: center;
  }

  .film-meta h1 {
    text-align: center;
  }

  .film .meta-list div {
    display: block;
    margin: 0.8rem 0 0;
  }

  .film .meta-list dt {
    min-width: 0;
    font-size: 0.72rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
  }

  .film .meta-list dd {
    margin-top: 0.2rem;
    line-height: 1.55;
  }
}

/* Star rating: a dim background row with a gold foreground row clipped to the
   rating's width. Shared by read-only display and the interactive widget. */
.stars {
  position: relative;
  display: inline-block;
  font-size: 1.25rem;
  line-height: 1;
  white-space: nowrap;
}

.stars-bg,
.stars-fg {
  letter-spacing: 0;
}

.stars-bg {
  color: var(--border);
}

.stars-fg {
  color: var(--gold);
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  overflow: hidden;
}

.review-list {
  list-style: none;
  padding: 0;
  margin: 1rem 0;
}

.review {
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border);
  /* Containing block for the row's stretched open-the-post link. Without it
     the overlay would size itself to the nearest positioned ancestor and
     cover whatever else wears that name. */
  position: relative;
}

/* The whole feed row opens its post (owner ask, restated 2026-09-28). A real
   anchor stretched over the row rather than a JS click handler on the <li>:
   a list item is not focusable, so a scripted row would be unreachable by
   Tab and would lose middle-click / ctrl-click open-in-a-new-tab. The anchor
   carries no content, so no control can be nested inside it — which also
   keeps this out of invalid-HTML territory, since review prose is rendered
   markdown and can contain links of its own. */
.review-open {
  position: absolute;
  inset: 0;
  z-index: 0;
  cursor: pointer;
}

/* Everything interactive inside the row paints above that overlay, or the
   overlay swallows its clicks. Scoped to the three containers a row is made
   of rather than listed control by control, so a control added to a row
   later is covered by the rule instead of silently losing its click. */
.review-head a,
.review-head button,
.feed-item a,
.review-body a {
  position: relative;
  z-index: 1;
}

/* Post prose reads white, not cream (owner pass, 2026-10-04). Site-wide by the
   owner's explicit choice, so a feed row and the post it opens agree. Links
   inside the rendered markdown keep --accent: prose and links must not match. */
.review-body {
  color: var(--white);
}

/* The row deliberately carries no hover treatment on its prose — the owner
   removed the underline-on-hover signal on 2026-10-04. The overlay still has
   cursor: pointer, so the row reads as clickable without the text lighting up.
   Do not re-add it: it is the one thing here that was taken away on purpose. */

/* The way forward at the foot of the feed (§2I increment 2, R132 decision 6).
   Deliberately NOT `.btn`: this is a link to more of what the reader is already
   looking at, not a command, and a solid lit-red block under every page of the
   feed would outshout the rows it follows. Quiet centred text link, with the
   same underline-on-hover signal the row's own links use. */
.feed-more {
  text-align: center;
  margin: 1.25rem 0 0;
}

.feed-older {
  color: var(--cream-muted);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid var(--border);
  padding-bottom: 2px;
}

.feed-older:hover,
.feed-older:focus-visible {
  color: var(--link);
  border-bottom-color: var(--link);
}

/* The end of the feed (§2I increment 3, R132 decision 7). It lives inside the
   list as a sibling of the rows, so it sheds the row chrome and reads as a
   closing line rather than another post. */
.feed-end {
  padding: 1.25rem 0 0.25rem;
  color: var(--cream-muted);
  text-align: center;
  border-bottom: none;
}

/* The scroll sentinel (§2I increment 3). It has to occupy a little height to
   cross the viewport edge while scrolling, and nothing else: the observer is
   watching when it appears, not what it looks like. */
.feed-sentinel {
  height: 1px;
  margin-top: 0.5rem;
}

.review-head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
  margin-bottom: 0.25rem;
  font-size: 0.95rem;
}

/* A post's date is plain text, never a link (owner pass, 2026-10-04). On the
   feed the row already opens through .review-open, so the linked date was a
   second way to the same page — and it read as red underlined text. White
   rather than --muted so it sits with the prose instead of receding from it. */
.post-date {
  color: var(--white);
}

.review-author {
  font-weight: 600;
  /* Remote handles like fedb@192.168.1.138:3031 are one unbreakable word —
     let it break so narrow screens don't scroll sideways. */
  overflow-wrap: anywhere;
}

/* Delete-review control (M5 increment 4): right-aligned in the head row. The
   more specific selector overrides form.inline's `margin: 0`. */
.review-head form.review-delete {
  margin-left: auto;
}

/* Applaud control (owner pass, 2026-10-05 — icon-only, replacing the pill).

   The resting icon reports THREE states, not two, because it is read as
   reporting who has applauded:

     you applauded              -> solid red      data-state="mine"
     others applauded, not you  -> red outline    data-state="others"
     nobody applauded           -> white outline  data-state="idle"

   Hover is a uniform scale(1.08) across all three states. The supplied
   white-glow art is NOT used — the owner rejected the outside glow, and a
   brightness lift cannot stand in for it on the idle icon because that art
   is already at 253,253,253 and clamps at 255.

   Both facts the state needs are already on the row (liked_by_viewer and
   like_count), so this needed no model change. data-state is derived in the
   template and recomputed by likes.js after each toggle.

   The base `button` rule paints a lit red mottle with a neon rim and a
   four-stop bloom, and carries margin-top: 1rem. Both are reset here — the
   pill version's first render showed that glow sitting around the art, and
   without the margin reset the control hangs 16px below the avatar.

   The three shipped PNGs were NOT drawn the same size. At alpha>=200 the
   clapperboard bodies measured 1059x973 (white outline), 1028x976 (red
   outline) and 1023x989 (solid red). They are registered by core AREA,
   centred on the core centre, so changing state never resizes the
   clapperboard. Registering by ink bbox instead would have shifted it. */
.applaud {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  vertical-align: middle;
}

.applaud-btn {
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  background: url("../images/applaud-icon-idle.e2a8ed789dfa.png") center / contain no-repeat;
  background-color: transparent;
  box-shadow: none;
  text-shadow: none;
  margin-top: 0;
  cursor: pointer;
}

.applaud-btn[data-state="others"] {
  background-image: url("../images/applaud-icon-others.d60c399aa187.png");
}

.applaud-btn[data-state="mine"] {
  background-image: url("../images/applaud-icon-mine.714c4d113b92.png");
}

/* Uniform scale, not a brightness lift. The idle art is already at
   253,253,253, so brightness() clamps at 255 and is invisible on it — a
   lift would have registered on the red states only, leaving the three
   states feeling inconsistent. transform is paint-only, so the row never
   reflows.

   The box-shadow and filter resets here are load-bearing, not decoration.
   `button:hover, .btn:hover` paints a five-stop red bloom and `button:hover`
   adds filter: brightness(1.1); both are (0,1,1) and therefore OUTSPECIFY the
   (0,1,0) `.applaud-btn` resets in the base rule. Without repeating them on
   the hover selector the icon lights up with the site's button halo the moment
   the cursor arrives. */
.applaud-btn:hover {
  transform: scale(1.08);
  box-shadow: none;
  filter: none;
}

.applaud-btn:disabled {
  filter: saturate(0.5) brightness(0.7);
  cursor: default;
  box-shadow: none;
}

/* Mono on purpose: the digits are the one piece of this control that is real
   text, and the site's lettering is a typewriter face. The number is always
   white and never tracks the icon: the icon alone carries who applauded, so a
   red number would be a second, redundant copy of that signal. */
.applaud-count {
  font-family: ui-monospace, "DejaVu Sans Mono", "Liberation Mono", monospace;
  font-weight: 700;
  font-size: 1rem;
  color: var(--white);
}

/* Reply control (owner pass, 2026-10-05). Sits immediately after the applaud
   control and follows the same visual contract — 26px icon, plain monospace
   count, no border, uniform scale(1.08) on hover with the same load-bearing
   box-shadow/filter resets against the base `button:hover` bloom.

   TWO states, not three. The owner chose these over the applaud's three on the
   grounds that the third state would have had to mean "you replied", and a
   reply is not reversible the way a like is — nothing this control does can
   take one back, so an icon claiming authorship of a reply would be a claim
   the control cannot act on.

     post has replies  -> red outline  data-state="others"
     no replies yet    -> white outline data-state="idle"

   The solid-red artwork was therefore NOT shipped: ManifestStaticFilesStorage
   hashes and serves every file in the static tree whether or not a rule
   points at it, so an unused PNG is dead weight on every deploy.

   Unlike the applaud this is an <a>, not a <button> — it navigates rather
   than toggling, so it must be a real link for middle-click, open-in-new-tab
   and Tab order. Two consequences handled here rather than in the template:
   `transform` does not apply to a non-replaced inline element, hence
   display: inline-block; and the base `a` rule gives it --link, which must
   be overridden to keep the icon's own ink as the only colour on it. */
.reply {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  vertical-align: middle;
}

.reply-btn {
  display: inline-block;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  background: url("../images/reply-icon-idle.c9a537437ff3.png") center / contain no-repeat;
  background-color: transparent;
  box-shadow: none;
  text-shadow: none;
  margin-top: 0;
  cursor: pointer;
}

.reply-btn[data-state="others"] {
  background-image: url("../images/reply-icon-others.a2e0ad62b9e1.png");
}

.reply-btn:hover,
.reply-btn:focus-visible {
  transform: scale(1.08);
  box-shadow: none;
  filter: none;
}

/* Same mono treatment and the same always-white rule as .applaud-count: the
   number is a count, not a status, and the icon carries the status. */
.reply-count {
  font-family: ui-monospace, "DejaVu Sans Mono", "Liberation Mono", monospace;
  font-weight: 700;
  font-size: 1rem;
  color: var(--white);
}

/* Shelve/edit controls under the film header. */
.film-actions {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 1rem;
}

.film-actions form {
  margin: 0;
}

/* Interactive star rating: the read-only .stars fill plus a layer of ten
   invisible half-star hit zones (see reeltalk.js). */
.star-rating {
  position: relative;
  display: inline-block;
}

.star-hits {
  position: absolute;
  inset: 0;
  display: flex;
  cursor: pointer;
}

.star-hits span {
  flex: 1 1 0;
  height: 100%;
}

/* Finish-flow modal (mark watched / edit review). */
.modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}

.modal[hidden] {
  display: none;
}

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.72);
}

.modal-dialog {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1.25rem 1.5rem 1.5rem;
  width: 100%;
  max-width: 26rem;
}

.modal-dialog h2 {
  margin-top: 0;
  font-size: 1.2rem;
}

.modal-dialog .star-rating .stars {
  font-size: 2rem;
}

/* The reply composer (feed interactions increment 4). Deliberately no new
   look: the textarea takes the identical field treatment the review modal
   gives its own — a bare `<textarea>` on this dark theme otherwise renders
   as a browser-default white box, which is the same class of trap as the
   caps face on a bare `<button>`. Nothing here is invisible in the diff and
   only a browser catches it. */
.reply-form {
  margin-top: 1.25rem;
}

.modal-dialog textarea,
.reply-form textarea {
  width: 100%;
  padding: 0.45rem 0.6rem;
  font: inherit;
  color: inherit;
  background: var(--field);
  border: 1px solid var(--brown);
  border-radius: 4px;
  margin-top: 0.25rem;
}

.modal-dialog button {
  margin-top: 1rem;
}

.reply-form button {
  margin-top: 0.75rem;
}

/* "replying to @x" on a flat thread row, and the orphan line on a reply
   whose parent is a tombstone. Both are metadata, so both take the muted
   metadata face at the row's own size rather than the body size. */
.reply-to,
.reply-parent-deleted {
  font-family: var(--ui);
  font-size: 0.85rem;
}

.required {
  color: var(--error);
}

/* Inline error line (e.g. a failed /find/ lookup). */
.error {
  color: var(--error);
}

/* --- User films page (M1 increment 6) ------------------------------------- */

.profile-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

/* Every avatar disc, at every size: a worn cream bezel with saturated red hugging
   the portrait inside it — the same hot-core-in-coloured-glass family as the nav
   tube and the wordmark. Sizes are rem so they scale with the root font. */
.avatar {
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
  border: 2px solid var(--avatar-ring);
  box-shadow: inset 0 0 0 2px rgba(196, 30, 24, 0.85), 0 0 7px rgba(255, 65, 56, 0.25);
}

/* Row heads are compact; the marquee corner and the profile pages share the base size. */
.avatar-row {
  width: 2.05rem;
  height: 2.05rem;
}

.profile-head h1 {
  margin: 0.5rem 0 0;
}

/* --- Profile page (M5) ---------------------------------------------------- */

/* No uploaded avatar — every new account and most remote mirrors: a hand-drawn
   silhouette on a distressed red-to-black plate, so an empty disc still reads as
   lit rather than broken. */
.avatar-placeholder {
  display: inline-block;
  background: radial-gradient(circle at 50% 34%, #d9b78e 0 15%, transparent 16%),
    radial-gradient(ellipse 78% 46% at 50% 96%, #d9b78e 0 52%, transparent 53%),
    linear-gradient(160deg, #7e1a15, #14100e);
}

.profile-id {
  display: flex;
  flex-direction: column;
}

/* Follow / edit control, right-aligned on the profile head row. */
.profile-actions {
  margin-left: auto;
}

.handle {
  margin: 0.25rem 0 0;
  color: var(--muted);
  font-size: 0.9rem;
}

.profile-summary {
  margin: 1rem 0;
}

.tabs {
  display: flex;
  gap: 0.25rem;
  border-bottom: 1px solid var(--border);
  margin-top: 1.25rem;
}

.tabs a {
  padding: 0.4rem 0.9rem;
  color: var(--muted);
  /* The nav row's size, so the two read as one type (owner pass, 2026-10-04). */
  font-size: 0.88rem;
  text-decoration: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.tabs a:hover {
  color: var(--link);
}

.tabs a.active {
  color: var(--fg);
  font-weight: 600;
  border-bottom-color: var(--accent);
}

.film-list {
  list-style: none;
  padding: 0;
  margin: 1rem 0;
}

.film-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
}

.film-row .thumb,
.feed-item .thumb,
.list-strip-poster,
.thumb-placeholder {
  width: 2.5rem;
  height: 3.75rem;
  object-fit: cover;
  border-radius: 3px;
  border: 1px solid var(--border);
  flex-shrink: 0;
}

.thumb-placeholder {
  background: var(--surface);
}

.film-row a {
  text-decoration: none;
}

.film-row a:hover {
  color: var(--link);
}

/* --- Home feed (M1 increment 6) -------------------------------------------- */

.feed h2 {
  margin-top: 1.5rem;
}

/* R34: poster thumb beside the event text on film-anchored rows. */
.feed-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0.25rem 0;
}

.feed-film {
  margin: 0.25rem 0;
  font-weight: 600;
}

.feed-item .feed-film {
  margin: 0;
}

/* --- The list row (lists increment 4, R139) ---------------------------------
   Three lines: the verb in the head row, the title here, then the poster
   strip. Nothing about the row is new chrome — it reuses the head, the tile
   size and the text colours every other feed row already wears. */
.feed-verb {
  color: var(--cream);
}

.list-strip {
  margin: 0.25rem 0;
}

.list-strip-title {
  margin: 0.25rem 0;
  font-weight: 600;
  color: var(--white);
}

/* The strip never wraps. The cap is what keeps the row short, so a wrapped
   strip would be the worst of both: the tiles it has room for on line one,
   and the +N stranded on a line of its own reading as a count of nothing.
   overflow:hidden is the backstop for a column narrower than five tiles,
   which the cap makes a corner case rather than the normal render. */
.list-strip-posters {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.4rem;
  overflow: hidden;
}

/* Secondary colour, vertically centred against the tiles: it reads as "and
   more in here", not as a sixth tile. */
.list-strip-count {
  flex-shrink: 0;
  color: var(--cream-muted);
  font-weight: 600;
  font-size: 0.9rem;
}

/* --- Landing/about + footer (M1 increment 7) --------------------------------- */

.landing-desc {
  font-size: 1.05rem;
}

.about-instance h2 {
  margin-top: 1.5rem;
  font-size: 1.2rem;
}

/* --- Footer (owner pass, 2026-09-19) ---------------------------------------
   Three zones on the worn chrome rail: the wordmark and tagline bottom-left,
   the wayfinding links in the middle, and a lit neon sign-off with a film reel
   on the right. The band runs as wide as the marquee above it (72rem) so its
   edges line up with the header and the home rail. */
.site-footer {
  position: relative;
  border-top: 3px solid var(--black-2);
  margin-top: 2rem;
}

.site-footer .container {
  max-width: 72rem;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1.5rem;
  padding-top: 1.6rem;
  padding-bottom: 2.4rem;
}

.site-footer a {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.9rem;
}

.site-footer a:hover {
  color: var(--cream);
}

.footer-brand {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.25rem 0.9rem;
  min-width: 0;
}

.footer-wordmark {
  font-family: var(--display);
  font-size: 2.4rem;
  line-height: 1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--cream);
}

.footer-tagline {
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.footer-links {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.7rem;
}

.footer-links a {
  font-size: 0.82rem;
}

.footer-sep {
  color: #4a3a2c;
  user-select: none;
}

.footer-signoff {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.55rem;
}

/* Neon script sign-off: the same hot-core-in-coloured-glass reading as the nav
   tube (R67) and the wordmark (R68), set at a slight tilt like bent tubing. */
.footer-neon {
  font-family: var(--script);
  font-size: 1.9rem;
  line-height: 1;
  color: #ff5f4d;
  transform: rotate(-3deg);
  text-shadow:
    0 0 3px rgba(255, 130, 110, 0.9),
    0 0 10px rgba(255, 65, 56, 0.75),
    0 0 24px rgba(255, 45, 32, 0.5),
    0 0 46px rgba(255, 30, 20, 0.3);
}

.footer-reel {
  width: 2rem;
  height: 2rem;
  flex: none;
  color: var(--red-bright);
  filter: drop-shadow(0 0 4px rgba(255, 65, 56, 0.8)) drop-shadow(0 0 12px rgba(255, 45, 32, 0.45));
}

@media (max-width: 40rem) {
  .site-footer .container {
    grid-template-columns: 1fr;
    justify-items: center;
    gap: 1rem;
    padding-top: 1.3rem;
    padding-bottom: 2rem;
  }

  .footer-brand {
    justify-content: center;
    text-align: center;
  }

  .footer-wordmark {
    font-size: 2rem;
  }

  .footer-signoff {
    justify-content: center;
  }

  .footer-neon {
    font-size: 1.6rem;
  }

  .footer-reel {
    width: 1.7rem;
    height: 1.7rem;
  }
}

/* --- Global search + suggest dropdown (M2 increment 4) ---------------------- */

.global-search {
  position: relative;
}

/* Wide centered search box (M6 artwork B); the suggest dropdown anchors to
   its bottom edge via the form's position:relative. */
.global-search input[type="search"] {
  width: 100%;
  padding: 0.5rem 0.9rem;
  font: inherit;
  color: inherit;
  background: var(--field);
  border: 1px solid var(--steel);
  border-radius: 4px;
}

.suggest-list {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 50;
  list-style: none;
  margin: 0;
  padding: 0.25rem 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.55);
}

.suggest-list a {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.75rem;
  color: var(--fg);
  text-decoration: none;
}

.suggest-list a:hover,
.suggest-list a.active {
  /* R32: keyboard highlight matches the mouse hover. */
  background: var(--surface-2);
}

/* R31: poster thumbnail in the dropdown rows (placeholder when missing). */
.suggest-thumb {
  width: 1.6rem;
  height: 2.4rem;
  object-fit: cover;
  border-radius: 2px;
  border: 1px solid var(--border);
  flex-shrink: 0;
}

.suggest-thumb-placeholder {
  background: var(--surface);
}

.search-row-main {
  flex: 1;
}

.search-row .watchlist-btn {
  margin-top: 0;
  padding: 0.25rem 0.7rem;
  font-size: 0.9rem;
  background: none;
  color: var(--accent);
  border: 1px solid var(--border);
  box-shadow: none;
}

.search-row .watchlist-btn:hover {
  border-color: var(--accent);
  filter: none;
  box-shadow: none;
}

.search-row .watchlist-btn:disabled {
  color: var(--muted);
  cursor: default;
  border-color: var(--border);
  box-shadow: none;
  filter: none;
}

.pager {
  display: flex;
  gap: 1rem;
  margin-top: 1rem;
}

/* --- File import/export (M3) ----------------------------------------------- */

table.results {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
  margin: 1rem 0;
}

table.results th,
table.results td {
  text-align: left;
  padding: 0.35rem 0.6rem;
  border-bottom: 1px solid var(--border);
}

table.results th {
  color: var(--muted);
  font-weight: 600;
}

/* --- Welcome / getting-started page (M6) ----------------------------------- */

.welcome-steps {
  margin-top: 1.5rem;
}

.step {
  display: flex;
  gap: 0.9rem;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--border);
}

/* The step discs carry the same lit-red recipe as the buttons (owner pass,
   2026-09-19): mottled crimson under a hot rim, bloom scaled to the disc and
   kept as tight as the reference's halo. */
.step-num {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  color: var(--cream);
  background-color: #861713;
  background-image: var(--neon-mottle), radial-gradient(circle at 50% 28%, #a0221b, #6d1210);
  border: 2px solid var(--neon-rim);
  border-radius: 50%;
  box-shadow:
    inset 0 0 7px rgba(255, 74, 52, 0.5),
    0 0 3px rgba(255, 96, 74, 0.8),
    0 0 8px rgba(255, 45, 32, 0.42);
  text-shadow: 0 1px 2px rgba(46, 2, 2, 0.8);
}

.step-body h2 {
  margin: 0.1rem 0 0.35rem;
  font-size: 1.15rem;
}

.step-body p {
  margin: 0;
  color: var(--muted);
}

/* --- Texture pass (M6 artwork, R60; site-wide grunge 2026-09-16) -----------
   Owner-supplied worn paper now lives only at the desktop outer edges (see
   body pseudo-elements). Thin amber/brown trim and dark content surfaces
   keep body copy clean. */

/* Header band: none since the owner texture pass (2026-09-16) — the halftone
   + red-glow marquee treatment was removed so the header carries the same
   site-wide grunge as the rest of the page. */

/* Grungy chrome rails (owner request, 2026-09-18): the header/footer rules are
   a worn chrome bar rather than a flat line — bright bevelled metal eaten by
   corrosion pits, re-polished in short streaks, warm rust stains and grime
   bleeding past the edges. Painted from an original strip (generated for this
   project, so rule 4 of REWRITE.md is satisfied) because CSS blend modes could
   not do it: the grunge tile is a dark texture, so every blend that eats metal
   (hard-light / overlay / multiply) crushed the whole rail to black instead of
   pitting it, and soft-light against the page backdrop was far too faint. The
   3px borders under/over these strips are now near-black (--black-2) so the
   pits read as dark gaps; the light steel lives in the strip itself. */
.site-header::after,
.site-footer::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 17px;
  background-image: url("../images/chrome-rail.e386a286d4c9.png");
  background-repeat: repeat-x;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.55));
  pointer-events: none;
}

.site-header::after {
  bottom: -10px;
}

.site-footer::before {
  top: -10px;
  /* Start mid-strip so the footer rail is not a copy of the header's pattern. */
  background-position: -1150px 0;
}

/* Content panels stay dark and nearly opaque over the grunge (owner texture
   pass): feed rows and review blocks keep text legible while the texture
   shows through the gaps between them. */
.feed-item,
.review {
  background: rgba(14, 12, 10, 0.88);
  border-radius: 4px;
}

.feed-item {
  padding: 0.5rem 0.6rem;
}

.review {
  padding-left: 0.6rem;
  padding-right: 0.6rem;
}

/* Buttons: lit red controls (owner pass, 2026-09-19; bloom tightened to the
   reference 2026-09-19). The reference button is not flat paint — sampling its
   interior gives luminance ~42 with dark and light blotching, wrapped in a ~2px
   rim that peaks at (245,120,118). Its glow is a *tight* halo, not a wide one:
   the mockup's luminance sits at flat backdrop until ~3px out and only lifts at
   the rim (2px above / 4px below at backdrop+4). So the fill is a mottled
   crimson tile over a dark-to-darker red gradient (the light lives in the edge,
   not the middle), and the rim carries hot glass plus three close bloom stops,
   same motif as the nav tube (R67) and the relit wordmark (R68). */
button,
.btn {
  background-color: #861713;
  background-image: var(--neon-mottle),
    linear-gradient(180deg, #9c1d17 0%, #861713 45%, #6b100e 100%);
  border: 2px solid var(--neon-rim);
  border-radius: 7px;
  box-shadow:
    inset 0 0 10px rgba(255, 74, 52, 0.5),
    inset 0 1px 0 rgba(255, 205, 195, 0.3),
    0 0 3px rgba(255, 96, 74, 0.8),
    0 0 7px rgba(255, 45, 32, 0.45),
    0 0 12px rgba(255, 30, 20, 0.18);
  text-shadow: 0 1px 2px rgba(46, 2, 2, 0.8);
}

button:hover,
.btn:hover {
  box-shadow:
    inset 0 0 12px rgba(255, 96, 70, 0.6),
    inset 0 1px 0 rgba(255, 205, 195, 0.35),
    0 0 4px rgba(255, 110, 86, 0.9),
    0 0 9px rgba(255, 55, 40, 0.52),
    0 0 15px rgba(255, 35, 24, 0.22);
}

/* A disabled control must not read as lit. */
button:disabled {
  border-color: #93504a;
  box-shadow: inset 0 0 8px rgba(120, 30, 22, 0.5);
  filter: saturate(0.55) brightness(0.8);
  cursor: default;
}

/* Poster / thumbnail placeholders: halftone dot fill (borders stay warm-brown). */
.poster-placeholder,
.thumb-placeholder,
.suggest-thumb-placeholder {
  background-image: radial-gradient(circle at center, rgba(233, 223, 203, 0.09) 1px, transparent 1.7px);
  background-size: 8px 8px;
}

/* --- Home 2-pane + rail (M6 artwork C, R64) ---------------------------------
   The home page runs as wide as the marquee band above it so the feed's left
   edge sits under the wordmark and the rail's right edge under the profile
   corner; every other page keeps the 40rem reading column. Below the stack
   point the rail falls in from the right and its two panels sit side by side. */
.container.wide-main {
  max-width: 72rem;
}

.home-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 22rem;
  gap: 2.5rem;
  align-items: start;
}

.rail {
  display: grid;
  gap: 1.5rem;
  /* The rail and feed share the document scroll. */
  position: static;
  max-height: none;
  overflow: visible;
}

/* The footer's second home (R131): the same partial the wide band uses,
   restacked for the 22rem column. One zone per row, each centred, instead of
   three zones spread across 72rem. The wrapper class is the only difference at
   the call site — which is the point: one body, two placements. Values are the
   ones the owner approved in the browser prototype, including the lighter top
   border: inside the rail the footer follows the genres panel, so a 3px seam
   reads as a second band boundary. */
.site-footer--rail {
  margin-top: 1.25rem;
  border-top-width: 2px;
}

.site-footer--rail .container {
  max-width: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.7rem;
  padding-top: 1.1rem;
  padding-bottom: 1.2rem;
}

.site-footer--rail .footer-signoff {
  justify-content: center;
}

/* The brand block centres on the tagline, not on itself. The single auto column
   is sized by the tagline (the wider line) and centred; the wordmark is placed
   at that column's left edge, so REELTALK's left edge meets the beginning of
   the phrase instead of the pair floating as one shrink-wrapped box with dead
   space after the tagline. Live dependency, not a coincidence: it holds while
   the tagline is wider than the wordmark. Shorten the tagline below the
   wordmark's width and the column sizes to the wordmark instead, the tagline
   centres inside it, and the two left edges stop meeting. */
.rail .footer-brand {
  display: grid;
  justify-content: center;
}

.rail .footer-wordmark {
  grid-row: 1;
  grid-column: 1;
  justify-self: start;
}

.rail .footer-tagline {
  grid-row: 2;
  grid-column: 1;
  justify-self: center;
}

/* Pane heading with the red hairline running out toward the rail. */
.pane-title {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin: 1.25rem 0 1rem;
  font-size: 2.5rem;
  line-height: 1;
  text-transform: uppercase;
  color: var(--cream);
}

.pane-title::after {
  content: "";
  flex: 1;
  height: 2px;
  background: linear-gradient(90deg, var(--red-bright), rgba(212, 43, 38, 0));
  box-shadow: 0 0 8px rgba(255, 65, 56, 0.4);
}

.pane-sub {
  margin: -0.6rem 0 1.25rem;
  font-size: 0.9rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* The owner-supplied ticket graphics head each rail card and print its title
   themselves (R64), so the cards under them need no heading of their own. */
.rail-banner {
  width: 100%;
  height: auto;
  transform: rotate(-0.8deg);
  filter: drop-shadow(0 7px 14px rgba(0, 0, 0, 0.55));
}

/* The trending card is a plain list on the dark rail surface: rank chip, title,
   review count. */
.trending-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.trending-list li {
  display: grid;
  grid-template-columns: 1.5rem minmax(0, 1fr);
  align-items: baseline;
  column-gap: 0.55rem;
  padding-bottom: 0.45rem;
  border-bottom: 1px solid rgba(233, 223, 203, 0.12);
}

.trending-list li:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.trending-rank {
  width: 1.4rem;
  height: 1.4rem;
  border: 1px solid var(--line);
  border-radius: 50%;
  font-size: 0.72rem;
  line-height: 1.35rem;
  text-align: center;
  color: var(--cream-muted);
}

.trending-film {
  font-weight: 600;
  text-decoration: none;
  color: var(--cream);
}

/* Scoped to the anchor: the anonymous rail renders the same text in a <span>,
   and :hover matches spans too — an unscoped rule would make the dead text
   light up as if it were clickable. */
a.trending-film:hover {
  color: var(--link);
  text-decoration: underline;
}

.trending-year {
  font-weight: 400;
  color: var(--muted);
}

.trending-count {
  grid-column: 2;
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Heading a graphic already shows sighted readers (the ticket banner). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Popular Genres: dark panel matching the feed panels, amber-lit pills on hover. */
.rail-panel {
  padding: 0.9rem 1rem 1.1rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: rgba(14, 12, 10, 0.88);
}

.rail-panel h2 {
  margin: 0 0 0.7rem;
  font-size: 1.5rem;
  text-transform: uppercase;
  color: var(--cream);
}

.genre-pills {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}

/* One class on both the member's <a> and the visitor's <span>, so the pill
   looks identical either way; only the anchor gets the hover treatment. */
.genre-pill {
  display: inline-block;
  padding: 0.2rem 0.65rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgba(27, 23, 19, 0.85);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--cream-muted);
}

a.genre-pill:hover {
  border-color: var(--amber);
  background: var(--amber);
  color: #12100d;
}

@media (max-width: 64rem) {
  .home-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 2rem;
  }

  .rail {
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    /* Below the stack point the rail falls in under the feed and goes back to
       ordinary document flow — the narrow-layout mapping §2I records for
       Mastodon (`layout-single-column { height: auto }`). A viewport-capped
       sticky scroller under a long feed would hide the footer behind its own
       scrollbar and make the reader hunt for it. */
    position: static;
    max-height: none;
    overflow: visible;
    overscroll-behavior: auto;
  }
}

/* --- Typography roles (M6 artwork, R60) ------------------------------------
   Placed last so these win over the `font: inherit` shorthands above. Bebas
   Neue for titles/section headings and the lit red controls; Oswald for
   metadata/small headings; Archivo (the body default) is used everywhere else,
   including the header's own text — see the rules below. */
h1,
h2 {
  font-family: var(--display);
  letter-spacing: 0.02em;
}

.meta-list,
.handle,
table.results th,
.search-row .watchlist-btn,
.pane-sub,
.trending-rank,
.trending-count,
.genre-pill {
  font-family: var(--ui);
}

/* The lit red controls take the marquee face (owner pass, 2026-09-19): Bebas
   Neue in caps, which is what the reference's button label reads as. Bebas
   ships a single weight, so 400 is explicit — leaving the inherited 600 would
   synthesise faux-bold — and it runs condensed, so the size and tracking step up
   to hold the control's presence; line-height holds the box at the height it had
   under Oswald. */
button,
.btn {
  font-family: var(--display);
  font-weight: 400;
  font-size: 1.1rem;
  line-height: 1.4;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* Ghost controls (Block / Follow / one-click Add to watchlist) share the
   `button` element but are not lit red, so they keep the metadata face and their
   own sentence case, weight, tracking and leading rather than inheriting the
   marquee label above. The reply composer's submit joins for the same reason: it
   is a bare `<button>` in a form that is not `form.inline`, and a caps marquee
   label on a reply box would read as a lit CTA rather than a small inline
   control. The applaud control left this list on the 2026-10-05 pass — it carries
   no text at all now, the word being baked into the artwork, so there is no
   label here for it to get wrong. */
form.inline button,
.search-row .watchlist-btn,
.reply-form button {
  font-family: var(--ui);
  font-weight: 600;
  line-height: 1.55;
  letter-spacing: normal;
  text-transform: none;
}

/* The header's text takes the film-title face (owner pass, R69): the nav row, its
   borderless Log out control and the profile link read in Archivo at the trending
   card's weight, so the marquee speaks the same voice as the rail it leads into.
   Log out is listed because the `button` role above claims it otherwise.
   The films-page tabs join here on the owner's pass of 2026-10-04 — "the same
   font as the nav bar type". They keep their own padding and active underline,
   which is what makes them tabs rather than nav links; only the voice changes. */
.site-nav a,
.site-nav form.inline button,
.header-user a,
.tabs a {
  font-family: var(--body);
  font-weight: 600;
}

/* --- Invite box (R82) -------------------------------------------------
   The pitch and the INVITE control on one's own profile, with the freshly
   minted single-use link under it once generated. Panel treatment matches
   the home rail's panels so it reads as an object the site already has.
   The Invite control deliberately sits in a plain <form>, NOT form.inline:
   form.inline strips the lit red fill and forces sentence case, and the
   label here is the caps control. */
.invite-box {
  margin: 1.5rem 0;
  padding: 0.9rem 1rem 1.1rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: rgba(14, 12, 10, 0.88);
}

.invite-pitch {
  margin: 0;
  font-family: var(--ui);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--cream);
}

.invite-form {
  margin: 0;
}

.invite-result {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.9rem;
}

/* flex-basis instead of the base input's width:100%, so the copy button sits
   beside the link and the pair wraps rather than overflowing under 40rem.
   min-width:0 is what lets a long URL shrink instead of shoving the button
   out of the row. */
.invite-url {
  flex: 1 1 16rem;
  min-width: 0;
  font-family: var(--ui);
  font-size: 0.78rem;
}

.invite-result .btn {
  margin-top: 0;
  white-space: nowrap;
}

.invite-note {
  flex-basis: 100%;
  margin: 0.15rem 0 0;
  font-size: 0.75rem;
  color: var(--muted);
}

/* --- User lists (§2K increment 2) -----------------------------------------
   The list page and the lists page. Deliberately small: the control row, the
   thread and the composer are all borrowed from the post page, so only the
   two shapes nothing else on this site has — a ranked film row and a card
   of lists — needed new rules. The starting point from the 2026-10-06 mock,
   not a settled design. */

.list-page-head {
  margin-bottom: 0.25rem;
}

/* The title is the page's own voice, so it takes the display face the
   generic h1 rule already gives it. overflow-wrap rather than the default
   so a long unbroken title cannot push the page sideways. */
.list-name {
  margin: 1.25rem 0 0.3rem;
  line-height: 1.05;
  overflow-wrap: anywhere;
}

/* The head's control row is the post page's .review-head, reused rather
   than restyled — only its bottom margin changes, because the title sits
   directly above it here instead of the row opening the article. */
.list-page-head .review-head {
  margin-bottom: 0;
}

.list-length {
  font-family: var(--ui);
  font-size: 0.82rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* A ranked film row: poster + title + year and nothing more (L8). Same
   metrics as .film-row so a list reads as the same kind of object as a
   films list, with the rank column the only thing added in front. */
.rank-list {
  list-style: none;
  padding: 0;
  margin: 1rem 0;
}

.rank-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border);
}

/* The number comes from forloop.counter in the template, never from
   ListItem.rank — a removal leaves its gap behind, so rank is an ordering
   key and this is the ordinal the member reads. */
.rank-num {
  flex: 0 0 1.75rem;
  font-family: var(--ui);
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--muted);
  text-align: right;
}

/* Repeated rather than added to the shared .film-row .thumb group so this
   section stays self-contained; the four values are that group's, so a
   poster in a list is the same size as one on the films page. */
.rank-row .thumb {
  width: 2.5rem;
  height: 3.75rem;
  object-fit: cover;
  border-radius: 3px;
  border: 1px solid var(--border);
  flex-shrink: 0;
}

.rank-film {
  text-decoration: none;
  overflow-wrap: anywhere;
}

.rank-film:hover {
  color: var(--link);
}

.rank-empty {
  padding: 0.5rem 0;
  font-size: 0.9rem;
}

/* The lists page's cards. auto-fill rather than a fixed column count so the
   row reflows on its own instead of needing a breakpoint per width. */
.list-mosaic {
  list-style: none;
  padding: 0;
  margin: 1rem 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: 0.75rem;
}

.list-card {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.85rem 1rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 4px;
}

.list-card:hover {
  background: var(--panel-2);
  border-color: var(--line);
}

.list-card-name {
  font-family: var(--display);
  font-size: 1.35rem;
  line-height: 1.1;
  color: var(--cream);
  text-decoration: none;
  overflow-wrap: anywhere;
}

.list-card-name:hover {
  color: var(--link);
}

.list-card-meta {
  font-family: var(--ui);
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --- List authoring (§2K increment 3) -------------------------------------
   The create page, the editor, and the maker's link into it. Two traps here
   are the same class the reply composer's comment calls out: a bare
   <textarea> and a bare input[type=search] both render browser-default on
   this dark theme, and neither shows up in a diff — only a browser catches
   it. Both are given the field treatment explicitly below. */

.list-edit-section {
  margin: 1.75rem 0;
}

.list-edit-section h2 {
  margin: 0 0 0.5rem;
  font-size: 1.5rem;
}

/* The description field. Same values as .reply-form textarea, copied rather
   than shared so this section stays self-contained. */
.list-text-form textarea {
  width: 100%;
  max-width: 42rem;
  padding: 0.45rem 0.6rem;
  font: inherit;
  color: inherit;
  background: var(--field);
  border: 1px solid var(--brown);
  border-radius: 4px;
  margin-top: 0.25rem;
}

.list-text-form .btn {
  margin-top: 0.9rem;
}

.list-cancel {
  margin-left: 0.75rem;
  font-family: var(--ui);
  font-size: 0.9rem;
  color: var(--muted);
}

.list-cancel:hover {
  color: var(--accent);
}

/* The maker's "Edit list" on the list page. Pushed to the right edge of the
   borrowed .review-head so it cannot crowd the applause and reply counts it
   sits beside. */
.list-edit-link {
  margin-left: auto;
  font-family: var(--ui);
  font-size: 0.82rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}

.list-edit-link:hover {
  color: var(--accent);
}

/* The editor's ranked row: the read page's .rank-row plus a control
   cluster. flex-wrap on the editing row only — three controls beside a
   poster and a title do not fit a phone width, and letting them drop to
   their own line beats shrinking any of the four. */
.rank-edit {
  flex-wrap: wrap;
}

.rank-controls {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex-shrink: 0;
}

/* The up/down/remove controls sit in form.inline, whose
   ``form.inline button`` rule (0,1,2) pins them to 0.9rem --muted, so a
   bare ``.rank-btn`` (0,1,0) loses and the arrows stay at the secondary-text
   colour. The owner's pass of 2026-10-07 took them off that: at
   --cream-muted they read as disabled rather than as available, which is
   the wrong signal for the main way you reorder a list. Scoping to
   ``.rank-controls`` outranks the form rule the same way
   ``.search-row .watchlist-btn`` does elsewhere in this file. */
.rank-controls .rank-btn {
  padding: 0.15rem 0.5rem;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--cream);
}

.rank-controls .rank-btn:hover:not(:disabled) {
  color: var(--white);
  border-color: var(--accent);
  filter: none;
  box-shadow: none;
}

.rank-controls .rank-btn:disabled {
  color: var(--muted);
}

/* The add-film search box. */
.list-add-search {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.5rem 0 1rem;
}

/* The typeahead wrapper. position:relative is what the shared .suggest-list
   anchors to, exactly as the header's .global-search does — the dropdown is
   the same component, not a copy of it. */
.list-add-picker {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  max-width: 28rem;
}

.list-add-search input[type="search"] {
  width: 100%;
  padding: 0.45rem 0.6rem;
  font: inherit;
  color: inherit;
  background: var(--field);
  border: 1px solid var(--brown);
  border-radius: 4px;
}

.list-add-search button {
  margin-top: 0;
  flex-shrink: 0;
}

/* The dropdown's rows are <button>s, not <a>s, because picking one is an
   action rather than a navigation. That means they arrive wearing the lit
   crimson control chrome and the marquee face, and both have to come off —
   otherwise every suggestion row is a big glowing red slab. The hover rule
   repeats the filter/shadow resets for the same reason the base ones do
   (R135). */
.list-add-picker .suggest-row {
  display: flex;
  width: 100%;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.75rem;
  margin: 0;
  font: inherit;
  text-align: left;
  text-decoration: none;
  text-transform: none;
  letter-spacing: normal;
  color: var(--fg);
  background: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
  text-shadow: none;
}

.list-add-picker .suggest-row:hover:not(:disabled),
.list-add-picker .suggest-row.active:not(:disabled) {
  /* Matches the header dropdown's own hover, so the two boxes highlight alike. */
  background: var(--surface-2);
  filter: none;
  box-shadow: none;
}

.list-add-picker .suggest-row:disabled {
  color: var(--muted);
  cursor: default;
  filter: none;
  box-shadow: none;
}

.suggest-row-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

.suggest-row-state {
  flex-shrink: 0;
  font-family: var(--ui);
  font-size: 0.75rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

/* The per-row Add control: the same ghost the search page's one-click
   watchlist button is, so adding to a list and adding to a watchlist look
   like the same kind of action in the same kind of row. */
.add-row .add-btn {
  margin-top: 0;
  padding: 0.25rem 0.7rem;
  font-family: var(--ui);
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.55;
  letter-spacing: normal;
  text-transform: none;
  background: none;
  color: var(--accent);
  border: 1px solid var(--border);
  box-shadow: none;
}

.add-row .add-btn:hover {
  border-color: var(--accent);
  filter: none;
  box-shadow: none;
}

.add-state {
  font-family: var(--ui);
  font-size: 0.78rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* The delete sits last and quietest. Every primary control on this site is
   lit crimson, so a destructive one styled as a primary would be the
   loudest thing on the page and the easiest to hit by accident; it takes
   the ghost look and only picks up the accent on hover. The hover rule
   repeats the filter/shadow resets because button:hover outspecs a bare
   class-level reset the moment the cursor arrives (R135). */
.list-delete-section {
  margin-top: 2.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
}

.btn-danger {
  font-family: var(--ui);
  font-weight: 600;
  font-size: 0.9rem;
  line-height: 1.55;
  letter-spacing: normal;
  text-transform: none;
  padding: 0.3rem 0.85rem;
  background: none;
  color: var(--muted);
  border: 1px solid var(--border);
  box-shadow: none;
  text-shadow: none;
}

.btn-danger:hover {
  color: var(--accent);
  border-color: var(--accent);
  filter: none;
  box-shadow: none;
}

/* The "New list" entry on one's own lists page. */
.list-toolbar {
  margin: 1.25rem 0 0.5rem;
}

.list-toolbar .btn {
  margin-top: 0;
}

/* --- Saving a list (§2K increment 5, L2 / R140) -------------------------
   The Save control and the notice a deleted list wears on the Saved tab. */

/* The Save control is `.btn` and nothing more — R140 2 ruled that lit
   crimson weight and explicitly parked any further design work on it for a
   future whole-UI pass, so the only line here is the reset R134 #6 demands
   of anything dropped into `.review-head`: `button, .btn` carries
   `margin-top: 1rem` and that rule is not opt-in. */
.list-save-btn {
  margin-top: 0;
}

/* A saved list whose maker deleted it stays on the Saved tab until its saver
   dismisses the notice (R140 1). What it must NOT do is read as navigable:
   the title is a plain span because `/list/<id>/` 404s, and the hover
   background is exactly what sells a card as a link. So the hover is pinned
   back to the resting paint — same specificity as `.list-card:hover`, later
   in the file, which is what makes it win — and the whole card sits at
   reduced emphasis to match being a record rather than a destination. */
.list-card-deleted {
  opacity: 0.62;
}

.list-card-deleted:hover {
  background: var(--panel);
  border-color: var(--border);
}

.list-card-deleted .list-card-name {
  color: var(--muted);
}

/* The notice line: the sentence and its Dismiss control together, wrapping
   onto a second line at narrow widths rather than overflowing the card. The
   Dismiss button rides in `form.inline`, which already gives it the small
   muted ghost look — deliberately NOT `.btn`, whose lit fill would make
   dismissing louder than the fact being dismissed. */
.list-deleted-notice {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.6rem;
  margin: 0.3rem 0 0;
  font-family: var(--ui);
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--cream);
}

/* Home feed polish (owner approved): larger avatars, clean continuous rows,
   and film posters aligned beneath the author with prose alongside. */
.feed .review-list {
  background: #0e0c0a;
  border-top: 1px solid var(--line);
}

.feed .review {
  padding: 18px 18px 18px 76px;
  border-radius: 0;
  background: transparent;
  min-height: 88px;
}

.feed .review-head {
  gap: 10px;
  margin-bottom: 8px;
  min-height: 28px;
}

.feed .avatar-row {
  position: absolute;
  left: 16px;
  top: 18px;
  width: 44px;
  height: 44px;
}

.feed .review-head .applaud {
  margin-left: auto;
}

.feed .feed-item {
  background: transparent;
  border-radius: 0;
  padding: 0;
  margin: 4px 0 8px;
}

.feed .review:has(> .feed-item) {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  column-gap: 16px;
  min-height: 164px;
  align-content: start;
  grid-template-rows: auto auto 1fr;
}

.feed .review:has(> .feed-item) > .review-head {
  grid-column: 1 / -1;
}

.feed .review > .feed-item {
  display: contents;
}

.feed .feed-item .thumb {
  position: static;
  grid-column: 1;
  grid-row: 2 / 4;
  width: 64px;
  height: 96px;
  border-radius: 2px;
}

.feed .feed-item .feed-film {
  grid-column: 2;
  grid-row: 2;
  align-self: start;
}

.feed .review:has(> .feed-item) > .review-body {
  grid-column: 2;
  grid-row: 3;
  min-width: 0;
}

.feed .review-body p {
  margin: 8px 0;
}

.feed .list-strip {
  margin: 4px 0 0;
}

.feed .list-strip-title {
  margin: 4px 0 10px;
}

@media (max-width: 600px) {
  .feed .review {
    padding: 16px 12px 16px 62px;
  }

  .feed .avatar-row {
    left: 12px;
    top: 16px;
    width: 36px;
    height: 36px;
  }

  .feed .review:has(> .feed-item) {
    grid-template-columns: 48px minmax(0, 1fr);
    column-gap: 12px;
    min-height: 132px;
  }

  .feed .feed-item .thumb {
    width: 48px;
    height: 72px;
  }

  .feed .review-head {
    gap: 6px 10px;
  }

  .feed .review-head .applaud {
    margin-left: 0;
  }

}
/* Home-feed identity and metadata hierarchy. */
.feed .review-author {
  color: var(--cream);
  font-weight: 700;
  text-decoration: none;
}

.feed .feed-film a {
  text-decoration: none;
  text-underline-offset: 3px;
}

.feed .review-author:hover,
.feed .review-author:focus-visible,
.feed .feed-film a:hover,
.feed .feed-film a:focus-visible {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.feed .review-head {
  column-gap: 14px;
  row-gap: 8px;
  font-family: var(--body);
  font-size: 0.95rem;
}

.feed .review-head .feed-verb {
  font-family: inherit;
  font-size: inherit;
  font-weight: 400;
}

.feed .post-date {
  font-family: inherit;
  font-size: inherit;
  font-weight: 400;
  letter-spacing: normal;
  color: var(--white);
}

.feed .feed-film {
  font-weight: 400;
  line-height: 1.45;
}

.feed .feed-film a {
  font-weight: 650;
}

@media (max-width: 600px) {
  .feed .review-head {
    column-gap: 10px;
    row-gap: 8px;
  }
}
/* Home feed section heading: compact display type and a restrained red rule. */
.feed .pane-title {
  font-size: 2rem;
  gap: 18px;
}

.feed .pane-title::after {
  max-width: 350px;
  background: linear-gradient(90deg, var(--red-bright), rgba(255, 65, 56, 0));
  box-shadow: none;
}
/* Feed prose links, including mentions: consistent with author/film links. */
.feed .review-body a {
  text-decoration: none;
  text-underline-offset: 3px;
}

.feed .review-body a:hover,
.feed .review-body a:focus-visible {
  text-decoration: underline;
}
/* Home rail: closer grouping and a restrained shadow beneath ticket artwork. */
.rail {
  gap: 1rem;
}

.rail-banner {
  filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.4));
}
/* Genre tags: compact rectangular labels beside the ticket artwork. */
.genre-pill {
  border-radius: 4px;
  background: #100e0c;
}
/* Trending rank markers: filled discs with clearly weighted numerals. */
.trending-list li {
  grid-template-columns: 32px minmax(0, 1fr);
  column-gap: 9px;
}

.trending-rank {
  width: 27px;
  height: 27px;
  display: grid;
  place-items: center;
  background: #4b3b2c;
  border: 1px solid var(--cream);
  color: #f3e3c7;
  font-family: var(--ui);
  font-weight: 700;
  font-size: 0.85rem;
  line-height: 1;
}
/* Header search: decorative cream magnifier with a clear text gutter. */
.global-search input[type="search"] {
  padding-left: 2.6rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%23e9dfcb' stroke-width='1.8' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='m15.5 15.5 5 5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: 0.9rem center;
  background-size: 18px 18px;
}

/* Shared cinema controls: keep after legacy component rules so all opt-in
   controls use the same typography, rim, hover and touch dimensions. */
.film-actions button,
.film-actions .btn,
.btn.cinema-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 38px;
  margin-top: 0;
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--cream-muted);
  border-radius: 4px;
  background: linear-gradient(180deg, #171410, #090807);
  color: var(--cream);
  box-shadow: inset 0 0 0 1px rgba(233, 223, 203, 0.08);
  font-family: var(--body);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: normal;
  text-transform: none;
  transition: background-color 150ms ease, border-color 150ms ease;
  text-shadow: none;
}

.film-actions button:hover,
.film-actions .btn:hover,
.btn.cinema-button:hover {
  background: linear-gradient(180deg, #282118, #15110d);
  border-color: var(--cream);
  color: var(--cream);
  box-shadow: inset 0 0 0 1px rgba(233, 223, 203, 0.12);
  filter: none;
}

.film-actions .film-watched,
.btn.cinema-button--primary {
  background: linear-gradient(180deg, #891c18, #60100e);
  border: 1px solid #df5a50;
  color: #fff2e4;
  box-shadow:
    inset 0 0 6px rgba(255, 74, 52, 0.14),
    0 0 3px rgba(255, 45, 32, 0.22);
}

.film-actions .film-watched:hover,
.btn.cinema-button--primary:hover {
  background: linear-gradient(180deg, #a42620, #761411);
  border-color: #ef7368;
  color: #fff2e4;
  box-shadow:
    inset 0 0 6px rgba(255, 74, 52, 0.2),
    0 0 5px rgba(255, 45, 32, 0.3);
}

.film-actions button:focus-visible,
.film-actions .btn:focus-visible,
.btn.cinema-button:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 3px;
}

.film-actions svg,
.cinema-button svg {
  width: 16px;
  height: 16px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (max-width: 600px), (pointer: coarse) {
  .film-actions button,
  .film-actions .btn,
  .btn.cinema-button {
    min-height: 44px;
  }
}


.btn.cinema-button:disabled {
  opacity: 0.55;
  filter: none;
  box-shadow: none;
  cursor: default;
}
