/*
 * Rising Seasons — app styles.
 *
 * Loaded after assets/css/main.css so these rules win on conflicts. The
 * site chrome (#header / #footer / #menu) keeps its dark #181818 styling
 * from main.css; this file forces the dark IMDb-style theme on the body
 * background and normalizes every interactive control to the same height
 * + alignment so the toolbar reads as one row.
 */

:root {
  /* Tells the browser to use dark UI for native widgets — scrollbars,
     <select> popup menus, calendar pickers — so dropdowns aren't white. */
  color-scheme: dark;

  /* Cinematic dark palette. The base is a near-black with a slight blue
     hue; surfaces step up through warm dark greys for tactile depth. */
  --bg: #07090f;
  --bg-grad:
    radial-gradient(ellipse 90% 60% at 50% -10%, rgba(245, 197, 24, 0.08), transparent 60%),
    radial-gradient(ellipse 60% 40% at 10% 10%, rgba(245, 197, 24, 0.04), transparent 70%),
    radial-gradient(ellipse 50% 50% at 90% 30%, rgba(74, 222, 128, 0.025), transparent 70%),
    linear-gradient(180deg, #0a0c14 0%, #07090f 60%, #050609 100%);
  --surface: #12151d;
  --surface-2: #181c26;
  --surface-3: #232836;
  --surface-glass: rgba(24, 28, 38, 0.65);

  --text: #f1f3f8;
  --muted: #a4adbd;
  --muted-2: #6f7785;

  --accent: #f5c518;     /* IMDb yellow */
  --accent-warm: #ffd24a;
  --accent-ink: #1a1500; /* high-contrast text on yellow */
  --accent-soft: rgba(245, 197, 24, 0.12);
  --accent-strong: rgba(245, 197, 24, 0.32);
  --accent-glow: 0 0 0 1px rgba(245, 197, 24, 0.4), 0 0 18px rgba(245, 197, 24, 0.15);

  --good: #34d39e;
  --good-soft: rgba(52, 211, 158, 0.14);
  --good-ink: #04231a;

  --warn: #fb923c;
  --danger: #f87171;

  --border: #232838;
  --border-strong: #343a4f;

  --radius: 16px;
  --radius-sm: 10px;
  --radius-xs: 6px;
  --header-h: 3.25rem;

  /* Uniform interactive sizing — every button, input, and chip respects
     these so the filter toolbar lines up cleanly. */
  --ctrl-h: 40px;
  --ctrl-h-sm: 32px;
  --ctrl-radius: 10px;
  --ctrl-pad-x: 0.95rem;
  --ctrl-font: 0.9rem;

  --shadow-lift: 0 6px 22px -8px rgba(0, 0, 0, 0.55), 0 2px 4px rgba(0, 0, 0, 0.3);
  --shadow-modal: 0 30px 80px -10px rgba(0, 0, 0, 0.7), 0 8px 24px -4px rgba(0, 0, 0, 0.4);

  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);

  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
}

* { box-sizing: border-box; }

/* --- background hard-locked to dark theme ---
   Set on <html> as well as the scoped body class so even if a higher-specificity
   selector somewhere in main.css fights for body's background, the dark colour
   shows through from html. */
html {
  background: var(--bg);
  background-image: var(--bg-grad);
  background-attachment: fixed;
  background-color: var(--bg);
  min-height: 100%;
  /* Always show the vertical scrollbar so its gutter is permanently
     reserved. Without this, expanding the More-filters panel grows the
     page tall enough to surface the scrollbar, which steals ~15px from
     the viewport width and yanks the centered .page sideways. Using
     overflow-y:scroll instead of scrollbar-gutter:stable for universal
     browser support (Safari < 18 ignores scrollbar-gutter). */
  overflow-y: scroll;
  scrollbar-gutter: stable;
}

body.rising-seasons-app {
  background: transparent !important;
  color: var(--text);
  line-height: 1.5;
  min-height: 100vh;
  font-family: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  /* main.css adds padding-top: 3.25rem for the fixed header — keep that. */
}

/* Shared site texture: main.css already applies the faint bg.jpg overlay
   via body::before at 5% opacity. We keep it (matches every other app)
   and just guarantee it sits BEHIND our dark gradients so the dark theme
   stays dominant and the overlay reads as subtle grain on top of the
   indigo/green corner washes. */
body.rising-seasons-app::before {
  z-index: -1;
}

body.rising-seasons-app a {
  color: var(--accent);
  text-decoration: none;
}
body.rising-seasons-app a:hover { text-decoration: underline; }

body.rising-seasons-app h1,
body.rising-seasons-app h2,
body.rising-seasons-app h3,
body.rising-seasons-app h4 {
  color: var(--text);
  margin: 0;
  letter-spacing: -0.01em;
  text-transform: none;
  font-weight: 600;
  line-height: 1.25;
}

body.rising-seasons-app input,
body.rising-seasons-app select,
body.rising-seasons-app textarea,
body.rising-seasons-app button {
  font-family: inherit;
}

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

/* ---------- Buttons (single source of truth) ----------
   Every interactive control in the app uses one of: .btn, .shape-chip,
   .genre-chip, .watch-toggle. They share the same height tokens and use
   flex for true horizontal+vertical centering so text never drifts.

   IMPORTANT — main.css line ~322 has `button:hover { color: #ce1b28
   !important }` (the site's red link colour). To stop our buttons
   turning red on hover, every color rule below uses !important so the
   class-scoped colour wins. The hover declaration must also be
   !important — without it, only the default state survives. */

.btn[hidden] { display: none; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  height: var(--ctrl-h);
  padding: 0 var(--ctrl-pad-x);
  border: 1px solid var(--border);
  border-radius: var(--ctrl-radius);
  background: var(--surface);
  color: var(--text) !important;
  font: inherit;
  font-size: var(--ctrl-font);
  font-weight: 500;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  box-shadow: none !important;
  transition: background 0.18s var(--ease), border-color 0.18s var(--ease),
              color 0.18s var(--ease), transform 0.1s var(--ease), filter 0.18s var(--ease);
}

.btn:hover {
  background: var(--surface-2);
  border-color: var(--border-strong);
  color: var(--text) !important;
  box-shadow: none !important;
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft), 0 0 0 1px var(--accent) !important;
}
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

/* Primary (yellow CTA) — high-contrast dark text on yellow */
.btn-primary,
.btn-primary:hover {
  background: linear-gradient(135deg, var(--accent-warm), var(--accent) 55%, #e0b00f);
  color: var(--accent-ink) !important;
  border-color: transparent;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.btn-primary:hover {
  filter: brightness(1.06);
  transform: translateY(-1px);
  box-shadow: 0 8px 20px -8px rgba(245, 197, 24, 0.45) !important;
}
.btn-primary:active { transform: translateY(0); }

/* Ghost (secondary action) — white text per the site's light-on-dark rule */
.btn-ghost,
.btn-ghost:hover {
  background: transparent;
  color: var(--text) !important;
  border-color: var(--border-strong);
}
.btn-ghost:hover { background: var(--surface-2); border-color: var(--border-strong); }

/* View-toggle buttons live inside a wrapper that draws the border, so they
   reset their own border to look like a single segmented control. */
.view-toggle {
  display: inline-flex;
  height: var(--ctrl-h);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border);
  border-radius: var(--ctrl-radius);
  overflow: hidden;
  align-self: stretch;
  padding: 3px;
  gap: 2px;
}
.view-btn,
.view-btn:hover {
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--muted) !important;
  width: 2.4rem;
  height: 100%;
  font-size: 1rem;
  box-shadow: none !important;
  transition: background 0.18s var(--ease), color 0.18s var(--ease);
}
.view-btn:hover { background: var(--surface-3); color: var(--text) !important; }
.view-btn[aria-pressed="true"],
.view-btn[aria-pressed="true"]:hover {
  background: var(--accent);
  color: var(--accent-ink) !important;
}

/* Modal close X — small circular glass button. Smaller than the
   surrounding controls (32 px) so it doesn't read as a primary action,
   uses backdrop-blur + a hairline border to feel like a deliberate
   floating overlay rather than a misplaced grey square. Icon sized in
   px and lined up with `line-height: 1` so the × is mathematically
   centred regardless of font metrics. */
.modal-close,
.modal-close:hover {
  width: 32px;
  height: 32px;
  padding: 0;
  border-radius: 50%;
  background: rgba(20, 24, 35, 0.62);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.85) !important;
  font-size: 18px;
  line-height: 1;
  font-weight: 400;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow:
    0 4px 14px rgba(0, 0, 0, 0.35),
    0 0 0 1px rgba(0, 0, 0, 0.4) inset !important;
  transition: background 0.18s var(--ease), border-color 0.18s var(--ease), color 0.18s var(--ease), transform 0.08s var(--ease);
}
.modal-close:hover {
  background: rgba(36, 41, 56, 0.85);
  border-color: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
}
.modal-close:active { transform: scale(0.94); }
.modal-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Modal "Mark as watched" button — extends .btn (white text by default). */
.watch-btn.is-watched,
.watch-btn.is-watched:hover {
  background: var(--good);
  color: var(--good-ink) !important;
  border-color: var(--good);
}
.watch-btn.is-watched:hover { filter: brightness(1.05); }

/* Card/row corner watched toggle — circular pill, smaller height */
.watch-toggle,
.watch-toggle:hover {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.4);
  background: rgba(0, 0, 0, 0.6);
  color: #ffffff !important;
  font-size: 0.95rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(4px);
  box-shadow: none !important;
  transition: background 0.15s, color 0.15s, transform 0.1s, border-color 0.15s;
  z-index: 2;
}
.watch-toggle:hover { transform: scale(1.08); background: rgba(0, 0, 0, 0.75); }
.watch-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.watch-toggle[aria-pressed="true"],
.watch-toggle[aria-pressed="true"]:hover {
  background: var(--good);
  color: var(--good-ink) !important;
  border-color: var(--good);
}

/* ---------- Page layout ---------- */

.page {
  /* Match the site footer's text container exactly — main.css `.inner` is
     `width: 75rem; max-width: calc(100% - 6rem)`, so we mirror that here.
     The page's content edges then line up with the footer text edges on
     every viewport size, and there's no horizontal shift when the body
     scrollbar appears (overflow-y: scroll on <html> keeps the gutter
     reserved at all times). */
  width: 75rem;
  max-width: calc(100% - 6rem);
  box-sizing: border-box;
  margin: 0 auto;
  padding: 0 0 3rem;
}

.hero {
  padding: 3.25rem 0 0.75rem;
  text-align: center;
  background: none !important;
  position: relative;
}

