/* Default = light "editorial cream" palette. Dark variant
     * lives in `[data-theme="dark"]` further down — the only
     * thing the toggle has to do is set that attribute on
     * <html>; every other surface flips through the variables.
     *
     * `--ink-rgb` / `--paper-rgb` are the *components* of ink/
     * paper as comma-separated triples, so existing rgba()
     * literals can spell themselves as `rgba(var(--ink-rgb),
     * 0.1)` and flip with the theme without touching the
     * alpha. Light mode: ink ≈ near-black, paper ≈ pure white.
     * Dark mode: those swap. */
:root {
  --bg-a: #eef0f4;
  --bg-b: #d4d8e0;
  --ink: #1a1e28;
  --ink-rgb: 26, 30, 40;
  --muted: #62687a;
  --paper-rgb: 255, 255, 255;
  --card: rgba(var(--paper-rgb), 0.86);
  --glass: rgba(var(--paper-rgb), 0.86);
  --accent: #10b981;
  --accent-rgb: 16, 185, 129;
  --border: rgba(var(--ink-rgb), 0.1);
  --display: "Newsreader", "Georgia", serif;
  --sans: "Inter Tight", -apple-system, sans-serif;
  /* Modern Apple-flavored sans for document cards — system-first
     so macOS / iOS visitors get real SF Pro Display, others fall
     back to Inter Tight (already loaded for body) and finally
     system-ui. Slightly tighter than `--sans` because it's used
     for hero text inside results. */
  --modern:
    -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    "Inter Tight", "Inter", system-ui, sans-serif;
}
/* Dark theme — ported from raphaelsty.github.io/knowledge.
   Deep black field, paper rises to #0c0c14 for cards, emerald
   accent (#10b981) carries over from light. */
[data-theme="dark"] {
  /* Lifted dark surface — the old #080808 field made doc cards
     read as harshly outlined panels and pushed white text into
     too-high contrast. The new tones sit a notch above pure
     black so cards blend into the field and ink reads softer. */
  --bg-a: #1a1a22;
  --bg-b: #131319;
  --ink: #e6e6ee;
  --ink-rgb: 230, 230, 238;
  --muted: #9a9aac;
  --paper-rgb: 26, 26, 34;
  --card: linear-gradient(
    145deg,
    rgba(30, 30, 40, 0.85),
    rgba(22, 22, 30, 0.92)
  );
  --glass: rgba(34, 34, 44, 0.72);
  --accent: #10b981;
  --accent-rgb: 16, 185, 129;
  --border: rgba(255, 255, 255, 0.05);
}
* {
  box-sizing: border-box;
}
html {
  background: #ffffff;
}

html[data-theme="dark"] {
  background: #15151c;
}
html,
body {
  margin: 0;
  padding: 0;
  min-height: 100vh;
  color: var(--ink);
}
body {
  font-family: var(--sans);
  background: transparent;
  isolation: isolate;
}
[data-theme="dark"] body {
  background: transparent;
}
a {
  color: inherit;
  text-decoration: none;
}

.layout {
  display: grid;
  grid-template-columns: 320px 1fr;
  min-height: 100vh;
}
.rail {
  padding: 22px 18px 18px;
  border-right: 1px solid var(--border);
  background: rgba(var(--paper-rgb), 0.82);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  gap: 0;
}
/* "Back to all libraries" — quiet nav link at the top of the rail.
     * Apple Mail / Music sidebars use the same pattern. */
.rail-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  margin: -4px -10px 14px;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  border-radius: 8px;
  letter-spacing: -0.005em;
  transition:
    background 0.12s ease,
    color 0.12s ease,
    transform 0.12s ease;
  align-self: flex-start;
}
.rail-back:hover {
  background: rgba(var(--ink-rgb), 0.06);
  color: var(--ink);
  transform: translateX(-1px);
}
.rail-back svg {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
  transition: transform 0.15s ease;
}
.rail-back:hover svg {
  transform: translateX(-2px);
}
.group {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.group + .group {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid rgba(var(--ink-rgb), 0.1);
}
#grpLibs {
  flex: 0 0 auto;
  max-height: 280px;
}

/* The library-picker affordance has been folded into the
 * personality rows themselves: hovering or tapping a row opens
 * the picker (see `.lib-row:hover .ava` below). The standalone
 * "+" button is hidden everywhere — its job is now redundant. */
.lib-add-btn {
  display: none;
}

/* ── Library picker modal ───────────────────────────────────
   Centred dialog over a soft dim. Multi-select rows; active
   libs pin to the top inside the list. Header / footer stay
   sticky so a long list stays scannable. */
.lib-picker[hidden],
.lib-picker-back[hidden] {
  display: none !important;
}
.lib-picker-back {
  position: fixed;
  inset: 0;
  background: rgba(var(--ink-rgb), 0.36);
  backdrop-filter: blur(6px) saturate(140%);
  -webkit-backdrop-filter: blur(6px) saturate(140%);
  z-index: 200;
  animation: lib-picker-fade 0.18s ease;
}
.lib-picker {
  position: fixed;
  z-index: 201;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  /* Scales with viewport on big screens (clamped to 980px so the
     content column doesn't sprawl into magazine-spread territory),
     never narrower than 520px on tiny ones, and always 32px from
     the edges on phones. */
  width: clamp(520px, 70vw, 980px);
  max-width: calc(100vw - 32px);
  max-height: min(820px, calc(100vh - 64px));
  display: flex;
  flex-direction: column;
  background: rgba(var(--paper-rgb), 0.98);
  backdrop-filter: blur(28px) saturate(180%);
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  border: 1px solid rgba(var(--ink-rgb), 0.08);
  border-radius: 18px;
  box-shadow:
    0 24px 60px rgba(var(--ink-rgb), 0.18),
    0 1px 0 rgba(255, 255, 255, 0.5) inset;
  overflow: hidden;
  animation: lib-picker-pop 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
@keyframes lib-picker-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes lib-picker-pop {
  from {
    opacity: 0;
    transform: translate(-50%, calc(-50% + 8px)) scale(0.98);
  }
  to {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
}
.lib-picker-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 20px 12px;
}
.lib-picker-head h2 {
  font-family: var(--display);
  font-weight: 500;
  font-size: 22px;
  letter-spacing: -0.01em;
  margin: 0;
  color: var(--ink);
}
.lib-picker-close {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
  color: var(--muted);
  border-radius: 999px;
  cursor: pointer;
  transition:
    background 0.15s ease,
    color 0.15s ease;
}
.lib-picker-close svg {
  width: 14px;
  height: 14px;
}
.lib-picker-close:hover {
  background: rgba(var(--ink-rgb), 0.06);
  color: var(--ink);
}
.lib-picker-search {
  flex: 0 0 auto;
  padding: 0 20px 12px;
}
/* Foot-action cluster — Select all + Clear all sit inline with
   the Close apply button at the bottom of the picker, so every
   modal-level action lives in one row above the count label. */
.lib-picker-foot-actions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
/* Modal-level action pills used in the picker footer next to the
   Close button. Same 32px height as `.lib-picker-apply` so all
   three sit on a shared baseline. Variants:
     - .lib-picker-act--accent  → Select all (emerald hover)
     - .lib-picker-act--danger  → Clear all (red hover)
   The base style stays neutral so a plain `.lib-picker-act` still
   reads as a quiet secondary control. */
.lib-picker-act {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 14px;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.005em;
  border-radius: 999px;
  border: 1px solid rgba(var(--ink-rgb), 0.12);
  background: rgba(var(--paper-rgb), 0.6);
  color: rgba(var(--ink-rgb), 0.78);
  cursor: pointer;
  transition:
    background 0.15s ease,
    color 0.15s ease,
    border-color 0.15s ease,
    box-shadow 0.15s ease,
    transform 0.15s ease;
}
.lib-picker-act svg {
  width: 13px;
  height: 13px;
  opacity: 0.7;
  transition: opacity 0.15s ease;
}
.lib-picker-act:hover {
  background: rgba(var(--ink-rgb), 0.04);
  color: var(--ink);
  border-color: rgba(var(--ink-rgb), 0.22);
}
.lib-picker-act:hover svg {
  opacity: 1;
}
.lib-picker-act:active {
  transform: translateY(1px);
}
/* Accent variant — Select all */
.lib-picker-act--accent:hover {
  background: rgba(var(--accent-rgb), 0.08);
  color: var(--accent);
  border-color: rgba(var(--accent-rgb), 0.4);
  box-shadow: 0 2px 8px rgba(var(--accent-rgb), 0.12);
}
/* Danger variant — Clear all */
.lib-picker-act--danger:hover {
  background: rgba(220, 38, 38, 0.08);
  color: rgb(220, 38, 38);
  border-color: rgba(220, 38, 38, 0.36);
  box-shadow: 0 2px 8px rgba(220, 38, 38, 0.12);
}
.lib-picker-search input {
  width: 100%;
  height: 36px;
  padding: 0 14px;
  border-radius: 10px;
  border: 1px solid rgba(var(--ink-rgb), 0.1);
  background: rgba(var(--paper-rgb), 0.6);
  font-family: var(--sans);
  font-size: 13.5px;
  color: var(--ink);
  letter-spacing: -0.005em;
  outline: none;
  transition:
    border-color 0.15s ease,
    background 0.15s ease,
    box-shadow 0.15s ease;
}
.lib-picker-search input::placeholder {
  color: var(--muted);
  opacity: 0.7;
}
.lib-picker-search input:focus {
  border-color: rgba(var(--accent-rgb), 0.45);
  background: rgba(var(--paper-rgb), 0.95);
  box-shadow: 0 0 0 4px rgba(var(--accent-rgb), 0.1);
}
/* ── Category sections inside the list ───────────────────────
   Mirrors the welcome page's grouped grid: a small uppercase
   eyebrow heading per category, the rows underneath. The
   "Already added" synthetic section is pinned at the top with
   an accent-tinted heading. */
.lib-picker-section {
  margin: 0;
  padding: 0 0 8px;
}
.lib-picker-section + .lib-picker-section {
  margin-top: 0;
  /* Divider lives on the heading instead of the section so it
     visually belongs to the header band — no empty strip between
     the rule and the title. */
  border-top: 0;
}
.lib-picker-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px 8px;
  position: sticky;
  top: 0;
  background: rgba(var(--paper-rgb), 0.98);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  z-index: 1;
}
.lib-picker-section + .lib-picker-section .lib-picker-section-head {
  border-top: 1px solid rgba(var(--ink-rgb), 0.05);
}
.lib-picker-section-title {
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.lib-picker-section.is-active .lib-picker-section-title {
  color: var(--accent);
}
.lib-picker-section-title {
  line-height: 1;
}
.lib-picker-section-count {
  font-size: 10.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  opacity: 0.7;
  padding: 1px 7px;
  border-radius: 999px;
  background: rgba(var(--ink-rgb), 0.05);
}
.lib-picker-section-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.lib-picker-empty {
  padding: 32px 16px;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
}
.lib-picker-section-empty {
  padding: 10px 14px;
  font-size: 12.5px;
  color: var(--muted);
  font-style: italic;
  letter-spacing: -0.005em;
}

.lib-picker-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* No top padding: a sticky-positioned heading sticks to the
     scroll container's content edge, so any padding here would
     show through as a gap above the stuck heading. */
  padding: 0 12px 12px;
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--ink-rgb), 0.18) transparent;
}
.lib-picker-row {
  display: grid;
  grid-template-columns: auto 32px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.12s ease;
}
.lib-picker-row:not(:has(.lib-picker-bookmark)) {
  grid-template-columns: auto 32px 1fr;
}
.lib-picker-row:hover {
  background: rgba(var(--ink-rgb), 0.04);
}
.lib-picker-row.on {
  background: rgba(var(--accent-rgb), 0.08);
}
.lib-picker-row.disabled {
  cursor: not-allowed;
  opacity: 0.45;
}
.lib-picker-row.disabled:hover {
  background: transparent;
}
.lib-picker-row.disabled input[type="checkbox"] {
  cursor: not-allowed;
}
.lib-picker-row input[type="checkbox"] {
  -webkit-appearance: none;
  appearance: none;
  width: 18px;
  height: 18px;
  border: 1.5px solid rgba(var(--ink-rgb), 0.22);
  border-radius: 5px;
  cursor: pointer;
  margin: 0;
  display: grid;
  place-items: center;
  background: rgba(var(--paper-rgb), 0.8);
  transition:
    background 0.12s ease,
    border-color 0.12s ease;
}
.lib-picker-row input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent);
}
.lib-picker-row input[type="checkbox"]:checked::after {
  content: "";
  width: 10px;
  height: 6px;
  border-left: 2px solid #ffffff;
  border-bottom: 2px solid #ffffff;
  transform: rotate(-45deg) translate(1px, -1px);
}
.lib-picker-row .ava {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  overflow: hidden;
  background: rgba(var(--ink-rgb), 0.06);
  display: grid;
  place-items: center;
}
.lib-picker-row .ava img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.lib-picker-row .info {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.lib-picker-row .info .name {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.005em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lib-picker-row .info .desc {
  font-size: 12px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Bookmark toggle — small flag icon to the right of each row,
   between the meta and the ✓. Outline at rest, filled emerald
   when bookmarked. Visible on hover (and always on bookmarked
   rows) so the row stays uncluttered until the user reaches for
   it. */
.lib-picker-bookmark {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  background: transparent;
  border: 0;
  border-radius: 8px;
  color: var(--muted);
  opacity: 0;
  cursor: pointer;
  transition:
    opacity 0.15s ease,
    background 0.15s ease,
    color 0.15s ease,
    transform 0.15s ease;
}
.lib-picker-bookmark svg {
  width: 14px;
  height: 14px;
}
.lib-picker-row:hover .lib-picker-bookmark,
.lib-picker-row:focus-within .lib-picker-bookmark,
.lib-picker-bookmark.on {
  opacity: 1;
}
.lib-picker-bookmark:hover {
  background: rgba(var(--accent-rgb), 0.1);
  color: var(--accent);
  transform: translateY(-1px);
}
.lib-picker-bookmark.on {
  color: var(--accent);
}
.lib-picker-bookmark.on:hover {
  background: rgba(var(--accent-rgb), 0.18);
}
.lib-picker-foot {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  padding: 14px 20px;
  border-top: 1px solid rgba(var(--ink-rgb), 0.08);
  background: rgba(var(--paper-rgb), 0.5);
}
.lib-picker-count {
  margin-right: auto;
  font-size: 12.5px;
  color: var(--muted);
  letter-spacing: -0.005em;
}
.lib-picker-cancel,
.lib-picker-apply {
  height: 32px;
  padding: 0 16px;
  border-radius: 999px;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    color 0.15s ease,
    box-shadow 0.15s ease;
}
.lib-picker-cancel {
  background: transparent;
  border: 1px solid rgba(var(--ink-rgb), 0.12);
  color: var(--ink);
}
.lib-picker-cancel:hover {
  border-color: rgba(var(--ink-rgb), 0.22);
  background: rgba(var(--ink-rgb), 0.04);
}
.lib-picker-apply {
  background: var(--accent);
  border: 1px solid var(--accent);
  color: #ffffff;
  box-shadow:
    0 1px 3px rgba(var(--accent-rgb), 0.22),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.lib-picker-apply:hover {
  background: color-mix(in srgb, var(--accent) 86%, #000 14%);
  box-shadow:
    0 4px 12px rgba(var(--accent-rgb), 0.3),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
@media (max-width: 540px) {
  .lib-picker {
    width: calc(100vw - 16px);
    /* Leave clear margins on top + bottom so the modal doesn't
     * kiss the iPhone notch / home-indicator. Safe-area insets
     * collapse to 0 on devices without them. */
    max-height: calc(
      100vh - 56px - env(safe-area-inset-top) - env(safe-area-inset-bottom)
    );
  }
}
#grpSrc {
  flex: 1;
}
#grpLibs .group-body {
  max-height: 200px;
}
#grpSrc .group-body {
  flex: 1;
}
.group-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  user-select: none;
  margin: 4px 4px 10px;
}
.group-head h3 {
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
  font-weight: 500;
  opacity: 0.7;
}
.clear-all {
  background: transparent;
  border: 0;
  padding: 0;
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
  opacity: 0.75;
  cursor: pointer;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  transition:
    color 0.12s,
    opacity 0.12s;
}
.clear-all:hover {
  color: var(--accent);
  opacity: 1;
}
.group-search-wrap {
  position: relative;
  margin: 0 0 8px;
}
.group-search-wrap::before {
  content: "⌕";
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 13px;
  color: var(--muted);
  opacity: 0.55;
  pointer-events: none;
}
.group-search {
  width: 100%;
  padding: 7px 28px 7px 28px;
  border: 0;
  border-radius: 7px;
  background: rgba(var(--ink-rgb), 0.045);
  font-family: var(--sans);
  font-size: 13px;
  color: var(--ink);
  outline: none;
  transition: background 0.15s;
}
.group-search::placeholder {
  color: var(--muted);
  opacity: 0.55;
}
.group-search:hover {
  background: rgba(var(--ink-rgb), 0.06);
}
.group-search:focus {
  background: rgba(var(--ink-rgb), 0.07);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.1);
}
.opt {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 10px;
  cursor: pointer;
  font-size: 13px;
  border-radius: 6px;
  position: relative;
  transition: background 0.08s;
}
.opt:hover {
  background: rgba(var(--ink-rgb), 0.04);
}
.opt.on {
  background: transparent;
}
.opt.on:hover {
  background: rgba(var(--ink-rgb), 0.03);
}
.opt.on.last-selected {
  margin-bottom: 6px;
}
.opt.on.last-selected::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: -3px;
  height: 1px;
  background: rgba(var(--ink-rgb), 0.08);
}
.opt input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.opt img.fav {
  width: 16px;
  height: 16px;
  border-radius: 3px;
  flex-shrink: 0;
  opacity: 0.9;
}
.opt .fav-fallback {
  width: 16px;
  height: 16px;
  border-radius: 4px;
  background: rgba(var(--ink-rgb), 0.08);
  color: var(--muted);
  display: inline-grid;
  place-items: center;
  font-size: 7px;
  line-height: 1;
  flex-shrink: 0;
}
/* Filled star for the synthetic Favorites pseudo-source.
     * Same 16px footprint as the real-source favicons so the column
     * stays aligned, but warm-orange ink and a soft tint background
     * so the chip reads as "your starred set" at a glance. */
