/* ==========================================================================
   Tweet Discovery — dark UI
   Design tokens first; every component rule below reads from them.
   Shared by the React dashboard and public/login.html.
   ========================================================================== */

:root {
  color-scheme: dark;

  /* Surfaces — one deep base plus three elevation steps. */
  --bg: #0b0d12;
  --surface: #14171f;
  --surface-2: #1a1e28;
  --surface-3: #222733;
  --border: #232833;
  --border-strong: #2f3542;

  /* Text — both values clear 4.5:1 on --bg and on every surface step. */
  --text: #e7eaf0;
  --text-soft: #c4cbd8;
  --muted: #99a1b3;

  /* Accent. --accent carries white text at ~4.6:1; --accent-hover is the
     brighter value used for links and focus rings on dark backgrounds. */
  --accent: #4470e0;
  --accent-hover: #5b85ec;
  --accent-weak: rgba(68, 112, 224, 0.1);
  --accent-soft: rgba(68, 112, 224, 0.2);
  --accent-ring: rgba(103, 143, 240, 0.55);

  /* Status */
  --success: #3ed492;
  --error: #f0777e;
  --warning: #f5a623;
  --warn: #f5c542;
  --bookmark: #f5c542;
  --meme: #a855f7;

  /* Per-source brand */
  --hn: #ff6600;
  --reddit: #ff4500;
  --twitter: #1d9bf0;
  --github: #a371f7;
  --blog: #3dd68c;
  --news: #f59e0b;
  --communities: #2dd4bf;
  /* Per-platform accents for the merged Dev Communities section. */
  --lobsters: #ac130d;
  --devto: #8b5cf6;
  --mastodon: #6364ff;
  --hashnode: #2962ff;

  /* Type */
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
  --font-mono: ui-monospace, SFMono-Regular, "Cascadia Code", "Segoe UI Mono",
    Menlo, Consolas, monospace;
  --fs-2xs: 0.6875rem;
  --fs-xs: 0.75rem;
  --fs-sm: 0.8125rem;
  --fs-md: 0.875rem;
  --fs-lg: 0.9375rem;
  --fs-xl: 1.0625rem;
  --fs-2xl: 1.125rem;
  --lh-tight: 1.25;
  --lh-snug: 1.4;
  --lh-body: 1.55;

  /* Spacing — 4px rhythm, deliberately compact for long scrolling lists. */
  --sp-1: 0.25rem;
  --sp-2: 0.375rem;
  --sp-3: 0.5rem;
  --sp-4: 0.75rem;
  --sp-5: 1rem;
  --sp-6: 1.5rem;
  --sp-7: 2rem;

  /* Radius */
  --r-xs: 4px;
  --r-sm: 6px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-full: 999px;

  /* Elevation — hairline + shadow instead of a border on everything. */
  --shadow-xs: 0 1px 1px rgba(0, 0, 0, 0.25);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3), 0 2px 8px -6px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 0 32px -6px rgba(0, 0, 0, 0.8);
  --shadow-lg: 0 28px 64px -20px rgba(0, 0, 0, 0.75);

  /* Motion */
  --ease: cubic-bezier(0.2, 0, 0, 1);
  --dur: 130ms;
}

/* Layout breakpoints. Custom properties cannot drive media queries, so these
   are written out where they are used, next to the component they change:
     phone    max-width: 760px   one column; sidebar is a drawer, detail a sheet
     tablet   761px – 1100px     sidebar column; detail covers the right side
     desktop  above 1100px       three columns — must not move
   Touch sizing keys off (pointer: coarse) and hover effects off (hover: hover),
   not width, so a touch laptop gets big targets without the phone layout. */

* {
  box-sizing: border-box;
}

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

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

@media (hover: hover) {
  a:hover {
    text-decoration: underline;
  }
}

button,
.item-card,
a {
  /* No grey flash on tap, and no double-tap zoom delay on buttons. */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

::selection {
  background: color-mix(in srgb, var(--accent) 45%, transparent);
  color: #fff;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  background: var(--bg);
  color: var(--text);
  min-height: 100vh;
  /* dvh: the visible height on mobile, where 100vh includes the collapsing
     address bar. The line above is the fallback for older browsers. */
  min-height: 100dvh;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}

.hidden {
  display: none !important;
}

.topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: 0.875rem var(--sp-6);
  /* An installed iOS app draws under the status bar (black-translucent), and
     landscape phones have a notch at the side. env() is 0 everywhere else. */
  padding-top: max(0.875rem, env(safe-area-inset-top));
  padding-left: max(var(--sp-6), env(safe-area-inset-left));
  padding-right: max(var(--sp-6), env(safe-area-inset-right));
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

.brand h1 {
  margin: 0;
  font-size: var(--fs-2xl);
  font-weight: 600;
  line-height: var(--lh-tight);
  letter-spacing: -0.012em;
}

.subtitle {
  margin: var(--sp-1) 0 0;
  color: var(--muted);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
}

/* Square icon buttons in the top bar: ☰ (phone only) and ↻. Qualified with
   .btn because the .btn rule comes later in this file and would win a tie. */
.btn.topbar-icon-btn {
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  font-size: 1.1rem;
  line-height: 1;
}

.btn.topbar-menu {
  display: none;
}

@media (max-width: 760px) {
  .topbar {
    /* Stays reachable while a long list scrolls underneath. */
    position: sticky;
    top: 0;
    z-index: 20;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    padding-top: max(var(--sp-3), env(safe-area-inset-top));
    padding-left: max(var(--sp-4), env(safe-area-inset-left));
    padding-right: max(var(--sp-4), env(safe-area-inset-right));
  }

  .btn.topbar-menu {
    display: inline-flex;
  }

  .brand {
    flex: 1;
    min-width: 0;
  }

  .brand h1 {
    font-size: var(--fs-lg);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* The drawer's "All (n)" carries the count; the title needs the room. */
  .subtitle,
  .topbar-actions .meta {
    display: none;
  }
}

.meta {
  color: var(--muted);
  font-size: var(--fs-sm);
}

.load-error {
  flex: 1 1 100%;
  margin-top: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--warn);
  background: color-mix(in srgb, var(--warn) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 28%, transparent);
  border-radius: var(--r-sm);
}

.load-error.hidden {
  display: none;
}

.layout {
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr) 360px;
  min-height: calc(100vh - 72px);
  min-height: calc(100dvh - 72px);
}

