:root {
  /* -----------------------------------------------------------------
     SOURCE! tokens — clean white, modern reader. Retired direction:
     amber-on-black terminal ("hacked into something"). This is now
     the ONE identity — the mobile/desktop toggle below swaps LAYOUT,
     not theme.
     ----------------------------------------------------------------- */
  --bg: #FFFFFF;
  --surface: #F7F7F4;
  --surface-2: #FFFFFF;
  --line: #E6E7E1;
  --ink: #14161B;
  --ink-muted: #6B6E67;
  --accent: #C98A00;
  --accent-dim: #8C6300;
  --accent-soft: #FFF4DC;
  --alert: #B8123A;

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);

  --display: "Poppins", "Inter", -apple-system, sans-serif;
  --body: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --data: "IBM Plex Mono", ui-monospace, monospace;
}

* { box-sizing: border-box; }

@media (prefers-reduced-motion: no-preference) {
  .tab-btn, .btn, .card { transition: transform 0.12s ease, background 0.15s ease, opacity 0.15s ease; }
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--body);
  -webkit-tap-highlight-color: transparent;
  height: 100%;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

a { color: var(--accent-dim); text-decoration: none; }
a:hover { text-decoration: underline; }

button { font-family: inherit; cursor: pointer; }

/* ---------------------------------------------------------------
   Header / wordmark
   --------------------------------------------------------------- */
.source-header {
  padding: calc(14px + var(--safe-top)) 18px 12px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.wordmark-wrap { display: flex; flex-direction: column; }

.wordmark {
  font-family: var(--display);
  font-weight: 800;
  font-size: 21px;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.wordmark-rule {
  width: 46px;
  height: 3px;
  background: var(--accent);
  border-radius: 2px;
  margin-top: 3px;
  transform: rotate(-1.5deg);
}

.tagline {
  font-family: var(--body);
  font-size: 11px;
  color: var(--ink-muted);
  margin-top: 5px;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.icon-btn {
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--ink);
  font-size: 16px;
  line-height: 1;
  flex-shrink: 0;
}

.icon-btn:active { background: var(--surface); transform: scale(0.94); }

.icon-btn.spinning { animation: icon-spin 0.7s linear infinite; }

@keyframes icon-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.view-menu { position: relative; }

.view-menu-btn {
  display: flex;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 20px;
  color: var(--ink);
  font-family: var(--body);
  font-weight: 600;
  font-size: 10.5px;
  letter-spacing: 0.02em;
  padding: 8px 13px;
}

.view-menu-list {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 168px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.14);
  padding: 6px;
  z-index: 40;
}

.view-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  color: var(--ink);
  font-family: var(--body);
  font-size: 13px;
  padding: 9px 10px;
  border-radius: 8px;
}

.view-menu-item:hover { background: var(--surface); }

.view-menu-item.active {
  color: var(--accent-dim);
  font-weight: 700;
}

.view-menu-sep {
  height: 1px;
  background: var(--line);
  margin: 5px 4px;
}

/* ---------------------------------------------------------------
   Main content area
   --------------------------------------------------------------- */
.source-main {
  flex: 1;
  overflow-y: auto;
  padding: 14px 14px calc(90px + var(--safe-bottom));
  background: var(--bg);
}

.state-block {
  text-align: center;
  padding: 60px 20px;
  color: var(--ink-muted);
}

.state-block h3 {
  font-family: var(--display);
  color: var(--ink);
  font-size: 15px;
  font-weight: 700;
  margin: 14px 0 6px;
}

.state-block p { font-size: 13px; margin: 0; }

.terminal-glyph { font-family: var(--display); font-size: 26px; color: var(--accent); font-weight: 700; }
.terminal-glyph.spin { animation: spin 1.1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------------------------------------------------------------
   Dispatch cards — clean reader-list style: thumbnail left,
   title/excerpt right, subtle hairline separators rather than
   boxed cards.
   --------------------------------------------------------------- */
.card {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px;
  margin-bottom: 8px;
  display: block;
}

.card:active { background: var(--surface); }

.card-meta {
  font-family: var(--data);
  font-size: 10.5px;
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}

.outlet-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

.outlet-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  color: #fff;
  font-family: var(--display);
  font-weight: 700;
  font-size: 9px;
  letter-spacing: 0;
  flex-shrink: 0;
}

/* Per-article paywall label — small badge next to the outlet/timestamp
   meta line. Hidden by default; only shown once the batched lookup
   confirms a specific article is soft- or hard-paywalled. */