.hero h1 {
  font-size: clamp(2.25rem, 5.5vw, 3.75rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.05;
  background: linear-gradient(135deg, #ffe169 0%, var(--accent) 45%, #f5c518 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 4px 24px rgba(245, 197, 24, 0.18));
}

.tagline {
  margin: 0.65rem auto 0;
  max-width: 38rem;
  color: var(--muted);
  font-size: 1.02rem;
  letter-spacing: -0.005em;
  line-height: 1.45;
}
.tagline em {
  color: var(--text);
  font-style: normal;
  font-weight: 500;
  background: linear-gradient(135deg, var(--text) 0%, var(--accent-warm) 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* ---------- Shape chips ----------
   Editorial discovery chips: a real subtle surface that defines each
   pill, a visible-but-soft outline, full white name + readable
   description + tertiary count. Compact, uniform, intentional.
   Active state lifts to a soft yellow wash + accent border + accent
   text without resorting to a bright slab. */

.shapes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem 0.5rem;
  justify-content: center;
  padding: 1.6rem 0 0.75rem;
  max-width: 56rem;
  margin: 0 auto;
}

.shape-chip,
.shape-chip:hover {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  height: 32px;
  padding: 0 0.85rem;
  /* Subtle surface — clearly lighter than the page bg so each chip
     reads as an object, never as floating text. */
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 999px;
  color: var(--text) !important;
  font: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.005em;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.02) inset !important;
  transition: background 0.18s var(--ease), border-color 0.18s var(--ease),
              color 0.18s var(--ease);
}
.shape-chip:hover {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.18);
}
.shape-chip:focus-visible {
  /* Same reasoning as .label-chip — inset focus ring so adjacent chips
     never share a visual frame. */
  outline: 2px solid rgba(245, 197, 24, 0.65);
  outline-offset: -2px;
}
.shape-chip[aria-pressed="true"],
.shape-chip[aria-pressed="true"]:hover {
  background: rgba(245, 197, 24, 0.12);
  border-color: rgba(245, 197, 24, 0.45);
  color: var(--accent) !important;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.02) inset !important;
}

.shape-icon {
  color: var(--accent);
  font-weight: 700;
  font-size: 0.9rem;
  line-height: 1;
  opacity: 0.95;
}
.shape-name {
  font-weight: 600;
  /* Stronger than description so the pattern name reads first. */
}

.shape-desc {
  display: none;
  color: rgba(231, 233, 238, 0.62);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0;
}
@media (min-width: 760px) {
  .shape-desc { display: inline; }
}
.shape-chip[aria-pressed="true"] .shape-desc {
  color: rgba(245, 197, 24, 0.7);
}

.shape-count {
  display: inline-flex;
  align-items: center;
  height: 17px;
  padding: 0 0.45rem;
  /* Tertiary badge — a real container so the number sits in a defined
     slot rather than floating loose, but quiet enough that the name
     still owns the chip. */
  background: rgba(255, 255, 255, 0.05);
  border-radius: 999px;
  font-size: 0.68rem;
  color: rgba(231, 233, 238, 0.6);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  margin-left: 0.1rem;
}
.shape-chip:hover .shape-count {
  background: rgba(255, 255, 255, 0.08);
  color: rgba(231, 233, 238, 0.75);
}
.shape-chip[aria-pressed="true"] .shape-count {
  background: rgba(245, 197, 24, 0.18);
  color: var(--accent);
}

.shape-chip:disabled,
.shape-chip.is-disabled {
  opacity: 0.3;
  cursor: not-allowed;
  pointer-events: none;
}

/* ---------- Filter toolbar ---------- */

.filters {
  padding: 1.5rem 0 0.5rem;
}

.filter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: stretch;
}

/* Primary row reads as one connected toolbar: glassy surface, single
   rounded shell, with controls visually grouped inside it.
   IMPORTANT: backdrop-filter creates a stacking context. The search
   dropdown (.search-suggestions) lives inside this row and can't escape
   that context. Lifting the whole row with position:relative + z-index
   guarantees the dropdown paints above .label-filters and .stats-bar
   below. The row has no visible overlap of its own — sibling content
   only appears once the dropdown is open. */
.filter-row.primary {
  position: relative;
  z-index: 50;
  isolation: isolate;
  /* Scoped control height — overrides the global 40 px just for this
     toolbar. The custom property cascades to every descendant that uses
     `var(--ctrl-h)` (search input, view-toggle rail, view buttons, the
     Surprise primary button), so they all shrink to 32 px in one shot
     while keeping the rest of the app (modal close, modal buttons, etc.)
     untouched. */
  --ctrl-h: 32px;
  align-items: center;
  background: var(--surface-glass);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--border);
  /* Top half of a unified two-row toolbar — fully rounded on top,
     squared off at the bottom, no bottom border. The filter row below
     extends the same surface and closes the shell. */
  border-radius: 12px 12px 0 0;
  border-bottom: 0;
  padding: 3px 3px 1px;
  gap: 0.3rem;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.02) inset, var(--shadow-lift);
}

/* Soften the Surprise CTA — was the heaviest element on the bar,
   competing with active filter pills. Now reads as a secondary action
   that's still clearly the primary yellow surface, just less shouty. */
.filter-row.primary .surprise {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0;
  padding: 0 0.85rem;
  filter: saturate(0.92);
}
.filter-row.primary .surprise:hover { filter: saturate(1) brightness(1.04); }

/* Tighter horizontal padding on the buttons inside the slimmer toolbar
   so the labels don't crowd the rounded edges at the smaller height. */
.filter-row.primary .btn { padding: 0 0.85rem; font-size: 0.85rem; }
.filter-row.primary .surprise { font-weight: 600; }
.filter-row.primary .view-btn { width: 2.1rem; font-size: 0.95rem; }

.filter-row label {
  display: flex;
  flex-direction: column;
  font-size: 0.75rem;
  color: var(--muted);
  gap: 0.25rem;
  min-width: 110px;
  flex: 1 1 110px;
}

.search {
  flex: 1 1 100% !important;
  min-width: 0 !important;
  position: relative;
}
@media (min-width: 760px) {
  .search { flex: 1 1 240px !important; }
}

.search > label { display: block; }

.search-suggestions {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  z-index: 100;
  margin: 0;
  padding: 0.3rem;
  list-style: none;
  /* Explicit solid color (not the theme alias) so the panel is never
     semi-transparent — content underneath must never bleed through. */
  background-color: #161922;
  background-image: linear-gradient(180deg, rgba(255,255,255,0.025), rgba(255,255,255,0));
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow:
    0 14px 36px rgba(0, 0, 0, 0.55),
    0 2px 8px rgba(0, 0, 0, 0.35),
    0 0 0 1px rgba(255, 255, 255, 0.03) inset;
  max-height: 380px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
.search-suggestions::-webkit-scrollbar {
  width: 10px;
}
.search-suggestions::-webkit-scrollbar-track {
  background: transparent;
  margin: 6px 0;
}
.search-suggestions::-webkit-scrollbar-thumb {
  background-color: var(--border-strong);
  background-clip: content-box;
  border: 3px solid transparent;
  border-radius: 999px;
}
.search-suggestions::-webkit-scrollbar-thumb:hover {
  background-color: var(--muted-2);
  background-clip: content-box;
}

.search-suggestion {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.45rem 0.6rem;
  min-height: 44px;
  cursor: pointer;
  color: var(--text);
  font-size: 0.9rem;
  border: 0;
  background: transparent;
  border-radius: 8px;
  transition: background 0.12s var(--ease);
}

.search-suggestion + .search-suggestion { margin-top: 1px; }

.search-suggestion:hover,
.search-suggestion[aria-selected="true"] {
  background: var(--surface-2);
}

.search-suggestion .ss-poster {
  flex: 0 0 32px;
  width: 32px;
  height: 48px;
  background: var(--border);
  border-radius: 3px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted-2);
  font-size: 0.7rem;
}

.search-suggestion .ss-poster img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.search-suggestion .ss-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1 1 auto;
}

.search-suggestion .ss-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.search-suggestion .ss-meta {
  font-size: 0.75rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.search-suggestion .ss-ep-hint {
  display: block;
  font-size: 0.72rem;
  color: var(--accent);
  font-style: italic;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 0.1rem;
}

.search-suggestion mark {
  background: transparent;
  color: var(--accent);
  font-weight: 600;
  padding: 0;
}

.search input,
.filter-row input,
.filter-row select {
  height: var(--ctrl-h);
  padding: 0 0.7rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--ctrl-radius);
  font: inherit;
  font-size: var(--ctrl-font);
  width: 100%;
  appearance: none;
  -webkit-appearance: none;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease), box-shadow 0.2s var(--ease);
  /* Tell the browser this control is dark so the native popup menu uses
     a dark theme too instead of the OS default light. */
  color-scheme: dark;
}

/* Some browsers (Firefox in particular) render <option> with the OS
   light theme even with color-scheme: dark — force dark explicitly. */
.filter-row select option {
  background: var(--surface);
  color: var(--text);
}

/* Inside the glassy primary toolbar the search field needs a transparent
   look so the surface reads as one piece, not nested boxes. */
.filter-row.primary .search input {
  background: transparent;
  border-color: transparent;
  padding: 0 0.8rem 0 2.15rem;
  font-size: 0.88rem;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a4adbd' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='7'/><path d='M21 21l-4.35-4.35'/></svg>");
  background-repeat: no-repeat;
  background-position: 0.7rem center;
  background-size: 0.9rem 0.9rem;
}
.filter-row.primary .search input:hover { background-color: rgba(255, 255, 255, 0.025); }
.filter-row.primary .search input:focus {
  background-color: rgba(255, 255, 255, 0.04);
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.search input { padding: 0 0.85rem; font-size: 1rem; }
.search input::placeholder { color: var(--muted-2); }

.filter-row select {
  padding-right: 2rem;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 1rem) calc(50% - 2px), calc(100% - 0.6rem) calc(50% - 2px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

.filter-row input:focus,
.filter-row select:focus,
.search input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ---------- Quick filters drawer ----------
 * Wraps the row of Type / Watched / IMDb / Gems chips behind a small
 * toggle so the main page reads results-first. The .label-filters
 * styles handle the panel chrome when expanded. */
.quick-filters-wrap {
  margin: 0.6rem 0;
}
.quick-filters-wrap > summary {
  cursor: pointer;
  list-style: none;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 0.85rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease), color 0.15s var(--ease);
}
.quick-filters-wrap > summary::-webkit-details-marker { display: none; }
.quick-filters-wrap > summary:hover {
  background: rgba(255, 255, 255, 0.06);
  border-color: var(--border-strong);
  color: var(--text);
}
.quick-filters-wrap[open] > summary {
  background: var(--accent-soft);
  border-color: var(--accent-strong);
  color: var(--accent);
}

/* ---------- "More filters" panel ----------
   Editorial filter sheet: caption-style labels, dense grid of slim
   inputs, soft hairline-divided sub-sections, integrated Reset link.
   Surface is just a hint above the page bg, not a strong card. */

/* Always-on panel chrome — keeps the section the same outer width whether
   the user has expanded the additional filters or not. Previously the
   background/border/padding only applied with [open], so opening the
   section made it appear to widen. */
.advanced {
  margin-top: 0.6rem;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.018));
  border: 1px solid rgba(255, 255, 255, 0.085);
  border-radius: 12px;
  padding: 0.9rem 1.1rem;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.04) inset,
    var(--shadow-lift);
}