@media (max-width: 1100px) {
  .layout {
    grid-template-columns: 200px minmax(0, 1fr);
  }
  /* The detail panel's tablet and phone rules sit after its base rule, further
     down: written here, its later `position: relative` silently won and the
     "overlay" rendered at the bottom of the page instead. */
}

/* Wider than a phone: an app shell. The top bar and any banner keep their
   height, the layout fills the rest of the screen, and the sidebar, the list
   and the detail panel each scroll on their own. When the page scrolled as a
   whole, both menus stayed at the top while you read further down the list.
   The flex column absorbs the top bar's changing height (a wrapped load error,
   the offline banner), which a fixed offset could not. */
@media (min-width: 761px) {
  #root {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
  }

  .layout {
    flex: 1;
    min-height: 0;
    grid-template-rows: minmax(0, 1fr);
  }

  .sidebar {
    overflow-y: auto;
  }
}

.drawer-backdrop {
  display: none;
}

/* Phone: one column, and the sidebar becomes an off-canvas drawer opened from
   the top bar's ☰ or a sideways swipe. After the tablet block above so it
   wins the tie. */
@media (max-width: 760px) {
  .layout {
    grid-template-columns: minmax(0, 1fr);
  }

  .sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 30;
    width: min(300px, 85vw);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-top: max(var(--sp-5), env(safe-area-inset-top));
    padding-bottom: max(var(--sp-5), env(safe-area-inset-bottom));
    transform: translateX(-100%);
    /* Hidden, not just off-screen, so its buttons leave the tab order. The
       delay keeps it visible while it slides out. */
    visibility: hidden;
    transition: transform 200ms var(--ease), visibility 0s linear 200ms;
  }

  .sidebar.open {
    transform: none;
    visibility: visible;
    transition-delay: 0s;
    box-shadow: var(--shadow-lg);
  }

  /* Always in the page, hidden until open, so a swipe can fade it in as the
     drawer follows the finger (useDrawerSwipe.js sets both inline mid-drag). */
  .drawer-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 25;
    background: rgba(4, 6, 10, 0.6);
    opacity: 0;
    visibility: hidden;
    transition: opacity 200ms var(--ease), visibility 0s linear 200ms;
  }

  .drawer-backdrop.open {
    opacity: 1;
    visibility: visible;
    transition-delay: 0s;
  }

  /* The page behind an open drawer must not scroll. */
  body:has(.sidebar.open) {
    overflow: hidden;
  }
}

.sidebar {
  padding: var(--sp-5) var(--sp-4);
  padding-left: max(var(--sp-4), env(safe-area-inset-left));
  border-right: 1px solid var(--border);
  background: var(--surface);
}

.sidebar h2,
.sidebar h3 {
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin: 0 0 var(--sp-3);
}

.source-filters {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.filter-btn {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  width: 100%;
  text-align: left;
  padding: 0.4rem var(--sp-3);
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-soft);
  cursor: pointer;
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}

/* Hover rules sit inside (hover: hover) so a tap on a touch screen does not
   leave them stuck on. Where a selector list mixed :hover with a state
   (.active, .selected, :focus), the state half stays outside, in place. */
@media (hover: hover) {
  .filter-btn:hover {
    background: var(--surface-2);
    border-color: var(--border);
    color: var(--text);
  }
}

.filter-btn.active {
  background: var(--surface-2);
  border-color: var(--border);
  color: var(--text);
}

.filter-btn.active {
  background: var(--accent-weak);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  color: var(--text);
  font-weight: 600;
}

@media (hover: hover) {
  .filter-btn.active:hover {
    background: var(--accent-weak);
    border-color: color-mix(in srgb, var(--accent) 40%, transparent);
    color: var(--text);
    font-weight: 600;
  }
}

.filter-btn .count {
  color: var(--muted);
  font-size: var(--fs-xs);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}

.filter-btn[data-source="bookmarks"].active {
  border-color: color-mix(in srgb, var(--bookmark) 40%, transparent);
  background: color-mix(in srgb, var(--bookmark) 10%, transparent);
}

.filter-btn[data-source="memes"].active {
  border-color: color-mix(in srgb, var(--meme) 45%, transparent);
  background: color-mix(in srgb, var(--meme) 12%, transparent);
}

.badge.bookmarks {
  background: var(--bookmark);
  color: var(--bg);
}

.badge.memes {
  background: var(--meme);
  color: var(--bg);
}

.memes-links {
  list-style: none;
  margin: 0;
  padding: var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.memes-links a {
  color: var(--accent-hover);
  text-decoration: none;
  font-size: var(--fs-md);
}

@media (hover: hover) {
  .memes-links a:hover {
    text-decoration: underline;
  }
}

.item-card.bookmarked {
  border-bottom-color: color-mix(in srgb, var(--bookmark) 28%, var(--border));
}

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

.item-bookmark-tweet {
  margin: var(--sp-2) 0 var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-sm);
  border-left: 2px solid var(--bookmark);
  background: color-mix(in srgb, var(--bookmark) 7%, var(--surface-2));
  color: var(--text-soft);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  white-space: pre-wrap;
  word-break: break-word;
}

.bookmark-section {
  margin: var(--sp-5) 0;
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--surface-2);
}

.bookmark-section h3 {
  margin: 0;
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.bookmark-section-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}

.bookmark-saved-at {
  font-size: var(--fs-2xs);
  color: var(--muted);
}

.bookmark-hint {
  margin: var(--sp-2) 0 var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--muted);
}

.bookmark-tweet {
  margin: 0 0 var(--sp-4);
  padding: var(--sp-4);
  border-radius: var(--r-sm);
  background: var(--bg);
  border: 1px solid var(--border);
  font-family: inherit;
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--text-soft);
  white-space: pre-wrap;
  word-break: break-word;
}

.bookmark-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
}

.bookmark-section.bookmark-saved {
  border-color: color-mix(in srgb, var(--bookmark) 32%, var(--border));
  background: color-mix(in srgb, var(--bookmark) 5%, var(--surface-2));
}

.bookmark-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.bookmark-list-item {
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid transparent;
  background: var(--surface-3);
}

.bookmark-list-item-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-3);
}

.bookmark-list-item-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  justify-content: flex-end;
}

.bookmark-entry-card .item-bookmark-tweet {
  margin-top: var(--sp-2);
}

.discovery-status {
  display: block;
  margin-top: var(--sp-5);
}

