/* Yapper — black and white, phone-shaped at every width.
 *
 * The app is laid out as a phone screen and stays that way however wide the
 * window gets: on a narrow viewport the frame disappears and it fills the
 * screen, and on a desktop it becomes a device sitting on a grey desk, with its
 * own internal scroll. One layout to reason about instead of two, and it is the
 * shape the content was written for — a feed column does not want to be 1600px
 * wide.
 *
 * Monochrome throughout, including the seeded avatars, which are greyscaled
 * rather than replaced so the colour never creeps back via content. */

:root {
  --ink: #101010;
  --ink-soft: #3d3d3d;
  --muted: #8d8d8d;
  --rule: #e9e9e9;
  --rule-strong: #d2d2d2;
  --paper: #ffffff;
  --paper-sunk: #fafafa;
  --desk: #ededed;

  /* Four faces, each with one job:
       Craze Retro    the "Yapper" wordmark, and nothing else. Its character
                      set is letters only, no digits or punctuation, so it
                      cannot be trusted with any other text.
       Michroma       headings: wide, squared, retro-futurist. No italic, so
                      nothing that uses it asks for one.
       IBM Plex Sans  everything you read. Chosen over Oxanium, which read
                      as squashed at small sizes.
       IBM Plex Mono  handles, timestamps, counts and labels: the parts that
                      are data rather than prose. */
  --wordmark: 'Craze Retro', 'Michroma', system-ui, sans-serif;
  --display: 'Michroma', 'IBM Plex Sans', system-ui, sans-serif;
  --sans: 'IBM Plex Sans', system-ui, -apple-system, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --phone-w: 430px;
  --gutter: 1.25rem;

  color-scheme: light;
}

/* Dark: the same monochrome, inverted. The device decides until the header
   toggle is used, and then the choice does (data-theme, set before first paint
   by the script at the top of index.html). Defined twice, once for each route
   in, so the toggle can override the device either way. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --ink: #f1f1f1;
    --ink-soft: #c8c8c8;
    --muted: #8f8f8f;
    --rule: #262626;
    --rule-strong: #3b3b3b;
    --paper: #111111;
    --paper-sunk: #181818;
    --desk: #050505;
    color-scheme: dark;
  }
}

:root[data-theme='dark'] {
  --ink: #f1f1f1;
  --ink-soft: #c8c8c8;
  --muted: #8f8f8f;
  --rule: #262626;
  --rule-strong: #3b3b3b;
  --paper: #111111;
  --paper-sunk: #181818;
  --desk: #050505;
  color-scheme: dark;
}

/* Set for one frame while the toggle switches theme. Chips and tabs fade their
   text colour but not their background, so without this a selected chip spent
   0.15s as white text on a white pill on its way to dark. */
.theme-switching *,
.theme-switching *::before,
.theme-switching *::after { transition: none !important; }

/* Craze Retro, by its author on 1001fonts.com under the 1001Fonts Free For
   Commercial Use license (public/fonts/1001fonts-craze-retro-eula.txt), which
   allows embedding in a web app. Served exactly as downloaded: the license
   forbids modifying it, which rules out subsetting or renaming the file. */
@font-face {
  font-family: 'Craze Retro';
  src: url('/fonts/Craze%20Retro.ttf') format('truetype');
  font-display: swap;
}

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

/* `[hidden]` and a class selector carry the same specificity, so whichever is
   declared last wins — and a page stylesheet always comes after the browser's.
   `.field { display: grid }` quietly beat it, and the signup-only Display name
   input showed on the Sign in tab. First rule in the file so nothing below can
   repeat that. */
[hidden] { display: none !important; }

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