/* Trigger: small, quiet, refined. A "+" rotates to "×" when open. */
.advanced summary {
  cursor: pointer;
  list-style: none;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.35rem 0.7rem;
  border-radius: 7px;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(231, 233, 238, 0.6);
  transition: color 0.15s var(--ease), background 0.15s var(--ease);
}
/* The browser draws a default focus ring on <summary> when one of its
 * children (e.g. the in-summary "Clear all filters" pill) is clicked —
 * focus moves to the summary and the ring frames BOTH children, looking
 * like a single black border wrapping the chip and the pill together.
 * Suppress that ring; the pill and the summary text each have their own
 * hover/focus indicators so no accessibility is lost. */
.advanced summary:focus,
.advanced summary:focus-visible {
  outline: none !important;
  box-shadow: none !important;
}
.advanced summary::-webkit-details-marker { display: none; }
.advanced summary:hover {
  color: var(--text);
  background: rgba(255, 255, 255, 0.035);
}
.advanced summary::before {
  content: '+';
  display: inline-block;
  width: 0.9rem;
  text-align: center;
  font-size: 0.95rem;
  font-weight: 400;
  color: rgba(231, 233, 238, 0.5);
  transition: transform 0.2s var(--ease), color 0.2s var(--ease);
}
.advanced[open] summary {
  color: var(--text);
  margin: 0 0 0.65rem;
}
.advanced[open] summary::before {
  transform: rotate(45deg);  /* + → × */
  color: var(--accent);
}

/* Row that pairs the Quick filters pill with the Clear-filters pill
 * immediately to its right. The .label-filters panel lives as a sibling
 * row below — its visibility is driven by the <details>' [open] state via
 * :has(), so the panel can't widen the row and push the Clear pill below
 * the summary. */
.quick-filters-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0.6rem 0;
}
.quick-filters-row > .quick-filters-wrap { margin: 0; }

#quickFiltersPanel { display: none; }
.filters:has(.quick-filters-wrap[open]) #quickFiltersPanel {
  display: flex;
  margin-top: 0.5rem;
}

.advanced summary .advanced-summary-label { display: inline-flex; align-items: center; }

/* "Clear filters" pill — anchored to the right side of the Quick filters
 * row so it's always visible alongside the filter controls, regardless of
 * whether either drawer is open. Hidden via [hidden] when no filters are
 * active. */
.advanced-reset,
.advanced-reset:hover {
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding: 0 0.85rem;
  background: rgba(248, 113, 113, 0.12);
  border: 1px solid rgba(248, 113, 113, 0.4);
  border-radius: 999px;
  color: var(--danger, #f87171) !important;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: none !important;
  line-height: 1;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease), color 0.15s var(--ease);
  flex: 0 0 auto;
  white-space: nowrap;
}
.advanced-reset:hover {
  background: rgba(248, 113, 113, 0.2);
  border-color: rgba(248, 113, 113, 0.6);
}
.advanced-reset:focus-visible {
  outline: 2px solid rgba(245, 197, 24, 0.55);
  outline-offset: 2px;
}
.advanced-reset[hidden] { display: none; }


/* Numeric inputs + Sort: 4-column grid for an even rhythm, caption
   labels above slim 32 px controls. */
.advanced .filter-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.7rem 0.7rem;
  align-items: end;
}
.advanced .filter-row label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
  flex: 0 1 auto;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* Captions in supporting role above the input — bright enough to
     scan cleanly against the dark panel without competing with the
     input value in full white. */
  color: rgba(231, 233, 238, 0.78);
}
.advanced .filter-row input,
.advanced .filter-row select {
  width: 100%;
  height: 32px;
  padding: 0 0.7rem;
  /* Stronger contrast than the panel itself so inputs read as
     defined slots, not the same plane as the panel surface. */
  background: rgba(255, 255, 255, 0.055);
  border: 1px solid rgba(255, 255, 255, 0.11);
  border-radius: 7px;
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  font-family: inherit;
  appearance: none;
  -webkit-appearance: none;
  color-scheme: dark;
  /* Subtle inner depth so each input sits like a small pressed slot. */
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.18) inset;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease),
              box-shadow 0.15s var(--ease);
}
.advanced .filter-row input:hover,
.advanced .filter-row select:hover {
  background: rgba(255, 255, 255, 0.075);
  border-color: rgba(255, 255, 255, 0.18);
}
.advanced .filter-row input:focus,
.advanced .filter-row select:focus {
  outline: none;
  background: rgba(255, 255, 255, 0.09);
  border-color: rgba(245, 197, 24, 0.55);
  box-shadow:
    0 0 0 2px rgba(245, 197, 24, 0.14),
    0 1px 0 rgba(0, 0, 0, 0.18) inset;
}
.advanced .filter-row input::placeholder {
  color: rgba(231, 233, 238, 0.55);
  font-weight: 400;
}
/* Restore the chevron on the slim Sort select (the default arrow gets
   stripped by appearance:none). Same dark SVG the toolbar uses. */
.advanced .filter-row select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23a4adbd' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='3,5 6,8 9,5'/></svg>");
  background-repeat: no-repeat;
  background-position: right 0.55rem center;
  background-size: 12px 12px;
  padding-right: 1.75rem;
}

/* Genres: editorial sub-section with its own caption + visible
   divider above. Chips are bigger and brighter than the inputs so
   the section reads as "tap a chip" rather than another row of
   form fields. */
.chip-section {
  position: relative;
  margin-top: 1.15rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(255, 255, 255, 0.075);
}
.chip-section-title {
  display: block;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(231, 233, 238, 0.85);
  margin-bottom: 0.5rem;
}
/* Hide the whole section when its chip row is empty (e.g. providers
   before the cache has been populated). :has() saves a JS toggle. */
.chip-section:has(.genre-row:empty) { display: none; }

.genre-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.4rem;
}
.genre-row:empty { display: none; }

.genre-chip,
.genre-chip:hover {
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding: 0 0.8rem;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px;
  color: var(--text) !important;
  font: inherit;
  font-size: 0.74rem;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  line-height: 1;
  /* Subtle top-edge lift gives each chip a sense of object */
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.03) inset !important;
  transition: background 0.18s var(--ease), border-color 0.18s var(--ease), color 0.18s var(--ease);
}
.genre-chip:hover {
  background: rgba(255, 255, 255, 0.09);
  border-color: rgba(255, 255, 255, 0.22);
  color: var(--text) !important;
}
.genre-chip[aria-pressed="true"],
.genre-chip[aria-pressed="true"]:hover {
  background: rgba(245, 197, 24, 0.13);
  border-color: rgba(245, 197, 24, 0.5);
  color: var(--accent) !important;
}
/* Tri-state for genre chips only — clicking a green chip again flips it to
   "exclude" (red). Click once more to clear. */
.genre-chip[data-exclude="true"],
.genre-chip[data-exclude="true"]:hover {
  background: rgba(248, 113, 113, 0.12);
  border-color: rgba(248, 113, 113, 0.55);
  color: var(--danger) !important;
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}
.genre-chip:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow:
    0 0 0 2px rgba(245, 197, 24, 0.18),
    0 1px 0 rgba(255, 255, 255, 0.03) inset !important;
}

/* Reset link: integrated, not a stranded button. */
.filter-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  margin-top: 1rem;
  padding-top: 0.8rem;
  border-top: 1px solid rgba(255, 255, 255, 0.075);
}
.filter-actions .btn,
.filter-actions .btn:hover {
  height: 26px;
  padding: 0 0.6rem;
  background: transparent;
  border: 0;
  color: rgba(231, 233, 238, 0.85) !important;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  box-shadow: none !important;
  transition: color 0.15s var(--ease);
}
.filter-actions .btn:hover { color: var(--accent) !important; background: transparent; }
.filter-actions .btn:disabled,
.filter-actions .btn[disabled] {
  opacity: 0.4;
  pointer-events: none;
}

/* Mobile: collapse the 4-up grid to 2 so inputs don't get squished. */
@media (max-width: 540px) {
  .advanced { padding: 0.75rem 0.85rem; }
  .advanced .filter-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .chip-section { margin-top: 0.9rem; padding-top: 0.8rem; }
  .filter-actions { margin-top: 0.85rem; padding-top: 0.7rem; }
}

/* ---------- Stats bar ---------- */

.stats-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 2rem;
  padding: 0.85rem 1.1rem;
  background: var(--surface-glass);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border: 1px solid var(--border);
  border-radius: 12px;
  margin: 1rem 0 0.5rem;
  font-size: 0.85rem;
  color: var(--muted);
  align-items: center;
  letter-spacing: 0.005em;
}
.stats-bar:empty { display: none; }
.stats-bar > span { display: inline-flex; align-items: baseline; gap: 0.35rem; }
.stats-bar strong {
  color: var(--text);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.stats-bar .progress {
  flex: 1 1 200px;
  min-width: 160px;
  height: 6px;
  background: rgba(255, 255, 255, 0.06);
  border-radius: 999px;
  overflow: hidden;
  position: relative;
}
.stats-bar .progress-fill {
  position: absolute; inset: 0;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-warm) 50%, var(--good) 100%);
  border-radius: 999px;
  transition: width 0.4s var(--ease);
  width: 0;
}
.stats-bar .stale {
  color: var(--warn);
  font-size: 0.78rem;
  padding: 0.15rem 0.55rem;
  background: rgba(251, 146, 60, 0.12);
  border-radius: 999px;
}

/* ---------- Meta + results ---------- */

.meta, .footer-meta {
  color: var(--muted);
  font-size: 0.85rem;
  letter-spacing: 0.005em;
}
.meta {
  margin: 1rem 0 0.75rem;
  padding-left: 0.15rem;
}
.footer-meta {
  padding: 1.5rem 0 0.5rem;
  text-align: center;
  font-size: 0.78rem;
  color: var(--muted-2);
}

.results-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 1.25rem;
  margin: 0.5rem 0 1rem;
}

.results-grid.list-view {
  grid-template-columns: 1fr;
  gap: 0.5rem;
}

@media (min-width: 980px) {
  .results-grid {
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  }
}