.paywall-badge {
  display: inline-block;
  font-family: var(--data);
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: 4px;
  flex-shrink: 0;
}
.paywall-badge.paywall-hard { background: var(--alert); color: #fff; }
.paywall-badge.paywall-soft { background: var(--surface); color: var(--ink-muted); border: 1px solid var(--line); }

.card-body { display: flex; gap: 10px; align-items: flex-start; }
.card-body .card-text { flex: 1; min-width: 0; }

.card-link { display: block; color: inherit; text-decoration: none; }
.card-link:hover .card-title { color: var(--accent-dim); text-decoration: none; }

.card-title {
  font-family: var(--display);
  font-weight: 600;
  font-size: 15px;
  line-height: 1.35;
  color: var(--ink);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card:hover .card-title { color: var(--accent-dim); }

.card-excerpt {
  font-size: 13px;
  color: var(--ink-muted);
  margin-top: 6px;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.card-thumb {
  width: 80px;
  height: 80px;
  flex-shrink: 0;
  object-fit: cover;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  display: none;
}

.card-thumb.loaded { display: block; }

/* ---------------------------------------------------------------
   Featured card — the newest dispatch in the Read tab gets a
   full-bleed image treatment on top instead of a side thumbnail, so
   the wire has a clear entry point rather than reading as one flat
   list from the very first card.
   --------------------------------------------------------------- */
.card-featured {
  padding: 0;
  overflow: hidden;
}

.card-featured .card-link { display: block; }

.card-featured-media {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--surface);
  overflow: hidden;
}

.card-featured-media .card-thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
  border-radius: 0;
}

.card-featured .card-meta,
.card-featured .card-title,
.card-featured .card-excerpt {
  padding-left: 14px;
  padding-right: 14px;
}

.card-featured .card-meta { margin-top: 12px; }

.card-featured .card-title {
  font-size: 19px;
  -webkit-line-clamp: 3;
}

.card-featured .card-excerpt {
  -webkit-line-clamp: 3;
  padding-bottom: 14px;
}

/* ---------------------------------------------------------------
   Headlines Only view — compact, RSS-style: no image, no excerpt,
   just outlet/time + title. Applies to every card, featured or not.
   --------------------------------------------------------------- */
.card-headlines-only.card-featured .card-title {
  padding-top: 12px;
  font-size: 17px;
}

.card.card-headlines-only { padding: 12px 14px; }

.card-featured .card-excerpt:last-child { padding-bottom: 14px; }
.card-featured .card-title:last-child { padding-bottom: 14px; }

.card-featured .buzz-badge,
.card-featured .tip-badge {
  width: auto;
  margin: 10px 14px 14px;
}

/* ---------------------------------------------------------------
   Scroll — the third View-menu density tier, built as "Expanded,
   taken further." Every card (not just the first) gets the full-
   bleed one-story-fills-the-screen treatment: bigger image, bigger
   type, full excerpt, generous whitespace, outlet identity reading
   like a poster credit. Same reverse-chronological order as every
   other mode — this is presentation only, never a reorder. No like/
   repost/reply counts anywhere; the only nod to "what people are
   saying" is a plain text link to the matched Bluesky post, when one
   exists — social feel, without the algorithm.
   --------------------------------------------------------------- */
.card-scroll {
  padding: 0;
  overflow: hidden;
  margin-bottom: 20px;
}

.card-scroll .card-link { display: block; }

.card-scroll-media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--surface);
  overflow: hidden;
}

.card-scroll-media .card-thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
  border-radius: 0;
}

.card-scroll-body { padding: 16px; }

.card-scroll-body-textonly { padding-top: 22px; }

.card-scroll-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--ink-muted);
  margin-bottom: 10px;
}

.card-scroll-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 22px;
  line-height: 1.25;
  margin-bottom: 10px;
}

.card-scroll-body-textonly .card-scroll-title { font-size: 26px; }

.card-scroll-excerpt {
  font-size: 15px;
  line-height: 1.6;
  color: var(--ink-muted);
}

.card-scroll-discuss {
  display: block;
  padding: 10px 16px 16px;
  font-size: 13px;
  color: var(--accent-dim);
  text-decoration: underline;
}

/* Buzz tab, Scroll mode — same underlying Trending-on-Bluesky cards,
   just roomier: no new data, just more breathing room per post. */
.card-scroll-post {
  padding: 18px !important;
  margin-bottom: 12px;
}

.card-scroll-post .card-title { font-size: 17px; }

/* trending-on-Bluesky badge, links out to Buzz */
.buzz-badge {
  display: block;
  width: 100%;
  text-align: left;
  margin-top: 9px;
  padding: 7px 10px;
  background: var(--accent-soft);
  color: var(--accent-dim);
  border: none;
  border-radius: 8px;
  font-family: var(--body);
  font-weight: 600;
  font-size: 12px;
}

/* tip/subscribe support link — outline treatment (vs. buzz-badge's
   filled amber) so the two block badges read as distinct actions when
   both appear on the same card. */
.tip-badge {
  display: block;
  width: 100%;
  text-align: left;
  margin-top: 9px;
  padding: 6px 10px;
  background: transparent;
  color: var(--accent-dim);
  border: 1px solid var(--accent);
  border-radius: 8px;
  font-family: var(--body);
  font-weight: 600;
  font-size: 12px;
  text-decoration: none;
}

/* "+ Spray" control — small and quiet on purpose, a secondary action next
   to (never competing with) tip-badge/buzz-badge. Sits on its own row
   under them since both are block-level. */