.discovery-status ul {
  list-style: none;
  padding: 0;
  margin: 0;
  font-size: var(--fs-xs);
}

.discovery-status li {
  padding: 0.3rem 0;
  color: var(--muted);
  line-height: var(--lh-snug);
}

.discovery-status li.ok {
  color: var(--success);
}

.discovery-status li.err {
  color: var(--error);
}

/* Ran, but degraded — distinct from both clean success and outright failure. */
.discovery-status li.warn {
  color: var(--warning);
}

.discovery-status li.idle {
  color: var(--muted);
}

/* Long messages must wrap rather than force the sidebar wider. */
.discovery-status li span {
  overflow-wrap: anywhere;
}

.run-warnings {
  margin-top: 0.2rem;
}

.run-warnings summary {
  cursor: pointer;
  font-size: var(--fs-2xs);
  opacity: 0.85;
}

.run-warning-items {
  margin-top: 0.2rem;
  padding-left: var(--sp-3);
}

.run-warning {
  position: relative;
  padding: 0.1rem 0;
  color: inherit;
  font-size: var(--fs-2xs);
  overflow-wrap: anywhere;
}

.run-warning::before {
  content: "·";
  position: absolute;
  left: -0.7rem;
}

.main {
  padding: var(--sp-5) var(--sp-6);
  overflow-y: auto;
}

.loading,
.empty {
  text-align: center;
  padding: var(--sp-7);
  color: var(--muted);
  font-size: var(--fs-md);
}

.source-sections {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

.source-section {
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

.source-section.hidden-section {
  display: none;
}

.source-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  flex-wrap: wrap;
}

.source-header-left {
  flex: 1 1 200px;
  min-width: 0;
}

.source-run-hint {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-xs);
  color: var(--muted);
  line-height: var(--lh-snug);
}

.source-header-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex: 1 1 auto;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.source-sub-header {
  padding: var(--sp-3) var(--sp-5);
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}

/* Phone: give the list the width, and stack a section's controls under its
   title instead of right-aligning them into ragged rows. */
@media (max-width: 760px) {
  .main {
    padding: var(--sp-4) var(--sp-3);
    padding-left: max(var(--sp-3), env(safe-area-inset-left));
    padding-right: max(var(--sp-3), env(safe-area-inset-right));
  }

  .source-sections {
    gap: var(--sp-5);
  }

  .source-header {
    gap: var(--sp-3);
    padding: var(--sp-4);
  }

  .source-header-actions {
    flex: 1 1 100%;
    justify-content: flex-start;
  }

  .source-sub-header {
    padding: var(--sp-3) var(--sp-4);
  }
}

.list-sort {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-xs);
  color: var(--muted);
}

.list-sort-label {
  white-space: nowrap;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}

.list-sort-select {
  font: inherit;
  font-size: var(--fs-xs);
  color: var(--text);
  background: var(--surface-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  padding: 0.25rem var(--sp-3);
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}

@media (hover: hover) {
  .list-sort-select:hover {
    border-color: color-mix(in srgb, var(--accent) 55%, var(--border-strong));
    outline: none;
  }
}

.list-sort-select:focus {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--border-strong));
  outline: none;
}

.source-header h2 {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: var(--lh-tight);
  letter-spacing: -0.006em;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.1rem 0.4rem;
  border-radius: var(--r-xs);
  font-size: var(--fs-2xs);
  font-weight: 700;
  line-height: 1.5;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.badge.hackernews { background: var(--hn); color: var(--bg); }
.badge.reddit { background: var(--reddit); color: var(--bg); }
.badge.twitter { background: var(--twitter); color: var(--bg); }
.badge.github { background: var(--github); color: var(--bg); }
.badge.news { background: var(--news); color: var(--bg); }
.badge.blog { background: var(--blog); color: var(--bg); }
.badge.communities { background: var(--communities); color: var(--bg); }

.item-badges {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
}

.badge-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  padding: 0.05rem 0.45rem;
  border-radius: var(--r-full);
  font-size: var(--fs-2xs);
  font-weight: 500;
  line-height: 1.6;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.badge-pill.warn {
  color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 30%, transparent);
  background: color-mix(in srgb, var(--warn) 10%, transparent);
}

.badge-pill.high {
  color: var(--success);
  border-color: color-mix(in srgb, var(--success) 35%, transparent);
  background: color-mix(in srgb, var(--success) 12%, transparent);
}

.badge-pill.med {
  color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 30%, transparent);
  background: color-mix(in srgb, var(--warn) 10%, transparent);
}

/* --- Source enable/disable --------------------------------------------- */

.filter-btn.source-off {
  opacity: 0.55;
}

/* A switch inside the filter row; clicking it must not select the source. */
.source-switch {
  float: right;
  width: 1.6rem;
  height: 0.85rem;
  margin-left: var(--sp-2);
  border-radius: 999px;
  cursor: pointer;
  position: relative;
  transition: background 0.12s ease;
}

.source-switch.on {
  background: var(--success);
}

.source-switch.off {
  background: var(--border);
}

.source-switch::after {
  content: "";
  position: absolute;
  top: 0.12rem;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: var(--bg);
  transition: left 0.12s ease;
}

.source-switch.on::after {
  left: 0.88rem;
}

.source-switch.off::after {
  left: 0.12rem;
}

/* Offline: the switch keeps its state but cannot be flipped (Sidebar.jsx). */
.source-switch[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
}

.discovery-status li.off {
  color: var(--muted);
  font-style: italic;
}

/* Items are kept, so the section still renders — just visibly inert. */
.source-section.disabled .source-header h2 {
  opacity: 0.6;
}

/* --- Sidebar: platforms nested under Dev Communities -------------------- */

.source-filter-group {
  display: contents;
}

.platform-nav {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 2px 0 var(--sp-2) var(--sp-3);
  padding-left: var(--sp-2);
  border-left: 1px solid var(--border);
}

.platform-nav-btn {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.25rem 0.4rem;
  border: 0;
  border-radius: var(--r-xs);
  background: transparent;
  color: var(--fg-dim);
  font-size: var(--fs-2xs);
  text-align: left;
  cursor: pointer;
}

@media (hover: hover) {
  .platform-nav-btn:hover {
    color: var(--fg);
    background: rgba(255, 255, 255, 0.04);
  }
}

.platform-nav-btn.active {
  color: var(--fg);
  background: rgba(45, 212, 191, 0.16);
}