.opt .fav-star {
  width: 16px;
  height: 16px;
  border-radius: 4px;
  background: rgba(var(--accent-rgb), 0.12);
  color: var(--accent);
  display: inline-grid;
  place-items: center;
  font-size: 11px;
  line-height: 1;
  flex-shrink: 0;
}
.opt.on .fav-star {
  background: rgba(var(--accent-rgb), 0.22);
}
.opt .label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 400;
  letter-spacing: -0.005em;
}
.opt.on .label {
  font-weight: 500;
}
.opt .count {
  color: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  opacity: 0.55;
  font-weight: 400;
}
.opt .check {
  width: 14px;
  flex-shrink: 0;
  color: var(--accent);
  font-size: 13px;
  font-weight: 600;
  display: inline-block;
  text-align: center;
  opacity: 0;
  transition: opacity 0.1s;
}
.opt.on .check {
  opacity: 1;
}
.opt.on .count {
  opacity: 0;
}
.lib-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  cursor: pointer;
  border: 0;
  background: transparent;
  text-align: left;
  width: 100%;
  font-family: inherit;
  font-size: inherit;
  color: inherit;
  border-radius: 6px;
  position: relative;
  transition: background 0.08s;
}
.lib-row:hover {
  background: rgba(var(--ink-rgb), 0.04);
}
.lib-row.on {
  background: transparent;
}
.lib-row.on:hover {
  background: rgba(var(--ink-rgb), 0.03);
}
.lib-row.on.last-selected {
  margin-bottom: 6px;
}
.lib-row.on.last-selected::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: -3px;
  height: 1px;
  background: rgba(var(--ink-rgb), 0.08);
}
.lib-row input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
/* The personality row IS the picker affordance now (no more "+"
 * button below the list). Make every part of the button — avatar,
 * name, description, even the ✓ glyph — read as a clickable link:
 * pointer cursor on every descendant, accent-tinted name on hover,
 * subtle avatar lift so the tap target is unambiguous. */
.lib-row,
.lib-row * {
  cursor: pointer;
}
.lib-row:hover .ava,
.lib-row:focus-visible .ava {
  box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 0.45);
  transform: scale(1.05);
}
.lib-row:hover .name,
.lib-row:focus-visible .name {
  color: var(--accent);
}
.lib-row .ava {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  overflow: hidden;
  flex-shrink: 0;
  background: white;
  transition:
    box-shadow 0.15s ease,
    transform 0.15s ease;
  box-shadow: 0 1px 2px rgba(var(--ink-rgb), 0.06);
}
.lib-row .ava img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.lib-row .info {
  flex: 1;
  min-width: 0;
  line-height: 1.2;
}
.lib-row .name {
  font-size: 13px;
  font-weight: 400;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  letter-spacing: -0.005em;
}
.lib-row.on .name {
  font-weight: 500;
}
.lib-row .desc {
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0.75;
  margin-top: 1px;
}
.lib-row .check {
  width: 14px;
  flex-shrink: 0;
  color: var(--accent);
  font-size: 13px;
  font-weight: 600;
  text-align: center;
  opacity: 0;
  transition: opacity 0.1s;
}
.lib-row.on .check {
  opacity: 1;
}
.lib-row.host {
  cursor: default;
}
.lib-row.host:hover {
  background: transparent;
}
.lib-row.host .check {
  opacity: 1;
}
.lib-row.host .desc::after {
  content: " · current";
  color: var(--accent);
  font-style: italic;
}
.group-body {
  overflow-y: auto;
  padding-right: 2px;
}
.group-body::-webkit-scrollbar {
  width: 5px;
}
.group-body::-webkit-scrollbar-thumb {
  background: rgba(var(--ink-rgb), 0.15);
  border-radius: 3px;
}
.group-body::-webkit-scrollbar-track {
  background: transparent;
}
.rail-foot {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid rgba(var(--ink-rgb), 0.1);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.rail-foot .count {
  font-size: 11px;
  color: var(--muted);
  opacity: 0.75;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}
.rail-sort {
  display: inline-flex;
  gap: 2px;
}
.sort-mini {
  background: transparent;
  border: 0;
  padding: 4px 9px;
  font-family: var(--sans);
  font-size: 11px;
  color: var(--muted);
  cursor: pointer;
  border-radius: 6px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  transition: all 0.12s;
}
.sort-mini:hover {
  color: var(--ink);
  background: rgba(var(--ink-rgb), 0.04);
}
.sort-mini.on {
  color: var(--ink);
  background: rgba(var(--ink-rgb), 0.07);
}
/* Pane is transparent — the body's gradient flows continuously
     * from rail to results, so the whole page reads as one surface. */
.pane {
  padding: 26px 0 60px;
}
/* ── Apple-style search bar ─────────────────────────────────
     * Pill-rounded translucent glass with refined inner highlight,
     * SF-Symbols magnifier on the left, sans-serif input (UI chrome
     * — never serif), and a soft accent ring on focus. */
/* ── Top-right action cluster (auth pill + theme toggle) ──────
     * Mirrors the welcome page's toolbar grouping: pill on the left,
     * compact theme button on the right, 0.6rem gap between them. */
.page-actions {
  position: fixed;
  top: 18px;
  right: 22px;
  z-index: 60;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}

/* Mobile-only drawer chrome — burger trigger, dimming backdrop,
 * in-drawer close button. Hidden on desktop; the @media block
 * below 768px overrides the display to surface them. */
.m-menu-btn,
.m-menu-backdrop,
.m-menu-close {
  display: none;
}

/* ── Profile pill ────────────────────────────────────────────
     * Identical visuals to `.auth-badge-me` on the welcome page, so
     * users see the same control no matter which view they're on. */
.auth-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 11px;
  background: rgba(var(--paper-rgb), 0.7);
  backdrop-filter: blur(14px) saturate(170%);
  -webkit-backdrop-filter: blur(14px) saturate(170%);
  border: 1px solid rgba(var(--ink-rgb), 0.1);
  border-radius: 999px;
  font-family: var(--sans);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: -0.005em;
  color: var(--ink);
  cursor: pointer;
  text-decoration: none;
  transition:
    background 0.15s ease,
    border-color 0.15s ease;
}
.auth-btn:hover {
  background: rgba(var(--paper-rgb), 0.94);
  border-color: rgba(var(--ink-rgb), 0.16);
}
.auth-btn img.av {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  object-fit: cover;
}
.auth-btn span {
  white-space: nowrap;
  letter-spacing: -0.005em;
}
.auth-btn.anon {
  padding: 0 14px;
  gap: 6px;
}
.auth-btn .gh {
  width: 13px;
  height: 13px;
  opacity: 0.85;
}
.auth-btn .gear-svg {
  width: 13px;
  height: 13px;
  color: var(--muted);
  opacity: 0.85;
  transition:
    transform 0.25s ease,
    opacity 0.15s ease,
    color 0.15s ease;
}
.auth-btn:hover .gear-svg {
  color: var(--accent);
  opacity: 1;
  transform: rotate(45deg);
}

