/* Shortlist docs — the site dresses like the app it documents: near-black
   surfaces, one amber accent (Plex's own #e5a00d), no second hue competing.
   Dark is the default because the product is dark; light exists because the
   reference page is 68k of prose and some people read long docs in daylight. */

/* ---------------------------------------------------------------- tokens -- */

:root {
  --font-sans:
    ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --font-mono:
    ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono",
    monospace;

  --amber: #e5a00d;
  --amber-bright: #f5c04a;
  --amber-deep: #b87d05;

  --gutter: clamp(1.25rem, 1rem + 2vw, 2.5rem);
  --measure: 68ch;
  --wide: 1200px;
  --radius: 14px;
  --radius-sm: 9px;

  --nav-h: 60px;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
}

:root,
:root[data-theme="dark"] {
  --bg: #08080a;
  --bg-soft: #0d0d10;
  --surface: #121216;
  --surface-2: #191920;
  --surface-3: #22222b;
  --border: rgba(255, 255, 255, 0.09);
  --border-strong: rgba(255, 255, 255, 0.16);
  --text: #f4f4f5;
  --text-soft: #c9c9d1;
  --muted: #94949f;
  --faint: #6b6b76;
  --accent: var(--amber);
  --accent-text: var(--amber-bright);
  --accent-quiet: rgba(229, 160, 13, 0.12);
  --accent-line: rgba(229, 160, 13, 0.34);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 12px 32px -12px rgba(0, 0, 0, 0.7);
  --shadow-lg:
    0 2px 4px rgba(0, 0, 0, 0.5), 0 32px 64px -24px rgba(0, 0, 0, 0.85);
  --code-bg: #0f0f13;
  --good: #4ade80;
  --warn: #fbbf24;
  color-scheme: dark;
}

:root[data-theme="light"] {
  --bg: #fcfcfb;
  --bg-soft: #f6f6f4;
  --surface: #ffffff;
  --surface-2: #f7f7f5;
  --surface-3: #eeeeeb;
  --border: rgba(24, 24, 27, 0.11);
  --border-strong: rgba(24, 24, 27, 0.22);
  --text: #18181b;
  --text-soft: #33333a;
  --muted: #5f5f6b;
  --faint: #8a8a96;
  --accent: var(--amber-deep);
  --accent-text: #93630a;
  --accent-quiet: rgba(229, 160, 13, 0.14);
  --accent-line: rgba(184, 125, 5, 0.4);
  --shadow:
    0 1px 2px rgba(24, 24, 27, 0.06), 0 10px 26px -14px rgba(24, 24, 27, 0.22);
  --shadow-lg:
    0 2px 6px rgba(24, 24, 27, 0.07), 0 28px 56px -22px rgba(24, 24, 27, 0.28);
  --code-bg: #f6f6f4;
  --good: #15803d;
  --warn: #a16207;
  color-scheme: light;
}

/* ------------------------------------------------------------------ base -- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 1.5rem);
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-wrap: break-word;
}

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

a {
  color: var(--accent-text);
  text-decoration-color: var(--accent-line);
  text-underline-offset: 3px;
}

a:hover {
  text-decoration-color: currentColor;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

h1,
h2,
h3,
h4 {
  line-height: 1.2;
  letter-spacing: -0.02em;
  font-weight: 650;
  margin: 0;
  text-wrap: balance;
}

code,
kbd,
pre,
samp {
  font-family: var(--font-mono);
  font-size: 0.9em;
}

hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 2.5rem 0;
}

.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;
}

.skip-link {
  position: absolute;
  left: 0.5rem;
  top: -3rem;
  z-index: 200;
  background: var(--accent);
  color: #1a1200;
  padding: 0.6rem 1rem;
  border-radius: var(--radius-sm);
  font-weight: 600;
  transition: top 0.15s var(--ease);
}

.skip-link:focus {
  top: 0.5rem;
}

.wrap {
  width: min(100% - var(--gutter) * 2, var(--wide));
  margin-inline: auto;
}

/* ------------------------------------------------------------------- nav -- */

.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
}

.nav__inner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: min(100% - var(--gutter) * 2, 1400px);
  margin-inline: auto;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-weight: 660;
  font-size: 1.03rem;
  letter-spacing: -0.02em;
  color: var(--text);
  text-decoration: none;
  margin-right: auto;
}

.brand__mark {
  width: 27px;
  height: 27px;
  flex: none;
  border-radius: 7px;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.nav__link {
  color: var(--muted);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 520;
  padding: 0.45rem 0.7rem;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  transition:
    color 0.15s var(--ease),
    background 0.15s var(--ease);
}

.nav__link:hover {
  color: var(--text);
  background: var(--surface-2);
}

.nav__link[aria-current="page"] {
  color: var(--accent-text);
}

.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: none;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  transition:
    color 0.15s var(--ease),
    border-color 0.15s var(--ease);
}