/* Disabled in config — still listed, because a hidden platform is
   indistinguishable from one that was never set up. */
.platform-nav-btn.off {
  opacity: 0.55;
}

.platform-nav-off {
  padding: 0 0.25rem;
  border-radius: var(--r-xs);
  background: var(--border);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.platform-nav-btn .count {
  margin-left: auto;
  opacity: 0.7;
}

/* --- Dev Communities platform panel ------------------------------------ */

/* Reads config, not items, so it stays informative on a cold store. */
.platform-panel {
  margin-bottom: var(--sp-3);
  padding: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--bg-soft, rgba(255, 255, 255, 0.02));
}

.platform-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--sp-2);
}

.platform-panel-head h3 {
  margin: 0;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-dim);
}

.platform-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.platform-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-xs);
}

.platform-row.disabled {
  opacity: 0.5;
}

.platform-dot {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  flex-shrink: 0;
}

.platform-dot.lobsters { background: var(--lobsters); }
.platform-dot.devto    { background: var(--devto); }
.platform-dot.mastodon { background: var(--mastodon); }
.platform-dot.hashnode { background: var(--hashnode); }

.platform-name {
  font-weight: 600;
  min-width: 5.5rem;
}

.platform-coverage {
  color: var(--fg-dim);
}

.platform-count {
  margin-left: auto;
  color: var(--fg-dim);
  font-variant-numeric: tabular-nums;
}

/* Full tag/instance/blog list, hidden until asked for — it is long. */
.platform-sources {
  flex-basis: 100%;
  padding-left: 1.2rem;
  color: var(--fg-dim);
  font-size: var(--fs-2xs);
  line-height: 1.6;
  word-break: break-word;
}

.platform-panel-hint {
  margin: var(--sp-3) 0 0;
  font-size: var(--fs-2xs);
  color: var(--fg-dim);
}

.platform-panel-error {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-xs);
  color: var(--danger, #f87171);
}

/* --- Dev Communities platform sub-filter ------------------------------- */

.platform-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.platform-btn {
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  background: transparent;
  color: var(--fg-dim);
  font-size: var(--fs-2xs);
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.12s ease, color 0.12s ease;
}

@media (hover: hover) {
  .platform-btn:hover:not(:disabled) {
    color: var(--fg);
    border-color: var(--fg-dim);
  }
}

.platform-btn.active {
  color: var(--bg);
  background: var(--communities);
  border-color: var(--communities);
}

/* Kept visible rather than hidden: a zero here means the platform errored or
   was rate-limited, which is worth seeing. */
.platform-btn.empty {
  opacity: 0.4;
  cursor: not-allowed;
}

.platform-btn .count {
  font-weight: 400;
  opacity: 0.75;
}

/* Platform identity on each card, so a filtered-to-All list stays readable. */
.badge-pill.lobsters { background: var(--lobsters); color: #fff; border-color: transparent; }
.badge-pill.devto    { background: var(--devto);    color: #fff; border-color: transparent; }
.badge-pill.mastodon { background: var(--mastodon); color: #fff; border-color: transparent; }
.badge-pill.hashnode { background: var(--hashnode); color: #fff; border-color: transparent; }

.badge-pill.read {
  background: var(--success);
  color: var(--bg);
  border-color: transparent;
}

/* --- Article brief (two-step drafting) --------------------------------- */

.article-brief {
  margin: var(--sp-4) 0;
  padding: var(--sp-3);
  border: 1px solid var(--border);
  border-left: 3px solid var(--success);
  border-radius: var(--r-sm);
}

.article-brief h3 {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-dim);
}

.article-summary {
  margin: 0 0 var(--sp-2);
  line-height: var(--lh-normal, 1.55);
}

.article-points {
  margin: 0 0 var(--sp-2);
  padding-left: var(--sp-4);
}

.article-points li {
  margin-bottom: 0.2rem;
}

.article-details {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--fg-dim);
}

.article-quote {
  margin: 0 0 var(--sp-2);
  padding-left: var(--sp-3);
  border-left: 2px solid var(--border);
  font-style: italic;
  color: var(--fg-dim);
}

.article-meta {
  margin: 0;
  font-size: var(--fs-2xs);
  color: var(--muted);
}

.article-unread-warning {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-left: 3px solid var(--warning);
  border-radius: var(--r-xs);
  background: rgba(245, 166, 35, 0.08);
  font-size: var(--fs-xs);
  color: var(--fg-dim);
}

.article-unread-warning span {
  flex: 1 1 14rem;
}

.btn-read-article {
  flex-shrink: 0;
}

.article-error {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  margin: var(--sp-3) 0;
  padding: var(--sp-2) var(--sp-3);
  border-left: 3px solid var(--warning);
  font-size: var(--fs-xs);
  color: var(--fg-dim);
}

.badge-pill.ghost {
  border-color: transparent;
  background: transparent;
  padding-left: 0;
}

.item-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.list-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-5);
  border-top: 1px solid var(--border);
  background: var(--surface-2);
}

