/* css/styles.css
 *
 * No Bootstrap. Everything here is deliberate.
 *
 * The two rules that fix the wonky cards in the old design:
 *   - the poster slot is a locked 2:3 box (posters are NOT all the same shape)
 *   - the title slot is a locked two-line box (long names used to grow the card)
 * Together they guarantee every tile is exactly the same height, always.
 */

/* ========================================================================= */
/* Tokens                                                                    */
/* ========================================================================= */
:root {
  color-scheme: only dark;
  --bg:            #0f0f11;
  --bg-raised:     #191a1d;
  --bg-raised-2:   #212328;
  --line:          #2c2e34;
  --text:          #f2f2f4;
  --text-dim:      #a3a5ad;
  --text-faint:    #74767e;

  --yes:           #1f8f3c;
  --yes-soft:      #123f21;
  --no:            #b03038;
  --no-soft:       #3f1519;
  --tie:           #9a7513;
  --tie-soft:      #3a2d0c;
  --unknown:       #4d5058;
  --unknown-soft:  #26282e;

  --accent:        #f5c518;   /* the IMDb yellow, used only for ratings */

  --radius:        14px;
  --radius-sm:     9px;
  --tile-w:        186px;
  --tile-gap:      16px;
  --shadow:        0 6px 22px rgba(0, 0, 0, .45);

  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* ========================================================================= */
/* Base                                                                      */
/* ========================================================================= */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.55;
  overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }
a:hover { text-decoration: none; }

img { max-width: 100%; }

h1, h2, h3 { line-height: 1.2; margin: 0 0 .4em; font-weight: 700; }

button { font: inherit; cursor: pointer; }

:focus-visible { outline: 2px solid #6da8ff; outline-offset: 2px; border-radius: 4px; }

/* ------------------------------------------------------------------------- */
/* Icons                                                                     */
/*                                                                           */
/* `currentColor` is the whole point: one definition of a thumb works on a    */
/* green badge, a red badge and grey body text without a second copy.        */
/* `em` sizing means an icon always matches the text it sits beside.          */
/* ------------------------------------------------------------------------- */
.icon {
  width: 1em;
  height: 1em;
  fill: currentColor;
  flex: 0 0 auto;
  vertical-align: -0.135em;   /* sit on the text baseline, not below it */
}

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

.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--bg-raised); padding: 10px 16px; z-index: 200;
}
.skip-link:focus { left: 8px; top: 8px; }

