/* The one stylesheet of the MovieRec static site. Copied by hand from the Flask app's stylesheets
   (static/css/base.css, cards.css, home.css, detail.css and lists.css) and trimmed to the markup
   of these pages: the same tokens, type, header, footer, cards and detail layout. Rules that
   only this site needs (the autocomplete list, the image frames, the remove button, loading
   spinner) use the same tokens. Keep the tokens in step with base.css.
   Mobile first: base rules are for phones, wider screens add min-width 600/900/1200px. */

/* --- Tokens --- */
/* The light theme is :root; the dark theme overrides the tokens that change below it. */
:root {
  /* Native controls and scrollbars follow the theme. */
  color-scheme: light;

  --color-bg: #FFFFFF;
  --color-surface: #FFFFFF;
  --color-subtle: #F4F4F4;
  --color-hairline: #E4E4E4;
  --color-hairline-strong: #CFCFCF;
  --color-control-border: #8A8A8F;
  --color-tag-bg: #F1F1F1;
  --color-tag-bg-hover: #E6E6E6;
  --color-hover-overlay: rgb(14 14 16 / 0.06);

  --color-ink: #0E0E10;
  --color-ink-hover: #2A2A2E;
  --color-text-muted: #5E5E66;
  --color-on-ink: #FFFFFF;

  /* The one accent, the logo's red: link hovers, the current page, the liked state, focus. */
  --color-accent: #D7261E;
  --color-accent-hover: #B51E17;
  --color-accent-soft: #FBEAE9;
  --color-rating: #B07A06;

  /* The header is dark in both themes, so only its background changes with the theme. */
  --color-header: #0E0E10;
  --color-header-text: #F4F4F5;
  --color-header-text-hover: #FFFFFF;
  --color-header-muted: #A0A0A8;
  --color-header-hover-overlay: rgb(255 255 255 / 0.06);
  --color-header-field: #1C1C1F;
  --color-header-field-border: #38383E;
  --color-header-field-border-hover: #56565D;
  --color-header-hairline: rgb(255 255 255 / 0.08);

  /* Discs that sit on a picture, not the page (the lists page's remove button), so they look
     the same in both themes. */
  --color-play-bg: rgb(14 14 16 / 0.82);
  --color-play-bg-hover: #0E0E10;
  --color-play-icon: #FFFFFF;

  --color-warning-border: rgb(245 158 11 / 0.45);
  --color-warning-bg: #FFFBEB;
  --color-warning-text: #B45309;
  --color-danger-border: rgb(220 38 38 / 0.3);
  --color-danger-bg: #FEF2F2;
  --color-danger-text: #991B1B;

  /* The arrow of selects in the muted text colour (%23 is "#"; a data URL cannot read a var). */
  --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%235E5E66' stroke-width='1.6'/%3E%3C/svg%3E");

  /* IBM Plex Sans for running text and controls, IBM Plex Sans Condensed for the logo and the
     display lines (page titles, empty-state messages). */
  --font-sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  --font-display: "IBM Plex Sans Condensed", "IBM Plex Sans", "Arial Narrow", sans-serif;

  --radius-sm: 6px;
  --radius-md: 8px;

  --duration-fast: 0.15s;
  --duration: 0.2s;
}

/* The dark theme applies when the system asks for dark and the visitor has not picked light, or
   when the visitor picked dark (theme.js sets data-theme on <html>). CSS cannot share one block
   between a media query and a selector, so the two blocks below are copies: keep them identical
   (tests/test_site_links.py checks). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --color-bg: #0F0F11;
    --color-surface: #17171A;
    --color-subtle: #1E1E22;
    --color-hairline: #2A2A2F;
    --color-hairline-strong: #3A3A40;
    --color-control-border: #6E6E76;
    --color-tag-bg: #232328;
    --color-tag-bg-hover: #2D2D33;
    --color-hover-overlay: rgb(255 255 255 / 0.08);
    --color-ink: #EDEDEF;
    --color-ink-hover: #D4D4D8;
    --color-text-muted: #A3A3AB;
    --color-on-ink: #0F0F11;
    --color-accent: #F2483D;
    --color-accent-hover: #FF6A5F;
    --color-accent-soft: #3A1A18;
    --color-rating: #E3A82B;
    --color-header: #0A0A0B;
    --color-warning-border: rgb(242 184 75 / 0.3);
    --color-warning-bg: #241B0B;
    --color-warning-text: #F2B84B;
    --color-danger-border: rgb(255 143 133 / 0.3);
    --color-danger-bg: #2A1213;
    --color-danger-text: #FF8F85;
    --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23A3A3AB' stroke-width='1.6'/%3E%3C/svg%3E");
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --color-bg: #0F0F11;
  --color-surface: #17171A;
  --color-subtle: #1E1E22;
  --color-hairline: #2A2A2F;
  --color-hairline-strong: #3A3A40;
  --color-control-border: #6E6E76;
  --color-tag-bg: #232328;
  --color-tag-bg-hover: #2D2D33;
  --color-hover-overlay: rgb(255 255 255 / 0.08);
  --color-ink: #EDEDEF;
  --color-ink-hover: #D4D4D8;
  --color-text-muted: #A3A3AB;
  --color-on-ink: #0F0F11;
  --color-accent: #F2483D;
  --color-accent-hover: #FF6A5F;
  --color-accent-soft: #3A1A18;
  --color-rating: #E3A82B;
  --color-header: #0A0A0B;
  --color-warning-border: rgb(242 184 75 / 0.3);
  --color-warning-bg: #241B0B;
  --color-warning-text: #F2B84B;
  --color-danger-border: rgb(255 143 133 / 0.3);
  --color-danger-bg: #2A1213;
  --color-danger-text: #FF8F85;
  --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23A3A3AB' stroke-width='1.6'/%3E%3C/svg%3E");
}

/* --- Reset --- */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

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