.spray-add-btn {
  display: inline-flex;
  align-items: center;
  margin-top: 6px;
  padding: 5px 10px;
  background: transparent;
  color: var(--ink-muted);
  border: 1px solid var(--line);
  border-radius: 8px;
  font-family: var(--body);
  font-weight: 600;
  font-size: 11.5px;
}
.spray-add-btn:hover { color: var(--ink); border-color: var(--ink-muted); }

/* Quick-remove state — one tap, no picker, when the reader is viewing a
   Spray they own. Uses the alert color so it visually reads as a removal,
   not a duplicate "add" affordance. */
.spray-remove-btn {
  color: var(--alert);
  border-color: var(--alert);
}
.spray-remove-btn:hover { color: var(--alert); border-color: var(--alert); background: rgba(184, 18, 58, 0.06); }
.spray-remove-btn:disabled { opacity: 0.5; }

/* "☆ Save" control — same quiet secondary-action treatment as
   "+ Spray", sitting right next to it (margin-left instead of stacking
   below, since both are inline-flex on the same row). Flips to a plain
   filled-star label + accent color on success rather than being
   removed, so tapping it a second time reads as "yep, still saved"
   instead of the control just vanishing. */
.save-btn {
  display: inline-flex;
  align-items: center;
  margin-top: 6px;
  margin-left: 6px;
  padding: 5px 10px;
  background: transparent;
  color: var(--ink-muted);
  border: 1px solid var(--line);
  border-radius: 8px;
  font-family: var(--body);
  font-weight: 600;
  font-size: 11.5px;
}
.save-btn:hover { color: var(--ink); border-color: var(--ink-muted); }
.save-btn:disabled { opacity: 0.6; }
.save-btn-done { color: var(--accent-dim); border-color: var(--accent); }
.save-btn-done:hover { color: var(--accent-dim); border-color: var(--accent); }

/* "Add to a Spray" picker — a bottom sheet on mobile widths, a centered
   modal above the phone-frame breakpoint. Checkboxes toggle immediately
   (no separate Save), same feel as a save-to-a-playlist picker. This is
   also the only place a reader can add a source to an EXISTING Spray at
   all — the guided Create flow only ever builds new ones. */
.spray-picker-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(20,22,27,0.45);
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.spray-picker-card {
  width: 100%;
  max-width: 420px;
  max-height: 70vh;
  overflow-y: auto;
  background: var(--surface);
  border-radius: 16px 16px 0 0;
  padding: 16px 18px calc(18px + var(--safe-bottom));
  box-shadow: 0 -8px 30px rgba(0,0,0,0.18);
}
@media (min-width: 700px) {
  .spray-picker-overlay { align-items: center; }
  .spray-picker-card { border-radius: 14px; max-height: 60vh; }
}
.spray-picker-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
  font-family: var(--body);
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
}
.spray-picker-close {
  flex: 0 0 auto;
  background: none;
  border: none;
  font-size: 20px;
  line-height: 1;
  color: var(--ink-muted);
  padding: 2px 6px;
}
.spray-picker-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: 4px;
}
.spray-picker-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 6px;
  font-family: var(--body);
  font-size: 13.5px;
  color: var(--ink);
  border-radius: 8px;
}
.spray-picker-row:hover { background: var(--bg); }
.spray-picker-row input[type="checkbox"] {
  width: 17px;
  height: 17px;
  accent-color: var(--accent);
  flex: 0 0 auto;
}
.spray-picker-empty {
  font-family: var(--body);
  font-size: 13px;
  color: var(--ink-muted);
  padding: 10px 2px 4px;
}
.spray-picker-newrow {
  display: flex;
  gap: 8px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}
.spray-picker-newrow input[type="text"] {
  flex: 1;
  min-width: 0;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  font-family: var(--body);
  font-size: 13px;
  background: var(--bg);
  color: var(--ink);
}

/* ---------------------------------------------------------------
   Spray toggle — Read tab's All | News | <your Sprays> | Create bar.
   Sits between the header and #main, hidden on every tab except Read.
   --------------------------------------------------------------- */
.spray-toggle {
  display: flex;
  /* row-reverse both right-justifies the bar AND mirrors pill order
     in one move: DOM order stays All -> News/Headlines -> your Sprays
     -> +Create, but it renders (right to left) Create -> Sprays ->
     Headlines -> All, packed flush against the right edge. */
  flex-direction: row-reverse;
  gap: 6px;
  overflow-x: auto;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* Snap-scroll rather than free-scroll — with many pills, a swipe
     settles on a pill edge instead of stopping mid-label. Cheap,
     no-JS improvement for the "many pills on a narrow phone" case;
     doesn't change layout/behavior when the bar isn't overflowing. */
  scroll-snap-type: x proximity;
  /* Edge-fade hint: a static mask (no scroll-position JS needed) that
     softens both edges so a reader can tell there's more to scroll to
     before they've swiped at all. Harmless when the bar doesn't
     overflow — nothing sits under the faded strip in that case. */
  mask-image: linear-gradient(to right, transparent, black 18px, black calc(100% - 18px), transparent);
  -webkit-mask-image: linear-gradient(to right, transparent, black 18px, black calc(100% - 18px), transparent);
}
.spray-toggle::-webkit-scrollbar { display: none; }
.spray-pill {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  max-width: 45vw;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-muted);
  font-family: var(--body);
  font-weight: 600;
  font-size: 13px;
  white-space: nowrap;
  scroll-snap-align: start;
}
.spray-pill-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Narrow phones specifically (not the general <700px mobile
   breakpoint) — tighten pill padding/type a touch so more of the bar
   reads at a glance before a reader needs to scroll at all. */