.icon-btn:hover {
  color: var(--text);
  border-color: var(--border-strong);
}

.icon-btn svg {
  width: 16px;
  height: 16px;
}

/* The toggle shows the theme you'd switch TO, so only one glyph is ever up. */
[data-theme="dark"] .icon-btn__sun,
[data-theme="light"] .icon-btn__moon {
  display: none;
}

.search-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 34px;
  padding: 0 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--faint);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
  transition:
    border-color 0.15s var(--ease),
    color 0.15s var(--ease);
}

.search-btn:hover {
  color: var(--text);
  border-color: var(--border-strong);
}

.search-btn svg {
  width: 14px;
  height: 14px;
  flex: none;
}

.search-btn kbd {
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.05rem 0.3rem;
  font-size: 0.72rem;
  color: var(--faint);
  background: var(--surface-2);
}

.nav__burger {
  display: none;
}

@media (max-width: 900px) {
  .nav__links,
  .search-btn kbd {
    display: none;
  }
  .nav__burger {
    display: inline-grid;
  }
}

/* Measured at 320: the brand, a worded search button and four 34px icons want
   387px inside a 275px bar, and the row pushed every page 86px sideways. Shed
   the parts that say something twice, widest first. The word goes before the
   icon, which keeps its aria-label; the sponsor heart goes before anything
   structural, and it is still in the footer. */
@media (max-width: 600px) {
  .search-btn {
    width: 34px;
    padding: 0;
    justify-content: center;
  }
  .search-btn__label {
    display: none;
  }
}

@media (max-width: 420px) {
  .nav__inner {
    gap: 0.4rem;
  }
  .icon-btn--heart {
    display: none;
  }
}

/* --------------------------------------------------------------- buttons -- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.7rem 1.25rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition:
    transform 0.12s var(--ease),
    background 0.15s var(--ease),
    border-color 0.15s var(--ease);
}

.btn:active {
  transform: translateY(1px);
}

.btn svg {
  width: 17px;
  height: 17px;
  flex: none;
}

.btn--primary {
  background: var(--amber);
  color: #1a1200;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.22) inset;
}

.btn--primary:hover {
  background: var(--amber-bright);
}

.btn--ghost {
  background: var(--surface);
  border-color: var(--border-strong);
  color: var(--text);
}

.btn--ghost:hover {
  background: var(--surface-2);
}

.btn--lg {
  padding: 0.85rem 1.6rem;
  font-size: 1rem;
}

/* -------------------------------------------------------------- sections -- */

.section {
  padding-block: clamp(3.5rem, 2rem + 6vw, 6.5rem);
}

.section--tint {
  background: var(--bg-soft);
  border-block: 1px solid var(--border);
}

.section__head {
  max-width: 42rem;
  margin-bottom: clamp(2rem, 1rem + 3vw, 3.25rem);
}

.section__head--center {
  margin-inline: auto;
  text-align: center;
}

.eyebrow {
  display: inline-block;
  font-size: 0.76rem;
  font-weight: 680;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin-bottom: 0.75rem;
}

.section h2 {
  font-size: clamp(1.6rem, 1.2rem + 1.8vw, 2.35rem);
  margin-bottom: 0.85rem;
}

.section__lede {
  color: var(--muted);
  font-size: clamp(1rem, 0.97rem + 0.2vw, 1.09rem);
  margin: 0;
  text-wrap: pretty;
}

/* ------------------------------------------------------------------ hero -- */

.hero {
  position: relative;
  overflow: hidden;
  padding-block: clamp(3rem, 1.5rem + 7vw, 6rem)
    clamp(2.5rem, 1rem + 5vw, 4.5rem);
}

/* A single warm bloom behind the headline, so the page has a light source
   without the gradient-banner look the stock theme had. */
.hero::before {
  content: "";
  position: absolute;
  inset: -40% 0 auto 50%;
  translate: -50% 0;
  width: min(1100px, 130%);
  aspect-ratio: 1;
  background: radial-gradient(
    circle,
    rgba(229, 160, 13, 0.16),
    transparent 62%
  );
  pointer-events: none;
  z-index: 0;
}

[data-theme="light"] .hero::before {
  background: radial-gradient(circle, rgba(229, 160, 13, 0.2), transparent 65%);
}

.hero > * {
  position: relative;
  z-index: 1;
}

.hero__inner {
  max-width: 50rem;
  margin-inline: auto;
  text-align: center;
}

.hero h1 {
  font-size: clamp(2.15rem, 1.3rem + 4.2vw, 4rem);
  letter-spacing: -0.035em;
  font-weight: 700;
  margin-bottom: 1.15rem;
}

.hero h1 em {
  font-style: normal;
  color: var(--accent-text);
}

.hero__sub {
  font-size: clamp(1.05rem, 0.98rem + 0.45vw, 1.28rem);
  color: var(--text-soft);
  margin: 0 auto 1.9rem;
  max-width: 40rem;
  text-wrap: pretty;
}