fieldset {
  border: 0;
  min-width: 0;
}

[role="list"] {
  list-style: none;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

/* A class that sets display (flex, grid) would otherwise show an element marked hidden. */
[hidden] {
  display: none !important;
}

button,
input,
select,
textarea {
  font: inherit;
}

/* --- Typography --- */
/* The column layout keeps the footer at the bottom of short pages. */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--color-ink);
  background-color: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* The text face loads 400/500/600, so headings and bold text use 600 and the browser never
   fakes a 700. The display lines set their own weight. */
h1,
h2,
h3 {
  font-weight: 600;
  line-height: 1.25;
}

strong,
b {
  font-weight: 600;
}

a {
  color: var(--color-accent);
  text-decoration: none;
  transition: color var(--duration-fast) ease;
}

a:hover {
  color: var(--color-accent-hover);
}

/* --- Focus --- */
:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* The accent is too dark to see on the black header. */
.header :focus-visible {
  outline-color: var(--color-header-text-hover);
}

.skip-link {
  position: absolute;
  top: 0;
  left: 1rem;
  z-index: 100;
  padding: 0.5rem 1rem;
  font-weight: 500;
  color: var(--color-ink);
  background-color: var(--color-surface);
  border: 1px solid var(--color-hairline);
  border-top: 0;
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  transform: translateY(-120%);
}

.skip-link:focus {
  transform: none;
}

/* <main> takes the focus after the skip link; it needs no ring. */
main:focus {
  outline: none;
}

@keyframes fade-in {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@keyframes spin {
  to {
    transform: rotate(1turn);
  }
}

/* --- Icons --- */
/* Font Awesome icons (render.js and the page headers): 1em high, as wide as the viewBox says,
   0.125em below the baseline. */
.icon {
  height: 1em;
  vertical-align: -0.125em;
  fill: currentColor;
}

/* --- Layout --- */
.container {
  width: 100%;
  max-width: 1240px;
  margin-inline: auto;
  padding-inline: 1rem;
}

@media (min-width: 600px) {
  .container {
    padding-inline: 1.5rem;
  }
}

@media (min-width: 900px) {
  .container {
    padding-inline: 2rem;
  }
}

/* --- Shared components --- */
.page {
  padding-block: 1.5rem 3rem;
}

@media (min-width: 900px) {
  .page {
    padding-block: 2.5rem 4rem;
  }
}

/* The one display line of a page, in the condensed face. */
.page-title {
  font-family: var(--font-display);
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--color-ink);
  overflow-wrap: break-word;
  text-wrap: balance;
}

@media (min-width: 900px) {
  .page-title {
    font-size: 2.5rem;
  }
}

.section-title {
  margin-bottom: 0.75rem;
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-ink);
  overflow-wrap: anywhere;
}

@media (min-width: 600px) {
  .section-title {
    font-size: 1.125rem;
  }
}

