/* ═════════════════════════════════════════════════════════════════════════
   NITRATE — DISCOVER PRINTS.  #/discover, what is NOT on the shelves.
   Owns .dsc-*.  Reads tokens.css and redefines nothing in it.

   The page is the inverse of the rest of NITRATE: every other surface draws
   what the estate HAS, so its cards are certainties — runtime, drives, files.
   These are absences, and the only honest thing to show about an absence is
   what it would be: art, a year, a rating, a sentence.  So the card is mostly
   poster, and the detail arrives on hover rather than being promised up front.

   🔴 2026-08-14: every hairline in this file was written `border: 1px solid
   var(--hair)`, and `--hair` is a WIDTH (1px), not a colour — so all nine
   declarations were invalid and the browser dropped them whole.  The search
   box, the poster frames, the Load-more, the modal, the toast and the unpicked
   ALL/FILMS/SERIES pills had no border at all; the pills were bare words.  The
   idiom every other stylesheet in the estate uses is `var(--hair) solid
   var(--rule)`, and that is what they say now.
   ═════════════════════════════════════════════════════════════════════════ */

.dsc { padding: 0 var(--pad) 96px; }

.dsc-head { padding: 26px 0 10px; }
.dsc-h1 {
  margin: 0;
  font-family: var(--font-marquee); font-weight: 800;
  font-size: clamp(28px, 4.2vw, 46px); letter-spacing: -.01em;
  text-transform: uppercase; color: var(--ink);
}
.dsc-lede {
  margin: 6px 0 0; max-width: 62ch;
  font-family: var(--font-ui); font-size: 13.5px; line-height: 1.45;
  color: var(--muted);
}

/* ---- search: pinned, because it is the fastest way to ask for one thing --- */
.dsc-searchbar { position: sticky; top: 0; z-index: 6; padding: 12px 0; background: var(--ground); }
.dsc-search {
  width: 100%; box-sizing: border-box; padding: 12px 14px;
  font-family: var(--font-ui); font-size: 15px;
  color: var(--ink); background: var(--panel);
  border: var(--hair) solid var(--rule); border-radius: 10px;
}
.dsc-search:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.dsc-sec { margin: 22px 0 0; }
.dsc-sec-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px; margin: 0 0 10px; }
.dsc-sec-title {
  margin: 0; font-family: var(--font-mono); font-size: 12px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted);
}
.dsc-empty { font-family: var(--font-ui); font-size: 13px; color: var(--muted); }

/* ---- the rail.  A grid, not a carousel: these are things to browse, and a
   carousel hides most of them behind an interaction. ------------------------ */