.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
}

.hero__meta {
  margin-top: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.4rem;
  justify-content: center;
  font-size: 0.86rem;
  color: var(--muted);
}

.hero__meta span {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.hero__meta svg {
  width: 14px;
  height: 14px;
  color: var(--accent);
  flex: none;
}

.hero__shot {
  margin-top: clamp(2.5rem, 1.5rem + 4vw, 4rem);
}

/* --------------------------------------------------------- media frames -- */

/* Screenshots need a container or they read as loose rectangles on the page.
   The Plex row shot gets a plain frame; app shots get a faux title bar. */
.frame {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}

.frame img {
  width: 100%;
}

.frame--chrome .frame__bar {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 0.85rem;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}

.frame__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--surface-3);
  flex: none;
}

.frame__title {
  margin-left: 0.5rem;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.76rem;
  color: var(--faint);
  font-family: var(--font-mono);
}

figure {
  margin: 0;
}

figcaption {
  margin-top: 0.85rem;
  font-size: 0.85rem;
  color: var(--muted);
  text-align: center;
  text-wrap: pretty;
}

/* ----------------------------------------------------------------- cards -- */

.grid {
  display: grid;
  gap: 1.1rem;
}

.grid--3 {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}

.grid--2 {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.4rem;
  transition:
    border-color 0.15s var(--ease),
    transform 0.15s var(--ease);
}

.card--link {
  text-decoration: none;
  color: inherit;
  display: block;
}

.card--link:hover {
  border-color: var(--accent-line);
  transform: translateY(-2px);
}

.card__icon {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 9px;
  background: var(--accent-quiet);
  color: var(--accent-text);
  margin-bottom: 0.95rem;
}

.card__icon svg {
  width: 19px;
  height: 19px;
}

.card h3 {
  font-size: 1.02rem;
  margin-bottom: 0.4rem;
}

.card p {
  margin: 0;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.6;
}

.card p + p {
  margin-top: 0.6rem;
}

.card__more {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-top: 0.85rem;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--accent-text);
}

/* ------------------------------------------------------ row templates -- */

.templates {
  display: grid;
  gap: 0.85rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 21rem), 1fr));
  max-width: 68rem;
  margin-inline: auto;
}

.template {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.9rem;
  align-items: start;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
}

.template__emoji {
  font-size: 1.35rem;
  line-height: 1.2;
}

.template h3 {
  font-size: 0.98rem;
  margin-bottom: 0.3rem;
}

.template p {
  margin: 0;
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.55;
}

.tag {
  display: inline-block;
  vertical-align: middle;
  margin-left: 0.35rem;
  padding: 0.05rem 0.45rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --------------------------------------------------------- pipeline -- */

/* Sources in, Shortlist, results out. The page named TMDB in one place, Radarr in
   another and the AI providers in two more, so nobody could see the shape of it. */
.pipeline {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  justify-content: center;
  gap: 0.85rem;
  max-width: 60rem;
  margin: 0 auto clamp(2rem, 1rem + 3vw, 3rem);
}

.pipeline__stage {
  flex: 1 1 14rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  text-align: center;
}

.pipeline__stage--core {
  border-color: var(--accent-line);
  background: var(--accent-quiet);
}

.pipeline__stage h3 {
  font-size: 0.94rem;
  margin-bottom: 0.3rem;
}

.pipeline__stage p {
  margin: 0;
  color: var(--muted);
  font-size: 0.85rem;
  line-height: 1.5;
}

.pipeline__arrow {
  align-self: center;
  color: var(--accent);
  font-size: 1.2rem;
  flex: none;
}

@media (max-width: 720px) {
  .pipeline__arrow {
    rotate: 90deg;
  }
}

/* --------------------------------------------------------- works with -- */

/* Capped at three columns so the six groups land as two even rows. The plain
   .grid--3 stretches to four on a wide screen and leaves two orphans. */
.grid--trio {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  max-width: 68rem;
  margin-inline: auto;
}

.supports {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.7rem;
}

.supports li {
  display: grid;
  gap: 0.1rem;
  font-size: 0.9rem;
}

.supports strong {
  color: var(--text);
  font-weight: 600;
}

.supports span {
  color: var(--muted);
  font-size: 0.86rem;
  line-height: 1.5;
}

/* ------------------------------------------------------------ stat band -- */
/* Four numbers under the hero. Column counts are fixed rather than auto-fit
   because auto-fit put three across and left the fourth alone on a second row
   through the whole 900-1000px range. */

.stats-band {
  background: var(--bg-soft);
  border-block: 1px solid var(--border);
  padding-block: clamp(1.75rem, 1rem + 2.5vw, 2.75rem);
}

.stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.5rem, 0.75rem + 2vw, 2.25rem);
  margin: 0;
  padding: 0;
  list-style: none;
}

.stat__value {
  margin: 0;
  font-size: clamp(2.1rem, 1.6rem + 2.2vw, 3rem);
  line-height: 1;
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--accent-text);
  font-variant-numeric: tabular-nums;
}