.pagination-meta {
  font-size: var(--fs-xs);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.pagination-controls {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.pagination-page {
  font-size: var(--fs-xs);
  color: var(--muted);
  min-width: 6.5rem;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.item-card {
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}

.item-card:last-child {
  border-bottom: none;
}

@media (hover: hover) {
  .item-card:hover {
    background: var(--accent-weak);
  }
}

.item-card.selected {
  background: var(--accent-weak);
}

.item-card.selected {
  background: var(--accent-soft);
  box-shadow: inset 2px 0 0 var(--accent-hover);
}

.item-card h3 {
  margin: 0 0 var(--sp-1);
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: var(--lh-tight);
  letter-spacing: -0.006em;
}

.item-meta {
  font-size: var(--fs-xs);
  color: var(--muted);
  margin-bottom: var(--sp-1);
}

.item-snippet {
  font-size: var(--fs-sm);
  color: var(--muted);
  margin: 0;
  line-height: var(--lh-snug);
}

.item-actions {
  margin-top: var(--sp-3);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  padding: 0.4rem var(--sp-4);
  border-radius: var(--r-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  color: var(--text);
  cursor: pointer;
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: var(--lh-snug);
  white-space: nowrap;
  text-decoration: none;
  box-shadow: var(--shadow-xs);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
    color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}

@media (hover: hover) {
  .btn:not(:disabled):hover {
    background: var(--surface-3);
    border-color: color-mix(in srgb, var(--accent) 40%, var(--border-strong));
    color: var(--text);
    text-decoration: none;
  }
}

.btn:not(:disabled):active {
  transform: translateY(1px);
  box-shadow: none;
}

.btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

@media (hover: hover) {
  .btn.primary:not(:disabled):hover {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
    color: #fff;
  }
}

.btn.ghost {
  background: transparent;
  border-color: var(--border);
  color: var(--text-soft);
  box-shadow: none;
}

.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
}

.detail-panel {
  padding: var(--sp-5) var(--sp-5) var(--sp-7);
  border-left: 1px solid var(--border);
  background: var(--surface);
  overflow-y: auto;
  position: relative;
}

.close-detail {
  position: absolute;
  top: var(--sp-3);
  right: var(--sp-3);
  width: 1.85rem;
  height: 1.85rem;
  padding: 0;
  font-size: 1.1rem;
  line-height: 1;
}

.close-detail-back {
  display: none;
}

/* Tablet: the panel covers the right side at full height, above everything.
   No backdrop, so the list stays clickable for switching items. */
@media (max-width: 1100px) {
  .detail-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    width: min(420px, 100%);
    padding-top: max(var(--sp-5), env(safe-area-inset-top));
    padding-right: max(var(--sp-5), env(safe-area-inset-right));
    padding-bottom: calc(var(--sp-7) + env(safe-area-inset-bottom));
    box-shadow: var(--shadow-lg);
    overscroll-behavior: contain;
  }

  .close-detail {
    top: max(var(--sp-3), env(safe-area-inset-top));
  }
}

/* Phone: a full-screen sheet with a sticky "← Back" bar. */
@media (max-width: 760px) {
  .detail-panel {
    width: 100%;
    padding-top: 0;
    border-left: 0;
  }

  /* Qualified with .btn to outrank .btn.ghost, whose transparent background
     and border would otherwise show through the sticky bar. */
  .btn.close-detail {
    position: sticky;
    top: 0;
    z-index: 2;
    display: flex;
    justify-content: flex-start;
    width: calc(100% + 2 * var(--sp-5));
    height: auto;
    min-height: calc(48px + env(safe-area-inset-top));
    margin: 0 calc(-1 * var(--sp-5)) var(--sp-3);
    padding: env(safe-area-inset-top) var(--sp-5) 0;
    font-size: var(--fs-md);
    font-weight: 600;
    color: var(--text);
    background: var(--surface);
    border: 0;
    border-bottom: 1px solid var(--border);
    border-radius: 0;
  }

  .close-detail-x {
    display: none;
  }

  .close-detail-back {
    display: inline;
  }

  /* aside.: the base .detail-panel h2 rule is declared below and would win. */
  aside.detail-panel h2 {
    padding-right: 0;
  }

  /* The list behind the sheet must not scroll; the sheet scrolls itself. */
  body:has(.detail-panel:not(.hidden)) {
    overflow: hidden;
  }
}

.detail-panel h2 {
  margin: var(--sp-3) 0 var(--sp-3);
  font-size: var(--fs-xl);
  font-weight: 600;
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
  padding-right: 2rem;
}

.detail-meta {
  font-size: var(--fs-xs);
  color: var(--muted);
  margin-bottom: var(--sp-5);
  line-height: var(--lh-snug);
}

.detail-snippet {
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  color: var(--text-soft);
  margin-bottom: var(--sp-6);
  white-space: pre-wrap;
}

.suggest-section {
  border-top: 1px solid var(--border);
  padding-top: var(--sp-5);
}

.suggest-section h3 {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-md);
  font-weight: 600;
  letter-spacing: -0.004em;
}

#tweetDraft {
  width: 100%;
  min-height: 110px;
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--text);
  font-family: inherit;
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  resize: vertical;
  transition: border-color var(--dur) var(--ease);
}

.thread-bullets {
  margin: var(--sp-4) 0 0;
  padding-left: var(--sp-6);
  font-size: var(--fs-sm);
  color: var(--muted);
  line-height: var(--lh-snug);
}

.suggest-empty {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--muted);
}

.generation-controls {
  margin: 0 0 var(--sp-4);
  padding: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
  max-height: 420px;
  overflow-y: auto;
}

.generation-controls-header h4 {
  margin: 0;
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.generation-controls-header p {
  margin: var(--sp-1) 0 var(--sp-4);
  font-size: var(--fs-xs);
  color: var(--muted);
  line-height: var(--lh-snug);
}

.control-group {
  margin-bottom: var(--sp-4);
}

.control-group:last-child {
  margin-bottom: 0;
}

.control-label {
  display: block;
  margin-bottom: var(--sp-1);
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.control-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.control-chip {
  border-radius: var(--r-full);
}

.control-chip.active {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--text);
}

@media (hover: hover) {
  .control-chip.active:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
    color: var(--text);
  }
}

.angle-controls {
  margin-top: var(--sp-3);
  padding: var(--sp-4);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-md);
}

.angle-row-tools {
  margin-bottom: var(--sp-2);
}

.control-help {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-2xs);
  color: var(--muted);
  line-height: var(--lh-snug);
}

.top-comments {
  margin: var(--sp-5) 0;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}

.top-comments-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-3);
}

.top-comments-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  justify-content: flex-end;
}

.top-comment-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-2);
}

.top-comments-header h3 {
  margin: 0;
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.top-comments-fetched {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-2xs);
  color: var(--muted);
}

.top-comments-empty {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  font-style: italic;
}

.top-comments-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.top-comment {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--surface-2);
}

.top-comment-meta {
  font-size: var(--fs-2xs);
  color: var(--muted);
  margin-bottom: var(--sp-1);
}

.top-comment-body {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--text-soft);
  white-space: pre-wrap;
  word-break: break-word;
}

.variants-stack {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
}

.variant-card {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
  overflow: hidden;
  cursor: pointer;
  box-shadow: var(--shadow-xs);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
    background var(--dur) var(--ease);
}

@media (hover: hover) {
  .variant-card:hover {
    border-color: color-mix(in srgb, var(--accent) 45%, var(--border-strong));
    box-shadow: var(--shadow-sm);
  }
}

.variant-card.selected {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent), var(--shadow-sm);
}

.variant-card-header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-1) var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border);
  background: var(--surface-3);
}

.variant-card.selected .variant-card-header {
  background: var(--accent-soft);
}