/* Theme toggle — small rounded square, matching the welcome
     * page's `.welcome-theme-toggle`. Lives inside `.page-actions`,
     * so it just needs its own visuals; positioning is handled by
     * the flex parent. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.35rem;
  border: none;
  border-radius: 6px;
  background: rgba(var(--ink-rgb), 0.05);
  color: var(--muted);
  cursor: pointer;
  transition:
    background 0.15s ease,
    color 0.15s ease;
}
.theme-toggle:hover {
  background: rgba(var(--ink-rgb), 0.09);
  color: var(--ink);
}
.theme-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.theme-toggle svg {
  width: 14px;
  height: 14px;
  display: block;
}

/* ── Profile modal ────────────────────────────────────────── */
.profile-back {
  position: fixed;
  inset: 0;
  background: rgba(var(--ink-rgb), 0.42);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 90;
}
.profile-back.open {
  opacity: 1;
  pointer-events: auto;
}
.profile-modal {
  position: fixed;
  left: 50%;
  top: 6%;
  transform: translateX(-50%) scale(0.97);
  width: min(720px, calc(100% - 40px));
  max-height: 88vh;
  background: rgba(var(--paper-rgb), 0.94);
  backdrop-filter: blur(28px) saturate(180%);
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  border: 1px solid rgba(var(--ink-rgb), 0.1);
  border-radius: 22px;
  box-shadow:
    0 0 0 1px rgba(var(--ink-rgb), 0.04),
    0 32px 90px rgba(var(--ink-rgb), 0.18),
    0 12px 36px rgba(var(--ink-rgb), 0.1);
  display: none;
  flex-direction: column;
  z-index: 100;
  opacity: 0;
  transition:
    opacity 0.22s cubic-bezier(0.32, 0.72, 0, 1),
    transform 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
.profile-modal.open {
  display: flex;
  opacity: 1;
  transform: translateX(-50%) scale(1);
}

/* Full-page profile mode — toggled on <body> when openProfile()
     * runs. The page now reads as a real route: the search UI is
     * hidden, the modal becomes a static document on top of the
     * cream/dark editorial gradient (body bg shows through), with an
     * Apple-style sticky top bar and a magazine-y hero. */
body.profile-fullpage {
  overflow-y: auto;
}
body.profile-fullpage .layout > .rail,
body.profile-fullpage .layout > .pane,
body.profile-fullpage .layout > .sort-toggle,
body.profile-fullpage .layout > .theme-toggle,
body.profile-fullpage .layout > .auth-btn,
body.profile-fullpage .profile-back {
  display: none !important;
}
body.profile-fullpage .profile-modal.open {
  position: static;
  transform: none;
  width: 100%;
  max-width: none;
  max-height: none;
  min-height: 100vh;
  margin: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  opacity: 1;
}

/* Hero header — large editorial avatar on the left, serif title
     * stacked above the @handle subtitle, Back link sitting in a
     * sticky top strip so the user can always escape the page. */
body.profile-fullpage .profile-head {
  position: relative;
  width: 100%;
  max-width: none;
  margin: 0;
  padding: 80px 64px 36px;
  gap: 28px;
  align-items: flex-end;
  border-bottom: 1px solid rgba(var(--ink-rgb), 0.1);
}
body.profile-fullpage .profile-head::before {
  content: "";
  position: absolute;
  left: 64px;
  right: 64px;
  top: 60px;
  height: 1px;
  background: rgba(var(--ink-rgb), 0.06);
}
@media (max-width: 720px) {
  body.profile-fullpage .profile-head {
    padding: 80px 24px 28px;
  }
  body.profile-fullpage .profile-head::before {
    left: 24px;
    right: 24px;
  }
}
body.profile-fullpage .profile-head .av {
  width: 92px;
  height: 92px;
  box-shadow:
    0 0 0 4px rgba(var(--paper-rgb), 0.85),
    0 8px 28px rgba(var(--ink-rgb), 0.18);
}
body.profile-fullpage .profile-head h2 {
  font-size: 56px;
  font-weight: 500;
  letter-spacing: -0.028em;
  line-height: 1.02;
  margin: 0 0 8px;
}
body.profile-fullpage .profile-head .sub {
  font-size: 15px;
  color: var(--muted);
  letter-spacing: -0.005em;
}
body.profile-fullpage .profile-head .x {
  align-self: flex-start;
  margin-top: 4px;
}

/* Sticky page chrome — wordmark top-left, the existing .x close
     * button (rendered by the modal head) is repositioned to the
     * top-right corner so it reads as a "Back to libraries" pill. */
body.profile-fullpage::before {
  content: "Knowledge";
  position: fixed;
  top: 22px;
  left: 28px;
  font-family: var(--display);
  font-size: 17px;
  font-weight: 500;
  letter-spacing: -0.012em;
  color: var(--ink);
  pointer-events: none;
  z-index: 200;
}

/* Body — uses the full page width with generous padding; the
     * source cards flow as a responsive grid so wide displays show
     * 2-3 cards across instead of one narrow column. */
body.profile-fullpage .profile-body {
  width: 100%;
  max-width: none;
  margin: 0;
  padding: 28px 64px 140px;
  overflow: visible;
}
@media (max-width: 720px) {
  body.profile-fullpage .profile-body {
    padding: 28px 24px 140px;
  }
}
body.profile-fullpage .section-label {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 28px 0 14px;
  margin: 0;
  border-top: 0;
}
body.profile-fullpage .section-label:first-of-type {
  padding-top: 8px;
}
body.profile-fullpage .section-hint {
  color: var(--muted);
  font-size: 13.5px;
  margin: -6px 0 18px;
  max-width: 56ch;
}

/* Profile (Name / Bio / Twitter URL / Public toggle) — these are
     * direct children of the profile-body, mixed with .source-card
     * blocks. Keep the simple Profile section in a single column at
     * comfortable reading width, then let the Sources section break
     * out into a multi-column grid via the wrapping rule below. */
body.profile-fullpage .profile-body > .field,
body.profile-fullpage .profile-body > .toggle-field {
  max-width: 920px;
}

/* Source cards: pack a flowing CSS grid so wide screens show
     * multiple cards side-by-side. Each card auto-sizes between
     * 360px and 1fr, so the layout collapses to a single column on
     * narrow viewports without media queries. */
body.profile-fullpage .profile-body {
  display: grid;
  grid-template-columns: 1fr;
  column-gap: 18px;
  row-gap: 0;
}
body.profile-fullpage .profile-body > .section-label,
body.profile-fullpage .profile-body > .section-hint,
body.profile-fullpage .profile-body > .field,
body.profile-fullpage .profile-body > .toggle-field {
  grid-column: 1 / -1;
}
@media (min-width: 1100px) {
  body.profile-fullpage .profile-body {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 1600px) {
  body.profile-fullpage .profile-body {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

body.profile-fullpage .source-card {
  background: rgba(var(--paper-rgb), 0.66);
  border: 1px solid rgba(var(--ink-rgb), 0.1);
  border-radius: 16px;
  padding: 22px 24px;
  margin: 0 0 18px;
  box-shadow: 0 1px 3px rgba(var(--ink-rgb), 0.04);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  transition:
    border-color 0.15s ease,
    box-shadow 0.2s ease,
    transform 0.2s ease;
}
body.profile-fullpage .source-card:hover,
body.profile-fullpage .source-card:focus-within {
  border-color: rgba(var(--ink-rgb), 0.14);
  box-shadow: 0 4px 16px rgba(var(--ink-rgb), 0.07);
}
body.profile-fullpage .source-card-head {
  font-family: var(--display);
  font-size: 19px;
  font-weight: 500;
  letter-spacing: -0.012em;
  margin: 0 0 4px;
}
body.profile-fullpage .source-card-desc {
  color: var(--muted);
  font-size: 13px;
  line-height: 1.55;
  margin: 0 0 14px;
  max-width: 60ch;
}

/* Sticky footer — auto-save status / sync bar / sign-out button
     * pinned to the viewport so it's always reachable while the user
     * scrolls. Cream-glass treatment, content stretches across the
     * full page width to mirror the body grid. */
body.profile-fullpage .profile-foot {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 14px 64px 16px;
  background: rgba(var(--paper-rgb), 0.72);
  border-top: 1px solid rgba(var(--ink-rgb), 0.1);
  backdrop-filter: blur(18px) saturate(180%);
  -webkit-backdrop-filter: blur(18px) saturate(180%);
  z-index: 150;
}
@media (max-width: 720px) {
  body.profile-fullpage .profile-foot {
    padding: 14px 24px 16px;
  }
}
body.profile-fullpage .profile-foot .save-status {
  font-size: 12.5px;
}
body.profile-fullpage .profile-foot .actions {
  margin-left: auto;
}

/* Promote the existing close button into a sticky "Back" pill in
     * the top-right corner — the user can always escape, no matter
     * how far they've scrolled. Hide the in-hero clone so we only
     * show one back affordance. */
body.profile-fullpage .profile-head .x {
  display: none;
}
body.profile-fullpage #pfClose,
body.profile-fullpage .profile-modal.open .x[id="pfClose"] {
  position: fixed;
  top: 18px;
  right: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  height: auto;
  padding: 9px 16px;
  border-radius: 999px;
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--muted);
  background: rgba(var(--paper-rgb), 0.72);
  border: 1px solid rgba(var(--ink-rgb), 0.1);
  backdrop-filter: blur(14px) saturate(180%);
  -webkit-backdrop-filter: blur(14px) saturate(180%);
  cursor: pointer;
  z-index: 201;
}
body.profile-fullpage #pfClose:hover {
  color: var(--ink);
  background: rgba(var(--paper-rgb), 0.94);
  border-color: rgba(var(--ink-rgb), 0.14);
}
/* Replace the × glyph with a labelled chevron + "Back" text. */
body.profile-fullpage #pfClose svg {
  display: none;
}
body.profile-fullpage #pfClose::before {
  content: "‹  Back";
  font-feature-settings: "ss01";
}
.profile-head {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 26px 30px 22px;
  border-bottom: 1px solid rgba(var(--ink-rgb), 0.1);
}
.profile-head .av {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  box-shadow:
    0 0 0 2px rgba(var(--paper-rgb), 0.7),
    0 2px 8px rgba(var(--ink-rgb), 0.1);
}
.profile-head .meta {
  flex: 1;
  min-width: 0;
}
.profile-head h2 {
  font-family: var(--display);
  font-size: 26px;
  font-weight: 500;
  margin: 0 0 3px;
  letter-spacing: -0.018em;
  line-height: 1.15;
}
.profile-head .sub {
  font-size: 12.5px;
  color: var(--muted);
  letter-spacing: -0.005em;
}
.profile-head .x {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(var(--ink-rgb), 0.06);
  border: 0;
  cursor: pointer;
  color: var(--muted);
  display: grid;
  place-items: center;
  transition:
    background 0.15s ease,
    color 0.15s ease;
}
.profile-head .x:hover {
  background: rgba(var(--ink-rgb), 0.12);
  color: var(--ink);
}
.profile-head .x svg {
  width: 12px;
  height: 12px;
}

.profile-body {
  flex: 1;
  overflow-y: auto;
  padding: 14px 30px 4px;
}
.profile-body::-webkit-scrollbar {
  width: 5px;
}
.profile-body::-webkit-scrollbar-thumb {
  background: rgba(var(--ink-rgb), 0.15);
  border-radius: 3px;
}

.field {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 14px;
  align-items: center;
  padding: 9px 0;
}
.field.col {
  grid-template-columns: 110px 1fr;
  align-items: start;
}
.field label {
  font-size: 12px;
  color: var(--muted);
  font-weight: 500;
  letter-spacing: 0.02em;
  padding-top: 7px;
}
.field input[type="text"],
.field textarea {
  width: 100%;
  padding: 8px 12px;
  background: rgba(var(--ink-rgb), 0.04);
  border: 0;
  border-radius: 8px;
  font-family: var(--sans);
  font-size: 13.5px;
  color: var(--ink);
  outline: none;
  transition:
    background 0.15s ease,
    box-shadow 0.15s ease;
}
.field input[type="text"]:hover,
.field textarea:hover {
  background: rgba(var(--ink-rgb), 0.06);
}
.field input[type="text"]:focus,
.field textarea:focus {
  background: rgba(var(--paper-rgb), 0.96);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.16);
}
.field textarea {
  min-height: 70px;
  resize: vertical;
  line-height: 1.5;
}
.field .with-prefix {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  background: rgba(var(--ink-rgb), 0.04);
  border-radius: 8px;
  transition:
    background 0.15s ease,
    box-shadow 0.15s ease;
}
.field .with-prefix:hover {
  background: rgba(var(--ink-rgb), 0.06);
}
.field .with-prefix:focus-within {
  background: rgba(var(--paper-rgb), 0.96);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.16);
}
.field .with-prefix .prefix {
  font-size: 12px;
  color: var(--muted);
  user-select: none;
}
.field .with-prefix input {
  background: transparent !important;
  padding: 8px 0 !important;
  box-shadow: none !important;
}

/* Secret credential field — masked by default, with a small
     * lock prefix and a reveal toggle on the right. Used for HN
     * password, Twitter cookies, the Zotero API key. Same focus
     * ring as the text inputs so the form reads as one cohesive
     * object; mono font on the value so pasted credentials keep
     * their character-by-character shape and a stray space jumps
     * out instead of hiding behind kerned proportional glyphs. */
.field .secret {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 4px 0 12px;
  background: rgba(var(--ink-rgb), 0.04);
  border-radius: 8px;
  transition:
    background 0.15s ease,
    box-shadow 0.15s ease;
}
.field .secret:hover {
  background: rgba(var(--ink-rgb), 0.06);
}
.field .secret:focus-within {
  background: rgba(var(--paper-rgb), 0.96);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.16);
}
.field .secret > .secret-icon {
  color: var(--muted);
  flex-shrink: 0;
  opacity: 0.55;
  display: flex;
  align-items: center;
  margin-right: 2px;
  transition:
    opacity 0.15s ease,
    color 0.15s ease;
}
.field .secret:focus-within > .secret-icon {
  opacity: 0.85;
  color: var(--ink);
}
.field .secret input[type="password"],
.field .secret input[type="text"] {
  flex: 1;
  min-width: 0;
  background: transparent !important;
  border: 0 !important;
  padding: 8px 0 !important;
  margin: 0;
  font-family: ui-monospace, "SF Mono", "Menlo", monospace;
  font-size: 12.5px;
  letter-spacing: 0.06em;
  color: var(--ink);
  outline: none;
  box-shadow: none !important;
}
/* Stay roomy and readable when masked: the bullet glyph is
     * narrower than mono chars, so widen letter-spacing a touch
     * just for type=password to keep the dot rhythm even. */