@media (max-width: 380px) {
  .spray-pill { padding: 6px 11px; font-size: 12px; max-width: 52vw; }
}
.spray-pill.active {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}
.spray-pill-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: 7px;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: rgba(255,255,255,0.18);
  font-size: 11px;
  line-height: 1;
  vertical-align: middle;
}
.spray-pill-x:hover { background: rgba(255,255,255,0.32); }
.spray-pill-create {
  color: var(--accent-dim);
  border-color: var(--accent-soft);
  background: transparent;
}

/* ---------------------------------------------------------------
   Sources tab — "Your Sprays" bar editor + guided Create flow
   --------------------------------------------------------------- */
.spray-bar-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
}
.spray-bar-row .spray-bar-name { flex: 1; min-width: 0; font-weight: 600; }
.spray-bar-row .spray-bar-btn {
  border: none;
  background: transparent;
  color: var(--ink-muted);
  font-size: 15px;
  padding: 4px 8px;
  line-height: 1;
}
.spray-bar-row .spray-bar-btn:disabled { opacity: 0.25; }
.spray-bar-row .spray-bar-btn.remove { color: var(--alert); }

.create-flow-step { margin-bottom: 16px; }
.create-flow-label {
  font-family: var(--display);
  font-weight: 700;
  font-size: 12.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  margin-bottom: 8px;
}
.create-flow-input {
  width: 100%;
  padding: 10px 12px;
  background: var(--bg);
  border: 1px solid var(--line);
  color: var(--ink);
  font-family: var(--body);
  font-size: 14px;
  border-radius: 8px;
  box-sizing: border-box;
}
.create-flow-picked {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0;
}
.create-flow-suggestion {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 4px;
  border-bottom: 1px solid var(--line);
}
.create-flow-suggestion label { flex: 1; font-size: 14px; }
.create-flow-checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 14px 0;
  font-size: 14px;
}

/* Create-flow tag picker — four branch tiles (News/Fun/Work/Local), each
   expanding into leaf chips (News/Fun/Work) or a location field (Local).
   Branches themselves are never taggable — only what's inside them is. */
.cf-branch-tiles {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 10px;
}
.cf-branch-tile {
  padding: 10px 12px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
  font-family: var(--display);
  font-weight: 700;
  font-size: 14px;
  color: var(--ink);
  cursor: pointer;
  text-align: left;
}
.cf-branch-tile.open {
  border-color: var(--accent);
  background: var(--accent-soft);
}
.cf-leaf-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 4px 0 12px;
}
.cf-leaf-chip {
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--bg);
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
}
.cf-leaf-chip.selected {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-ink, #fff);
}
.cf-tags-picked {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 2px 0 12px;
}

/* Sources tab intro — sits above the two entry doors */
/* Calmer, more onboarding-like intro — a small accent rule under the
   headline (the same motif as onboarding's ob-rule), more breathing
   room above the doors, so this reads as a continuation of the
   onboarding "feel" rather than a denser dashboard screen. */
.sources-area-head {
  margin: 6px 2px 16px;
}
.sources-area-rule {
  width: 36px;
  height: 3px;
  background: var(--accent);
  border-radius: 2px;
  margin-bottom: 12px;
}
.sources-area-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 20px;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.sources-area-sub {
  font-size: 12.5px;
  color: var(--ink-muted);
  margin-top: 4px;
  line-height: 1.4;
}

.sources-signin-hint {
  font-size: 13px;
  color: var(--ink-muted);
  margin: 14px 2px 0;
}

/* Registry rows — the "drill in as deep as possible" list. Each row
   expands in place; the detail always ends at the same "+ Spray"
   picker used from a post, so there's exactly one edit mechanism in
   the whole app, reached from wherever a reader happens to be. */
.source-row.bordered { border-top: 1px solid var(--line); }
.source-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 12px 14px;
  background: none;
  border: none;
  text-align: left;
  font-family: var(--body);
  font-weight: 600;
  font-size: 13.5px;
  color: var(--ink);
}
.source-row-chevron {
  color: var(--ink-muted);
  font-weight: 700;
  font-size: 15px;
  flex: 0 0 auto;
  margin-left: 10px;
}
.source-row-detail {
  padding: 0 14px 14px;
}
.source-row-in {
  font-size: 12.5px;
  color: var(--ink);
  margin-bottom: 10px;
  line-height: 1.4;
}
.source-row-in.muted { color: var(--ink-muted); }

/* Suggested-for-you pills, part of the Expand Your Mind area — tap one
   to open the same "+ Spray" picker directly (add to an existing Spray
   or spin up a new one from the picker's own quick-create row). */