/* Buttons: 40px high. Primary actions are ink, not accent. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 2.5rem;
  padding: 0.375rem 1rem;
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.25;
  text-align: center;
  text-decoration: none;
  color: var(--color-ink);
  background-color: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background-color var(--duration-fast) ease,
    border-color var(--duration-fast) ease,
    color var(--duration-fast) ease;
}

.btn .icon {
  flex: none;
  font-size: 0.95em;
}

.btn-primary {
  color: var(--color-on-ink);
  background-color: var(--color-ink);
  border-color: var(--color-ink);
}

.btn-primary:hover {
  color: var(--color-on-ink);
  background-color: var(--color-ink-hover);
  border-color: var(--color-ink-hover);
}

.btn-secondary {
  color: var(--color-ink);
  background-color: var(--color-surface);
  border-color: var(--color-hairline-strong);
}

.btn-secondary:hover {
  color: var(--color-ink);
  background-color: var(--color-tag-bg);
}

/* Genre links (home and movie page) and genre toggles (home): flat tags that darken on hover. */
.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  list-style: none;
}

.tag {
  display: inline-block;
  padding: 0.25rem 0.625rem;
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.5;
  color: var(--color-ink);
  text-decoration: none;
  background-color: var(--color-tag-bg);
  border-radius: var(--radius-sm);
  transition: background-color var(--duration-fast) ease;
}

.tag:hover {
  color: var(--color-ink);
  background-color: var(--color-tag-bg-hover);
}

/* Facts in a row (year · runtime · ★ 8,2), separated by middle dots that screen readers skip. */
.meta-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  font-size: 0.9375rem;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  list-style: none;
}

.meta-line > * + *::before {
  content: "\00B7";
  content: "\00B7" / "";
  margin-inline: 0.5em;
  color: var(--color-text-muted);
}

/* "★ 8,2": the star in the rating colour, the number in ink. */
.rating {
  color: var(--color-ink);
  font-variant-numeric: tabular-nums;
}

.rating-star {
  color: var(--color-rating);
}

/* A plain box with a hairline border: search forms, empty states, the error box. */
.panel {
  padding: 1.25rem;
  background-color: var(--color-surface);
  border: 1px solid var(--color-hairline);
  border-radius: var(--radius-md);
}

@media (min-width: 600px) {
  .panel {
    padding: 1.5rem;
  }
}

/* Names (cast, director): ink text on a faint underline that turns accent on hover. */
.link {
  color: var(--color-ink);
  text-decoration: underline;
  text-decoration-color: var(--color-hairline-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  transition: text-decoration-color var(--duration-fast) ease, color var(--duration-fast) ease;
}

.link:hover {
  color: var(--color-ink);
  text-decoration-color: var(--color-accent);
}

/* Read by screen readers, not drawn. The header's nav label is only hidden on phones. */
.sr-only,
.nav-label {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --- Logo --- */
/* The wordmark: a red recording dot, "Movie" in Condensed Medium and "Rec" in Bold. Every
   length is in em, so it scales with the text around it and keeps its shape in a fallback face. */
.logo {
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

.logo-dot {
  display: inline-block;
  width: 0.55em;
  height: 0.55em;
  margin-right: 0.3em;
  vertical-align: middle;
  background-color: var(--color-accent);
  border-radius: 50%;
}

.logo-rec {
  font-family: var(--font-display);
  font-weight: 700;
}

/* --- Header --- */
/* Phones: the brand, an icon-only "Listelerim" and the theme button share the first row, the
   search takes the second (the home page hides it, its own forms are right below). From 600px
   the nav shows its label; from 900px everything fits on one row. */
.header {
  color-scheme: dark;
  padding-block: 0.75rem;
  color: var(--color-header-text);
  background-color: var(--color-header);
  border-bottom: 1px solid var(--color-header-hairline);
}

.header-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.625rem 1rem;
}

.header-brand {
  min-width: 0;
  margin-right: auto;
  color: inherit;
}

.header-brand:hover {
  color: var(--color-header-text-hover);
}

.site-title {
  display: flex;
  font-size: 1.375rem;
  line-height: 1;
}

.header-nav {
  flex: none;
}

.nav-link,
.theme-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-width: 2.75rem;
  height: 2.75rem;
  padding-inline: 0.625rem;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--color-header-muted);
  border-radius: var(--radius-sm);
  transition: color var(--duration-fast) ease, background-color var(--duration-fast) ease;
}

.nav-link:hover,
.theme-toggle:hover {
  color: var(--color-header-text-hover);
  background-color: var(--color-header-hover-overlay);
}

.theme-toggle {
  flex: none;
  background: none;
  border: 0;
  cursor: pointer;
}

/* theme.js always sets data-theme, so without it the script has not run and the button could
   not work. The icon shows the theme a click switches to. */
:root:not([data-theme]) .theme-toggle,
[data-theme="light"] .theme-sun,
[data-theme="dark"] .theme-moon {
  display: none;
}