body {
  margin: 0;
  font-family: var(--sans);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

/* ---- the phone ---------------------------------------------------------- */

.phone {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: var(--phone-w);
  min-height: 100dvh;
  margin: 0 auto;
  background: var(--paper);
  position: relative;
}

@media (min-width: 560px) {
  body {
    background: var(--desk);
    padding: 2rem 1rem;
  }

  .phone {
    height: min(880px, calc(100dvh - 4rem));
    min-height: 0; /* so the height above actually binds */
    border: 1px solid var(--rule-strong);
    border-radius: 2.5rem;
    overflow: hidden;
    box-shadow:
      0 1px 2px rgba(0, 0, 0, 0.04),
      0 24px 60px -24px rgba(0, 0, 0, 0.25);
  }

  /* The speaker slot. Pure decoration, and the one thing that makes it read as
     a phone rather than as a narrow website. */
  .phone::before {
    content: '';
    position: absolute;
    top: 0.85rem;
    left: 50%;
    transform: translateX(-50%);
    width: 3.25rem;
    height: 0.3rem;
    border-radius: 999px;
    background: var(--rule-strong);
    z-index: 3;
  }

  .head { padding-top: 1.9rem; }
}

/* ---- chrome ------------------------------------------------------------- */

.head {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem var(--gutter) 0.9rem;
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
  z-index: 2;
}

.mark {
  font-family: var(--wordmark);
  font-size: 1.6rem;
  font-weight: 400;
  letter-spacing: 0.02em;
  line-height: 1;
  color: var(--ink);
  text-decoration: none;
}

.head__right {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-size: 0.8rem;
  color: var(--muted);
}

.head__right a { color: var(--muted); text-decoration: none; }
.head__right a:hover { color: var(--ink); }

.head__end { display: flex; align-items: center; gap: 0.6rem; min-width: 0; }
.head__right .glass--small { white-space: nowrap; }

/* With the theme toggle beside it, "Leave demo" ran out of room on a small
   phone and broke onto two lines. The "Guest" label is the part that can go:
   the button already says whose session this is. */
@media (max-width: 380px) {
  .head__right .who { display: none; }
}

/* Light and dark. A half-filled circle, the same mark zayda.dev uses. */
.theme-toggle {
  appearance: none;
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.theme-toggle:hover { border-color: var(--ink); }

/* The scrolling region. On desktop this is what scrolls, not the page, which is
   what keeps the device fixed on the desk. */
.wrap {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--gutter);
}

.foot {
  flex: none;
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem var(--gutter);
  border-top: 1px solid var(--rule);
  font-size: 0.72rem;
  color: var(--muted);
  background: var(--paper);
}

.foot a { color: var(--muted); text-decoration: none; }
.foot a:hover { color: var(--ink); text-decoration: underline; }

/* ---- signed out --------------------------------------------------------- */

.label {
  font-size: 0.64rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 0.6rem;
}

.gate__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: 1.45rem;
  line-height: 1.3;
  margin: 0 0 0.8rem;
  letter-spacing: -0.01em;
}

/* Michroma has no italic; the second line is set apart by tone instead. */
.gate__title em { font-style: normal; color: var(--ink-soft); }

.gate__lede {
  margin: 0 0 1.75rem;
  color: var(--ink-soft);
  font-size: 0.92rem;
}

/* ---- tabs --------------------------------------------------------------- */

.tabs {
  display: flex;
  gap: 1.4rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 1.1rem;
}