.source-suggest-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 4px;
}
.source-suggest-pill {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 9px 14px;
  border-radius: 14px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--body);
  font-weight: 600;
  font-size: 13.5px;
  text-align: left;
  cursor: pointer;
}
.source-suggest-pill:active { background: var(--accent-soft); border-color: var(--accent); }
.source-suggest-sub {
  display: block;
  font-family: var(--data);
  font-weight: 400;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--ink-muted);
  margin-top: 2px;
}

/* Plain text-link toggle (still used elsewhere, e.g. Actions/On Trend
   expand rows) */
.link-toggle {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  padding: 10px 2px;
  font-family: var(--body);
  font-weight: 600;
  font-size: 13.5px;
  color: var(--accent-dim);
  cursor: pointer;
}

/* section headers within a tab (e.g. Buzz: Actions / Trending) */
.section-label {
  font-family: var(--display);
  font-weight: 700;
  font-size: 12.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  margin: 20px 2px 8px;
}

.section-label:first-child { margin-top: 2px; }

/* small eyebrow line under a section-label, e.g. "Latest from Rogan's List" */
.section-sub {
  font-size: 12px;
  color: var(--ink-muted);
  margin: -4px 2px 8px;
}

/* On Trend: a matched Bluesky post nested under its story */
.on-trend-post {
  padding: 8px 0;
  border-top: 1px solid var(--line);
}

.on-trend-post-text {
  font-size: 13px;
  color: var(--ink-muted);
  line-height: 1.4;
  margin: 4px 0 4px;
}

.on-trend-post-link {
  font-size: 12.5px;
  color: var(--accent-dim);
}

/* plain link rows, used for the non-preview items in a top-item
   preview list (e.g. Actions after the first item) */
.plain-row {
  display: block;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
  font-size: 13.5px;
  color: var(--ink);
  line-height: 1.4;
}

.plain-row:last-child { border-bottom: none; }
.plain-row:hover { color: var(--accent-dim); }

/* signature stamp badge, now on white */
.stamp {
  display: inline-block;
  font-family: var(--display);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 12px;
  background: var(--accent-soft);
  color: var(--accent-dim);
}

.stamp.unverified { background: #FCE4E9; color: var(--alert); }

/* ---------------------------------------------------------------
   Onboarding
   --------------------------------------------------------------- */
.onboarding {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--bg);
  color: var(--ink);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 32px 26px calc(32px + var(--safe-bottom));
}

.onboarding .ob-wordmark {
  font-family: var(--display);
  font-weight: 800;
  font-size: 20px;
  color: var(--ink);
  margin-bottom: 6px;
}

.onboarding .ob-rule {
  width: 46px;
  height: 3px;
  background: var(--accent);
  border-radius: 2px;
  margin-bottom: 30px;
  transform: rotate(-1.5deg);
}

.onboarding h1 {
  font-family: var(--display);
  font-size: 25px;
  font-weight: 700;
  line-height: 1.3;
  margin: 0 0 12px;
}

.onboarding p {
  font-family: var(--body);
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink-muted);
  margin: 0 0 30px;
}

.ob-btn {
  display: block;
  width: 100%;
  text-align: left;
  font-family: var(--body);
  font-size: 15px;
  font-weight: 600;
  padding: 15px 16px;
  margin-bottom: 10px;
  border: 1.5px solid var(--ink);
  background: var(--ink);
  color: var(--bg);
  border-radius: 10px;
}

.ob-btn.secondary { background: transparent; color: var(--ink); }

.ob-btn-sub {
  display: block;
  font-family: var(--body);
  font-size: 11.5px;
  font-weight: 400;
  opacity: 0.65;
  margin-top: 3px;
}

.ob-whats-this {
  position: absolute;
  right: 22px;
  bottom: calc(22px + var(--safe-bottom));
  font-family: var(--body);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-muted);
  text-decoration: underline;
}

.ob-whats-this-panel {
  position: absolute;
  left: 22px;
  right: 22px;
  bottom: calc(56px + var(--safe-bottom));
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 14px 34px 14px 16px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}

.ob-whats-this-panel p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink);
}

.ob-whats-this-close {
  position: absolute;
  top: 8px;
  right: 10px;
  font-size: 18px;
  line-height: 1;
  color: var(--ink-muted);
  background: none;
  border: none;
  padding: 4px;
}

/* ---------------------------------------------------------------
   Bottom tab bar (mobile layout)
   --------------------------------------------------------------- */
.tab-bar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  background: var(--surface-2);
  border-top: 1px solid var(--line);
  padding-bottom: var(--safe-bottom);
  display: flex;
  z-index: 20;
}

.tab-btn {
  flex: 1;
  background: none;
  border: none;
  color: var(--ink-muted);
  font-family: var(--body);
  font-weight: 600;
  font-size: 11px;
  letter-spacing: 0.01em;
  padding: 10px 4px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
}

.tab-btn.active { color: var(--accent-dim); }

/* ---------------------------------------------------------------
   Buttons
   --------------------------------------------------------------- */