.nav-link[aria-current="page"] {
  color: var(--color-header-text-hover);
}

.nav-link[aria-current="page"]::after {
  content: "";
  position: absolute;
  right: 0.625rem;
  bottom: 0.25rem;
  left: 0.625rem;
  height: 2px;
  background-color: var(--color-accent);
}

/* A dark field with the search button inside its right end. */
.header-search-form {
  position: relative;
  display: flex;
  flex: 1 1 100%;
}

.page-home .header-search-form {
  display: none;
}

.header-search-form .combo {
  flex: 1 1 auto;
  min-width: 0;
}

/* 16px text keeps iOS from zooming in when the field is focused. */
.header-search-form input[type="search"] {
  width: 100%;
  height: 2.5rem;
  padding: 0 2.75rem 0 0.875rem;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--color-header-text);
  background-color: var(--color-header-field);
  border: 1px solid var(--color-header-field-border);
  border-radius: var(--radius-sm);
  transition: border-color var(--duration-fast) ease;
}

.header-search-form input[type="search"]:hover,
.header-search-form input[type="search"]:focus {
  border-color: var(--color-header-field-border-hover);
}

.header-search-form input[type="search"]::placeholder {
  color: var(--color-header-muted);
  opacity: 1;
}

.header-search-form input[type="search"]::-webkit-search-cancel-button {
  cursor: pointer;
}

.header-search-form button[type="submit"] {
  position: absolute;
  top: 0;
  right: 0;
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  color: var(--color-header-muted);
  background: none;
  border: 0;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  cursor: pointer;
  transition: color var(--duration-fast) ease;
}

.header-search-form button[type="submit"]:hover {
  color: var(--color-header-text-hover);
}

@media (min-width: 600px) {
  .site-title {
    font-size: 1.5rem;
  }

  .nav-link,
  .theme-toggle {
    min-width: 2.5rem;
    height: 2.5rem;
  }

  .nav-label {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip-path: none;
  }
}

@media (min-width: 900px) {
  .header {
    padding-block: 0.875rem;
  }

  .header-bar {
    flex-wrap: nowrap;
    gap: 1rem;
  }

  .header-search-form,
  .page-home .header-search-form {
    display: flex;
    flex: 0 1 20rem;
  }

  .header-search-form input[type="search"] {
    font-size: 0.9375rem;
  }
}

/* --- Footer --- */
/* Quiet: the page background under a hairline, small muted text. */
.footer {
  margin-top: auto;
  padding-block: 1.5rem 2rem;
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--color-text-muted);
  background-color: var(--color-bg);
  border-top: 1px solid var(--color-hairline);
}

.footer-content {
  display: grid;
  gap: 0.5rem;
}

.footer-brand {
  font-size: 1.125rem;
  line-height: 1;
  color: var(--color-ink);
}

/* The TMDB logo in its own colours, sized to the text. */
.footer img {
  display: inline-block;
  height: 10px;
  width: auto;
  margin-right: 0.5rem;
  vertical-align: 0;
}

/* Wide screens: the name on the left, the notice and the credit on the right of one line. */
@media (min-width: 900px) {
  .footer-content {
    display: flex;
    align-items: baseline;
    gap: 2rem;
  }

  .footer-brand,
  .footer-credit {
    flex: none;
  }

  .footer-notice {
    margin-left: auto;
    text-align: right;
  }
}

/* --- Error page --- */
.error-panel {
  max-width: 34rem;
  margin: 1rem auto;
  padding: 1.75rem 1.25rem;
}

.error-code {
  margin-bottom: 0.5rem;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.error-page-message {
  margin: 0.75rem 0 1.5rem;
  color: var(--color-text-muted);
}

@media (min-width: 600px) {
  .error-panel {
    margin-block: 3rem;
    padding: 2.5rem;
  }
}

/* --- Form controls --- */
.form-group {
  margin-bottom: 1.25rem;
}

/* Only direct children: the genre toggles style themselves. */
.form-group > label,
.form-group > legend {
  display: block;
  margin-bottom: 0.375rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-ink);
}

/* 16px on phones so iOS does not zoom into the field. */
.form-control {
  display: block;
  width: 100%;
  min-height: 2.5rem;
  padding: 0.5rem 0.75rem;
  font-size: 1rem;
  line-height: 1.5;
  color: var(--color-ink);
  background-color: var(--color-surface);
  border: 1px solid var(--color-control-border);
  border-radius: var(--radius-sm);
  appearance: none;
  transition: border-color var(--duration-fast) ease;
}

.form-control::placeholder {
  color: var(--color-text-muted);
  opacity: 1;
}