.variant-card-titles {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.variant-key {
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.variant-key-code {
  font-size: var(--fs-2xs);
  font-family: var(--font-mono);
  color: var(--muted);
  padding: 0.05rem 0.35rem;
  border-radius: var(--r-xs);
  border: 1px solid var(--border);
  background: var(--bg);
}

.variant-hint {
  font-size: var(--fs-2xs);
  color: var(--muted);
}

.variant-card-body {
  margin: 0;
  padding: var(--sp-4);
  font-family: inherit;
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--text-soft);
  white-space: pre-wrap;
  word-break: break-word;
}

.variant-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--border);
}

.btn-sm {
  padding: 0.25rem 0.6rem;
  font-size: var(--fs-xs);
}

.draft-edit-section {
  margin-top: var(--sp-1);
}

.draft-edit-section.hidden {
  display: none;
}

.draft-edit-label {
  display: block;
  margin-bottom: var(--sp-2);
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.tweet-draft-standalone {
  width: 100%;
  min-height: 110px;
  padding: var(--sp-4);
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--text);
  font-family: inherit;
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  resize: vertical;
  transition: border-color var(--dur) var(--ease);
}

.prompt-modal {
  border: none;
  padding: 0;
  max-width: min(720px, 92vw);
  width: 100%;
  background: transparent;
  color: var(--text);
}

.prompt-modal::backdrop {
  background: rgba(4, 6, 10, 0.66);
  backdrop-filter: blur(3px);
}

.prompt-modal-panel {
  display: flex;
  flex-direction: column;
  max-height: min(85vh, 720px);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.prompt-modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
  border-bottom: 1px solid var(--border);
}

.prompt-modal-header h2 {
  margin: 0;
  font-size: var(--fs-lg);
  font-weight: 600;
  line-height: var(--lh-tight);
  letter-spacing: -0.006em;
}

.prompt-modal-meta {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-xs);
  color: var(--muted);
  line-height: var(--lh-snug);
}

.prompt-modal-close {
  font-size: 1.1rem;
  line-height: 1;
  padding: 0.1rem 0.45rem;
}

.prompt-modal-text {
  flex: 1;
  margin: 0;
  padding: var(--sp-5);
  overflow: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
  background: var(--bg);
  border: none;
  color: var(--text-soft);
}

.prompt-modal-footer {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-5) var(--sp-5);
  border-top: 1px solid var(--border);
}

/* Phone: the prompt preview takes the whole screen. The base rules cap it at
   92vw × 85vh with a rounded frame, which on a phone wastes the margins and
   leaves a sliver of page around a long monospace wall. */
@media (max-width: 760px) {
  .prompt-modal {
    width: 100%;
    max-width: none;
    height: 100dvh;
    max-height: none;
    margin: 0;
  }

  .prompt-modal-panel {
    height: 100%;
    max-height: none;
    border: 0;
    border-radius: 0;
    padding-top: env(safe-area-inset-top);
  }

  .prompt-modal-footer {
    padding-bottom: calc(var(--sp-5) + env(safe-area-inset-bottom));
  }
}

.suggest-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
}

.empty-list {
  padding: var(--sp-6);
  text-align: center;
  color: var(--muted);
  font-size: var(--fs-sm);
}

.twitter-band-tabs,
.band-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.twitter-band-btn,
.band-btn {
  font-size: var(--fs-xs);
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-full);
  background: var(--surface-3);
  color: var(--text-soft);
  cursor: pointer;
  line-height: var(--lh-snug);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
    color var(--dur) var(--ease);
}

@media (hover: hover) {
  .twitter-band-btn:hover,
  .band-btn:hover {
    border-color: color-mix(in srgb, var(--accent) 45%, var(--border-strong));
    color: var(--text);
  }
}

.twitter-band-btn.active,
.band-btn.active {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--text);
}

/* Phone: every filter tab row is one line you swipe, not a wrapped block
   that pushes the list down. The row bleeds to the sub-header's edges so the
   swipe starts at the screen edge. After the tab rules above, to win ties. */
@media (max-width: 760px) {
  .platform-tabs,
  .twitter-band-tabs,
  .band-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    margin: 0 calc(-1 * var(--sp-4));
    padding: 0 var(--sp-4);
  }

  .platform-tabs::-webkit-scrollbar,
  .twitter-band-tabs::-webkit-scrollbar,
  .band-tabs::-webkit-scrollbar {
    display: none;
  }

  .platform-btn,
  .twitter-band-btn,
  .band-btn {
    flex: none;
    white-space: nowrap;
  }
}

.item-summary {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  line-height: var(--lh-snug);
}

.comments-nudge.warn {
  color: var(--warn, #b45309);
  font-size: var(--fs-sm);
  margin: var(--sp-1) 0 0;
}

.reply-suggest-section {
  margin: var(--sp-5) 0;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}

.reply-draft {
  width: 100%;
  min-height: 4.5rem;
  margin: var(--sp-3) 0;
  padding: var(--sp-3) var(--sp-4);
  font: inherit;
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  background: var(--bg);
  color: var(--text);
  resize: vertical;
  transition: border-color var(--dur) var(--ease);
}

.reply-variants-list {
  list-style: none;
  margin: var(--sp-3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.reply-variants-list .btn-reply-variant {
  display: flex;
  width: 100%;
  justify-content: flex-start;
  text-align: left;
  white-space: normal;
  height: auto;
  line-height: var(--lh-snug);
}

.reply-variants-list .btn-reply-variant.active {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--text);
}

.twitter-insights-panel {
  padding: var(--sp-5) var(--sp-5) 0;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}

.insights-hint {
  font-size: var(--fs-xs);
  color: var(--muted);
  margin: 0 0 var(--sp-4);
  line-height: var(--lh-snug);
}

.insight-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}

.insight-card {
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-4);
  background: var(--surface-3);
  box-shadow: var(--shadow-xs);
}

.insight-card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-3);
  margin-bottom: var(--sp-2);
}

.insight-card-header h3 {
  margin: 0;
  font-size: var(--fs-sm);
  font-weight: 600;
  line-height: var(--lh-tight);
}

.insight-card-body {
  font-size: var(--fs-sm);
  color: var(--text-soft);
  margin: 0;
  line-height: var(--lh-snug);
}

.insight-draft {
  margin: var(--sp-3) 0 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  font-style: italic;
  line-height: var(--lh-snug);
}