.field .secret input[type="password"] {
  letter-spacing: 0.18em;
}
.field .secret input::placeholder {
  color: var(--muted);
  opacity: 0.6;
  font-family: var(--sans);
  font-size: 13px;
  letter-spacing: 0;
  font-style: italic;
}
/* Subtle "encrypted" affordance: a tiny key glyph that fades
     * in when the field is empty + unfocused, vanishes the moment
     * the user starts typing or focuses. Pure decoration. */
.field .secret-eye {
  background: transparent;
  border: 0;
  padding: 6px;
  margin: 0;
  border-radius: 6px;
  color: var(--muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition:
    background 0.12s ease,
    color 0.12s ease,
    opacity 0.12s ease;
  opacity: 0.45;
}
.field .secret:hover .secret-eye,
.field .secret:focus-within .secret-eye {
  opacity: 0.95;
}
.field .secret-eye:hover {
  background: rgba(var(--ink-rgb), 0.08);
  color: var(--ink);
}
.field .secret-eye:focus-visible {
  outline: 2px solid rgba(var(--accent-rgb), 0.4);
  outline-offset: 1px;
}
.field .secret-eye[aria-pressed="true"] {
  color: var(--accent);
  opacity: 1;
}
.field .secret-eye .eye-hide {
  display: none;
}
.field .secret-eye[aria-pressed="true"] .eye-show {
  display: none;
}
.field .secret-eye[aria-pressed="true"] .eye-hide {
  display: inline-block;
}

/* Section label — Newsreader display face, small accent dot, no
     * uppercase shouting. Matches the typographic register of the
     * welcome page's `pm-section-title`. */
.section-label {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--display);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -0.012em;
  color: var(--ink);
  padding: 22px 0 6px;
  border-top: 1px solid rgba(var(--ink-rgb), 0.1);
  margin-top: 12px;
}
.section-label::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
  flex-shrink: 0;
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.14);
}
.section-label:first-of-type {
  border-top: 0;
  padding-top: 4px;
  margin-top: 0;
}
.section-hint {
  font-size: 12.5px;
  color: var(--muted);
  margin: 0 0 14px;
  line-height: 1.55;
  max-width: 56ch;
  padding-left: 16px;
}

/* Per-source card — soft elevated tile grouping a source's
     * description, credentials, and tutorial. Hover lifts the card
     * subtly so it feels interactive even before you click an input. */
.source-card {
  padding: 16px 18px;
  margin: 0 0 14px;
  border: 1px solid rgba(var(--ink-rgb), 0.1);
  border-radius: 14px;
  background: rgba(var(--paper-rgb), 0.52);
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.source-card:hover,
.source-card:focus-within {
  background: rgba(var(--paper-rgb), 0.78);
  border-color: rgba(var(--ink-rgb), 0.12);
  box-shadow: 0 2px 10px rgba(var(--ink-rgb), 0.04);
}
.source-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--sans);
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 6px;
  letter-spacing: -0.012em;
}
.source-card-head img.icon {
  width: 15px;
  height: 15px;
  opacity: 0.9;
  border-radius: 3px;
}
.source-card-desc {
  font-size: 12px;
  color: var(--muted);
  line-height: 1.55;
  margin: 0 0 10px;
  max-width: 56ch;
}
.source-card-note {
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--muted);
  margin: 0 0 12px;
  padding: 7px 10px;
  border-left: 2px solid rgba(var(--accent-rgb), 0.4);
  background: rgba(var(--accent-rgb), 0.06);
  border-radius: 0 6px 6px 0;
  max-width: 56ch;
}
.source-card-note strong {
  color: var(--ink);
  font-weight: 600;
}
.source-card-desc code,
.tw-how code {
  background: rgba(var(--ink-rgb), 0.07);
  padding: 1px 5px;
  border-radius: 3px;
  font-family: ui-monospace, "SF Mono", monospace;
  font-size: 10.5px;
  color: var(--ink);
  letter-spacing: 0;
}
.source-card-desc a,
.tw-how a {
  color: var(--accent);
  text-decoration: none;
  font-weight: 500;
}
.source-card-desc a:hover,
.tw-how a:hover {
  text-decoration: underline;
}
.source-card .field {
  grid-template-columns: 90px 1fr;
  padding: 6px 0;
}
.source-card .field label {
  font-size: 11.5px;
  padding-top: 7px;
}

/* Websites probe status — per-line state list under the textarea
     * with kind badge, status message, and "narrow to:" subtree chips
     * for sitemaps that have multiple sections. */
.websites-status {
  list-style: none;
  padding: 0;
  margin: 8px 0 0;
  font-family: var(--sans);
  font-size: 12px;
}
.websites-status:empty {
  display: none;
}
.websites-status li {
  padding: 8px 0;
  border-top: 1px solid rgba(var(--ink-rgb), 0.1);
}
.websites-status li:first-child {
  border-top: 0;
  padding-top: 6px;
}
.websites-row {
  display: flex;
  gap: 12px;
  align-items: baseline;
  flex-wrap: wrap;
}
.websites-url {
  color: var(--ink);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: ui-monospace, "SF Mono", monospace;
  font-size: 11px;
  letter-spacing: 0;
}
.websites-msg {
  font-size: 11.5px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.websites-msg .kind {
  padding: 1px 7px;
  border-radius: 4px;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-family: var(--sans);
}
.websites-msg .kind.feed {
  background: rgba(255, 122, 24, 0.16);
  color: #b85209;
}
.websites-msg .kind.sitemap {
  background: rgba(42, 142, 79, 0.14);
  color: #2a8e4f;
}
.websites-status li.ok .websites-msg {
  color: #2a8e4f;
}
.websites-status li.bad .websites-msg {
  color: var(--accent);
}
.websites-status li.probing .websites-msg {
  color: var(--muted);
  opacity: 0.7;
}

.websites-subtrees {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 7px;
  align-items: center;
}
.websites-subtrees-label {
  font-size: 10.5px;
  color: var(--muted);
  font-style: italic;
  padding: 2px 4px 2px 0;
  letter-spacing: 0.01em;
}
.websites-chip {
  background: rgba(var(--ink-rgb), 0.05);
  border: 1px solid rgba(var(--ink-rgb), 0.1);
  padding: 2px 9px;
  border-radius: 999px;
  cursor: pointer;
  display: inline-flex;
  gap: 6px;
  align-items: center;
  font-family: var(--sans);
  font-size: 11px;
  color: var(--ink);
  transition: all 0.12s ease;
}
.websites-chip:hover {
  background: var(--accent);
  color: white;
  border-color: var(--accent);
}
.websites-chip code {
  font-family: ui-monospace, "SF Mono", monospace;
  font-size: 10.5px;
  background: transparent;
  padding: 0;
  color: inherit;
  border-radius: 0;
}
.websites-chip-count {
  color: var(--muted);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  transition: color 0.12s ease;
}
.websites-chip:hover .websites-chip-count {
  color: rgba(var(--paper-rgb), 0.85);
}

/* HN verify-login UI: small action button + inline status pill +
     * subtle disconnect text-link. Same Apple-segmented vibe as the
     * sort toggle so it doesn't add new visual language. */
.hn-verify-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 0 2px;
  margin-left: 90px;
}
.verify-btn {
  background: rgba(var(--ink-rgb), 0.06);
  border: 1px solid rgba(var(--ink-rgb), 0.1);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  padding: 6px 14px;
  border-radius: 7px;
  cursor: pointer;
  transition: all 0.15s ease;
  letter-spacing: -0.005em;
}
.verify-btn:hover {
  background: rgba(var(--ink-rgb), 0.1);
  border-color: rgba(var(--ink-rgb), 0.14);
}
.verify-btn:disabled {
  opacity: 0.5;
  cursor: default;
}
.verify-btn:active:not(:disabled) {
  transform: translateY(0.5px);
}

.verify-status {
  flex: 1;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--sans);
  font-size: 11.5px;
  color: var(--muted);
}
.verify-status:empty {
  display: none;
}
.verify-status.probing {
  color: var(--muted);
  opacity: 0.85;
}
.verify-status.ok {
  color: #2a8e4f;
}
.verify-status.bad {
  color: var(--accent);
}
.verify-status .glyph {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  display: inline-grid;
  place-items: center;
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  flex-shrink: 0;
}
.verify-status.probing .glyph {
  background: rgba(var(--ink-rgb), 0.06);
  color: var(--muted);
  animation: probe-spin 1s linear infinite;
}
.verify-status.ok .glyph {
  background: rgba(42, 142, 79, 0.15);
  color: #2a8e4f;
}
.verify-status.bad .glyph {
  background: rgba(var(--accent-rgb), 0.15);
  color: var(--accent);
}

.disconnect-link {
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: var(--sans);
  font-size: 11px;
  color: var(--muted);
  text-decoration: none;
  letter-spacing: -0.005em;
  transition: color 0.12s ease;
}
.disconnect-link:hover {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Connected badge that sits in the source-card header. */
.conn-badge {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(42, 142, 79, 0.12);
  color: #2a8e4f;
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.conn-badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #2a8e4f;
  box-shadow: 0 0 0 2px rgba(42, 142, 79, 0.18);
}
.conn-badge:empty {
  display: none;
}
.conn-badge.bad {
  background: rgba(var(--accent-rgb), 0.12);
  color: var(--accent);
}
.conn-badge.bad::before {
  background: var(--accent);
  box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 0.18);
}

/* Zotero connection summary — small panel with item counts that
     * appears between the description and the API-key field once the
     * key is verified. Same understated chip family as conn-badge. */
.zot-summary {
  display: none;
  margin: 0 0 12px;
  padding: 10px 12px;
  background: rgba(42, 142, 79, 0.07);
  border: 1px solid rgba(42, 142, 79, 0.15);
  border-radius: 8px;
  font-family: var(--sans);
  font-size: 12px;
  color: var(--ink);
  line-height: 1.5;
}
.zot-summary.show {
  display: block;
}
.zot-summary .row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 1px 0;
}
.zot-summary .row b {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.zot-summary .row .lib {
  color: var(--muted);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.zot-summary .row .count {
  color: #2a8e4f;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  font-size: 11px;
}
.zot-summary .total {
  padding-top: 6px;
  margin-top: 6px;
  border-top: 1px solid rgba(42, 142, 79, 0.18);
  font-weight: 600;
}

/* Browser-cookie tutorial — collapsed by default, accent toggle. */
.tw-how {
  margin: 0 0 12px;
  font-size: 12px;
  border-top: 1px solid rgba(var(--ink-rgb), 0.1);
  padding-top: 10px;
}
.tw-how summary {
  cursor: pointer;
  color: var(--accent);
  font-weight: 500;
  padding: 2px 0;
  user-select: none;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.tw-how summary::-webkit-details-marker {
  display: none;
}
.tw-how summary::before {
  content: "▸";
  transition: transform 0.18s ease;
  display: inline-block;
  font-size: 10px;
}
.tw-how[open] summary::before {
  transform: rotate(90deg);
}
.tw-how summary:hover {
  text-decoration: underline;
}
.tw-how ul {
  margin: 8px 0 0;
  padding-left: 22px;
  color: var(--muted);
}
.tw-how li {
  margin-bottom: 5px;
  line-height: 1.55;
}
.tw-how strong {
  color: var(--ink);
  font-weight: 600;
}

/* Probe indicator — sits to the right of each handle field. */
.probe-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
}
.probe-wrap > .with-prefix,
.probe-wrap > input {
  flex: 1;
}
.probe-status {
  flex-shrink: 0;
  min-width: 18px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--sans);
  font-size: 11.5px;
  font-weight: 500;
  color: var(--muted);
  letter-spacing: -0.005em;
  transition:
    color 0.15s ease,
    opacity 0.15s ease;
}
.probe-status.probing {
  color: var(--muted);
  opacity: 0.65;
}
.probe-status.ok {
  color: #2a8e4f;
}
.probe-status.bad {
  color: var(--accent);
}
.probe-status .glyph {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  display: inline-grid;
  place-items: center;
  font-size: 10px;
  font-weight: 700;
  line-height: 1;
}
.probe-status.ok .glyph {
  background: rgba(42, 142, 79, 0.15);
  color: #2a8e4f;
}
.probe-status.bad .glyph {
  background: rgba(var(--accent-rgb), 0.15);
  color: var(--accent);
}
.probe-status.probing .glyph {
  background: rgba(var(--ink-rgb), 0.06);
  color: var(--muted);
  animation: probe-spin 1s linear infinite;
}
@keyframes probe-spin {
  0%,
  100% {
    opacity: 0.4;
  }
  50% {
    opacity: 1;
  }
}
.probe-status .meta {
  font-size: 11px;
  opacity: 0.85;
  font-variant-numeric: tabular-nums;
}

/* Sync — button row + per-step list. */
.sync-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 4px 0 8px;
}
.sync-steps {
  list-style: none;
  padding: 0;
  margin: 6px 0 12px;
  font-family: var(--sans);
  font-size: 12px;
}
.sync-steps:empty {
  display: none;
}
.sync-steps li {
  display: grid;
  grid-template-columns: 18px 1fr auto;
  gap: 8px;
  padding: 4px 4px;
  align-items: center;
  color: var(--ink);
}
.sync-steps li .dot {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 10px;
  font-weight: 600;
  background: rgba(var(--ink-rgb), 0.06);
  color: var(--muted);
}
.sync-steps li.running .dot {
  background: rgba(var(--ink-rgb), 0.06);
  color: var(--muted);
  animation: probe-spin 1s linear infinite;
}
.sync-steps li.done .dot {
  background: rgba(42, 142, 79, 0.15);
  color: #2a8e4f;
}
.sync-steps li.error .dot {
  background: rgba(var(--accent-rgb), 0.15);
  color: var(--accent);
}
.sync-steps li .label {
  color: var(--ink);
}
.sync-steps li.done .label {
  color: var(--ink);
}
.sync-steps li.error .label {
  color: var(--accent);
  font-weight: 500;
}
.sync-steps li .count {
  color: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.toggle-field {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 0;
}
.toggle-field .label {
  font-size: 13.5px;
  color: var(--ink);
}
.toggle-field .hint {
  font-size: 11px;
  color: var(--muted);
}
.switch {
  position: relative;
  width: 40px;
  height: 24px;
  flex-shrink: 0;
  cursor: pointer;
}
.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}
.switch .track {
  position: absolute;
  inset: 0;
  background: rgba(var(--ink-rgb), 0.14);
  border-radius: 999px;
  transition: background 0.18s ease;
}
.switch .knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 20px;
  height: 20px;
  background: white;
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(var(--ink-rgb), 0.2);
  transition: transform 0.18s ease;
}
.switch input:checked + .track {
  background: var(--accent);
}
.switch input:checked + .track + .knob {
  transform: translateX(16px);
}