.btn {
  font-family: var(--body);
  font-weight: 600;
  font-size: 13px;
  padding: 10px 16px;
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  border-radius: 8px;
}

.btn:active { background: var(--ink); color: var(--bg); }
.btn.primary { background: var(--ink); color: var(--bg); }
.btn.primary:active { background: var(--accent-dim); border-color: var(--accent-dim); }

/* ---------------------------------------------------------------
   Toast
   --------------------------------------------------------------- */
#toast {
  position: fixed;
  bottom: calc(70px + var(--safe-bottom));
  left: 50%;
  transform: translateX(-50%) translateY(10px);
  background: var(--ink);
  color: var(--bg);
  font-family: var(--body);
  font-size: 12.5px;
  padding: 9px 14px;
  border-radius: 8px;
  opacity: 0;
  pointer-events: none;
  z-index: 50;
  max-width: 90%;
}

#toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

/* ---------------------------------------------------------------
   DESKTOP layout — this is the "swap out" view: top nav instead of
   a bottom tab bar, wider multi-column card grid. Same theme, same
   components, different arrangement. Answers the original "add a
   mobile view the user can swap [out of]" ask now that the theme
   itself is unified.
   --------------------------------------------------------------- */
body[data-layout="desktop"] .tab-bar {
  position: static;
  border-top: none;
  border-bottom: 1px solid var(--line);
  padding-bottom: 0;
  max-width: 720px;
  margin: 0 auto;
}

body[data-layout="desktop"] .tab-btn {
  flex-direction: row;
  gap: 6px;
  padding: 14px 8px;
}

body[data-layout="desktop"] .source-main {
  max-width: 720px;
  margin: 0 auto;
  padding-bottom: 40px;
  width: 100%;
}

body[data-layout="desktop"] #main {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  align-items: start;
}

body[data-layout="desktop"] .state-block {
  grid-column: 1 / -1;
}

@media (min-width: 900px) {
  body[data-layout="desktop"] .tab-bar,
  body[data-layout="desktop"] .source-main {
    max-width: 960px;
  }
  body[data-layout="desktop"] #main {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

/* ---------------------------------------------------------------
   Desktop Read tab — reader pane (left) + selectable feed (right),
   overriding the generic Sources/Buzz masonry grid above. The
   left two columns' worth of width holds whatever story is
   selected, full-size, with a "More" button that loads the actual
   article inline. The right column is the feed you pick the next
   story from — RSS (headlines) or post/social style, per the View
   menu. No badge/label calling out "top story" or "latest" — the
   pane just shows whichever story is selected, full stop.
   --------------------------------------------------------------- */
body[data-layout="desktop"] #main.read-layout {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 22px;
  align-items: start;
}

@media (min-width: 900px) {
  body[data-layout="desktop"] #main.read-layout {
    grid-template-columns: 2fr 1fr;
  }
}

/* ---------------------------------------------------------------
   Desktop side panel — fills the dead space beyond the centered main
   column (720/960px) on wide screens with a stack of small stat/
   context modules (midterms countdown, Iran War day, gas price,
   climate metrics, top Bluesky post). Desktop layout only, and only
   once there's real room for it — narrower desktop widths keep the
   space collapsed rather than cramming a panel in. Never fully
   vanishes even when a reader hides everything in it — collapses to
   just the header row so the gear (the only way back) stays reachable.
   --------------------------------------------------------------- */
.desktop-side-panel { display: none; }
@media (min-width: 1180px) {
  body[data-layout="desktop"] .desktop-side-panel:not([hidden]) {
    display: block;
    position: fixed;
    top: 176px;
    right: 28px;
    width: 260px;
    max-height: calc(100vh - 196px);
    overflow-y: auto;
    padding-right: 4px;
  }
}
.desktop-bsky-rail-head {
  font-family: var(--display);
  font-weight: 700;
  font-size: 12.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
}
.desktop-side-panel .card {
  margin-bottom: 8px;
  padding: 10px 12px;
}
.desktop-side-panel .card.panel-top-post {
  padding: 15px 16px;
}
.desktop-side-panel .card.panel-top-post .card-meta {
  font-size: 11.5px;
  margin-bottom: 8px;
}
.desktop-side-panel .card.panel-top-post .card-title {
  font-size: 18px;
  line-height: 1.32;
  font-weight: 700;
  -webkit-line-clamp: 4;
}
.desktop-bsky-rail-more {
  display: block;
  text-align: center;
  font-size: 12px;
  font-weight: 600;
  color: var(--accent-dim);
  padding: 10px 0 4px;
  margin-bottom: 14px;
}

.panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 10px;
}

.panel-head-text {
  display: flex;
  flex-direction: column;
}

.panel-date {
  font-size: 11px;
  font-weight: 500;
  color: var(--ink-muted);
  margin-top: 2px;
}

.panel-settings { position: relative; }

.panel-settings-btn {
  width: 26px;
  height: 26px;
  font-size: 13px;
}

.panel-settings-list {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 220px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.14);
  padding: 8px;
  z-index: 40;
}

