:root {
  /* True OLED black - not the near-black #0a0a0e this used to be. Makes the
     UI disappear into the phone bezel on OLED screens instead of reading as
     a dark-gray "admin dashboard" surface. --bg-elevated/-2 stay as they
     were, since they were already a full tier lighter than the old --bg and
     read even more clearly as "raised" now that the base is truly black. */
  --bg: #000000;
  --bg-elevated: #15161b;
  --bg-elevated-2: #1d1e24;
  --accent: #e50914;
  --accent-hover: #f6121d;
  --accent-glow: rgba(229, 9, 20, 0.25);
  --teal: #22b8b0;
  --teal-hover: #2dd4c8;
  --teal-glow: rgba(34, 184, 176, 0.22);
  /* Text-safe teal - identical to --teal in dark mode (8.6:1 on black, no
     issue there), but --teal itself only hits 2.5:1 against a white/light
     background, well under the 4.5:1 AA floor for text. Every place teal
     is used as a TEXT color (not a background/border/glow) should read
     this token instead so the light theme override below can substitute a
     darker, still-recognizably-teal shade that actually passes contrast. */
  --teal-text: var(--teal);
  /* Status colors - dark-theme defaults matched to what used to be
     hardcoded directly in .field-error/.field-hint-warn/.field-success and
     the online-status dot. Those hex values were tuned to read well
     against OLED black only; on the light theme's white background they
     drop to 1.7-2.8:1 (badly failing AA) since nothing there ever
     adjusted them. Light-theme override below substitutes darker,
     still-clearly-red/amber/green shades that actually pass. */
  --status-warn: #ffb4b4;
  --status-error: #ff6b6b;
  --status-success: #4ade80;
  /* --accent itself is 4.38:1 on black (dark default), just under the
     4.5:1 AA text floor; --accent-hover clears it at 5.02:1. On the light
     theme's white background plain --accent already passes at 4.80:1, so
     this token points at different values per theme rather than always
     using the (there, unnecessary) lighter hover shade. */
  --accent-link: var(--accent-hover);
  --text: #f2f2f2;
  --text-dim: #9aa0a6;
  --text-dimmer: rgba(255, 255, 255, 0.6);
  --text-faint: rgba(255, 255, 255, 0.38);
  --border: #24262c;
  --border-subtle: rgba(255, 255, 255, 0.07);
  --border-focus: rgba(34, 184, 176, 0.45);
  --radius: 12px;
  --radius-lg: 20px;
  --radius-pill: 999px;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --transition: all 0.2s var(--ease);

  /* ---- Theme-able surface tokens (dark defaults) ----
     Generic translucent-white "wash" tints used all over for hover states,
     subtle fills and hairline separators. Named by intensity, not by where
     they're used, since the same 0.03/0.04/etc value shows up in dozens of
     unrelated places. Light theme below flips these to translucent black
     at roughly matching visual weight. */
  --surf-1: rgba(255,255,255,0.03);
  --surf-2: rgba(255,255,255,0.04);
  --surf-3: rgba(255,255,255,0.05);
  --surf-4: rgba(255,255,255,0.06);
  --surf-6: rgba(255,255,255,0.12);
  --surf-9: rgba(255,255,255,0.015);
  --divider-color: rgba(255,255,255,0.08);
  /* Sticky/fixed page chrome (topbar, mobile tab bar) - a translucent dark
     glass in dark mode, translucent light glass in light mode. */
  --chrome-bg: rgba(10,10,14,0.72);
  --chrome-bg-strong: rgba(10,10,14,0.85);
  /* Elevated floating glass panels: toast/status dock, invite popups. */
  --panel-glass-bg: rgba(21,22,27,0.93);
  /* Chat surfaces (chats.html workspace + floating widget) - these were
     hand-picked WhatsApp-dark-mode colors, not derived from the generic
     --bg-elevated scale, so they get their own tokens. */
  --chat-sidebar-bg: #111b21;
  --chat-thread-bg: #0b141a;
  --chat-search-input-bg: #202c33;
  --chat-composer-bg: rgba(32, 44, 51, 0.9);
  --chat-drawer-bg: #0c0c10;
  --btn-secondary-hover-bg: #292933;
  --body-glow-color: #0d1a1a;
  /* Soft vignette shade for edge-blends (sidebar's inward fade) - a strong
     black works on dark backgrounds but reads as a bold gray-black stripe
     on white, so light theme dials the opacity way down rather than
     reusing the same value. */
  --edge-fade: rgba(0,0,0,0.7);
  /* Lets native form controls (scrollbars, checkboxes, date pickers)
     render in the matching dark/light style automatically. */
  color-scheme: dark;
}

/* ==================== Light theme ====================
   Two ways in: (1) the OS is set to light and the person hasn't manually
   picked a theme here (no [data-theme] attribute yet - handled by the
   media query below), or (2) they explicitly chose Light from Profile
   (theme.js sets [data-theme="light"] on <html> and persists it, so it
   wins regardless of OS setting). Manually picking Dark just removes any
   light override by setting [data-theme="dark"], which matches neither
   selector below and falls back to the plain dark :root values above. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme]) { --bg: #ffffff; --bg-elevated: #f4f5f7; --bg-elevated-2: #e9eaed; --text: #14181b; --text-dim: #55606a; --text-dimmer: rgba(0,0,0,0.62); --text-faint: rgba(0,0,0,0.4); --border: #d8dadd; --border-subtle: rgba(0,0,0,0.08); --border-focus: rgba(34,184,176,0.5); --surf-1: rgba(0,0,0,0.035); --surf-2: rgba(0,0,0,0.045); --surf-3: rgba(0,0,0,0.05); --surf-4: rgba(0,0,0,0.06); --surf-6: rgba(0,0,0,0.09); --surf-9: rgba(0,0,0,0.02); --divider-color: rgba(0,0,0,0.08); --chrome-bg: rgba(255,255,255,0.75); --chrome-bg-strong: rgba(255,255,255,0.85); --panel-glass-bg: rgba(255,255,255,0.92); --chat-sidebar-bg: #ffffff; --chat-thread-bg: #f2f3f5; --chat-search-input-bg: #eceef1; --chat-composer-bg: rgba(255,255,255,0.92); --chat-drawer-bg: #ffffff; --btn-secondary-hover-bg: #e4e6ea; --body-glow-color: #eaf5f4; --teal-text: #136763; --status-warn: #b3271e; --status-error: #c0281f; --status-success: #1a7a40; --accent-link: var(--accent); --edge-fade: rgba(0,0,0,0.10); color-scheme: light; }
}
:root[data-theme="light"] {
  --bg: #ffffff; --bg-elevated: #f4f5f7; --bg-elevated-2: #e9eaed; --text: #14181b; --text-dim: #55606a; --text-dimmer: rgba(0,0,0,0.62); --text-faint: rgba(0,0,0,0.4); --border: #d8dadd; --border-subtle: rgba(0,0,0,0.08); --border-focus: rgba(34,184,176,0.5); --surf-1: rgba(0,0,0,0.035); --surf-2: rgba(0,0,0,0.045); --surf-3: rgba(0,0,0,0.05); --surf-4: rgba(0,0,0,0.06); --surf-6: rgba(0,0,0,0.09); --surf-9: rgba(0,0,0,0.02); --divider-color: rgba(0,0,0,0.08); --chrome-bg: rgba(255,255,255,0.75); --chrome-bg-strong: rgba(255,255,255,0.85); --panel-glass-bg: rgba(255,255,255,0.92); --chat-sidebar-bg: #ffffff; --chat-thread-bg: #f2f3f5; --chat-search-input-bg: #eceef1; --chat-composer-bg: rgba(255,255,255,0.92); --chat-drawer-bg: #ffffff; --btn-secondary-hover-bg: #e4e6ea; --body-glow-color: #eaf5f4; --teal-text: #136763; --status-warn: #b3271e; --status-error: #c0281f; --status-success: #1a7a40; --accent-link: var(--accent); --edge-fade: rgba(0,0,0,0.10); color-scheme: light;
}

* { box-sizing: border-box; }

/* Visually hides content while keeping it in the accessibility tree - used
   for form <label>s on inputs that rely on placeholder text for sighted
   users. A placeholder alone isn't a valid accessible name (WCAG 3.3.2):
   it vanishes once typing starts and isn't surfaced consistently by every
   screen reader, so these inputs need a real <label>, just not a visible
   one that would duplicate the placeholder on screen. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ==================== Site-wide GM announcement banner ==================== */
.site-banner-bar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 10px 44px 10px 16px;
  background: linear-gradient(90deg, rgba(34,184,176,0.16) 0%, rgba(34,184,176,0.08) 100%);
  border-bottom: 1px solid rgba(34,184,176,0.3);
  color: var(--text);
  font-size: 13px;
  font-weight: 600;
  text-align: center;
}
.site-banner-close {
  position: absolute;
  right: 12px; top: 50%; transform: translateY(-50%);
  background: none; border: none; color: var(--text-dim);
  font-size: 13px; cursor: pointer; padding: 4px;
}
.site-banner-close:hover { color: var(--text); }

body {
  margin: 0;
  min-height: 100vh;
  position: relative;
  background:
    radial-gradient(ellipse at top, var(--body-glow-color) 0%, var(--bg) 55%),
    var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  letter-spacing: -0.005em;
}

/* Subtle plexus/network geometry backdrop - fixed, low-opacity, non-interactive */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.35;
  background-image:
    radial-gradient(circle at 8% 20%, rgba(34,184,176,0.5) 0, rgba(34,184,176,0.5) 1.5px, transparent 1.5px),
    radial-gradient(circle at 18% 55%, rgba(34,184,176,0.4) 0, rgba(34,184,176,0.4) 1.5px, transparent 1.5px),
    radial-gradient(circle at 4% 80%, rgba(34,184,176,0.4) 0, rgba(34,184,176,0.4) 1.5px, transparent 1.5px),
    radial-gradient(circle at 92% 15%, rgba(34,184,176,0.35) 0, rgba(34,184,176,0.35) 1.5px, transparent 1.5px),
    radial-gradient(circle at 96% 60%, rgba(34,184,176,0.3) 0, rgba(34,184,176,0.3) 1.5px, transparent 1.5px),
    linear-gradient(105deg, transparent 0%, transparent 3%, rgba(34,184,176,0.06) 3.2%, transparent 3.4%, transparent 100%),
    linear-gradient(70deg, transparent 0%, transparent 12%, rgba(34,184,176,0.05) 12.2%, transparent 12.4%, transparent 100%);
  background-size: 100% 100%;
}

a { color: inherit; }

/* ==================== Top navigation ==================== */
.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 32px;
  background: var(--chrome-bg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border-subtle);
}
.logo {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -0.3px;
  text-decoration: none;
  color: var(--text);
  white-space: nowrap;
}
.logo span { color: var(--text); }
.logo-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  filter: drop-shadow(0 0 6px rgba(34,184,176,0.5));
  transition: filter .2s var(--ease);
}
.logo-mark svg { width: 100%; height: 100%; transition: transform .35s var(--ease); }
.logo:hover .logo-mark { filter: drop-shadow(0 0 10px rgba(34,184,176,0.8)); }
.logo:hover .logo-mark svg { transform: rotate(180deg); }
.logo-mark svg circle { transition: transform .35s var(--ease); transform-origin: center; }
.logo:hover .logo-mark svg circle:first-child { transform: translateX(1.5px); }
.logo:hover .logo-mark svg circle:last-child { transform: translateX(-1.5px); }

/* Fixed bottom tab bar - mobile only (see @media block below for the
   display:flex override). Purely additive: the existing horizontal-scroll
   .nav-links row stays exactly as-is and still reaches every page, this
   just gives the 5 most-used destinations a thumb-reachable shortcut. */
.mobile-tab-nav {
  display: none;
}

/* Nav links live inside a rounded "pill group" capsule instead of floating
   loose across the bar - reads as one unified control instead of a list. */
.nav-links {
  display: flex;
  gap: 2px;
  align-items: center;
  background: var(--surf-1);
  border: 1px solid var(--border-subtle);
  padding: 4px;
  border-radius: var(--radius-pill);
}
.nav-links a {
  color: var(--text-dimmer);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 600;
  padding: 7px 16px;
  border-radius: var(--radius-pill);
  border-bottom: none;
  transition: var(--transition);
}
.nav-links a:hover { color: var(--text); background: var(--surf-3); }
.nav-links a.active { color: #0a0a0e; background: var(--teal); box-shadow: 0 0 16px var(--teal-glow); }
/* The avatar + logout link that trail the pill group aren't part of the
   capsule - give them a little breathing room and drop the plain
   underlined "Log out" text link in favor of a quiet icon-style button. */
.nav-links > #navAvatar,
.nav-links > a[onclick*="logout"] {
  margin-left: 6px;
}
.nav-links a[onclick*="logout"] {
  background: transparent;
  border: 1px solid var(--border-subtle);
  color: var(--text-dim);
  padding: 7px 14px;
}
.nav-links a[onclick*="logout"]:hover { color: var(--accent-link); border-color: var(--accent-glow); background: rgba(229,9,20,0.08); }

.page {
  max-width: 1100px;
  margin: 0 auto;
  padding: 28px 32px 90px;
}

.page-narrow {
  max-width: 480px;
  margin: 0 auto;
  padding: 60px 24px 80px;
}

h1.page-title { font-size: 26px; margin: 8px 0 26px; font-weight: 800; letter-spacing: -0.5px; }

/* ==================== Poster-style grid ==================== */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 22px;
  margin-bottom: 10px;
}