.profile-foot {
  padding: 14px 26px 18px;
  border-top: 1px solid rgba(var(--ink-rgb), 0.1);
  display: flex;
  gap: 12px;
  align-items: center;
}
.profile-foot .actions {
  margin-left: auto;
}
.pf-btn.ghost {
  background: rgba(var(--ink-rgb), 0.06);
  color: var(--ink);
}
.pf-btn.ghost:hover {
  background: rgba(var(--ink-rgb), 0.1);
  color: var(--ink);
}
.pf-btn.sync-btn {
  font-weight: 500;
}
.pf-btn.sync-btn:disabled {
  opacity: 0.65;
  cursor: progress;
}

/* Slim progress strip that takes the place of the auto-save status
     * while a sync is running. Apple-style: 4px track, accent fill,
     * one-line step text underneath. */
.foot-progress {
  flex: 1;
  display: none;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}
.foot-progress.show {
  display: flex;
}
.sync-bar {
  height: 4px;
  background: rgba(var(--ink-rgb), 0.07);
  border-radius: 999px;
  overflow: hidden;
}
.sync-bar-fill {
  height: 100%;
  width: 0%;
  background: var(--accent);
  transition: width 0.3s cubic-bezier(0.32, 0.72, 0, 1);
  border-radius: 999px;
}
.sync-step-text {
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
  letter-spacing: -0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Hide the auto-save status while progress is showing. */
.foot-progress.show ~ .save-status {
  display: none;
}
.save-status {
  font-size: 12px;
  color: var(--muted);
}
.save-status.ok {
  color: var(--accent);
}
.profile-foot .actions {
  display: flex;
  gap: 8px;
}
.pf-btn {
  background: transparent;
  border: 0;
  padding: 8px 14px;
  cursor: pointer;
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  border-radius: 8px;
  letter-spacing: 0.01em;
  transition: all 0.15s ease;
}
.pf-btn:hover {
  color: var(--ink);
  background: rgba(var(--ink-rgb), 0.05);
}
.pf-btn.danger:hover {
  color: var(--accent);
  background: rgba(var(--accent-rgb), 0.08);
}
.pf-btn.primary {
  background: var(--ink);
  color: white;
  padding: 8px 18px;
}
.pf-btn.primary:hover {
  background: var(--accent);
}

/* Floating segmented sort control — fixed bottom-right of the
     * viewport. Only meaningful when there's an active search query
     * (latest-mode is implicitly date-sorted), so it's hidden by
     * default and the JS reveals it via .show on every refresh. */
.sort-toggle {
  position: fixed;
  bottom: 24px;
  right: 28px;
  z-index: 50;
  gap: 2px;
  padding: 3px;
  background: rgba(var(--paper-rgb), 0.78);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(var(--ink-rgb), 0.1);
  border-radius: 10px;
  box-shadow:
    0 1px 0 rgba(var(--paper-rgb), 0.8) inset,
    0 12px 32px rgba(var(--ink-rgb), 0.1),
    0 2px 6px rgba(var(--ink-rgb), 0.04);
  display: none;
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity 0.18s ease,
    transform 0.18s ease;
}
.sort-toggle.show {
  display: inline-flex;
  opacity: 1;
  transform: translateY(0);
}
.sort-pill {
  background: transparent;
  border: 0;
  padding: 6px 14px;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
  cursor: pointer;
  border-radius: 7px;
  letter-spacing: -0.005em;
  transition: all 0.15s ease;
}
.sort-pill:hover:not(.on) {
  color: var(--ink);
}
.sort-pill.on {
  background: rgba(var(--paper-rgb), 0.96);
  color: var(--ink);
  box-shadow:
    0 1px 2px rgba(var(--ink-rgb), 0.08),
    0 0 0 0.5px rgba(var(--ink-rgb), 0.05);
}

/* (Original spotlight rule kept below as a base; search-row
     * overrides margin and adds the row layout.) */
.spotlight {
  max-width: 720px;
  margin-top: 0;
  margin-bottom: 30px;
  margin-left: max(44px, calc((100% - 1320px) / 2));
  margin-right: auto;
  position: relative;
  background: rgba(var(--paper-rgb), 0.86);
  backdrop-filter: blur(28px) saturate(180%);
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  border: 1px solid rgba(var(--ink-rgb), 0.08);
  border-radius: 14px;
  box-shadow:
    0 1px 0 rgba(var(--paper-rgb), 0.9) inset,
    0 0 0 1px rgba(var(--ink-rgb), 0.04),
    0 8px 24px rgba(var(--ink-rgb), 0.06),
    0 2px 6px rgba(var(--ink-rgb), 0.04);
  transition:
    box-shadow 0.2s ease,
    border-color 0.2s ease,
    background 0.2s ease;
}
.spotlight:hover {
  background: rgba(var(--paper-rgb), 0.92);
}
/* Dark-mode shadows: the base rules use rgba(var(--ink-rgb), …),
   which becomes a *white* drop shadow under the dark theme
   (`--ink` is near-white) and reads as a glowing halo around the
   bar. Replace with quiet black drops + faint accent ring so the
   bar still has depth without ever lighting up. */
[data-theme="dark"] .spotlight {
  border-color: rgba(255, 255, 255, 0.06);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.02) inset,
    0 8px 24px rgba(0, 0, 0, 0.32),
    0 2px 6px rgba(0, 0, 0, 0.2);
}
[data-theme="dark"] .spotlight:focus-within {
  background: rgba(var(--paper-rgb), 0.92);
  border-color: rgba(255, 255, 255, 0.08);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.02) inset,
    0 0 0 3px rgba(var(--accent-rgb), 0.12),
    0 12px 32px rgba(0, 0, 0, 0.36),
    0 2px 6px rgba(0, 0, 0, 0.22);
}
/* Active-tag chip strip — sits between the spotlight and the
   result list. One pill per active tag (emerald fill, white ink),
   with a × cancel glyph that drops the tag and re-runs the
   server-side filter. A "Clear all" pill appears once 2+ tags
   are active. The strip is hidden when state.tags is empty. */
/* Filter strip — wraps both the active-tag pills and the banned-
   source chips into one flex row so they sit on the same line
   (and wrap together) instead of stacking. Anchored to the same
   spotlight column so everything reads as one filter band under
   the search bar.

   The strip collapses to zero size when both children are hidden
   (`:has(> :not([hidden]))` flips the margins on/off). When any
   filter is active we open up generous space both above (so the
   strip detaches from the search bar) and below (so the first
   result has room to breathe). */
.filter-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0 max(44px, calc((100% - 1320px) / 2));
  max-width: 720px;
}
.filter-strip:has(> :not([hidden])) {
  margin-top: 14px;
  margin-bottom: 22px;
}
.filter-strip > [hidden] {
  display: none;
}

/* ── Query metrics pill ───────────────────────────────────────────
   Subtle row above the results list. Shows result count, query
   latency, and the candidate-pool size in three monospace segments
   separated by middots. Right-aligned within the same content
   column the result cards use, so it reads like a timing readout
   from a search engine console rather than a UI control. */
/* Lives in the rail footer (bottom-right of the left panel,
   under the Sources list). Compact one-line readout: "{n} results
   · {t} ms · {N} candidates". Inherits the rail-foot's `.count`
   color via the legacy class on the first segment, but stays a
   single line that wraps gracefully on narrow rails. */
.query-metrics {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  font-family: var(--sans);
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: rgba(var(--ink-rgb), 0.5);
  user-select: none;
}
.query-metrics[hidden] {
  display: none;
}
.qm-segment {
  white-space: nowrap;
}
.qm-time {
  color: rgba(var(--ink-rgb), 0.62);
  font-weight: 500;
}
.qm-results {
  color: rgba(var(--ink-rgb), 0.72);
  font-weight: 500;
}
.qm-sep {
  color: rgba(var(--ink-rgb), 0.25);
}
.active-tags {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0;
}
.active-tag {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 28px;
  padding: 0 6px 0 12px;
  background: var(--accent);
  color: white;
  border: 0;
  border-radius: 999px;
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.005em;
  cursor: pointer;
  box-shadow:
    0 1px 3px rgba(var(--accent-rgb), 0.22),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
  transition:
    background 0.15s ease,
    transform 0.15s ease,
    box-shadow 0.15s ease;
}
.active-tag:hover {
  background: color-mix(in srgb, var(--accent) 86%, #000 14%);
  transform: translateY(-1px);
  box-shadow:
    0 4px 10px rgba(var(--accent-rgb), 0.3),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
.active-tag svg {
  width: 12px;
  height: 12px;
  padding: 4px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.18);
  box-sizing: content-box;
  opacity: 0.9;
  transition:
    background 0.15s ease,
    opacity 0.15s ease;
}
.active-tag:hover svg {
  background: rgba(255, 255, 255, 0.32);
  opacity: 1;
}
.active-tag-clear {
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding: 0 14px;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition:
    color 0.15s ease,
    border-color 0.15s ease,
    background 0.15s ease;
}
.active-tag-clear:hover {
  color: var(--ink);
  border-color: rgba(var(--ink-rgb), 0.22);
  background: rgba(var(--ink-rgb), 0.04);
}

/* Result-sources strip — sits under the spotlight and lists up to
   five sources actually present in the current result set, plus any
   currently-banned sources so the user can restore them. */
.result-sources {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  align-items: center;
}
.result-source {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: rgba(var(--paper-rgb), 0.6);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition:
    color 0.15s ease,
    border-color 0.15s ease,
    background 0.15s ease,
    opacity 0.15s ease;
}
.result-source img {
  width: 14px;
  height: 14px;
  border-radius: 3px;
  flex-shrink: 0;
  opacity: 0.9;
}
.result-source-count {
  color: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  font-weight: 400;
}
.result-source svg {
  width: 12px;
  height: 12px;
  opacity: 0.55;
  transition:
    opacity 0.15s ease,
    color 0.15s ease;
}
.result-source:hover {
  border-color: rgba(220, 38, 38, 0.45);
  color: rgb(220, 38, 38);
  background: rgba(220, 38, 38, 0.06);
}
.result-source:hover svg {
  opacity: 1;
}
/* Banned chip — strike-through label, dim, and a circular-arrow icon
   instead of the ✕ so the action reads as "restore". */
.result-source.banned {
  color: var(--muted);
  border-color: var(--border);
  background: transparent;
  text-decoration: line-through;
  opacity: 0.75;
}
.result-source.banned:hover {
  color: var(--ink);
  border-color: rgba(var(--ink-rgb), 0.22);
  background: rgba(var(--ink-rgb), 0.04);
  text-decoration: none;
  opacity: 1;
}
.result-source.banned svg {
  opacity: 0.85;
}

.spotlight:focus-within {
  background: rgba(var(--paper-rgb), 0.98);
  border-color: rgba(var(--ink-rgb), 0.12);
  box-shadow:
    0 1px 0 rgba(var(--paper-rgb), 0.9) inset,
    0 0 0 4px rgba(var(--accent-rgb), 0.14),
    0 12px 32px rgba(var(--ink-rgb), 0.1),
    0 2px 6px rgba(var(--ink-rgb), 0.04);
}
.spotlight-mag {
  position: absolute;
  left: 20px;
  top: 50%;
  transform: translateY(-50%);
  width: 20px;
  height: 20px;
  color: var(--muted);
  opacity: 0.65;
  pointer-events: none;
  transition:
    opacity 0.18s ease,
    color 0.18s ease;
}
.spotlight:focus-within .spotlight-mag {
  color: var(--ink);
  opacity: 0.85;
}
.spotlight input {
  width: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  font-family: var(--sans);
  font-size: 16px;
  font-weight: 400;
  letter-spacing: -0.012em;
  color: var(--ink);
  padding: 12px 96px 12px 46px;
}
.spotlight input::placeholder {
  color: var(--muted);
  opacity: 0.55;
  font-weight: 400;
}
/* Re-ranker status pastille — anchored at the right end of the
     * search bar, a tiny coloured dot that signals where the
     * in-browser ColBERT model stands. Hidden until the worker
     * starts; orange (with a gentle pulse) while the model is
     * downloading; solid green once the model is ready and
     * re-ranking is live; dim red on any worker error. The native
     * title="" tooltip carries the verbose status string from the
     * worker's `status` events. */
.reranker-dot {
  position: absolute;
  /* Sits at the right edge of the bar when the input is empty.
       * When the user types, a CSS sibling rule below shifts it
       * left (`right: 42px`) so the appearing clear button doesn't
       * overlap it. */
  right: 18px;
  top: 50%;
  transform: translateY(-50%);
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: transparent;
  transition:
    background 0.2s ease,
    box-shadow 0.2s ease,
    opacity 0.2s ease;
  pointer-events: auto;
  cursor: help;
  opacity: 0;
}
.reranker-dot[data-state="loading"] {
  opacity: 1;
  background: #f59e0b;
  box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.45);
  animation: reranker-pulse 1.6s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.reranker-dot[data-state="ready"] {
  opacity: 1;
  background: #22c55e;
  box-shadow: 0 0 0 0 rgba(34, 197, 94, 0);
}
.reranker-dot[data-state="error"] {
  opacity: 0.85;
  background: #b91c1c;
}
@keyframes reranker-pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.55);
  }
  70% {
    box-shadow: 0 0 0 7px rgba(245, 158, 11, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(245, 158, 11, 0);
  }
}
/* Clear button — Apple's filled-circle xmark, anchored at the
     * very right of the bar. Hidden until the input has content. */