.tab {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: 0 0 0.6rem;
  font-family: inherit;
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.tab:hover { color: var(--ink-soft); }

/* Four feed tabs do not fit a 320px phone at this letter-spacing, so the row
   scrolls sideways rather than wrapping. The rule moves from a border to an
   inset shadow because a scrolling row clips the -1px overlap the active
   tab's underline relies on; children paint over an inset shadow anyway. */
.tabs--feed {
  gap: 1.15rem;
  border-bottom: 0;
  box-shadow: inset 0 -1px 0 var(--rule);
  overflow-x: auto;
  scrollbar-width: none;
}

.tabs--feed::-webkit-scrollbar { display: none; }

/* At 320px the four labels are 9px too wide at the normal gap; a tighter gap
   fits them, so the scroll above is only ever a fallback. */
@media (max-width: 359px) {
  .tabs--feed { gap: 0.75rem; }
  .tabs--feed .tab { letter-spacing: 0.1em; }
}

.tabs--feed .tab {
  flex: none;
  margin-bottom: 0;
  white-space: nowrap;
}

.tab.is-on {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

/* ---- forms and cards ---------------------------------------------------- */

.card {
  display: grid;
  gap: 1.1rem;
  padding: 1.25rem;
  border: 1px solid var(--rule);
  border-radius: 1.25rem;
  background: var(--paper-sunk);
}

.field { display: grid; gap: 0.35rem; }

.field label {
  font-size: 0.64rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.field small { font-size: 0.72rem; color: var(--muted); }

.field input,
textarea {
  font-family: inherit;
  font-weight: 300;
  font-size: 1rem;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule-strong);
  border-radius: 0;
  padding: 0.4rem 0;
  width: 100%;
  transition: border-color 0.15s ease;
}

.field input:focus,
textarea:focus {
  outline: none;
  border-bottom-color: var(--ink);
}

textarea {
  resize: vertical;
  border: 1px solid var(--rule-strong);
  border-radius: 0.9rem;
  padding: 0.75rem 0.85rem;
  line-height: 1.5;
}

/* The one filled element on the page, so the primary action is unmistakable
   without a single colour being involved. */
.glass {
  appearance: none;
  font-family: inherit;
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--ink);
  border: 1px solid var(--ink);
  border-radius: 999px;
  padding: 0.7rem 1.6rem;
  cursor: pointer;
  transition: opacity 0.15s ease, transform 0.08s ease;
}

.glass:hover { opacity: 0.84; }
.glass:active { transform: translateY(1px); }
.glass:disabled { opacity: 0.35; cursor: default; transform: none; }

/* Follow and sign-out: outlined, so they never compete with the filled one. */
.glass--small {
  padding: 0.42rem 1rem;
  font-size: 0.62rem;
  color: var(--ink);
  background: transparent;
}

.glass--small:hover { background: var(--ink); color: var(--paper); opacity: 1; }

.status {
  margin: 0;
  font-size: 0.78rem;
  color: var(--muted);
  min-height: 1.2em;
}

/* ---- the way in --------------------------------------------------------- */

.gate__demo { display: grid; gap: 0.9rem; justify-items: start; }

.gate__note {
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.6;
  color: var(--muted);
}

/* ---- compose ------------------------------------------------------------ */

.compose { margin-bottom: 1.4rem; gap: 0.85rem; }

.compose__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.counter {
  font-size: 0.74rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.compose__tools { display: flex; align-items: center; gap: 0.9rem; }

/* A text button: for secondary actions that should not look like the Yap
   button or like a link that navigates. */
.linkish {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  font-family: inherit;
  font-size: 0.74rem;
  color: var(--ink-soft);
  cursor: pointer;
}

.linkish:hover { color: var(--ink); text-decoration: underline; }

.compose__hint {
  margin: -0.2rem 0 0;
  font-size: 0.74rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

.sources-edit { display: grid; gap: 0.5rem; }
.sources-edit:empty { display: none; }

.source-edit {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 0.4rem;
}

.source-edit__url,
.source-edit__kind {
  min-width: 0;
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: 300;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--rule-strong);
  border-radius: 0.6rem;
  padding: 0.4rem 0.55rem;
}

.source-edit__kind { max-width: 8.5rem; }

.source-edit__tip {
  grid-column: 1 / -1;
  margin: -0.1rem 0 0.15rem;
  font-size: 0.7rem;
  line-height: 1.45;
  color: var(--muted);
}

.compose__help {
  margin: -0.3rem 0 0;
  font-size: 0.72rem;
  line-height: 1.5;
  color: var(--muted);
}

.compose__help a { color: var(--ink-soft); }

.guide__steps { margin: 0 0 1rem; padding-left: 1.2rem; display: grid; gap: 0.6rem; }
.guide__steps li { font-size: 0.86rem; line-height: 1.55; color: var(--ink-soft); }
.guide__steps b { font-weight: 400; color: var(--ink); }

.book-search { display: grid; gap: 0.35rem; }
.book-results { display: grid; gap: 0.2rem; }

.book-result {
  appearance: none;
  text-align: left;
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: 300;
  color: var(--ink-soft);
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 0.6rem;
  padding: 0.4rem 0.6rem;
  cursor: pointer;
}

.book-result:hover { border-color: var(--ink); color: var(--ink); }

/* ---- sources guide and search ------------------------------------------- */

.source-search { margin-bottom: 0.35rem; }
.source-search input { width: 100%; }
.source-results { margin-bottom: 1rem; }

.guide h1,
.guide h2 {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.15;
  margin: 1rem 0 0.6rem;
}

.guide h1 { font-size: 1.2rem; line-height: 1.35; }
.guide h2 { font-size: 0.98rem; line-height: 1.4; margin-top: 1.6rem; }
.guide p { font-size: 0.9rem; color: var(--ink-soft); }
.guide dl { margin: 0; display: grid; gap: 0.15rem; }
.guide dt { font-weight: 400; font-size: 0.88rem; margin-top: 0.6rem; }
.guide dd { margin: 0; font-size: 0.84rem; line-height: 1.55; color: var(--ink-soft); }
.guide__note { font-size: 0.8rem !important; color: var(--muted) !important; }
.explore__note a { color: var(--ink-soft); }

.source-edit__url:focus,
.source-edit__kind:focus { outline: none; border-color: var(--ink); }

.source-edit__remove {
  appearance: none;
  width: 1.8rem;
  height: 1.8rem;
  border: 0;
  border-radius: 999px;
  background: none;
  font-size: 1.1rem;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
}

.source-edit__remove:hover { color: var(--ink); background: var(--rule); }

/* A source under a yap: title, then a line saying what it is. */
.sources {
  list-style: none;
  margin: -0.15rem 0 0.6rem;
  padding: 0;
  display: grid;
  gap: 0.45rem;
}

/* A source card: a square that says what kind of thing it is, beside the
   title and where it comes from. The square stands in for a preview image
   until link previews exist, and stays as the kind marker after. */
.source {
  display: grid;
  grid-template-columns: 3.4rem minmax(0, 1fr);
  align-items: center;
  gap: 0.7rem;
  padding: 0.45rem;
  border: 1px solid var(--rule);
  border-radius: 0.85rem;
  background: var(--paper-sunk);
}

.source__mark {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border-radius: 0.6rem;
  border: 1px solid var(--rule-strong);
  background: var(--paper);
}

.source__kind {
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.source--verified .source__mark { border-color: var(--ink); }

.source__check {
  position: absolute;
  right: -0.35rem;
  bottom: -0.35rem;
  display: grid;
  place-items: center;
  width: 1.15rem;
  height: 1.15rem;
  border-radius: 999px;
  background: var(--ink);
  color: var(--paper);
  font-size: 0.62rem;
  border: 2px solid var(--paper-sunk);
}

.source__text { display: grid; gap: 0.1rem; min-width: 0; }

.source__link {
  font-size: 0.84rem;
  font-weight: 400;
  color: var(--ink);
  text-decoration: none;
  overflow-wrap: anywhere;
}

a.source__link:hover { text-decoration: underline; }

.source__meta { font-size: 0.7rem; line-height: 1.5; color: var(--muted); }
.source__archive { color: var(--muted); }
.source__archive:hover { color: var(--ink); }

/* Outlined when unverified, filled when the site is a known primary source:
   the same weight-not-colour rule as everything else. */
a.source__badge { text-decoration: none; }

.source__badge {
  display: inline-block;
  padding: 0 0.4rem;
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
}

.source__badge--primary {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

/* ---- feed --------------------------------------------------------------- */

.feed { display: grid; }

.yap {
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  gap: 0.85rem;
  padding: 1.1rem 0;
  border-bottom: 1px solid var(--rule);
}

.yap:last-child { border-bottom: 0; }

.avatar {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 999px;
  object-fit: cover;
  border: 1px solid var(--rule);
  background: var(--paper-sunk);
  /* Greyscaled rather than swapped out, so a colourful seeded avatar cannot
     reintroduce colour the rest of the page has removed. */
  filter: grayscale(1) contrast(0.95);
}

.avatar--initials {
  display: inline-grid;
  place-items: center;
  flex: none;
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
}

.profile__head .avatar--initials { font-size: 1.15rem; }

.yap__head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.2rem;
}

.yap__name {
  font-weight: 500;
  font-size: 0.92rem;
  color: var(--ink);
  text-decoration: none;
}

.yap__name:hover { text-decoration: underline; }

.yap__handle, .yap__when { font-size: 0.76rem; color: var(--muted); }

/* "Why you're seeing this", above a ranked yap. Hover shows the numbers. */
.yap__why {
  margin: 0 0 0.25rem;
  font-size: 0.72rem;
  line-height: 1.4;
  color: var(--muted);
  cursor: help;
}

.yap__body {
  margin: 0 0 0.55rem;
  font-size: 0.95rem;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}

/* Hashtags and mentions are links, set apart by weight rather than colour. */
.yap__body .tag,
.yap__body .mention {
  color: var(--ink);
  font-weight: 400;
  text-decoration: none;
}

.yap__body .tag:hover,
.yap__body .mention:hover { text-decoration: underline; }

/* Heart outline until liked, filled after — the only state change that needs to
   be felt rather than read. */
.like {
  appearance: none;
  background: none;
  border: 0;
  padding: 0.2rem 0;
  font-family: inherit;
  font-size: 0.82rem;
  color: var(--muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  transition: color 0.15s ease, transform 0.12s ease;
}

/* The heart is an inline SVG with no width or height attributes — it takes its
   size from here, and without this rule it collapses and the button renders as
   a bare number. */
.like svg {
  width: 1.05rem;
  height: 1.05rem;
  display: block;
  flex: none;
  overflow: visible;
}

.like:hover { color: var(--ink); }
.like:active { transform: scale(0.92); }
.like[aria-pressed='true'] { color: var(--ink); }

/* Signed out: the count without the button. */
.like--static,
.like--static:hover { cursor: default; color: var(--muted); }
.like--static:active { transform: none; }

/* ---- explore ------------------------------------------------------------ */

.explore { padding-top: 0.35rem; }

.news { margin-bottom: 1.6rem; }
.news .yap:last-of-type { border-bottom: 1px solid var(--rule); }

.more {
  display: inline-block;
  margin-top: 0.8rem;
  text-decoration: none;
}

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

.trend {
  list-style: none;
  margin: 0 0 0.9rem;
  padding: 0;
}

.trend a {
  display: grid;
  grid-template-columns: 1.6rem 1fr;
  align-items: baseline;
  column-gap: 0.4rem;
  padding: 0.65rem 0;
  border-bottom: 1px solid var(--rule);
  color: var(--ink);
  text-decoration: none;
}

.trend li:last-child a { border-bottom: 0; }

.trend__rank {
  grid-row: span 2;
  font-family: var(--display);
  font-size: 0.95rem;
  line-height: 1;
  color: var(--muted);
}

.trend__tag { font-weight: 400; font-size: 0.98rem; }
.trend a:hover .trend__tag { text-decoration: underline; }
.trend__meta { font-size: 0.74rem; color: var(--muted); }

.explore__note {
  margin: 0 0 1.6rem;
  font-size: 0.74rem;
  line-height: 1.6;
  color: var(--muted);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin-bottom: 0.5rem;
}

.chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.3rem 0.75rem;
  font-size: 0.8rem;
  color: var(--ink-soft);
  text-decoration: none;
  border: 1px solid var(--rule);
  border-radius: 999px;
  transition: border-color 0.15s ease, color 0.15s ease;
}

.chip span { font-size: 0.68rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.chip:hover { border-color: var(--ink); color: var(--ink); }

/* ---- topics ------------------------------------------------------------- */

.topic-bar { margin: -0.35rem 0 0.4rem; }

/* One row that scrolls sideways: eight topics never fit a phone, and
   wrapping them into three rows would push the feed off the first screen. */
.chips--scroll {
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  padding: 0.1rem 0 0.5rem;
  margin-bottom: 0;
}

.chips--scroll::-webkit-scrollbar { display: none; }

/* The topics rail. The page buttons sit over the row's ends on a fade, so
   the row reads as continuing past the edge, which is the cue that it
   scrolls. Each appears only when there is more in its direction. */
.rail { position: relative; }

/* Keeps a chip that scrolls into view clear of the page buttons laid over
   the row's ends, rather than half under one. */
.rail .chips--scroll { scroll-padding-inline: 2.8rem; }

.rail__btn {
  appearance: none;
  position: absolute;
  top: 0;
  bottom: 0.5rem;
  z-index: 1;
  width: 2.6rem;
  padding: 0;
  border: 0;
  display: flex;
  align-items: center;
  cursor: pointer;
  color: var(--ink);
}

.rail__btn--prev {
  left: 0;
  justify-content: flex-start;
  background: linear-gradient(to right, var(--paper) 45%, transparent);
}

.rail__btn--next {
  right: 0;
  justify-content: flex-end;
  background: linear-gradient(to left, var(--paper) 45%, transparent);
}

.rail__btn span {
  display: grid;
  place-items: center;
  width: 1.7rem;
  height: 1.7rem;
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  background: var(--paper);
  font-size: 1.05rem;
  line-height: 1;
  transition: border-color 0.15s ease;
}

.rail__btn:hover span { border-color: var(--ink); }

/* A pointer that can drag gets a hand; touch screens just swipe. */
@media (hover: hover) and (pointer: fine) {
  .chips--scroll { cursor: grab; }
  .chips--scroll.is-dragging { cursor: grabbing; user-select: none; }
  .chips--scroll.is-dragging .chip { pointer-events: none; }
}

/* Sub-topics under the rail: smaller, and few enough to wrap. */
.chips--sub { gap: 0.35rem; margin: 0.1rem 0 0.35rem; }

.chip--sub {
  appearance: none;
  font-family: inherit;
  font-weight: 300;
  font-size: 0.72rem;
  padding: 0.18rem 0.6rem;
  background: var(--paper);
  cursor: pointer;
}

.chip--sub[aria-pressed='true'] { border-color: var(--ink); color: var(--ink); font-weight: 400; }

.chip--topic {
  appearance: none;
  flex: none;
  font-family: inherit;
  font-weight: 300;
  background: var(--paper);
  cursor: pointer;
  white-space: nowrap;
}

/* The selected topic is filled, the same rule as the one filled button. */
.chip--topic[aria-pressed='true'] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

.topic__blurb {
  margin: 0.15rem 0 0.2rem;
  font-size: 0.76rem;
  line-height: 1.5;
  color: var(--muted);
}

.area { display: grid; gap: 0.1rem; margin-top: 0.15rem; }

.area__name {
  margin: 0;
  font-family: var(--display);
  font-size: 0.95rem;
  line-height: 1.35;
}

.area__tools { margin: 0; font-size: 0.74rem; color: var(--muted); }
.area__tools .linkish[aria-pressed='true'] { color: var(--ink); font-weight: 400; }

.area-picker { display: grid; gap: 0.6rem; margin: 0.2rem 0 0.8rem; }

.area-picker__row {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr) auto;
  gap: 0.45rem;
  align-items: center;
}

.area__select {
  min-width: 0;
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 300;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--rule-strong);
  border-radius: 0.6rem;
  padding: 0.4rem 0.45rem;
}

.area__select:focus { outline: none; border-color: var(--ink); }

.empty {
  margin: 2.5rem 0;
  text-align: center;
  font-size: 0.88rem;
  color: var(--muted);
}

/* ---- profile ------------------------------------------------------------ */

.back { display: inline-block; text-decoration: none; }
.back:hover { color: var(--ink); }

/* Wraps rather than squeezing: at phone width a long display name and a Follow
   button do not fit on one line, and wrapping the button beneath reads far
   better than hyphenating someone's name into it. */
.profile__head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.9rem;
  margin: 0.9rem 0 1.1rem;
}

.profile__head .avatar { width: 3.75rem; height: 3.75rem; }

.profile__who { flex: 1 1 9rem; min-width: 0; }

.profile__head h1,
.profile__head h2 {
  font-family: var(--display);
  font-weight: 400;
  font-size: 1.1rem;
  line-height: 1.3;
  margin: 0;
  overflow-wrap: anywhere;
}

.profile__head .glass--small { flex: none; margin-left: auto; }

.profile__stats {
  display: flex;
  gap: 1.75rem;
  padding: 0 0 1.1rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 0.4rem;
}

.profile__stats div { display: grid; gap: 0.1rem; }

.profile__stats b {
  font-family: var(--display);
  font-size: 1.05rem;
  font-weight: 400;
  line-height: 1;
}

.profile__stats span {
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---- suggestions -------------------------------------------------------- */

.suggest {
  margin-top: 1.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}

.suggest-row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem 0;
}

.who { flex: 1 1 auto; min-width: 0; }

.who a {
  display: block;
  font-weight: 500;
  font-size: 0.88rem;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.who a:hover { text-decoration: underline; }
.who span { font-size: 0.74rem; color: var(--muted); }

/* Data, not prose: handles, timestamps, counts and labels are set in Plex
   Mono, so they read as the app talking rather than a person. */
.label,
.yap__handle,
.yap__when,
.counter,
.trend__meta,
.source__kind,
.who span,
.profile__stats span,
.chip span {
  font-family: var(--mono);
}

/* ---- utility ------------------------------------------------------------ */

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

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

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