.thread-section {
  margin-top: var(--sp-4);
  padding-top: var(--sp-3);
  border-top: 1px dashed var(--border-strong);
}

.thread-section h4 {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.thread-tweets-list {
  margin: var(--sp-2) 0 0;
  padding-left: var(--sp-6);
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
}

.thread-order {
  font-weight: 600;
  color: var(--muted);
  margin-right: var(--sp-1);
}

.detail-actions-twitter {
  margin: var(--sp-4) 0;
}

.btn-danger {
  border-color: color-mix(in srgb, var(--error) 40%, var(--border-strong));
  color: var(--error);
  background: transparent;
}

@media (hover: hover) {
  .btn-danger:not(:disabled):hover {
    background: color-mix(in srgb, var(--error) 12%, transparent);
    border-color: var(--error);
    color: var(--error);
  }
}

/* ==========================================================================
   Detail sheet internals on phones. After every base rule it overrides
   (generation controls, draft, actions, warnings) so it wins the ties.
   ========================================================================== */

@media (max-width: 760px) {
  /* A 420px scroll box inside a scrolling sheet: two thumbs fighting over
     one swipe. On a phone the controls simply take their full height. */
  .generation-controls {
    max-height: none;
    overflow: visible;
  }

  #tweetDraft {
    min-height: 140px;
  }

  /* The actions stick to the bottom of the sheet while you read variants and
     edit the draft, as one swipeable row with the common ones first. It sits
     inside the suggestions section, so it only appears once you are there. */
  .suggest-actions {
    position: sticky;
    /* Sticky offsets are measured inside the sheet's padding, so bottom: 0
       would park the bar 32px up with text scrolling beneath it. Cancel the
       sheet's bottom padding (phone rule above) to sit on the screen edge. */
    bottom: calc(-1 * (var(--sp-7) + env(safe-area-inset-bottom, 0px)));
    z-index: 1;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    margin: var(--sp-4) calc(-1 * var(--sp-5)) 0;
    padding: var(--sp-3) var(--sp-5) calc(var(--sp-3) + env(safe-area-inset-bottom));
    background: var(--surface);
    border-top: 1px solid var(--border);
  }

  .suggest-actions::-webkit-scrollbar {
    display: none;
  }

  .suggest-actions .btn {
    flex: none;
  }

  /* Order only; the markup keeps its own order for wide screens. */
  #btnSuggest { order: 0; }
  #btnCopy { order: 1; }
  #btnShare { order: 2; }
  #btnSaveDraft { order: 3; }
  #btnBookmark { order: 4; }
  #btnPreviewPrompt { order: 5; }
  #btnPostToX { order: 6; }

  .detail-actions-twitter .btn,
  .article-unread-warning .btn {
    width: 100%;
  }
}

/* ==========================================================================
   Keyboard focus — one visible ring on everything interactive.
   A translucent box-shadow is used (rather than outline alone) so the ring
   survives the `outline: none` rules in login.html and follows border radii.
   ========================================================================== */

button:focus-visible,
a:focus-visible,
select:focus-visible,
input:focus-visible,
textarea:focus-visible,
pre:focus-visible,
summary:focus-visible {
  outline: 2px solid transparent;
  outline-offset: 2px;
  box-shadow: 0 0 0 3px var(--accent-ring);
  border-color: var(--accent);
}

/* ==========================================================================
   Reduced motion — drop every transition added above.
   ========================================================================== */

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

/* ==========================================================================
   Feedback — 👍/👎 on ideas and on each generated draft
   ========================================================================== */

.feedback-buttons {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.feedback-buttons.compact {
  flex-direction: row;
  align-items: center;
}

.feedback-row {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  flex-wrap: wrap;
}

.feedback-good,
.feedback-bad {
  /* The emoji carries the meaning; the button is a neutral frame until it is
     the active choice. A permanently coloured pair reads as a warning. */
  min-width: 2.6rem;
  line-height: 1.2;
}

.feedback-good.active {
  border-color: var(--success);
  color: var(--success);
  background: rgba(62, 212, 146, 0.12);
}

.feedback-bad.active {
  border-color: var(--error);
  color: var(--error);
  background: rgba(240, 119, 126, 0.12);
}

.feedback-reason-shown {
  font-size: var(--fs-2xs);
  color: var(--muted);
  font-style: italic;
  max-width: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.feedback-reason-form {
  display: flex;
  gap: var(--sp-2);
  align-items: center;
}

.feedback-reason-input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.3rem 0.6rem;
  font-family: inherit;
  font-size: var(--fs-xs);
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 4px);
}

.feedback-reason-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-ring);
}

.feedback-error {
  margin: 0;
  font-size: var(--fs-2xs);
  color: var(--error);
}

.detail-idea-feedback {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  margin-bottom: var(--sp-3);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 4px);
}

.detail-feedback-label {
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}


/* --- sidebar footer: sign out ---------------------------------------------- */

/* Last in the sidebar, which on a phone is inside the drawer. */
.sidebar-footer {
  margin-top: var(--sp-4);
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}

.btn.sidebar-signout {
  width: 100%;
}


/* --- learning status panel ------------------------------------------------ */

.learning-panel {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  font-size: var(--fs-2xs);
  border-top: 1px solid var(--border);
}

.learning-panel h4 {
  margin: 0;
  font-size: var(--fs-2xs);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.learning-metric {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  color: var(--text-soft);
}

.learning-metric .learning-value {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.learning-metric.active .learning-value {
  color: var(--success);
}

.learning-bar {
  height: 3px;
  background: var(--surface-3);
  border-radius: 2px;
  overflow: hidden;
}

.learning-bar span {
  display: block;
  height: 100%;
  background: var(--accent);
}

.learning-bar.active span {
  background: var(--success);
}

.learning-exports {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.learning-exports a {
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px dotted var(--border-strong);
}

@media (hover: hover) {
  .learning-exports a:hover {
    color: var(--accent-hover);
  }
}

/* --- HN quality: debate digest + advisory draft flags --------------------- */

.debate-digest {
  margin: var(--sp-2) 0 var(--sp-3);
  padding: var(--sp-3);
  font-size: var(--fs-xs);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 4px);
}

.debate-digest summary {
  cursor: pointer;
  color: var(--text-soft);
  font-weight: 600;
}

.debate-digest-body p {
  margin: var(--sp-2) 0 0;
  color: var(--text-soft);
  line-height: var(--lh-body);
}

.variant-flags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1);
  margin: 0;
  padding: 0 var(--sp-4) var(--sp-2);
  list-style: none;
}