.form-control:hover {
  border-color: var(--color-ink-hover);
}

.form-control:focus {
  border-color: var(--color-ink);
}

.form-control:user-invalid {
  border-color: var(--color-danger-text);
}

/* appearance: none drops the native arrow, so selects draw their own. */
select.form-control {
  padding-right: 2.5rem;
  background-image: var(--select-arrow);
  background-repeat: no-repeat;
  background-position: right 0.875rem center;
  background-size: 0.75rem;
  cursor: pointer;
}

@media (min-width: 600px) {
  .form-control {
    font-size: 0.9375rem;
  }
}

/* Genre toggles: each label's text is a .tag; the checkbox stays in the page for keyboards and
   screen readers. */
.genre-options {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
}

.genre-options input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.genre-options .tag {
  cursor: pointer;
  user-select: none;
}

/* Checked fills with ink and gains a tick, so the state does not rest on colour alone. */
.genre-options input:checked + .tag {
  color: var(--color-on-ink);
  background-color: var(--color-ink);
}

.genre-options input:checked + .tag:hover {
  background-color: var(--color-ink-hover);
}

/* Font Awesome's check (Font Awesome Free 6.5.1, CC BY 4.0) masking the text colour. */
.genre-options input:checked + .tag::before {
  content: "";
  display: inline-block;
  width: 0.875em;
  height: 1em;
  margin-right: 0.35rem;
  font-size: 0.75em;
  vertical-align: -0.125em;
  background-color: currentColor;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.genre-options input:focus-visible + .tag {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* --- Autocomplete (autocomplete.js) --- */
.combo {
  position: relative;
}

.combo__list {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 20;
  max-height: 20rem;
  overflow-y: auto;
  padding: 0.25rem;
  list-style: none;
  background-color: var(--color-surface);
  border: 1px solid var(--color-hairline-strong);
  border-radius: var(--radius-sm);
}

.combo__option {
  display: flex;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.4375rem 0.625rem;
  font-size: 0.9375rem;
  color: var(--color-ink);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.combo__option:hover,
.combo__option[aria-selected="true"] {
  background-color: var(--color-tag-bg);
}

.combo__meta {
  flex-shrink: 0;
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

/* --- Alerts --- */
.alert {
  padding: 0.75rem 1rem;
  margin-bottom: 1.5rem;
  font-size: 0.9375rem;
  overflow-wrap: anywhere;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  animation: fade-in var(--duration) ease both;
}

.alert-warning {
  color: var(--color-warning-text);
  background-color: var(--color-warning-bg);
  border-color: var(--color-warning-border);
}

/* Notes rather than warnings (the movie page's "closest match"): quiet, in ink. */
.alert-info {
  color: var(--color-ink);
  background-color: var(--color-subtle);
  border-color: var(--color-hairline);
}

.alert p + p {
  margin-top: 0.4rem;
}

.alert-icon {
  margin-right: 0.5rem;
}

/* --- Loading --- */
.loading {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 2rem 0;
  color: var(--color-text-muted);
}

.spinner {
  width: 1.25rem;
  height: 1.25rem;
  border: 2px solid var(--color-hairline);
  border-top-color: var(--color-ink);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

/* --- Empty states --- */
/* The reason in a display line, what to try next in muted text below. */
.empty-state {
  padding: 2.5rem 1.5rem;
  text-align: center;
  overflow-wrap: anywhere;
}

.empty-state-message {
  max-width: 32rem;
  margin-inline: auto;
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 600;
  line-height: 1.25;
  color: var(--color-ink);
  text-wrap: balance;
}

.empty-state-hint {
  max-width: 32rem;
  margin: 0.75rem auto 0;
  font-size: 0.9375rem;
  color: var(--color-text-muted);
}

.empty-state-hint:first-child {
  margin-top: 0;
}

.empty-state-action {
  margin-top: 1.5rem;
}

@media (min-width: 600px) {
  .empty-state {
    padding-block: 3.5rem;
  }
}

/* --- Image frames --- */
/* A poster or photo in its 2:3 shape, with the placeholder underneath: common.js removes an
   image that fails to load, which reveals it. The hairline keeps light posters from melting
   into the page. */
.image-frame {
  position: relative;
  aspect-ratio: 2 / 3;
  overflow: hidden;
  background-color: var(--color-subtle);
  border: 1px solid var(--color-hairline);
  border-radius: var(--radius-md);
  transition: background-color var(--duration-fast) ease;
}

.image-frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: filter var(--duration-fast) ease;
}

.image-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.5rem;
  font-size: 0.8125rem;
  line-height: 1.3;
  text-align: center;
  color: var(--color-text-muted);
}

.image-placeholder .icon {
  font-size: 1.75rem;
}

/* --- Movie cards --- */
/* No box: the poster with the title and a muted meta line below, on the page background. */
.movie-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.75rem 1rem;
  list-style: none;
}

/* A card fills its grid cell; the remove button sits over its poster. */
.movie-grid > li {
  position: relative;
  display: grid;
}

@media (min-width: 600px) {
  .movie-grid {
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 2rem 1.5rem;
  }
}

.movie-card {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  color: var(--color-ink);
  border-radius: var(--radius-md);
}

.movie-card:hover {
  color: var(--color-ink);
}

.movie-card:hover .movie-card-image {
  background-color: var(--color-tag-bg-hover);
}

.movie-card:hover .movie-card-image img {
  filter: brightness(0.9);
}

.movie-card-body {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

.movie-card-title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-family: var(--font-sans);
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-ink);
  text-decoration-line: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  transition: text-decoration-color var(--duration-fast) ease;
}

.movie-card:hover .movie-card-title {
  text-decoration-color: var(--color-accent);
}

.movie-card-meta {
  min-height: 1lh;
  font-size: 0.8125rem;
  line-height: 1.4;
}

.movie-card-note {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

/* The lists page's remove button: a dark disc on the poster's corner. */
.card-remove {
  position: absolute;
  top: 0.375rem;
  right: 0.375rem;
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  font-size: 1rem;
  color: var(--color-play-icon);
  background-color: var(--color-play-bg);
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  transition: background-color var(--duration-fast) ease;
}

.card-remove:hover {
  background-color: var(--color-play-bg-hover);
}

/* --- Home --- */
/* The Flask app's home.css: the headline, the tabbed search panel, genre shortcuts, popular
   movies and search results. Phones: one column, the search before the content (home.js folds
   it on result pages). From 900px the search is a column left of the content, so reading order
   and tab order agree, and it stays in view while the results scroll. */
.home-layout {
  display: grid;
  gap: 2rem;
}

@media (min-width: 900px) {
  /* The headline tops the content column; result pages have none and its row stays empty. */
  .home-layout {
    grid-template-columns: 320px minmax(0, 1fr);
    grid-template-areas:
      "search intro"
      "search main";
    grid-template-rows: auto 1fr;
    align-items: start;
    column-gap: 2.5rem;
    row-gap: 0;
  }

  .home-intro {
    grid-area: intro;
    margin-bottom: 2.25rem;
  }

  /* A panel taller than the window scrolls on its own, so its button stays reachable. A
     scroll box cuts off focus rings at its edges, so keyboard focus scrolls a control well
     clear of them (and the tabs keep room above them, see .search-tabs). */
  .search-column {
    grid-area: search;
    position: sticky;
    top: 1rem;
    max-height: calc(100vh - 2rem);
    max-height: calc(100dvh - 2rem);
    overflow-y: auto;
    scroll-padding-block: 1rem;
  }

  .home-main {
    grid-area: main;
  }
}

@media (min-width: 1200px) {
  .home-layout {
    grid-template-columns: 340px minmax(0, 1fr);
    column-gap: 3rem;
  }
}

.home-intro-text {
  margin-top: 0.5rem;
  font-size: 1.0625rem;
  color: var(--color-text-muted);
}

/* "Aramayı düzenle": a disclosure row, the label on the left, the chevron on the right. */
.search-toggle {
  width: 100%;
  justify-content: space-between;
}

/* Only home.js sets aria-expanded="false", so the panel folds on result pages only. */
.search-toggle[aria-expanded="false"] + .search-panel {
  display: none;
}

.search-toggle[aria-expanded="true"] {
  margin-bottom: 0.75rem;
}

/* Points down while folded, up while open. */
.search-toggle-chevron {
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  transition: transform var(--duration) ease;
}

.search-toggle[aria-expanded="true"] .search-toggle-chevron {
  transform: rotate(180deg);
}

@media (min-width: 900px) {
  .search-toggle {
    display: none;
  }

  /* As specific as the fold rule above, so it wins. */
  .search-toggle[aria-expanded] + .search-panel {
    display: block;
  }
}

/* .panel's padding as --panel-pad, shared with the tabs, which reach out to the panel's edges. */
.search-panel {
  --panel-pad: 1.25rem;
  padding: var(--panel-pad);
}

@media (min-width: 600px) {
  .search-panel {
    --panel-pad: 1.5rem;
  }
}

/* Underline tabs across the top of the panel: the hairline runs edge to edge and the
   selected tab draws its accent line over it. The tabs start 0.25rem below the panel's top
   edge, the reach of the focus ring (2px out, 2px wide), which the scrolling column would
   otherwise cut off there. */
.search-tabs {
  display: flex;
  gap: 1.5rem;
  margin: calc(-1 * var(--panel-pad)) calc(-1 * var(--panel-pad)) var(--panel-pad);
  padding: 0.25rem var(--panel-pad) 0;
  border-bottom: 1px solid var(--color-hairline);
}

/* The 2px border sits on the hairline (the -1px margin), so the selected tab never shifts. */
.search-tabs [role="tab"] {
  margin-bottom: -1px;
  padding: 0.5625rem 0 0.6875rem;
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  color: var(--color-text-muted);
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  transition: color var(--duration-fast) ease, border-color var(--duration-fast) ease;
}

.search-tabs [role="tab"]:hover {
  color: var(--color-ink);
}

.search-tabs [role="tab"][aria-selected="true"] {
  color: var(--color-ink);
  border-bottom-color: var(--color-accent);
}

.search-form .btn {
  width: 100%;
}

.year-range {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
}

.year-range label {
  display: block;
  margin-bottom: 0.25rem;
  font-size: 0.8125rem;
  color: var(--color-text-muted);
}

/* The results follow the hidden home sections, which must not push them down. */
.home-section:not([hidden]) ~ .home-section {
  margin-top: 2.75rem;
}

/* A display line like the page titles, a little smaller so a long film name wraps less; the
   count follows in muted text figures. */
.results-title {
  margin-bottom: 0.375rem;
  font-size: 1.75rem;
  overflow-wrap: anywhere;
}

/* home.js focuses the heading when results arrive; the ring would only distract. */
.results-title:focus {
  outline: none;
}

.results-count {
  margin-left: 0.375rem;
  font-family: var(--font-sans);
  font-size: 0.9375rem;
  font-weight: 400;
  letter-spacing: 0;
  white-space: nowrap;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.results-summary {
  margin-top: 0.25rem;
  font-size: 0.875rem;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

/* The grid starts one hairline below the heading block. */
.results-body > .movie-grid {
  margin-top: 1.25rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--color-hairline);
}

@media (min-width: 900px) {
  .results-title {
    font-size: 2.25rem;
  }
}

/* "Daha fazla göster" jumps to the first new card; keep it clear of the window edge. */
.results-body .movie-grid > li {
  scroll-margin-top: 1rem;
}

.more-results {
  width: 100%;
  margin-top: 2.25rem;
}

@media (min-width: 600px) {
  .more-results {
    display: flex;
    width: fit-content;
    margin-inline: auto;
  }
}

/* --- Movie and person pages --- */
/* Phones: the poster or photo small on the left with the title block beside it, the body under
   both. From 600px: the image column on the left, the title block and the body on the right. */
.detail-layout {
  display: grid;
  grid-template-columns: clamp(5.5rem, 28vw, 7.5rem) minmax(0, 1fr);
  grid-template-areas:
    "media header"
    "body body";
  gap: 1.5rem 1rem;
  align-items: start;
}

.detail-media {
  grid-area: media;
}

.detail-header {
  grid-area: header;
  min-width: 0;
}

.detail-body {
  grid-area: body;
  min-width: 0;
}

.detail-title {
  font-size: clamp(1.625rem, 7.2vw, 2.125rem);
}

.movie-tagline {
  margin-top: 0.5rem;
  font-size: 1.0625rem;
  line-height: 1.4;
  color: var(--color-text-muted);
}

/* The phone column beside the poster is too narrow for one line, and a wrapped line would
   start with a dot, so phones stack the facts without dots; from 600px they share one line. */
.movie-detail-meta {
  flex-direction: column;
  margin-top: 0.75rem;
  font-size: 0.875rem;
  line-height: 1.5;
}

.movie-detail-meta > li::before {
  display: none;
}

.rating-scale {
  color: var(--color-text-muted);
}

/* Like and watchlist: a full-width pair on phones that stacks when the labels do not fit. */
.movie-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.action-btn {
  flex: 1 0 auto;
}

.action-btn .icon {
  transition: color var(--duration-fast) ease;
}

/* On: movie.js swaps in the solid icon, the heart in the accent and the bookmark in ink. */
.btn-like.liked .icon {
  color: var(--color-accent);
}

.btn-watchlist.added .icon {
  color: var(--color-ink);
}

.action-status {
  margin-top: 0.5rem;
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

.action-status:empty {
  display: none;
}

.detail-section {
  margin-top: 2rem;
}

.detail-text {
  max-width: 65ch;
  line-height: 1.65;
}

.detail-note {
  color: var(--color-text-muted);
}

/* Director and cast: names in a row, separated by commas (screen readers hear the list). */
.name-list {
  display: flex;
  flex-wrap: wrap;
  row-gap: 0.25rem;
  max-width: 65ch;
  list-style: none;
}

.name-list li:not(:last-child)::after {
  content: ",";
  content: "," / "";
  margin-right: 0.4em;
}

/* The trailer thumbnail is a play button; movie.js puts the player in its 16:9 box. */
.trailer-play,
.movie-trailer {
  display: block;
  width: 100%;
  max-width: 40rem;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: var(--radius-md);
}

/* The fill shows only until the thumbnail loads, like a poster's. */
.trailer-play {
  position: relative;
  overflow: hidden;
  padding: 0;
  background-color: var(--color-subtle);
  cursor: pointer;
}

/* YouTube thumbnails are 4:3 with black bars; covering the 16:9 box crops the bars. */
.trailer-thumbnail {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: filter var(--duration-fast) ease;
}

.trailer-play-icon {
  position: absolute;
  top: 50%;
  left: 50%;
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  font-size: 1.25rem;
  /* It sits on the picture, not the page, so it looks the same in both themes. */
  color: var(--color-play-icon);
  background-color: var(--color-play-bg);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  transition: background-color var(--duration-fast) ease;
}

/* The triangle's visual centre sits left of its box. */
.trailer-play-icon .icon {
  margin-left: 0.15em;
}

.trailer-play:hover .trailer-thumbnail {
  filter: brightness(0.85);
}

.trailer-play:hover .trailer-play-icon {
  background-color: var(--color-play-bg-hover);
}

/* The card grid under the article, after a hairline. */
.detail-cards {
  margin-top: 3rem;
  padding-top: 2rem;
  border-top: 1px solid var(--color-hairline);
}

.person-role {
  margin-top: 0.5rem;
  font-size: 1rem;
  color: var(--color-text-muted);
}

.person-known-for {
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

.page-note {
  margin-top: 1.5rem;
  font-size: 0.875rem;
}

@media (min-width: 600px) {
  .detail-layout {
    grid-template-columns: 200px minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "media header"
      "media body";
    gap: 1.75rem 2rem;
  }

  .detail-image .image-placeholder {
    gap: 0.75rem;
    font-size: 0.875rem;
  }

  .detail-image .image-placeholder .icon {
    font-size: 2.5rem;
  }

  .detail-title {
    font-size: 2.5rem;
  }

  .movie-tagline {
    font-size: 1.1875rem;
  }

  .movie-detail-meta {
    flex-direction: row;
    font-size: 0.9375rem;
  }

  .movie-detail-meta > li::before {
    display: inline;
  }

  .action-btn {
    flex-grow: 0;
  }

  .person-role {
    font-size: 1.0625rem;
  }
}

@media (min-width: 900px) {
  .detail-layout {
    grid-template-columns: 260px minmax(0, 1fr);
    column-gap: 3rem;
  }

  .detail-title {
    font-size: 3rem;
  }

  .detail-cards {
    margin-top: 4rem;
    padding-top: 2.5rem;
  }
}

@media (min-width: 1200px) {
  .detail-layout {
    grid-template-columns: 300px minmax(0, 1fr);
    column-gap: 3.5rem;
  }
}

/* --- Lists page --- */
.list-section {
  margin-top: 2.5rem;
}

/* After the first list, a hairline separates the lists. */
.list-section + .list-section {
  padding-top: 2rem;
  border-top: 1px solid var(--color-hairline);
}

/* Not a sibling of the lists, which #lists-root holds, so it draws the hairline itself. */
.recommendations {
  padding-top: 2rem;
  border-top: 1px solid var(--color-hairline);
}

.recommendations-hint {
  margin: -0.25rem 0 1rem;
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

.list-count {
  margin-left: 0.25rem;
  font-weight: 400;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.empty-list {
  max-width: 40rem;
}

.empty-list-message {
  font-weight: 500;
}

.empty-list-hint {
  margin-top: 0.25rem;
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

.empty-list-link {
  display: inline-block;
  margin-top: 0.75rem;
  font-size: 0.9375rem;
  font-weight: 500;
}

@media (min-width: 900px) {
  .list-section {
    margin-top: 3rem;
  }
}

/* --- Reduced motion --- */
/* Animations finish at once (so fade-ins still end visible), spinners stop and transitions jump. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