.card {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  aspect-ratio: 2 / 3;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  text-decoration: none;
  color: #fff;
  border: 1px solid var(--border-subtle);
  transition: transform .2s var(--ease), box-shadow .2s var(--ease), border-color .2s var(--ease);
  box-shadow: 0 4px 18px rgba(0,0,0,0.35);
}
.card:hover {
  transform: translateY(-4px) scale(1.03);
  box-shadow: 0 20px 40px rgba(0,0,0,0.6);
  border-color: rgba(34,184,176,0.35);
  z-index: 5;
}
.card-16x9 {
  aspect-ratio: 16 / 9;
}
.card-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 52px;
  height: 52px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  color: #fff;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.25);
  backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity .2s var(--ease), transform .2s var(--ease);
  text-shadow: 0 2px 8px rgba(0,0,0,0.6);
}
.card:hover .card-play { opacity: 1; transform: translate(-50%, -50%) scale(1.08); }
.card-info {
  position: relative;
  z-index: 1;
  padding: 14px 14px 16px;
  background: linear-gradient(to top, rgba(0,0,0,0.92), rgba(0,0,0,0) 90%);
}
.card-title {
  font-size: 13px;
  font-weight: 700;
  line-height: 1.3;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  letter-spacing: -0.1px;
}
.card-meta { font-size: 11px; color: var(--text-dimmer); margin-top: 4px; }
.card-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  background: rgba(10,10,14,0.7);
  backdrop-filter: blur(4px);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-subtle);
  z-index: 2;
}
.card-actions {
  position: absolute;
  top: 8px;
  right: 8px;
  display: flex;
  gap: 6px;
  opacity: 0;
  transition: opacity .2s var(--ease);
  z-index: 3;
}
.card:hover .card-actions { opacity: 1; }
.card-actions button {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.15);
  background: rgba(10,10,14,0.7);
  backdrop-filter: blur(4px);
  color: #fff;
  cursor: pointer;
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: var(--transition);
}
.card-actions button:hover { background: var(--accent); border-color: var(--accent); }

/* Real extracted video frame, sitting behind the play icon/actions/title -
   those all stay z-index'd or DOM-ordered above it already, this just
   needs to never outrank them. Absent entirely (no poster yet, or it
   failed to load) just leaves the gradient class showing through. */
.card-poster-img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0;
}