.panel-settings-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  font-family: var(--body);
  font-size: 12.5px;
  color: var(--ink);
  padding: 7px 6px;
  border-radius: 8px;
  cursor: pointer;
}

.panel-settings-item:hover { background: var(--surface); }

.panel-settings-item input[type="checkbox"] { flex-shrink: 0; }

.panel-settings-sep {
  height: 1px;
  background: var(--line);
  margin: 5px 4px;
}

.panel-signin-hint {
  font-family: var(--body);
  font-size: 11.5px;
  color: var(--ink-muted);
  padding: 8px 6px 4px;
  line-height: 1.4;
}

.panel-signin-hint a {
  color: var(--accent-dim);
  font-weight: 600;
  text-decoration: none;
}

.panel-stat {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 11px 13px;
  margin-bottom: 8px;
}

.panel-stat-value {
  display: block;
  font-family: var(--display);
  font-weight: 700;
  font-size: 19px;
  color: var(--ink);
  line-height: 1.15;
}

.panel-stat-label {
  display: block;
  font-family: var(--body);
  font-size: 11.5px;
  color: var(--ink-muted);
  margin-top: 2px;
}

.state-block-mini {
  font-size: 12.5px;
  color: var(--ink-muted);
  padding: 4px 2px;
}

.reader-pane {
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface-2);
  position: sticky;
  top: 14px;
}

.reader-image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  background: var(--surface);
}

/* Scroll — the reader pane is Desktop's primary reading surface, so this
   is where Scroll's full-bleed, one-story identity actually has to live
   (the side rail's own Scroll treatment is a compact list, not this).
   Taller image, bigger display type, more room, a plain "join the
   conversation" link — matches the mobile Scroll card's feel without
   ever showing a like/repost count. */
.reader-image-scroll { aspect-ratio: 16 / 10; }

.reader-body { padding: 18px 22px 22px; }
.reader-body-textonly { padding-top: 24px; }
.reader-body-scroll { padding: 26px 30px 28px; }

.reader-title {
  font-family: var(--display);
  font-size: 25px;
  font-weight: 700;
  line-height: 1.25;
  margin: 10px 0 12px;
  color: var(--ink);
}
.reader-title-large { font-size: 30px; }
.reader-title-scroll { font-size: 34px; line-height: 1.18; margin: 14px 0 16px; }

.reader-excerpt {
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--ink-muted);
  margin: 0 0 18px;
}
.reader-excerpt-scroll { font-size: 17px; line-height: 1.7; margin-bottom: 14px; }

.reader-discuss-scroll {
  display: inline-block;
  margin: 0 0 20px;
  font-size: 13.5px;
  color: var(--accent-dim);
  text-decoration: underline;
}

.reader-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}

.reader-open-link {
  text-decoration: none;
  text-align: center;
}

.tip-btn {
  text-decoration: none;
  text-align: center;
  border-color: var(--accent);
  color: var(--accent-dim);
}

.reader-frame-wrap { margin-top: 18px; }

.reader-article-loading .state-block { padding: 30px 0; }

.reader-article-error {
  font-size: 13.5px;
  color: var(--ink-muted);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 14px 16px;
}

.reader-article {
  border-top: 1px solid var(--line);
  padding-top: 18px;
  font-size: 16px;
  line-height: 1.7;
  color: var(--ink);
}

.reader-article-byline {
  font-family: var(--data);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  margin-bottom: 14px;
}

.reader-article h1,
.reader-article h2,
.reader-article h3 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.3;
  margin: 22px 0 10px;
  color: var(--ink);
}

.reader-article h1 { font-size: 21px; }
.reader-article h2 { font-size: 19px; }
.reader-article h3 { font-size: 17px; }

.reader-article p { margin: 0 0 16px; }

.reader-article a { color: var(--accent-dim); text-decoration: underline; }

.reader-article img,
.reader-article figure {
  max-width: 100%;
  height: auto;
  border-radius: 8px;
  margin: 16px 0;
}

.reader-article figcaption {
  font-size: 12.5px;
  color: var(--ink-muted);
  margin-top: 6px;
}

.reader-article blockquote {
  margin: 16px 0;
  padding: 4px 0 4px 16px;
  border-left: 3px solid var(--accent);
  color: var(--ink-muted);
  font-style: italic;
}

.reader-article ul,
.reader-article ol {
  margin: 0 0 16px;
  padding-left: 22px;
}

.reader-article li { margin-bottom: 6px; }

.reader-frame-note {
  font-size: 11.5px;
  color: var(--ink-muted);
  margin-top: 14px;
}

.reader-feed {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: calc(100vh - 150px);
  overflow-y: auto;
  padding-right: 2px;
}

.feed-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  text-align: left;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px 12px;
}