.stat__unit {
  margin-left: 0.22em;
  font-size: 0.4em;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--muted);
}

.stat__label {
  margin: 0.5rem 0 0;
  font-size: 0.98rem;
  font-weight: 640;
}

.stat__note {
  margin: 0.3rem 0 0;
  color: var(--muted);
  font-size: 0.86rem;
  text-wrap: pretty;
}

@media (max-width: 479px) {
  .stats {
    grid-template-columns: 1fr;
  }
}

@media (min-width: 1000px) {
  .stats {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0;
  }
  .stat {
    padding-inline: clamp(1rem, 0.4rem + 1.6vw, 2rem);
  }
  .stat + .stat {
    border-left: 1px solid var(--border);
  }
  .stat:first-child {
    padding-left: 0;
  }
  .stat:last-child {
    padding-right: 0;
  }
}

/* ----------------------------------------------------------------- tour -- */
/* One grid, three layouts, no duplicated content. The steps and the pictures are
   siblings in reading order, so:
     narrow            one column, each step followed by its own picture
     wide, no script   two columns, each step beside its own picture
     wide, with script every picture moves into one pinned frame that changes
   Only the third is scoped under .js-tour-ready, and only site.js adds that class
   (after proving it can drive it — same contract as .reveal at the foot of this
   file). Nothing here is hidden or dimmed by CSS alone, so a blocked script leaves
   five readable steps and five visible pictures instead of a page of grey. */

/* `minmax(0, 1fr)`, not the implicit `auto`: an auto column is at least as wide
   as its widest item's min-content, and at 320 the address bar's monospace path
   pushed that to 321px inside a 275px page. Measured. */
.tour {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(2rem, 1.25rem + 3vw, 3.25rem);
}

/* Decoration for the pinned layout only. Hidden until site.js turns that on, so
   nobody else gets an empty groove down the page. */
.tour__rail {
  display: none;
}

.tour-step {
  display: grid;
  grid-template-columns: 2.25rem minmax(0, 1fr);
  column-gap: 1.05rem;
  row-gap: 0.5rem;
  align-content: start;
}

.tour-step__num {
  grid-column: 1;
  grid-row: 1 / span 2;
  margin: 0;
  width: 2.25rem;
  height: 2.25rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-soft);
  font-size: 0.95rem;
  font-weight: 680;
  font-variant-numeric: tabular-nums;
}

.tour-step__title {
  grid-column: 2;
  grid-row: 1;
  align-self: center;
  margin: 0;
  font-size: clamp(1.2rem, 1.05rem + 0.7vw, 1.5rem);
  text-wrap: balance;
}

.tour-step__body {
  grid-column: 2;
  grid-row: 2;
  margin: 0;
  color: var(--muted);
  font-size: 0.97rem;
  text-wrap: pretty;
}

.tour-panel {
  margin: 0;
}

.tour-panel img {
  display: block;
  width: 100%;
  height: auto;
}

@media (min-width: 901px) {
  .tour {
    grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
    column-gap: clamp(2rem, 1rem + 3.5vw, 4rem);
    align-items: center;
  }

  .tour-step {
    grid-column: 1;
  }

  .tour-panel {
    grid-column: 2;
  }

  /* --- pinned layout, script only ------------------------------------- */

  .js-tour-ready .tour {
    grid-template-rows: repeat(var(--tour-steps), auto);
    align-items: start;
  }

  .js-tour-ready .tour__rail {
    display: block;
    position: absolute;
    left: calc(1.125rem - 1px);
    top: 0.5rem;
    bottom: 0.5rem;
    width: 2px;
    border-radius: 2px;
    background: var(--border);
    overflow: hidden;
  }

  .js-tour-ready .tour__rail-fill {
    display: block;
    width: 100%;
    height: 0;
    background: var(--accent);
    transition: height 0.12s linear;
  }

  .js-tour-ready .tour-step {
    min-height: 66vh;
    align-content: center;
    opacity: 0.42;
    transition: opacity 0.35s var(--ease);
  }

  .js-tour-ready .tour-step.is-active {
    opacity: 1;
  }

  .js-tour-ready .tour-step.is-active .tour-step__num {
    background: var(--accent);
    border-color: transparent;
    color: #1a1200;
  }

  /* Every panel occupies the whole second column and sticks inside it. `1 / -1`
     needs the rows to be explicit, which is what --tour-steps is for. */
  /* Stacked in one grid area, so each is its own box and none of them affects
     any other's size. Measured: giving them all ONE fixed shape is the trap. The
     five pictures run from 1.25:1 to 1.84:1, and a 16:10 frame shrank the
     tallest until the app's own text was unreadable — `object-fit: contain`
     stops it being cropped, not being shrunk. Each panel keeps its own shape
     instead; only the height cap below ever makes one letterbox, and only on a
     viewport too short to show it whole. */
  .js-tour-ready .tour-panel {
    grid-column: 2;
    grid-row: 1 / -1;
    align-self: start;
    position: sticky;
    top: calc(var(--nav-h) + 7vh);
    /* One box for all five, with the picture centred in it, so the frame stops
       jumping up and down the viewport as the pictures swap. */
    height: calc(100vh - var(--nav-h) - 14vh);
    display: flex;
    flex-direction: column;
    justify-content: center;
    opacity: 0;
    visibility: hidden;
    transition:
      opacity 0.35s var(--ease),
      visibility 0.35s;
  }

  .js-tour-ready .tour-panel.is-active {
    opacity: 1;
    visibility: visible;
  }

  .js-tour-ready .tour-panel .frame {
    min-height: 0;
    max-height: 100%;
    display: flex;
    flex-direction: column;
    background: var(--surface-2);
  }

  /* Only bites on a viewport too short to show a picture whole: the frame hits
     the box height, the picture shrinks inside it, and `contain` letterboxes it
     rather than cropping. */
  .js-tour-ready .tour-panel img {
    min-height: 0;
    object-fit: contain;
  }
}