.variant-flag {
  /* Amber, not red: these never block anything, and a red badge on a draft
     the reader is free to post would be lying about how serious it is. */
  padding: 0.1rem 0.45rem;
  font-size: var(--fs-2xs);
  color: var(--warning);
  background: rgba(245, 166, 35, 0.12);
  border: 1px solid rgba(245, 166, 35, 0.35);
  border-radius: 999px;
  cursor: help;
}

.variant-flag.info {
  color: var(--muted);
  background: var(--surface-3);
  border-color: var(--border);
}

/* ==========================================================================
   Update bar — a newer deploy is waiting in the service worker
   ========================================================================== */

.update-bar {
  position: fixed;
  left: 50%;
  bottom: calc(var(--sp-5) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  z-index: 50;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  max-width: calc(100vw - 2 * var(--sp-5));
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-5);
  font-size: var(--fs-sm);
  color: var(--text);
  background: var(--surface-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-full);
  box-shadow: var(--shadow-lg);
}

.update-bar .btn {
  border-radius: var(--r-full);
}

/* --- offline: the queue as last loaded ------------------------------------ */

.offline-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3) var(--sp-4);
  padding: var(--sp-3) var(--sp-6);
  padding-left: max(var(--sp-6), env(safe-area-inset-left));
  padding-right: max(var(--sp-6), env(safe-area-inset-right));
  font-size: var(--fs-sm);
  color: var(--text);
  background: color-mix(in srgb, var(--warn) 12%, var(--surface));
  border-bottom: 1px solid color-mix(in srgb, var(--warn) 35%, var(--border));
}

@media (max-width: 760px) {
  .offline-banner {
    padding-inline: max(var(--sp-5), env(safe-area-inset-left)) max(var(--sp-5), env(safe-area-inset-right));
  }
}

/* --- in-app toast and confirm (replace alert/confirm) --------------------- */

.toast-stack {
  position: fixed;
  left: 50%;
  bottom: calc(var(--sp-5) + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  /* Above the detail sheet, the drawer and the update bar. */
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  width: min(440px, calc(100vw - 2 * var(--sp-5)));
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-2) var(--sp-3) var(--sp-5);
  font-size: var(--fs-sm);
  color: var(--text);
  background: var(--surface-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
}

.toast.error {
  border-color: color-mix(in srgb, var(--error) 55%, var(--border-strong));
}

.toast-message {
  flex: 1;
  min-width: 0;
  max-height: 30vh;
  overflow-y: auto;
  padding-block: var(--sp-1);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.btn.toast-close {
  flex: none;
  padding: 0 var(--sp-3);
  font-size: var(--fs-lg);
  line-height: 1.6;
}

/* On a phone with the detail sheet open, clear its sticky action bar. */
@media (max-width: 760px) {
  body:has(.detail-panel:not(.hidden)) .toast-stack {
    bottom: calc(76px + env(safe-area-inset-bottom, 0px));
  }
}

.confirm-dialog {
  width: min(420px, calc(100vw - 2 * var(--sp-5)));
  max-width: none;
  padding: 0;
  color: var(--text);
  background: transparent;
  border: none;
}

.confirm-dialog::backdrop {
  background: rgba(4, 6, 10, 0.66);
}

.confirm-dialog-panel {
  padding: var(--sp-5);
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
}

.confirm-dialog-message {
  margin: 0 0 var(--sp-5);
  max-height: 50vh;
  overflow-y: auto;
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.confirm-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-3);
}

/* ==========================================================================
   Long unbreakable content — URLs, handles, hashes and endpoints are normal in
   fetched posts and comments. Break them instead of letting one word push a
   card past its section (where it is silently cut off) or the detail sheet
   sideways. break-word only acts where a word would otherwise overflow, so
   ordinary text lays out exactly as before, at every width.
   ========================================================================== */

.main,
.detail-panel,
.sidebar,
.prompt-modal {
  overflow-wrap: break-word;
}

/* Flex items size to their longest word, which break-word does not change.
   These rows need anywhere (it lowers that minimum) and permission to shrink. */
.badge-pill,
.top-comment-meta,
.reply-variants-list .btn-reply-variant {
  overflow-wrap: anywhere;
}

.badge-pill {
  max-width: 100%;
}

.top-comment-row > :first-child {
  min-width: 0;
}

/* ==========================================================================
   Touch targets — on a coarse pointer every control is at least 44px tall
   (40px for .btn-sm), with 8px between small neighbours. Keyed off
   (pointer: coarse), not width, so a mouse never sees it. Last in the file so
   it wins ties with the base rules above.
   ========================================================================== */

@media (pointer: coarse) {
  .btn,
  .filter-btn,
  .platform-btn,
  .twitter-band-btn,
  .band-btn,
  .platform-nav-btn,
  .control-chip,
  .list-sort-select {
    min-height: 44px;
  }

  .btn-sm {
    min-height: 40px;
  }

  .btn.topbar-icon-btn,
  .close-detail,
  .feedback-good,
  .feedback-bad {
    min-width: 44px;
    min-height: 44px;
  }

  /* baseline alignment would pin the label to the top of a taller row. */
  .filter-btn {
    align-items: center;
  }

  /* The larger × on tablets would otherwise sit on the title's last word. */
  .detail-panel h2 {
    padding-right: 3.25rem;
  }

  /* The switch keeps its drawn size; an invisible pad around it takes the tap. */
  .source-switch::before {
    content: "";
    position: absolute;
    inset: -15px -12px;
  }

  .feedback-row,
  .control-row,
  .variant-card-actions,
  .top-comments-toolbar,
  .bookmark-actions,
  .bookmark-list-item-actions {
    gap: var(--sp-3);
  }
}

/* ==========================================================================
   No zoom when typing — iOS zooms the page in when a field under 16px takes
   focus, and does not zoom back out. Every text field in the app, listed by
   the selector that sizes it (#tweetDraft's id outranks a plain textarea
   rule). Coarse pointers only, so desktop keeps its compact type.
   ========================================================================== */

@media (pointer: coarse) {
  input,
  select,
  textarea,
  #tweetDraft,
  .tweet-draft-standalone,
  .reply-draft,
  .feedback-reason-input,
  .list-sort-select {
    font-size: 16px;
  }
}