/* ---------- Card (grid view) ---------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: border-color 0.2s var(--ease), transform 0.25s var(--ease),
              box-shadow 0.25s var(--ease);
  cursor: pointer;
  position: relative;
}
.card:hover {
  border-color: var(--border-strong);
  transform: translateY(-3px);
  box-shadow: var(--shadow-lift);
}
.card:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--accent-glow);
}
.card.is-watched {
  border-color: rgba(52, 211, 158, 0.4);
}
.card.is-watched::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: var(--radius);
  pointer-events: none;
  box-shadow: inset 0 0 0 1px rgba(52, 211, 158, 0.25);
}
.card.is-watched .card-poster img { opacity: 0.55; }

/* Posters: TMDB poster_path images are 2:3 — match the natural aspect so
   the full poster shows without zooming or cropping. */
.card-poster {
  position: relative;
  aspect-ratio: 2 / 3;
  background: var(--surface-2);
  overflow: hidden;
}

.card-poster img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;          /* container is 2:3 = native aspect, so no crop */
  object-position: center;
  background: var(--surface-2);
  transition: opacity 0.2s;
}

.poster-fallback {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 30% 30%, rgba(245, 197, 24, 0.18), transparent 60%),
    radial-gradient(circle at 70% 70%, rgba(74, 222, 128, 0.12), transparent 60%),
    var(--surface-2);
}

.card-body {
  padding: 0.85rem 1rem 1rem;
  /* Grid so the curve always sits at its own row, regardless of how many
     lines the chip row above takes. Row order matches DOM source:
       1. card-head    (title + season)
       2. card-meta    (year + genres)
       3. card-shapes  (1fr — absorbs any extra vertical space so the
                        curve doesn't drift down when chips wrap)
       4. .curve       (sparkline, fixed height)
       5. card-stats   (single horizontal line)
     Since .results-grid stretches all cards in a row to the same height,
     the 1fr region resolves to the same value across siblings — putting
     every sparkline at the identical y from the top of its card. */
  display: grid;
  grid-template-rows: auto auto 1fr auto auto;
  row-gap: 0.55rem;
  flex: 1;
}

.card-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
}
.card-title {
  font-size: 1rem;
  letter-spacing: -0.01em;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.card-season {
  font-size: 0.78rem;
  color: var(--muted);
  white-space: nowrap;
  flex-shrink: 0;
}
.card-meta {
  display: flex;
  gap: 0.6rem;
  font-size: 0.75rem;
  color: var(--muted);
  flex-wrap: wrap;
}
/* Chip row wraps freely — overflow is preserved so every shape/provider
 * chip stays visible. Card-body's grid handles curve alignment so a
 * 2-line wrap here doesn't push the sparkline below it; the curve stays
 * pinned to its own row, the chip area just consumes more of the 1fr
 * flex region between meta and curve. */
.card-shapes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-content: flex-start;
}

.shape-tag {
  background: var(--surface-3);
  color: var(--text);
  font-size: 0.68rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  border: 1px solid transparent;
  font-family: inherit;
  line-height: 1.4;
}
button.shape-tag.is-clickable {
  cursor: pointer;
  transition: background-color 0.12s, color 0.12s, border-color 0.12s;
}
button.shape-tag.is-clickable:hover {
  background: var(--accent-soft);
  color: var(--accent);
  border-color: var(--accent-strong);
}
.shape-tag.active {
  background: var(--accent-soft);
  color: var(--accent);
}

/* Streaming-platform chip — distinct from the shape tags so the row reads
 * as "<pattern tags> · <where to watch>" rather than one homogenous token
 * blob. Cyan-tinted outline + leading play glyph give it a "channel" feel
 * versus the warm-filled trajectory tags. */
.provider-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  background: rgba(56, 189, 248, 0.08);
  color: rgba(125, 211, 252, 0.95);
  font-size: 0.66rem;
  font-weight: 600;
  padding: 0.1rem 0.55rem 0.1rem 0.45rem;
  border-radius: 999px;
  border: 1px solid rgba(56, 189, 248, 0.28);
  line-height: 1.4;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.provider-tag::before {
  content: '▶';
  font-size: 0.55rem;
  opacity: 0.85;
}

/* List-view genre line — mirrors .card-meta on the grid card. Lives inside
 * .row-head so it flows inline with title / season / year, separated by a
 * subtle bullet so the row stays compact. */
.row-genres {
  font-size: 0.78rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.row-genres:empty,
.row-genres[hidden] { display: none; }
.row-genres::before {
  content: '·';
  margin: 0 0.45rem 0 0;
  color: var(--muted-2);
}

/* Best / Worst season rank badges. Designed to sit inline with the
   season-metadata line ("S2 · 10 eps") rather than the title — compact
   pill, no wrap, subtle tinted surface. Icon + uppercase label give a
   premium streaming-app feel without competing with the title. */
.best-badge,
.worst-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  /* No left margin — these now sit at the start of .card-shapes/.row-shapes
     where the row's gap handles spacing from the next pill. */
  padding: 0 0.42rem;
  height: 1.05rem;
  line-height: 1;
  border-radius: 999px;
  border: 1px solid transparent;
  font-weight: 700;
  letter-spacing: 0.06em;
  white-space: nowrap;
  vertical-align: middle;
  font-size: 0.6rem;
  text-transform: uppercase;
  flex-shrink: 0;
}
.best-badge {
  color: var(--accent);
  background: rgba(245, 197, 24, 0.12);
  border-color: rgba(245, 197, 24, 0.28);
}
.worst-badge {
  color: var(--danger);
  background: rgba(248, 113, 113, 0.10);
  border-color: rgba(248, 113, 113, 0.28);
}
.rank-badge-icon {
  font-size: 0.72rem;
  line-height: 1;
  /* Slight optical lift — symbols sit lower than baseline. */
  transform: translateY(-0.04em);
}
.worst-badge .rank-badge-icon {
  /* The ▼ symbol is bottom-heavy; shift the opposite way. */
  transform: translateY(0.02em);
  font-size: 0.58rem;
}
.rank-badge-label { line-height: 1; }

.above-imdb {
  display: inline-block;
  margin-left: 0.3rem;
  color: var(--good);
  font-weight: 700;
  font-size: 0.85em;
  cursor: help;
  vertical-align: middle;
}
.above-imdb-pill {
  padding: 0.05rem 0.5rem;
  background: rgba(74, 222, 128, 0.15);
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  cursor: default;
}

/* ---------- Quick label filters ----------
   Bottom half of the unified toolbar — same glass surface as the
   search row above, separated only by a near-invisible hairline. No
   per-group boxes, no per-pill borders, no extra container. The shared
   shell anchors the filters to the toolbar so they read as part of it,
   not floating below it. */
.label-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* Horizontal gap between groups (~1rem) does the work of dividers. */
  gap: 0.3rem 1rem;
  /* Snug interior — close to the search row above, just enough room
     for the pills not to touch the bottom of the shell. */
  padding: 0.3rem 0.5rem 0.32rem;
  background: var(--surface-glass);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--border);
  /* Inner hairline divider only — perimeter shares the search row's
     border, top is the seam between rows. */
  border-top: 1px solid rgba(255, 255, 255, 0.04);
  border-radius: 0 0 12px 12px;
  /* Generous spacing AFTER the toolbar before the shape chips. */
  margin-bottom: 0.85rem;
}

/* Group = just a flex line of [tiny caption] [chips]. No surface, no
   border, no fixed height. */