.spotlight input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}
.spotlight-clear {
  position: absolute;
  right: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 17px;
  height: 17px;
  background: rgba(var(--ink-rgb), 0.22);
  border: 0;
  padding: 0;
  cursor: pointer;
  border-radius: 50%;
  color: rgba(var(--paper-rgb), 0.96);
  display: none;
  align-items: center;
  justify-content: center;
  transition:
    background 0.12s ease,
    transform 0.12s ease;
}
.spotlight-clear svg {
  width: 9px;
  height: 9px;
  display: block;
}
.spotlight-clear:hover {
  background: rgba(var(--ink-rgb), 0.36);
}
.spotlight-clear:active {
  transform: translateY(-50%) scale(0.92);
}

/* Toggle: input not empty → show clear button. */
.spotlight input:not(:placeholder-shown) ~ .spotlight-clear {
  display: inline-flex;
}
/* When the clear button appears, shift the rerank dot leftward
     * so it doesn't sit on top of the clear button. (Clear is at
     * right:14 + 17px wide → its left edge is at right:31; the dot
     * at right:42 leaves an 11px gap.) */
.spotlight input:not(:placeholder-shown) ~ .reranker-dot {
  right: 42px;
}

/* ── Glass cards (mirrors the welcome page .document) ──────
     * Each result is its own translucent paper with the same
     * blur/border/radius/shadow as the welcome cards, so the body
     * mesh no longer flows through the result rows. The 1320 px
     * max-width + min-44 px gutter is now hosted on the container. */
.results {
  max-width: none;
  margin: 0;
  padding: 0 max(44px, calc((100% - 1320px) / 2));
  display: flex;
  flex-direction: column;
  gap: 0;
}
.result {
  padding: 32px 0 12px;
}
.result:first-child {
  padding-top: 0;
}
.result {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    "body body"
    "tags pics";
  gap: 24px 40px;
  align-items: start;
  position: relative;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  transition: background 0.25s ease;
}
.result + .result {
  border-top: 1px solid rgba(var(--ink-rgb), 0.08);
}
.result:hover {
  background: transparent;
  border-color: rgba(var(--ink-rgb), 0.08);
  transform: none;
  box-shadow: none;
}

/* ── Dark theme: same geometry as light, just a softer hover tint.
   The doc reads as text on the page field — no card, no shift in
   alignment between themes. The horizontal divider rule is
   inherited from the base `.result + .result` and uses
   `--border`, which already adapts. */
[data-theme="dark"] .result:hover {
  background: rgba(255, 255, 255, 0.02);
}
/* No character cap on the body — the summary uses all the room
     * the 1fr column gives it. */
.result-body {
  min-width: 0;
}
/* Kicker — Apple News style: small, tight tracking, sentence-cased
     * source name, separators are extra whitespace not glyphs. */
.result-kicker {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
  font-family: var(--sans);
  font-size: 12px;
  color: var(--muted);
  font-weight: 400;
  font-feature-settings:
    "tnum" 1,
    "ss01" 1;
}
.result-kicker .src-fav {
  width: 16px;
  height: 16px;
  border-radius: 4px;
  opacity: 0.95;
}
.result-kicker .src {
  color: var(--ink);
  font-weight: 600;
  letter-spacing: -0.005em;
}
/* Per-card ✕ — sits flush against the source label, hidden until
   the card is hovered so the kicker stays clean by default. Red on
   hover so the destructive intent reads. The kicker uses gap: 12px
   between sibling spans, which would push the ✕ too far from the
   source label — collapse the gap with a negative margin. */
.result-kicker .src-ban {
  margin-left: -8px;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  border-radius: 4px;
  display: inline-grid;
  place-items: center;
  opacity: 0;
  transition:
    opacity 0.12s,
    color 0.12s,
    background 0.12s;
}
.result:hover .src-ban,
.result:focus-within .src-ban {
  opacity: 0.55;
}
.result-kicker .src-ban:hover {
  opacity: 1;
  color: rgb(220, 38, 38);
  background: rgba(220, 38, 38, 0.1);
}
.result-kicker .dot {
  color: var(--muted);
  opacity: 0.4;
}
.result-kicker .date {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.005em;
}
.result-kicker .from {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.result-kicker .from img {
  width: 16px;
  height: 16px;
  border-radius: 50%;
}
/* Light-grey "not indexed yet" pill for docs that exist in PG but
     * haven't been embedded into the ColBERT index (just-synced
     * backlog awaiting `make run`). */
.result-kicker .pending {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px 8px;
  border-radius: 999px;
  background: rgba(var(--ink-rgb), 0.06);
  color: var(--muted);
  font-family: var(--sans);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.85;
}
.result-kicker .pending::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--muted);
  opacity: 0.6;
}
/* Tweet pill — replaces the source label on twitter docs.
     * Soft light fill at rest, snaps to solid ink on hover with a
     * tiny lift, very Apple action-button. */
.result-kicker .tweet-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 3px 11px 3px 9px;
  border-radius: 999px;
  background: rgba(var(--ink-rgb), 0.06);
  text-decoration: none;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: -0.005em;
  transition:
    background 0.18s ease,
    color 0.18s ease,
    transform 0.18s cubic-bezier(0.32, 0.72, 0, 1),
    box-shadow 0.18s ease;
}
.result-kicker .tweet-link:hover {
  background: var(--ink);
  color: white;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(var(--ink-rgb), 0.18);
}
.result-kicker .tweet-icon {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}

/* "via @handle" attribution — surfaces the originating tweet for
     * docs whose `source_url` is a tweet permalink (Twitter thread or
     * bookmark drove us to the resource). Quieter than `.tweet-link`
     * because it's secondary metadata, not the primary source label. */
.result-kicker .via-tweet {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px 2px 7px;
  border-radius: 999px;
  background: rgba(var(--ink-rgb), 0.04);
  color: var(--muted);
  text-decoration: none;
  font-family: var(--sans);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: -0.005em;
  transition:
    background 0.18s ease,
    color 0.18s ease;
}
.result-kicker .via-tweet:hover {
  background: rgba(var(--ink-rgb), 0.1);
  color: var(--ink);
}
.result-kicker .via-tweet .tweet-icon {
  width: 11px;
  height: 11px;
  opacity: 0.7;
}
.result-kicker .via-tweet:hover .tweet-icon {
  opacity: 1;
}
/* Bottom-right meta strip — when a document appears in multiple
     * library results, an avatar stack of the *other* people whose
     * libraries also have it sits to the LEFT of the score, with a
     * comfortable gap between them. */
.result-foot-right {
  grid-area: pics;
  display: flex;
  align-items: center;
  gap: 10px;
  pointer-events: auto;
  justify-self: end;
  /* The grid sets `align-items: start`, so the score badge (small
     content) anchors to the top of its row while the Related pill
     in the tags row sits taller. Centering this cell within its
     grid row puts the score badge on the same horizontal centerline
     as the Related pill on the right. */
  align-self: center;
}

/* Shared-by stack — sits inline at the right end of the kicker
     * row, near the title. Bigger than the old bottom-right pile so
     * it reads as "this is in these people's libraries too" at a
     * glance, without dominating the card. Single-library mode
     * renders nothing (no other owners exist), so this whole
     * affordance is opt-in to multi-library views by construction. */
.result .shared-by {
  display: inline-flex;
  align-items: center;
  padding: 0;
  gap: 0;
}
/* Each avatar: a real <a> linking to the personality, so a
     * cmd-click opens their library. White ring against the warm
     * page background gives a magazine-credit feel; soft shadow
     * separates overlapping discs. */