/* ------------------------------------------------- privacy-order flow -- */
/* The four-step diagram used by /faq/ and by the landing page's privacy
   section, from one file, so the site can never end up describing the write
   order two different ways. Each step also states who can see the row at that
   moment, which is the part the prose could never show at a glance. */

.flow {
  margin: 1.75rem 0;
}

.flow__steps {
  display: grid;
  gap: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}

.flow__step {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.25rem 0.9rem;
  padding: 0 0 1.35rem 0;
}

.flow__step:last-child {
  padding-bottom: 0;
}

/* The spine: the order is the whole point, so the steps are drawn as one run
   rather than four separate cards. It stops at the last badge. */
.flow__step:not(:last-child)::before {
  content: "";
  position: absolute;
  left: 15px;
  top: 34px;
  bottom: 6px;
  width: 2px;
  background: var(--accent-line);
}

.flow__num {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--accent-quiet);
  color: var(--accent-text);
  border: 1px solid var(--accent-line);
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 700;
}

.flow__step--final .flow__num {
  background: var(--accent);
  border-color: var(--accent);
  color: #1a1200; /* same near-black the amber buttons use; white on amber is 2.2:1 */
}

.flow__body strong {
  display: block;
  color: var(--text);
  font-size: 1rem;
  /* Not typography: 1rem x 1.9 is the 32px badge beside it, so the step title
     sits on the badge's centre line without a second alignment rule. */
  line-height: 1.9;
}

.flow__body span {
  display: block;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.55;
  text-wrap: pretty;
}

.flow__state {
  grid-column: 2;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0.6rem 0 0;
  padding: 0.3rem 0.65rem 0.3rem 0.5rem;
  justify-self: start;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-size: 0.82rem;
  line-height: 1.35;
}

.flow__state svg {
  flex: none;
  width: 15px;
  height: 15px;
}

.flow__state--on {
  border-color: var(--accent-line);
  background: var(--accent-quiet);
  color: var(--accent-text);
}

.flow figcaption {
  margin-top: 1.4rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.88rem;
  line-height: 1.6;
  text-align: left; /* the site centres figcaptions under centred images; this figure is prose-aligned */
  text-wrap: pretty;
}

/* Wide enough for the state to sit beside its step instead of under it. The
   breakpoint is the content's, not the viewport's: `.prose` is capped at 68ch,
   so this fires on a desktop docs page and never on a phone. */
@media (min-width: 900px) {
  .flow__step {
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: start;
    column-gap: 1rem;
  }
  .flow__state {
    grid-column: 3;
    grid-row: 1;
    margin-top: 0.3rem;
    /* A width, not a max-width: each step is its own grid, so an auto column
       sizes to that row's own text and the chips come out ragged down the
       left. Fixing the width lines all four up into one rail. */
    width: 13rem;
  }
}

/* -------------------------------------------------------- closing call -- */

.cta {
  position: relative;
  overflow: hidden;
  max-width: 46rem;
  margin-inline: auto;
  padding: clamp(2rem, 1.25rem + 3vw, 3.25rem)
    clamp(1.25rem, 0.75rem + 2vw, 2.5rem);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  text-align: center;
}

/* The same warm bloom as the hero, so the page opens and closes on one light
   source rather than fading out into a plain box. */
.cta::before {
  content: "";
  position: absolute;
  inset: -55% 15% auto;
  height: 18rem;
  background: radial-gradient(closest-side, var(--accent-quiet), transparent);
  pointer-events: none;
}

.cta > * {
  position: relative;
}

.cta h2 {
  font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.1rem);
  margin-bottom: 0.75rem;
}

.cta p {
  margin: 0 auto;
  max-width: 34rem;
  color: var(--muted);
  text-wrap: pretty;
}