.label-group {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  height: auto;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.label-group:hover,
.label-group:focus-within {
  background: transparent;
  border: 0;
  box-shadow: none;
}

/* Section caption: quiet, low-contrast, no divider. Just a label. */
.label-group-name {
  display: inline-flex;
  align-items: center;
  height: auto;
  padding: 0;
  margin: 0 0.05rem 0 0;
  font-size: 0.62rem;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: rgba(231, 233, 238, 0.55);
  font-weight: 600;
  border: 0;
  user-select: none;
  white-space: nowrap;
}

/* Chips: invisible until you hover or activate. No border, no shadow,
   no container — they read as tokens on the page. */
/* Total reset across every conceivable chip state. main.css applies a
 * sitewide `button { box-shadow: inset 0 0 0 1px #555 }` and changes it
 * to red on hover; without aggressive overrides, both the hovered chip
 * and its neighbor in the same group end up with 1px insets that read
 * together as a single border wrapping both buttons. We also keep the
 * focus indicator inside the chip (background-only) so the focus ring
 * never extends into a neighbor. */
.label-chip,
.label-chip:hover,
.label-chip:focus,
.label-chip:focus-visible,
.label-chip:active,
.label-chip[aria-pressed="true"],
.label-chip[aria-pressed="true"]:hover,
.label-chip[aria-pressed="true"]:focus,
.label-chip[aria-pressed="true"]:focus-visible {
  outline: 0 !important;
  border: 0 !important;
  box-shadow: none !important;
}

.label-chip {
  appearance: none;
  -webkit-appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 26px;
  padding: 0 0.65rem;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 0.76rem;
  font-weight: 600;
  line-height: 1;
  border-radius: 7px;
  cursor: pointer;
  transition:
    background 0.18s var(--ease),
    color 0.18s var(--ease);
  white-space: nowrap;
}
/* Bigger gap so even if some downstream theme tries to draw a 1px outline
 * it can't visually touch the neighbor — but they still feel like one
 * group thanks to the parent .label-group's gap rhythm. */
.label-chip + .label-chip { margin-left: 0.35rem; }
.label-chip:hover {
  color: #ffffff !important;
  background: rgba(255, 255, 255, 0.06);
}
.label-chip:focus-visible {
  /* Background-only focus indicator — no outline, no shadow. Cannot
     possibly extend into the adjacent chip's space. */
  background: rgba(245, 197, 24, 0.2);
  color: var(--accent) !important;
}

/* Active = a soft accent wash + accent text. No ring, no shadow.
   Reads as a quietly highlighted token rather than a button. Tinted
   one notch quieter than the shape chips above so the toolbar pills
   don't draw attention away from the editorial pattern chips. */
.label-chip[aria-pressed="true"] {
  background: rgba(245, 197, 24, 0.085);
  color: rgba(245, 197, 24, 0.92);
  box-shadow: none;
}
.label-chip[aria-pressed="true"]:hover {
  background: rgba(245, 197, 24, 0.14);
  color: var(--accent);
}
.label-chip-good[aria-pressed="true"] {
  background: rgba(74, 222, 128, 0.085);
  color: rgba(74, 222, 128, 0.92);
}
.label-chip-good[aria-pressed="true"]:hover {
  background: rgba(74, 222, 128, 0.14);
  color: var(--good);
}

.search-suggestion-empty {
  cursor: default;
  color: var(--muted-2);
  font-style: italic;
  padding: 0.5rem 0.7rem;
}
.search-suggestion-empty:hover {
  background: transparent;
}

.show-seasons {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.show-season {
  display: grid;
  grid-template-columns: 56px 1fr 110px auto;
  gap: 0.85rem;
  align-items: center;
  padding: 0.7rem 0.9rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  cursor: pointer;
  transition: background 0.18s var(--ease), border-color 0.18s var(--ease), transform 0.18s var(--ease);
}
.show-season:hover {
  background: var(--surface-3);
  border-color: var(--border-strong);
  transform: translateX(2px);
}
.show-season:focus-visible {
  background: var(--surface-3);
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.show-season.is-watched {
  border-color: rgba(52, 211, 158, 0.35);
}

.show-season .ss-num {
  font-weight: 600;
  font-size: 1rem;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.show-season .ss-meta {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.show-season .ss-eps {
  font-size: 0.78rem;
  color: var(--muted);
}
.show-season .ss-shape-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-top: 0.2rem;
}

.show-season .ss-spark {
  width: 100%;
  height: 36px;
  background: var(--surface);
  border-radius: 4px;
  display: block;
}

.show-season .ss-stats {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  font-size: 0.78rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.show-season .ss-avg {
  color: var(--text);
  font-weight: 600;
}
.show-season .ss-watched-tag {
  color: var(--good);
  font-size: 0.7rem;
}

@media (max-width: 560px) {
  /* The season-trend sparkline is the whole point of the app — restore
     it on mobile by stacking the row into two grid rows. Top row keeps
     S# / meta / stats compact; bottom row is a full-width spark. */
  .show-season {
    grid-template-columns: 48px 1fr auto;
    grid-template-areas:
      "num   meta  stats"
      "spark spark spark";
    row-gap: 0.45rem;
    align-items: start;
  }
  .show-season .ss-num   { grid-area: num; }
  .show-season .ss-meta  { grid-area: meta; }
  .show-season .ss-stats { grid-area: stats; }
  .show-season .ss-spark {
    grid-area: spark;
    display: block;
    width: 100%;
    height: 44px;
  }
}

.curve {
  /* The card body that wraps this SVG has 1rem of horizontal padding, so a
     plain width:100% would leave the yellow line drawn 1rem inset from the
     card's left/right edges. Extend the curve out past that padding with
     negative margins so the line literally starts at the card edges. */
  width: calc(100% + 2rem);
  margin-left: -1rem;
  margin-right: -1rem;
  height: 70px;
  background:
    radial-gradient(ellipse 60% 50% at 50% 100%, rgba(245, 197, 24, 0.06), transparent 70%),
    var(--surface-2);
  /* Keep the bottom corners rounded with the card (top corners flush against
     the content above) — but no border-radius makes the line/area truly hit
     the corner pixels without any rounded clip. */
  border-radius: 0;
  display: block;
  /* Let hover dots at viewBox x=0 / x=W render fully instead of half-clipped. */
  overflow: visible;
}
.curve-area { fill: rgba(245, 197, 24, 0.18); stroke: none; }
.curve-line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 4px rgba(245, 197, 24, 0.35));
}
.curve-dots circle {
  fill: var(--accent);
  cursor: help;
}

.modal-curve {
  width: 100%;
  height: 180px;
  /* Modal-panel is a flex column with overflow-y: auto. Without flex-shrink: 0,
     the SVG (which has no intrinsic content height) collapses when the modal's
     other content pushes the panel past its max-height, squashing the curve
     into a thin strip even though the viewBox math is correct. */
  flex-shrink: 0;
  background:
    radial-gradient(ellipse 60% 50% at 50% 100%, rgba(245, 197, 24, 0.08), transparent 70%),
    var(--surface-2);
  border-radius: 12px;
  padding: 0.5rem;
}

.season-overlay {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  flex-shrink: 0;
}
.season-overlay[hidden] { display: none; }
.overlay-curve {
  width: 100%;
  height: 200px;
  flex-shrink: 0;
  background: var(--surface-2);
  border-radius: 12px;
  padding: 0.5rem;
}
.overlay-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.8rem;
  font-size: 0.78rem;
  color: var(--muted);
}
.overlay-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.overlay-legend-swatch {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 2px;
}

.compare-fab {
  position: fixed;
  bottom: 1.25rem;
  right: 1.25rem;
  z-index: 9000;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.55rem 1rem;
  border-radius: 999px;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: #1a1300;
  font-weight: 700;
  font-size: 0.9rem;
  cursor: pointer;
  box-shadow:
    0 10px 24px rgba(0, 0, 0, 0.45),
    0 2px 8px rgba(245, 197, 24, 0.35);
  transition: transform 0.12s var(--ease), box-shadow 0.2s var(--ease);
}
.compare-fab[hidden] { display: none; }
.compare-fab:hover { transform: translateY(-1px); }
.compare-fab-icon { font-size: 1.05rem; }
.compare-fab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.35rem;
  height: 1.35rem;
  padding: 0 0.4rem;
  border-radius: 999px;
  background: rgba(26, 19, 0, 0.18);
  font-size: 0.8rem;
}

.compare-legend-remove {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.2rem 0.55rem;
  color: var(--text);
  cursor: pointer;
  font-size: 0.78rem;
  transition: border-color 0.15s, background 0.15s;
}
.compare-legend-remove:hover {
  border-color: var(--danger);
  background: rgba(248, 113, 113, 0.08);
}
.compare-legend-x {
  margin-left: 0.15rem;
  color: var(--muted);
  font-weight: 700;
}

.provider-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.35rem;
}
.provider-badges:empty { display: none; }
.provider-badge {
  display: inline-block;
  padding: 0.15rem 0.55rem;
  font-size: 0.72rem;
  font-weight: 600;
  border-radius: 999px;
  color: var(--text);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--border);
}

/* Result-tile stats — single horizontal line, comfortable gap, values are
 * self-describing so we don't need uppercase labels. Wraps when the row
 * is narrow, but stays compact on the common widths. */
.card-stats,
.row-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.9rem;
  font-size: 0.76rem;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  line-height: 1.3;
}
.card-stats > span,
.row-stats > span {
  white-space: nowrap;
}
.card-stats .stat-runtime[hidden],
.row-stats .stat-runtime[hidden] { display: none; }
.stat-climb { color: var(--good); font-weight: 600; }

/* ---------- List view rows ---------- */

.row {
  display: grid;
  /* Layout: poster · text (1fr, fills available width so stats line out
     horizontally) · curve (240px, right of the row) · watch (36px, far
     right edge). With no gray sparkline backdrop, the empty space inside
     row-main between text and curve just reads as row surface — no
     visible padding gap. */
  grid-template-columns: 56px 1fr 240px 36px;
  gap: 1rem;
  align-items: center;
  padding: 0.7rem 0.95rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease), transform 0.2s var(--ease);
  position: relative;
}
.row:hover {
  border-color: var(--border-strong);
  background: var(--surface-2);
}
.row:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.row.is-watched { border-color: rgba(52, 211, 158, 0.4); }
.row.is-watched .row-poster img { opacity: 0.55; }

.row-poster {
  width: 56px;
  aspect-ratio: 2 / 3;
  border-radius: var(--radius-sm);
  overflow: hidden;
  position: relative;
  background: var(--surface-2);
}
.row-poster img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}

.row-main {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
}
.row-head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: baseline;
}
.row-title {
  font-size: 1rem;
  font-weight: 600;
  margin: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.row-season, .row-year {
  font-size: 0.78rem;
  color: var(--muted);
}
.row-shapes { display: flex; gap: 0.3rem; flex-wrap: wrap; }
/* .row-stats styled together with .card-stats above as one stats grid. */
.row-curve {
  display: block;
  width: 100%;
  height: 56px;
  /* No gray rectangle backdrop — the sparkline floats directly on the
     row's surface. Removing the box also removes the "gray padding"
     perception, since there's no container that can look incompletely
     filled when the trend line happens to be high or low at the edges. */
  background: transparent;
  border-radius: 0;
  overflow: visible;
}
/* Slightly thicker stroke + brighter area fill scoped to the list-view
 * row sparkline, since it now sits on the row surface (darker than the
 * old --surface-2 box) and benefits from a touch more presence. */
.row-curve .curve-line { stroke-width: 2.4; }
.row-curve .curve-area { fill: rgba(245, 197, 24, 0.32); }
/* Stay in the grid cell — must override the base + :hover absolute
   positioning that .watch-toggle sets for the card corner overlay. */
.row-watch,
.row-watch:hover {
  position: static;
  top: auto;
  right: auto;
  width: 2rem;
  height: 2rem;
}

@media (max-width: 760px) {
  /* Stack the row into two rows so the season-trend curve — the whole
     point of the app — stays visible on mobile instead of being dropped
     for layout space. Top row: poster + title block + watch toggle.
     Bottom row: full-width curve. */
  .row {
    grid-template-columns: 48px 1fr 36px;
    grid-template-areas:
      "poster main   watch"
      "curve  curve  curve";
    row-gap: 0.5rem;
  }
  .row-poster { grid-area: poster; }
  .row-main   { grid-area: main; }
  .row-watch  { grid-area: watch; }
  .row-curve {
    grid-area: curve;
    display: block;
    height: 44px;
    width: 100%;
    /* Reset the desktop edge-bleed — on mobile the curve spans the full
       width of the row's second grid row already, so the negative margin
       would just push it under the row's left border. */
    margin-left: 0;
  }
}

/* ---------- Pagination (prev / numbers / next) ---------- */

.pager {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.25rem;
  margin: 1.25rem 0 0;
  padding: 0.25rem 0;
}
.pager[hidden] { display: none; }
/* Top pager: small, quiet — sits between the meta line and the results
 * grid. The bottom pager keeps the larger feel since it's the natural
 * landing spot after scrolling through results. */
.pager-top {
  margin: 0.25rem 0 0.85rem;
  padding: 0;
}

.pager .page-btn,
.pager .page-btn:hover {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 0.55rem;
  background: transparent;
  color: var(--muted) !important;
  border: 1px solid transparent;
  border-radius: 8px;
  font: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  box-shadow: none !important;
  transition: background 0.18s var(--ease), border-color 0.18s var(--ease), color 0.18s var(--ease);
}
.pager .page-btn:hover {
  background: rgba(255, 255, 255, 0.06);
  border-color: transparent;
  color: var(--text) !important;
}
.pager .page-btn:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.pager .page-btn[aria-current="page"],
.pager .page-btn[aria-current="page"]:hover {
  background: rgba(245, 197, 24, 0.14);
  color: var(--accent) !important;
  border-color: rgba(245, 197, 24, 0.28);
  font-weight: 700;
}
.pager .page-btn:disabled,
.pager .page-btn[aria-disabled="true"] {
  opacity: 0.3;
  cursor: not-allowed;
  color: var(--muted) !important;
}
.pager .page-ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5rem;
  height: 32px;
  color: var(--muted-2);
  user-select: none;
  font-size: 0.82rem;
}
/* Compact even further on the top pager so it never crowds the results. */
.pager-top .page-btn { min-width: 28px; height: 28px; font-size: 0.78rem; padding: 0 0.4rem; }
.pager-top .page-ellipsis { min-width: 1.25rem; height: 28px; font-size: 0.78rem; }