/* ========================================================================= */
/* Header                                                                    */
/* ========================================================================= */
.site-header {
  position: sticky; top: 0; z-index: 100;
  display: flex; align-items: center; gap: 16px;
  padding: 10px clamp(12px, 3vw, 28px);
  background: rgba(15, 15, 17, .92);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

.site-header__brand {
  display: flex; align-items: center; gap: 9px;
  font-weight: 700; font-size: 1.2rem;
  flex-shrink: 0;
}
.site-header__mark {
  width: 48px; height: 48px; display: block; flex: 0 0 auto;
  filter: none !important;
  forced-color-adjust: none;
}
.site-header__name { white-space: nowrap; }

.site-header__search { margin-left: auto; display: flex; position: relative; }
.site-header__search .search-field { width: clamp(210px, 28vw, 380px); }
/* The instant-results panel hangs off the header form, so it needs room to be
   readable even when the field itself is narrow. It grows leftwards. */
.site-header__search .instant-results { left: auto; width: min(420px, 92vw); }

/* ------------------------------------------------------------------------- */
/* Search field                                                              */
/*                                                                           */
/* One pill holds the input and the button. The button is not a separate      */
/* control sitting next to the field, it is the right-hand cap of it, a       */
/* couple of shades lighter than the well so it reads as pressable without    */
/* turning into a white block. It is the site's only search bar, and it sits  */
/* in the header on every page, phones included.                              */
/* ------------------------------------------------------------------------- */
.search-field {
  display: flex; align-items: stretch;
  min-width: 0;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 999px;
  overflow: hidden;
}
.search-field:focus-within { border-color: #3d4048; }
.search-field input {
  flex: 1; min-width: 0;
  padding: 15px 22px;
  font-size: 1.05rem;
  background: transparent;
  border: 0;
  color: var(--text);
  outline: none;
}
.search-field input::placeholder { color: var(--text-faint); }
/* Chrome draws its own clear "x" on type=search, which collides with the cap. */
.search-field input::-webkit-search-decoration,
.search-field input::-webkit-search-cancel-button { -webkit-appearance: none; }
.search-field__go {
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
  padding: 0 22px;
  font-size: 1.25rem;
  background: var(--bg-raised-2);
  border: 0;
  border-left: 1px solid var(--line);
  border-radius: 0;
  color: var(--text);
  cursor: pointer;
}
.search-field__go:hover { background: #2c2f36; }
.search-field__go svg { width: 1em; height: 1em; display: block; }

.search-field--sm input { padding: 10px 17px; font-size: 1rem; }
.search-field--sm .search-field__go { padding: 0 16px; font-size: 1.1rem; }

@media (max-width: 760px) {
  .site-header__name { display: none; }
  .site-header__search { flex: 1; }
  .site-header__search .search-field { width: 100%; }
  /* The placeholder carries the full question here, so it is shrunk to fit.
     Typed text keeps its own size; only the placeholder gets smaller. */
  .search-field--sm input { padding: 10px 14px; }
  .search-field--sm input::placeholder { font-size: .84rem; }
}
@media (max-width: 420px) {
  .search-field--sm input::placeholder { font-size: .76rem; }
  .search-field--sm .search-field__go { padding: 0 13px; }
}

main { min-height: 60vh; }

/* Instant search dropdown */
.instant-results {
  position: absolute; left: 0; right: 0; top: calc(100% + 8px);
  z-index: 60;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  text-align: left;
}
.instant-results__item {
  display: flex; align-items: center; gap: 12px;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
}
.instant-results__item:last-child { border-bottom: 0; }
.instant-results__item:hover { background: var(--bg-raised-2); }
.instant-results__item img,
.instant-results__nopic {
  width: 34px; height: 51px; flex: 0 0 34px;
  object-fit: cover; border-radius: 4px; background: #000;
}
.instant-results__text { flex: 1; min-width: 0; }
.instant-results__title {
  display: block; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.instant-results__year { display: block; font-size: .8rem; color: var(--text-faint); }
.instant-results__verdict {
  flex-shrink: 0;
  font-size: .72rem; font-weight: 700; letter-spacing: .04em;
  padding: 4px 9px; border-radius: 999px;
}

/* ========================================================================= */
/* Section headings                                                          */
/* ========================================================================= */
.row-section { padding: 26px 0 34px; }

/* Each row sits on its own ground, so a long page of poster strips reads as
   distinct sections rather than one endless scroll. Kept very low contrast:
   these are backgrounds, not decoration, and the posters must stay the
   brightest thing on screen. */
.row-section--1 { background: linear-gradient(180deg, rgba(64, 124, 232, .17), transparent 80%); }
.row-section--2 { background: linear-gradient(180deg, rgba(232, 64, 128, .15), transparent 80%); }
.row-section--3 { background: linear-gradient(180deg, rgba(32, 196, 160, .15), transparent 80%); }
.row-section--4 { background: linear-gradient(180deg, rgba(240, 176, 32, .15), transparent 80%); }
.row-section--5 { background: linear-gradient(180deg, rgba(150, 88, 240, .16), transparent 80%); }
.row-section__head { padding: 0 clamp(16px, 4vw, 32px); margin-bottom: 14px; }

.section-title {
  display: flex; align-items: center; gap: 11px;
  font-size: clamp(1.25rem, 2.6vw, 1.6rem);
  margin: 0;
}

/* ========================================================================= */
/* The marquee                                                               */
/*                                                                           */
/* The track holds two identical copies of the tile list. JS advances         */
/* scrollLeft at a constant speed and subtracts one copy's width when it      */
/* reaches the seam, so the loop never visibly restarts.                      */
/* ========================================================================= */
.marquee {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: auto;          /* JS drives this; smooth would fight it */
  scrollbar-width: none;          /* Firefox */
  -ms-overflow-style: none;
  padding: 22px clamp(16px, 4vw, 32px);
}

/* No edge fade. It was a mask-image, which has to be re-rasterised every time
   the thing under it moves, and that is what made the card edges shimmer as a
   row drifted. Replacing it with gradient overlays only moved the problem:
   they smeared dark over each section's own colour and dimmed the headings.
   Cards now simply clip at the container edge, which is what the flicker fix
   actually needed. The real cure is the compositing layer on .movie-tile__link
   below, so the card is painted once rather than on every frame. */
.marquee::-webkit-scrollbar { display: none; }
.marquee.is-dragging { user-select: none; }
/* Only ever set once the pointer has really moved, never on a plain click.
   Setting it on pointerdown made the mouseup hit test to the marquee instead
   of the poster, so no film could be opened. */
.marquee.is-dragging * { pointer-events: none; }

/* Progressive enhancement. The second copy of the tile list only exists to
   make the loop seamless, so it stays hidden until JS is actually driving the
   animation. No JS (or reduced motion) = one clean, swipeable row with no
   duplicates, rather than every poster silently listed twice. */
.movie-tile[aria-hidden="true"] { display: none; }
.marquee--live .movie-tile[aria-hidden="true"] { display: block; }

.marquee__track {
  display: flex;
  width: max-content;
  align-items: stretch;   /* every tile the full height of the tallest */
  overflow-anchor: none;
}

/* The gap lives on the TILE, not as a flex `gap` on the track. A container
   gap leaves a half-gap unaccounted for at the seam, which makes the loop
   jitter by a few pixels on every lap. Margin on each tile divides evenly. */
.movie-tile { margin-right: var(--tile-gap); }

.marquee-empty {
  padding: 24px clamp(16px, 4vw, 32px);
  color: var(--text-faint);
}

/* ========================================================================= */
/* Movie tile                                                                */
/* ========================================================================= */
.movie-tile {
  position: relative;
  flex: 0 0 var(--tile-w);
  width: var(--tile-w);
}

.movie-tile__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  /* Promotes the card to its own layer, so the overlay gradient is rasterised
     once instead of on every scroll frame. This is what stops the flicker. */
  transform: translateZ(0);
  backface-visibility: hidden;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform .18s ease, border-color .18s ease, box-shadow .18s ease;
}
.movie-tile__link:hover,
.movie-tile__link:focus-visible {
  transform: translateY(-4px);
  border-color: #454851;
  box-shadow: var(--shadow);
}

/* A locked 2:3 window. The image crops to fit it rather than deciding the
   card's height for itself.

   The image MUST be position:absolute. An in-flow child contributes its own
   height to the box, and in the flex algorithm that content height beats
   `aspect-ratio` - which is the original bug: a 500x820 poster made a 303px
   slot while a 500x750 one made 277px, and every card below shifted. */
.movie-tile__poster {
  position: relative;
  aspect-ratio: 2 / 3;
  width: 100%;
  background: #000;
  flex: 0 0 auto;
  overflow: hidden;
}
.movie-tile__poster img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

/* Title bottom-left, rating bottom-right, both over the poster.

   This is what keeps the row short. When the title had its own block under the
   poster, every card had to reserve two lines for it, so a row of one-line
   titles carried a band of dead space. Absolutely positioned text cannot add
   to the card's height, so a two-line title now costs nothing at all.

   The two sit in a flex row, so a long title wraps against the rating instead
   of running underneath it. */
.movie-tile__overlay {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 30px 9px 8px;
  background: linear-gradient(to top,
              rgba(0, 0, 0, .93) 0%,
              rgba(0, 0, 0, .8) 38%,
              rgba(0, 0, 0, .34) 72%,
              transparent 100%);
  pointer-events: none;
}

/* Year and rating live in the opposite corner from the title. */
.movie-tile__topright {
  position: absolute;
  top: 7px; right: 7px;
  display: flex; align-items: center; gap: 5px;
  pointer-events: none;
}

.movie-tile__title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin: 0;
  font-size: .88rem;
  font-weight: 700;
  line-height: 1.24;
  overflow-wrap: anywhere;
  hyphens: auto;
  pointer-events: auto;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
}

.movie-tile__year {
  padding: 3px 7px;
  font-size: .7rem; font-weight: 700;
  color: rgba(255, 255, 255, .82);
  background: rgba(0, 0, 0, .72);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
  pointer-events: auto;
}

.movie-tile__rating {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 3px;
  padding: 3px 7px;
  font-size: .72rem; font-weight: 700;
  background: rgba(0, 0, 0, .78);
  border-radius: 999px;
  pointer-events: auto;          /* so it can carry its own tooltip */
}
.movie-tile__star { color: var(--accent); font-size: .8em; }

/* The verdict strip.
   Three facts on one line: what the answer is, how lopsided the vote was, and
   how many votes it rests on. The percentage is ALSO drawn as a fill behind
   the text, so the shape of the answer reads before the numbers do. */
.movie-tile__verdict {
  position: relative;
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  padding: 8px 10px;
  overflow: hidden;
  line-height: 1;
  border-top: 1px solid rgba(255, 255, 255, .07);
}

/* The fill. `currentColor` means it is always a lighter wash of whatever
   colour the verdict already is, so it needs no per-state rule. */
.movie-tile__verdict::before {
  content: '';
  position: absolute;
  top: 0; bottom: 0; left: 0;
  width: var(--fill, 0%);
  background: currentColor;
  opacity: 0;
  pointer-events: none;
}

.movie-tile__verdict.has-vote-split {
  --split-left: var(--yes-soft);
  --split-right: var(--no-soft);
  background: linear-gradient(
    var(--angle, 96deg),
    var(--split-left) 0 calc(var(--split, 50%) - 8%),
    var(--split-right) calc(var(--split, 50%) + 8%) 100%
  );
}
.movie-tile__verdict.has-vote-split.split-majority-no {
  --split-left: var(--no-soft);
  --split-right: var(--yes-soft);
}
.movie-tile__verdict.has-vote-split::before { display: none; }
.movie-tile__verdict.has-vote-split .movie-tile__verdict-meta {
  color: #fff;
  opacity: 1;
}
.movie-tile__verdict.has-vote-split .movie-tile__n { opacity: 1; }
.movie-tile__verdict.verdict--tie { color: #fff; }

.movie-tile__verdict-word,
.movie-tile__verdict-meta { position: relative; }

.movie-tile__verdict-word {
  font-size: .78rem;
  font-weight: 800;
  letter-spacing: .07em;
  white-space: nowrap;
  /* Uppercased here rather than in the data, so screen readers still get
     "Yes" and not "Y. E. S." */
  text-transform: uppercase;
}

.movie-tile__verdict-meta {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  font-size: .7rem;
  font-weight: 700;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  opacity: .85;
}
.movie-tile__sep { opacity: .4; font-weight: 400; padding: 0 1px; }
.movie-tile__n   { opacity: .8; font-weight: 600; }
.movie-tile__verdict-meta--empty {
  font-size: .68rem; font-weight: 600; opacity: .6; letter-spacing: .01em;
}

/* On the narrowest cards the vote count is the first thing to go: the word
   and the percentage are what matter, and the count is in the tooltip. */
@media (max-width: 480px) {
  .movie-tile__verdict { padding: 7px 8px; }
  .movie-tile__verdict-word { font-size: .72rem; letter-spacing: .05em; }
  .movie-tile__sep, .movie-tile__n { display: none; }
}

/* The emoji badge, kept. */
.icon-circle {
  position: absolute;
  top: -14px; left: -10px;
  width: 50px; height: 50px;
  display: flex; align-items: center; justify-content: center;
  font-size: 2.04rem; line-height: 1;
  color: #fff;
  border-radius: 50%;
  border: 3px solid var(--bg);
  box-shadow: 0 3px 10px rgba(0, 0, 0, .5);
  pointer-events: auto;   /* it carries its own tooltip */
  z-index: 2;
  filter: none !important;
  forced-color-adjust: none;
}
.icon-circle.thumbs-up    { background: var(--yes); }
.icon-circle.thumbs-down  { background: var(--no); }
.icon-circle.question-mark{ background: var(--unknown); }
.icon-circle.split        { background: #d6a000; }

/* ========================================================================= */
/* Verdict colours, shared everywhere                                        */
/* ========================================================================= */
.verdict--yes     { background: var(--yes-soft);     color: #7ee29a; }
.verdict--no      { background: var(--no-soft);      color: #ff9ba1; }
.verdict--tie     { background: var(--tie-soft);     color: #f0d183; }
.verdict--unknown { background: var(--unknown-soft); color: var(--text-dim); }

.verdict-inline {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 5px;
  font-size: .85em;
  letter-spacing: .05em;
}

/* ========================================================================= */
/* How it works                                                              */
/* ========================================================================= */
.how-it-works {
  padding: 44px clamp(16px, 4vw, 32px) 60px;
  border-top: 1px solid var(--line);
  margin-top: 20px;
}
.how-it-works > h2 { font-size: 1.4rem; margin-bottom: 20px; }
.how-it-works__grid {
  display: grid;
  gap: 22px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  max-width: 1100px;
}
.how-it-works h3 { font-size: 1.02rem; margin-bottom: .3em; }
.how-it-works p { margin: 0; color: var(--text-dim); font-size: .94rem; }

/* ========================================================================= */
/* Search results                                                            */
/* ========================================================================= */
.search-results {
  max-width: 980px;
  margin: 0 auto;
  padding: 28px clamp(16px, 4vw, 32px) 60px;
}
.search-results__title { font-size: clamp(1.3rem, 3vw, 1.75rem); margin-bottom: 22px; }

.movie-row {
  display: flex;
  gap: 14px;
  align-items: stretch;
  padding: 14px;
  margin-bottom: 14px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.movie-row:hover { border-color: #40434c; }

/* The vote control IS the progress bar: two stacked segments sized by the
   split, each one the button for its own side. Reading the balance and
   changing it happen in the same place. */
.votebar {
  flex: 0 0 46px;
  display: flex; flex-direction: column;
  width: 46px;
  border-radius: 11px;
  overflow: hidden;
  background: var(--line);
}
.votebar__half {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px;
  border: 0; padding: 6px 2px;
  color: #fff; cursor: pointer;
  font-size: .62rem; font-weight: 800;
  line-height: 1;
  transition: filter .15s ease, flex-basis .7s cubic-bezier(.22, .9, .28, 1);
  min-height: 34px;
}
.votebar__half--yes { background: var(--yes); flex: 0 0 var(--yes-share, 50%); }
.votebar__half--no  { background: var(--no);  flex: 1 1 auto; }
.votebar__half:hover:not(:disabled) { filter: brightness(1.22); }
.votebar__half:disabled { opacity: .6; cursor: default; }
.votebar__half.active { box-shadow: inset 0 0 0 2px #fff; }
.votebar__icon { font-size: 1.05rem; }
.votebar__pct { font-variant-numeric: tabular-nums; opacity: .9; }

.movie-row__poster { flex: 0 0 110px; }
.movie-row__poster img {
  width: 110px;
  height: 165px;        /* 110 x 165 is exactly 2:3 */
  object-fit: cover;
  border-radius: var(--radius-sm);
  display: block;
  background: #000;
}

.movie-row__body { flex: 1; min-width: 0; }
.movie-row__head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 9px; }
.movie-row__title { flex: 1; min-width: 0; font-size: 1.16rem; margin: 0; }
.movie-row__title a:hover { text-decoration: underline; }
.movie-row__year { color: var(--text-faint); font-weight: 400; }
.movie-row__ratings { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 6px; }

.movie-row__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 9px;
  margin: 0 0 9px;
  font-size: .85rem;
}
.badge-verdict {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 11px;
  border-radius: 999px;
  font-weight: 700; font-size: .76rem; letter-spacing: .05em;
}
.badge-verdict__pct { opacity: .75; font-weight: 600; }

.badge-score {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 4px 10px;
  background: var(--bg-raised-2);
  border-radius: 999px;
  font-size: .78rem; font-weight: 700;
}
.badge-score__star { color: var(--accent); font-size: .9em; }
.badge-score__src { color: var(--text-faint); font-weight: 600; font-size: .68rem; }
.movie-row__ratings .badge-score:hover { background: #2d3036; }
.badge-score--imdb .badge-score__src { color: var(--accent); }
.badge-score--tmdb .badge-score__src {
  color: #84cfa6;
  background: linear-gradient(90deg, #84cfa6 0%, #41bfcb 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
}

.movie-row__votes { color: var(--text-faint); font-size: .8rem; }

.movie-row__overview {
  margin: 0 0 10px;
  color: var(--text-dim);
  font-size: .92rem;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.movie-row__actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin: 0;
}
.vote-icons--row { display: flex; gap: 6px; }
.vote-icons--row .vote-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  background: var(--bg-raised-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--text);
  font-size: .85rem; font-weight: 600;
}
.vote-icons--row .vote-btn__icon { font-size: 1.05rem; }
.vote-icons--row .up-vote-btn:hover:not(:disabled),
.vote-icons--row .up-vote-btn.active   { border-color: var(--yes); background: var(--yes-soft); }
.vote-icons--row .down-vote-btn:hover:not(:disabled),
.vote-icons--row .down-vote-btn.active { border-color: var(--no);  background: var(--no-soft); }
.vote-icons--row .vote-btn:disabled { opacity: .55; cursor: default; }

.movie-row__cta { margin: 6px 0 0; }

/* The link out of a search result is the main action on that row, so it looks
   like a button rather than a sentence with an arrow after it. */
.btn-primary {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 17px;
  background: var(--text);
  color: #111;
  border-radius: 999px;
  font-size: .86rem; font-weight: 700;
  transition: background .15s ease, transform .15s ease;
}
.btn-primary:hover { background: #fff; transform: translateY(-1px); text-decoration: none; }
.btn-primary__chev { font-size: .78em; opacity: .55; }

.btn-ghost {
  display: inline-block;
  padding: 7px 15px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: .85rem; font-weight: 600;
  color: var(--text-dim);
}
.btn-ghost:hover { border-color: #565a65; color: var(--text); }

.empty-state {
  padding: 50px clamp(16px, 4vw, 32px);
  text-align: center;
  color: var(--text-dim);
}
.empty-state a { text-decoration: underline; }

@media (max-width: 600px) {
  .movie-row { flex-wrap: wrap; }
  .movie-row__body { flex: 1 1 100%; order: 3; text-align: left; }
  .votebar { flex: 0 0 40px; width: 40px; }
  .movie-row__poster { flex: 0 0 92px; }
  .movie-row__poster img { width: 92px; height: 138px; }
}

/* ========================================================================= */
/* Movie page                                                                */
/* ========================================================================= */
.movie-page {
  max-width: 1080px;
  margin: 0 auto;
  padding: 28px clamp(16px, 4vw, 32px) 64px;
}
.movie-page__h1 {
  font-size: clamp(1.35rem, 3.6vw, 2.15rem);
  letter-spacing: -.015em;
  margin-bottom: 24px;
}

.movie-page__grid {
  display: grid;
  grid-template-columns: 280px 1fr;
  gap: 30px;
  align-items: start;
}
.movie-page__main { min-width: 0; }
@media (max-width: 820px) {
  .movie-page__grid { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .movie-page__posterwrap,
  .movie-page__main { display: contents; }
  .movie-page__grid .movie-page__posterbtn {
    width: 100vw;
    margin-left: calc(50% - 50vw);
  }
  .movie-page__main > .answer { order: 1; }
  .movie-page__main > .factbar { order: 2; }
  .movie-page__main > .synopsis { order: 3; }
  .movie-page__main > .trailer { order: 4; }
  .movie-page__resources { order: 5; min-width: 0; }
  .movie-page__main > .credits { order: 6; }
}

.movie-page__posterbtn {
  display: block;
  position: relative;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: var(--radius);
  overflow: hidden;
}
.movie-page__zoom {
  position: absolute;
  right: 9px; bottom: 9px;
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  font-size: 1rem;
  color: #fff;
  background: rgba(0, 0, 0, .62);
  border-radius: 50%;
  opacity: 0;
  transition: opacity .18s ease;
  pointer-events: none;
}
.movie-page__posterbtn:hover .movie-page__zoom,
.movie-page__posterbtn:focus-visible .movie-page__zoom { opacity: 1; }

.movie-page__poster {
  width: 100%;
  /* `height: auto` is load-bearing. The <img> carries width/height attributes
     (which stop the page jumping as it loads), and those map to an absolute
     CSS height that would otherwise beat `aspect-ratio` and stretch the box. */
  height: auto;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  display: block;
  background: #000;
}

/* The answer block. Verdict, split, and the two buttons that change it, all
   in one card: the verdict IS the vote count, so separating them put half the
   point of the page below the fold. */
/* Compact on purpose. The verdict, the split and the two buttons are three
   short lines of information, and the block used to take a screenful to say
   them. Everything here is sized to fit in half the height it did. */
.answer {
  padding: 11px 13px 12px;
  border-radius: var(--radius);
  margin-bottom: 14px;
  /* A vote can turn this block from grey to green or green to red. That is
     the single most important thing a vote does, so it fades rather than
     cutting: a cut is indistinguishable from a page that never changed. */
  transition: background-color .55s ease, color .55s ease;
}
.answer__head { display: flex; align-items: center; gap: 11px; }
.answer__icon { font-size: 1.7rem; line-height: 1; margin: 0; flex: 0 0 auto; }
.answer__headline { font-size: clamp(1rem, 2.1vw, 1.22rem); margin: 0; min-width: 0; }

/* One gradient, green into red, centred on the yes percentage. The
   angle comes from the film id, so the dividing line leans a few degrees one
   way or the other rather than being a dead straight vertical on every page.
   When both sides have votes, the colours blend around that diagonal. */
.answer__bar {
  display: flex;
  height: 22px;
  margin: 9px 0 0;
  border-radius: 999px;
  overflow: hidden;
  /* --split is registered below, which is what lets the gradient slide to the
     new balance instead of jumping to it. */
  transition: --split .7s cubic-bezier(.22, .9, .28, 1);
  font-size: .72rem; font-weight: 600;
  background: linear-gradient(
    var(--angle, 96deg),
    var(--yes) 0 var(--split, 50%),
    var(--no)  var(--split, 50%) 100%
  );
}
.answer__bar.has-vote-split {
  background: linear-gradient(
    var(--angle, 96deg),
    var(--yes) 0 calc(var(--split, 50%) - 8%),
    var(--no)  calc(var(--split, 50%) + 8%) 100%
  );
}
/* Each half shows its own count, and its percentage. A half with no votes
   shows nothing: an empty side already says zero, and a "0%" pinned to the
   end of the bar reads as a scale label, which this is not. */
.answer__bar span {
  display: flex; align-items: center; gap: 5px;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .55);
  /* Same curve and length as the gradient above, so the label edge and the
     colour edge travel together. */
  transition: width .7s cubic-bezier(.22, .9, .28, 1);
}
.answer__bar strong { font-weight: 800; }
.answer__bar-yes { width: var(--split, 50%); padding-left: 11px; }
.answer__bar-no  { flex: 1; justify-content: flex-end; padding-right: 11px; }

.answer__vote { display: flex; gap: 8px; margin-top: 9px; }
.answer__vote .vote-btn {
  flex: 1;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  padding: 7px 12px;
  background: rgba(0, 0, 0, .28);
  border: 2px solid rgba(255, 255, 255, .14);
  border-radius: 9px;
  color: inherit;
  font-size: .84rem; font-weight: 700;
  transition: transform .12s ease, border-color .12s ease, background .12s ease;
}
.answer__vote .vote-btn__icon { font-size: 1.1rem; }
/* Each button carries its own colour on hover and when it is your vote, so
   the NO button is always red and the YES button always green, whatever
   verdict the banner behind them happens to be. */
.answer__vote .vote-btn:hover:not(:disabled),
.answer__vote .vote-btn:focus-visible { transform: translateY(-1px); }

.answer__vote .up-vote-btn:hover:not(:disabled),
.answer__vote .up-vote-btn.active {
  background: var(--yes);
  border-color: #55c97a;
  color: #fff;
}
.answer__vote .down-vote-btn:hover:not(:disabled),
.answer__vote .down-vote-btn.active {
  background: var(--no);
  border-color: #ef7b83;
  color: #fff;
}
.answer__vote .vote-btn.active { box-shadow: inset 0 0 0 2px rgba(255, 255, 255, .5); }
.answer__vote .vote-btn:disabled { opacity: .55; cursor: default; }

@media (max-width: 560px) {
  /* The head stays a row even here: the icon is small enough to sit beside
     the headline, and stacking it was most of the wasted height. */
  .answer__vote { flex-direction: column; }
}

/* Every outbound link in one row: IMDb, TMDB, the trailer, the official site. */
.linkrow { display: flex; flex-wrap: wrap; gap: 9px; margin-bottom: 12px; }

/* Under the poster the links stack into a single column, so they read as a
   block belonging to the film rather than a toolbar floating above the text. */
.linkrow--stack {
  flex-direction: column;
  gap: 7px;
  margin: 12px 0 0;
}
.linkrow--stack .linkrow__item {
  flex-direction: row;
  align-items: baseline;
  gap: 9px;
  min-width: 0;
  padding: 9px 13px;
}
.linkrow--stack .linkrow__src { flex: 0 0 auto; }
.linkrow--stack .linkrow__num { font-size: 1.02rem; margin-left: auto; padding-right: 16px; }
.linkrow--stack .linkrow__num--plain { font-size: 1.02rem; }
.linkrow--stack .linkrow__ext { top: 50%; transform: translateY(-50%); }
.linkrow__item {
  display: flex; flex-direction: column; gap: 2px;
  min-width: 104px;
  padding: 9px 14px 10px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 12px;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  position: relative;
  transition: border-color .15s ease, background .15s ease, transform .15s ease;
}
.linkrow__item:hover { background: var(--bg-raised-2); border-color: #4b4f59; transform: translateY(-1px); }
/* The source name is the label people read first, so it is the same size as
   the value beside it rather than a caption under it. */
.linkrow__src {
  font-size: .95rem; font-weight: 800; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-faint); line-height: 1.15;
}
.linkrow__num {
  display: flex; align-items: baseline; gap: 4px;
  font-size: 1.02rem; font-weight: 800; line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.linkrow__num--plain { font-weight: 700; align-items: center; }
.linkrow__ext {
  position: absolute; top: 9px; right: 10px;
  font-size: .72rem; color: var(--text-faint);
}
.linkrow__item--imdb .linkrow__src { color: var(--accent); }
.linkrow__item--imdb:hover { border-color: var(--accent); }
/* TMDB's own wordmark runs green into blue, so ours does too. The solid
   colour is the fallback for anything without background-clip: text. */
.linkrow__item--tmdb .linkrow__src {
  color: #84cfa6;
  background: linear-gradient(90deg, #84cfa6 0%, #41bfcb 100%);
  -webkit-background-clip: text;
          background-clip: text;
  -webkit-text-fill-color: transparent;
}
.linkrow__item--tmdb:hover { border-color: #5cc8a0; }
.linkrow__item--yt .linkrow__src { color: #ff6b6b; }
.linkrow__item--yt:hover { border-color: #ff6b6b; }

/* Facts row */
.factbar {
  display: flex; flex-wrap: wrap; gap: 8px;
  list-style: none; margin: 0 0 18px; padding: 0;
  max-height: 68px;
  overflow: hidden;
}
.factbar__item {
  display: inline-flex; align-items: baseline; gap: 5px;
  padding: 5px 12px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: .84rem;
}
.factbar__item--score { font-weight: 700; }
.factbar__star { color: var(--accent); font-size: .95em; }
.factbar__of  { color: var(--text-faint); font-size: .74rem; }
.factbar__src { color: var(--text-faint); font-size: .72rem; font-weight: 600; }
.factbar__item--genre { color: var(--text-dim); }
.factbar__item--tag { color: var(--text-dim); border-style: dashed; }
.factbar__item--tag a:hover { color: var(--text); text-decoration: underline; }

/* Outbound links */
.linkbar { display: flex; flex-wrap: wrap; gap: 9px; margin-bottom: 22px; }
.linkbar__btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 10px 18px;
  background: var(--bg-raised-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: .9rem; font-weight: 600;
  color: var(--text);
}
.linkbar__btn:hover { background: #30333b; border-color: #4b4f59; }
.linkbar__ext { font-size: .78em; opacity: .55; margin-left: 1px; }
.linkbar__btn--play { background: var(--text); color: #111; border-color: transparent; }
.linkbar__btn--play:hover { background: #fff; }
.linkbar__btn--imdb { background: var(--accent); color: #111; border-color: transparent; font-weight: 800; }
.linkbar__btn--imdb:hover { background: #ffd633; }

/* Trailer */
.trailer { margin-bottom: 24px; }
.trailer__facade,
.trailer__player {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: #000;
}
.trailer__facade { position: relative; padding: 0; }
.trailer__facade img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  opacity: .78;
  transition: opacity .2s ease, transform .3s ease;
}
.trailer__facade:hover img { opacity: 1; transform: scale(1.02); }
.trailer__play {
  position: absolute; inset: 0; margin: auto;
  width: 72px; height: 72px;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.6rem; color: #fff;
  background: rgba(0, 0, 0, .62);
  border: 2px solid rgba(255, 255, 255, .85);
  border-radius: 50%;
  padding-left: 4px;
}
.trailer__facade:hover .trailer__play { background: var(--no); border-color: var(--no); }
.trailer__label {
  position: absolute; left: 14px; bottom: 12px;
  padding: 4px 11px;
  background: rgba(0, 0, 0, .7);
  border-radius: 999px;
  font-size: .8rem; color: #fff;
}
.trailer__player { border: 0; }

/* Voting */
.voting {
  padding: 22px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin-bottom: 24px;
}
.voting__h2 { font-size: 1.15rem; margin-bottom: 2px; }
.voting__hint { margin: 0 0 16px; color: var(--text-faint); font-size: .85rem; }

.vote-icons--page { display: flex; gap: 12px; margin-bottom: 18px; }
.vote-icons--page .vote-btn {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 16px 12px;
  background: var(--bg-raised-2);
  border: 2px solid var(--line);
  border-radius: var(--radius);
  color: var(--text);
  font-size: .92rem; font-weight: 600;
  text-align: center;
  transition: transform .12s ease, border-color .12s ease, background .12s ease;
}
.vote-icons--page .vote-btn__icon { font-size: 1.7rem; }
.vote-icons--page .vote-btn:hover:not(:disabled) { transform: translateY(-2px); }
.vote-icons--page .up-vote-btn:hover:not(:disabled)   { border-color: var(--yes); background: var(--yes-soft); }
.vote-icons--page .down-vote-btn:hover:not(:disabled) { border-color: var(--no);  background: var(--no-soft); }
.vote-icons--page .up-vote-btn.active   { border-color: var(--yes); background: var(--yes-soft); }
.vote-icons--page .down-vote-btn.active { border-color: var(--no);  background: var(--no-soft); }
.vote-icons--page .vote-btn:disabled { opacity: .55; cursor: default; }

.progress {
  display: flex;
  height: 32px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--bg-raised-2);
  font-size: .82rem; font-weight: 700;
}
.progress > div {
  display: flex; align-items: center; justify-content: center;
  white-space: nowrap;
  transition: width .35s ease;
}
.progress__yes  { background: var(--yes); color: #fff; }
.progress__no   { background: var(--no);  color: #fff; }
.progress__none { flex: 1; color: var(--text-faint); font-weight: 500; }

.vote-stats__count { margin: 9px 0 0; color: var(--text-faint); font-size: .83rem; }

/* Synopsis + where to watch */
.synopsis { margin-bottom: 24px; }
.synopsis p { color: var(--text-dim); margin: 0; }

/* Where to watch lives in the left column under the IMDb and TMDB buttons,
   so the list runs down the page rather than across it. */
.watch { margin: 18px 0 0; }
.watch h2 { font-size: .95rem; margin-bottom: 9px; }
.watch__list {
  display: flex; flex-direction: column; gap: 6px;
  list-style: none; margin: 0 0 9px; padding: 0;
}
.watch__item { display: block; }
.watch__link {
  display: flex; align-items: center; gap: 9px;
  padding: 6px 11px 6px 6px;
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: .85rem;
  color: var(--text);
  transition: border-color .15s ease, background .15s ease;
}
a.watch__link:hover { background: var(--bg-raised-2); border-color: #4b4f59; }
.watch__link img { width: 28px; height: 28px; border-radius: 6px; flex: 0 0 auto; }
.watch__name { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.watch__kind {
  color: var(--text-faint); font-size: .68rem; text-transform: uppercase;
  letter-spacing: .05em; margin-left: auto; flex: 0 0 auto;
}
.watch__more { margin: 0 0 6px; font-size: .82rem; }
.watch__more a { color: #7fb3ff; text-decoration: underline; }
.watch__legal { margin: 0; color: var(--text-faint); font-size: .72rem; line-height: 1.35; }

/* ------------------------------------------------------------------------- */
/* Cast and crew, under the trailer                                          */
/* ------------------------------------------------------------------------- */
.credits { margin-bottom: 24px; }
.credits h2 { font-size: 1.15rem; margin-bottom: 12px; }
.credits__group-title { margin: 12px 0 8px; color: var(--text-dim); font-size: .82rem; text-transform: uppercase; letter-spacing: .08em; }
.credits__list {
  display: flex; flex-wrap: wrap; gap: 14px;
  list-style: none; margin: 0 0 16px; padding: 0;
}
.credits__list:last-child { margin-bottom: 0; }
.credits__person {
  width: 82px;
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
  font-size: .76rem;
}
.credits__person-link {
  display: flex; flex-direction: column; align-items: center;
  color: inherit;
}
.credits__person-link:hover .credits__name,
.credits__person-link:focus-visible .credits__name { text-decoration: underline; }
.credits__face {
  width: 72px; height: 72px;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 20%;   /* headshots are framed high, not centred */
  background: var(--bg-raised-2);
  border: 1px solid var(--line);
  margin-bottom: 6px;
}
.credits__face--blank {
  display: flex; align-items: center; justify-content: center;
  font-size: 1.1rem; font-weight: 700; color: var(--text-faint);
}
.credits__name { font-weight: 600; line-height: 1.25; }
.credits__role { color: var(--text-faint); line-height: 1.25; }
/* The crew row is the answer to "who made this", so it reads slightly louder
   than the cast strip below it. */
.credits__list--crew .credits__role { color: var(--text-dim); font-weight: 600; }

/* Related */
.related { margin-top: 42px; padding-top: 30px; border-top: 1px solid var(--line); }
.related .section-title { margin-bottom: 18px; }
.related .marquee { width: 100%; max-width: 100%; }
.movie-page__wide-row {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}
.movie-page__wide-row > .section-title { padding: 0 clamp(16px, 4vw, 32px); }
.related__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 26px 16px;
}
.related__grid .movie-tile { width: 100%; flex: none; margin-right: 0; }

.movie-extras, .media-gallery, .reviews { margin-top: 42px; padding-top: 30px; border-top: 1px solid var(--line); }
.movie-extras--sidebar { margin-top: 24px; padding-top: 20px; }
.movie-extras--sidebar p { display: flex; justify-content: space-between; gap: 10px; margin: 0 0 7px; font-size: .84rem; }
.movie-extras--sidebar p span { color: var(--text-dim); }
.movie-extras__bar { display: none; }
@media (max-width: 820px) {
  .movie-extras--sidebar p {
    display: grid;
    grid-template-columns: 62px minmax(0, 1fr) auto;
    align-items: center;
  }
  .movie-extras__bar {
    display: block;
    height: 14px;
    overflow: hidden;
    background: var(--bg-raised-2);
    border-radius: 999px;
  }
  .movie-extras__bar > span {
    display: block;
    height: 100%;
    background: linear-gradient(90deg, #4894e8, #67c7a5);
    border-radius: inherit;
  }
}
.movie-extras .section-title, .media-gallery .section-title, .reviews .section-title { margin-bottom: 16px; }
.movie-extras .section-title:not(:first-child) { margin-top: 28px; }
.money-chart { display: grid; gap: 10px; max-width: 760px; }
.money-chart__row { display: grid; grid-template-columns: 70px minmax(120px, 1fr) auto; align-items: center; gap: 12px; font-size: .86rem; }
.money-chart__track { height: 14px; overflow: hidden; background: var(--bg-raised-2); border-radius: 999px; }
.money-chart__track > span { display: block; height: 100%; background: linear-gradient(90deg, #4894e8, #67c7a5); border-radius: inherit; }
.keyword-list { display: flex; flex-wrap: wrap; gap: 8px; }
.keyword-list a { padding: 6px 10px; background: var(--bg-raised-2); border: 1px solid var(--line); border-radius: 999px; color: var(--text-dim); font-size: .8rem; }
.keyword-list a:hover { color: var(--text); border-color: #555963; }
.media-gallery__marquee .marquee__track { gap: 12px; }
.media-gallery__item { flex: 0 0 min(390px, 78vw); padding: 0; border: 0; background: none; cursor: pointer; }
.media-gallery__item img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--radius-sm); display: block; }
.media-gallery__item--poster { flex-basis: min(190px, 44vw); }
.media-gallery__item--poster img { aspect-ratio: 2 / 3; }
.reviews__list { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; }
.review { padding: 16px; background: var(--bg-raised); border: 1px solid var(--line); border-radius: var(--radius); }
.review h3 { font-size: .9rem; margin-bottom: 8px; }
.review p { color: var(--text-dim); font-size: .84rem; line-height: 1.55; }
.review a { color: #7fb3ff; font-size: .8rem; text-decoration: underline; }

/* ========================================================================= */
/* Footer                                                                    */
/* ========================================================================= */
.site-footer {
  border-top: 1px solid var(--line);
  padding: 16px clamp(16px, 4vw, 32px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px 26px;
}
.site-footer__stats { color: var(--text-dim); }
.site-footer__stats:hover { color: var(--text); text-decoration: underline; }

.voted-page {
  min-height: calc(100dvh - 69px);
  display: flex;
  align-items: center;
  overflow: hidden;
}
.voted-library {
  width: 100vw;
  padding: 28px clamp(16px, 4vw, 32px);
  will-change: scroll-position;
}
.voted-library .marquee__track { align-items: center; }
.voted-library .movie-tile {
  --voted-tile-w: clamp(240px, calc((100dvh - 210px) * 2 / 3), 520px);
  flex: 0 0 var(--voted-tile-w);
  width: var(--voted-tile-w);
  contain: layout style;
}
.voted-library .movie-tile__verdict {
  min-height: clamp(48px, 6.5dvh, 70px);
  padding: clamp(12px, 1.6dvh, 18px) clamp(15px, 1.8vw, 24px);
}
.voted-library .movie-tile__verdict-word {
  font-size: clamp(1rem, 1.8dvh, 1.35rem);
}
.voted-library .movie-tile__verdict-meta {
  gap: 6px;
  font-size: clamp(.9rem, 1.55dvh, 1.18rem);
}
.rows-paused .voted-library { scrollbar-width: none; }
.rows-paused .voted-library::-webkit-scrollbar {
  display: none;
}
.site-footer__stats {
  margin: 0;
  color: var(--text-dim);
  font-size: .84rem;
  white-space: nowrap;
}
.site-footer__stats strong { color: var(--text); font-variant-numeric: tabular-nums; }
.site-footer__speed {
  display: inline-flex; align-items: center; gap: 9px;
  margin: 0;
  font-size: .76rem; color: var(--text-faint);
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
.site-footer__speed label { white-space: nowrap; }
.site-footer__speed output {
  min-width: 3.4em; text-align: left;
  font-variant-numeric: tabular-nums; color: var(--text-dim);
}
.site-footer__speed input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: clamp(110px, 24vw, 190px);
  height: 4px; border-radius: 99px;
  background: var(--line);
  cursor: pointer;
}
.site-footer__speed input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--text-dim); border: 0; cursor: pointer;
  transition: background .15s ease;
}
.site-footer__speed input[type="range"]::-moz-range-thumb {
  width: 15px; height: 15px; border-radius: 50%;
  background: var(--text-dim); border: 0; cursor: pointer;
}
.site-footer__speed input[type="range"]:hover::-webkit-slider-thumb { background: var(--text); }
.site-footer__speed input[type="range"]:hover::-moz-range-thumb { background: var(--text); }
.site-footer__speed input[type="range"]:focus-visible { outline: 2px solid #6da8ff; outline-offset: 3px; }
@media (hover: none), (pointer: coarse) {
  .site-footer__speed input[type="range"] {
    height: 32px;
    margin: 0;
    touch-action: pan-y;
    background: linear-gradient(var(--line), var(--line)) center / 100% 4px no-repeat;
  }
}

/* When the rows are stopped, say so by letting the scrollbar show: the row is
   still scrollable by hand, and hiding that would look broken rather than off. */
.rows-paused .marquee { scrollbar-width: thin; }
.rows-paused .marquee::-webkit-scrollbar { display: block; height: 8px; }
.rows-paused .marquee::-webkit-scrollbar-thumb { background: #33353c; border-radius: 99px; }

.site-footer__legal { margin: 0; color: var(--text-faint); font-size: .76rem; white-space: nowrap; }
.site-footer__legal a { color: var(--text-faint); text-decoration: underline; }
.site-footer__legal a:hover { color: var(--text-dim); }
.site-footer__privacy { padding: 0; border: 0; background: none; color: var(--text-faint); font: inherit; font-size: .76rem; text-decoration: underline; cursor: pointer; }
.site-footer__privacy:hover { color: var(--text-dim); }
.footer-compact { display: none; }

@media (max-width: 600px) {
  .site-footer {
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 6px;
    padding: 9px 8px;
  }
  .site-footer__stats,
  .site-footer__speed,
  .site-footer__legal {
    font-size: .66rem;
  }
  .site-footer__speed { gap: 4px; }
  .site-footer__speed input[type="range"] { width: clamp(54px, 17vw, 76px); }
  .site-footer__speed output { min-width: 2.8em; }
  .site-footer__privacy { font-size: .66rem; }
  .footer-wide { display: none; }
  .footer-compact { display: inline; }
}

.privacy-notice {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 80;
  max-width: min(320px, calc(100vw - 32px));
  padding: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--bg-raised);
  box-shadow: 0 8px 28px rgba(0, 0, 0, .35);
  font-size: .78rem;
}
.privacy-notice p { margin: 0 0 10px; color: var(--text-dim); }
.privacy-notice button { border: 0; background: none; color: var(--text-dim); font: inherit; text-decoration: underline; cursor: pointer; }
.privacy-notice [data-privacy-confirm] { float: right; padding: 4px 9px; border-radius: 5px; background: var(--text); color: var(--bg); text-decoration: none; }
.privacy-dialog { width: min(440px, calc(100vw - 32px)); padding: 22px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--bg-raised); color: var(--text); }
.privacy-dialog::backdrop { background: rgba(0, 0, 0, .7); }
.privacy-dialog h2 { margin: 0 0 14px; font-size: 1.2rem; }
.privacy-dialog p { margin: 0 0 12px; color: var(--text-dim); font-size: .88rem; line-height: 1.5; }
.privacy-dialog [data-privacy-close] { float: right; padding: 7px 12px; border: 0; border-radius: 5px; background: var(--text); color: var(--bg); cursor: pointer; }


/* ========================================================================= */
/* Tooltip                                                                   */
/*                                                                           */
/* One element, reused, moved with `transform` so it never triggers layout.  */
/* Without JavaScript, title attributes retain native browser behavior. JS   */
/* moves their text into accessible labels and custom tooltip data at start. */
/* ========================================================================= */
.tip {
  position: fixed;
  top: 0; left: 0;
  z-index: 400;
  max-width: min(330px, 82vw);
  padding: 9px 13px;
  background: rgba(28, 29, 34, .97);
  color: var(--text);
  border: 1px solid #3a3d46;
  border-radius: 9px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .55), 0 2px 6px rgba(0, 0, 0, .4);
  backdrop-filter: blur(8px);
  font-size: .82rem;
  line-height: 1.45;
  text-align: left;
  pointer-events: none;          /* must never sit between cursor and link */
  opacity: 0;
  transition: opacity .13s ease;
  will-change: transform;
}
.tip.is-visible { opacity: 1; }

/* The little arrow. Drawn with a rotated square so it inherits the border. */
.tip::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -5px;
  width: 9px; height: 9px;
  margin-left: -4.5px;
  background: rgba(28, 29, 34, .97);
  border-right: 1px solid #3a3d46;
  border-bottom: 1px solid #3a3d46;
  transform: rotate(45deg);
}
.tip--below::after {
  bottom: auto;
  top: -5px;
  border-right: 0; border-bottom: 0;
  border-left: 1px solid #3a3d46;
  border-top: 1px solid #3a3d46;
}

@media (prefers-reduced-motion: reduce) {
  .tip { transition: none; }
}

/* A coarse pointer has no hover, so the tooltip never applies. */
@media (hover: none) {
  .tip { display: none; }
}

/* ========================================================================= */
/* Lightbox                                                                  */
/* ========================================================================= */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(16px, 5vw, 56px);
  background: rgba(6, 6, 8, .9);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity .18s ease;
  cursor: pointer;
}
.lightbox.is-open { opacity: 1; }

/* Load-bearing. `display: flex` above beats the browser's own rule for the
   `hidden` attribute, so a closed lightbox stayed full screen at zero opacity
   and swallowed every click on the page underneath it. The poster opened
   once, and after that nothing on the page could be clicked again. */
.lightbox[hidden] { display: none; }

.lightbox__figure {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  max-height: 100%;
}
.lightbox__img {
  max-width: 100%;
  max-height: calc(100vh - 130px);
  width: auto; height: auto;
  border-radius: 10px;
  box-shadow: 0 24px 70px rgba(0, 0, 0, .7);
  cursor: grab;
  touch-action: none;
  user-select: none;
  transform: scale(.97);
  transition: transform .2s ease;
}
.lightbox.is-swiping .lightbox__img {
  cursor: grabbing;
  transition: none;
}
.lightbox.is-open .lightbox__img { transform: scale(1); }
.lightbox__cap { color: var(--text-dim); font-size: .88rem; text-align: center; }

.lightbox__close {
  position: absolute;
  top: 14px; right: 16px;
  width: 42px; height: 42px;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.1rem;
  color: var(--text);
  background: rgba(255, 255, 255, .1);
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 50%;
  cursor: pointer;
}
.lightbox__close:hover { background: rgba(255, 255, 255, .2); }
.lightbox__nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 50px; height: 64px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(255, 255, 255, .18); border-radius: 12px;
  background: rgba(0, 0, 0, .48); color: #fff;
  font-size: 2.4rem; line-height: 1; cursor: pointer;
}
.lightbox__nav--prev { left: 16px; }
.lightbox__nav--next { right: 16px; }
.lightbox__nav:hover { background: rgba(255, 255, 255, .18); }
.lightbox__nav[hidden] { display: none; }

/* Stop the page behind scrolling while the lightbox is up. */
.lightbox-open, .lightbox-open body { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .lightbox, .lightbox__img { transition: none; }
}

/* ========================================================================= */
/* Toast                                                                     */
/* ========================================================================= */
#toast {
  position: fixed;
  left: 50%; bottom: 28px;
  transform: translate(-50%, 16px);
  padding: 13px 24px;
  background: var(--bg-raised-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--shadow);
  font-size: .92rem; font-weight: 600;
  opacity: 0; pointer-events: none;
  transition: opacity .25s ease, transform .25s ease;
  z-index: 300;
  max-width: min(92vw, 480px);
  text-align: center;
}
#toast.show { opacity: 1; transform: translate(-50%, 0); }
#toast.is-error { border-color: var(--no); color: #ff9ba1; }

/* ========================================================================= */
/* Vote feedback                                                             */
/*                                                                           */
/* A vote used to be acknowledged by a small pill at the bottom of the       */
/* window - easy to miss, and nowhere near the thing it was talking about.   */
/* Now the answer lands in the middle of the screen at a size that cannot be */
/* argued with, then flies into the control that was pressed, which is also  */
/* the bar that is sliding to its new balance. Announcement and consequence, */
/* joined by one movement.                                                   */
/*                                                                           */
/* The toast is still there for errors, where a quiet line at the bottom is  */
/* the right weight.                                                         */
/* ========================================================================= */

/* A custom property is an opaque token to the engine unless it is registered
   with a type, and opaque tokens do not interpolate - they snap. Registering
   these two as percentages is the whole reason the gradient and the stacked
   bar can slide. Both are set on a parent and read by a child, so they
   inherit. The initial values match the fallbacks written at each use. */
@property --split     { syntax: "<percentage>"; inherits: true; initial-value: 50%; }
@property --yes-share { syntax: "<percentage>"; inherits: true; initial-value: 50%; }

.vote-burst {
  position: fixed;
  left: 50%; top: 44%;
  z-index: 400;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 30px 46px 26px;
  border-radius: 26px;
  pointer-events: none;
  text-align: center;
  white-space: nowrap;
  transform: translate(-50%, -50%) scale(.4);
  opacity: 0;
  will-change: transform, opacity;
  border: 2px solid var(--burst-edge);
  background:
    radial-gradient(circle at 50% 38%, var(--burst-glow) 0%, transparent 68%),
    var(--bg-raised-2);
  box-shadow:
    0 24px 70px rgba(0, 0, 0, .6),
    0 0 0 1px rgba(255, 255, 255, .05) inset,
    0 0 60px var(--burst-glow);
}
.vote-burst--yes { --burst-edge: #3fbf67; --burst-glow: rgba(31, 143, 60, .45); color: #b6f2c8; }
.vote-burst--no  { --burst-edge: #e05a63; --burst-glow: rgba(176, 48, 56, .45); color: #ffc2c6; }

.vote-burst__icon { display: block; line-height: 0; }
.vote-burst__icon .icon {
  width: 64px; height: 64px;
  filter: drop-shadow(0 4px 14px rgba(0, 0, 0, .5));
  animation: burst-icon .75s cubic-bezier(.3, 1.6, .5, 1) .05s both;
}
.vote-burst__word {
  font-size: clamp(2.6rem, 9vw, 4.1rem);
  font-weight: 900;
  line-height: 1;
  letter-spacing: .02em;
  color: #fff;
  text-shadow: 0 3px 18px var(--burst-glow), 0 1px 2px rgba(0, 0, 0, .7);
}
.vote-burst__sub {
  font-size: .95rem;
  font-weight: 700;
  letter-spacing: .01em;
  opacity: .92;
}

/* Two rings, one chasing the other, so the burst reads as an impact rather
   than a box that merely appeared. */
.vote-burst__ring {
  position: absolute;
  left: 50%; top: 50%;
  width: 100%; height: 100%;
  margin: 0;
  border: 2px solid var(--burst-edge);
  border-radius: 26px;
  transform: translate(-50%, -50%);
  animation: burst-ring 1.1s ease-out both;
}
.vote-burst__ring--late { animation-delay: .22s; }

@keyframes burst-ring {
  from { opacity: .8; transform: translate(-50%, -50%) scale(1); }
  to   { opacity: 0;  transform: translate(-50%, -50%) scale(1.85); }
}
@keyframes burst-icon {
  0%   { transform: scale(.2) rotate(-24deg); }
  60%  { transform: scale(1.25) rotate(6deg); }
  100% { transform: scale(1) rotate(0); }
}

/* The bar the burst is flying towards. A short bloom, timed so it is still
   running while the split slides underneath it. */
.is-vote-flash { animation: vote-flash .9s ease-out; }
@keyframes vote-flash {
  0%   { filter: brightness(1); }
  22%  { filter: brightness(1.55) saturate(1.3); }
  100% { filter: brightness(1); }
}

/* The moment the burst lands. */
.is-vote-landed { animation: vote-landed .5s cubic-bezier(.3, 1.7, .5, 1); }
@keyframes vote-landed {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.14); }
  100% { transform: scale(1); }
}

/* Reserved for the case that actually matters: the verdict itself turned
   over. A vote that only moves the percentage inside the same verdict does
   not get this. */
.is-verdict-turn { animation: verdict-turn .7s cubic-bezier(.3, 1.5, .45, 1); }
@keyframes verdict-turn {
  0%   { transform: scale(.88) rotate(-4deg); }
  45%  { transform: scale(1.1) rotate(3deg); }
  100% { transform: scale(1) rotate(0); }
}

@media (max-width: 560px) {
  .vote-burst { padding: 24px 30px 20px; }
  .vote-burst__icon .icon { width: 50px; height: 50px; }
}

/* Motion sickness is a real thing and the confirmation still has to work
   without any of the above: it appears, it is readable, it goes away. */
@media (prefers-reduced-motion: reduce) {
  .vote-burst { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  .vote-burst__ring { display: none; }
}

/* ========================================================================= */
/* Responsive tile sizing                                                    */
/* ========================================================================= */
@media (max-width: 1100px) { :root { --tile-w: 168px; } }
@media (max-width: 760px)  { :root { --tile-w: 148px; --tile-gap: 12px; } }
@media (max-width: 480px)  { :root { --tile-w: 132px; --tile-gap: 10px; } }

@media (max-width: 560px) {
  .vote-icons--page { flex-direction: column; }
}

/* ========================================================================= */
/* Reduced motion                                                            */
/*                                                                           */
/* Some people get genuinely motion-sick from sideways drift. When the OS     */
/* says so, the JS stops auto-scrolling and this turns the marquee into a     */
/* normal, snappy, swipeable row that stays exactly where it is put.          */
/* ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

@media (prefers-reduced-motion: reduce) and (hover: hover) and (pointer: fine) {
  .marquee {
    scroll-snap-type: x mandatory;
    scrollbar-width: thin;
  }
  .marquee::-webkit-scrollbar { display: block; height: 8px; }
  .voted-library { scrollbar-width: none; }
  .voted-library::-webkit-scrollbar { display: none; }
  .marquee--live .movie-tile[aria-hidden="true"] { display: none; }
  .movie-tile { scroll-snap-align: start; }
  .movie-tile__link:hover { transform: none; }
}