.result .shared-by .ava {
  position: relative;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  margin-left: -5px;
  background: white;
  box-shadow:
    0 0 0 1.5px #ffffff,
    0 0 0 2.5px var(--border),
    0 1px 3px rgba(var(--ink-rgb), 0.08);
  overflow: visible;
  transition:
    transform 0.22s cubic-bezier(0.32, 0.72, 0, 1),
    box-shadow 0.22s cubic-bezier(0.32, 0.72, 0, 1),
    z-index 0s 0.22s;
  cursor: pointer;
  text-decoration: none;
  z-index: 1;
}
.result .shared-by .ava:first-child {
  margin-left: 0;
}
.result .shared-by .ava img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}
.result .shared-by .ava:hover {
  transform: translateY(-2px) scale(1.08);
  z-index: 10;
  box-shadow:
    0 0 0 1.5px #ffffff,
    0 0 0 2.5px var(--border),
    0 8px 18px rgba(var(--ink-rgb), 0.18);
  transition:
    transform 0.22s cubic-bezier(0.32, 0.72, 0, 1),
    box-shadow 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
/* Apple-style dark-glass name tooltip with a caret. Pops above
     * the avatar on hover; sized for the slightly bigger discs. */
.result .shared-by .ava::after {
  content: attr(data-name);
  position: absolute;
  bottom: calc(100% + 12px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: rgba(var(--ink-rgb), 0.94);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: white;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  padding: 6px 12px;
  border-radius: 8px;
  white-space: nowrap;
  letter-spacing: -0.005em;
  pointer-events: none;
  opacity: 0;
  transition:
    opacity 0.2s cubic-bezier(0.32, 0.72, 0, 1),
    transform 0.2s cubic-bezier(0.32, 0.72, 0, 1);
  box-shadow: 0 6px 18px rgba(var(--ink-rgb), 0.22);
  z-index: 11;
}
.result .shared-by .ava::before {
  content: "";
  position: absolute;
  bottom: calc(100% + 4px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  border: 5px solid transparent;
  border-top-color: rgba(var(--ink-rgb), 0.94);
  pointer-events: none;
  opacity: 0;
  transition:
    opacity 0.2s cubic-bezier(0.32, 0.72, 0, 1),
    transform 0.2s cubic-bezier(0.32, 0.72, 0, 1);
  z-index: 11;
}
.result .shared-by .ava:hover::after,
.result .shared-by .ava:hover::before {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
/* Overflow chip — same size & treatment as the avatars but a
     * subtle muted fill with a "+N" label. */
.result .shared-by .more {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  margin-left: -5px;
  background: rgba(var(--ink-rgb), 0.06);
  color: var(--muted);
  display: grid;
  place-items: center;
  font-size: 8.5px;
  font-weight: 600;
  font-family: var(--sans);
  letter-spacing: -0.01em;
  box-shadow:
    0 0 0 2px var(--bg-a),
    0 2px 5px rgba(var(--ink-rgb), 0.08);
}

/* Retrieval score — quiet light-grey mono digits, sits at the
     * right end of the foot strip. */
.result-foot-right .score {
  font-family: ui-monospace, "SF Mono", "Menlo", monospace;
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
  opacity: 0.5;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  transition:
    color 0.25s ease,
    opacity 0.25s ease;
}
/* Re-ranker score — bolder ink, full opacity, accent-tinted.
     * Marks rows the in-browser ColBERT pass has scored, so during
     * the streaming rerank the user can watch the bolder values
     * climb the list as they're computed. */
.result-foot-right .score.reranked {
  color: var(--accent);
  opacity: 0.85;
}
/* Title — Newsreader, slightly larger, very tight tracking & lh */
.result h3 {
  font-family: var(--modern);
  /* Google-style result title: 20px, regular-to-medium weight,
     ~26px line-height. Tighter tracking matches the SF Pro
     fallback at this size. */
  font-size: 20px;
  font-weight: 500;
  margin: 0 0 12px;
  letter-spacing: -0.018em;
  line-height: 1.3;
  color: var(--ink);
}
.result h3 a {
  transition: color 0.15s;
}
.result h3 a:hover {
  color: var(--accent);
}
/* Summary — refined sans, justified with hyphenation so both edges
     * align cleanly without giant word-gaps (newspaper typography). */
.result-summary {
  font-family: var(--modern);
  /* Google-style snippet: 14px, ~1.58 line-height, slightly muted
     ink so the title carries the visual hierarchy. */
  font-size: 14px;
  line-height: 1.58;
  color: rgba(var(--ink-rgb), 0.72);
  margin: 0;
  font-weight: 400;
  letter-spacing: -0.005em;
  text-align: justify;
  text-justify: inter-word;
  hyphens: auto;
  -webkit-hyphens: auto;
}
/* Real-time enhancer — when a richer description lands from the
     * page's `<meta>` tags, the swap fades in so the user notices
     * the upgrade without it feeling jumpy. */
.result-summary.enhanced {
  animation: summary-enrich 0.32s cubic-bezier(0.32, 0.72, 0, 1);
}
@keyframes summary-enrich {
  from {
    opacity: 0.4;
  }
  to {
    opacity: 1;
  }
}
/* Highlight wrapper for query matches inside titles + summaries.
     * Soft accent-tinted background; the negative side-margins offset
     * the inner padding so highlights don't disturb line height. */
.result mark.hl {
  all: unset;
  /* Token color only — same emerald as the reranker score (var(--accent)). */
  color: var(--accent);
  font-weight: 600;
}

/* Tags row — wraps the tag pills *and* the "More like this"
   * affordance. Tags grow to the left edge; the similar-pill
   * gets pushed to the right via `margin-left: auto`. Both wrap
   * gracefully on narrow viewports. */
.result-tags-row {
  grid-area: tags;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
.result-body {
  grid-area: body;
}

/* Tags — soft pill style, no hashes, very subtle background */
.result-tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px;
  /* margin-top is now owned by `.result-tags-row` so it doesn't
     * stack on top of an outer parent's spacing. */
}

/* "More like this" pill — primary CTA on the card now. Quiet at
   * rest (matches the tag pills' weight) but accent-tinted on
   * hover and stays accent when its panel is expanded. The
   * chevron flips 180° via `aria-expanded="true"` so the same
   * pill reads as both "open" and "close". */
.result-similar {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px 5px 13px;
  border: 1px solid rgba(var(--ink-rgb), 0.1);
  border-radius: 999px;
  background: rgba(var(--ink-rgb), 0.04);
  color: rgba(var(--ink-rgb), 0.78);
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition:
    background 0.18s ease,
    color 0.18s ease,
    border-color 0.18s ease,
    transform 0.18s cubic-bezier(0.32, 0.72, 0, 1);
}
.result-similar:hover {
  background: rgba(var(--accent-rgb), 0.08);
  border-color: rgba(var(--accent-rgb), 0.25);
  color: var(--accent);
  transform: translateY(-1px);
}
.result-similar[aria-expanded="true"],
.result-similar.on {
  background: rgba(var(--accent-rgb), 0.1);
  border-color: rgba(var(--accent-rgb), 0.3);
  color: var(--accent);
}
.result-similar:focus-visible {
  outline: 2px solid rgba(var(--accent-rgb), 0.4);
  outline-offset: 2px;
}
.result-similar-label {
  white-space: nowrap;
}
.result-similar-chev {
  width: 13px;
  height: 13px;
  transition: transform 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
.result-similar[aria-expanded="true"] .result-similar-chev,
.result-similar.on .result-similar-chev {
  transform: rotate(180deg);
}
.result-tag {
  background: rgba(var(--ink-rgb), 0.05);
  border: 0;
  padding: 5px 13px;
  cursor: pointer;
  color: rgba(var(--ink-rgb), 0.72);
  font-family: var(--modern);
  font-size: 12.5px;
  border-radius: 999px;
  font-weight: 500;
  letter-spacing: -0.008em;
  transition: all 0.15s ease;
}
.result-tag:hover,
.result-tag.active {
  background: var(--accent);
  color: white;
}
/* When the tag pill is hovered or active (green fill, white text),
   force the matched-token highlight inside it to white too,
   otherwise the emerald-on-emerald disappears. */
.result-tag:hover mark.hl,
.result-tag.active mark.hl {
  color: #ffffff;
}
/* ── Find-similar inline panel ──────────────────────────────
     * Spans the full width of the card (grid-column 1 / -1) and
     * collapses cleanly via max-height. Header + sparkle accent +
     * a column of compact rows; loading state has 3 pulsing dots. */
.similar-panel {
  grid-column: 1 / -1;
  max-height: 0;
  overflow: hidden;
  opacity: 0;
  transition:
    max-height 0.35s cubic-bezier(0.32, 0.72, 0, 1),
    opacity 0.25s ease,
    margin-top 0.25s ease;
  margin-top: 0;
}
.similar-panel.open {
  max-height: 1200px; /* generous; collapses to actual content */
  opacity: 1;
  margin-top: 28px;
}
.similar-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-bottom: 14px;
  border-bottom: 1px solid rgba(var(--ink-rgb), 0.1);
  font-family: var(--sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.similar-head .spark {
  width: 14px;
  height: 14px;
  color: var(--accent);
  flex-shrink: 0;
}
.similar-head .target {
  font-style: italic;
  font-weight: 400;
  color: var(--ink);
  text-transform: none;
  letter-spacing: 0;
  opacity: 0.6;
}
.similar-head .target b {
  font-weight: 500;
  color: var(--ink);
  opacity: 1;
}
.similar-loading {
  display: inline-flex;
  gap: 4px;
  margin-left: auto;
}
.similar-loading span {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--muted);
  opacity: 0.4;
  animation: similar-pulse 1.2s ease-in-out infinite;
}
.similar-loading span:nth-child(2) {
  animation-delay: 0.15s;
}
.similar-loading span:nth-child(3) {
  animation-delay: 0.3s;
}
@keyframes similar-pulse {
  0%,
  80%,
  100% {
    opacity: 0.25;
    transform: scale(0.85);
  }
  40% {
    opacity: 1;
    transform: scale(1);
  }
}

.similar-list {
  padding-top: 8px;
  display: flex;
  flex-direction: column;
}
.similar-row {
  display: grid;
  grid-template-columns: 28px 1fr auto auto auto;
  gap: 14px;
  align-items: center;
  padding: 10px 8px;
  border-radius: 10px;
  color: inherit;
  text-decoration: none;
  transition: background 0.12s ease;
  position: relative;
}
.similar-row:hover {
  background: rgba(var(--ink-rgb), 0.04);
}
.similar-row .ico {
  width: 28px;
  height: 28px;
  border-radius: 7px;
  background: rgba(var(--ink-rgb), 0.05);
  display: grid;
  place-items: center;
  overflow: hidden;
}
.similar-row .ico img {
  width: 18px;
  height: 18px;
}
.similar-row .body {
  min-width: 0;
}
.similar-row h4 {
  font-family: var(--display);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.25;
  margin: 0 0 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--ink);
}
.similar-row:hover h4 {
  color: var(--accent);
}
.similar-row .meta {
  font-family: var(--sans);
  font-size: 11.5px;
  color: var(--muted);
  display: inline-flex;
  gap: 8px;
  align-items: center;
}
.similar-row .meta .src {
  font-weight: 600;
  color: rgba(var(--ink-rgb), 0.7);
  letter-spacing: -0.005em;
}
.similar-row .meta .dot {
  opacity: 0.4;
}
.similar-row .from-ava {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  vertical-align: middle;
  margin-right: 4px;
}
.similar-row .similar-score {
  font-family: ui-monospace, "SF Mono", monospace;
  font-size: 10.5px;
  font-weight: 500;
  color: var(--muted);
  opacity: 0.5;
  font-variant-numeric: tabular-nums;
}
.similar-row .similar-fav {
  width: 26px;
  height: 26px;
  border-radius: 7px;
  flex-shrink: 0;
  opacity: 0.55;
  transition:
    opacity 0.15s ease,
    color 0.15s ease,
    background 0.15s ease;
}
.similar-row:hover .similar-fav {
  opacity: 1;
}
.similar-row .similar-fav.on {
  opacity: 1;
}
.similar-row .arrow {
  color: var(--muted);
  opacity: 0;
  transform: translateX(-3px);
  transition:
    opacity 0.15s ease,
    transform 0.15s ease;
}
.similar-row:hover .arrow {
  opacity: 0.7;
  transform: translateX(0);
  color: var(--accent);
}
.similar-empty {
  padding: 18px 8px;
  font-family: var(--display);
  font-style: italic;
  color: var(--muted);
  font-size: 14px;
}

/* Action buttons — pinned to the top-right corner of each result
     * card. A horizontal pair instead of the old vertical stack:
     * tighter cluster, doesn't overlap the score / owner-avatars
     * meta strip in the bottom-right. Hidden until the row is
     * hovered to keep the page calm; an *active* favorite stays
     * visible because saved state is more useful than calm. */
.result-actions {
  position: absolute;
  top: 26px;
  /* Align horizontally with the bottom-right score cluster so the
       * top + bottom right edges of every result card visually agree. */
  right: max(44px, calc((100% - 1320px) / 2));
  display: inline-flex;
  align-items: center;
  gap: 4px;
  opacity: 0;
  transition: opacity 0.2s ease;
}
.result:hover .result-actions,
.result-actions:focus-within {
  opacity: 1;
}
.act {
  width: 28px;
  height: 28px;
  display: inline-grid;
  place-items: center;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition:
    background 0.15s ease,
    color 0.15s ease,
    transform 0.18s cubic-bezier(0.32, 0.72, 0, 1);
}
.act svg {
  width: 15px;
  height: 15px;
  display: block;
}
.act:hover {
  background: rgba(var(--ink-rgb), 0.07);
  color: var(--ink);
  transform: translateY(-1px);
}
.act:active {
  transform: translateY(0);
}
.act:focus-visible {
  outline: 2px solid rgba(var(--accent-rgb), 0.4);
  outline-offset: 1px;
}
/* Favourite, when active: filled heart, accent colour, kept
     * visible even when the row isn't hovered. */
.act-fav.on {
  color: var(--accent);
}
.act-fav.on:hover {
  background: rgba(var(--accent-rgb), 0.1);
}
.result .act-fav.on {
  /* Punch through the parent row's opacity:0 so a saved row
       * always shows its heart at rest. */
  opacity: 1;
}
.result:not(:hover) .result-actions:has(.act-fav.on) {
  opacity: 1;
}
/* The above :has rule covers most modern browsers; the fallback
     * below makes sure the row's whole `.result-actions` cluster
     * stays visible whenever any child is .on, even pre-:has. */
.result-actions .act-fav.on ~ .act,
.result-actions .act-fav.on {
  opacity: 1;
}

.state {
  text-align: center;
  padding: 60px 0;
  color: var(--muted);
  font-family: var(--display);
  font-style: italic;
  font-size: 22px;
}
.lib-empty[hidden] {
  display: none !important;
}
.lib-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 14px;
  padding: 80px 24px;
  /* Sit in the same horizontal box as the spotlight search bar so
     the empty state reads as "centered under the search". The
     calc/margin pair mirrors `.spotlight` exactly. */
  max-width: 720px;
  margin-left: max(44px, calc((100% - 1320px) / 2));
  margin-right: auto;
  font-style: normal;
}
.lib-empty svg {
  width: 56px;
  height: 56px;
  color: rgba(var(--ink-rgb), 0.18);
}
.lib-empty h2 {
  font-family: var(--display);
  font-size: 28px;
  font-weight: 500;
  letter-spacing: -0.012em;
  color: var(--ink);
  margin: 0;
  font-style: normal;
}
.lib-empty p {
  font-family: var(--sans);
  font-size: 14px;
  color: var(--muted);
  margin: 0;
  letter-spacing: -0.005em;
}
.lib-empty-add {
  margin-top: 6px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 36px;
  padding: 0 18px;
  border-radius: 999px;
  background: var(--accent);
  color: #ffffff;
  border: 1px solid var(--accent);
  font-family: var(--sans);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.005em;
  cursor: pointer;
  box-shadow:
    0 1px 3px rgba(var(--accent-rgb), 0.22),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
  transition:
    background 0.15s ease,
    transform 0.15s ease,
    box-shadow 0.15s ease;
}
.lib-empty-add svg {
  width: 14px;
  height: 14px;
  color: currentColor;
}
.lib-empty-add:hover {
  background: color-mix(in srgb, var(--accent) 86%, #000 14%);
  transform: translateY(-1px);
  box-shadow:
    0 6px 14px rgba(var(--accent-rgb), 0.3),
    inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
@media (max-width: 880px) {
  .layout {
    grid-template-columns: 100%;
  }
  .rail {
    position: relative;
    top: 0;
    height: auto;
  }
  #grpLibs {
    max-height: none;
  }
}

/* ============================================================
   Mobile (≤768px) — phone layout overrides only.
   Purely additive: every rule below sits inside a media query
   so the desktop UI is untouched. Goals:
     - Single column, no rail clutter (libraries open via the
       picker modal, source filters become a horizontal strip)
     - Spotlight and content hug 14px gutters
     - Result cards trim padding + tighten typography
     - Picker / profile modals fill the screen
     - Search input stays ≥16px so iOS doesn't zoom on focus
   ============================================================ */
@media (max-width: 768px) {
  /* ── Mobile drawer ───────────────────────────────────────────
   * The rail becomes a slide-in drawer from the right; a ☰ pill
   * floats at the top right of the page; tapping it slides the
   * drawer in over a dimmed backdrop. The page-actions cluster
   * (auth, theme, MCP, bookmark) is moved into the drawer at boot
   * by the inline script in search.html so every control lives in
   * one column.
   * ──────────────────────────────────────────────────────────── */
  .m-menu-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    /* Standard mobile FAB metrics — 56 × 56 with a 24 px icon
     * (Material's "regular" floating action button). Stays
     * within thumb reach for one-handed phone use. */
    bottom: 22px;
    right: 18px;
    z-index: 70;
    width: 56px;
    height: 56px;
    padding: 0;
    background: rgba(var(--paper-rgb), 0.96);
    backdrop-filter: blur(14px) saturate(170%);
    -webkit-backdrop-filter: blur(14px) saturate(170%);
    border: 1px solid rgba(var(--ink-rgb), 0.08);
    border-radius: 999px;
    color: var(--ink);
    cursor: pointer;
    box-shadow:
      0 6px 16px rgba(0, 0, 0, 0.14),
      0 2px 4px rgba(0, 0, 0, 0.06);
  }
  .m-menu-btn svg {
    width: 24px;
    height: 24px;
  }
  .m-menu-btn svg {
    width: 18px;
    height: 18px;
  }
  body.drawer-open .m-menu-btn {
    /* Hide the trigger while the drawer is open — the in-drawer ×
     * is the only dismiss control while open. */
    display: none;
  }

  .m-menu-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 80;
    opacity: 0;
    transition: opacity 0.2s ease;
  }
  body.drawer-open .m-menu-backdrop {
    opacity: 1;
  }
  .m-menu-backdrop[hidden] {
    /* hidden attribute kept on close for screen readers; CSS
     * still fades via the body class. */
  }

  /* `.m-menu-close` styling lives in the unified `.rail-back,
   * .m-menu-close` selector groups above (desktop) and below
   * (mobile-pill metrics) so the two pills are byte-identical. */

  /* Rail = drawer. Off-screen at right by default; slides in when
   * `body.drawer-open`. Full vertical height, fixed 320px wide
   * (capped at 86vw on tiny screens).
   *
   * Layout: a single flex-wrap container so the top-row pills
   * (close, All libraries, sign-in, theme, …) flow together on
   * one shared baseline. Section elements (groups, lib-add) are
   * forced to their own rows below via `flex-basis: 100%` + a
   * higher `order` so the flex wrap sequence is:
   *   row 1 → drawer header (the controls user wants aligned)
   *   row 2+ → groups in source order. */
  .rail {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 90;
    width: min(320px, 86vw);
    height: 100vh;
    padding: 14px 16px;
    border: 0;
    border-left: 1px solid var(--border);
    background: rgba(var(--paper-rgb), 0.98);
    backdrop-filter: blur(20px) saturate(180%);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    transform: translateX(100%);
    transition: transform 0.25s cubic-bezier(0.2, 0.8, 0.2, 1);
  }
  body.drawer-open .rail {
    transform: translateX(0);
  }

  /* `display: contents` flattens page-actions into the rail's
   * flex layout, so its individual pills (Bookmark, MCP) sit on
   * the same row as the Close + "All libraries" pills. Sign in
   * and theme toggle are hidden on mobile — the welcome page is
   * the canonical place to authenticate / switch theme. */
  .rail .page-actions {
    display: contents;
  }
  .rail .auth-btn,
  .rail .theme-toggle {
    display: none;
  }
  .rail .kb-trigger {
    height: 26px;
    padding: 0 11px;
    font-size: 11.5px;
    flex: 0 0 auto;
  }

  /* Avatar lift on hover/focus is shared with desktop above; the
   * `:active` state additionally amplifies the row background on
   * touch press since touch devices don't fire `:hover`. */
  .rail .lib-row:active {
    background: rgba(var(--ink-rgb), 0.06);
  }
  .rail .lib-row:active .ava {
    box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 0.45);
    transform: scale(1.05);
  }

  /* Mobile pill metrics for "All libraries". */
  .rail-back {
    flex: 0 0 auto;
    margin: 0;
    height: 26px;
    padding: 0 11px;
    border-radius: 999px;
    font-size: 11.5px;
  }
  .rail-back svg {
    width: 13px;
    height: 13px;
  }

  /* Bare × cross — sits on the same flex row as the
   * "All libraries" pill, pushed to the far right via
   * `margin-left: auto`. Rail-back has DOM-order 2, the cross
   * comes first in DOM but `order: 3` puts it after rail-back
   * in the visual layout while staying on the same row. */
  .m-menu-close {
    order: 3;
    flex: 0 0 auto;
    align-self: center;
    margin: 0 0 0 auto;
    width: 28px;
    height: 28px;
    padding: 0;
    background: transparent;
    border: 0;
    color: var(--muted);
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.12s ease;
  }
  .m-menu-close:hover {
    color: var(--ink);
  }
  .m-menu-close svg {
    width: 18px;
    height: 18px;
  }
  /* Rail-back leads the row; Bookmark / MCP wrap to row 2 via
   * default order:0 vs higher orders elsewhere. Setting
   * rail-back's order to 2 makes it visually after the (DOM-first)
   * close button when its margin-left: auto is computed. */
  .rail-back {
    order: 2;
  }
  .rail .kb-trigger {
    order: 4;
  }

  /* Section blocks below the header row — each forced to a fresh
   * row via flex-basis 100%, ordered AFTER the inline pills so
   * the wrap sequence stays predictable regardless of DOM order. */
  .rail #grpLibs,
  .rail #grpSrc {
    flex-basis: 100%;
    order: 10;
  }
  /* On mobile, the `+` add-library pill is redundant — tapping
   * any personality row in the libraries list opens the same
   * picker. Hide it to keep the drawer clean. */
  .rail .lib-add-btn {
    display: none;
  }

  /* Libraries + Sources groups: surface their group-head + search
   * input on mobile so the user has the same controls as desktop;
   * lists scroll inside the drawer's natural overflow. */
  #grpLibs,
  #grpSrc {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }
  #grpLibs > .group-head,
  #grpSrc > .group-head {
    display: flex;
  }
  #grpLibs > .group-body,
  #grpSrc > .group-body {
    display: block;
  }
  /* Drop the rail-foot (duplicates info shown elsewhere). */
  .rail-foot {
    display: none;
  }

  /* — Pane + spotlight ————————————————————————————— */
  .pane {
    padding: 14px 0 80px;
  }
  .spotlight {
    margin-left: 14px;
    margin-right: 14px;
    margin-bottom: 16px;
    max-width: none;
  }
  .spotlight input {
    /* 16px is the iOS auto-zoom threshold — don't dip below it. */
    font-size: 16px;
    padding: 11px 86px 11px 42px;
  }
  .spotlight-mag {
    left: 14px;
  }

  /* — Filter strip + results gutter ————————————————— */
  .filter-strip {
    margin-left: 14px;
    margin-right: 14px;
    max-width: none;
  }
  .results {
    padding: 0 14px;
  }
  .lib-empty {
    margin-left: 14px;
    margin-right: 14px;
    max-width: none;
    padding: 60px 8px;
  }
  .lib-empty h2 {
    font-size: 22px;
  }

  /* — Result cards: turn the divider list into actual cards on
     phones. Each result gets a soft surface, rounded corners, and
     a tap highlight; the inter-result `border-top` divider is
     suppressed in favor of vertical gap between cards. Internal
     grid keeps the same three-row structure (body / tags /
     similar+score). */
  .results {
    gap: 12px;
  }
  .result {
    padding: 16px 14px 12px;
    background: var(--bg-glass, rgba(var(--ink-rgb), 0.025));
    border: 1px solid rgba(var(--ink-rgb), 0.08);
    border-radius: 14px;
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "body  body"
      "tags  tags"
      ".     score";
    gap: 12px 10px;
    transition:
      background 0.15s ease,
      transform 0.15s ease;
  }
  .result:first-child {
    padding-top: 16px;
  }
  /* Cards already separate visually — drop the inter-row line. */
  .result + .result {
    border-top: 0;
  }
  /* Subtle press feedback on touch. */
  .result:active {
    transform: scale(0.995);
    background: rgba(var(--ink-rgb), 0.04);
  }
  [data-theme="dark"] .result {
    background: rgba(255, 255, 255, 0.03);
    border-color: rgba(255, 255, 255, 0.06);
  }
  [data-theme="dark"] .result:active {
    background: rgba(255, 255, 255, 0.05);
  }
  .result-body {
    grid-area: body;
  }
  /* Keep the tags row as a single flex container on phones so the
   * "More like this" pill flows inline with the tag chips and reads
   * as the last chip. The desktop `margin-left: auto` (which pushes
   * the pill to the right edge) is dropped so it sits naturally
   * after the last tag. */
  .result-similar {
    margin-left: 0;
  }
  .result-foot-right {
    grid-area: score;
    justify-self: end;
  }
  .result-kicker {
    gap: 8px;
    margin-bottom: 8px;
    font-size: 11px;
  }
  .result h3 {
    font-size: 18px;
    line-height: 1.32;
    margin: 0 0 8px;
  }
  .result-summary {
    font-size: 13.5px;
    line-height: 1.55;
    /* Justify reads poorly at narrow widths — switch to flush
       left so we don't get giant word-gaps on phone columns. */
    text-align: left;
    hyphens: none;
    -webkit-hyphens: none;
    /* Cap at 4 lines so cards stay scannable on small screens —
       full text is still one tap away in the source link. */
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .result-tags-row {
    gap: 6px;
  }
  .result-tag {
    font-size: 11.5px;
    padding: 4px 10px;
  }
  .result-similar {
    padding: 4px 10px 4px 11px;
    font-size: 11.5px;
  }
  .result-foot-right {
    gap: 8px;
  }

  /* — Filter chips ———————————————————————————————— */
  .active-tag {
    height: 26px;
    font-size: 12px;
  }
  .result-source {
    height: 24px;
    font-size: 11.5px;
  }

  /* — Library picker: leave breathing room on top + bottom so
       the modal doesn't kiss the screen edges (iPhone notch /
       home indicator). `env(safe-area-inset-*)` falls back to 0
       on devices without them. ——————————————— */
  .lib-picker {
    width: calc(100vw - 16px);
    max-width: 100%;
    max-height: calc(
      100vh - 56px - env(safe-area-inset-top) - env(safe-area-inset-bottom)
    );
    border-radius: 16px;
  }
  .lib-picker-head {
    padding: 14px 16px 8px;
  }
  .lib-picker-head h2 {
    font-size: 18px;
  }
  .lib-picker-search,
  .lib-picker-list {
    padding-left: 14px;
    padding-right: 14px;
  }
  /* iOS auto-zooms inputs <16px. Bump the picker search field
   * (and any input inside the profile/settings modal) to 16px
   * on phones so tapping in doesn't pan-and-zoom the page. */
  .lib-picker-search input,
  .profile-modal .profile-input,
  .profile-modal input[type="text"],
  .profile-modal input[type="url"],
  .profile-modal input[type="email"],
  .profile-modal input[type="password"],
  .profile-modal input[type="search"],
  .profile-modal textarea {
    font-size: 16px;
  }
  .lib-picker-foot {
    /* Single-row footer on phones — Select all · Clear all · count
       · Close all share one baseline. The count flexes (and
       ellipsizes) to absorb leftover width so the buttons keep
       their natural sizes. */
    padding: 10px 12px;
    gap: 6px;
    flex-wrap: nowrap;
    align-items: center;
  }
  .lib-picker-act {
    padding: 0 10px;
    height: 30px;
    font-size: 12px;
    flex: 0 0 auto;
  }
  .lib-picker-act svg {
    width: 12px;
    height: 12px;
  }
  .lib-picker-count {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
    margin: 0;
    font-size: 11.5px;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .lib-picker-apply {
    height: 30px;
    padding: 0 14px;
    font-size: 12px;
    flex: 0 0 auto;
  }

  /* — Profile / sources modal ———————————————————— */
  .profile-modal {
    width: calc(100vw - 12px);
    max-width: 100%;
    max-height: calc(100vh - 24px);
    border-radius: 14px;
  }

  /* — Floating sort toggle ———————————————————————— */
  .sort-toggle {
    right: 14px;
    bottom: 14px;
  }

  /* — Tweet pill in kicker should never overflow ———— */
  .result-kicker .tweet-link,
  .result-kicker .via-tweet {
    max-width: 100%;
  }
}

/* Very small phones: trim a touch more so 320–360px widths
   don't crowd. */
@media (max-width: 380px) {
  .spotlight,
  .filter-strip,
  .results,
  .lib-empty {
    margin-left: 10px;
    margin-right: 10px;
    padding-left: 10px;
    padding-right: 10px;
  }
  .results,
  .filter-strip {
    padding: 0;
  }
  .result h3 {
    font-size: 17px;
  }
  .result-summary {
    font-size: 13px;
  }
}