/* ---------- Empty + error ---------- */

.empty {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--muted);
  padding: 4rem 1.5rem;
  background:
    radial-gradient(ellipse 80% 60% at 50% 0%, rgba(245, 197, 24, 0.04), transparent 70%),
    var(--surface);
  border: 1px dashed var(--border-strong);
  border-radius: 14px;
  font-size: 0.95rem;
  line-height: 1.5;
}
.empty p { margin: 0.35rem 0; }
.empty p:first-child { color: var(--text); font-size: 1.05rem; font-weight: 500; }
.empty code {
  background: var(--surface-2);
  padding: 0.1rem 0.4rem;
  border-radius: 4px;
  font-size: 0.85em;
}
.empty pre {
  background: var(--surface-2);
  padding: 0.75rem;
  border-radius: var(--radius-sm);
  overflow-x: auto;
  text-align: left;
  display: inline-block;
  margin: 0.5rem 0;
}

/* ---------- Skeleton ---------- */

.skeleton { animation: skel-pulse 1.4s ease-in-out infinite; }
.skeleton .skeleton-block {
  background-image: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 50%, var(--surface-2) 75%);
  background-size: 200% 100%;
  animation: skel-shimmer 1.4s linear infinite;
  width: 100%;
  height: 100%;
  border-radius: var(--radius-sm);
}
.skeleton .sk-curve { height: 70px; margin: 0.5rem 0; }
.skeleton .skeleton-line {
  height: 14px;
  border-radius: 4px;
  margin: 0.4rem 0;
  background-image: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 50%, var(--surface-2) 75%);
  background-size: 200% 100%;
  animation: skel-shimmer 1.4s linear infinite;
}
.skeleton .w-40 { width: 40%; }
.skeleton .w-70 { width: 70%; }
.skeleton .w-90 { width: 90%; }

@keyframes skel-pulse { 0%, 100% { opacity: 0.85; } 50% { opacity: 1; } }
@keyframes skel-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ---------- Modal ---------- */

.modal {
  position: fixed;
  inset: 0;
  z-index: 11000;
  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);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.modal-panel {
  position: relative;
  /* Brighter surface than the page bg so the panel reads as an elevated
     content layer rather than the same dark sheet with a thin outline.
     Stronger top-edge gradient + a more present border + a wider shadow
     give it visual lift away from the page. */
  background:
    radial-gradient(ellipse 80% 50% at 50% 0%, rgba(245, 197, 24, 0.07), transparent 60%),
    linear-gradient(180deg, #1a1f2c, #14182265 40%, #0e1219 100%),
    var(--surface);
  border: 1px solid rgba(255, 255, 255, 0.085);
  border-radius: 18px;
  max-width: 780px;
  width: 100%;
  /* 100dvh fixes iOS Safari over-counting the URL bar height. The vh
     line is a fallback for older browsers that don't know dvh. */
  max-height: calc(100vh - 2rem);
  max-height: calc(100dvh - 2rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1.9rem 1.9rem 1.6rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  box-shadow:
    0 24px 60px rgba(0, 0, 0, 0.55),
    0 4px 14px rgba(0, 0, 0, 0.45),
    0 0 0 1px rgba(255, 255, 255, 0.03) inset;
}
.modal-panel::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 18px;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.04), transparent 25%);
}

.modal-close {
  align-self: flex-end;
  margin-bottom: -1.5rem;  /* sit on top of header */
  position: relative;
  z-index: 2;
}

/* Roll-again is anchored directly above the poster — same width, slim
   height, square-ish corners — so it reads as part of the poster card
   rather than a floating CTA. The shared --modal-poster-w token keeps
   it locked to the poster on every breakpoint. */
.modal-panel { --modal-poster-w: 120px; }
.modal-reroll {
  position: absolute;
  top: 1.75rem;            /* matches .modal-panel padding */
  left: 1.75rem;           /* matches .modal-panel padding */
  width: var(--modal-poster-w);
  height: 30px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0 0.55rem;
  border: 1px solid rgba(245, 197, 24, 0.55);
  border-radius: 8px;
  background: linear-gradient(180deg, var(--accent) 0%, #d8a912 100%);
  color: var(--accent-ink) !important;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.02em;
  cursor: pointer;
  box-shadow:
    0 4px 14px rgba(245, 197, 24, 0.22),
    0 0 0 1px rgba(0, 0, 0, 0.18) inset !important;
  transition: filter 0.18s var(--ease), transform 0.08s var(--ease), box-shadow 0.18s var(--ease);
}
.modal-reroll:hover {
  filter: brightness(1.06);
  box-shadow:
    0 6px 18px rgba(245, 197, 24, 0.32),
    0 0 0 1px rgba(0, 0, 0, 0.18) inset !important;
}
.modal-reroll:active { transform: translateY(1px); }
.modal-reroll:focus-visible {
  outline: 2px solid #fff8d2;
  outline-offset: 2px;
}
.modal-reroll[hidden] { display: none !important; }

/* When Roll-again is visible (surprise pick), shift the modal header
   down by the button's height + a small breathing gap so the poster
   sits flush beneath it. Sibling combinator works because the reroll
   button precedes .modal-header in DOM order. */
.modal-reroll:not([hidden]) ~ .modal-header {
  margin-top: calc(30px - 0.4rem);
}

.modal-header {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}

.modal-poster {
  width: 120px;
  aspect-ratio: 2 / 3;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  position: relative;
  overflow: hidden;
  flex-shrink: 0;
}
.modal-poster img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}

.modal-heading {
  flex: 1 1 240px;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 0;
}
.modal-heading h2 {
  font-size: 1.55rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
}
.modal-subtitle {
  margin: 0;
  color: var(--muted);
  font-size: 0.92rem;
  letter-spacing: 0.005em;
}
.modal-shapes { display: flex; gap: 0.35rem; flex-wrap: wrap; margin-top: 0.15rem; }
.modal-shapes:empty { display: none; }
.modal-stats {
  margin: 0;
  color: var(--muted);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.005em;
}

.modal-overview {
  margin: 0;
  color: var(--text);
  font-size: 0.95rem;
  line-height: 1.55;
  opacity: 0.92;
}
.modal-overview:empty { display: none; }

.modal-section {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--muted);
  font-weight: 600;
  margin: 0.2rem 0 -0.3rem;
}