.feed-item.active {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.feed-item-rss { flex-direction: column; gap: 5px; }

.feed-item-title {
  font-family: var(--display);
  font-weight: 600;
  font-size: 13.5px;
  color: var(--ink);
  line-height: 1.35;
}

.feed-item-meta {
  font-family: var(--data);
  font-size: 10px;
  color: var(--ink-muted);
  display: flex;
  align-items: center;
  gap: 6px;
  text-transform: uppercase;
}

.feed-item-post .feed-item-thumb {
  width: 56px;
  height: 56px;
  border-radius: 8px;
  object-fit: cover;
  flex-shrink: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  display: none;
}

.feed-item-post .feed-item-thumb.loaded { display: block; }

.feed-item-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.feed-item-excerpt {
  font-size: 12px;
  color: var(--ink-muted);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Scroll mode's reader-feed rail — roomier than the default Expanded
   list item, but still a compact selectable row (not the full-bleed
   card the main Scroll reading surface uses elsewhere). */
.feed-item-scroll { padding: 12px; gap: 12px; }

.feed-item-scroll .feed-item-thumb {
  border-radius: 10px;
  object-fit: cover;
  flex-shrink: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  display: none;
}

.feed-item-scroll .feed-item-thumb.loaded { display: block; }

.feed-item-thumb-lg {
  width: 84px;
  height: 84px;
}

.feed-item-title-lg {
  font-size: 15px;
  line-height: 1.3;
}

.feed-item-excerpt-lg {
  font-size: 12.5px;
  -webkit-line-clamp: 3;
}

.feed-item-discuss {
  font-family: var(--data);
  font-size: 10.5px;
  font-weight: 600;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

/* ---------------------------------------------------------------
   Layout review toggle — REVIEW-ONLY, not an in-product control.
   Fixed to the real browser viewport (not switched to
   position:absolute like the tab-bar/onboarding/toast are inside
   the phone-frame preview below), so it renders OUTSIDE the phone
   frame on the desktop-preview backdrop. Hidden entirely under
   700px — a real phone never sees it.
   --------------------------------------------------------------- */
.layout-review {
  display: none;
}

@media (min-width: 700px) {
  .layout-review {
    display: flex;
    align-items: center;
    gap: 8px;
    position: fixed;
    top: 16px;
    left: 16px;
    z-index: 50;
    background: rgba(20, 22, 27, 0.85);
    border-radius: 20px;
    padding: 5px 6px 5px 10px;
    backdrop-filter: blur(4px);
  }

  /* Label reads as a caption, not a third toggle state: smaller,
     dimmer, letter-spaced, and separated from the buttons by a
     hairline divider rather than sitting flush against them. */
  .layout-review-label {
    font-family: var(--data);
    font-size: 8.5px;
    letter-spacing: 0.14em;
    color: rgba(255, 255, 255, 0.4);
    padding-right: 8px;
    border-right: 1px solid rgba(255, 255, 255, 0.18);
  }

  .layout-review-btn {
    background: transparent;
    border: none;
    color: rgba(255, 255, 255, 0.7);
    font-family: var(--body);
    font-weight: 600;
    font-size: 10px;
    letter-spacing: 0.02em;
    padding: 6px 10px;
    border-radius: 16px;
  }

  .layout-review-btn.active {
    background: #FFFFFF;
    color: var(--ink);
  }

  /* Desktop layout has no phone-frame to push down (that's a
     Mobile-layout-only treatment) — its header sits flush at the
     real document top, which collided with the fixed review pill
     above. Give it generous clearance (measured against the pill's
     actual rendered height, not just eyeballed) plus a safety margin. */
  body[data-layout="desktop"] .source-header {
    padding-top: 76px;
  }
}

/* ---------------------------------------------------------------
   PHONE FRAME PREVIEW — when the Mobile layout is loaded on a wide
   (desktop-class) screen, scope the whole app into a fixed
   phone-sized frame instead of stretching the bottom tab bar / cards
   full browser width. Presentation-only: no markup/JS change. The
   one real behavior shift is that elements using position:fixed
   (tab bar, onboarding overlay, toast) normally resolve against the
   real browser viewport — inside the frame they're switched to
   position:absolute so they stay scoped to the phone body instead of
   pinning to the actual window edges.
   --------------------------------------------------------------- */
@media (min-width: 700px) {
  html {
    background: #E7E7E2;
    min-height: 100vh;
    display: flex;
  }

  body[data-layout="mobile"] {
    position: relative;
    width: 390px;
    height: 844px;
    max-height: calc(100vh - 96px);
    min-height: 0;
    /* 64px top clearance keeps the frame's rounded corner and the
       wordmark inside it clear of the fixed layout-review pill
       (top:16px), which previously overlapped the header. */
    margin: 64px auto 32px;
    border: 10px solid var(--ink);
    border-radius: 46px;
    overflow: hidden;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
  }

  /* decorative notch, purely cosmetic phone-bezel cue */
  body[data-layout="mobile"]::before {
    content: "";
    position: absolute;
    top: 8px;
    left: 50%;
    transform: translateX(-50%);
    width: 96px;
    height: 22px;
    background: var(--ink);
    border-radius: 14px;
    z-index: 30;
  }

  body[data-layout="mobile"] .source-header {
    padding-top: 34px;
  }

  body[data-layout="mobile"] .tab-bar,
  body[data-layout="mobile"] .onboarding,
  body[data-layout="mobile"] #toast {
    position: absolute;
  }
}