.card-grad-0 { background: linear-gradient(150deg, #6d1b2f 0%, #1b1b3a 100%); }
.card-grad-1 { background: linear-gradient(150deg, #4a1b5e 0%, #16161c 100%); }
.card-grad-2 { background: linear-gradient(150deg, #7a3a0e 0%, #1b1b1b 100%); }
.card-grad-3 { background: linear-gradient(150deg, #0e4a4a 0%, #16161c 100%); }
.card-grad-4 { background: linear-gradient(150deg, #5e1b3a 0%, #16161c 100%); }
.card-grad-5 { background: linear-gradient(150deg, #1b3a5e 0%, #16161c 100%); }
.card-grad-6 { background: linear-gradient(150deg, #3a5e1b 0%, #16161c 100%); }
.card-grad-7 { background: linear-gradient(150deg, #5e4a1b 0%, #16161c 100%); }

/* Shimmering skeleton sweep for a card mid-conversion - toggled by adding
   .card-converting alongside the existing gradient class, no markup change
   needed beyond that one class name. */
.card-converting { position: relative; }
.card-converting::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 30%, rgba(255,255,255,0.09) 50%, transparent 70%);
  transform: translateX(-100%);
  animation: cardShimmer 1.8s infinite;
}
@keyframes cardShimmer {
  100% { transform: translateX(100%); }
}

/* ==================== Buttons ==================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: var(--radius-pill);
  padding: 11px 20px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1px;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s var(--ease), transform .1s var(--ease), box-shadow .15s var(--ease);
}
.btn:hover { background: var(--accent-hover); box-shadow: 0 6px 18px var(--accent-glow); transform: translateY(-1px); }
.btn:active { transform: scale(0.96); }
.btn:disabled { opacity: 0.5; cursor: default; transform: none; box-shadow: none; }
.btn-secondary { background: var(--bg-elevated-2); color: var(--text); }
.btn-secondary:hover { background: var(--btn-secondary-hover-bg); box-shadow: none; }
.btn-block { width: 100%; }

.btn-teal { background: var(--teal); color: #06201e; }
.btn-teal:hover { background: var(--teal-hover); box-shadow: 0 6px 18px var(--teal-glow); }

.btn-outline {
  background: transparent;
  color: var(--text);
  border: 1px solid var(--border-subtle);
}
.btn-outline:hover { border-color: var(--teal); color: var(--teal-text); background: rgba(34,184,176,0.08); box-shadow: none; transform: none; }

/* ==================== Storage tier pricing cards ==================== */
.tier-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
}
.tier-card {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 16px 10px;
  border-radius: var(--radius);
  text-align: center;
  white-space: normal;
}
.tier-card-size {
  font-size: 18px;
  font-weight: 800;
  letter-spacing: -0.3px;
  color: var(--text);
}
.tier-card-label {
  font-size: 11px;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.tier-card-price {
  font-size: 12px;
  font-weight: 700;
  color: var(--teal-text);
  margin-top: 4px;
}
.tier-card.btn-teal .tier-card-size,
.tier-card.btn-teal .tier-card-price { color: #06201e; }
.tier-card.btn-teal .tier-card-label { color: rgba(6,32,30,0.7); }

/* 100GB block stepper (profile.html) - sits below the fixed tier cards
   for anyone who wants to stack past the 350GB ceiling. */
.storage-block-tier { margin-top: 14px; }
.storage-block-row {
  display: flex; align-items: center; gap: 10px; margin-top: 8px; flex-wrap: wrap;
}
.storage-block-count {
  font-size: 13px; font-weight: 700; color: var(--text); min-width: 140px; text-align: center;
}

/* ==================== List rows ==================== */
.list-row {
  position: relative;
  display: block;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius);
  padding: 18px 22px;
  margin-bottom: 10px;
  text-decoration: none;
  overflow: hidden;
  box-shadow: 0 6px 24px rgba(0,0,0,0.25);
  transition: var(--transition);
}
.list-row:hover { border-color: rgba(34,184,176,0.25); }
.list-row::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, var(--teal) 0%, transparent 60%);
  opacity: 0.6;
}
.list-row-flex {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.list-row-title { font-weight: 700; font-size: 15px; }
.list-row-meta { font-size: 12px; color: var(--text-dimmer); margin-top: 4px; }

/* ==================== Numbered step badges (onboarding) ==================== */
.step {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  padding: 14px 0;
  border-top: 1px solid var(--border-subtle);
}
.step:first-child { border-top: none; padding-top: 0; }
.step-badge {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--teal);
  color: #06201e;
  font-size: 12px;
  font-weight: 800;
  display: flex;
  align-items: center;
  justify-content: center;
}
.step-body h3 { margin: 0 0 4px; font-size: 14px; color: var(--text); font-weight: 700; }
.step-body p { margin: 0; font-size: 13px; color: var(--text-dimmer); line-height: 1.6; }

.invite-pill {
  display: inline-block;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 16px;
  letter-spacing: 1px;
  background: var(--bg);
  border: 1px dashed var(--border-subtle);
  border-radius: var(--radius-pill);
  padding: 8px 18px;
  color: var(--teal-text);
}

/* ==================== Panels / cards for forms ==================== */
.panel {
  max-width: 900px;
  margin: 0 auto 26px;
  background: var(--bg-elevated);
  border-radius: var(--radius-lg);
  padding: 26px 28px;
  border: 1px solid var(--border-subtle);
  box-shadow: 0 8px 32px rgba(0,0,0,0.37);
}
.panel h2 { font-size: 17px; margin: 0 0 16px; font-weight: 800; letter-spacing: -0.2px; }
.panel h3 { font-size: 12.5px; margin: 0 0 10px; color: var(--text-dimmer); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
.panel label { display: block; font-size: 12px; color: var(--text-dimmer); margin-bottom: 6px; font-weight: 500; }
.panel p { font-size: 13.5px; color: var(--text-dimmer); line-height: 1.65; }
.panel ol, .panel ul { font-size: 13.5px; color: var(--text-dimmer); line-height: 1.8; padding-left: 20px; }
.panel code {
  background: var(--bg);
  border: 1px solid var(--border-subtle);
  border-radius: 5px;
  padding: 1px 6px;
  font-size: 12px;
  color: var(--status-warn);
}

/* ==================== Inputs ==================== */
input[type=text], input[type=password], input[type=email] {
  width: 100%;
  padding: 13px 16px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-subtle);
  background: var(--bg-elevated-2);
  color: var(--text);
  font-size: 14px;
  margin-bottom: 14px;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}
input[type=text]:focus, input[type=password]:focus, input[type=email]:focus {
  outline: none;
  border-color: var(--border-focus);
  box-shadow: 0 0 0 3px var(--teal-glow);
}
/* Bumped from --text-faint (38% opacity) to --text-dim - placeholder text
   like "Type a message..." was too low-contrast against the OLED-black
   background to read comfortably. */
input[type=text]::placeholder, input[type=password]::placeholder, input[type=email]::placeholder { color: var(--text-dim); }

/* Native file inputs still work everywhere (functionality untouched) but no
   longer look like a raw OS control - styled to sit quietly inside whatever
   dropzone wraps it. Pages using the .dropzone treatment hide this further
   (see .dropzone-input below); this is just the fallback bare style. */
input[type=file] {
  width: 100%;
  color: var(--text-dimmer);
  font-size: 13px;
  margin-bottom: 14px;
  padding: 10px;
  border-radius: var(--radius);
  border: 1px dashed var(--border-subtle);
  background: var(--bg-elevated-2);
}

/* Drag-and-drop dropzone wrapper - wraps the real (functional, unchanged)
   file input. The input is stretched invisibly over the whole zone so
   clicking/dragging anywhere on it still opens/accepts files exactly as a
   native <input type=file> always has; this purely changes what it looks
   like at rest and while a file is hovering over it. */
.dropzone {
  position: relative;
  border: 2px dashed var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 36px 20px;
  text-align: center;
  background: var(--bg-elevated-2);
  transition: var(--transition);
  cursor: pointer;
  margin-bottom: 14px;
}
.dropzone:hover, .dropzone.drag-over {
  border-color: var(--teal);
  background: rgba(34,184,176,0.05);
}
.dropzone.dropzone-disabled {
  cursor: not-allowed;
  opacity: 0.45;
  pointer-events: none;
}
.dropzone .dropzone-icon {
  font-size: 26px;
  margin-bottom: 8px;
  opacity: 0.85;
}
.dropzone .dropzone-title { font-size: 14px; font-weight: 700; color: var(--text); }
.dropzone .dropzone-sub { font-size: 12px; color: var(--text-dimmer); margin-top: 4px; }
.dropzone .dropzone-filename {
  font-size: 13px; font-weight: 700; color: var(--teal-text); margin-top: 6px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.storage-setup-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(34,184,176,0.08);
  border: 1px solid rgba(34,184,176,0.3);
  border-radius: var(--radius-md, 10px);
  padding: 10px 14px;
  font-size: 12.5px;
  color: var(--text-dimmer);
  margin-bottom: 14px;
}
.storage-setup-banner .spin {
  width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0;
  border: 2px solid rgba(34,184,176,0.3); border-top-color: #22b8b0;
  animation: storageSetupSpin .8s linear infinite;
}
@keyframes storageSetupSpin { to { transform: rotate(360deg); } }

.dropzone-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  margin: 0;
}

.progress-wrap { margin-top: 14px; display: none; }
.progress-bar { width: 100%; height: 7px; background: var(--bg-elevated-2); border-radius: var(--radius-pill); overflow: hidden; }
.progress-fill { height: 100%; width: 0%; background: linear-gradient(90deg, var(--teal), var(--teal-hover)); box-shadow: 0 0 12px var(--teal-glow); transition: width .2s var(--ease); }
.progress-label { font-size: 11.5px; color: var(--text-dimmer); margin-top: 8px; }
.field-error { color: var(--status-error); font-size: 12px; margin-top: 10px; display: none; }
.field-hint { color: var(--text-dim); font-size: 11px; margin-bottom: 14px; padding-left: 4px; }
.field-hint.field-hint-warn { color: var(--status-warn); }
.field-success { color: var(--status-success); font-size: 12px; margin-top: 10px; display: none; }

.empty { color: var(--text-dimmer); text-align: center; margin: 60px 0; font-size: 14px; }

/* ==================== Playlist manage list ==================== */
.episode-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 11px 0;
  border-top: 1px solid var(--border-subtle);
  gap: 10px;
}
.episode-name { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
.episode-controls { display: flex; gap: 5px; flex-shrink: 0; }
.episode-controls button {
  background: var(--bg-elevated-2);
  color: var(--text);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  padding: 6px 12px;
  font-size: 12px;
  cursor: pointer;
  transition: var(--transition);
}
.episode-controls button:hover { background: #2c2c36; border-color: var(--border-focus); }

.episode-row[draggable="true"] { cursor: grab; transition: background 0.12s, opacity 0.12s; }
.episode-row[draggable="true"]:active { cursor: grabbing; }
.episode-row.dragging { opacity: 0.4; }
.episode-row.drag-over-top { box-shadow: inset 0 2px 0 0 var(--accent, #6c5ce7); }
.episode-row.drag-over-bottom { box-shadow: inset 0 -2px 0 0 var(--accent, #6c5ce7); }
.drag-handle {
  color: var(--text-dimmer);
  font-size: 14px;
  cursor: grab;
  flex-shrink: 0;
  padding: 0 2px;
  user-select: none;
}

/* ==================== Pricing / landing ==================== */
.hero {
  text-align: center;
  padding: 100px 24px 70px;
  background: radial-gradient(ellipse 700px 320px at 50% 0%, rgba(34,184,176,0.18), transparent 70%);
  position: relative;
}
.hero h1 { font-size: 44px; font-weight: 800; letter-spacing: -1.2px; margin-bottom: 14px; line-height: 1.12; }
.hero p { color: var(--text-dimmer); font-size: 16px; max-width: 480px; margin: 0 auto 30px; }

/* Decorative CSS-only mockup of the watch.html UI - no real screenshot
   asset exists, so this is a stylized approximation for the landing hero. */
.hero-mockup {
  max-width: 560px;
  margin: 44px auto 0;
}
.hero-mockup-frame {
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: 0 30px 70px rgba(0,0,0,0.55);
}
.hero-mockup-topbar {
  display: flex;
  gap: 6px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border-subtle);
}
.hero-mockup-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--border-subtle);
}
.hero-mockup-video {
  position: relative;
  aspect-ratio: 16 / 8;
  background:
    radial-gradient(ellipse 400px 200px at 30% 30%, rgba(34,184,176,0.25), transparent 60%),
    radial-gradient(ellipse 300px 200px at 75% 70%, rgba(90,60,220,0.22), transparent 60%),
    linear-gradient(160deg, #17171d 0%, #0c0c10 100%);
  display: flex;
  align-items: center;
  justify-content: center;
}
.hero-mockup-play {
  width: 56px; height: 56px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.25);
  backdrop-filter: blur(6px);
  color: #fff;
  font-size: 18px;
  padding-left: 3px;
}
.hero-mockup-chat {
  position: absolute;
  right: 16px;
  bottom: 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-end;
  max-width: 60%;
}
.hero-mockup-bubble {
  background: rgba(20,20,26,0.85);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  padding: 6px 12px;
  font-size: 12px;
  color: var(--text-dim);
  white-space: nowrap;
}
.hero-mockup-bubble-a { background: rgba(34,184,176,0.16); border-color: rgba(34,184,176,0.3); color: #cdfbf6; }
.hero-mockup-avatars {
  position: absolute;
  left: 16px;
  top: 16px;
  display: flex;
}
.hero-mockup-avatar {
  width: 26px; height: 26px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(150deg, #0e4a4a 0%, #16161c 100%);
  border: 2px solid var(--bg-elevated);
  font-size: 10px; font-weight: 700; color: #fff;
  margin-left: -8px;
}
.hero-mockup-avatar:first-child { margin-left: 0; }
.pricing-card {
  max-width: 340px;
  margin: 40px auto 0;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: 32px;
  text-align: center;
  position: relative;
  overflow: hidden;
  box-shadow: 0 20px 60px rgba(0,0,0,0.5);
}
.pricing-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--teal), transparent);
}
/* Soft glow bleeding out from behind the pricing card, per the "premium
   product hero" treatment - purely decorative, sits behind the card. */
.pricing-card::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 260px; height: 180px;
  transform: translate(-50%, -50%);
  background: var(--teal);
  filter: blur(90px);
  opacity: 0.15;
  z-index: -1;
}
.pricing-card .price { font-size: 38px; font-weight: 800; margin: 10px 0; letter-spacing: -1px; }
.pricing-card .price span { font-size: 14px; color: var(--text-dimmer); font-weight: 500; }
.badge-pill {
  display: inline-block;
  background: var(--bg-elevated-2);
  border: 1px solid var(--border-subtle);
  color: var(--text-dimmer);
  font-size: 11px;
  font-weight: 700;
  padding: 5px 14px;
  border-radius: var(--radius-pill);
  margin-bottom: 10px;
}
.status-active { color: var(--status-success); }
.status-inactive { color: var(--status-error); }

/* ==================== Friends / presence ==================== */
.friend-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 10px 10px;
  border-radius: var(--radius);
  transition: var(--transition);
}
.friend-row:hover { background: var(--surf-1); }
.friend-avatar {
  width: 38px; height: 38px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(150deg, #0e4a4a 0%, #16161c 100%);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 14px; color: #fff;
  border: 1px solid var(--border-subtle);
}
.friend-avatar.avatar-online {
  box-shadow: 0 0 0 2px var(--bg-elevated-2), 0 0 0 4px var(--status-success);
}
.friend-avatar.avatar-live {
  box-shadow: 0 0 0 2px var(--bg-elevated-2), 0 0 0 4px var(--teal), 0 0 10px var(--teal-glow);
  animation: avatarLivePulse 1.8s ease-in-out infinite;
}
@keyframes avatarLivePulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--bg-elevated-2), 0 0 0 4px var(--teal), 0 0 10px var(--teal-glow); }
  50% { box-shadow: 0 0 0 2px var(--bg-elevated-2), 0 0 0 4px var(--teal), 0 0 16px var(--teal-glow); }
}
.friend-name { font-weight: 700; font-size: 14px; }
.friend-status { font-size: 12px; color: var(--text-dimmer); margin-top: 2px; }
.friend-status.watching { color: var(--teal-text); }
.dot-live {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--teal); margin-right: 5px; box-shadow: 0 0 6px var(--teal);
  animation: livePulse 1.6s ease-in-out infinite;
}
@keyframes livePulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}
.friend-actions { display: flex; gap: 8px; flex-shrink: 0; align-items: center; }

/* ==================== Chat panel (watch.html) ==================== */
.chat-panel {
  position: fixed; top: 0; right: 0; bottom: 0; width: 320px; max-width: 85vw;
  /* Default/fallback opacity - the transparency slider in the chat header
     (see watch.html) overrides this directly via inline style.backgroundColor
     on #chatPanel instead of a CSS variable, since var() as the alpha
     argument of rgba() proved unreliable in the field (Safari in
     particular). Message bubbles (.chat-msg) have their own fixed opacity
     so text stays legible no matter how transparent the panel gets. */
  background: rgba(12,12,16,0.92); backdrop-filter: blur(14px);
  border-left: 1px solid var(--border-subtle);
  display: flex; flex-direction: column; z-index: 60;
  transform: translateX(100%); transition: transform .28s var(--ease);
}
.chat-panel.open { transform: translateX(0); }
.chat-header {
  padding: 16px 18px; border-bottom: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: space-between;
  font-size: 13px; font-weight: 700;
  gap: 8px;
}
.chat-header .chat-header-actions { display: flex; align-items: center; gap: 4px; }
.chat-header button { background: none; border: none; color: var(--text-dimmer); font-size: 16px; cursor: pointer; }
.chat-opacity-row {
  display: none; align-items: center; gap: 8px;
  padding: 10px 18px; border-bottom: 1px solid var(--border-subtle);
  font-size: 11px; color: var(--text-dimmer);
}
.chat-opacity-row.open { display: flex; }
.chat-opacity-row input[type="range"] { flex: 1; margin: 0; }
.chat-messages { flex: 1; overflow-y: auto; padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; }
.chat-msg { font-size: 13px; line-height: 1.4; background: var(--surf-1); border-radius: var(--radius); padding: 8px 12px; max-width: 88%; }
.chat-msg .who { font-weight: 700; color: var(--teal-text); margin-right: 6px; }
/* Host messages sit on the right with a teal-tinted border, everyone
   else's on the left - same bubble element, same menu/report logic
   underneath, this is purely which side it lands on. */
.chat-msg-guest { align-self: flex-start; border-radius: 4px 14px 14px 14px; }
.chat-msg-host { align-self: flex-end; border: 1px solid rgba(34,184,176,0.28); border-radius: 14px 4px 14px 14px; }
.chat-input-row { display: flex; gap: 8px; padding: 14px; border-top: 1px solid var(--border-subtle); }
.chat-input-row input {
  flex: 1; margin: 0; padding: 10px 14px; font-size: 13px;
  border-radius: var(--radius-pill); border: 1px solid var(--border-subtle); background: var(--bg-elevated-2); color: var(--text);
}
.chat-toggle-btn {
  position: fixed; bottom: 22px; right: 22px; z-index: 55;
  width: 48px; height: 48px; border-radius: 50%; background: var(--teal); color: #06201e;
  border: none; cursor: pointer; font-size: 18px; box-shadow: 0 8px 24px rgba(34,184,176,0.35);
  transition: var(--transition);
}
.chat-toggle-btn:hover { transform: translateY(-2px); box-shadow: 0 12px 28px rgba(34,184,176,0.45); }

/* ==================== Visibility segmented control ==================== */
/* Same markup/JS everywhere (a wrapping div + N .visibility-option divs,
   click just toggles the .selected class) - this is a pure CSS re-skin
   into a single pill-shaped segmented control, no HTML/JS changes needed. */
.visibility-select {
  display: flex;
  gap: 4px;
  margin-bottom: 14px;
  background: var(--bg-elevated-2);
  border: 1px solid var(--border-subtle);
  border-radius: 14px;
  padding: 5px;
}
.visibility-option {
  flex: 1;
  text-align: center;
  padding: 10px 8px;
  border-radius: 10px;
  border: 1px solid transparent;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  color: var(--text-dimmer);
  transition: var(--transition);
}
.visibility-option:hover { color: var(--text); }
.visibility-option.selected {
  border-color: rgba(34,184,176,0.3);
  color: var(--teal-text);
  background: var(--bg-elevated);
  box-shadow: 0 4px 14px rgba(0,0,0,0.3);
}
.visibility-option span { color: var(--text-dim); font-weight: 400; }
.visibility-option.selected span { color: var(--text-dimmer); }

/* ---- Appearance / theme picker (profile.html) ---- */
.theme-choice-row {
  display: flex; gap: 8px; background: var(--bg-elevated-2);
  border: 1px solid var(--border-subtle); border-radius: 14px; padding: 5px;
}
.theme-choice-btn {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 12px 8px; border-radius: 10px; border: 1px solid transparent;
  background: none; cursor: pointer; font-size: 12px; font-weight: 600;
  color: var(--text-dimmer); transition: var(--transition);
}
.theme-choice-icon { font-size: 18px; }
.theme-choice-btn:hover { color: var(--text); }
.theme-choice-btn.theme-choice-active {
  background: var(--bg-elevated); border-color: rgba(34,184,176,0.3); color: var(--teal-text);
  box-shadow: 0 4px 14px rgba(0,0,0,0.3);
}

.photo-grid {
  /* Fixed-size tiles that pack left-to-right and wrap, like Google/Apple
     Photos - NOT minmax(...,1fr), which stretches whatever few tiles
     exist to fill the entire row width (that's what made 2 photos look
     like 2 giant slabs instead of a gallery). */
  display: grid;
  grid-template-columns: repeat(auto-fill, 150px);
  gap: 4px;
  margin-bottom: 10px;
}
.photo-thumb {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  aspect-ratio: 1 / 1;
  background: var(--bg-elevated-2);
  border: 1px solid var(--border-subtle);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: var(--transition);
}
.photo-thumb:hover { border-color: rgba(34,184,176,0.3); }
.photo-thumb img { width: 100%; height: 100%; object-fit: cover; cursor: pointer; display: block; transition: transform .35s var(--ease); }
.photo-thumb:hover img { transform: scale(1.06); }
.photo-thumb::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(10,10,14,0.55) 0%, transparent 55%);
  opacity: 0; transition: var(--transition); pointer-events: none;
}
.photo-thumb:hover::after { opacity: 1; }
.photo-thumb-loading { color: var(--text-dimmer); font-size: 13px; }
.photo-remove-btn {
  position: absolute; top: 6px; right: 6px; width: 24px; height: 24px; border-radius: 50%;
  background: rgba(10,10,14,0.7); backdrop-filter: blur(4px); color: #fff; border: 1px solid rgba(255,255,255,0.15); cursor: pointer; font-size: 11px;
  display: flex; align-items: center; justify-content: center; z-index: 2;
  opacity: 0; transition: var(--transition);
}
.photo-thumb:hover .photo-remove-btn { opacity: 1; }
.photo-remove-btn:hover { background: var(--accent); border-color: var(--accent); }

/* "Shared by <name>" label pinned to the bottom-left of every gallery
   tile (photos and videos) so it's always clear whose upload it was -
   shown for both plain shared galleries and chat auto-synced ones. */
.tile-shared-by {
  position: absolute; left: 6px; bottom: 6px; z-index: 2;
  background: rgba(10,10,14,0.7); backdrop-filter: blur(4px);
  color: var(--text-dimmer); font-size: 10.5px; font-weight: 600;
  padding: 3px 8px; border-radius: var(--radius-pill);
  border: 1px solid rgba(255,255,255,0.1);
  max-width: calc(100% - 12px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ==================== Nav avatar + profile dropdown capsule ==================== */
/* The slot element itself is always the <profile.html> link (topbar and
   sidebar each have their own) - renderNavAvatar() just adds/removes the
   .nav-avatar / .nav-avatar-fallback / .nav-avatar-photo classes and fills
   its content, it never builds a separate nested <a>. */
.nav-avatar-slot { text-decoration: none; }
.nav-avatar {
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 50%; overflow: hidden;
  text-decoration: none; flex-shrink: 0; border: 1.5px solid var(--teal);
  transition: var(--transition);
}
.nav-avatar:hover { box-shadow: 0 0 0 3px var(--teal-glow); }
.nav-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.nav-avatar-fallback { background: var(--teal); color: #06201e; font-weight: 700; font-size: 12px; }

/* Storage usage gauge (profile.html) - the bar element itself already
   exists in the page and is filled via JS width%; this just gives its
   track a modern pill look with room to glow. */
#storageUsageBar { box-shadow: 0 0 10px var(--teal-glow); }

/* ==================== Empty states ==================== */
/* .empty is already the one class every page's JS falls back to for "no
   videos/photos/friends/playlists yet" - re-skinning it here upgrades every
   empty state across the whole app at once, no per-page changes needed. */
.empty {
  color: var(--text-dimmer);
  text-align: center;
  margin: 20px 0;
  padding: 50px 24px;
  font-size: 13.5px;
  line-height: 1.6;
  background: var(--surf-9);
  border: 1px dashed var(--border-subtle);
  border-radius: var(--radius-lg);
}

/* ==================== Callout banners (home.html) ==================== */
/* Targeting the existing ids directly - #verifyBanner / #invitedBanner /
   #needsSubPanel are already plain .panel divs in home.html; this just
   gives them a distinct "this needs your attention" treatment instead of
   looking like just another content panel. */
#verifyBanner, #invitedBanner, #needsSubPanel {
  background: linear-gradient(90deg, rgba(34,184,176,0.09) 0%, var(--bg-elevated) 100%) !important;
  border-color: rgba(34,184,176,0.22) !important;
}

/* ==================== Auth pages (login / signup) ==================== */
/* .page-narrow is only ever used by login.html/signup.html/onboarding.html
   - safe to add an ambient glow backdrop scoped to it without touching any
   other layout. */
.page-narrow {
  position: relative;
}
.page-narrow::before {
  content: "";
  position: absolute;
  top: -40px; left: 50%;
  width: 420px; height: 260px;
  transform: translateX(-50%);
  background:
    radial-gradient(circle at 30% 20%, rgba(34,184,176,0.10), transparent 60%),
    radial-gradient(circle at 75% 60%, rgba(229,9,20,0.06), transparent 55%);
  filter: blur(10px);
  pointer-events: none;
  z-index: -1;
}
.page-narrow .panel,
.page-narrow > div.panel {
  box-shadow: 0 30px 70px rgba(0,0,0,0.55);
}
/* The two OAuth buttons on login/signup sit side by side in a flex row
   directly in the markup now (see login.html / signup.html) - no CSS
   needed here beyond .btn-outline itself. */

/* ==================== Responsive ==================== */
@media (max-width: 760px) {
  /* Bottom tab bar already covers every destination in .nav-links on
     mobile, so the topbar's job shrinks down to just "logo + contextual
     account actions" (avatar, log out) instead of duplicating the whole
     nav as a second horizontal-scroll list. Targeting a[href]:not([onclick])
     hides exactly the plain destination links while leaving the avatar
     span and the onclick-driven Log out link (the only two things that
     don't already have a mobile-tab-nav equivalent) untouched - no HTML
     changes needed on any of the 8+ pages that share this markup. */
  .topbar { padding: 12px 16px; gap: 10px; }
  .nav-links { gap: 6px; padding: 3px; background: transparent; border: none; }
  /* Scoped to body:has(.mobile-tab-nav) - only the logged-in app pages that
     actually have a bottom tab bar as a replacement. Logged-out pages
     (index.html's Log in/Sign up, policy.html's back-to-Home link) have no
     such bar and must keep their only nav links visible. */
  body:has(.mobile-tab-nav) .nav-links a[href]:not([onclick]) { display: none; }
  .nav-links a { padding: 7px 12px; font-size: 12.5px; white-space: nowrap; }
  .page, .page-narrow { padding-left: 16px; padding-right: 16px; }
  h1.page-title { font-size: 21px; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 14px; }
  .panel { padding: 18px 18px; border-radius: var(--radius); }
  /* Chat becomes a bottom sheet instead of a right-side panel on narrow
     screens - same element, same open/close JS (toggleChat() just adds/
     removes the .open class either way), just a different resting
     position and slide direction. */
  .chat-panel {
    width: 100%; max-width: 100%;
    top: auto; bottom: 0; left: 0; right: 0;
    height: 70vh;
    border-left: none;
    border-top: 1px solid var(--border-subtle);
    border-radius: 20px 20px 0 0;
    transform: translateY(100%);
  }
  .chat-panel.open { transform: translateY(0); }
  .dashboard-grid { grid-template-columns: 1fr !important; }
  .dashboard-sidebar { border-left: none !important; padding-left: 0 !important; border-top: 1px solid var(--border-subtle); padding-top: 20px; margin-top: 4px; }

  /* Sliding icon rail with a FIXED center "bubble": the teal circle stays put
     in the middle of the bar while the icon track slides underneath it. The
     icon centered under the bubble is the current page. chat-common.js wraps
     the items in .mobile-tab-track, injects the bubble, and clones the set on
     both sides into a ring so there's never empty space at the Home/Profile
     ends; the centered icon stays highlighted as you drag. */
  .mobile-tab-nav {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 30;
    display: block;
    background: var(--chrome-bg-strong);
    backdrop-filter: blur(18px) saturate(1.4);
    -webkit-backdrop-filter: blur(18px) saturate(1.4);
    border-top: 1px solid var(--border-subtle);
  }
  /* The stationary teal bubble, centered over the icon row and sitting BEHIND
     the icons (z-index 0) so whichever icon is centered reads as inside it.
     Hidden until chat-common.js has centered the current page (no flash). */
  .mobile-tab-bubble {
    position: absolute;
    top: 11px; left: 50%; margin-left: -22px;
    width: 44px; height: 44px;
    border-radius: var(--radius-pill);
    background: var(--teal);
    box-shadow: 0 6px 18px var(--teal-glow);
    pointer-events: none;
    z-index: 0;
    opacity: 0;
    transition: opacity 0.2s var(--ease);
  }
  .mobile-tab-nav.tabs-ready .mobile-tab-bubble { opacity: 1; }
  /* The horizontally-scrollable track that holds the tabs and slides under
     the fixed bubble. */
  .mobile-tab-track {
    display: flex;
    gap: 2px;
    padding: 9px 0 calc(9px + env(safe-area-inset-bottom));
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .mobile-tab-track::-webkit-scrollbar { display: none; }
  .mobile-tab-item {
    position: relative;
    z-index: 1;
    flex: 0 0 auto;
    width: 66px;
    scroll-snap-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: 2px 0;
    text-decoration: none;
    color: var(--text-dimmer);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.01em;
    opacity: 0.55;
    transform: scale(0.88);
    transition: opacity 0.25s var(--ease), transform 0.25s var(--ease), color 0.25s var(--ease);
  }
  .mobile-tab-icon {
    line-height: 1;
    width: 44px; height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-pill);
    background: transparent;
    color: inherit;
    transition: color 0.25s var(--ease);
  }
  /* SVG line icons matched to the desktop .ig-sidebar set. */
  .mobile-tab-icon svg { width: 22px; height: 22px; display: block; }
  /* Profile tab shows the real avatar (renderNavAvatar fills .nav-avatar-slot),
     forced circular to sit flush inside the round bubble and sized to match
     the other icons' 44px hit area. */
  .mobile-tab-item .mobile-tab-icon.nav-avatar-slot,
  .mobile-tab-item .mobile-tab-icon.nav-avatar {
    width: 44px; height: 44px;
    border-radius: var(--radius-pill);
    overflow: hidden;
  }
  .mobile-tab-item .mobile-tab-icon.nav-avatar-fallback { font-size: 16px; }
  .mobile-tab-label { max-width: 100%; white-space: nowrap; }
  /* The tab centered under the bubble: full size, dark icon on the teal
     bubble, teal label. Applied by chat-common.js (and to .active as a no-JS
     fallback for the current page). */
  .mobile-tab-item.centered, .mobile-tab-item.active {
    opacity: 1;
    transform: scale(1);
  }
  .mobile-tab-item.centered .mobile-tab-icon,
  .mobile-tab-item.active .mobile-tab-icon { color: #0a0a0e; }
  .mobile-tab-item.centered .mobile-tab-label,
  .mobile-tab-item.active .mobile-tab-label { color: var(--teal-text); }
  /* Body-level padding so the fixed bar never covers the last row of
     content - scoped to :has(.mobile-tab-nav) so pages that don't render
     the bar (watch.html, login, signup, index, policy, onboarding) are
     completely unaffected. */
  body:has(.mobile-tab-nav) { padding-bottom: 84px; }
}

/* ==================== Home dashboard: two-column layout ==================== */
.dashboard-grid {
  display: grid;
  grid-template-columns: 1fr 360px;
  gap: 30px;
  align-items: start;
}
.dashboard-main { display: flex; flex-direction: column; }
.dashboard-sidebar {
  border-left: 1px solid var(--border-subtle);
  padding-left: 30px;
  position: sticky;
  top: 90px;
}
.dashboard-sidebar .panel { margin-bottom: 18px; }

/* Live watch party rows (home.html) - visually distinct from a plain
   friend-row so "someone is live right now" reads as the headline feed
   item it is. */
.live-party-row {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px;
  border-radius: var(--radius);
  background: rgba(34,184,176,0.05);
  border: 1px solid rgba(34,184,176,0.15);
  margin-bottom: 10px;
  transition: var(--transition);
}
.live-party-row:hover { border-color: rgba(34,184,176,0.35); transform: translateY(-1px); }
.live-party-row:last-child { margin-bottom: 0; }
.live-party-info { flex: 1; min-width: 0; }
.live-party-title { font-weight: 700; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.live-party-meta { font-size: 12px; color: var(--text-dimmer); margin-top: 2px; }

/* Destructive row actions (Unfriend, etc.) only reveal themselves once the
   row itself is being hovered/targeted, instead of sitting permanently
   next to every name in the list. */
.friend-actions [data-unfriend] {
  opacity: 0;
  transition: var(--transition);
}
.friend-row:hover .friend-actions [data-unfriend],
.friend-row:focus-within .friend-actions [data-unfriend] {
  opacity: 1;
}

/* ==================== System toast dock (background-convert.js) ==================== */
.system-toast-dock {
  position: fixed;
  bottom: 24px;
  left: 24px;
  z-index: 2000;
  display: flex;
  flex-direction: column;
  gap: 12px;
  pointer-events: none;
  max-width: calc(100vw - 48px);
}
.status-toast {
  pointer-events: auto;
  display: none;
  align-items: center;
  gap: 14px;
  background: var(--panel-glass-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: var(--border-subtle);
  border-left: 3px solid var(--teal);
  padding: 14px 18px;
  border-radius: var(--radius);
  box-shadow: 0 16px 32px rgba(0,0,0,0.5);
  animation: toastSlideIn .3s var(--ease);
  max-width: 340px;
}
.toast-spinner {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  border: 2px solid rgba(34,184,176,0.2);
  border-top-color: var(--teal);
  border-radius: 50%;
  animation: toastSpin .8s linear infinite;
}
.toast-body { display: flex; flex-direction: column; min-width: 0; }
.toast-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.toast-sub { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }
@keyframes toastSpin { to { transform: rotate(360deg); } }
@keyframes toastSlideIn {
  from { transform: translateY(16px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
@media (max-width: 760px) {
  .system-toast-dock { left: 12px; bottom: 76px; }
  .status-toast { max-width: calc(100vw - 24px); }
}

/* ==================== Personal chat / DMs / groups (chat-common.js) ==================== */

/* Generic small round close button, used by any overlay chat-common.js
   builds (picker, and shared with the lightbox's own close button) on
   pages that don't already define their own .close-btn. */
.close-btn {
  background: var(--bg-elevated-2); color: var(--text); border: none; border-radius: 6px;
  padding: 6px 12px; font-size: 12px; cursor: pointer;
}

/* Small unread-count pill - shown in the nav bar, mobile tab bar, FAB,
   drawer rows, chats.html list rows, and the watch.html Inbox tab. Same
   1-9 / "9+" convention used everywhere else in the app. */
.chat-nav-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 4px; margin-left: 5px;
  background: var(--accent); color: #fff; font-size: 10px; font-weight: 700;
  border-radius: var(--radius-pill); line-height: 1;
}
.nav-links a { display: inline-flex; align-items: center; }
.mobile-tab-label { display: inline-flex; align-items: center; }

/* ---- Floating widget (Messenger-style docked chat popup) on non-video pages ----
   Pinned bottom-right, sits in its own fixed stacking layer above normal page
   content so it reads as persistent chrome (like Facebook's chat heads) rather
   than something that scrolls away or only appears lower down the page. */
.chat-fab {
  position: fixed; right: 20px; bottom: 20px; z-index: 500;
  height: 56px; min-width: 56px; padding: 0 22px 0 16px; border-radius: 999px; border: 2px solid var(--surf-6);
  background: linear-gradient(150deg, var(--teal) 0%, #0e7a72 100%); color: #06201e; font-size: 24px; cursor: pointer;
  box-shadow: 0 12px 32px rgba(0,0,0,0.55), 0 0 0 4px rgba(34,184,176,0.12); transition: var(--transition);
  display: flex; align-items: center; justify-content: center; gap: 9px;
  animation: chatFabPulse 2.6s ease-in-out infinite;
}
.chat-fab:hover { background: linear-gradient(150deg, var(--teal-hover) 0%, #0e7a72 100%); transform: scale(1.04); animation-play-state: paused; }
.chat-fab.chat-fab-open { transform: none; animation: none; }
.chat-fab-label { font-size: 14.5px; font-weight: 700; white-space: nowrap; }
@keyframes chatFabPulse {
  0%, 100% { box-shadow: 0 12px 32px rgba(0,0,0,0.55), 0 0 0 4px rgba(34,184,176,0.12); }
  50% { box-shadow: 0 12px 32px rgba(0,0,0,0.55), 0 0 0 8px rgba(34,184,176,0.22); }
}
.chat-fab-badge {
  position: absolute; top: -4px; right: -4px; min-width: 20px; height: 20px; padding: 0 4px;
  background: #ef4444; border: 2px solid var(--bg); font-size: 10.5px;
}
@media (max-width: 760px) {
  .chat-fab { padding: 0; width: 56px; }
  .chat-fab-label { display: none; }
}

/* ---- Floating chat-head window stack (Messenger-style) ----
   Fixed to the bottom-right corner, stacking new windows outward from the
   right edge (row-reverse) so the most recently opened/focused one sits
   closest to the FAB that opened it. z-index 9999 sits above ordinary page
   chrome; the lightbox/friend-picker modals go even higher (10000) so they
   still correctly cover an open chat window when triggered from inside one. */
.chat-head-stack {
  position: fixed; bottom: 0; right: 84px; z-index: 9999;
  display: flex; flex-direction: row-reverse; align-items: flex-end; gap: 12px;
  pointer-events: none; /* only the windows themselves (not the gaps) should be clickable */
}
.chat-head-stack > .chat-window { pointer-events: auto; }

.chat-window {
  width: 300px; height: 400px; max-height: calc(100vh - 24px);
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--chat-drawer-bg); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--border-subtle); border-radius: 12px 12px 0 0;
  box-shadow: 0 20px 50px rgba(0,0,0,0.55);
  transition: height 0.22s var(--ease, ease);
}
/* Minimized: collapse everything except the thread header (which IS the
   window's title bar now - chatRenderThreadInto renders it with onMinimize/
   onClose wired in, so there's exactly one header, not a chrome header
   stacked on top of the thread's own header). */
.chat-window.chat-window-minimized { height: 44px; }
.chat-window.chat-window-minimized > *:not(.chat-thread-header) { display: none; }

.chat-window-minimize-btn, .chat-window-close-btn {
  width: 22px; height: 22px; border-radius: 50%; border: none; background: var(--surf-4);
  color: var(--text-dim); font-size: 12px; cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: var(--transition);
}
.chat-window-minimize-btn:hover, .chat-window-close-btn:hover { background: var(--surf-6); color: var(--text); }
.chat-window-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }

/* Popover version of the chat picker list (opened via the FAB, distinct
   from .chat-picker-overlay which is the full-screen "start a new chat"
   friend picker modal). Reuses .chat-drawer-row/.chat-drawer-header
   styling (also shared with watch.html's compact Inbox tab) rather than
   duplicating row layout rules. */
.chat-picker-popover {
  position: fixed; right: 20px; bottom: 92px; z-index: 9999;
  width: 300px; height: 400px; max-height: calc(100vh - 120px);
  background: var(--chat-drawer-bg); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--border-subtle); border-radius: 14px 14px 10px 10px;
  box-shadow: 0 24px 60px rgba(0,0,0,0.6);
  flex-direction: column; overflow: hidden;
}
.chat-picker-popover .chat-drawer-rows { flex: 1; overflow-y: auto; }
.chat-drawer-row-open { opacity: 0.55; }

@media (max-width: 768px) {
  .chat-head-stack, .chat-picker-popover, .chat-fab { display: none !important; }
}

.chat-drawer {
  position: fixed; right: 20px; bottom: 92px; z-index: 500;
  width: 340px; height: 460px; max-height: calc(100vh - 120px);
  background: var(--chat-drawer-bg); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--border-subtle); border-radius: 14px 14px 10px 10px;
  box-shadow: 0 24px 60px rgba(0,0,0,0.6);
  flex-direction: column; overflow: hidden;
}
.chat-drawer-list, .chat-drawer-thread { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.chat-drawer-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 13px 14px; border-bottom: 1px solid var(--border-subtle); font-weight: 800; font-size: 14.5px;
  background: linear-gradient(180deg, rgba(34,184,176,0.14) 0%, rgba(34,184,176,0.03) 100%);
}
.chat-drawer-header-actions { display: flex; align-items: center; gap: 6px; }
.chat-drawer-close {
  width: 26px; height: 26px; border-radius: 50%; border: none; background: var(--surf-4);
  color: var(--text-dim); font-size: 12px; cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: var(--transition);
}
.chat-drawer-close:hover { background: var(--surf-6); color: var(--text); }
.chat-drawer-rows { flex: 1; overflow-y: auto; }
.chat-drawer-row {
  padding: 10px 14px 10px 11px; border-bottom: 1px solid var(--border-subtle); cursor: pointer;
  border-left: 3px solid transparent;
  display: flex; align-items: center; gap: 10px; position: relative; transition: var(--transition);
}
.chat-drawer-row:hover { background: var(--surf-2); }
.chat-drawer-row-unread { background: rgba(34,184,176,0.06); border-left-color: var(--teal); }
.chat-drawer-row-unread:hover { background: rgba(34,184,176,0.1); }
.chat-drawer-row-unread .chat-drawer-row-preview { color: #e8e8ea; font-weight: 600; }
.chat-drawer-avatar {
  width: 38px; height: 38px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(150deg, #0e4a4a 0%, #16161c 100%);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 14px; color: #fff;
  border: 1px solid var(--border-subtle);
}
.chat-drawer-row-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.chat-drawer-row-name-line { display: flex; align-items: baseline; justify-content: space-between; gap: 6px; }
.chat-drawer-row-name { font-size: 13px; font-weight: 700; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-drawer-row-time { font-size: 10px; color: var(--text-dim); flex-shrink: 0; }
.chat-drawer-row-preview {
  font-size: 11.5px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%;
}
.chat-drawer-row .chat-nav-badge { flex-shrink: 0; margin-left: 0; }

/* ---- Shared thread renderer (drawer, /chats.html, watch.html Inbox tab) ---- */
.chat-thread-header {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  border-bottom: 1px solid var(--border-subtle);
  background: linear-gradient(180deg, var(--surf-1) 0%, transparent 100%);
}
.chat-thread-back { background: none; border: none; color: var(--text-dimmer); font-size: 16px; cursor: pointer; padding: 0; flex-shrink: 0; }
/* The avatar+title area is now a button (opens chat settings on click) -
   reset button chrome so it still lays out and reads exactly like the
   plain div it used to be. */
.chat-thread-identity {
  display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0;
  background: none; border: none; padding: 0; margin: 0; cursor: pointer; text-align: left; font: inherit; color: inherit;
}
.chat-thread-avatar {
  width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(150deg, #0e4a4a 0%, #16161c 100%);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 13px; color: #fff;
  border: 1px solid var(--border-subtle);
}
.chat-thread-title-wrap { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.chat-thread-title { font-weight: 700; font-size: 13.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-thread-muted-icon { font-size: 10px; opacity: 0.65; }
.chat-thread-status {
  font-size: 10.5px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-thread-status-typing { color: var(--teal-text); font-style: italic; }
.chat-thread-header-actions { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.chat-toggle-switch { position: relative; display: inline-block; width: 30px; height: 17px; flex-shrink: 0; }
.chat-toggle-switch input { opacity: 0; width: 0; height: 0; }
.chat-toggle-slider {
  position: absolute; inset: 0; background: #3a3b42; border-radius: var(--radius-pill); cursor: pointer; transition: var(--transition);
}
.chat-toggle-slider::before {
  content: ""; position: absolute; width: 13px; height: 13px; left: 2px; top: 2px;
  background: #fff; border-radius: 50%; transition: var(--transition);
}
.chat-toggle-switch input:checked + .chat-toggle-slider { background: var(--teal); }
.chat-toggle-switch input:checked + .chat-toggle-slider::before { transform: translateX(13px); }

.chat-thread-messages {
  flex: 1; min-height: 0; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 8px;
}
.chat-msg2 {
  max-width: 82%; padding: 8px 11px; border-radius: 16px; font-size: 12.5px; line-height: 1.4;
  background: var(--surf-2);
}
/* SameCouch's own bubble silhouette - neither WhatsApp's tail nub nor
   Messenger/Instagram's fully-uniform pill. Each bubble has one sharp
   "cut" corner on the side nearest its sender's own messages (bottom-right
   for you, bottom-left for them); consecutive bubbles from the same
   sender only show that cut on the LAST one in the run, so a quick burst
   reads as one continuous shape with the cut appearing once, at the end. */
.chat-msg2-mine { align-self: flex-end; background: rgba(34,184,176,0.16); border: 1px solid rgba(34,184,176,0.3); border-bottom-right-radius: 4px; }
.chat-msg2-theirs { align-self: flex-start; background: var(--surf-3); border: 1px solid var(--border-subtle); border-bottom-left-radius: 4px; }
.chat-msg2-sender { font-weight: 700; color: var(--teal-text); font-size: 11px; margin-bottom: 2px; }
/* Consecutive same-sender bubbles within a few minutes visually merge -
   tighter gap between them, and the touching corners flatten out to the
   base radius so only the run's own start (top) and end (bottom) keep
   their shaping. */
.chat-msg2.chat-msg2-grouped-top { margin-top: -5px; }
.chat-msg2-mine.chat-msg2-grouped-top { border-top-right-radius: 4px; }
.chat-msg2-mine.chat-msg2-grouped-bottom { border-bottom-right-radius: 16px; }
.chat-msg2-theirs.chat-msg2-grouped-top { border-top-left-radius: 4px; }
.chat-msg2-theirs.chat-msg2-grouped-bottom { border-bottom-left-radius: 16px; }
.chat-msg2-text { white-space: pre-wrap; word-break: break-word; }
.chat-msg2-meta { display: flex; align-items: center; gap: 4px; margin-top: 4px; }
/* Time + receipt read as one blended unit pinned to the end of the row -
   the auto margin sits on the TIME (not the receipt after it), so all
   the row's leftover space collects before the pair instead of wedging
   itself between them. Star/reply stay packed at gap:4px on the left,
   invisible at rest (opacity:0) so they don't show as a gap either. */
.chat-msg2-time { font-size: 10px; color: var(--text-dim); margin-left: auto; }
.chat-reply-btn { background: none; border: none; color: var(--text-dim); font-size: 11px; cursor: pointer; padding: 0; opacity: 0; transition: var(--transition); }
.chat-msg2:hover .chat-reply-btn { opacity: 1; }
.chat-star-btn { background: none; border: none; color: var(--text-dim); font-size: 12px; cursor: pointer; padding: 0; opacity: 0; transition: var(--transition); }
.chat-msg2:hover .chat-star-btn, .chat-star-btn.chat-star-btn-active { opacity: 1; }
.chat-star-btn.chat-star-btn-active { color: #f5b942; }
/* Two separate check-mark glyphs side by side always leave visible
   daylight between them (font kerning doesn't let letters overlap) - a
   plain "&#10003;&#10003;" reads as two distinct ticks with a gap, not
   WhatsApp's single interlocked double-check shape. Wrapping each in
   its own span and pulling the second one back with a negative margin
   lets them overlap into one blended icon instead. */
.chat-receipt { font-size: 10px; color: var(--text-dim); display: inline-flex; align-items: center; }
.chat-receipt-tick { display: inline-block; line-height: 1; }
.chat-receipt-tick-2 { margin-left: -5px; }
.chat-receipt-read { color: var(--teal-text); }

.chat-reply-quote {
  border-left: 2px solid var(--teal); padding: 3px 8px; margin-bottom: 5px;
  font-size: 11px; color: var(--text-dim); background: var(--surf-1); border-radius: 0 6px 6px 0;
}
.chat-reply-quote .chat-reply-name { font-weight: 700; color: var(--teal-text); margin-right: 4px; }
.chat-reply-preview {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 6px 12px; font-size: 11px; color: var(--text-dim);
  background: rgba(34,184,176,0.06); border-top: 1px solid var(--border-subtle);
}
.chat-reply-preview button { background: none; border: none; color: var(--text-dimmer); cursor: pointer; font-size: 12px; }

.chat-media-slot { margin-bottom: 5px; cursor: pointer; border-radius: 8px; overflow: hidden; position: relative; max-width: 220px; }
.chat-media-slot img, .chat-media-slot video { max-width: 100%; max-height: 220px; display: block; border-radius: 8px; }
.chat-media-loading { font-size: 11px; color: var(--text-dim); padding: 10px; }
.chat-video-play-badge {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  font-size: 20px; color: #fff; text-shadow: 0 2px 6px rgba(0,0,0,0.6); pointer-events: none;
}
.chat-file-chip {
  display: flex; align-items: center; gap: 8px; padding: 8px 10px;
  background: var(--surf-2); border: 1px solid var(--border-subtle); border-radius: 8px; cursor: pointer;
}
.chat-file-icon { font-size: 16px; }
.chat-file-name { font-size: 12px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 140px; }
.chat-file-size { font-size: 10.5px; color: var(--text-dim); margin-left: auto; }

/* Floating capsule input bar - detached from the message feed with its own
   blur + shadow instead of sitting flush in a bordered footer strip. */
.chat-thread-composer {
  display: flex; gap: 8px; align-items: center;
  margin: 0 12px 12px; padding: 8px 8px 8px 16px;
  background: var(--chat-composer-bg);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  box-shadow: 0 10px 28px rgba(0,0,0,0.35);
}
.chat-thread-composer input[type="text"] { flex: 1; margin: 0; background: transparent; border: none; padding: 8px 0; }
.chat-thread-composer #chatSendBtn {
  border-radius: 50%; width: 38px; height: 38px; padding: 0; flex-shrink: 0;
  background: var(--surf-4); color: var(--text-faint); box-shadow: none; cursor: default;
  transition: var(--transition);
}
.chat-thread-composer #chatSendBtn.chat-send-btn-active {
  background: var(--teal); color: #06201e; cursor: pointer; box-shadow: 0 4px 14px rgba(34,184,176,0.35);
}
.chat-thread-composer #chatSendBtn:hover.chat-send-btn-active { background: var(--teal-hover); }
.chat-attach-btn {
  background: none; border: 1px solid var(--border-subtle); color: var(--text-dimmer);
  border-radius: 50%; width: 32px; height: 32px; flex-shrink: 0; cursor: pointer; font-size: 14px;
}
.chat-attach-btn:hover { border-color: var(--teal); color: var(--teal-text); }
.chat-attach-preview {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 6px 12px 10px; font-size: 11.5px; color: var(--text-dim);
}
.chat-attach-preview button { background: none; border: none; color: var(--text-dimmer); cursor: pointer; }

/* ---- /chats.html full workspace ----
   Edge-to-edge two-pane app shell (WhatsApp Web style) instead of a boxed
   "widget floating in a dashboard page" - no outer border/shadow/radius,
   fills the viewport below the topbar. The sidebar and the conversation
   canvas are told apart by a background-color shift, not a hard divider. */
.chats-workspace {
  display: grid; grid-template-columns: 340px 1fr; gap: 0;
  overflow: hidden;
  height: calc(100vh - 74px);
  background: #0d1418;
}
.chats-list-col {
  background: var(--chat-sidebar-bg);
  border-right: 1px solid var(--surf-4);
  display: flex; flex-direction: column; min-height: 0;
}
.chats-list-header { display: flex; gap: 8px; padding: 14px; border-bottom: 1px solid var(--surf-4); }
.chats-search-wrap { position: relative; flex: 1; display: flex; align-items: center; }
.chats-search-wrap svg { position: absolute; left: 13px; width: 14px; height: 14px; color: var(--text-dim); pointer-events: none; }
.chats-search-wrap input { flex: 1; margin: 0; padding-left: 34px; background: var(--chat-search-input-bg); border-color: transparent; }
#chatsListRows { flex: 1; overflow-y: auto; }
.chats-thread-col { display: flex; flex-direction: column; min-height: 0; background: var(--chat-thread-bg); position: relative; }
/* Two-tone halftone texture behind the message feed instead of a flat
   void - teal and accent-red dots offset into a light diamond grid, so
   it reads as SameCouch's own duotone rather than a mono wallpaper
   pattern (no image asset, still cheap). */
.chats-thread-col::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none; opacity: 0.6;
  background-image:
    radial-gradient(rgba(34,184,176,0.05) 1px, transparent 1px),
    radial-gradient(rgba(229,9,20,0.035) 1px, transparent 1px);
  background-size: 26px 26px, 26px 26px;
  background-position: 0 0, 13px 13px;
}
.chats-thread-col > * { position: relative; z-index: 1; }
.chats-thread-col .empty { background: transparent; border: none; margin: auto; }

.chat-list-row {
  padding: 12px 16px 12px 13px; border-bottom: 1px solid var(--border-subtle); cursor: pointer;
  border-left: 3px solid transparent;
  display: flex; align-items: center; justify-content: space-between; gap: 8px; transition: var(--transition);
}
.chat-list-row:hover { background: var(--surf-1); }
.chat-list-row-active { background: rgba(34,184,176,0.08); border-left-color: var(--teal); box-shadow: inset 0 0 20px rgba(34,184,176,0.06); }
/* Unread rows get a warm accent-red rail instead of reusing the same teal
   as "active" - two different signals (currently open vs. needs your
   attention) get two different colors from the site's own duotone,
   rather than one blue tint standing in for both like most chat apps. */
.chat-list-row-unread { background: rgba(229,9,20,0.05); border-left-color: var(--accent); }
.chat-list-row-unread:hover { background: rgba(229,9,20,0.09); }
.chat-list-row-avatar {
  width: 42px; height: 42px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(150deg, #0e4a4a 0%, #16161c 100%);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 15px; color: #fff; border: 1px solid var(--border-subtle);
}
.chat-list-row-main { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 3px; }
.chat-list-row-name-line { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.chat-list-row-name { font-size: 13.5px; font-weight: 700; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-list-row-time { font-size: 10.5px; color: var(--text-dim); flex-shrink: 0; }
.chat-list-row-group-tag {
  font-size: 9.5px; font-weight: 700; color: var(--teal-text); border: 1px solid rgba(34,184,176,0.35);
  border-radius: var(--radius-pill); padding: 1px 6px; margin-left: 4px;
}
.chat-list-row-preview { font-size: 12px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
.chat-list-row-unread .chat-list-row-preview { color: #e8e8ea; font-weight: 600; }

.chat-members-panel { padding: 14px 16px; border-top: 1px solid var(--border-subtle); }
.chat-member-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 6px 0; }
.chat-member-real-name { font-size: 12.5px; color: var(--text-dim); flex-shrink: 0; }
.chat-nickname-input { max-width: 160px; margin: 0; font-size: 12px; padding: 6px 10px; }
.chat-nickname-input-wrap { display: inline-flex; align-items: center; gap: 6px; }
.chat-nickname-saved {
  pointer-events: none; white-space: nowrap;
  font-size: 10.5px; font-weight: 700; color: var(--teal-text);
  opacity: 0; transform: translateX(-4px); transition: opacity 0.2s ease, transform 0.2s ease;
}
.chat-nickname-saved-show { opacity: 1; transform: translateX(0); }

/* ---- Media picker overlay (Add photos/videos - galleries & playlists) ----
   Dimmed-but-see-through backdrop (blur + a low-opacity dark tint, not a
   flat opaque block) so the gallery/playlist content underneath stays
   visible while picking - the "perfect background tint" gallery's picker
   already had, now shared so playlists.html's video picker matches it
   exactly instead of inventing its own. */
.picker-overlay {
  position: fixed; inset: 0; background: rgba(6,6,10,0.85); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center; z-index: 998; padding: 24px;
}
.picker-panel {
  background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 14px;
  max-width: 720px; width: 100%; max-height: 80vh; overflow-y: auto; padding: 20px;
}
.picker-panel h3 { margin: 0 0 14px; font-size: 15px; display: flex; align-items: center; justify-content: space-between; }
/* Bigger, full-height variant for the searchable video picker (playlist's
   "Videos" button, gallery's upgraded video picker) - a flex column so the
   video grid scrolls internally while the search bar stays put at top. */
.picker-panel-lg {
  max-width: 920px; width: 100%; height: 78vh; max-height: 640px;
  display: flex; flex-direction: column; overflow: hidden;
}
.picker-panel-lg h3 { flex-shrink: 0; }
.picker-search-row { flex-shrink: 0; margin-bottom: 12px; }
.picker-search-row input {
  width: 100%; margin: 0; background: var(--surf-3); border: 1px solid var(--border-subtle);
  border-radius: 999px; padding: 9px 16px; font-size: 13.5px; color: var(--text);
}
.picker-panel-lg .ig-grid { flex: 1; min-height: 0; overflow-y: auto; align-content: flex-start; }

/* ---- Picker overlay (new chat / friend + group picker) ---- */
.chat-picker-overlay, .chat-lightbox-overlay {
  position: fixed; inset: 0; z-index: 10000; background: rgba(6,6,9,0.78);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.chat-picker-panel {
  background: var(--bg-elevated); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
  padding: 20px; width: 100%; max-width: 360px; max-height: 80vh; overflow-y: auto;
}
.chat-picker-panel h3 { display: flex; align-items: center; justify-content: space-between; margin: 0 0 14px; }
.chat-picker-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; font-size: 13px; cursor: pointer; }
.chat-picker-row input[type="checkbox"] { width: auto; margin: 0; }

/* .chat-picker-panel-tall + .chat-picker-new-body: the modal "New message"
   variant of the friend picker (chats.html / watch.html's inbox) gets a
   fixed-height flex column so its friend list scrolls internally while the
   Chat button stays pinned at the bottom, instead of scrolling away with
   the rest of the panel like a plain overflow:auto block would. */
.chat-picker-panel-tall { display: flex; flex-direction: column; height: 68vh; max-height: 520px; padding-bottom: 14px; }
.chat-picker-panel-tall h3 { flex-shrink: 0; }

/* ---- Shared friend picker: search + multi-select rows + sticky Chat
   button - used both in-place (FAB popover "new message" view) and inside
   the modal above. One implementation so "select people -> Chat" behaves
   and looks identical everywhere it appears. */
.chat-picker-new-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.chat-picker-search-row { padding: 10px 12px; flex-shrink: 0; }
.chat-picker-panel .chat-picker-search-row { padding: 0 0 12px; }
.chat-picker-search-row input {
  width: 100%; margin: 0; background: var(--surf-3); border: 1px solid var(--border-subtle);
  border-radius: 999px; padding: 8px 14px; font-size: 13px; color: var(--text);
}
.chat-picker-friend-list { flex: 1; min-height: 0; overflow-y: auto; padding: 0 6px; }
.chat-picker-panel .chat-picker-friend-list { padding: 0; }
.chat-picker-friend-row {
  display: flex; align-items: center; gap: 12px; padding: 9px 8px; border-radius: 10px;
  cursor: pointer; transition: var(--transition);
}
.chat-picker-friend-row:hover { background: var(--surf-2); }
.chat-picker-friend-row-selected { background: rgba(34,184,176,0.1); }
.chat-picker-friend-avatar {
  flex-shrink: 0; width: 38px; height: 38px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  background: var(--surf-5); color: var(--text); font-weight: 700; font-size: 15px;
}
.chat-picker-friend-name { flex: 1; font-size: 13.5px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-picker-friend-check {
  flex-shrink: 0; width: 20px; height: 20px; border-radius: 50%; border: 2px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: center; font-size: 11px; color: transparent; transition: var(--transition);
}
.chat-picker-friend-row-selected .chat-picker-friend-check { background: var(--teal); border-color: var(--teal); color: #06201e; }
.chat-picker-chat-btn-row { flex-shrink: 0; padding: 10px 12px 0; }
.chat-picker-panel .chat-picker-chat-btn-row { padding: 10px 0 0; }
.chat-picker-chat-btn { width: 100%; border-radius: 999px; padding: 10px; font-weight: 700; }

/* ---- New-message pencil button in the popover's list header ---- */
.chat-drawer-new-btn {
  width: 26px; height: 26px; border-radius: 50%; border: none; background: var(--surf-4);
  color: var(--text-dim); font-size: 13px; cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: var(--transition);
}
.chat-drawer-new-btn:hover { background: var(--teal); color: #06201e; }

/* ---- Chat settings panel (contact/group info - opened from the thread
   header avatar/title everywhere chatRenderThreadInto is used) ---- */
.chat-settings-panel {
  background: var(--bg-elevated); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
  padding: 20px; width: 100%; max-width: 380px; max-height: 85vh; overflow-y: auto;
}
.chat-settings-header { display: flex; align-items: center; justify-content: space-between; margin: 0 0 16px; }
.chat-settings-header h3 { margin: 0; }
.chat-settings-identity { display: flex; flex-direction: column; align-items: center; gap: 8px; margin-bottom: 20px; }
.chat-settings-avatar {
  width: 64px; height: 64px; border-radius: 50%;
  background: linear-gradient(150deg, #0e4a4a 0%, #16161c 100%);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 24px; color: #fff; border: 1px solid var(--border-subtle);
}
.chat-settings-title { font-weight: 700; font-size: 15px; color: var(--text); text-align: center; }
.chat-settings-section { padding: 14px 0; border-top: 1px solid var(--border-subtle); }
.chat-settings-section h4 { margin: 0 0 8px; font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); }
.chat-settings-explainer { font-size: 12px; line-height: 1.55; color: var(--text-dim); margin: 6px 0 0; }
.chat-settings-toggle-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  font-size: 13px; color: var(--text); cursor: pointer;
}
.chat-settings-member-list, .chat-settings-starred-list { display: flex; flex-direction: column; gap: 6px; }
.chat-settings-member-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: 13px; color: var(--text); padding: 4px 0; }
.chat-settings-you-tag { color: var(--text-dim); font-size: 11.5px; }
.chat-settings-add-friend-btn {
  flex-shrink: 0; border: 1px solid var(--teal); background: transparent; color: var(--teal-text);
  border-radius: 999px; padding: 4px 11px; font-size: 11.5px; font-weight: 700; cursor: pointer; transition: var(--transition);
}
.chat-settings-add-friend-btn:hover { background: var(--teal); color: #06201e; }
.chat-settings-member-requested { flex-shrink: 0; font-size: 11px; color: var(--text-dim); }
.chat-settings-starred-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 10px; background: var(--surf-2); border-radius: 8px; font-size: 12.5px;
}
.chat-settings-starred-sender { font-weight: 700; color: var(--text); margin-right: 6px; }
.chat-settings-starred-snippet { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-settings-unstar-btn { background: none; border: none; color: #f5b942; font-size: 14px; cursor: pointer; padding: 0; flex-shrink: 0; }

/* ---- Lightbox (shared: widget, /chats.html, watch.html Inbox) ---- */
.chat-lightbox-body { max-width: 100%; max-height: 85vh; display: flex; align-items: center; justify-content: center; }
.chat-lightbox-body img, .chat-lightbox-body video { max-width: 100%; max-height: 85vh; border-radius: 8px; box-shadow: 0 12px 40px rgba(0,0,0,0.5); }
.chat-lightbox-close, .chat-lightbox-download {
  position: absolute; top: 20px; width: 40px; height: 40px; border-radius: 50%;
  background: rgba(10,10,14,0.7); color: #fff; border: 1px solid rgba(255,255,255,0.15); cursor: pointer;
  display: flex; align-items: center; justify-content: center; font-size: 16px; text-decoration: none;
}
.chat-lightbox-close:hover, .chat-lightbox-download:hover { background: var(--accent); border-color: var(--accent); }
.chat-lightbox-close { right: 20px; }
.chat-lightbox-download { right: 74px; }

/* ---- watch.html: Movie Chat / Personal Inbox tab switcher ---- */
.chat-mode-tabs { display: flex; gap: 4px; padding: 8px 14px 0; }
.chat-mode-tab {
  flex: 1; background: none; border: none; color: var(--text-dimmer); font-size: 11.5px; font-weight: 700;
  padding: 8px 6px; border-radius: var(--radius) var(--radius) 0 0; cursor: pointer; position: relative;
  display: flex; align-items: center; justify-content: center; gap: 4px;
}
.chat-mode-tab.active { color: var(--teal-text); background: rgba(34,184,176,0.08); }
.chat-mode-body { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.pin-time-btn {
  background: none; border: 1px solid var(--border-subtle); color: var(--text-dimmer);
  border-radius: 50%; width: 34px; height: 34px; flex-shrink: 0; cursor: pointer; font-size: 14px;
}
.pin-time-btn:hover { border-color: var(--teal); color: var(--teal-text); }
.seek-pin-pill {
  background: rgba(0,0,0,0.3); border: 1px solid rgba(34,184,176,0.35); color: var(--teal-text);
  border-radius: 6px; padding: 5px 10px; font-size: 11px; font-family: inherit; cursor: pointer;
}
.seek-pin-pill:hover { background: rgba(34,184,176,0.15); }

/* ---- Members/nicknames collapsible - global version so pages without
   their own page-scoped copy (chats.html) still get correct styling. ---- */
.collapsible-header {
  width: 100%; background: none; border: none; padding: 0; margin: 18px 0 0;
  display: flex; align-items: center; justify-content: space-between; cursor: pointer; text-align: left;
}
.collapsible-header:first-of-type { margin-top: 0; }
.collapsible-header .collapse-chevron { font-size: 11px; color: var(--text-dim); transition: var(--transition); }
.collapsible-body { display: none; padding-top: 10px; }
.collapsible-body.open { display: block; }

@media (max-width: 760px) {
  /* Single-pane on mobile, like the native WhatsApp app: show the chat list
     OR the open thread, never both stacked. #chatsWorkspace toggles the
     .thread-open class (chats.html JS) once a chat is opened; the back
     arrow chatRenderThreadInto renders (opts.onBack) flips it off again. */
  .chats-workspace { grid-template-columns: 1fr; height: calc(100vh - 74px - 64px); }
  .chats-workspace:not(.thread-open) .chats-thread-col { display: none; }
  .chats-workspace.thread-open .chats-list-col { display: none; }
  .chat-drawer { right: 12px; left: 12px; width: auto; bottom: 82px; }
  .chat-fab { right: 16px; bottom: 78px; }
}
@media (min-width: 761px) {
  /* The back arrow only makes sense once list+thread aren't both visible -
     desktop always shows both panes on the /chats.html workspace, so hide
     it there specifically. It must stay visible everywhere else
     (floating widget drawer, watch.html's compact Inbox tab) even on wide
     screens, since those are single-pane regardless of viewport width -
     hiding it globally left no way back to the chat list on desktop. */
  .chats-thread-col .chat-thread-back { display: none; }
}

/* ==================== Live invite popups + nav badges (invite-common.js) ==================== */
.invite-nav-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 4px; margin-left: 5px;
  background: var(--accent); color: #fff; font-size: 10px; font-weight: 700;
  border-radius: var(--radius-pill); line-height: 1;
}

.invite-popup-dock {
  position: fixed; top: 78px; right: 20px; z-index: 300;
  display: flex; flex-direction: column; gap: 10px; max-width: 300px;
}
.invite-popup {
  position: relative;
  background: var(--panel-glass-bg); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--border-focus); border-radius: var(--radius);
  padding: 14px 16px; box-shadow: 0 16px 36px rgba(0,0,0,0.5);
  animation: invitePopupIn .25s var(--ease);
}
@keyframes invitePopupIn {
  from { transform: translateX(16px); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}
.invite-popup-close {
  position: absolute; top: 8px; right: 8px; background: none; border: none;
  color: var(--text-dim); font-size: 12px; cursor: pointer; padding: 4px;
}
.invite-popup-close:hover { color: var(--text); }
.invite-popup-title { font-size: 13px; font-weight: 700; color: var(--text); padding-right: 20px; }
.invite-popup-sub { font-size: 12.5px; color: var(--teal-text); margin-top: 2px; }
.invite-popup-actions { display: flex; gap: 8px; margin-top: 10px; }

@media (max-width: 760px) {
  .invite-popup-dock { top: auto; bottom: 84px; right: 12px; left: 12px; max-width: none; }
}

/* ==================== Pull-to-refresh indicator (pull-to-refresh.js) ==================== */
.pull-refresh-indicator {
  position: fixed; top: -40px; left: 50%; transform: translate(-50%, 0px);
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--bg-elevated-2); border: 1px solid var(--border-subtle);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 4px 12px rgba(0,0,0,0.4); opacity: 0; z-index: 1000;
  transition: transform .2s cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity .2s;
}
.pull-refresh-spinner {
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid rgba(34,184,176,0.25); border-top-color: var(--teal);
}
.pull-refresh-indicator.refreshing .pull-refresh-spinner { animation: pullRefreshSpin .7s linear infinite; }
@keyframes pullRefreshSpin { to { transform: rotate(360deg); } }

/* ==================== Watch stories carousel (home.html) ==================== */
.watch-stories-container {
  display: flex; gap: 16px; padding: 16px 32px 4px;
  overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch;
}
.watch-stories-container::-webkit-scrollbar { display: none; }
.story-item {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  flex-shrink: 0; cursor: pointer; scroll-snap-align: start; text-decoration: none;
  width: 68px; background: none; border: none;
}
.story-avatar-wrap {
  position: relative; width: 60px; height: 60px; border-radius: 50%; padding: 3px;
  background: var(--bg-elevated-2);
}
.story-item.is-live .story-avatar-wrap {
  background: linear-gradient(135deg, var(--teal) 0%, #007aff 100%);
  box-shadow: 0 0 12px var(--teal-glow);
}
.story-avatar, .story-avatar-plus {
  width: 100%; height: 100%; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(150deg, #0e4a4a 0%, #16161c 100%);
  border: 2px solid var(--bg); font-size: 15px; font-weight: 700; color: #fff; overflow: hidden;
}
.story-avatar-plus { font-size: 24px; background: var(--bg-elevated-2); color: var(--teal-text); }
.story-avatar img { width: 100%; height: 100%; object-fit: cover; }
.live-pill {
  position: absolute; bottom: -2px; left: 50%; transform: translateX(-50%);
  background: var(--accent); color: #fff; font-size: 8.5px; font-weight: 800;
  padding: 1.5px 6px; border-radius: 6px; letter-spacing: 0.4px; border: 1.5px solid var(--bg);
  white-space: nowrap;
}
.story-username {
  font-size: 11.5px; color: var(--text-dimmer); font-weight: 600;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 760px) {
  .watch-stories-container { padding: 14px 16px 4px; gap: 12px; }
}

/* ==================== Design overhaul, phase 1: foundation ====================
   Utility classes (replaces one-off inline styles on auth pages), a
   borderless "no-panel" auth layout, a reusable bottom-sheet component for
   later phases, brand-tinted OAuth button hovers, and progressive-enhancement
   view transitions. Purely additive - nothing existing above is renamed or
   removed, so every other page keeps working exactly as it does today. */

/* ---- Small utility classes (replace repeated inline styles) ---- */
.text-center { text-align: center; }
.text-right { text-align: right; }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.mb-2 { margin-bottom: 8px; }
.mb-3 { margin-bottom: 14px; }
.mb-4 { margin-bottom: 18px; }
.mt-3 { margin-top: 14px; }
.flex-row { display: flex; align-items: center; }
.flex-1 { flex: 1; }
.gap-2 { gap: 8px; }
.gap-3 { gap: 10px; }

/* Faint whitespace-style divider (replaces hard 1px var(--border) lines
   like the "OR" separator on login/signup) - consumer apps prefer this
   barely-there look over a hard rule. */
.divider-row { display: flex; align-items: center; gap: 10px; margin: 18px 0; }
.divider-line { flex: 1; height: 1px; background: var(--divider-color); }
.divider-label { font-size: 11px; color: var(--text-dim); }

/* ---- No-panel, edge-to-edge auth layout (login / signup / choose-name) ----
   Replaces .page-narrow > .panel for these three pages specifically - the
   form sits directly on the ambient background instead of inside a floating
   box, centered top-to-bottom so the task is the only thing on screen. */
.auth-layout {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: calc(100vh - 60px);
  padding: 24px;
}
.auth-content {
  width: 100%;
  max-width: 380px;
  display: flex;
  flex-direction: column;
}
.auth-brand-header { text-align: center; margin-bottom: 22px; }
.auth-brand-header .logo-mark { width: 30px; height: 30px; margin: 0 auto 12px; }
.auth-brand-header h2 { font-size: 22px; font-weight: 800; letter-spacing: -0.4px; margin: 0 0 6px; }
.auth-subtitle { color: var(--text-dim); font-size: 13px; margin: 0; line-height: 1.5; }

/* Soft, borderless inputs - a slightly-elevated fill instead of a bordered
   box, larger radius ("squircle") and more generous padding than the
   pill-shaped inputs used elsewhere in the app (library/upload forms keep
   their existing look; this is scoped to .auth-content only). */
.auth-content input[type=text],
.auth-content input[type=email],
.auth-content input[type=password] {
  border-radius: 16px;
  padding: 15px 18px;
  background: var(--bg-elevated-2);
  border: 1px solid transparent;
}
.auth-content input[type=text]:focus,
.auth-content input[type=email]:focus,
.auth-content input[type=password]:focus {
  border-color: var(--teal);
}
.auth-switch-line { margin-top: 18px; text-align: center; font-size: 13px; color: var(--text-dim); }
.auth-switch-line a { color: var(--teal-text); font-weight: 600; text-decoration: none; }
.auth-switch-line a:hover { text-decoration: underline; }
.auth-forgot-link { font-size: 12px; color: var(--text-dim); text-decoration: none; }
.auth-forgot-link:hover { color: var(--teal-text); }

/* Minimal top strip for auth pages - just enough for a way back to the
   marketing site, no nav pill group (the cross-link to log in/sign up
   already lives at the bottom of .auth-content). */
.auth-topbar {
  display: flex; justify-content: center; padding: 20px 16px 0;
}

/* Brand-tinted hover for the OAuth buttons - a 5%-opacity wash of each
   provider's own color instead of the generic teal .btn-outline hover. */
.btn-google:hover { background: rgba(255, 193, 7, 0.07); border-color: rgba(255, 193, 7, 0.35); color: var(--text); }
.btn-facebook:hover { background: rgba(24, 119, 242, 0.09); border-color: rgba(24, 119, 242, 0.4); color: var(--text); }

/* ---- Reusable bottom sheet (replaces centered modal dialogs for
   in-flow actions - invite pickers, option menus, filters, etc.) ----
   Markup: <div class="bottom-sheet-overlay" id="...">
             <div class="bottom-sheet-content">
               <div class="sheet-drag-handle"></div>
               ...content...
             </div>
           </div>
   JS: toggle the "active" class on the overlay to open/close. */
.bottom-sheet-overlay {
  position: fixed; inset: 0; z-index: 500;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  display: flex; align-items: flex-end; justify-content: center;
  opacity: 0; pointer-events: none;
  transition: opacity 0.25s var(--ease);
}
.bottom-sheet-overlay.active { opacity: 1; pointer-events: auto; }
.bottom-sheet-content {
  width: 100%; max-width: 520px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: 24px 24px 0 0;
  padding: 14px 22px 28px;
  max-height: 82vh; overflow-y: auto;
  transform: translateY(100%);
  transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
  box-shadow: 0 -20px 50px rgba(0, 0, 0, 0.5);
}
.bottom-sheet-overlay.active .bottom-sheet-content { transform: translateY(0); }
.sheet-drag-handle {
  width: 40px; height: 5px; background: var(--border);
  border-radius: var(--radius-pill); margin: 0 auto 16px;
}
.sheet-title { font-size: 16px; font-weight: 800; margin: 0 0 14px; letter-spacing: -0.2px; }

@media (min-width: 761px) {
  /* On desktop, the same overlay centers instead of docking to the bottom -
     the "sheet" framing only makes sense as a thumb-reachable mobile
     pattern; wide screens get a normal centered dialog with the same markup. */
  .bottom-sheet-overlay { align-items: center; }
  .bottom-sheet-content { border-radius: var(--radius-lg); transform: translateY(12px) scale(0.98); }
  .bottom-sheet-overlay.active .bottom-sheet-content { transform: translateY(0) scale(1); }
}

@media (max-width: 760px) {
  .auth-layout { min-height: calc(100vh - 100px); padding: 16px; }
}

/* ---- View Transitions API: smooth cross-fade between full page loads on
   browsers that support it (Chrome/Edge). No-op elsewhere - progressive
   enhancement only, nothing breaks on browsers without support. ---- */
@view-transition {
  navigation: auto;
}
::view-transition-old(root) {
  animation: 90ms cubic-bezier(0.4, 0, 1, 1) both auth-fade-out;
}
::view-transition-new(root) {
  animation: 210ms cubic-bezier(0, 0, 0.2, 1) both auth-slide-in;
}
@keyframes auth-fade-out { to { opacity: 0; } }
@keyframes auth-slide-in {
  from { transform: translateY(8px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

/* ==================== Community (community.html) ====================
   A community is deliberately a separate, bigger-than-chat concept: its
   own membership, a public feed anyone in it can post/comment on, and
   named channels for topic-scoped messaging - all backed by its own
   communities/communityDirectory/communityMessages RTDB trees, not the
   friend-graph-gated chats/ system. */
.community-back-link { display: inline-block; color: var(--text-dim); font-size: 13px; text-decoration: none; margin-bottom: 16px; }
.community-back-link:hover { color: var(--teal-text); }

.community-grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.community-card {
  background: var(--bg-elevated); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg);
  padding: 16px; display: flex; flex-direction: column; transition: var(--transition);
}
.community-card:hover { border-color: rgba(34,184,176,0.35); }
.community-card-avatar {
  width: 44px; height: 44px; border-radius: 50%;
  background: linear-gradient(150deg, #0e4a4a 0%, #16161c 100%);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 17px; color: #fff; margin-bottom: 10px;
}
.community-card-name { font-weight: 700; font-size: 14.5px; color: var(--text); }
.community-card-desc {
  font-size: 12px; color: var(--text-dim); margin-top: 4px; line-height: 1.5;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  min-height: 32px;
}
.community-card-meta { font-size: 11px; color: var(--text-dimmer); margin-top: 8px; }

.community-header {
  display: flex; align-items: flex-start; gap: 16px; padding: 20px 0; border-bottom: 1px solid var(--border-subtle); margin-bottom: 18px;
}
.community-header-avatar {
  width: 60px; height: 60px; border-radius: 50%; flex-shrink: 0;
  background: linear-gradient(150deg, #0e4a4a 0%, #16161c 100%);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 22px; color: #fff; border: 1px solid var(--border-subtle);
}
.community-header-main { flex: 1; min-width: 0; }
.community-header-name { font-weight: 800; font-size: 19px; color: var(--text); }
.community-header-desc { font-size: 13px; color: var(--text-dim); margin-top: 4px; line-height: 1.55; max-width: 560px; }
.community-header-meta { font-size: 12px; color: var(--text-dimmer); margin-top: 6px; }
.community-header-actions { flex-shrink: 0; }

.community-tabs { display: flex; gap: 6px; border-bottom: 1px solid var(--border-subtle); margin-bottom: 20px; }
.community-tab {
  background: none; border: none; color: var(--text-dimmer); font-size: 13px; font-weight: 700;
  padding: 10px 16px; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.community-tab.active { color: var(--teal-text); border-bottom-color: var(--teal); }

/* ---- Feed ---- */
.community-post {
  background: var(--bg-elevated); border: 1px solid var(--border-subtle); border-radius: var(--radius);
  padding: 16px; margin-bottom: 14px;
}
.community-post-author { font-weight: 700; font-size: 13.5px; color: var(--text); display: inline; }
.community-post-time { font-size: 11px; color: var(--text-dim); display: inline; margin-left: 8px; }
.community-post-text { font-size: 13.5px; color: var(--text); line-height: 1.6; margin-top: 8px; white-space: pre-wrap; word-break: break-word; }
.community-post-comment-toggle {
  background: none; border: none; color: var(--text-dim); font-size: 12px; cursor: pointer; padding: 0; margin-top: 10px;
}
.community-post-comment-toggle:hover { color: var(--teal-text); }
.community-post-comments { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border-subtle); display: flex; flex-direction: column; gap: 8px; }
.community-comment-row { font-size: 12.5px; color: var(--text-dim); }
.community-comment-author { font-weight: 700; color: var(--text); margin-right: 6px; }
.community-comment-composer { margin-top: 4px; }
.community-comment-input { font-size: 12.5px; padding: 8px 10px; }

/* ---- Channels ---- */
.community-channels-layout {
  display: grid; grid-template-columns: 200px 1fr; gap: 0;
  border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); overflow: hidden;
  height: 560px; max-height: 70vh;
}
.community-channel-sidebar {
  background: var(--bg-elevated); border-right: 1px solid var(--border-subtle);
  padding: 10px; display: flex; flex-direction: column; gap: 2px; overflow-y: auto;
}
.community-channel-row {
  background: none; border: none; color: var(--text-dim); font-size: 13px; text-align: left;
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
}
.community-channel-row:hover { background: var(--surf-2); color: var(--text); }
.community-channel-row-active { background: rgba(34,184,176,0.12); color: var(--teal-text); }
.community-channel-add {
  background: none; border: 1px dashed var(--border-subtle); color: var(--text-dim); font-size: 12px;
  padding: 8px 10px; border-radius: 8px; cursor: pointer; margin-top: 6px;
}
.community-channel-add:hover { border-color: var(--teal); color: var(--teal-text); }
.community-channel-main { display: flex; flex-direction: column; min-height: 0; }
.community-channel-header { padding: 12px 16px; border-bottom: 1px solid var(--border-subtle); font-weight: 700; font-size: 13.5px; color: var(--text); flex-shrink: 0; }
.community-channel-messages { flex: 1; overflow-y: auto; padding: 12px 16px; display: flex; flex-direction: column; gap: 12px; }
.community-channel-msg-sender { font-weight: 700; font-size: 12.5px; color: var(--text); }
.community-channel-msg-time { font-size: 10.5px; color: var(--text-dim); margin-left: 8px; }
.community-channel-msg-text { font-size: 13px; color: var(--text); line-height: 1.5; margin-top: 3px; white-space: pre-wrap; word-break: break-word; }
.community-channel-composer { padding: 10px 16px; border-top: 1px solid var(--border-subtle); flex-shrink: 0; }
.community-channel-composer input { margin: 0; }
.community-channel-readonly { padding: 10px 16px; border-top: 1px solid var(--border-subtle); font-size: 12px; color: var(--text-dim); flex-shrink: 0; }

/* ==================== Instagram-style tabs + 3-col grid ====================
   Shared by /library.html, /playlists.html, and /gallery.html - visual
   pattern adapted from the ts-full-stack-instagram-clone reference repo's
   ProfileTabs/ProfilePost components (re-themed to our dark/teal palette,
   not Instagram's). Each page keeps its own upload/fetch/delete logic;
   this only governs how entries render and how hover-previews sit on
   top of a tile. */
.ig-tabs { display: flex; justify-content: center; gap: 48px; border-bottom: 1px solid var(--border-subtle); margin-bottom: 24px; }
.ig-tab-btn {
  background: none; border: none; border-top: 2px solid transparent; margin-top: -1px;
  display: flex; align-items: center; gap: 6px; padding: 14px 4px 12px;
  color: var(--text-dim); font-size: 11px; font-weight: 700; letter-spacing: 1px; text-transform: uppercase;
  cursor: pointer; transition: var(--transition);
}
.ig-tab-btn svg { width: 14px; height: 14px; flex-shrink: 0; }
.ig-tab-btn:hover { color: var(--text-dimmer); }
.ig-tab-btn.active { color: var(--teal-text); border-top-color: var(--teal); }

.ig-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; margin-bottom: 10px; }
.ig-grid-tile {
  position: relative; aspect-ratio: 1 / 1; overflow: hidden; cursor: pointer;
  background: var(--bg-elevated-2); border-radius: 2px; text-decoration: none; display: block;
}
.ig-grid-tile img, .ig-grid-tile video { width: 100%; height: 100%; object-fit: cover; display: block; }
.ig-grid-tile-play {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 22px; color: rgba(255,255,255,0.9); pointer-events: none; text-align: center; padding: 6px;
  z-index: 2; transition: opacity .15s var(--ease);
}
.ig-grid-tile-overlay {
  position: absolute; inset: 0; background: rgba(0,0,0,0.4); opacity: 0; transition: var(--transition);
  display: flex; align-items: center; justify-content: center; color: #fff; font-size: 12px; font-weight: 600;
  text-align: center; padding: 8px; pointer-events: none; z-index: 2;
}
.ig-grid-tile:hover .ig-grid-tile-overlay { opacity: 1; }
/* Hover preview layer - a muted <video> laid over the static poster,
   used both for Library's within-one-video scrub and Playlists'
   across-videos-in-order preview. Hidden until JS has fetched a real
   playback URL and started it, so a slow/failed fetch just leaves the
   static poster/gradient showing. */
.ig-grid-tile-preview-video {
  position: absolute; inset: 0; z-index: 1; display: none; background: #000;
}
/* A picked cover picture (playlist/gallery card) sits below the hover
   preview layer, not instead of it - picking one is purely about what
   shows at rest, and never changes what happens on hover. */
.ig-grid-tile-cover-img {
  position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; object-fit: cover; display: block;
}
.ig-grid-tile-previewing .ig-grid-tile-play { opacity: 0; }
/* Gallery's random slideshow preview swaps a plain <img> in the same
   layer instead, for the photo frames in its photos+videos mix. */
.ig-grid-tile-preview-img {
  position: absolute; inset: 0; z-index: 1; display: none; width: 100%; height: 100%; object-fit: cover; background: #000;
}
.ig-grid-tile-delete {
  position: absolute; top: 6px; right: 6px; width: 26px; height: 26px; border-radius: 50%;
  background: rgba(10,10,14,0.65); border: 1px solid rgba(255,255,255,0.15); color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: 12px; cursor: pointer;
  opacity: 0; transition: var(--transition); z-index: 3;
}
.ig-grid-tile:hover .ig-grid-tile-delete { opacity: 1; }
.ig-grid-tile-delete:hover { background: var(--accent); border-color: var(--accent); }
/* Second icon button (e.g. "manage/rename") - mirrors .ig-grid-tile-delete
   on the opposite top corner so both can appear on the same tile. */
.ig-grid-tile-manage {
  position: absolute; top: 6px; left: 6px; width: 26px; height: 26px; border-radius: 50%;
  background: rgba(10,10,14,0.65); border: 1px solid rgba(255,255,255,0.15); color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: 12px; cursor: pointer;
  opacity: 0; transition: var(--transition); z-index: 3;
}
.ig-grid-tile:hover .ig-grid-tile-manage { opacity: 1; }
.ig-grid-tile-manage:hover { background: var(--teal); border-color: var(--teal); color: #06201e; }
.ig-grid-tile-loading { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--text-dimmer); font-size: 13px; }
/* Always-visible small label (item counts, etc.) bottom-left of a tile -
   unlike .ig-grid-tile-overlay this isn't hover-gated, since a
   playlist/gallery card needs its count legible without hovering. */
.ig-grid-tile-badge {
  position: absolute; bottom: 6px; left: 6px; z-index: 2;
  background: rgba(10,10,14,0.65); color: #fff; font-size: 10px; font-weight: 600;
  padding: 3px 7px; border-radius: 999px; pointer-events: none;
}
/* Video-picker-specific tile bits: the name label (picker tiles need their
   filename legible without hovering, unlike a playlist/gallery card) and
   the "already added" confirmation stamp shown right after a click. */
.ig-grid-tile-name {
  position: absolute; left: 6px; right: 6px; bottom: 6px; z-index: 2;
  font-size: 10.5px; color: rgba(255,255,255,0.92); line-height: 1.3; pointer-events: none;
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  text-shadow: 0 1px 3px rgba(0,0,0,0.8);
}
.ig-grid-tile.added { pointer-events: none; }
.ig-grid-tile.added::after {
  content: "\2713 Added"; position: absolute; inset: 0; z-index: 4; background: rgba(34,184,176,0.88); color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600;
}

@media (max-width: 600px) {
  .ig-tabs { gap: 28px; }
  .ig-grid-tile-delete, .ig-grid-tile-manage { opacity: 1; } /* no hover on touch - always visible */
}

@media (max-width: 760px) {
  .community-channels-layout { grid-template-columns: 1fr; height: auto; max-height: none; }
  .community-channel-sidebar { flex-direction: row; flex-wrap: wrap; border-right: none; border-bottom: 1px solid var(--border-subtle); }
  .community-channel-messages { max-height: 50vh; }
}

/* ==================== Instagram-style sidebar nav (desktop) ====================
   Replaces the horizontal .topbar/.nav-links row on wide screens with a
   collapsed icon rail, wider by default only on :hover, revealing text
   labels beside each icon - same pattern as the ts-full-stack-instagram-
   clone reference repo's left nav (re-themed: dark surface, teal accent
   pill on the active item instead of Instagram's plain black/white).
   Only present on pages that include a <nav class="ig-sidebar">; other
   pages (gm-admin.html, watch.html, auth pages) are completely
   unaffected. Mobile (<=760px, matching the .mobile-tab-nav breakpoint)
   hides the sidebar entirely and falls back to the existing .topbar +
   bottom tab bar. */
body:has(.ig-sidebar) { padding-left: 76px; }
body:has(.ig-sidebar) .topbar { display: none; }

.ig-sidebar {
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 200;
  width: 76px; padding: 14px 8px;
  display: flex; flex-direction: column;
  background: var(--chrome-bg-strong); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  /* Soft inward vignette instead of a hard 1px border - the sidebar just
     fades toward its own right edge and disappears into the page
     background rather than announcing a seam. --edge-fade is black at low
     opacity in light theme (a strong black would just look like a bold
     gray stripe on white) and black at higher opacity in dark theme,
     where the page itself is already near-black. (An inset shadow stays
     inside the box regardless of overflow:hidden, unlike an outset one,
     which is why this reads clean at any width.) */
  box-shadow: inset -18px 0 22px -20px var(--edge-fade);
  overflow: hidden; transition: width .16s var(--ease);
}
.ig-sidebar:hover, .ig-sidebar:focus-within {
  width: 232px;
  box-shadow: inset -18px 0 22px -20px var(--edge-fade), 14px 0 34px var(--edge-fade);
}

.ig-sidebar-logo {
  display: flex; align-items: center; gap: 13px; padding: 10px; margin-bottom: 12px;
  text-decoration: none; color: var(--text); flex-shrink: 0;
}
.ig-sidebar-logo-mark { flex-shrink: 0; width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; }
.ig-sidebar-logo-mark svg { width: 26px; height: 20px; }
.ig-sidebar-logo-text {
  font-weight: 800; font-size: 17px; white-space: nowrap;
  opacity: 0; transform: translateX(-6px); transition: var(--transition);
}
.ig-sidebar:hover .ig-sidebar-logo-text, .ig-sidebar:focus-within .ig-sidebar-logo-text { opacity: 1; transform: translateX(0); }

.ig-sidebar-links { display: flex; flex-direction: column; gap: 2px; flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; }
.ig-sidebar-bottom { display: flex; flex-direction: column; gap: 2px; flex-shrink: 0; padding-top: 8px; margin-top: 8px; border-top: 1px solid var(--border-subtle); }

.ig-sidebar-item {
  display: flex; align-items: center; gap: 16px; padding: 12px 10px; border-radius: 999px;
  color: var(--text-dimmer); text-decoration: none; cursor: pointer;
  transition: var(--transition); white-space: nowrap; flex-shrink: 0;
}
.ig-sidebar-item:hover { background: var(--surf-3); color: var(--text); }
/* Soft glow tint instead of a flat filled block or a hard-edged ring - just
   a gentle radial-feeling wash + blurred glow with no crisp border, so the
   active state blends into the row rather than looking like a stamped-on
   pill. */
.ig-sidebar-item.active {
  background: radial-gradient(ellipse at 30% 50%, rgba(34,184,176,0.22) 0%, rgba(34,184,176,0.1) 70%, rgba(34,184,176,0.06) 100%);
  color: var(--teal-text); font-weight: 700;
  box-shadow: 0 0 14px rgba(34,184,176,0.12);
}
.ig-sidebar-item.active:hover { background: radial-gradient(ellipse at 30% 50%, rgba(34,184,176,0.3) 0%, rgba(34,184,176,0.14) 70%, rgba(34,184,176,0.08) 100%); }
.ig-sidebar-icon { flex-shrink: 0; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; }
.ig-sidebar-icon svg { width: 24px; height: 24px; }
.ig-sidebar-label {
  font-size: 14.5px; opacity: 0; transform: translateX(-6px); transition: var(--transition);
  display: flex; align-items: center;
}
.ig-sidebar:hover .ig-sidebar-label, .ig-sidebar:focus-within .ig-sidebar-label { opacity: 1; transform: translateX(0); }

/* The real profile picture (renderNavAvatar populates .nav-avatar-slot in
   place - see firebase-config.js) lives in its own icon slot, same as
   every other row's <svg> icon - NOT applied to the row (.ig-sidebar-item)
   itself, since that has its own padding which under border-box sizing
   would otherwise fight .nav-avatar's fixed width/height and squash the
   actual photo down to a sliver inside an oversized bordered box. Sized
   a little larger than the plain-icon items to read as "your photo"
   rather than another generic glyph. */
.ig-sidebar-item .nav-avatar-slot { flex-shrink: 0; width: 28px; height: 28px; }

/* ---- SameCouch avatar shape ----
   Every avatar site-wide (nav, chat, stories, community) uses this one
   soft "squircle" instead of the plain circle Instagram/Facebook/
   WhatsApp/basically everyone else uses for profile pictures - a small,
   consistent change that immediately reads as its own visual identity
   rather than a reskin. Sits after each class's own rule (same
   specificity, later wins) so it only ever touches border-radius. */
.nav-avatar, .chat-drawer-avatar, .chat-thread-avatar, .chat-list-row-avatar,
.chat-picker-friend-avatar, .chat-settings-avatar, .friend-avatar,
.story-avatar, .story-avatar-plus, .community-card-avatar, .community-header-avatar,
.hero-mockup-avatar {
  border-radius: 30%;
}

@media (max-width: 760px) {
  .ig-sidebar { display: none; }
  body:has(.ig-sidebar) { padding-left: 0; }
  body:has(.ig-sidebar) .topbar { display: flex; }
}