.dsc-strip {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

.dsc-card { margin: 0; }
.dsc-shot {
  position: relative; aspect-ratio: 2 / 3; overflow: hidden;
  border-radius: 10px; background: var(--panel-2);
  border: var(--hair) solid var(--rule);
}
.dsc-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.dsc-noart {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 22px; color: var(--muted);
}

/* hover panel — brief info + the button, as Jellyseerr does it.
   ⭐ :focus-within as well as :hover, so the keyboard reaches the button. */
.dsc-over {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 6px;
  padding: 10px;
  background: linear-gradient(180deg, rgba(0,0,0,.05) 0%, rgba(0,0,0,.82) 62%);
  opacity: 0; transition: opacity .16s ease;
}
.dsc-shot:hover .dsc-over,
.dsc-shot:focus-within .dsc-over { opacity: 1; }
.dsc-meta { display: flex; gap: 8px; font-family: var(--font-mono); font-size: 11px; color: #fff; }
.dsc-rate { color: #ffd166; }
.dsc-blurb {
  margin: 0; font-family: var(--font-ui); font-size: 11.5px; line-height: 1.35;
  color: rgba(255,255,255,.86);
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.dsc-ask {
  margin-top: 4px; padding: 7px 10px; width: 100%;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em;
  color: #08131f; background: var(--accent);
  border: 0; border-radius: 7px; cursor: pointer;
}
.dsc-ask:disabled { opacity: .55; cursor: default; }

.dsc-cap { display: flex; flex-direction: column; gap: 1px; padding: 7px 2px 0; }
.dsc-title {
  font-family: var(--font-ui); font-size: 13px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dsc-sub { font-family: var(--font-mono); font-size: 10.5px; color: var(--muted); }

.dsc-card.is-asked .dsc-shot { outline: 2px solid var(--accent); outline-offset: 1px; }
.dsc-card.is-failed .dsc-shot { outline: 2px solid var(--crit); outline-offset: 1px; }

.dsc-more {
  margin: 14px auto 0; display: block; padding: 9px 18px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em;
  color: var(--ink); background: var(--panel); cursor: pointer;
  border: var(--hair) solid var(--rule); border-radius: 8px;
}
.dsc-more:disabled { opacity: .5; cursor: default; }

/* ⭐ THE END OF A RAIL IS A LINE, NOT A WHEEL. Pages arrive on scroll now
   (John: "don't make user click load more"), so this element is usually silent
   and empty — it speaks only to say the feed is loading, that it has ended and
   how much it showed, or that it broke and can be retried. `is-quiet` strips
   the control chrome, because a status that looks like a button reads as a
   button nobody pressed.
   ⛔ It is never given `display:none`: an element with no box cannot intersect,
   and hiding the sentinel would silently kill the paging it exists for.
   ⛔ Nothing here animates. A spinner would be the only moving thing on a page
   whose whole argument is that it stands still. */
.dsc-more.is-quiet,
.dsc-more.is-quiet:disabled {
  opacity: 1; cursor: default;
  color: var(--muted); background: none; border-color: transparent;
  letter-spacing: .12em;
}

/* ------------------------------------------------------------------ modal */
.dsc-modal-wrap {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-items: center; padding: 20px;
  background: rgba(0,0,0,.62);
}
.dsc-modal {
  position: relative; width: min(560px, 100%); max-height: 86vh; overflow: auto;
  padding: 20px; border-radius: 14px;
  background: var(--panel); border: var(--hair) solid var(--rule);
  box-shadow: 0 24px 70px rgba(0,0,0,.5);
}
.dsc-modal::before {
  content: ''; position: absolute; inset: 0 0 auto; height: 132px;
  background-image: var(--shot); background-size: cover; background-position: 50% 30%;
  opacity: .16; border-radius: 14px 14px 0 0; pointer-events: none;
}
.dsc-modal-head { position: relative; }
.dsc-modal-title {
  margin: 0; font-family: var(--font-marquee); font-weight: 800;
  font-size: 24px; color: var(--ink);
}
.dsc-modal-sub { margin: 4px 0 0; font-family: var(--font-mono); font-size: 11.5px; color: var(--muted); }
.dsc-modal-blurb {
  position: relative; margin: 12px 0 0;
  font-family: var(--font-ui); font-size: 13.5px; line-height: 1.5; color: var(--ink-2);
}

.dsc-seasons { margin: 16px 0 0; }
.dsc-seasons-note { margin: 0; font-family: var(--font-ui); font-size: 12.5px; color: var(--muted); }
.dsc-seasons-bar { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; }
.dsc-seasons-lab { font-family: var(--font-mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.dsc-linkish {
  padding: 0; border: 0; background: none; cursor: pointer;
  font-family: var(--font-mono); font-size: 11px; color: var(--accent);
  text-decoration: underline;
}
.dsc-seasons-grid { display: grid; gap: 6px; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); }
.dsc-season {
  display: flex; align-items: center; gap: 6px; padding: 7px 8px;
  border: var(--hair) solid var(--rule); border-radius: 8px; cursor: pointer;
  font-family: var(--font-mono); font-size: 11px; color: var(--ink);
}
.dsc-season-e { color: var(--muted); }

.dsc-modal-foot { display: flex; justify-content: flex-end; gap: 10px; margin: 18px 0 0; }
.dsc-btn {
  padding: 9px 16px; border-radius: 8px; cursor: pointer;
  font-family: var(--font-mono); font-size: 11.5px; letter-spacing: .1em;
}
.dsc-btn-ghost { color: var(--ink); background: transparent; border: var(--hair) solid var(--rule); }
.dsc-btn-go { color: #08131f; background: var(--accent); border: 0; }
.dsc-btn-go:disabled { opacity: .6; cursor: default; }

/* ------------------------------------------------- the flight and the toast
   John's one change to Jellyseerr's flow: the poster travels to the corner and
   the answer arrives where it lands, instead of at the opposite end of the
   screen from the thing you clicked. */
.dsc-ghost {
  position: fixed; z-index: 70; margin: 0; pointer-events: none;
  border-radius: 10px; overflow: hidden;
  transition: transform .62s cubic-bezier(.2,.7,.3,1), opacity .62s ease;
  will-change: transform, opacity;
}
.dsc-ghost .dsc-over { display: none; }
.dsc-ghost img { width: 100%; height: 100%; object-fit: cover; }

#dsc-toasts {
  position: fixed; right: 16px; bottom: 16px; z-index: 80;
  display: flex; flex-direction: column; gap: 8px; align-items: flex-end;
}
.dsc-toast {
  display: flex; align-items: center; gap: 10px;
  min-width: 260px; max-width: min(420px, 92vw);
  padding: 12px 14px; border-radius: 10px;
  background: var(--panel); border: var(--hair) solid var(--rule);
  box-shadow: 0 14px 40px rgba(0,0,0,.42);
  font-family: var(--font-ui); font-size: 13.5px; color: var(--ink);
  animation: dsc-toast-in .24s ease both;
}
.dsc-toast.is-going { opacity: 0; transform: translateY(6px); transition: opacity .24s ease, transform .24s ease; }
.dsc-toast-ico {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center; font-size: 13px; font-weight: 700;
}
.dsc-toast.is-ok .dsc-toast-ico { color: #0b1f14; background: #4ade80; }
.dsc-toast.is-bad .dsc-toast-ico { color: #2a0b0b; background: var(--crit); }
.dsc-toast-text { flex: 1 1 auto; }
.dsc-toast-x {
  flex: 0 0 auto; border: 0; background: none; cursor: pointer;
  font-size: 18px; line-height: 1; color: var(--muted);
}
@keyframes dsc-toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .dsc-ghost { transition: none; }
  .dsc-toast { animation: none; }
}

@media (max-width: 560px) {
  .dsc-strip { grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: 10px; }
  .dsc-blurb { -webkit-line-clamp: 3; }
}

/* The allowance line. Deliberately plain: it is a rule, not a warning. */
.dsc-quota {
  margin: 8px 0 0; font-family: var(--font-mono); font-size: 11px;
  letter-spacing: .04em; color: var(--muted);
}

/* WAITING — requested and on its way. Dimmed and inert: the poster is still
   worth seeing, but nothing here is a control. */
/* ⚠️ dimmed, but NOT disabled: the poster still opens the read-only dossier.
   Only the request control is withheld. */
.dsc-card.is-waiting .dsc-shot { opacity: .72; }
.dsc-card.is-waiting .dsc-shot { outline: var(--hair) dashed var(--rule); outline-offset: 1px; }
.dsc-soon {
  margin-top: 4px; padding: 6px 10px; text-align: center;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .12em;
  color: var(--ground); background: var(--muted); border-radius: 7px;
}

/* ALL / FILMS / SERIES. A segmented control, not a dropdown: three options that
   fit on one line should never cost a click to see. */
.dsc-filter { display: flex; gap: 6px; margin: 12px 0 0; }
.dsc-pick {
  padding: 6px 14px; cursor: pointer; border-radius: 999px;
  font-family: var(--font-mono); font-size: 11px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
  background: transparent; border: var(--hair) solid var(--rule);
}
.dsc-pick:hover { color: var(--ink); }
.dsc-pick[aria-pressed="true"] {
  color: var(--ground); background: var(--accent); border-color: var(--accent);
}

/* ON THE SHELF — a search hit we already own. Green, because it is the one
   answer that needs no action at all. */
.dsc-card.is-owned .dsc-shot { outline: 2px solid #4ade80; outline-offset: 1px; }
.dsc-have {
  margin-top: 4px; padding: 6px 10px; text-align: center;
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .12em;
  color: #0b1f14; background: #4ade80; border-radius: 7px;
}

/* ═══════════════════════════════════════════ GENRES AND STUDIOS ═══════════
   Grids of shelf labels above the results zone, each opening its own rail.
   John, 2026-08-14, asked for them "under movies ... sorted by popularity",
   after Jellyseerr's /discover/movies/genres and /studio/<id>; then "dont
   forget series genres", so SERIES has a Genres grid too.

   ⭐ ONE TREATMENT, THREE GRIDS. The series genres are drawn by the same
   .dsc-tiles / .dsc-genre rules as the film ones and get nothing of their own —
   not a tint, not a badge, not a second layout. They are the same kind of
   object (a shelf label that opens a rail) and the tab above already says which
   library is being browsed, so a second visual language would be decoration
   claiming to be information.  Studios remain film-only: there is no
   /discover/tv/studio upstream to draw one from.

   ⭐ ORANGE IS THE PICK, AND NOTHING ELSE HERE. A tile carries the accent only
   while its rail is the one open, and the underline is the same 2px inset the
   Screener puts under the column it sorted by — same signal, same meaning, on
   purpose.  The tiles are otherwise the panel and a hairline: they are labels
   on a shelf, not buttons on a phone.
   ⛔ No count on a genre tile.  There is no honest number to put there, and a
   dishonest one would be the only thing on it anybody read. -------------- */
.dsc-sec-note {
  font-family: var(--font-ui); font-size: 12px; line-height: 1.4;
  color: var(--muted);
}
.dsc-tiles-all { margin-left: auto; }

.dsc-tiles {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
}
/* the studio list is long and ordered, so the head of it is the useful part */
.dsc-tiles:not(.is-all) .is-extra { display: none; }
/* ⭐ except the one currently open — collapsing the list must not hide the pick
   that the rail below is still showing */
.dsc-tiles:not(.is-all) .is-extra[aria-pressed="true"] { display: flex; }

.dsc-tile {
  position: relative; isolation: isolate; overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 5px;
  min-height: 74px; padding: 10px 11px;
  text-align: left; cursor: pointer;
  color: var(--ink); background: var(--panel);
  border: var(--hair) solid var(--rule); border-radius: 10px;
}
.dsc-tile:hover { border-color: var(--muted); }
.dsc-tile[aria-pressed="true"] {
  border-color: var(--accent);
  box-shadow: inset 0 -2px 0 var(--accent);
}
.dsc-tile[aria-pressed="true"] .dsc-tile-name { color: var(--accent); }

/* the marquee face doing what it was drawn for: signage */
.dsc-tile-name {
  font-family: var(--font-marquee); font-weight: 700;
  font-size: clamp(15px, 1.4vw, 19px); line-height: 1.04;
  letter-spacing: -.01em; text-transform: uppercase; color: var(--ink);
}

/* ⚠️ LIGHT IS THE BASE, per tokens.css — the plate is held far back here and
   carries further on the dark theme, exactly as the saga doors do. */
.dsc-tile-art {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
  opacity: .16; filter: saturate(.55);
  transition: opacity .16s ease;
}
.dsc-genre.has-art::after {          /* the scrim the name has to read against */
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--panel) 52%, transparent) 0%,
              color-mix(in srgb, var(--panel) 88%, transparent) 100%);
}
.dsc-genre:hover .dsc-tile-art { opacity: .26; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .dsc-tile-art { opacity: .30; filter: saturate(.75); }
  :root:not([data-theme="light"]) .dsc-genre:hover .dsc-tile-art { opacity: .42; }
  :root:not([data-theme="light"]) .dsc-genre.has-art .dsc-tile-name { text-shadow: 0 1px 3px rgba(0,0,0,.55); }
}
:root[data-theme="dark"] .dsc-tile-art { opacity: .30; filter: saturate(.75); }
:root[data-theme="dark"] .dsc-genre:hover .dsc-tile-art { opacity: .42; }
:root[data-theme="dark"] .dsc-genre.has-art .dsc-tile-name { text-shadow: 0 1px 3px rgba(0,0,0,.55); }
@media (prefers-contrast: more) { .dsc-tile-art { opacity: .10; } }

/* ---- studios: the mark, then the one true number ------------------------- */
.dsc-studio { min-height: 92px; justify-content: space-between; }
.dsc-studio-plate {
  display: flex; align-items: center; flex: 1 1 auto;
  min-height: 38px; overflow: hidden;
}
.dsc-studio-mark {
  width: auto; height: auto; max-width: 100%; max-height: 34px;
  object-fit: contain; object-position: left center;
}
/* ⭐ ONE INVERT, ON A KNOWN INPUT. discover.js pulls the logo through TMDB's
   duotone filter, so whatever the studio's own artwork was, the file that
   arrives is white-on-transparent — right for the vault, invisible on the light
   table. Because the input is now a single known tone, inverting it is exact;
   inverting the raw art would have fixed the black marks and broken the white
   ones. ⚠️ Light is the base, dark overrides — the tokens.css contract. */
.dsc-studio-mark { filter: invert(1); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .dsc-studio-mark { filter: none; }
}
:root[data-theme="dark"] .dsc-studio-mark { filter: none; }
:root[data-theme="light"] .dsc-studio-mark { filter: invert(1); }

.dsc-held {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* ---- the rail a tile opens, in place ------------------------------------- */
.dsc-drill { margin: 14px 0 0; padding: 13px 0 0; border-top: var(--hair) solid var(--rule); }
.dsc-drill-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 9px; margin: 0 0 10px; }
.dsc-drill-name {                    /* what you filtered by = the accent */
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--accent);
}
.dsc-drill-note { font-family: var(--font-mono); font-size: 10.5px; color: var(--muted); }
.dsc-drill-clear { margin-left: auto; }

@media (max-width: 560px) {
  .dsc-tiles { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 8px; }
  .dsc-tile { min-height: 66px; padding: 9px 10px; }
  .dsc-studio { min-height: 84px; }
  .dsc-studio-mark { max-height: 28px; }

  /* ⭐ THREE ROWS EACH ON A PHONE. The grids now sit ABOVE the rail, and at two
     columns 19 genres and 12 studios put the first poster ~1400px down — two
     screenfuls of labels before a single film. Cut to three rows it is ~590px,
     and the "show all" in each head is the way past. ⛔ The cut is CSS, not a
     different list built in JS: rotating a phone must not need a rebuild — and
     because it is a rule on .dsc-tiles rather than a count, the series grid's
     16 genres are cut by the same six without a line being added for them. */
  .dsc-tiles:not(.is-all) > *:nth-child(n+7) { display: none; }
  .dsc-tiles:not(.is-all) > *[aria-pressed="true"] { display: flex; }
}
/* nothing is hidden at this width, so the control that reveals it is not shown */
@media (min-width: 561px) { .dsc-tiles-all.is-narrow-only { display: none; } }

/* The gated read-me. Sits above everything and cannot be dismissed by Esc or a
   backdrop click — the tick is the only way past. */
.dsc-rm-wrap { z-index: 90; }
.dsc-rm-list { margin: 12px 0 0; padding-left: 18px; }
.dsc-rm-list li {
  margin: 0 0 5px; font-family: var(--font-ui); font-size: 13px; color: var(--ink-2);
}
.dsc-rm-tick {
  display: flex; align-items: center; gap: 8px; margin: 14px 0 0; cursor: pointer;
  font-family: var(--font-ui); font-size: 13px; color: var(--ink);
}
.dsc-rm-hide { margin-top: 6px; color: var(--muted); }
.dsc-rm-note {
  margin: 10px 0 0; font-family: var(--font-mono); font-size: 10.5px; color: var(--muted);
}