.modal-episodes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.35rem;
}
.modal-episodes li {
  display: grid;
  grid-template-columns: 3rem 1fr auto;
  gap: 0.75rem;
  align-items: center;
  padding: 0.55rem 0.85rem;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-variant-numeric: tabular-nums;
  font-size: 0.9rem;
}
.modal-episodes .ep-number {
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.modal-episodes .ep-name {
  color: var(--text);
  font-weight: 500;
  font-size: 0.92rem;
  letter-spacing: -0.005em;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* When the build pipeline didn't include episode titles, hide the
   empty slot entirely so the layout collapses to ep# | rating cleanly. */
.modal-episodes .ep-name:empty { display: none; }
.modal-episodes .ep-meta {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.1rem;
  line-height: 1.15;
}
.modal-episodes .ep-rating {
  color: var(--accent);
  font-weight: 700;
  font-size: 1rem;
}
.modal-episodes .ep-votes  {
  color: var(--muted-2);
  font-size: 0.74rem;
  white-space: nowrap;
}
.modal-episodes .ep-runtime {
  color: var(--muted-2);
  font-size: 0.74rem;
  white-space: nowrap;
}

.modal-actions {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  flex-wrap: wrap;
}
/* Top-of-modal action row: a thin divider underneath separates it from the
 * descriptive content (overview / episodes) that follows. Extra vertical
 * padding gives the buttons breathing room. */
.modal-actions-top {
  margin: 0.25rem 0 0.1rem;
  padding: 0.75rem 0 1.1rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
/* Hierarchy inside .modal-actions: each modal's primary action (watch
 * on season-modal, compare on show-modal) gets an accent surface so it
 * reads as the obvious primary button. Secondary buttons stay ghost.
 * IMDb anchor sits flush-right via margin-left:auto. */
.modal-actions .watch-btn,
.modal-actions .compare-btn {
  background: var(--accent-soft);
  border: 1px solid var(--accent-strong);
  color: var(--accent) !important;
  font-weight: 700;
}
.modal-actions .watch-btn:hover,
.modal-actions .compare-btn:hover {
  background: rgba(245, 197, 24, 0.18);
  border-color: rgba(245, 197, 24, 0.5);
}
/* "Already added" state — green to signal the success-of-state, same
 * pattern the watch button uses when a season is marked watched. */
.modal-actions .watch-btn.is-watched,
.modal-actions .compare-btn.is-in-compare {
  background: rgba(74, 222, 128, 0.16);
  border-color: rgba(74, 222, 128, 0.45);
  color: var(--good) !important;
}
.modal-imdb { margin-left: auto; }

@media (prefers-reduced-motion: reduce) {
  .skeleton, .skeleton .skeleton-block, .skeleton .skeleton-line {
    animation: none;
  }
  .card, .row { transition: none; }
  /* The mobile drawer's slide-up and backdrop fade-in can feel abrupt
     for motion-sensitive users — disable both and just show/hide. */
  .advanced-backdrop,
  details.advanced[open] { animation: none; }
}

/* ---------- Content-width alignment guard ----------
   Every top-level block under <main class="page"> — the unified toolbar,
   the expanded More-filters panel, the stats bar, the results count, and
   the list/grid of results — has to share the same horizontal box so the
   left/right border edges stack vertically. Without this, intrinsic
   sizing from a <select>'s longest option, a long row title, or the
   advanced-panel's grid can grow a single block past .page's content
   area and the page reads as misaligned.

   The fix has three parts:
   1. Lock each block to width:100% inside .page's content box with
      box-sizing:border-box so border+padding live INSIDE the width.
   2. Set min-width:0 so flex/grid intrinsic minimums don't expand the
      box (default min-width:auto would let a wide <select> push a track
      out, even with minmax(0, 1fr) on the column).
   3. Belt-and-braces on the advanced-panel form controls themselves —
      their label parents already have min-width:0, but locking the
      input/select to min-width:0 guarantees they can't drag the 4-up
      grid wider than its container on any browser. */
.filter-row.primary,
.label-filters,
.advanced,
.advanced[open],
.stats-bar,
.meta,
.results-grid,
.row {
  box-sizing: border-box;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  margin-left: 0;
  margin-right: 0;
}

.advanced .filter-row input,
.advanced .filter-row select {
  min-width: 0;
}

/* ============================================================================
   Mobile redesign — phones-first refinements that make the app feel
   intentional on a small screen, not a squeezed desktop layout.

   Targeted breakpoints:
     - 760px — large phones / small tablets in portrait
     - 600px — phone portrait (the main mobile experience)
     - 430px — small phones (iPhone SE / mini class)

   Anti-overflow guarantees:
   - the page never scrolls horizontally
   - long titles, chip labels, and poster captions wrap or ellipsis
   - the shape-chip strip wraps instead of forcing a horizontal scroll
   ========================================================================= */

/* No horizontal scroll, ever — long unbreakable text inside a control
   should reflow or ellipsis instead of pushing the viewport wide. */
html, body { overflow-x: hidden; }

/* Backdrop element for the mobile "advanced filters" drawer. Inserted
   into <body> by app.js; only visible while the drawer is open on a
   phone-sized viewport. Sits above the site header (z 10001) so the
   whole screen dims behind the drawer panel (z 10500). */
.advanced-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 10400;
  background: rgba(4, 6, 12, 0.62);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  animation: backdrop-fade-in 0.18s var(--ease);
}
body.advanced-drawer-open .advanced-backdrop { display: block; }

/* Body scroll-lock — iOS-safe. The `position: fixed` + width preserve the
   visual position while preventing the page from scrolling under the
   drawer. JS captures and restores scroll position; the top offset is
   set as a CSS custom property at the moment the drawer opens. */
body.advanced-drawer-open {
  position: fixed;
  top: var(--scroll-lock-y, 0);
  left: 0;
  right: 0;
  width: 100%;
  overflow: hidden;
}

@keyframes backdrop-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes drawer-slide-up {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}


/* ----------------------------------------------------------------------------
   ≤ 760px — large phones and small tablets
   ------------------------------------------------------------------------- */

@media (max-width: 760px) {
  /* Side spacing is handled by .page's max-width: calc(100% - 6rem) already,
     same as the footer .inner. Only the bottom padding gets compacted here. */
  .page { padding: 0 0 1.5rem; }

  /* Compact hero — claim less vertical space so results show above fold. */
  .hero { padding: 1.5rem 0 0.35rem; }
  .hero h1 { font-size: clamp(1.75rem, 8vw, 2.4rem); }
  .tagline { font-size: 0.92rem; max-width: 100%; line-height: 1.4; }

  /* Shape chips: tighter strip, but still readable and tappable. */
  .shapes {
    padding: 0.75rem 0 0.25rem;
    gap: 0.4rem 0.4rem;
  }
  .shape-chip,
  .shape-chip:hover {
    height: 36px;
    padding: 0 0.8rem;
    font-size: 0.8rem;
  }
  .shape-count { height: 18px; font-size: 0.68rem; }

  /* Filters block: extra breathing room between sections so the toolbar,
     label pills, and shape strip don't all crowd against each other. */
  .filters { padding: 0.75rem 0 0.25rem; }

  /* Primary toolbar — turn into a flexible two-row layout:
       row 1: search (full width)
       row 2: view-toggle + surprise (side by side)
     Inputs sized for thumb taps. */
  .filter-row.primary {
    --ctrl-h: 44px;
    padding: 4px 4px 4px;
    gap: 0.35rem;
    border-radius: 12px;
    align-items: stretch;
  }
  .filter-row.primary .search { flex: 1 1 100% !important; order: 1; }
  .filter-row.primary .search input {
    font-size: 16px;          /* prevents iOS auto-zoom on focus */
    padding-left: 2.4rem;
  }
  .filter-row.primary .view-toggle {
    order: 2;
    flex: 0 0 auto;
    align-self: stretch;
  }
  .filter-row.primary .view-btn { width: 2.6rem; font-size: 1rem; }
  .filter-row.primary .surprise {
    order: 3;
    flex: 1 1 auto;
    font-size: 0.88rem;
    padding: 0 1rem;
  }

  /* Quick label filters — keep glass surface but stack each group on its
     own line so the captions never collide with their pills. */
  .label-filters {
    flex-direction: column;
    align-items: stretch;
    gap: 0.15rem;
    padding: 0.55rem 0.65rem;
    margin-bottom: 0.75rem;
  }
  .label-group {
    flex-wrap: wrap;
    gap: 0.25rem 0.35rem;
    padding: 0.2rem 0;
  }
  .label-group + .label-group {
    border-top: 1px solid rgba(255, 255, 255, 0.045);
    padding-top: 0.45rem;
    margin-top: 0.1rem;
  }
  .label-group-name {
    flex: 0 0 100%;
    margin: 0 0 0.15rem;
    font-size: 0.6rem;
  }
  .label-chip {
    height: 36px;
    padding: 0 0.85rem;
    font-size: 0.82rem;
    border-radius: 8px;
  }
  .label-chip + .label-chip { margin-left: 0; }

  /* List rows already shed the curve here — also bump tap height. */
  .row-watch { width: 2.25rem; height: 2.25rem; }

  /* Stats bar: shorter font + larger gap-rhythm. */
  .stats-bar {
    padding: 0.65rem 0.9rem;
    font-size: 0.8rem;
    gap: 0.5rem 1.25rem;
  }
  .stats-bar .progress { flex-basis: 100%; }

  /* Pager — tighter, taller tap targets. */
  .pager { gap: 0.3rem; }
  .pager .page-btn {
    padding: 0 0.55rem;
    min-width: 40px;
    height: 40px;
    font-size: 0.85rem;
  }

  /* Modal becomes a bottom sheet on phones — full width, rounded only
     at the top, anchored to the bottom of the viewport with safe-area
     padding so the action buttons don't sit under the home indicator. */
  .modal {
    padding: 0;
    align-items: flex-end;
  }
  .modal-panel {
    width: 100%;
    max-width: 100%;
    max-height: calc(100vh - 1rem);
    max-height: calc(100dvh - 1rem);
    border-radius: 18px 18px 0 0;
    border-bottom: 0;
    padding: 1rem 1rem 1.1rem;
    padding-bottom: max(1rem, env(safe-area-inset-bottom));
    gap: 0.85rem;
    --modal-poster-w: 92px;
  }
  .modal-panel::before { border-radius: 18px 18px 0 0; }
  .modal-poster { width: var(--modal-poster-w); }
  .modal-close {
    margin-bottom: -1.5rem;
    /* Float the close button over the header — it stays reachable at
       the top of the sheet without consuming a full row of padding. */
  }
  .modal-reroll {
    top: 1rem;
    left: 1rem;
    height: 28px;
    font-size: 0.72rem;
  }
  .modal-reroll:not([hidden]) ~ .modal-header {
    margin-top: calc(28px - 0.4rem);
  }
  .modal-header { gap: 0.85rem; }
  .modal-heading h2 { font-size: 1.35rem; line-height: 1.2; }
  .modal-curve { height: 150px; padding: 0.4rem; }
  .modal-episodes li {
    grid-template-columns: 2.6rem 1fr auto;
    gap: 0.6rem;
    padding: 0.55rem 0.7rem;
    font-size: 0.88rem;
  }

  /* Action buttons stack to be each full-width tappable bars. */
  .modal-actions {
    flex-direction: column;
    align-items: stretch;
    gap: 0.55rem;
  }
  .modal-actions .btn {
    width: 100%;
    height: 44px;
  }
  .modal-imdb { margin-left: 0; }
}

/* ----------------------------------------------------------------------------
   ≤ 600px — phone portrait (the main mobile experience)

   Major changes here:
   - Result cards in GRID view flip to full-width horizontal cards
   - The "More filters" details element becomes a bottom-sheet drawer
   - Tap targets uniformly meet the 40-44px guidance
   ------------------------------------------------------------------------- */

@media (max-width: 600px) {

  /* --- Cards in grid view: full-width horizontal layout ---------------- */

  .results-grid {
    grid-template-columns: 1fr;
    gap: 0.7rem;
  }
  .results-grid.list-view { gap: 0.55rem; }

  .card {
    flex-direction: row;
    align-items: stretch;
    min-height: 156px;
  }
  .card-poster {
    flex: 0 0 104px;
    width: 104px;
    aspect-ratio: 2 / 3;
  }
  .card-body {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0.7rem 0.85rem 0.8rem;
    gap: 0.45rem;
  }
  .card-head { gap: 0.4rem; }
  .card-title {
    font-size: 0.98rem;
    -webkit-line-clamp: 2;
  }
  .card-season { font-size: 0.74rem; }
  .card-meta { font-size: 0.72rem; gap: 0.45rem; }
  .card-shapes { gap: 0.25rem; }
  .card .curve { height: 48px; }
  .card-stats {
    gap: 0.55rem;
    font-size: 0.72rem;
  }
  /* Watch toggle is roomier so it's easier to thumb-tap on the corner. */
  .card .watch-toggle {
    width: 2.25rem;
    height: 2.25rem;
    top: 0.4rem;
    right: 0.4rem;
  }
  /* Mobile cards go horizontal (poster | body), so the desktop edge-bleed
     trick would push the curve into the poster on the left. Match the
     mobile card-body padding (0.85rem) on the right only, and leave the
     left edge flush with the body's left padding so the line still feels
     edge-anchored on the side it can be. */
  .card .curve {
    margin-left: 0;
    margin-right: -0.85rem;
    width: calc(100% + 0.85rem);
  }

  /* List view rows — already tight; just give the watch button a
     bigger circular tap target. */
  .row {
    grid-template-columns: 56px 1fr 40px;
    column-gap: 0.85rem;
    row-gap: 0.55rem;
    padding: 0.7rem 0.85rem;
  }
  .row-curve { height: 48px; }
  .row-watch {
    width: 2.5rem;
    height: 2.5rem;
  }

  /* --- Shape chips: keep the descriptions hidden (already), but pad the
       tap area a touch more so they meet ~38-40px. -------------------- */
  .shape-chip,
  .shape-chip:hover {
    height: 38px;
    padding: 0 0.9rem;
    font-size: 0.82rem;
  }

  /* --- Advanced "More filters" — becomes a slide-up bottom sheet ----- */

  /* The trigger button: when CLOSED, render as a full-width pill so it
     reads as a clear action, not a tiny inline link. */
  .advanced summary {
    width: 100%;
    height: 44px;
    margin: 0;
    padding: 0 1rem;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    color: var(--text);
    font-size: 0.78rem;
    letter-spacing: 0.1em;
    justify-content: center;
  }
  .advanced summary:hover { background: rgba(255, 255, 255, 0.06); }

  /* When OPEN: the entire <details> becomes a fixed bottom sheet. The
     summary stays at the top of the sheet (sticky) and acts as the
     close handle ("×" replaces "+" via the existing transform). */
  details.advanced[open] {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    top: auto;
    width: 100%;
    /* 100dvh accounts for the iOS URL bar — 100vh over-counts and the
       sheet would extend below the visible viewport. */
    max-height: 85vh;
    max-height: 85dvh;
    z-index: 10500;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    background:
      linear-gradient(180deg, #181c26 0%, #12151d 100%);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-bottom: 0;
    border-radius: 18px 18px 0 0;
    box-shadow:
      0 -20px 60px rgba(0, 0, 0, 0.55),
      0 -2px 8px rgba(0, 0, 0, 0.35);
    animation: drawer-slide-up 0.25s var(--ease);
  }
  details.advanced[open] > summary {
    position: sticky;
    top: 0;
    z-index: 2;
    width: 100%;
    height: 52px;
    margin: 0;
    padding: 0 1.1rem;
    background: rgba(18, 21, 29, 0.92);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    border: 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 18px 18px 0 0;
    color: var(--text);
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    justify-content: space-between;
  }
  details.advanced[open] > summary::before { order: 2; font-size: 1.4rem; }
  details.advanced[open] > summary:hover { background: rgba(24, 28, 38, 0.95); }

  /* A subtle drag-handle bar at the very top of the sheet — signals
     "this is a sheet you can dismiss," even though we close via tap. */
  details.advanced[open] > summary::after {
    content: '';
    position: absolute;
    top: 6px;
    left: 50%;
    transform: translateX(-50%);
    width: 36px;
    height: 4px;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.15);
  }

  /* Strip the open-panel chrome the desktop layout adds — the fixed
     sheet provides its own background, border, and rounding. */
  .advanced[open] {
    background: transparent;
    border: 0;
    box-shadow: none;
  }
  .advanced[open] .filter-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.7rem 0.7rem;
    padding: 0.9rem 1.1rem 0;
  }
  .advanced[open] .filter-row input,
  .advanced[open] .filter-row select {
    height: 44px;
    font-size: 16px;          /* prevents iOS zoom on focus */
    border-radius: 9px;
  }
  .genre-row {
    padding: 1rem 1.1rem;
    margin-top: 0.5rem;
    gap: 0.4rem 0.4rem;
  }
  .genre-row::before { font-size: 0.62rem; margin-bottom: 0.3rem; }
  .genre-chip,
  .genre-chip:hover {
    height: 38px;
    padding: 0 0.95rem;
    font-size: 0.8rem;
  }
  .filter-actions {
    margin: 0;
    padding: 0.85rem 1.1rem 1.1rem;
    padding-bottom: max(0.85rem, env(safe-area-inset-bottom));
    border-top: 1px solid rgba(255, 255, 255, 0.075);
    justify-content: stretch;
  }
  .filter-actions .btn,
  .filter-actions .btn:hover {
    width: 100%;
    height: 40px;
    font-size: 0.75rem;
    color: var(--accent) !important;
  }

  /* --- Search dropdown: aligned to the toolbar but full-bleed inside
       the screen edges with a slightly taller row. ------------------ */
  .search-suggestions {
    max-height: 60vh;
    border-radius: 12px;
  }
  .search-suggestion {
    min-height: 48px;
    padding: 0.55rem 0.7rem;
    font-size: 0.92rem;
  }
  .search-suggestion .ss-poster {
    flex: 0 0 36px;
    width: 36px;
    height: 54px;
  }
}

/* ----------------------------------------------------------------------------
   ≤ 430px — small phones (iPhone SE / mini / Pixel 4a)
   ------------------------------------------------------------------------- */

@media (max-width: 430px) {
  /* Tighten the side gutter on the smallest phones to match the footer's
     <480px breakpoint (max-width: calc(100% - 3rem)). */
  .page { padding: 0 0 1.25rem; max-width: calc(100% - 3rem); }

  .hero { padding: 1.1rem 0 0.2rem; }
  .hero h1 { font-size: clamp(1.5rem, 8vw, 1.95rem); }
  .tagline { font-size: 0.85rem; }

  /* Narrower cards: poster shrinks just enough that the title can fit
     two lines of ~22 characters without ellipsising mid-word. */
  .card { min-height: 140px; }
  .card-poster { flex: 0 0 92px; width: 92px; }
  .card-body { padding: 0.6rem 0.7rem 0.7rem; gap: 0.4rem; }
  .card-title { font-size: 0.92rem; }
  .card .curve { height: 42px; }
  /* Votes column is the lowest-value stat in the trio; drop it on the
     tightest screens so climb + avg get full room. */
  .card .stat-votes { display: none; }

  /* List view: drop the season label inline (year stays). */
  .row-poster { width: 48px; }
  .row { grid-template-columns: 48px 1fr 40px; }
  .row-curve { height: 40px; }

  /* Drawer rows go single-column at this width so the input labels and
     values both have full breathing room. */
  .advanced[open] .filter-row {
    grid-template-columns: 1fr;
    gap: 0.55rem;
  }

  /* Modal sheet: slightly taller and tighter so episodes show in full. */
  .modal-panel {
    --modal-poster-w: 84px;
    padding: 0.9rem 0.85rem 1rem;
    padding-bottom: max(0.85rem, env(safe-area-inset-bottom));
  }
  .modal-heading h2 { font-size: 1.2rem; }
  .modal-subtitle, .modal-stats { font-size: 0.8rem; }
  .modal-curve { height: 130px; }
  .modal-episodes li {
    grid-template-columns: 2.4rem 1fr auto;
    padding: 0.5rem 0.6rem;
    font-size: 0.85rem;
  }

  /* Pager: drop ellipsis tokens and lean on prev/next for navigation. */
  .pager .page-ellipsis { display: none; }
  .pager .page-btn { min-width: 38px; height: 38px; font-size: 0.8rem; padding: 0 0.45rem; }

  /* Stats bar collapses to a stacked, scannable line list. */
  .stats-bar {
    gap: 0.4rem 0;
    flex-direction: column;
    align-items: stretch;
  }
  .stats-bar > span { justify-content: space-between; }
}

/* ---------- Tweak shared chrome (#header, #footer, #menu) for our theme ----
   main.css already styles these dark — these tweaks just make the inline
   chrome blend with the rest of the IMDb-yellow accent palette. */

#header { background: #181818; }
#header > nav > a { color: rgba(255, 255, 255, 0.85); }
#header > nav > a:hover { color: var(--accent); text-decoration: none; }

#footer a { color: var(--accent); }
#footer a:hover { color: var(--accent); text-decoration: underline; }

/* ---------- Footer "What's new" chip + changelog popover ---------- */

.footer-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.5rem;
}
.footer-meta-text { color: var(--muted-2); }
.footer-meta-sep { color: var(--border-strong); }