.cta .hero__cta {
  margin-top: 1.75rem;
}

/* --------------------------------------------------------------- table -- */

.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  -webkit-overflow-scrolling: touch;
}

.table-scroll table {
  border-collapse: collapse;
  width: 100%;
  min-width: 44rem;
  font-size: 0.91rem;
}

.table-scroll th,
.table-scroll td {
  text-align: left;
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

.table-scroll thead th {
  background: var(--surface-2);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 640;
  white-space: nowrap;
}

.table-scroll tbody tr:last-child td {
  border-bottom: 0;
}

.table-scroll tbody tr:hover {
  background: var(--surface-2);
}

.table-scroll td:first-child {
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
}

.yes {
  color: var(--good);
  font-weight: 700;
}

.no {
  color: var(--faint);
}

/* ---------------------------------------------------------------- code -- */

.codeblock {
  position: relative;
  background: var(--code-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

.codeblock__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.55rem 0.6rem 0.55rem 1rem;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  font-size: 0.78rem;
  color: var(--muted);
  font-family: var(--font-mono);
}

.codeblock pre {
  margin: 0;
  padding: 1.1rem;
  overflow-x: auto;
  font-size: 0.86rem;
  line-height: 1.75;
  -webkit-overflow-scrolling: touch;
}

.copy {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.3rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--muted);
  font: inherit;
  font-size: 0.75rem;
  font-family: var(--font-sans);
  cursor: pointer;
  transition:
    color 0.15s var(--ease),
    border-color 0.15s var(--ease);
}

.copy:hover {
  color: var(--text);
  border-color: var(--border-strong);
}

.copy[data-copied="true"] {
  color: var(--good);
  border-color: var(--good);
}

.copy svg {
  width: 13px;
  height: 13px;
}

/* ----------------------------------------------------------------- faq -- */

.faq {
  max-width: 48rem;
  margin-inline: auto;
  display: grid;
  gap: 0.65rem;
}

.faq details {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.faq details[open] {
  border-color: var(--border-strong);
}

.faq summary {
  cursor: pointer;
  padding: 1rem 1.2rem;
  font-weight: 600;
  font-size: 0.98rem;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary::after {
  content: "";
  width: 8px;
  height: 8px;
  flex: none;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  rotate: 45deg;
  translate: 0 -2px;
  transition: rotate 0.2s var(--ease);
}

.faq details[open] summary::after {
  rotate: -135deg;
  translate: 0 2px;
}

.faq__body {
  padding: 0 1.2rem 1.15rem;
  color: var(--muted);
  font-size: 0.93rem;
}

.faq__body > :first-child {
  margin-top: 0;
}

.faq__body > :last-child {
  margin-bottom: 0;
}

/* -------------------------------------------------------------- callout -- */

.callout {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.85rem;
  padding: 1rem 1.2rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 0.92rem;
}

.callout svg {
  width: 18px;
  height: 18px;
  color: var(--accent);
  margin-top: 0.2rem;
  flex: none;
}

.callout > div > :first-child {
  margin-top: 0;
}

.callout > div > :last-child {
  margin-bottom: 0;
}

/* --------------------------------------------------------------- footer -- */

.footer {
  border-top: 1px solid var(--border);
  background: var(--bg-soft);
  padding-block: 3rem 2rem;
  font-size: 0.9rem;
}

.footer__grid {
  display: grid;
  gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  margin-bottom: 2.25rem;
}

.icon-btn--heart:hover svg {
  /* Fills on hover only — a permanently red heart in the header reads as a notification badge, and
     an unread count is the last thing a docs page should imply. */
  fill: currentColor;
  color: #e25555;
}

.footer h4 a {
  /* "Plex how-to" is both a column heading and a real page, so its heading is a link. It must still
     read as a heading rather than as the first item in its own list. */
  color: inherit;
  text-decoration: none;
}

.footer h4 a:hover {
  color: var(--ink);
}

.footer h4 {
  font-size: 0.78rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 0.85rem;
  font-weight: 640;
}

.footer ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.footer a {
  color: var(--muted);
  text-decoration: none;
}

/* Sub-pages sit under their section rather than reading as siblings of it. */
.footer__kid {
  padding-left: 0.75rem;
  font-size: 0.9em;
}

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

.footer__blurb {
  color: var(--muted);
  margin: 0.75rem 0 0;
  max-width: 22rem;
  font-size: 0.88rem;
}

.footer__base {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  justify-content: space-between;
  align-items: center;
  border-top: 1px solid var(--border);
  padding-top: 1.5rem;
  color: var(--faint);
  font-size: 0.85rem;
}

/* ---------------------------------------------------------- docs layout -- */

.docs {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr) 200px;
  gap: clamp(1.5rem, 1rem + 2vw, 3rem);
  width: min(100% - var(--gutter) * 2, 1400px);
  margin-inline: auto;
  align-items: start;
}

.sidebar,
.toc {
  position: sticky;
  top: calc(var(--nav-h) + 1.5rem);
  max-height: calc(100vh - var(--nav-h) - 3rem);
  overflow-y: auto;
  padding-block: 2rem;
  font-size: 0.9rem;
  scrollbar-width: thin;
}

.sidebar h4,
.toc h4 {
  font-size: 0.74rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 0.75rem;
  font-weight: 640;
}

.sidebar ul,
.toc ul {
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 0;
  display: grid;
  gap: 0.15rem;
}

.sidebar a {
  display: block;
  padding: 0.4rem 0.7rem;
  border-radius: var(--radius-sm);
  color: var(--muted);
  text-decoration: none;
  transition:
    color 0.15s var(--ease),
    background 0.15s var(--ease);
}

.sidebar a:hover {
  color: var(--text);
  background: var(--surface-2);
}

/* Guide sub-pages, shown only while you're inside that section. Scoped under
   .sidebar so it outweighs the `.sidebar ul` margin reset above it. */
.sidebar .sidebar__children {
  margin: 0.2rem 0 0.5rem 0.85rem;
  padding-left: 0.7rem;
  border-left: 1px solid var(--border);
  gap: 0;
}

.sidebar__children a {
  padding: 0.3rem 0.6rem;
  font-size: 0.85rem;
}

.sidebar a[aria-current="page"] {
  color: var(--accent-text);
  background: var(--accent-quiet);
  font-weight: 600;
}

.toc a {
  display: block;
  padding: 0.28rem 0 0.28rem 0.75rem;
  border-left: 2px solid var(--border);
  color: var(--muted);
  text-decoration: none;
  font-size: 0.85rem;
  line-height: 1.45;
  transition:
    color 0.15s var(--ease),
    border-color 0.15s var(--ease);
}

.toc a:hover {
  color: var(--text);
}

.toc a.is-active {
  color: var(--accent-text);
  border-left-color: var(--accent);
}

.toc a[data-level="3"] {
  padding-left: 1.5rem;
  font-size: 0.81rem;
}

@media (max-width: 1180px) {
  .docs {
    grid-template-columns: 230px minmax(0, 1fr);
  }
  .toc {
    display: none;
  }
}

@media (max-width: 900px) {
  .docs {
    grid-template-columns: minmax(0, 1fr);
  }
  .sidebar {
    display: none;
    position: static;
    max-height: none;
    padding-block: 1rem 0;
    border-bottom: 1px solid var(--border);
  }
  .sidebar.is-open {
    display: block;
  }
}

/* ---------------------------------------------------------------- prose -- */

.prose {
  padding-block: 2.5rem 4rem;
  min-width: 0;
}

.prose > * {
  max-width: var(--measure);
}

.prose__head {
  margin-bottom: 2.25rem;
  padding-bottom: 1.75rem;
  border-bottom: 1px solid var(--border);
}

.prose__head h1 {
  font-size: clamp(1.85rem, 1.4rem + 2vw, 2.65rem);
  letter-spacing: -0.03em;
  margin-bottom: 0.65rem;
}

.prose__head p {
  margin: 0;
  color: var(--muted);
  font-size: 1.05rem;
  text-wrap: pretty;
}

.prose h2 {
  font-size: 1.5rem;
  margin: 2.75rem 0 0.9rem;
  padding-top: 0.5rem;
}

.prose h3 {
  font-size: 1.17rem;
  margin: 2rem 0 0.7rem;
}

.prose h4 {
  font-size: 1.02rem;
  margin: 1.6rem 0 0.5rem;
}

.prose p,
.prose ul,
.prose ol {
  margin: 0 0 1.1rem;
}

.prose li {
  margin-bottom: 0.4rem;
}

.prose li > ul,
.prose li > ol {
  margin-top: 0.4rem;
  margin-bottom: 0.5rem;
}

.prose strong {
  color: var(--text);
  font-weight: 640;
}

.prose blockquote {
  margin: 1.5rem 0;
  padding: 0.9rem 1.2rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-soft);
}

.prose blockquote > :first-child {
  margin-top: 0;
}

.prose blockquote > :last-child {
  margin-bottom: 0;
}

.prose :not(pre) > code {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 0.1em 0.38em;
  color: var(--accent-text);
  /* NOT `nowrap`. It defeated the `overflow-wrap` beside it, so a long inline code span — an API
     path, or the ranking formula — set a min-content width wider than a phone and panned the whole
     page sideways. Reference was 555px of content in a 316px viewport. */
  white-space: normal;
  overflow-wrap: anywhere;
}

.prose pre {
  background: var(--code-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.1rem;
  overflow-x: auto;
  margin: 0 0 1.3rem;
  font-size: 0.86rem;
  line-height: 1.7;
  -webkit-overflow-scrolling: touch;
}

.prose pre code {
  background: none;
  border: 0;
  padding: 0;
  color: var(--text-soft);
  white-space: pre;
}

/* Long reference tables are the main reason this site needs a wide column. */
.prose table {
  border-collapse: collapse;
  width: 100%;
  font-size: 0.89rem;
  margin: 0 0 1.3rem;
}

.prose .table-scroll {
  max-width: none;
  margin-bottom: 1.3rem;
}

.prose .table-scroll table {
  margin: 0;
}

.prose th,
.prose td {
  text-align: left;
  padding: 0.65rem 0.9rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}

.prose thead th {
  background: var(--surface-2);
  font-size: 0.77rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.prose img {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-block: 1.3rem;
  max-width: 100%;
}

.prose .anchor {
  opacity: 0;
  margin-left: 0.4rem;
  color: var(--faint);
  text-decoration: none;
  font-weight: 400;
  transition: opacity 0.15s var(--ease);
}

.prose h2:hover .anchor,
.prose h3:hover .anchor,
.anchor:focus-visible {
  opacity: 1;
}

/* prev / next */

.pager {
  display: grid;
  gap: 0.85rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  margin-top: 3.5rem;
  padding-top: 2rem;
  border-top: 1px solid var(--border);
  max-width: var(--measure);
}

.pager a {
  display: block;
  padding: 0.95rem 1.15rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s var(--ease);
}

.pager a:hover {
  border-color: var(--accent-line);
}

.pager small {
  display: block;
  color: var(--faint);
  font-size: 0.78rem;
  margin-bottom: 0.2rem;
}

.pager strong {
  color: var(--accent-text);
  font-size: 0.95rem;
}

.pager .is-next {
  text-align: right;
}

.edit-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 2rem;
  font-size: 0.86rem;
  color: var(--muted);
  text-decoration: none;
}

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

.edit-link svg {
  width: 14px;
  height: 14px;
}

/* --------------------------------------------------------------- search -- */

.search-dialog {
  width: min(100% - 2rem, 40rem);
  max-height: min(70vh, 34rem);
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow-lg);
  margin-top: 9vh;
  overflow: hidden;
}

.search-dialog::backdrop {
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(3px);
}

.search-dialog__input {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.9rem 1.1rem;
  border-bottom: 1px solid var(--border);
}

.search-dialog__input svg {
  width: 17px;
  height: 17px;
  color: var(--faint);
  flex: none;
}

.search-dialog__input input {
  flex: 1;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 1rem;
  outline: none;
  min-width: 0;
}

.search-results {
  overflow-y: auto;
  max-height: calc(min(70vh, 34rem) - 4rem);
  padding: 0.5rem;
  margin: 0;
  list-style: none;
}

.search-results li a {
  display: block;
  padding: 0.65rem 0.8rem;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
}

.search-results li a:hover,
.search-results li a:focus-visible,
.search-results li.is-active a {
  background: var(--accent-quiet);
}

.search-results strong {
  display: block;
  font-size: 0.93rem;
  color: var(--text);
}

.search-results small {
  display: block;
  color: var(--muted);
  font-size: 0.82rem;
  margin-top: 0.15rem;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.search-results mark {
  background: var(--accent-quiet);
  color: var(--accent-text);
  border-radius: 3px;
  padding: 0 2px;
}

.search-empty {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--muted);
  font-size: 0.9rem;
}

/* ---------------------------------------------------------------- utils -- */

.stack-lg > * + * {
  margin-top: clamp(1.75rem, 1rem + 2.5vw, 2.75rem);
}

.center {
  text-align: center;
}

.mt-lg {
  margin-top: clamp(1.75rem, 1rem + 2.5vw, 2.75rem);
}

/* --------------------------------------------------------------- reveal -- */
/* Fade-up for section reveals. Visible at rest by design: `.reveal` on its own
   carries no hidden state, so this file plus no JS (or JS that threw, or a
   browser with no IntersectionObserver) renders every section normally. Only
   site.js adds `.js-reveal-ready` to <html>, and only after it has confirmed it
   can un-hide again — CSS never hides content on its own.

   No prefers-reduced-motion block here: the sitewide rule near the top of this
   file already forces transition-duration to 0.01ms on every element, so this
   transition is already imperceptible under it. site.js skips the observer
   entirely in that case, so the class is never even added. */
.reveal {
  opacity: 1;
  transform: none;
}

.js-reveal-ready .reveal {
  opacity: 0;
  transform: translateY(16px);
}

/* The transition lives on the VISIBLE state, not the hidden one. Put it on the
   hidden rule and the browser animates INTO it: site.js adds .js-reveal-ready
   after first paint, every section below the fold fades out over half a second,
   and only then fades back in. Measured, not guessed — an offscreen section
   read opacity 0.0166 mid-fade-out. Here the hide is instantaneous and only the
   reveal animates, because a transition is read from the after-change style. */
.js-reveal-ready .reveal.is-visible {
  opacity: 1;
  transform: none;
  transition:
    opacity 0.5s var(--ease),
    transform 0.5s var(--ease);
}