/* Footer "What's new" pill. main.css applies height/line-height/color !important
 * to every button on the site, so most properties here need !important to win. */
.whats-new-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: auto !important;
  line-height: 1.2 !important;
  padding: 0.3rem 0.7rem 0.3rem 0.75rem !important;
  border-radius: 999px;
  font-size: 0.78rem !important;
  font-weight: 600;
  color: var(--text) !important;
  background: var(--surface-2);
  border: 1px solid var(--accent-strong);
  box-shadow: none !important;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.05s ease;
}
.whats-new-chip:hover {
  background: rgba(245, 197, 24, 0.14);
  border-color: var(--accent);
  color: var(--text) !important;
}
.whats-new-chip:active { transform: translateY(1px); }
.whats-new-chip:focus-visible {
  outline: none;
  box-shadow: var(--accent-glow) !important;
}
.whats-new-chip-counts { color: var(--muted); font-weight: 500; }
.whats-new-chip-added { color: var(--good); font-weight: 700; }
.whats-new-chip-removed { color: var(--danger); font-weight: 700; }
.whats-new-chip-cta {
  color: var(--accent);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.68rem;
  padding-left: 0.55rem;
  border-left: 1px solid var(--border-strong);
}
.whats-new-chip-caret { color: var(--accent); font-size: 0.7rem; }

/* Modal panel — slightly tighter than the season modal because it's a
 * read-only summary, no media or curve. */
.changelog-panel {
  max-width: 560px;
  gap: 1.1rem;
}
.changelog-header { display: flex; flex-direction: column; gap: 0.25rem; }
.changelog-header h2 { margin: 0; font-size: 1.35rem; }
.changelog-panel .modal-subtitle { color: var(--muted); font-size: 0.85rem; }

.changelog-section { display: flex; flex-direction: column; gap: 0.55rem; }
.changelog-section .modal-section {
  margin: 0;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
  font-weight: 600;
}

/* "At a glance" totals: render as a horizontal stat strip with separators. */
#changelogTotals {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1rem;
  padding: 0.65rem 0.85rem;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.changelog-stat {
  font-size: 0.88rem;
  color: var(--muted);
}
.changelog-stat strong { color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; }

.changelog-shape-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}
.changelog-shape-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.18rem 0.55rem;
  border-radius: 999px;
  font-size: 0.74rem;
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text);
}
.changelog-shape-pill.is-up {
  border-color: rgba(52, 211, 158, 0.35);
  background: var(--good-soft);
  color: var(--good);
}
.changelog-shape-pill.is-down {
  border-color: rgba(248, 113, 113, 0.32);
  background: rgba(248, 113, 113, 0.1);
  color: var(--danger);
}

/* Lists: a single softly-bordered card containing tight rows. Only the
 * Added list gets a max-height — Dropped + Swings are usually short. */
.changelog-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  overflow: hidden;
}
#changelogAddedList { max-height: 260px; overflow-y: auto; }
.changelog-list li {
  padding: 0;
  margin: 0;
  border-bottom: 1px solid var(--border);
}
.changelog-list li:last-child { border-bottom: 0; }
.changelog-list-muted li {
  padding: 0.5rem 0.85rem;
  font-size: 0.88rem;
  color: var(--muted);
}

/* Button rows inside lists. main.css's site-wide button defaults — 3.25rem
 * height, gray inset border, gray !important text — would otherwise paint
 * each row as a tall hollow button. Override all of them. */
.changelog-item-link {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  height: auto !important;
  line-height: 1.35 !important;
  padding: 0.5rem 0.85rem !important;
  background: transparent !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  color: var(--text) !important;
  text-align: left;
  font: inherit;
  font-size: 0.88rem !important;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.changelog-item-link:hover { background: var(--surface-3) !important; color: var(--text) !important; }
.changelog-item-link:focus-visible {
  outline: none;
  background: var(--surface-3) !important;
  box-shadow: inset 2px 0 0 var(--accent) !important;
}

.changelog-swing-delta {
  font-variant-numeric: tabular-nums;
  font-size: 0.82rem;
  color: var(--muted);
  white-space: nowrap;
}
.changelog-swing-delta.is-up { color: var(--good); }
.changelog-swing-delta.is-down { color: var(--danger); }

@media (max-width: 600px) {
  .changelog-panel {
    padding: 1.5rem 1.25rem 1.25rem;
    gap: 0.9rem;
  }
  .changelog-header h2 { font-size: 1.15rem; }
  .changelog-stat { font-size: 0.82rem; }
  #changelogAddedList { max-height: 220px; }
  .whats-new-chip {
    padding: 0.25rem 0.6rem !important;
    font-size: 0.72rem !important;
    gap: 0.4rem;
  }
  .whats-new-chip-cta { padding-left: 0.4rem; font-size: 0.62rem; }
}
