* { box-sizing: border-box; }
[hidden] { display: none !important; }

/* ============ FIRST-LOGIN TUTORIAL OVERLAY ============ */
.tutorial-backdrop {
  position: fixed; inset: 0;
  background: rgba(5, 7, 16, 0.78);
  z-index: 9000;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  animation: tut-fade 220ms ease;
}
.tutorial-backdrop.dim {
  background: transparent;       /* spotlight does the dimming via box-shadow */
  backdrop-filter: none; -webkit-backdrop-filter: none;
  pointer-events: auto;          /* still captures clicks */
}
@keyframes tut-fade { from { opacity: 0; } to { opacity: 1; } }

.tutorial-modal {
  position: fixed; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: min(520px, 92vw);
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  padding: 28px 30px 22px;
  box-shadow: 0 30px 70px rgba(0,0,0,0.65);
  z-index: 9100;
  animation: tut-pop 240ms cubic-bezier(.32,.72,0,1);
}
@keyframes tut-pop {
  from { opacity: 0; transform: translate(-50%, -45%) scale(0.96); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
.tutorial-modal h2 {
  font-family: "Fraunces", Georgia, serif;
  font-style: italic; font-weight: 500;
  font-size: 32px; letter-spacing: -0.02em;
  margin: 0 0 10px;
  color: var(--text-primary);
}
.tutorial-modal p {
  color: var(--text-secondary);
  font-size: 14px; line-height: 1.55;
  margin: 0 0 14px;
}
.tutorial-bullets {
  margin: 0 0 14px; padding-left: 20px;
  color: var(--text-secondary);
}
.tutorial-bullets li { margin: 6px 0; font-size: 13.5px; line-height: 1.5; }

.tutorial-actions {
  display: flex; justify-content: flex-end; gap: 8px;
  margin-top: 14px;
}
.tutorial-actions button { padding: 8px 16px; font-size: 13px; }

.tutorial-progress {
  position: absolute; bottom: 10px; left: 14px;
  font-size: 11px; color: var(--text-muted);
  letter-spacing: 0.08em; text-transform: uppercase;
}

/* Spotlight cutout via FOUR blur panels arranged around the target.
   The four panels (top / bottom / left / right) collectively cover the
   entire viewport EXCEPT a rectangular hole over the target — the
   target stays 100% sharp + bright. mask-image was unreliable across
   browsers; this approach uses plain divs and works everywhere. */
.tutorial-blur-panel {
  position: fixed;
  z-index: 9050;
  pointer-events: auto;
  background: rgba(5, 7, 16, 0.55);
  backdrop-filter: blur(10px) brightness(0.55) saturate(110%);
  -webkit-backdrop-filter: blur(10px) brightness(0.55) saturate(110%);
  animation: tut-fade 240ms ease;
}

/* Glowing ring drawn JUST outside the cutout, so the spotlighted
   button reads as "this is alive — pay attention to me." Sits ABOVE
   the blur overlay (z-index +1) but doesn't catch clicks. */
.tutorial-spotlight-ring {
  position: fixed;
  z-index: 9060;
  pointer-events: none;
  border-radius: 14px;
  border: 1.5px solid rgba(232, 227, 212, 0.55);
  box-shadow:
    0 0 0 1px rgba(232, 227, 212, 0.12),
    0 0 24px 4px rgba(232, 227, 212, 0.22);
  animation: tut-ring-pulse 1.8s ease-in-out infinite;
  transition: all 280ms cubic-bezier(.32,.72,0,1);
}
@keyframes tut-ring-pulse {
  0%, 100% { box-shadow: 0 0 0 1px rgba(232,227,212,0.12), 0 0 24px 4px rgba(232,227,212,0.22); }
  50%      { box-shadow: 0 0 0 1px rgba(232,227,212,0.18), 0 0 32px 8px rgba(232,227,212,0.34); }
}

.tutorial-tooltip {
  position: fixed;
  z-index: 9110;
  width: min(360px, 92vw);
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: 10px;
  padding: 16px 18px 14px;
  box-shadow: 0 20px 50px rgba(0,0,0,0.65);
  animation: tut-pop-tip 240ms cubic-bezier(.32,.72,0,1);
}
@keyframes tut-pop-tip {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.tutorial-tooltip h3 {
  font-family: "Fraunces", Georgia, serif;
  font-style: italic; font-weight: 500;
  font-size: 18px; letter-spacing: -0.01em;
  margin: 0 0 6px;
  color: var(--text-primary);
}
.tutorial-tooltip p {
  color: var(--text-secondary);
  font-size: 13px; line-height: 1.5;
  margin: 0 0 12px;
}
.tutorial-tooltip .tutorial-actions { margin-top: 0; }
.tutorial-tooltip .tutorial-progress {
  position: relative; bottom: auto; left: auto;
  margin-top: 8px;
}

/* ============ PREMIUM INTERACTION DEFAULTS ============
   Browser defaults are the single biggest "this is a website" tell. The
   selection highlight ships browser-blue, focus is the OS-default outline,
   scrollbars are giant chrome grey. Three lines each replaces all of it
   with the cream-on-matte palette. */

::selection { background: rgba(245, 245, 247, 0.20); color: var(--text-primary); }
::-moz-selection { background: rgba(245, 245, 247, 0.20); color: var(--text-primary); }
body[data-theme="light"] ::selection { background: rgba(10, 10, 12, 0.14); color: var(--bg-base); }

/* Focus ring — a hairline cream outline, only on keyboard focus (not on
   click, so the cursor doesn't smash a glow into every button press). */
:focus { outline: none; }
:focus-visible {
  outline: 1.5px solid rgba(245, 245, 247, 0.55);
  outline-offset: 2px;
  border-radius: 4px;
}
body[data-theme="light"] :focus-visible {
  outline-color: rgba(10, 10, 12, 0.55);
}

/* Thin, restrained scrollbars. WebKit only (Firefox uses scrollbar-color
   declared on html below). 4px wide, cream at low opacity, no buttons. */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(245, 245, 247, 0.10);
  border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover { background: rgba(245, 245, 247, 0.20); }
::-webkit-scrollbar-corner { background: transparent; }
html {
  scrollbar-width: thin;
  scrollbar-color: rgba(245, 245, 247, 0.10) transparent;
}
body[data-theme="light"] ::-webkit-scrollbar-thumb { background: rgba(10, 10, 12, 0.14); }
body[data-theme="light"] ::-webkit-scrollbar-thumb:hover { background: rgba(10, 10, 12, 0.26); }
body[data-theme="light"] html { scrollbar-color: rgba(10, 10, 12, 0.14) transparent; }

/* =========================================================
   THEME — semantic colour tokens.
   Default values are the existing dark theme. body[data-theme="light"]
   redefines them for light mode. We don't refactor the hardcoded hexes
   throughout the rest of the stylesheet (would touch hundreds of lines);
   instead the section at the BOTTOM of this file targets the highest-
   impact selectors with light overrides, which is enough to flip the
   look without missing edge cases.
========================================================= */
:root {
  /* "Editorial Black" palette — pure charcoal page bed, white off-cream
     text, ONE saturated red accent used sparingly (active rail, one CTA,
     hero outlines). The whole composition is grayscale + a single
     surgical red moment. Fashion-magazine / Hermes look. */
  --pal-charcoal:   #0a0a0b;   /* page bed — near pure black */
  --pal-charcoal-2: #121214;   /* surface */
  --pal-charcoal-3: #1c1c20;   /* card surface — slightly raised */
  --pal-charcoal-4: #26262c;   /* hover state */
  --pal-paper:      #ededed;   /* primary text — almost white */
  --pal-paper-2:    #b4b4b8;   /* secondary text */
  --pal-paper-wash: #6e6e74;   /* muted */
  /* Deep burgundy — wine-cellar / Penguin Classics / Hermès packaging.
     Dark + muted, never reads as "gym red." Cream text remains legible
     against it; burgundy reads distinct from both cream and charcoal. */
  --pal-burgundy:      #7a2e2e;
  --pal-burgundy-deep: #5c2222;
  /* Every historical alias resolves to burgundy — old class rules + inline
     hex references all migrate to the new accent without further changes. */
  --pal-matcha:     var(--pal-burgundy);
  --pal-matcha-deep:var(--pal-burgundy-deep);
  --pal-bone:       var(--pal-burgundy);
  --pal-bone-deep:  var(--pal-burgundy-deep);
  --pal-camel:      var(--pal-burgundy);
  --pal-camel-deep: var(--pal-burgundy-deep);
  --pal-red:        var(--pal-burgundy);
  --pal-red-deep:   var(--pal-burgundy-deep);

  --bg-base:       var(--pal-charcoal);
  --bg-surface:    var(--pal-charcoal-2);
  --bg-elevated:   var(--pal-charcoal-3);
  --bg-hover:      var(--pal-charcoal-4);
  --bg-active:     var(--pal-charcoal-4);
  /* Dedicated chat surface — flat near-black à la Character.AI. Slightly
     darker than --bg-elevated so the chat panel reads as a calm reading
     ground, not a raised card. Light theme overrides to pure white below. */
  --bg-chat:       #161618;
  --text-primary:  var(--pal-paper);
  --text-secondary:var(--pal-paper-2);
  --text-muted:    var(--pal-paper-wash);
  --text-faint:    rgba(237, 237, 237, 0.32);
  /* Hairline borders are white-at-low-opacity — pure grayscale chrome. */
  --border-default:rgba(255, 255, 255, 0.08);
  --border-subtle: rgba(255, 255, 255, 0.04);
  /* The single saturated colour in the whole product. Use only on:
     - primary CTAs
     - the active sidebar rail
     - hero outline accents
     Anywhere else: stay grayscale. */
  --accent:        var(--pal-red);
  --accent-ink:    var(--pal-paper);
  --accent-cool:   var(--pal-red);
}

/* Non-admin users see the same character-creation tools as admins. The only
   admin-only UI bit is the bulk "Scan avatars" button (it triggers OpenAI
   vision calls in a loop and would burn through the server's quota). */
body.non-admin #btn-scan-nsfw {
  display: none !important;
}

/* Character Creator agent is a Home-only tool — hide it when the user is
   inside a chat / call / settings / workshop view. */
body.not-on-home #agent-dock {
  display: none !important;
}

/* Like button on character cards — high-contrast heart pill. Soft pink
   bg even when not liked so it's clearly a button; saturates pink when
   liked. Sits prominently in the stats row. */
.char-card-like-btn {
  display: inline-flex !important;
  align-items: center;
  gap: 5px;
  background: rgba(236, 72, 153, 0.12) !important;
  border: 1.5px solid rgba(236, 72, 153, 0.45) !important;
  color: #f9a8d4 !important;
  padding: 4px 12px !important;
  font-size: 13px !important;
  font-weight: 600;
  cursor: pointer;
  border-radius: 999px !important;
  transition: background .12s, border-color .12s, color .12s, transform .08s;
}
.char-card-like-btn:hover {
  background: rgba(236, 72, 153, 0.25) !important;
  border-color: #ec4899 !important;
  color: #fff !important;
  transform: scale(1.04);
}
.char-card-like-btn:active { transform: scale(0.97); }
.char-card-like-btn.liked {
  background: linear-gradient(135deg, #db2777 0%, #ec4899 100%) !important;
  border-color: #ec4899 !important;
  color: #fff !important;
}
.char-card-like-btn:disabled { opacity: 0.6; cursor: wait; }

/* ============ GALLERY HERO CARD ============ */
/* Compact "continue chatting" card. Avatar lives in its own circular
   image so the character's face is always fully visible (banner crop
   was unflattering). Background is a blurred copy of the same avatar. */
.gallery-hero {
  position: relative;
  border-radius: 12px;
  overflow: hidden;
  margin: 0 0 18px 0;
  isolation: isolate;
  cursor: pointer;
  border: 1px solid var(--border-default);
  transition: transform .15s, box-shadow .15s;
}
.gallery-hero:hover {
  transform: translateY(-1px);
  box-shadow: 0 10px 28px rgba(0,0,0,0.35);
}
.gallery-hero-bg {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  z-index: 0;
  filter: blur(28px) saturate(1.1);
  transform: scale(1.15);   /* hides the blur edge */
  opacity: 0.55;
}
.gallery-hero-content {
  position: relative; z-index: 1;
  display: flex; align-items: center; gap: 22px;
  padding: 22px 28px;
  background: linear-gradient(135deg, rgba(8,9,12,0.6) 0%, rgba(8,9,12,0.85) 100%);
  color: #fff;
}
.gallery-hero-avatar {
  width: 96px; height: 96px;
  border-radius: 50%;
  /* Match sidebar avatars: cover + default center crop, plain background
     for transparency. Was using "center top" which clipped foreheads. */
  object-fit: cover;
  background: #232733;
  border: 3px solid rgba(255,255,255,0.15);
  box-shadow: 0 6px 20px rgba(0,0,0,0.4);
  flex-shrink: 0;
}
.gallery-hero-text {
  display: flex; flex-direction: column; justify-content: center;
  min-width: 0;
}
.gallery-hero-eyebrow {
  font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
  color: #a5b4fc; opacity: 0.95; margin-bottom: 4px;
  text-transform: uppercase;
}
.gallery-hero-name {
  font-size: 22px; font-weight: 700; line-height: 1.15;
  text-shadow: 0 2px 8px rgba(0,0,0,0.4);
}
.gallery-hero-tagline {
  font-size: 13px; color: rgba(255,255,255,0.85);
  margin-top: 4px;
  text-shadow: 0 1px 4px rgba(0,0,0,0.35);
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.gallery-hero-meta {
  display: flex; gap: 10px; align-items: center;
  font-size: 11px; color: rgba(255,255,255,0.65);
  margin-top: 6px;
}
.gallery-hero-actions { margin-top: 12px; }
.gallery-hero-actions button {
  font-size: 13px; padding: 7px 16px; border-radius: 8px;
}
/* Mobile: stack the avatar above the text */
@media (max-width: 600px) {
  .gallery-hero-content { flex-direction: column; align-items: flex-start; gap: 14px; padding: 18px 20px; }
  .gallery-hero-avatar { width: 80px; height: 80px; }
}

/* ============ SCROLLBARS ============ */
/* Firefox */
* {
  scrollbar-width: thin;
  scrollbar-color: #2a2a2a transparent;
}
/* Chromium / Safari / Edge */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: #2a2a2a;
  border-radius: 8px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover {
  background: #3d4a6b;
  background-clip: padding-box;
  border: 2px solid transparent;
}
::-webkit-scrollbar-thumb:active { background: #ededed; background-clip: padding-box; border: 2px solid transparent; }
::-webkit-scrollbar-corner { background: transparent; }
/* Slightly thinner inside compact scroll panes (chat, popovers, sidebars) */
.chat-messages::-webkit-scrollbar,
.agent-messages::-webkit-scrollbar,
.sidebar-character-list::-webkit-scrollbar,
.menu-list::-webkit-scrollbar,
.character-sidebar-list::-webkit-scrollbar,
.events::-webkit-scrollbar,
.transcript::-webkit-scrollbar,
.tag-library-groups::-webkit-scrollbar,
.filter-popover-body::-webkit-scrollbar,
.modal-card::-webkit-scrollbar,
.agent-history-list::-webkit-scrollbar { width: 6px; height: 6px; }
html, body {
  margin: 0; padding: 0; min-height: 100%;
  /* Kill horizontal overflow so the whole page can't be slid sideways
     on touch devices. Any element that ends up wider than the viewport
     should scroll inside its own container, not the document. */
  overflow-x: hidden; max-width: 100%;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: none;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-feature-settings: "cv02", "cv03", "cv04", "cv11";  /* Inter's calibrated alts: rounder I/J, friendlier 1, etc. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: -0.005em;  /* slight tightening — matches Linear/Vercel feel */
  color: var(--text-primary);
  line-height: 1.5;
}

/* ============ INK SPECKLE OVERLAY ============
   Visible film-grain across the whole page. The colour matrix tints the
   noise toward a bright cobalt so it reads as ink-particles on midnight
   when set to screen-blend over the dark canvas. */
/* ============ WOVEN LINEN TEXTURE ============
   Real linen looks like crossing threads — horizontal weft + vertical
   warp. The body keeps its solid base colour; the linen weave is added
   via a SINGLE pseudo-element (z-index -1, so it's behind ALL content
   including avatars). One stack, one layer, one place — won't break. */

/* Linen texture on the BODY (not html) with scroll-attached so the
   pattern tiles with the entire page height — not just the viewport.
   The previous fixed-attachment on html only painted the initial
   viewport region, leaving the scrolled-down part of the page bare
   below the fold. Scroll-attached + body = continuous linen across
   every pixel of the content height. */
/* Texture lives on html so it's always visible — body content sits on top.
   Fixed-attachment background means the texture is anchored to the viewport
   (not re-tiled by page height changes) — typing in a search box that
   filters the grid no longer causes the SVG noise to re-roll its seed. */
html {
  background-color: var(--bg-base);
  background-image:
    repeating-linear-gradient(0deg,
      rgba(255,255,255,0.04) 0px, rgba(255,255,255,0.04) 1px,
      transparent 1px, transparent 3px),
    repeating-linear-gradient(90deg,
      rgba(255,255,255,0.04) 0px, rgba(255,255,255,0.04) 1px,
      transparent 1px, transparent 3px),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.2' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.9  0 0 0 0 0.87  0 0 0 0 0.78  0 0 0 0.10 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-repeat: repeat, repeat, repeat;
  background-attachment: fixed, fixed, fixed;
}
body {
  background: transparent;
  min-height: 100vh;
}

/* Raised surfaces (modals, cards, sections) use a SOLID elevated charcoal
   with the SAME linen-weave + noise pattern as the body. They look like
   the same continuous fabric — just very slightly raised. No transparency
   (avoids compounding alpha that dims the texture), no backdrop-blur
   (blur destroys 1px linen stripes). */
.character-card,
.modal-card,
.umf-section,
.feed-item {
  position: relative;
  background-color: var(--bg-elevated);
  background-image:
    repeating-linear-gradient(0deg,
      rgba(255,255,255,0.04) 0px, rgba(255,255,255,0.04) 1px,
      transparent 1px, transparent 3px),
    repeating-linear-gradient(90deg,
      rgba(255,255,255,0.04) 0px, rgba(255,255,255,0.04) 1px,
      transparent 1px, transparent 3px),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.2' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.9  0 0 0 0 0.87  0 0 0 0 0.78  0 0 0 0.10 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-repeat: repeat, repeat, repeat;
}
/* Editorial heading hierarchy — Fraunces displayed BIG. Magazine-cover
   typography. Hero H1 is now dramatic; everything else stays small +
   restrained so the heroes do the work. */
h1, h2 {
  font-family: "Fraunces", Georgia, "Times New Roman", serif;
  font-variation-settings: "opsz" 144, "SOFT" 50;
  letter-spacing: -0.03em; line-height: 1.02;
  font-weight: 400;   /* Fraunces 400 at display opsz is already weighty */
}
h3, h4 { font-weight: 600; letter-spacing: -0.005em; line-height: 1.25; }
h1 { font-size: 64px; }
h2 { font-size: 28px; }
h3 { font-size: 14px; text-transform: uppercase; letter-spacing: 0.08em; }
button, input, select, textarea { font-family: inherit; letter-spacing: inherit; }

/* ============ GLOBAL MOTION ============
   Apple's "spring out" easing — fast acceleration, soft settle. 280ms is
   the sweet spot where interactions feel weighted but not laggy. Faster
   than this reads as twitchy; slower than this reads as broken. */
button, a, .character-card, .feed-item, .sidebar-link, .umf-link,
.profile-stat-tile, .chat-bubble-action, .mode {
  transition:
    background-color 280ms cubic-bezier(0.32, 0.72, 0, 1),
    border-color     280ms cubic-bezier(0.32, 0.72, 0, 1),
    color            280ms cubic-bezier(0.32, 0.72, 0, 1),
    transform        280ms cubic-bezier(0.32, 0.72, 0, 1),
    box-shadow       280ms cubic-bezier(0.32, 0.72, 0, 1),
    opacity          280ms cubic-bezier(0.32, 0.72, 0, 1);
}

/* ============ TYPOGRAPHY HEROES (Apple-luxury scale) ============
   Apple-luxury is small text at rest, dramatic at hero moments. We bump
   page-level h1s and add a micro-caps section label utility. Tabular
   numerals so stat tiles align vertically the way SF Pro Display does. */
h1 { font-size: 44px; letter-spacing: -0.028em; line-height: 1.1; font-weight: 700; }
h2 { font-size: 22px; letter-spacing: -0.018em; line-height: 1.25; font-weight: 700; }
h3 { font-size: 15px; letter-spacing: -0.005em; line-height: 1.3; font-weight: 600; }
.micro-label {
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-muted);
}
.tabular { font-variant-numeric: tabular-nums; }
.profile-stat-num,
.feed-item-when,
.story-cast-chip,
.umf-count { font-variant-numeric: tabular-nums; }

/* ============ STIPPLED SHADOW RINGS ============
   Replaces / supplements the smooth box-shadow with a dotted halftone
   shadow that fades out radially. Made with a repeating radial-gradient
   masked by a soft ellipse. The dots look hand-stippled — Apple Vision
   Pro / luxury-print aesthetic.

   Cards / modals get a pseudo-element behind them carrying the stipple.
   We keep the soft drop-shadow too because the dots alone don't read as
   depth — the combo is what sells it. */
.character-card,
.feed-item,
.umf-section,
.modal-card {
  position: relative;
  /* Deep ink-tinted drop shadow on midnight. */
  box-shadow:
    0 1px 2px rgba(0,0,0,0.4),
    0 14px 36px -16px rgba(0,0,0,0.65);
}
/* Flyout keeps its own position: fixed from line ~4066. The id-selector
   above was setting position:relative which overrode the fixed rule. */
#user-menu-flyout {
  box-shadow:
    0 1px 2px rgba(0,0,0,0.4),
    0 14px 36px -16px rgba(0,0,0,0.65);
}
/* Cobalt speckle-dot shadow ring — bright cobalt dots dispersing outward
   from the card below, so the card reads as "ink resting on midnight"
   instead of "shape with shadow". The dots show against the dark canvas. */
.character-card::after,
.feed-item::after,
.modal-card::after {
  content: '';
  position: absolute;
  inset: -18px -14px -28px -14px;
  z-index: -1;
  pointer-events: none;
  /* Quiet cream-on-night specks — much less saturated than the cobalt
     version. Still reads as "dots making the shadow" but stops fighting
     the eye for attention. */
  background-image: radial-gradient(circle, rgba(232, 227, 212, 0.22) 0.9px, transparent 1.4px);
  background-size: 4px 4px;
  -webkit-mask-image: radial-gradient(ellipse 78% 65% at 50% 95%, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0) 72%);
          mask-image: radial-gradient(ellipse 78% 65% at 50% 95%, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0) 72%);
  opacity: 0.55;
  border-radius: inherit;
}

/* Subtle press-state on every clickable button (Apple/Linear cue). */
button:active:not(:disabled),
.character-card:active,
.feed-item:active { transform: translateY(1px) scale(0.998); }

/* View-switch fade. JS sets data-view to the current view; pinning the
   :not selector to .main view containers lets us fade them without
   touching the JS controller. */
.gallery, .chat-layout, .feed-layout, .profile-layout,
.workshop-layout, .story-layout, #view-bcall, #view-admin {
  animation: aic-fade-in 220ms cubic-bezier(.2,.8,.2,1);
}
@keyframes aic-fade-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ============ SOFT ELEVATION ============
   Replace flat 1px borders with hair borders + soft shadows on key surfaces.
   The shadow is a 2-stop "near + far" pattern — looks like ambient light
   instead of a hard outline. Premium apps default to this. */
.character-card,
.feed-item,
.umf-section,
.modal-card {
  box-shadow:
    0 1px 0 rgba(255,255,255,0.02) inset,
    0 1px 3px rgba(0,0,0,0.20),
    0 8px 24px -8px rgba(0,0,0,0.35);
}

/* Glassmorphic topbar — subtle blur + translucency for that ChatGPT/Apple
   "floating chrome" effect. Falls back to a flat fill on browsers without
   backdrop-filter (older Firefox). */
.topbar {
  backdrop-filter: blur(14px) saturate(120%);
  -webkit-backdrop-filter: blur(14px) saturate(120%);
  background-color: rgba(10, 10, 11, 0.78);
  border-bottom-color: rgba(255,255,255,0.06);
}
body[data-theme="light"] .topbar {
  background-color: rgba(255, 255, 255, 0.72);
  border-bottom-color: rgba(0,0,0,0.06);
}
/* ============ APP SIDEBAR ============ */
.app-sidebar {
  position: fixed; left: 0; top: 0;
  width: 220px; height: 100vh;
  background: var(--bg-base); border-right: 1px solid var(--border-subtle);
  display: flex; flex-direction: column;
  padding: 14px 10px;
  transition: width 0.18s ease;
  z-index: 50;
}
.app-sidebar.collapsed { width: 56px; }
.app-sidebar.collapsed .sidebar-brand-name,
.app-sidebar.collapsed .sidebar-link span:not(.sidebar-icon) { display: none; }
.app-sidebar.collapsed .sidebar-link { justify-content: center; }
.sidebar-brand {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 10px 14px;
  border-bottom: 1px solid var(--border-subtle);
  margin-bottom: 10px;
  /* button reset — sidebar-brand is now a <button> for "click → Home" */
  background: transparent;
  border-left: none; border-right: none; border-top: none;
  color: inherit;
  font: inherit;
  width: 100%;
  text-align: left;
  cursor: pointer;
  transition: background .12s;
}
.sidebar-brand:hover {
  background: var(--bg-elevated);
}
.sidebar-brand-mark {
  font-size: 22px; color: #ededed;
  flex-shrink: 0;
}
.sidebar-brand-name { font-weight: 700; font-size: 14px; }
.sidebar-nav { display: flex; flex-direction: column; gap: 2px; }
.sidebar-nav-section {
  margin: 14px 12px 4px;
  font-size: 10.5px; font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.10em;
  opacity: 0.7;
}
.app-sidebar.collapsed .sidebar-nav-section { display: none; }
.sidebar-link { position: relative; }
.sidebar-link-badge {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  background: var(--pal-burgundy, #7a2e2e); color: #fff;
  border-radius: 999px; padding: 1px 6px;
  font-size: 10px; font-weight: 700; line-height: 1.4;
  min-width: 18px; text-align: center;
}
.sidebar-link {
  display: flex; align-items: center; gap: 12px;
  background: transparent; border: none; color: var(--text-muted);
  padding: 9px 10px; border-radius: 8px;
  font-size: 13px; font-weight: 500; cursor: pointer; text-align: left;
  position: relative;
}
.sidebar-link:hover { background: rgba(255,255,255,0.05); color: var(--text-primary); }
.sidebar-link.active {
  background: rgba(255,255,255,0.06);
  color: var(--text-primary);
  font-weight: 600;
}
/* The single editorial-red moment in the sidebar — slim rail on the
   left edge of the active link. Restraint: just this one place. */
.sidebar-link.active::before {
  content: '';
  position: absolute;
  left: -1px; top: 50%; transform: translateY(-50%);
  width: 2px; height: 14px; border-radius: 4px;
  background: var(--pal-red);
}

/* Line-icons. Monochrome, currentColor — inherits the muted link state. */
.sidebar-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; flex-shrink: 0;
  color: inherit;
}
.sidebar-icon svg { width: 17px; height: 17px; display: block; }
.sidebar-link.active .sidebar-icon { color: var(--text-primary); }

/* Brand mark — flat, monochrome. The gradient pill is the AI-startup
   giveaway; a flat letterform in soft cream reads as luxury serif on
   matte black. Vibes: Hermes, Aesop, Apollo. */
.sidebar-brand {
  font-family: "Fraunces", Georgia, serif;
  font-variation-settings: "opsz" 144;
  font-weight: 500;
  letter-spacing: -0.02em;
  padding: 14px 10px 18px;
}
.sidebar-brand-name {
  font-size: 19px;
}
.sidebar-brand-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 8px;
  background: transparent;
  color: var(--text-primary);
  border: 1px solid rgba(255,255,255,0.18);
  position: relative;
}
.sidebar-brand-mark svg { width: 16px; height: 16px; }
/* Editorial-red ledger underline below the brand mark — single
   surgical red moment, like the red box in the poster. */
.sidebar-brand-mark::after {
  content: '';
  position: absolute;
  left: 4px; right: 4px; bottom: -3px;
  height: 1.5px;
  background: var(--pal-red);
}

/* User-menu flyout link icons — same treatment, slightly smaller. */
.umf-link-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; flex-shrink: 0;
  color: inherit;
  margin-right: 10px;
}
.umf-link-icon svg { width: 16px; height: 16px; display: block; }
.umf-link { display: inline-flex; align-items: center; }
.umf-link.primary .umf-link-icon { color: #fff; }
.sidebar-icon { font-size: 16px; flex-shrink: 0; width: 20px; text-align: center; }
.sidebar-spacer { flex: 1; }
.sidebar-footer { border-top: 1px solid var(--border-subtle); padding-top: 8px; }

/* Characters section inside the main app sidebar */
.sidebar-section-header {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted);
  padding: 14px 12px 6px;
  border-top: 1px solid var(--border-subtle); margin-top: 10px;
}
.app-sidebar.collapsed .sidebar-section-header,
.app-sidebar.collapsed .sidebar-character-list,
.app-sidebar.collapsed .sidebar-legal-links { display: none; }
.sidebar-mini-btn {
  background: var(--bg-active); border: 1px solid #2a2a2a; color: var(--text-primary);
  border-radius: 4px; padding: 0 7px; font-size: 13px; cursor: pointer;
  line-height: 1.6;
}
.sidebar-mini-btn:hover { background: #2a2a2a; border-color: #ededed; }

.sidebar-character-list {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: 2px 6px 8px; display: flex; flex-direction: column; gap: 2px;
}
.sidebar-character-item {
  display: flex; align-items: center; gap: 9px;
  padding: 6px 8px; border-radius: 8px; cursor: pointer;
  border: 1px solid transparent;
}
.sidebar-character-item:hover { background: var(--bg-elevated); }
.sidebar-character-item.active { background: var(--bg-active); border-color: #2a2a2a; }
.sidebar-character-avatar {
  width: 28px; height: 28px; border-radius: 50%;
  object-fit: cover; background: #232733; border: 1px solid var(--border-default);
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; color: var(--text-muted);
}
.sidebar-character-name {
  font-size: 12.5px; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 1; min-width: 0;
}
.sidebar-character-empty {
  padding: 8px 12px; font-size: 11px; color: #555;
  font-style: italic; line-height: 1.4;
}

.app-shell-main {
  margin-left: 220px;     /* offset for the fixed sidebar */
  display: flex; flex-direction: column;
  min-height: 100vh;
  transition: margin-left 0.18s ease;
}
.app-sidebar.collapsed ~ .app-shell-main { margin-left: 56px; }
/* Sibling-selector trick above won't fire because they're not direct siblings;
   we set the margin via a body class below as a backup */
body.sidebar-collapsed .app-shell-main { margin-left: 56px; }
.topbar {
  display: flex; justify-content: space-between; align-items: center;
  padding: 10px 20px;
  /* Phase 4 C5 — PWA / iOS notch polish. When the page is launched as a
     standalone PWA (Add-to-Home), env(safe-area-inset-top) reports the
     notch height. Pad the top of the bar so the brand isn't hidden. */
  padding-top: calc(10px + env(safe-area-inset-top, 0px));
  background: var(--bg-elevated); border-bottom: 1px solid var(--border-default);
  position: sticky; top: 0; z-index: 5;
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 600; }
.tabs { display: flex; gap: 4px; }
.tab {
  background: transparent; border: 1px solid transparent; color: var(--text-muted);
  padding: 6px 14px; border-radius: 8px; cursor: pointer; font-size: 13px;
}
.tab:hover { background: var(--bg-hover); color: var(--text-primary); }
.tab.active { background: var(--bg-active); color: var(--text-primary); border-color: #2a2a2a; }
.dot { width: 10px; height: 10px; border-radius: 50%; background: #555; box-shadow: 0 0 6px transparent; }
.dot.running { background: #2dd47d; box-shadow: 0 0 8px #2dd47d80; }
.dot.paused  { background: #f5b042; box-shadow: 0 0 8px #f5b04280; }
.dot.stopped { background: #555; }
.status-text { color: #888; font-weight: 400; font-size: 13px; }
.controls button { margin-left: 6px; }

/* Default ghost — white-hairline on charcoal. Pure grayscale. */
button {
  background: rgba(255,255,255,0.04);
  color: var(--text-primary);
  border: 1px solid rgba(255,255,255,0.12);
  padding: 7px 13px; border-radius: 8px; cursor: pointer; font-size: 13px;
  font-weight: 500;
}
button:hover { background: rgba(255,255,255,0.08); border-color: rgba(255,255,255,0.22); }
/* Primary CTA — the ONE place red appears as a full fill. Single
   editorial moment, the way the red rectangle pops in the poster. */
button.primary {
  background: var(--pal-red); color: var(--pal-paper);
  border-color: var(--pal-red);
  font-weight: 600;
}
button.primary:hover { background: var(--pal-red-deep); border-color: var(--pal-red-deep); }
button.danger { background: #2a1010; border-color: rgba(255, 90, 90, 0.45); color: #ff9090; }
button.danger:hover { background: #381515; }
button.ghost.danger-text { color: #ff9090; }
button.ghost.danger-text:hover { color: #ffb5b5; }
button:disabled,
button.primary:disabled {
  background: var(--border-default); color: var(--text-faint); border-color: var(--border-default);
  cursor: not-allowed; opacity: 0.7;
}

.layout {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
  padding: 16px; max-width: 1600px; margin: 0 auto;
}
.panel {
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 8px;
  padding: 16px; min-height: 70vh;
}
.right-panel { display: flex; flex-direction: column; }

h2 {
  margin: 16px 0 8px 0; font-size: 13px; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--text-muted); border-bottom: 1px solid var(--border-default);
  padding-bottom: 6px;
}
h2:first-child { margin-top: 0; }

.row {
  display: flex; align-items: center; gap: 8px; margin: 6px 0; flex-wrap: wrap;
}
.row.col { flex-direction: column; align-items: stretch; }
.row.right { justify-content: flex-end; }
.row label {
  font-size: 12px; color: var(--text-muted); min-width: 110px;
}
.row.col label { min-width: 0; margin-bottom: 4px; }

/* Inputs sit on the textured surface above them. Same texture pattern
   inside the input as outside, so the field reads as a recessed window
   into the surface — not a solid box pasted on top of it. */
input, select, textarea {
  background-color: transparent;
  background-image:
    repeating-linear-gradient(0deg,
      rgba(255,255,255,0.025) 0px, rgba(255,255,255,0.025) 1px,
      transparent 1px, transparent 3px),
    repeating-linear-gradient(90deg,
      rgba(255,255,255,0.025) 0px, rgba(255,255,255,0.025) 1px,
      transparent 1px, transparent 3px);
  color: var(--text-primary);
  border: 1px solid var(--border-default);
  border-radius: 8px; padding: 6px 8px; font-size: 13px; flex: 1;
  min-width: 80px; font-family: inherit;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.18);    /* subtle inset so it reads as a recessed field */
}
input[type="number"] { min-width: 90px; max-width: 140px; }
textarea { resize: vertical; min-height: 100px; font-family: ui-monospace, Menlo, Consolas, monospace; }
input:focus, select:focus, textarea:focus { outline: none; border-color: #ededed; }

.transcript {
  flex: 1; min-height: 250px; max-height: 50vh; overflow-y: auto;
  background: rgba(0,0,0,0.18); border: 1px solid var(--border-default); border-radius: 8px;
  padding: 10px; font-size: 13px; line-height: 1.5;
}
.msg { margin: 6px 0; padding: 6px 10px; border-radius: 8px;
  position: relative; padding-right: 32px; }
.msg.user      { background: var(--bg-active); }
.msg.assistant { background: #1a2418; }
.msg.system    { background: #2a2218; border-left: 3px solid #f5b042; }
.msg .who { font-weight: 600; font-size: 11px; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 2px; letter-spacing: 0.05em; }
.msg .del-btn {
  position: absolute; top: 4px; right: 4px;
  background: transparent; border: none; color: #555; cursor: pointer;
  font-size: 14px; padding: 2px 6px; border-radius: 4px; opacity: 0;
  transition: opacity .15s, color .15s, background .15s;
}
.msg:hover .del-btn { opacity: 1; }
.msg .del-btn:hover { color: #ff6c6c; background: #2a1818; }

.memory-stats {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--text-muted); margin-bottom: 6px;
}
.memory-stats .muted { color: #555; }
button.ghost {
  background: transparent; border: none; color: var(--text-muted);
  padding: 2px 6px; font-size: 14px; margin-left: auto;
}
button.ghost:hover { color: var(--text-primary); background: var(--bg-hover); }

.events {
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11px;
  background: var(--bg-base); border: 1px solid var(--border-default); border-radius: 8px;
  padding: 8px; max-height: 25vh; overflow-y: auto; color: #888; margin-top: 8px;
}
.events div { padding: 1px 0; }
.events .err { color: #ff6c6c; }

/* ---- big live state banner ---- */
.state-banner {
  display: flex; align-items: center; gap: 14px;
  padding: 14px 16px; margin-bottom: 14px;
  background: var(--border-subtle); border: 1px solid var(--border-default); border-radius: 8px;
  transition: background .25s, border-color .25s;
}
.state-pulse {
  width: 16px; height: 16px; border-radius: 50%;
  background: #555; flex-shrink: 0;
  box-shadow: 0 0 0 0 transparent;
}
.state-text { display: flex; flex-direction: column; }
.state-label { font-size: 16px; font-weight: 600; letter-spacing: .02em; }
.state-sub   { font-size: 12px; color: var(--text-muted); margin-top: 2px; }

/* per-state colors + animation */
.state-banner.idle        { border-color: var(--border-default); }
.state-banner.idle        .state-pulse { background: #555; }
.state-banner.loading     { border-color: #ededed; background: #1a2032; }
.state-banner.loading     .state-pulse { background: #ededed; animation: pulse 1.2s ease-in-out infinite; }
.state-banner.listening   { border-color: #2dd47d; background: #18241e; }
.state-banner.listening   .state-pulse { background: #2dd47d; animation: pulse 1.5s ease-in-out infinite; }
.state-banner.hearing     { border-color: #2dd47d; background: #1a2c20; }
.state-banner.hearing     .state-pulse { background: #2dd47d; animation: pulse 0.6s ease-in-out infinite; }
.state-banner.transcribing{ border-color: #f5b042; background: #2a2218; }
.state-banner.transcribing.state-pulse,
.state-banner.transcribing .state-pulse { background: #f5b042; animation: pulse 0.8s ease-in-out infinite; }
.state-banner.thinking    { border-color: #b561ff; background: #221a2c; }
.state-banner.thinking    .state-pulse { background: #b561ff; animation: pulse 0.8s ease-in-out infinite; }
.state-banner.speaking    { border-color: #4fa6ff; background: #182230; }
.state-banner.speaking    .state-pulse { background: #4fa6ff; animation: pulse 0.5s ease-in-out infinite; }
.state-banner.paused      { border-color: #f5b042; background: #2a221a; }
.state-banner.paused      .state-pulse { background: #f5b042; }
.state-banner.error       { border-color: #c0392b; background: #2a1818; }
.state-banner.error       .state-pulse { background: #ff6c6c; animation: pulse 0.4s ease-in-out infinite; }

@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 currentColor; opacity: 1; }
  70%  { box-shadow: 0 0 0 10px transparent; opacity: 0.7; }
  100% { box-shadow: 0 0 0 0 transparent; opacity: 1; }
}

.workshop-layout {
  display: flex; flex-direction: column; height: calc(100vh - 56px);
  padding: 12px; gap: 10px;
}
.workshop-bar {
  display: flex; align-items: center; gap: 16px;
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 8px;
  padding: 10px 14px;
}
.workshop-info { display: flex; flex-direction: column; gap: 2px; }
.workshop-info .muted { color: var(--text-muted); font-size: 12px; }
.workshop-status { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.workshop-status a { color: #ededed; font-size: 13px; text-decoration: none; }
.workshop-status a:hover { text-decoration: underline; }
.workshop-frame {
  flex: 1; width: 100%; border: 1px solid var(--border-default); border-radius: 8px;
  background: white;
}
.workshop-empty {
  flex: 1; padding: 30px; background: var(--bg-elevated); border: 1px solid var(--border-default);
  border-radius: 8px; color: var(--text-muted); line-height: 1.6;
}
.workshop-empty code {
  background: var(--bg-base); padding: 2px 6px; border-radius: 4px;
  border: 1px solid var(--border-default); font-size: 12px;
}

/* ============ MUTED + BACK BTN ============ */
.muted { color: var(--text-muted); font-size: 12px; }
.back-btn { font-size: 18px; line-height: 1; padding: 4px 8px; }

/* ============ GALLERY ============ */
.gallery {
  /* Fill the full main area instead of capping at 1600 + auto-margin centering.
     The old setup left big symmetric gutters on wide CSS viewports, making the
     page look "small" — especially when the grid was empty (Favorites tab). */
  width: 100%; padding: 24px 28px;
}
/* Simpler 2-row flex layout (no display:contents which broke grid in some browsers) */
.gallery-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 8px 16px;
  margin-bottom: 16px;
}
.gallery-header > div:first-child {
  flex: 1; min-width: 200px;
  display: flex; flex-direction: column; gap: 4px;
}
.gallery-header > div:last-child {
  display: flex; gap: 8px; flex-shrink: 0;
}
.gallery-toolbar { margin-bottom: 14px; }

/* Quick-filter strip — single compact row of the most-used tag pills */
.quick-filters { margin: 0 0 16px; }
.quick-filter-row {
  display: flex; flex-wrap: wrap; gap: 8px;
  align-items: center;
}
/* Hairline outlined pill — no fill, no shadow, no gradient. */
.quick-filter-tag {
  background: transparent;
  border: 1px solid var(--border-default);
  color: var(--text-secondary);
  padding: 5px 14px; border-radius: 999px;
  font-size: 12.5px; font-weight: 500; letter-spacing: 0.005em;
  cursor: pointer;
  box-shadow: none;
}
.quick-filter-tag:hover {
  border-color: var(--text-primary);
  color: var(--text-primary);
  transform: none;
  box-shadow: none;
}
.quick-filter-tag.include {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
  box-shadow: none;
}
.quick-filter-tag.include::before { content: "✓ "; }
.quick-filter-tag.exclude {
  background: linear-gradient(180deg, #3a1f1f 0%, #2a1818 100%);
  border-color: #ff6c6c; color: #ff8a8a; font-weight: 600;
  box-shadow: 0 0 0 2px rgba(255, 108, 108, 0.15);
}
.quick-filter-tag.exclude::before { content: "− "; }
.quick-filter-more {
  background: transparent; border: 1px dashed #3a3a3a; color: var(--text-muted);
  padding: 6px 14px; border-radius: 12px; font-size: 12px; cursor: pointer;
  transition: color .12s, border-color .12s;
}
.quick-filter-more:hover { color: #ededed; border-color: #ededed; border-style: solid; }

/* Tab strip: All / Favorites */
.gallery-tabs {
  display: flex; gap: 6px;
  margin-top: 32px;
  margin-bottom: 0;
  padding: 0 4px 0;
  border-bottom: 1px solid var(--border-default);
  /* Scroll horizontally inside the tab strip when the row gets too wide
     for the viewport (especially on phones). Without this, the row pushes
     the page wider and the whole layout becomes horizontally slidable. */
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none;        /* Firefox */
  -ms-overflow-style: none;     /* old Edge */
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}
.gallery-tabs::-webkit-scrollbar { display: none; }
.gallery-tab { flex: 0 0 auto; scroll-snap-align: start; white-space: nowrap; }
/* Reduce the gap between the tabs row and the first row of cards so they
   visually read as one block. */
.gallery-tabs + .character-grid,
.gallery-tabs + #character-grid,
.gallery-tabs ~ .character-grid {
  margin-top: 12px;
}
.gallery-tab {
  background: transparent; border: none;
  color: var(--text-muted);
  padding: 8px 14px;
  font-size: 13px; cursor: pointer;
  border-bottom: 2px solid transparent;
  display: inline-flex; align-items: center; gap: 6px;
}
.gallery-tab:hover { color: var(--text-primary); }
.gallery-tab.active {
  color: var(--text-primary);
  border-bottom-color: #ededed;
  font-weight: 600;
}
/* NSFW unlock switch — sits inline in the tab strip, not a tab */
.nsfw-switch {
  display: inline-flex; align-items: center; gap: 8px;
  margin-left: 14px; padding: 4px 10px; cursor: pointer;
  border-radius: 8px; user-select: none;
  transition: background .12s;
}
.nsfw-switch:hover { background: rgba(255,108,108,0.06); }
.nsfw-switch input { display: none; }
.nsfw-switch-track {
  position: relative; width: 34px; height: 18px;
  background: var(--border-default); border-radius: 12px;
  transition: background .18s ease;
  flex-shrink: 0;
}
.nsfw-switch-thumb {
  position: absolute; top: 2px; left: 2px;
  width: 14px; height: 14px; border-radius: 50%;
  background: #c0c5d0;
  transition: transform .18s ease, background .18s ease;
}
.nsfw-switch input:checked + .nsfw-switch-track {
  background: #ff6c6c;
}
.nsfw-switch input:checked + .nsfw-switch-track .nsfw-switch-thumb {
  transform: translateX(16px);
  background: #fff;
}
.nsfw-switch-label {
  font-size: 13px; color: #c87878; font-weight: 500;
}
.nsfw-switch input:checked ~ .nsfw-switch-label {
  color: #ff8a8a; font-weight: 600;
}
/* Action button on the right of the tab strip — visually distinct from tabs */
.gallery-tab-action {
  margin-left: auto;
  background: #1a2032; color: #c0c5d0;
  border: 1px solid #2a2a2a;
  padding: 6px 12px; border-radius: 8px;
  font-size: 12px; cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
.gallery-tab-action:hover { background: #232b3f; border-color: #ededed; color: #fff; }
.gallery-tab-action:disabled { opacity: 0.6; cursor: wait; }
.gallery-tabs { display: flex; align-items: center; }

/* Cloud mode: hide all local-only features (voice, SD studio, /imagine).
   Body gets `.cloud-mode` class set by loadAuthState() when /api/auth/me
   returns cloud:true (the CLOUD env var on the server). */
body.cloud-mode .char-card-actions button[title="Call"],
body.cloud-mode #char-modes-bar .mode[data-mode="call"],
body.cloud-mode #call-controls,
body.cloud-mode [data-section="call"],
body.cloud-mode #workshop-link,
body.cloud-mode .sidebar-link[data-nav="workshop"],
body.cloud-mode #btn-chat-imagine,
body.cloud-mode #status-dot,
body.cloud-mode #status-text { display: none !important; }
.gallery-tab-count {
  background: var(--bg-active); color: var(--text-muted);
  border-radius: 8px;
  padding: 1px 7px; font-size: 11px;
  min-width: 18px; text-align: center;
}
.gallery-tab.active .gallery-tab-count {
  background: #2a2a2a; color: var(--text-primary);
}

/* Star button on each character card (top-left of banner) */
.char-card-fav {
  position: absolute; top: 10px; left: 10px;
  background: rgba(0,0,0,0.6); color: #d0d4dc;
  border: none; border-radius: 50%;
  /* Explicit padding: 0 so the inherited button padding (7px 13px)
     doesn't squish the icon inside a forced 28×28 box — that's what
     was making the favorite button look oval. */
  width: 28px; height: 28px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; cursor: pointer; z-index: 2;
  backdrop-filter: blur(8px);
  transition: color .12s, transform .12s, background .12s;
}
.char-card-fav:hover { transform: scale(1.12); background: rgba(0,0,0,0.8); }
.char-card-fav.active { color: #ffd166; }

/* 3-dots overflow menu on each character card */
.char-card-menu-wrap {
  position: absolute; top: 10px; left: 46px; z-index: 3;
}
.char-card-menu-btn {
  background: rgba(0,0,0,0.6); color: #d0d4dc;
  border: none; border-radius: 50%;
  width: 28px; height: 28px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; line-height: 1; font-weight: 700; cursor: pointer;
  backdrop-filter: blur(8px);
  transition: background .12s, color .12s, transform .12s;
}
.char-card-menu-btn:hover {
  background: rgba(0,0,0,0.85); color: #fff; transform: scale(1.08);
}
.char-card-menu {
  position: absolute; top: 34px; left: 0;
  min-width: 190px;
  /* Solid opaque background — was transparent over banner art, making the
     menu items unreadable. Plus a backdrop blur for extra contrast. */
  background: rgba(15, 18, 24, 0.96);
  backdrop-filter: blur(12px) saturate(1.2);
  -webkit-backdrop-filter: blur(12px) saturate(1.2);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px; padding: 4px;
  box-shadow: 0 12px 32px rgba(0,0,0,0.55);
  display: flex; flex-direction: column; gap: 2px;
  z-index: 4;
}
.char-card-menu-item {
  display: flex; align-items: center; gap: 8px;
  background: transparent; border: none;
  color: var(--text-primary); text-align: left;
  padding: 8px 12px; border-radius: 8px;
  font-size: 13px; cursor: pointer;
  width: 100%;
}
.char-card-menu-item:hover { background: #2a2a2a; }
.char-card-menu-item span { font-size: 14px; width: 18px; text-align: center; }
.char-card-menu-item.danger { color: #ff8a8a; }
.char-card-menu-item.danger:hover { background: rgba(255, 108, 108, 0.18); }
.filter-tags-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 10px;
}
.filter-tags-label {
  font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.06em;
}
.search-input-wrap {
  position: relative; max-width: 480px;
}
.search-input-wrap .search-icon {
  position: absolute; left: 12px; top: 20px; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--text-muted); opacity: 0.7;
  pointer-events: none;
}
/* Honeypot inputs — visually offscreen but still in the DOM so the
   browser's autofill engine targets them instead of the real search box. */
.autofill-honeypot {
  position: absolute; left: -9999px; top: -9999px;
  width: 1px; height: 1px; opacity: 0;
  pointer-events: none;
}
/* Admin-only UI — hidden by default, revealed only when body.is-admin is
   set (by app.js when CURRENT_USER.is_superuser is true). Keeps deployer
   knobs like model paths + ports out of regular users' faces. */
.admin-only { display: none !important; }
body.is-admin .admin-only { display: revert !important; }
/* Mod-or-admin: things like Staff-Pick toggle, NSFW toggle on non-owner
   cards, delete-other-user's-post in feed. Admin always sees these
   (admin > mod). Plain users never see them. */
.mod-only { display: none !important; }
body.is-mod .mod-only { display: revert !important; }
/* Fix native dropdown menus on dark theme — Chrome/Edge default the
   option list to system colors, which renders white-on-white on dark
   backgrounds. Force readable colors on both <select> + <option>. */
select {
  background: var(--bg-elevated);
  color: var(--text-primary);
  color-scheme: dark;
}
select option {
  background: var(--bg-elevated);
  color: var(--text-primary);
}
body[data-theme="light"] select { color-scheme: light; }
body[data-theme="light"] select option {
  background: #ffffff; color: #111827;
}
/* Search row: center the filter button against the input itself (NOT
   the wrap with the hint below) so heights line up cleanly. */
.search-row { align-items: flex-start !important; }
.search-row .filter-btn { margin-top: 0; height: 40px; }
/* Target both `type="search"` (legacy) and `type="text"` (autofill-defense
   variant) so the input always renders at full width with the same chrome. */
.search-input-wrap input[type="search"],
.search-input-wrap input[type="text"]:not(.autofill-honeypot) {
  width: 100%; padding: 10px 36px 10px 36px; font-size: 14px;
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 8px;
  transition: border-color 200ms ease, box-shadow 200ms ease, background 200ms ease;
}
/* Search focus glow — soft indigo halo on focus, matches the primary
   button color so the focused input feels actionable. Inset shadow
   gives it a subtle lift instead of a flat ring. */
.search-input-wrap input[type="search"]:focus,
.search-input-wrap input[type="text"]:not(.autofill-honeypot):focus {
  outline: none;
  border-color: rgba(99, 102, 241, 0.55);
  background: var(--bg-hover);
  box-shadow:
    0 0 0 3px rgba(99, 102, 241, 0.18),
    0 4px 14px rgba(99, 102, 241, 0.12);
}
.search-input-wrap input[type="search"]::-webkit-search-cancel-button { display: none; }
.search-input-wrap .search-hint {
  display: block; margin-top: 8px; padding-left: 4px;
  font-family: 'Fraunces', Georgia, serif; font-style: italic;
  font-size: 13.5px; font-weight: 500;
  color: #f5f1ea;
  text-shadow: 0 0 8px rgba(255, 248, 232, 0.45),
               0 0 18px rgba(255, 240, 210, 0.22);
  letter-spacing: 0.015em; pointer-events: none;
}
.search-clear {
  position: absolute; right: 8px; top: 20px; transform: translateY(-50%);
  font-size: 14px;
}
/* Empty state — Fraunces italic, no dashed border, no icon banner.
   Reads like a printed bookplate, not a UI dialog. */
.gallery-empty {
  color: var(--text-muted); text-align: center;
  padding: 96px 24px; line-height: 1.5;
  min-height: 280px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px;
  background: transparent;
  border: none;
}
.gallery-empty-icon {
  font-size: 72px; line-height: 1;
  opacity: 0.55;
  margin-bottom: 4px;
  animation: empty-float 4500ms ease-in-out infinite;
  filter: drop-shadow(0 6px 16px rgba(0, 0, 0, 0.25));
}
@keyframes empty-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}
@media (prefers-reduced-motion: reduce) {
  .gallery-empty-icon { animation: none; }
}
.gallery-empty-title {
  font-family: "Fraunces", Georgia, serif;
  font-variation-settings: "opsz" 96, "SOFT" 50;
  font-style: italic;
  font-weight: 400;
  font-size: 32px;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  margin: 0;
}
.gallery-empty-sub {
  margin: 0;
  max-width: 360px;
  color: var(--text-muted);
  font-size: 14px;
}
.gallery-empty-actions {
  display: flex; flex-wrap: wrap; gap: 10px;
  justify-content: center;
  margin-top: 8px;
}
body[data-theme="light"] .gallery-empty {
  background: #ffffff;
  border-color: #e5e7eb;
}
body[data-theme="light"] .gallery-empty-title { color: #111827; }
body[data-theme="light"] .gallery-empty-sub { color: var(--text-faint); }

/* ============ LOADING SKELETONS ============ */
@keyframes shimmer {
  0%   { background-position: -400px 0; }
  100% { background-position: 400px 0; }
}
.skeleton-card {
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 12px;
  overflow: hidden; display: flex; flex-direction: column;
}
.skeleton-banner, .skeleton-line {
  background: linear-gradient(90deg, var(--bg-hover) 0%, #232733 50%, var(--bg-hover) 100%);
  background-size: 800px 100%;
  animation: shimmer 1.4s linear infinite;
}
.skeleton-banner { height: 100px; }
.skeleton-card-body { padding: 36px 16px 14px; display: flex; flex-direction: column; gap: 10px; }
.skeleton-line { height: 12px; border-radius: 4px; }
.skeleton-line.short { width: 60%; }
.skeleton-line.tall  { height: 16px; }

/* ============ WELCOME BANNER ============ */
.welcome-banner {
  background: linear-gradient(135deg, #1d2a4f 0%, #2a1d3e 100%);
  border: 1px solid #3a3a3a; border-radius: 8px;
  padding: 16px 20px; margin-bottom: 16px;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.welcome-banner .welcome-text { flex: 1; }
.welcome-banner h3 { margin: 0 0 4px; font-size: 15px; }
.welcome-banner p  { margin: 0; font-size: 13px; color: var(--text-muted); }
.welcome-banner .ghost { padding: 6px 10px; font-size: 16px; color: var(--text-muted); }
.welcome-banner .ghost:hover { color: #ffffff; }

/* ============ DRAG-AND-DROP OVERLAY ============ */
.gallery { position: relative; }
.drop-overlay {
  position: fixed; inset: 0;
  background: rgba(14, 15, 19, 0.85);
  display: flex; align-items: center; justify-content: center;
  z-index: 150; pointer-events: none;
  backdrop-filter: blur(4px);
}
.drop-overlay-card {
  background: var(--bg-elevated); border: 2px dashed #ededed; border-radius: 12px;
  padding: 50px 80px; text-align: center; color: var(--text-primary);
}
.gallery-header h1 { margin: 0; font-size: 24px; }
.gallery-header .muted { margin: 0; font-size: 14px; }
.character-grid {
  display: grid; gap: 12px;
  /* Force exactly 4 columns at desktop. minmax(0, 1fr) prevents content from
     pushing tracks wider than 25% — fixes the "2 huge cards" problem on
     high-DPI / scaled displays where auto-fit was collapsing to 2 tracks. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
  width: 100%;  /* always span the gallery container, even when empty */
}
@media (max-width: 1100px) {
  .character-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.character-card {
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 12px;
  display: flex; flex-direction: column;
  transition: border-color .15s, transform .15s;
  cursor: default; overflow: hidden;
  width: 100%; min-width: 0;
}
.character-card { position: relative; }  /* avatar overlay anchors to this */
.character-card:hover {
  border-color: rgba(255,255,255,0.14);
  transform: translateY(-2px);
  box-shadow:
    0 1px 0 rgba(255,255,255,0.04) inset,
    0 4px 12px rgba(0,0,0,0.30),
    0 18px 36px -14px rgba(0,0,0,0.50);
}
.character-card.new {
  align-items: center; justify-content: center;
  /* Match the overall aspect of a real card (3/4 banner + ~140px body) so the
     "+" placeholder doesn't stretch tall when it lands alone in a row. */
  aspect-ratio: 3 / 5;
  min-height: 0;
  border: 2px dashed var(--border-default); background: transparent; cursor: pointer;
  color: var(--text-muted); font-size: 14px;
}
.character-card.new:hover { border-color: #ededed; color: var(--text-primary); }

/* Art-first card: avatar fills the top ~65% of the card. Title overlays
   the bottom of the art with a soft gradient for legibility. */
.char-card-banner {
  position: relative;
  aspect-ratio: 3/4;
  background: linear-gradient(135deg, #2a2d3a 0%, var(--bg-elevated) 100%);
  overflow: hidden;
}
.char-card-banner-bg {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  pointer-events: none;
}
/* Gradient overlay so the title text sits readable on top of any image */
.char-card-banner::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(0,0,0,0.45) 0%,
    rgba(0,0,0,0) 30%,
    rgba(0,0,0,0) 60%,
    rgba(0,0,0,0.85) 100%);
  pointer-events: none;
}
.char-card-art-title {
  position: absolute; left: 14px; right: 14px; bottom: 14px;
  z-index: 1;
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 8px; pointer-events: none;
}
.char-card-art-title .name {
  font-size: 18px; font-weight: 700; color: #fff;
  text-shadow: 0 2px 4px rgba(0,0,0,0.6);
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.char-card-art-title .msg-count {
  display: inline-flex; align-items: center; gap: 4px;
  background: rgba(0,0,0,0.6); backdrop-filter: blur(6px);
  padding: 3px 9px; border-radius: 8px;
  font-size: 11px; color: #fff;
  flex-shrink: 0;     /* never let the badge get squished by a long name */
  pointer-events: auto;
}
.char-card-tag {
  position: absolute; top: 10px; right: 10px;
  background: rgba(0,0,0,0.6); color: var(--text-primary);
  font-size: 10px; padding: 4px 10px; border-radius: 12px;
  text-transform: uppercase; letter-spacing: 0.05em;
  backdrop-filter: blur(8px); z-index: 1;
}
/* Avatar circle is removed in the art-first design — the art IS the avatar */
.char-card-avatar-wrap { display: none; }

.char-card-body {
  padding: 12px 14px 14px;
  display: flex; flex-direction: column; gap: 8px;
  flex: 1;
}
.char-card-meta { flex: 1; min-height: 0; }
.char-card-name { display: none; }  /* now in the art overlay */
.char-card-tagline {
  font-size: 12px; color: #c0c5d0; margin: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.4;
}
.char-card-tags {
  display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px;
}
.char-card-tag-pill {
  font-size: 10px; padding: 2px 8px; border-radius: 8px;
  border: 1px solid;
  white-space: nowrap;
}
.char-card-tag-pill::before { content: "#"; opacity: 0.6; }
.char-card-credit {
  font-size: 10px; color: var(--text-muted);
  font-style: italic;
  margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.char-card-stats {
  display: flex; gap: 8px; font-size: 11px; color: var(--text-muted);
}
.char-card-stat { display: flex; align-items: center; gap: 4px; }
.char-card-actions { display: flex; gap: 4px; margin-top: 4px; }
.char-card-actions button {
  flex: 1; padding: 6px 4px; font-size: 11px;
}

/* ============ CHAR DETAIL ============ */
.char-detail {
  /* No max-width — let chat/call/settings fill the full main area now that
     the character switcher lives in the app sidebar instead of an inline pane. */
  width: 100%; padding: 8px 16px;
}
/* In-chat: zero the outer padding so the chat surface bleeds edge-to-edge
   like Character.AI. With the chat-window also stripped of its border-radius
   below, there is no "card floating in a black room" effect — the chat IS
   the page surface. Story / Call / Settings tabs keep their normal padding. */
body.in-chat .char-detail {
  padding: 0 !important;
}
.char-mode-section { display: block; }

#char-modes-bar {
  display: flex; gap: 4px; margin: 0 auto;
}
#char-modes-bar .mode {
  background: transparent; border: 1px solid transparent; color: var(--text-muted);
  padding: 6px 14px; border-radius: 8px; cursor: pointer; font-size: 13px;
}
#char-modes-bar .mode:hover { background: var(--bg-hover); color: var(--text-primary); }
#char-modes-bar .mode.active { background: var(--bg-active); color: var(--text-primary); border-color: #2a2a2a; }

/* ============ CHAT ============ */
.chat-layout {
  display: flex; gap: 12px;
  height: calc(100dvh - 110px);   /* dvh = dynamic viewport height —
                                     resizes when iOS / Android keyboards
                                     open, so the composer stays visible
                                     instead of being covered. */
}
@supports not (height: 100dvh) {
  .chat-layout { height: calc(100vh - 110px); }   /* fallback */
}
/* In character mode the topbar is stripped down to just back-arrow +
   Chat/Story tabs (~56px tall), so the default `-110px` leaves a dead
   strip at the bottom of the viewport. Tighten the calc so the chat-
   window's input bar sits flush against the viewport bottom. */
body.in-character .chat-layout {
  height: calc(100dvh - 56px);
}
@supports not (height: 100dvh) {
  body.in-character .chat-layout { height: calc(100vh - 56px); }
}
/* The character switcher now lives in the main app sidebar — hide the
   duplicate inline one so the chat window can use the full width. */
.chat-sidebar { display: none !important; }
.chat-layout.sidebar-collapsed .chat-sidebar { display: none; }

.chat-sidebar {
  width: 240px; flex-shrink: 0;
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 12px;
  display: flex; flex-direction: column; overflow: hidden;
}
.chat-sidebar-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--border-default);
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted);
}
.chat-sidebar-header button { padding: 4px 10px; font-size: 12px; }

.character-sidebar-list {
  flex: 1; overflow-y: auto; padding: 6px;
}
.sidebar-char-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  margin-bottom: 2px; border: 1px solid transparent;
}
.sidebar-char-item:hover { background: var(--bg-hover); }
.sidebar-char-item.active { background: var(--bg-active); border-color: #2a2a2a; }
.sidebar-char-avatar {
  width: 32px; height: 32px; border-radius: 50%;
  object-fit: cover; background: #232733; border: 1px solid var(--border-default);
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; color: var(--text-muted);
}
.sidebar-char-meta { flex: 1; min-width: 0; }
.sidebar-char-name {
  font-size: 13px; font-weight: 500; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sidebar-char-tagline {
  font-size: 11px; color: var(--text-muted); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Reply-length toggle (Short / Long) in the chat header */
.reply-length-toggle, .story-length-toggle {
  display: inline-flex;
  background: var(--bg-base); border: 1px solid var(--border-default);
  border-radius: 8px; padding: 2px;
  flex-shrink: 0;
}
.story-length-opt {
  background: transparent; border: none;
  color: var(--text-muted);
  padding: 4px 12px; font-size: 12px; cursor: pointer;
  border-radius: 8px;
}
.story-length-opt:hover { color: var(--text-primary); }
.story-length-opt.active {
  background: var(--bg-elevated);
  color: var(--text-primary);
}

/* Inline spinner inside the toolbar publish button while a publish /
   update is in flight. Just a tiny rotating ring — keeps the button
   readable but signals "working." */
.story-pub-spinner {
  display: inline-block;
  width: 12px; height: 12px;
  margin-right: 8px;
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  vertical-align: -2px;
  animation: story-pub-spin 700ms linear infinite;
}
@keyframes story-pub-spin { to { transform: rotate(360deg); } }
button.is-busy {
  cursor: progress !important;
  opacity: 0.85;
}
.reply-length-opt {
  background: transparent; border: none;
  color: var(--text-muted);
  padding: 4px 10px; font-size: 12px; cursor: pointer;
  border-radius: 8px;
  transition: background .12s, color .12s;
}
.reply-length-opt:hover { color: var(--text-primary); }
.reply-length-opt.active {
  background: var(--bg-active); color: var(--text-primary); font-weight: 600;
}

/* Vibe picker — moved to a collapsed icon at the left of the chat input
   bar. Click expands a popover with all options. */
.vibe-input-wrap {
  position: relative;
  display: inline-flex;
  align-items: center;
}
.vibe-input-btn {
  background: linear-gradient(135deg, #4338ca 0%, #db2777 100%);
  border: none;
  color: #fff;
  width: 36px; height: 36px;
  border-radius: 50%;
  font-size: 16px;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: transform .1s, box-shadow .12s;
  flex-shrink: 0;
}
.vibe-input-btn:hover {
  transform: scale(1.06);
  box-shadow: 0 4px 14px rgba(219, 39, 119, 0.4);
}
.vibe-popover {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 6px;
  display: flex; flex-direction: column;
  gap: 2px;
  min-width: 160px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
  z-index: 50;
}
.vibe-pop-opt {
  background: transparent; border: none;
  color: #c0c5d0;
  padding: 8px 12px; font-size: 13px;
  cursor: pointer;
  border-radius: 8px;
  text-align: left;
  white-space: nowrap;
  transition: background .12s, color .12s;
}
.vibe-pop-opt:hover { background: #1a1f2b; color: var(--text-primary); }
.vibe-pop-opt.active {
  background: linear-gradient(135deg, #4338ca 0%, #db2777 100%);
  color: #fff; font-weight: 600;
}

/* ============ SESSION DROPDOWN ============ */
.chat-header-actions { position: relative; flex-shrink: 0; }
#btn-session-menu {
  font-size: 22px; line-height: 1; padding: 4px 12px;
  color: #c0c5d0;
}
#btn-session-menu:hover { color: #ffffff; background: var(--bg-hover); }
/* Desktop has the topbar Chat/Story tabs already, so the inline "📖 Story"
   button is mobile-only. The @media block below (max-width: 720px) flips
   it visible alongside the existing mobile chat-header treatment. */
.chat-header-story-btn { display: none; }
/* Reply-length picker inside the chat ⋮ menu — mobile-only (desktop keeps
   the inline header toggle). Hidden by default; the mobile @media block
   flips it visible. */
.menu-reply-length { display: none; }
.menu-reply-length-opt {
  background: transparent;
  border: 1px solid var(--border-default);
  color: var(--text-muted);
  padding: 8px 10px;
  font-size: 13px;
  border-radius: 8px;
  cursor: pointer;
  flex: 1 1 auto;
  -webkit-tap-highlight-color: transparent;
}
.menu-reply-length-opt.active {
  background: var(--bg-active);
  color: var(--text-primary);
  border-color: #ededed;
  font-weight: 600;
}
.session-menu {
  position: absolute; top: 100%; right: 0; margin-top: 6px;
  width: 340px;
  /* Use almost the full viewport height so every menu item fits without
     needing to scroll on a normal-sized window. */
  max-height: calc(100vh - 80px);
  /* One shade brighter than the chat-window behind it. The chat-window
     uses --bg-elevated (#1c1c20); the dropdown uses --pal-charcoal-4
     (#26262c). The lift in brightness + the desktop scrim below means
     the menu always reads as a clear raised surface, never blended. */
  background-color: var(--pal-charcoal-4);
  background-image: none;
  opacity: 1;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 10px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.65),
              0 0 0 1px rgba(0, 0, 0, 0.4);
  display: flex; flex-direction: column; padding: 6px;
  /* Sit above the page-level scrim defined below. */
  z-index: 1001;
  overflow-y: auto;
}
/* NOTE: desktop intentionally has NO page-level scrim — the user
   asked for the dropdown to be visible WITHOUT darkening the rest of
   the chat. The dropdown's brighter background-color (charcoal-4 vs
   the chat-window's charcoal-3) plus the heavy shadow + bright border
   already give it a clear "raised surface" feel against the chat.
   The mobile @media block below adds its own scrim — that's fine,
   small screens need it because the menu covers more of the viewport. */
/* Children of the menu shouldn't shrink — without this, a menu with
   many items causes every row to compress when max-height clips. */
.session-menu > .menu-action,
.session-menu > .menu-divider,
.session-menu > .menu-section-header,
.session-menu > .menu-reply-length {
  flex-shrink: 0;
}
/* Phone: the chat-window has overflow: hidden, which would clip any
   absolute popup. Promote the menu to position: fixed and anchor it to
   the top-right corner — appears right under the ⋮ button when tapped,
   stays hidden otherwise. Same dropdown UX as desktop, just escapes
   the overflow chain. */
@media (max-width: 720px) {
  /* Anchored sheet under the chat header. The menu is reparented to <body>
     in JS (openSessionMenu) so position:fixed always resolves against the
     viewport — iOS Safari otherwise scopes fixed positioning to any
     transformed/will-change ancestor, which made the dropdown clip.
     Background uses background-color (not the shorthand) + opacity:1 so
     Safari can't render it translucent. */
  .session-menu {
    position: fixed !important;
    top: 56px !important;
    right: 8px !important;
    left: auto !important;
    bottom: auto !important;
    width: 270px !important;
    max-height: 78vh;
    margin: 0 !important;
    border-radius: 12px !important;
    background-color: #15172a !important;
    background-image: none !important;
    opacity: 1 !important;
    border: 1px solid rgba(255,255,255,0.16) !important;
    box-shadow: 0 16px 36px rgba(0, 0, 0, 0.65);
    z-index: 5000;
    padding: 6px !important;
    isolation: isolate;
    /* Menu scrolls as a last-resort when there are too many fixed items
       for the viewport — and the inner chat-history sub-list has its own
       scroll for when the user has many sessions. In practice on a normal
       phone (852px tall), the fixed items + a 180px chat-history band fit
       inside the 78vh cap and the menu itself doesn't need to scroll. */
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
  }
  /* Chat-history sub-list — fixed reasonable size (~3-4 rows visible) so
     the user can actually browse sessions without it collapsing to a
     hairline. Scrolls internally; the rest of the menu items stay put.
     flex-shrink:0 is critical — without it, flexbox squashes the list
     below max-height when the menu's natural content is taller than
     its 78vh cap. */
  .menu-list {
    flex-shrink: 0 !important;
    max-height: 180px !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch;
    /* iOS Safari's momentum scroll occasionally leaks the gesture to
       the parent menu — contain it so the menu doesn't accidentally
       scroll along with the list. */
    overscroll-behavior: contain;
  }
  /* Same flex-shrink:0 on the action buttons + dividers so the whole
     menu just gets taller and scrolls (via the menu's overflow-y:auto)
     when there's too much content, instead of every row shrinking. */
  .menu-action, .menu-divider, .menu-section-header {
    flex-shrink: 0 !important;
  }
  /* Backdrop scrim — clicking it closes the menu via the existing
     outside-click handler. Drawn as a pseudo-element on <body> so it
     covers the whole viewport without touching the DOM. */
  body.session-menu-open::before {
    content: "";
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.32);
    z-index: 4500;
  }
  .menu-action {
    min-height: 38px;
    font-size: 13.5px;
    padding: 8px 10px;
    color: #f3f4f6;
    line-height: 1.25;
    /* Disable iOS tap highlight rectangle so the dark menu stays clean. */
    -webkit-tap-highlight-color: transparent;
  }
  .menu-action.menu-primary { font-size: 13.5px; font-weight: 600; }
  .menu-section-header { font-size: 10.5px; padding: 6px 8px 2px; }
  .menu-divider { margin: 4px 0; }
  .menu-session-item { font-size: 13px; padding: 8px 10px; min-height: 38px; }
  .menu-session-item .meta { font-size: 11px; }
}
.menu-section-header {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted); padding: 6px 8px;
}
.menu-list {
  max-height: 220px; overflow-y: auto; margin-bottom: 4px;
}
.menu-session-item {
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  font-size: 13px; border: 1px solid transparent;
  display: flex; align-items: center; gap: 6px;
}
.menu-session-item:hover { background: var(--bg-hover); }
.menu-session-item.active { background: var(--bg-active); border-color: #2a2a2a; }
.menu-session-item-text {
  flex: 1 1 auto; min-width: 0;
}
.menu-session-item .name {
  color: var(--text-primary); font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.menu-session-item .meta { font-size: 11px; color: var(--text-muted); margin-top: 1px; }
.menu-session-rename {
  flex: 0 0 auto;
  background: transparent; border: 1px solid var(--border-default);
  color: var(--text-muted); font-size: 12px;
  width: 26px; height: 26px;
  border-radius: 8px;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  opacity: 0;
  transition: opacity .12s, background .12s, color .12s, border-color .12s;
}
.menu-session-item:hover .menu-session-rename,
.menu-session-rename:focus-visible { opacity: 1; }
.menu-session-rename:hover {
  background: #2a2a2a; color: #fff; border-color: #ededed;
}
.menu-session-pin {
  flex: 0 0 auto;
  background: transparent; border: 1px solid var(--border-default);
  font-size: 12px;
  width: 26px; height: 26px;
  border-radius: 8px;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  opacity: 0;
  filter: grayscale(0.6);
  transition: opacity .12s, background .12s, filter .12s, border-color .12s;
}
.menu-session-item:hover .menu-session-pin,
.menu-session-pin.is-pinned,
.menu-session-pin:focus-visible { opacity: 1; }
.menu-session-pin.is-pinned { filter: none; border-color: #ededed; }
.menu-session-pin:hover { background: #2a2a2a; border-color: #ededed; filter: none; }
.menu-divider {
  height: 1px; background: var(--border-default); margin: 4px 0;
}
.menu-action {
  background: transparent; border: none; color: var(--text-primary);
  padding: 8px 10px; border-radius: 8px; text-align: left;
  font-size: 13px; cursor: pointer;
}
.menu-action:hover { background: var(--bg-hover); }
.menu-action.menu-primary {
  color: #ffffff;
  font-weight: 600;
  text-shadow: 0 0 8px rgba(255, 248, 232, 0.55),
               0 0 18px rgba(255, 240, 210, 0.28);
}
.menu-action.menu-primary:hover {
  background: rgba(255, 255, 255, 0.06);
  text-shadow: 0 0 10px rgba(255, 248, 232, 0.75),
               0 0 22px rgba(255, 240, 210, 0.40);
}
.menu-action.menu-danger:hover { background: #2a1818; color: #ff6c6c; }
.menu-empty {
  padding: 12px 10px; font-size: 12px; color: var(--text-muted); text-align: center;
}

/* ============ AUTH PAGE ============ */
.auth-body {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 30% 20%, #1a1d2c 0%, var(--bg-base) 60%);
  padding: 20px;
}
.auth-shell { width: 100%; max-width: 420px; }
.auth-card {
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 12px;
  padding: 32px 28px; box-shadow: 0 12px 36px rgba(0,0,0,0.4);
}
.auth-title { margin: 0 0 6px 0; font-size: 24px; font-weight: 700; }
.auth-sub { margin: 0 0 20px 0; font-size: 13px; }
.auth-tabs { display: flex; gap: 4px; background: var(--bg-base); padding: 4px;
  border-radius: 8px; margin-bottom: 20px; }
.auth-tab {
  flex: 1; background: transparent; border: none; color: var(--text-muted);
  padding: 8px 14px; border-radius: 8px; cursor: pointer; font-size: 13px;
}
.auth-tab.active { background: var(--bg-active); color: var(--text-primary); }
.auth-form .row { margin-bottom: 12px; }
.auth-form input { padding: 10px 12px; font-size: 14px; }
.auth-form label { font-size: 12px; color: var(--text-muted); margin-bottom: 4px; }
.auth-error {
  background: #2a1818; color: #ff8a8a; border: 1px solid #c0392b;
  border-radius: 8px; padding: 8px 12px; font-size: 13px; margin-bottom: 12px;
}
.auth-submit { width: 100%; padding: 11px; font-size: 14px; margin-top: 4px; }
.google-signin-wrap {
  display: flex; justify-content: center; margin-bottom: 14px;
}
.auth-divider {
  display: flex; align-items: center; gap: 10px;
  margin: 4px 0 14px; font-size: 11px; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.12em;
}
.auth-divider::before, .auth-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--border-default);
}
.auth-divider span { padding: 0 4px; }

/* ============================================================ */
/* MOBILE RESPONSIVE                                             */
/* ============================================================ */
@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; padding: 12px; gap: 12px; }
  .panel { min-height: 0; }
  .settings-layout { grid-template-columns: 1fr; }
}

.mobile-menu-btn { display: none; font-size: 18px; padding: 4px 10px; margin-right: 4px; }

@media (max-width: 900px) {
  .app-sidebar {
    left: -240px;
    transition: left .22s ease;
    box-shadow: 4px 0 24px rgba(0,0,0,0.5);
  }
  .app-sidebar.mobile-open { left: 0; }
  .app-shell-main { margin-left: 0 !important; }
  body.sidebar-collapsed .app-shell-main { margin-left: 0 !important; }
  .mobile-menu-btn { display: inline-flex; }
  /* Larger touch targets on cards + chat input */
  .character-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 10px; }
  .char-card-actions button { padding: 10px 6px; font-size: 13px; }
  .chat-input-bar { padding: 10px; gap: 6px; }
  .chat-input-bar input { padding: 12px; font-size: 16px; }  /* 16px = no iOS zoom */
  .chat-input-bar button { padding: 10px 14px; }
  /* Agent dock takes the full width on mobile */
  .agent-dock { width: 100%; right: 0; }
  /* Quick filters wrap nicely */
  .quick-filter-row { gap: 6px; }
  .quick-filter-tag, .quick-filter-more { padding: 8px 14px; font-size: 13px; }
  /* Tabs become more touch-friendly */
  .gallery-tab { padding: 10px 12px; font-size: 14px; }
  /* NSFW toggle pulled to the front of the scroll strip on mobile so
     it's always visible without horizontal scrolling. Background tint
     + border make it visually distinct from the regular tabs. */
  .gallery-tabs .nsfw-switch {
    order: -1;
    flex-shrink: 0;
    background: rgba(220, 38, 38, 0.10);
    border: 1px solid rgba(220, 38, 38, 0.35);
    border-radius: 999px;
    padding: 6px 10px;
    margin-right: 6px;
  }
  .gallery-tabs .nsfw-switch .nsfw-switch-label { font-size: 12px; }

  /* Chat-view mobile: collapse the page to a single fixed viewport.
     Hide the bottom nav (the side hamburger still opens the same menu),
     hide top user controls (avatar / streak / notif / theme), and lock
     body scroll so only the chat-messages list scrolls. */
  /* Bottom mobile-nav hides in any character sub-tab — chat or story.
     Story-mode users shouldn't see the bottom Chats/Library/Feed bar
     stealing real estate either. */
  body.in-character #mobile-nav { display: none !important; }
  body.in-character {
    padding-bottom: 0 !important;
    overflow: hidden;
    height: 100dvh;
  }
  body.in-character #streak-badge-wrap,
  body.in-character #notif-bell-wrap,
  body.in-character #user-menu,
  body.in-character #btn-theme-toggle,
  body.in-character #workshop-link,
  body.in-character #brand-text,
  body.in-character .status-text,
  body.in-character #status-dot {
    display: none !important;
  }
  /* Hamburger STAYS visible in character views so users can still reach
     Group Chat / Workshop / other top-level pages without having to back
     out to home first. Sits between ← back and the Chat/Story tabs. */
  body.in-character #btn-mobile-menu {
    display: inline-flex !important;
    font-size: 18px;
    padding: 6px 8px;
    color: var(--text-primary);
    flex-shrink: 0;
  }
  /* Mobile in-character (chat or story) topbar: keep ONLY the back arrow
     + Chat/Story mode tabs visible. Strip topbar padding so it's a thin
     strip sitting under the iOS notch via safe-area-top. */
  body.in-character .topbar {
    padding: 0 8px !important;
    min-height: 0 !important;
    background: var(--bg-base);
    border-bottom: 1px solid var(--border-default);
    padding-top: env(safe-area-inset-top, 0px) !important;
    gap: 4px !important;
    align-items: center !important;
    flex-wrap: nowrap !important;
  }
  /* Back button — always visible in character views so users can pop
     back to home without relying on Safari's swipe-back gesture. */
  body.in-character #btn-back {
    display: inline-flex !important;
    font-size: 20px;
    padding: 6px 10px;
    color: var(--text-primary);
    flex-shrink: 0;
  }
  body.in-character .topbar .brand {
    flex: 0 0 auto !important;
    padding: 0 !important;
    background: transparent !important;
    border: none !important;
  }
  /* Edge-to-edge Chat/Story tabs in the topbar. order:0 overrides the
     wrap-to-third-row treatment used outside character views. */
  body.in-character #char-modes-bar {
    order: 0 !important;
    flex: 1 1 auto;
    padding: 6px 0 !important;
    border-top: none !important;
    gap: 8px;
    display: flex;
    justify-content: center;
  }
  body.in-character #char-modes-bar .mode {
    flex: 1 1 auto;
    max-width: 160px;
    padding: 10px 14px !important;
    font-size: 14px !important;
    font-weight: 600;
    min-height: 40px;
  }
  /* Chat-mode story-icon button in the chat header is redundant now —
     hide it on mobile too since the topbar Chat/Story tabs are back. */
  .chat-header-story-btn {
    font-size: 18px; line-height: 1; padding: 4px 8px;
    color: #c0c5d0;
    display: none;
  }
  .chat-header-story-btn:hover { color: #fff; background: var(--bg-hover); }
  /* With the topbar gone, the chat layout fills the whole viewport (minus
     the safe-area top inset so it doesn't slide under the iOS notch).
     Locking the layout to 100dvh + overflow:hidden on the body prevents
     Safari from resizing the chat-window when the URL bar collapses on
     scroll — without this lock the input bar would jitter every scroll. */
  body.in-chat .chat-layout {
    height: calc(100dvh - env(safe-area-inset-top, 0px)) !important;
    padding-top: env(safe-area-inset-top, 0px);
  }
  body.in-chat .chat-window {
    /* Pin the whole chat panel: header at top, messages flex-fill,
       input bar at bottom. No height jumps on focus/keyboard open
       because the parent height is dvh, which Safari already adjusts
       in lockstep with the visible viewport. */
    height: 100%;
    min-height: 0;
    overscroll-behavior: contain;
    /* Character.AI mobile look — chat panel runs edge-to-edge. No
       rounded card corners or hairline border on a phone, where the
       chat IS the screen. */
    border-radius: 0;
    border: 0;
  }
  body.in-chat .chat-messages {
    /* Only the messages list scrolls — the header and input bar stay
       put. overflow-y on chat-messages already exists; we just make sure
       overscroll doesn't bubble up to the body. */
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }
  body.in-chat .app-shell-main {
    height: 100dvh;
    overflow: hidden;
  }
}
@media (max-width: 600px) {
  .character-grid { grid-template-columns: 1fr !important; }
  .gallery { padding: 14px 12px; }
  .gallery-header h1 { font-size: 20px; }
  .modal-card { padding: 18px 14px; }
}

/* ============================================================
   MOBILE BOTTOM NAVIGATION (visible under 720px)
   Replaces the sidebar — sidebar eats half the phone screen.
   Fixed-position bar at bottom with 5 tabs (Home / Library / Feed
   / Group / You). Body gets bottom padding so the nav doesn't
   cover content. iOS safe-area aware via env(safe-area-inset).
   ============================================================ */
@media (max-width: 720px) {
  .app-sidebar { display: none !important; }
  .mobile-nav { display: flex !important; }
  /* Hide deployer-only actions that lengthen the gallery-tabs row. The
     Scan-avatars button sits at the end of the row and forces horizontal
     scroll even when the user only wants to pick a filter. Admins can
     access it from the admin panel. */
  #btn-scan-nsfw { display: none !important; }
  /* Same logic for the gallery-tabs — give them edge-to-edge breathing
     room and a touch-momentum feel. */
  .gallery-tabs { padding-left: 12px; padding-right: 12px; }
  /* Reserve room at the bottom of the page so the fixed nav doesn't
     cover the last row of content. Home (gallery) also has the
     Character Creator pill stacked above the nav, so add another 44px
     of room there. */
  body { padding-bottom: calc(58px + env(safe-area-inset-bottom)); }
  body:not(.not-on-home) {
    padding-bottom: calc(58px + 48px + env(safe-area-inset-bottom));
  }
  /* Main content reclaims the sidebar's column */
  .gallery, .feed-layout, .library-layout, .profile-layout,
  .chat-layout, .group-layout, .story-layout {
    margin-left: 0 !important;
  }

  /* M3 — bigger base font, generous touch targets */
  body { font-size: 15px; }
  button, .button, .menu-action,
  .feed-tab, .feed-tweet-action, .char-card-share-btn,
  .feed-suggested-follow, .primary, .ghost {
    min-height: 40px;
  }
  /* Exception — circular icon buttons must stay square at their
     specified size (otherwise the 40px min-height makes them oval).
     Keep the original 28×28 so they read as buttons, not pills. */
  .char-card-fav,
  .char-card-menu-btn {
    min-height: 28px !important;
  }
  .feed-tweet-action { padding: 10px 14px 10px 10px; }
  .feed-tweet-action-iconwrap { width: 36px; height: 36px; }

  /* M2 — modal sizing: full-bleed bottom sheet feel on phones */
  .modal { padding: 0 !important; align-items: flex-end !important; }
  .modal-card {
    width: 100% !important; max-width: 100% !important;
    max-height: 92vh; border-radius: 18px 18px 0 0 !important;
    margin: 0 !important;
    padding-bottom: calc(env(safe-area-inset-bottom) + 16px);
    animation: mobileSheetSlide 280ms cubic-bezier(.2,.8,.2,1);
    position: relative;
  }
  /* iOS-style grabber pill at the top of every bottom-sheet modal —
     signals the swipe-down-to-dismiss affordance. */
  .modal-card::before {
    content: "";
    position: absolute;
    top: 8px; left: 50%;
    transform: translateX(-50%);
    width: 40px; height: 4px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.22);
    pointer-events: none;
  }
  /* Bigger × hit targets so close is one easy tap, not pixel-hunting. */
  .modal-card .modal-close,
  .modal-card button[aria-label="Close"] {
    min-width: 44px; min-height: 44px;
    padding: 8px !important;
    font-size: 22px !important;
    line-height: 1 !important;
  }
  @keyframes mobileSheetSlide {
    from { transform: translateY(100%); opacity: 0.6; }
    to   { transform: translateY(0); opacity: 1; }
  }
  .post-detail-card { max-height: 92vh; }

  /* M2 — composer: stack content tighter, bigger tap targets */
  .feed-composer { padding: 12px; }
  .feed-composer-row { gap: 10px; }
  .feed-composer-avatar { flex: 0 0 36px; width: 36px; height: 36px; font-size: 14px; }
  .feed-composer textarea { font-size: 16px; /* keeps iOS from auto-zooming on focus */ }
  .feed-composer-image-btn { padding: 9px 14px; }

  /* M4 — gallery: 2-col grid, smaller cards */
  .character-grid {
    grid-template-columns: repeat(2, 1fr) !important;
    gap: 12px !important;
  }
  #profile-character-grid {
    grid-template-columns: repeat(2, 1fr) !important;
    gap: 12px !important;
  }
  .library-grid {
    grid-template-columns: repeat(2, 1fr) !important;
    gap: 12px !important;
  }

  /* Topbar: hide the giant mode bar on small screens */
  .topbar { padding: 8px 12px; }
  .brand .status-text { display: none; }

  /* Feed posts: tighter side padding */
  .feed-tweet { padding: 14px 14px; gap: 10px; }
  .feed-tweet-avatar { flex: 0 0 42px; width: 42px; height: 42px; }
  .feed-tweet-body { font-size: 16px; }

  /* Inputs: 16px font prevents iOS Safari auto-zoom on focus */
  input, textarea, select { font-size: 16px !important; }
}
.profile-popover {
  position: fixed; z-index: 250; width: 280px;
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  border-radius: 12px; padding: 14px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
  animation: popoverIn 160ms ease;
}
@keyframes popoverIn {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.profile-popover-head { display: flex; gap: 10px; align-items: center; }
.profile-popover-avatar {
  width: 44px; height: 44px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-primary); font-weight: 600; font-size: 16px;
  overflow: hidden; flex: 0 0 44px;
}
.profile-popover-avatar img { width: 100%; height: 100%; object-fit: cover; }
.profile-popover-name { font-weight: 700; color: var(--text-primary); font-size: 14px; }
.profile-popover-followers { color: var(--text-muted); font-size: 12px; margin-top: 2px; }
.profile-popover-bio {
  color: var(--text-secondary); font-size: 13px; line-height: 1.45;
  margin-top: 10px;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.profile-popover-actions {
  display: flex; gap: 8px; margin-top: 12px;
}
.profile-popover-actions button {
  flex: 1; padding: 7px 12px; font-size: 12.5px; border-radius: 999px;
}

/* C1 — Press-down scale animation. Reads as "the device responded" on
   touch devices. Only kicks in on mobile (hover-less inputs) so cursor
   users don't get a weird click jolt. */
@media (hover: none) and (pointer: coarse) {
  button:active,
  .sidebar-link:active,
  .feed-tweet-action:active,
  .char-card-share-btn:active,
  .feed-suggested-follow:active,
  .mobile-nav-btn:active,
  .feed-tab:active,
  .gallery-tab:active,
  .profile-tab:active,
  .menu-action:active {
    transform: scale(0.96);
    transition: transform 80ms ease;
  }
}

.toast-undo {
  display: flex; align-items: center; gap: 12px;
  background: rgba(15, 20, 25, 0.95) !important;
  color: #f5f1ea !important;
  padding: 12px 14px 12px 16px !important;
  border: 1px solid rgba(255, 255, 255, 0.12) !important;
  border-radius: 12px !important;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
}
.toast-undo .toast-text { font-size: 13px; }
.toast-undo-btn {
  background: rgba(255, 255, 255, 0.10);
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: #f5f1ea;
  padding: 6px 14px; border-radius: 999px;
  font-size: 12px; font-weight: 600;
  cursor: pointer;
  transition: background 120ms ease;
}
.toast-undo-btn:hover { background: rgba(255, 255, 255, 0.18); }
.toast-leaving { opacity: 0; transform: translateY(8px); transition: all 200ms ease; }

/* Confetti burst for first-engagement celebration. Pure-CSS particles
   that fountain up + spin out from the bottom-center of the viewport. */
.confetti-burst {
  position: fixed; left: 50%; bottom: 80px; z-index: 300;
  pointer-events: none;
}
.confetti-piece {
  position: absolute; width: 8px; height: 14px;
  border-radius: 2px;
  animation: confettiFly 1.4s cubic-bezier(.2,.7,.4,1) forwards;
  animation-delay: var(--d, 0s);
  opacity: 0;
}
@keyframes confettiFly {
  0%   { transform: translate(0, 0) rotate(0deg); opacity: 1; }
  100% { transform: translate(var(--x, 0), var(--y, -200px)) rotate(var(--r, 360deg)); opacity: 0; }
}

/* Native View Transitions: small crossfade between view switches */
@supports (view-transition-name: a) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 220ms;
    animation-timing-function: cubic-bezier(.2, .8, .2, 1);
  }
  /* On phones, swap the crossfade for an iOS-style horizontal slide:
     new view enters from the right, old view exits to the left. Reads
     as forward navigation in a native app. */
  @media (max-width: 720px) {
    @keyframes app-slide-in {
      from { transform: translateX(100%); opacity: 0.5; }
      to   { transform: translateX(0); opacity: 1; }
    }
    @keyframes app-slide-out {
      from { transform: translateX(0); opacity: 1; }
      to   { transform: translateX(-30%); opacity: 0; }
    }
    ::view-transition-new(root) {
      animation: app-slide-in 260ms cubic-bezier(.2, .8, .2, 1);
    }
    ::view-transition-old(root) {
      animation: app-slide-out 260ms cubic-bezier(.2, .8, .2, 1);
    }
  }
}

.mobile-nav {
  display: none;
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 100;
  height: calc(58px + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  background: rgba(14, 15, 19, 0.92);
  backdrop-filter: blur(20px) saturate(1.4);
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  border-top: 1px solid var(--border-subtle);
  align-items: stretch; justify-content: space-around;
  /* Let the centered elevated Chats button overflow above the nav bar. */
  overflow: visible;
}
body[data-theme="light"] .mobile-nav {
  background: rgba(255, 252, 247, 0.92);
}
.mobile-nav-btn {
  flex: 1; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px;
  background: transparent; border: none; cursor: pointer;
  color: var(--text-muted); font-size: 10px; font-weight: 500;
  padding: 0 4px; min-height: 44px;
  transition: color 160ms ease;
  position: relative;
  -webkit-tap-highlight-color: transparent;
}
.mobile-nav-btn svg { stroke: currentColor; }
.mobile-nav-btn:active { transform: scale(0.94); }
.mobile-nav-btn.is-active { color: var(--text-primary); }
.mobile-nav-btn.is-active svg { stroke-width: 2; }
/* Elevated centered Chats button — anchors the nav like the central
   create / record buttons in Instagram, TikTok, Reels. Circular brand-
   burgundy ground, larger icon, lifted above the bar so it reads as
   the primary destination. The button itself becomes the red circle;
   SVG sits naturally inside it with the original viewBox sizing. */
.mobile-nav-center {
  flex: 0 0 56px;
  position: relative;
  align-self: flex-start;
  width: 56px; height: 56px;
  margin-top: -18px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--pal-burgundy, #7a2e2e) 0%, var(--pal-burgundy-deep, #5c2222) 100%);
  color: #fff !important;
  box-shadow: 0 6px 18px rgba(122,46,46,0.55), 0 2px 4px rgba(0,0,0,0.3);
  border: 3px solid rgba(14, 15, 19, 0.92);
  padding: 0 !important;
  min-height: 0 !important;
  gap: 0;
  transition: transform 160ms ease, box-shadow 160ms ease, filter 160ms ease;
}
.mobile-nav-center svg {
  width: 26px !important; height: 26px !important;
  stroke: #fff !important;
  stroke-width: 2 !important;
}
.mobile-nav-center:hover {
  filter: brightness(1.1);
  box-shadow: 0 8px 22px rgba(122,46,46,0.7);
}
.mobile-nav-center:active { transform: scale(0.94); }
/* "Chats" caption floats below the circle so the button retains its
   identity. Pinned absolute so it doesn't push the circle off-center. */
.mobile-nav-center span {
  position: absolute;
  top: calc(100% + 2px); left: 50%;
  transform: translateX(-50%);
  color: var(--text-muted);
  font-weight: 600;
  font-size: 9px;
  white-space: nowrap;
}
.mobile-nav-center.is-active span { color: var(--pal-burgundy, #7a2e2e); }
body[data-theme="light"] .mobile-nav-center {
  border-color: rgba(255, 252, 247, 0.92);
}
.mobile-nav-badge {
  position: absolute; top: 6px; right: calc(50% - 18px);
  background: var(--pal-burgundy, #7a2e2e); color: #fff;
  border-radius: 999px; padding: 1px 5px;
  font-size: 9px; font-weight: 700; line-height: 1.3;
  min-width: 14px; text-align: center;
  /* Phase 4 A6 — pop on first appearance instead of hard-cutting in. */
  animation: badgePop 220ms cubic-bezier(.34,1.56,.64,1);
}
@keyframes badgePop {
  0%   { transform: scale(0); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}

@media (max-width: 700px) {
  /* Topbar — give it room to wrap */
  .topbar {
    flex-wrap: wrap; padding: 8px 12px; gap: 8px;
  }
  .brand { gap: 6px; font-size: 14px; }
  .brand .status-text { display: none; }
  #char-modes-bar {
    order: 3; width: 100%; justify-content: center;
    padding-top: 6px; border-top: 1px solid var(--border-default);
  }
  #char-modes-bar .mode {
    flex: 1; padding: 8px 6px; font-size: 12px; max-width: 120px;
  }
  #call-controls { gap: 4px; }
  #call-controls button {
    margin-left: 0; padding: 5px 8px; font-size: 11px;
  }
  #user-menu, #workshop-link { font-size: 11px; }

  /* Gallery */
  .gallery { padding: 16px 12px; }
  .gallery-header {
    grid-template-columns: 1fr;
    gap: 8px;
    margin-bottom: 12px;
  }
  .gallery-header h1 { font-size: 20px; }
  .gallery-header > div:last-child { width: 100%; justify-self: stretch; }
  .gallery-header > div:last-child button { flex: 1; }
  .character-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px;
  }
  /* Let the banner keep its native 3/4 aspect ratio so portrait avatars
     fill the card properly. The previous height: 70px override made the
     banner a thin stripe and cards looked shrunken-together. */
  .char-card-banner { height: auto; aspect-ratio: 3/4; }
  .char-card-avatar-wrap { width: 50px; height: 50px; left: 12px; bottom: -22px; }
  .char-card-body { padding: 28px 12px 12px; gap: 8px; }
  .char-card-name { font-size: 14px; }
  .char-card-actions button { font-size: 11px; padding: 5px 2px; }

  /* Chat layout: sidebar drawer instead of side-by-side */
  .chat-layout { flex-direction: column; height: calc(100vh - 100px); }
  .chat-sidebar {
    width: 100%; max-height: 200px; flex-shrink: 0;
  }
  .chat-layout.sidebar-collapsed .chat-sidebar { display: none; }
  .character-sidebar-list {
    display: flex; flex-direction: row; overflow-x: auto; overflow-y: hidden;
    padding: 6px;
  }
  .sidebar-char-item {
    flex-direction: column; min-width: 80px; max-width: 100px; text-align: center;
    padding: 6px; gap: 6px;
  }
  .sidebar-char-meta { width: 100%; }
  .sidebar-char-tagline { display: none; }
  .sidebar-char-name { font-size: 11px; }

  .chat-window-header {
    padding: 8px 10px; gap: 6px;
  }
  /* Slim chat header on phones — was eating ~80px of vertical room. */
  .chat-header-avatar { width: 32px !important; height: 32px !important; }
  .chat-header-name { font-size: 14px; }
  .chat-header-sub { font-size: 11px; }
  .chat-header-session .muted { display: none; }
  .chat-header-identity { padding: 2px 6px 2px 2px; gap: 8px; flex: 1 1 auto; min-width: 0; }
  .chat-header { padding: 6px 10px !important; min-height: 52px; }
  /* The chat-header has too many buttons (reply-length, 🧠, +, 📖, ⋮)
     to fit beside the identity tile on a 393px phone — the name was
     getting truncated to "A...". Tighten gaps + drop the reply-length
     toggle entirely on mobile (users can still set it from desktop, and
     mobile users rarely need to switch mid-conversation). */
  .chat-header-actions { gap: 2px; }
  .reply-length-toggle { display: none !important; }
  /* Surface the reply-length picker inside the ⋮ menu now that the header
     toggle is gone on mobile. flex-row with two pills, full menu width. */
  .menu-reply-length {
    display: flex !important;
    align-items: center;
    gap: 6px;
    padding: 6px 8px 8px;
    flex-wrap: wrap;
  }
  .menu-reply-length .menu-section-header {
    flex: 0 0 100%;
    text-transform: uppercase;
    font-size: 10.5px;
    color: var(--text-muted);
  }
  /* Story-icon button stays hidden: the topbar Chat/Story tabs above are
     the canonical mode switch and we don't want a redundant duplicate
     in the chat-header taking room from the avatar/name. */
  #btn-memory, #btn-new-session-quick { font-size: 16px; padding: 4px 6px; }
  #btn-session-menu { padding: 4px 8px; }
  /* Character.AI-style mobile cleanup — the row of inline action icons
     (✎ Edit, 🔄 Regenerate) below every bubble made the chat look noisy
     and "floaty". Collapse the row to just the ⋮ More menu, which already
     contains every action (Copy / Edit / Regenerate / Rewind / Branch /
     Translate / Delete). One dot per bubble, no clutter. */
  .chat-bubble-actions {
    opacity: 1;
    gap: 0;
    /* Tuck the menu trigger flush under the bubble's corner instead of a
       full row underneath — no extra vertical breathing room. */
    margin-top: 2px;
  }
  /* Hide direct .chat-bubble-action children of .chat-bubble-actions
     (the standalone ✎ and 🔄 buttons). The ⋮ button lives inside
     .chat-bubble-menu-wrap so it survives this rule. */
  .chat-bubble-actions > .chat-bubble-action { display: none; }
  .chat-bubble-menu-wrap > .chat-bubble-action {
    /* Keep an iOS-standard 44px hit area on the ⋮ trigger, but render it
       as a small inline dot with no visual chrome. */
    width: 32px !important; height: 32px !important;
    font-size: 16px !important;
    opacity: 0.55;
  }
  .chat-bubble-menu-wrap > .chat-bubble-action:active { opacity: 1; }
  #active-session-name { display: none; }
  .chat-bubble { max-width: 90%; font-size: 13px; }
  .chat-input-bar input { font-size: 14px; padding: 10px; }

  /* Settings — give labels their own line */
  .row label { min-width: 0; flex-basis: 100%; margin-bottom: 2px; }
  .row { gap: 6px; }
  input[type="number"] { max-width: 100px; }

  /* Modals */
  .modal-card {
    padding: 18px 16px; width: 100%; max-width: 100%;
    border-radius: 0; min-height: 100vh; max-height: 100vh;
  }

  /* Auth pages */
  .auth-card { padding: 24px 18px; border-radius: 12px; }
  .auth-title { font-size: 20px; }

  /* Toasts above the bottom edge — clear the fixed bottom nav (58px)
     plus safe-area, otherwise success/error flashes hide under the nav. */
  .toast-container {
    left: 12px; right: 12px;
    bottom: calc(70px + env(safe-area-inset-bottom, 0px));
  }
  .toast { max-width: 100%; }
}

@media (max-width: 420px) {
  /* Keep 2 columns even on the narrowest phones — single-col made the
     gallery feel like a list rather than a CAI-style card grid. */
  .character-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .char-card-banner { height: auto; aspect-ratio: 3/4; }
  #char-modes-bar .mode {
    font-size: 11px; padding: 6px 4px;
  }
}

.active-session-pill {
  display: inline-block; margin-left: 6px;
  padding: 1px 8px; border-radius: 8px;
  background: var(--bg-active); border: 1px solid #2a2a2a;
  font-size: 11px; color: var(--text-muted);
}

.chat-window-header {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; border-bottom: 1px solid var(--border-default);
  font-size: 13px;
  /* Phase 4 B4 — sticky header so the avatar + name stay pinned while
     scrolling history. Tinted/blurred background keeps content beneath
     readable as it slides under. */
  position: sticky; top: 0; z-index: 6;
  background: var(--bg-elevated);
  backdrop-filter: blur(10px) saturate(1.3);
  -webkit-backdrop-filter: blur(10px) saturate(1.3);
}
.chat-window-header .muted { color: var(--text-muted); }
.chat-window-header .ghost { margin-left: 0; padding: 2px 8px; font-size: 13px; }

/* Clickable avatar + name tile. Wrapper is a <button> so keyboard users
   can tab to it; the grey hover state is the affordance the user asked for. */
.chat-header-identity {
  display: flex; align-items: center; gap: 12px;
  flex: 1; min-width: 0;
  background: transparent; border: 1px solid transparent;
  border-radius: 8px;
  padding: 4px 10px 4px 4px;
  cursor: pointer;
  text-align: left;
  color: inherit;
  font: inherit;
}
.chat-header-identity:hover { background: rgba(255,255,255,0.05); border-color: rgba(255,255,255,0.06); }
.chat-header-identity:focus-visible { outline: 2px solid #ededed; outline-offset: 2px; }
body[data-theme="light"] .chat-header-identity:hover { background: rgba(0,0,0,0.05); border-color: rgba(0,0,0,0.06); }

.chat-header-avatar {
  width: 44px; height: 44px; border-radius: 50%;
  object-fit: cover; background: var(--bg-base); border: 1px solid var(--border-default);
  flex: 0 0 auto;
}
.chat-header-avatar:not([src]) { background: var(--bg-elevated); }
/* Avatar monogram fallback — a serif letter on near-black surface, the
   way the Hermes app or Aesop's character avatars render initials. The
   data-monogram attribute is set by JS (paintChatHeader) when no src. */
.chat-header-avatar[data-monogram]:not([src])::before {
  content: attr(data-monogram);
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%;
  font-family: "Fraunces", Georgia, serif;
  font-variation-settings: "opsz" 144;
  font-style: italic; font-weight: 500;
  font-size: 18px; color: #c2c4cc;
  letter-spacing: -0.02em;
}
.chat-header-meta { flex: 1; min-width: 0; overflow: hidden; }

/* ============ CHARACTER INFO MODAL ============ */
.character-info-card { max-width: 520px; }
.character-info-head {
  display: flex; align-items: center; gap: 14px;
  padding-bottom: 14px; margin-bottom: 14px;
  border-bottom: 1px solid var(--border-default);
}
.character-info-avatar {
  width: 72px; height: 72px; border-radius: 50%;
  object-fit: cover; background: var(--bg-base); border: 1px solid var(--border-default);
  flex: 0 0 auto;
}
.character-info-head-meta { flex: 1; min-width: 0; }
.character-info-head-meta h2 { margin: 0 0 4px; }
.character-info-head-meta p { margin: 0; }
.character-info-section { margin-bottom: 14px; }
.character-info-section h3 {
  margin: 0 0 6px;
  font-size: 13px; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--text-muted);
  font-weight: 600;
}
.character-info-section p {
  margin: 0; color: var(--text-primary);
  font-size: 14px; line-height: 1.5;
  white-space: pre-wrap; word-break: break-word;
}
.character-info-section-row {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 6px;
}
.character-info-section-row h3 { margin: 0; }
.character-info-edit-btn {
  font-size: 11px; padding: 2px 8px;
  opacity: 0.75;
}
.character-info-edit-btn:hover { opacity: 1; }
.character-info-section textarea {
  width: 100%;
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  color: var(--text-primary);
  padding: 10px 12px;
  font-size: 14px; line-height: 1.5;
  resize: vertical; min-height: 72px;
  font-family: inherit;
}
.character-info-section textarea:focus { outline: none; border-color: #ededed; }
.character-info-edit-actions {
  display: flex; justify-content: flex-end; gap: 8px;
  margin-top: 8px;
}
body[data-theme="light"] .character-info-section p { color: #1f2937; }
body[data-theme="light"] .character-info-head { border-bottom-color: #e5e7eb; }
body[data-theme="light"] .character-info-section textarea { background: #ffffff; border-color: var(--text-secondary); color: #1f2937; }
.chat-header-name {
  font-size: 16px; font-weight: 600; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-header-sub {
  font-size: 12px;
  display: flex; align-items: center; gap: 6px;
  overflow: hidden;
}
#chat-header-tagline {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0; flex: 0 1 auto;
}
.chat-header-actions { flex-shrink: 0; min-width: 0; }
.chat-header-session {
  display: flex; align-items: center; gap: 6px;
  flex-shrink: 0;
}
.chat-header-session span { color: var(--text-primary); }

.chat-window {
  flex: 1; min-width: 0;
  /* Character.AI-style full-bleed chat surface — no card border, no rounded
     corners, no gap to the page edge. The chat IS the page; the only
     elevation step is the slightly-lighter sticky header on top. */
  background: var(--bg-chat);
  border: 0;
  border-radius: 0;
  display: flex; flex-direction: column;
  overflow: hidden;
  position: relative;  /* anchor for floating .chat-scroll-bottom-btn */
}
/* "+ Create new character" tile inside the user's own profile grid.
   Brand burgundy red — same accent as the logo and every other primary
   CTA in the app. The wordmark + glyph pop on the deep red ground. */
.character-card-create {
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--pal-burgundy, #7a2e2e) 0%, var(--pal-burgundy-deep, #5c2222) 100%);
  border: 1px dashed rgba(255,255,255,0.32);
  color: #fff;
  cursor: pointer;
  min-height: 260px;
  padding: 16px;
  transition: transform 160ms ease, box-shadow 160ms ease, filter 160ms ease;
}
.character-card-create:hover {
  transform: translateY(-2px);
  filter: brightness(1.08);
  box-shadow: 0 10px 26px rgba(122,46,46,0.45);
}
.character-card-create:active { transform: scale(0.98); }
.char-card-create-inner {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  text-align: center;
}
.char-card-create-plus {
  font-size: 56px; line-height: 1;
  font-weight: 300;
  width: 88px; height: 88px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.18);
  margin-bottom: 6px;
}
.char-card-create-label {
  font-family: "Fraunces", Georgia, serif;
  font-style: italic; font-weight: 500;
  font-size: 18px;
}
.char-card-create-sub {
  font-size: 12px; opacity: 0.85;
  letter-spacing: 0.04em; text-transform: uppercase;
}

/* "+ New Character" header button on the Chats tab — brand burgundy
   gradient with a soft red glow on hover. Matches the create-tile so
   both manual-create entry points read as the same action. */
#btn-chats-new-character {
  background: linear-gradient(135deg, var(--pal-burgundy, #7a2e2e) 0%, var(--pal-burgundy-deep, #5c2222) 100%) !important;
  color: #fff !important;
  border: 1px solid rgba(255,255,255,0.18) !important;
  box-shadow: 0 4px 14px rgba(122,46,46,0.4);
  font-weight: 600;
}
#btn-chats-new-character:hover {
  filter: brightness(1.10);
  box-shadow: 0 6px 18px rgba(122,46,46,0.55);
}

/* =========================================================
   Chats tab — mobile-first list of recent conversations. Top header
   carries a primary "+ New Character" button that opens the OG manual
   creation modal (parallel to the AI-driven bottom Character Creator pill). */
.chats-layout {
  display: flex; flex-direction: column;
  padding: 28px 32px 32px;
  gap: 18px;
  min-height: 100vh;
  /* Fill the available space on desktop — only narrow to a comfortable
     reading column once the viewport is wider than a typical iPad
     landscape (where line-length starts to hurt readability). */
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
}
.chats-header {
  display: flex; align-items: flex-start; gap: 12px;
  justify-content: space-between;
}
.chats-head-titles h1 {
  font-family: "Fraunces", Georgia, serif;
  font-variation-settings: "opsz" 144;
  font-style: italic; font-weight: 500;
  font-size: 28px; margin: 0 0 4px;
}
.chats-list {
  display: flex; flex-direction: column;
  gap: 4px;
}
.chats-row {
  display: flex; align-items: center; gap: 12px;
  width: 100%; text-align: left;
  background: transparent; border: 1px solid transparent;
  border-radius: 10px;
  padding: 10px 12px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background 140ms ease, border-color 140ms ease;
}
.chats-row:hover, .chats-row:active {
  background: var(--bg-hover);
  border-color: var(--border-subtle);
}
.chats-row-avatar {
  width: 48px; height: 48px; border-radius: 50%;
  object-fit: cover; background: var(--bg-elevated);
  flex: 0 0 auto;
  border: 1px solid var(--border-subtle);
}
.chats-row-avatar-fallback {
  display: flex; align-items: center; justify-content: center;
  font-family: "Fraunces", Georgia, serif;
  font-size: 22px; color: var(--pal-camel, #b8915a);
  font-style: italic;
}
.chats-row-body { flex: 1; min-width: 0; }
.chats-row-name-line {
  display: flex; align-items: baseline; gap: 8px;
  justify-content: space-between;
}
.chats-row-name {
  font-weight: 600; font-size: 15px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chats-row-time { flex-shrink: 0; font-size: 11px; }
.chats-row-snippet {
  font-size: 13px;
  margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
body[data-theme="light"] .chats-row-avatar-fallback { color: #b07028; }

/* Mobile bottom nav now has 6 buttons (Home, Library, Chats, Group,
   Feed, You). Tighten spacing so the 6th tab fits without label clip. */
@media (max-width: 720px) {
  .mobile-nav-btn { padding: 0 2px; font-size: 9.5px; }
  .mobile-nav-btn svg { width: 20px; height: 20px; }
  .chats-layout {
    padding: 16px 12px calc(80px + env(safe-area-inset-bottom, 0px));
    max-width: none;
  }
  .chats-head-titles h1 { font-size: 22px; }
}

/* Per-character chat backdrop — DISABLED by user request. The chat tab
   now uses a plain flat background (`--bg-elevated`) regardless of the
   character's banner_image / banner_color. The classes are still added
   by paintChatHeader() so other places that look for them keep working,
   but the visual backdrop is suppressed and children stack normally.
   Was: blurred banner image / gradient color overlay via ::before. */
.chat-window.has-character-bg::before,
.chat-window.has-character-tint::before { display: none !important; }
.chat-window.has-character-bg > *,
.chat-window.has-character-tint > * { position: static; z-index: auto; }

/* The page-level html element paints a repeating-linear-gradient "linen
   weave" + an SVG noise pattern as its background (see html { } at the
   top of the file). That texture is visible *through* the chat-window
   because the chat-window's solid bg sits over an html background with
   `background-attachment: fixed` — Chromium composites the fixed pattern
   above the chat-window in some configurations. User asked for a plain
   flat background in the chat tab; the cleanest fix is to suppress the
   html-level pattern entirely while we're in chat mode. Every other view
   (gallery, library, feed, profile, story) keeps the linen texture. */
body.in-chat,
body.in-chat html {
  background-image: none !important;
}
html:has(body.in-chat) {
  background-image: none !important;
}
/* The blanket "every child gets z-index:1" above was clobbering the
   chat-window-header's own z-index:6, making it stack at the SAME level
   as .chat-messages — and since chat-messages comes later in the DOM,
   user chat bubbles ended up rendering ON TOP of the header (and, more
   visibly, on top of the open ⋮ dropdown). Re-raise the header to win
   against the messages list when a character backdrop is active. */
.chat-window.has-character-bg > .chat-window-header,
.chat-window.has-character-tint > .chat-window-header { z-index: 7; }
.chat-messages {
  flex: 1; overflow-y: auto; padding: 20px;
  display: flex; flex-direction: column; gap: 12px;
}
.chat-row {
  display: flex; align-items: flex-end; gap: 8px;
  max-width: 75%;
}
.chat-row.assistant { align-self: flex-start; }
.chat-row.user      { align-self: flex-end; flex-direction: row-reverse; }
.chat-row.system    { align-self: center; max-width: 90%; }

.chat-row-avatar {
  width: 32px; height: 32px; border-radius: 50%;
  object-fit: cover; background: #232733; border: 1px solid var(--border-default);
  flex: 0 0 auto;
}
.chat-row-avatar:not([src]) {
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; color: var(--text-muted);
}

.chat-bubble {
  padding: 10px 14px; border-radius: 12px;
  font-size: 14px; line-height: 1.5; white-space: pre-wrap; word-wrap: break-word;
  min-width: 0;
  position: relative;
}
/* Subtle fade + slide-up on new bubbles. Runs once per row insert (CSS
   animations don't replay on attribute changes), so re-renders during
   streaming don't re-trigger. The cascade on initial history-paint is
   intentional — matches the CAI / iMessage feel of "messages settling
   into view". */
.chat-row {
  animation: chat-row-enter 220ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
@keyframes chat-row-enter {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .chat-row { animation: none; }
}

/* Chat skeleton — placeholder bubbles while history loads. The shimmer
   sweep across each bubble cues "loading" without being noisy. Auto-
   replaced the moment loadChatHistory() returns. */
.chat-skeleton {
  display: flex; flex-direction: column; gap: 14px;
  padding: 18px 14px;
}
.chat-skel-row {
  display: flex;
}
.chat-skel-row.user { justify-content: flex-end; }
.chat-skel-row.assistant { justify-content: flex-start; }
.chat-skel-bubble {
  width: 60%; max-width: 320px; height: 38px;
  border-radius: 12px;
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0.04) 0%,
    rgba(255, 255, 255, 0.10) 50%,
    rgba(255, 255, 255, 0.04) 100%);
  background-size: 200% 100%;
  animation: chat-skel-shimmer 1400ms linear infinite;
}
.chat-skel-bubble.short { width: 40%; max-width: 220px; height: 30px; }
@keyframes chat-skel-shimmer {
  from { background-position: -100% 0; }
  to   { background-position:  100% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .chat-skel-bubble { animation: none; }
}

/* Typing-indicator dots — shown inside an empty streaming bubble while
   the bot is "thinking" before the first token arrives. Three dots
   bounce in a loop. CSS-only; activated by the .is-empty class set in
   _setBubbleText() and removed the moment text appears. */
.chat-bubble.streaming.is-empty {
  min-width: 60px; min-height: 22px;
  position: relative;
}
.chat-bubble.streaming.is-empty::after {
  content: "";
  display: block;
  width: 32px; height: 8px;
  background:
    radial-gradient(circle at 4px 4px,  currentColor 3px, transparent 3.5px),
    radial-gradient(circle at 16px 4px, currentColor 3px, transparent 3.5px),
    radial-gradient(circle at 28px 4px, currentColor 3px, transparent 3.5px);
  opacity: 0.5;
  animation: typing-dots 1100ms ease-in-out infinite;
}
@keyframes typing-dots {
  0%, 100% { opacity: 0.3; transform: translateY(0); }
  50%      { opacity: 0.85; transform: translateY(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .chat-bubble.streaming.is-empty::after { animation: none; opacity: 0.6; }
}
.chat-bubble-pinmark {
  position: absolute;
  top: -8px; right: -6px;
  font-size: 14px;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.45));
  pointer-events: none;
  user-select: none;
}
/* Your message bubble (right) — muted dark burgundy. Distinct from
   the assistant's neutral charcoal so the two sides read as different
   speakers, but nothing fights the eye. */
.chat-bubble.user {
  background: rgba(122, 46, 46, 0.32);
  color: var(--text-primary);
  border: 1px solid rgba(122, 46, 46, 0.35);
  border-bottom-right-radius: 4px;
}
/* Assistant bubble (left) — neutral elevated charcoal, slightly muted
   text so the bubbles don't burn into the eye on long sessions. */
.chat-bubble.assistant {
  background: rgba(255, 255, 255, 0.04);
  color: var(--text-secondary);
  border: 1px solid var(--border-subtle);
  border-bottom-left-radius: 4px;
}
.chat-bubble.system {
  background: transparent; color: var(--text-muted);
  font-size: 12px; font-style: italic; text-align: center;
}
.chat-bubble.streaming::after {
  content: "▍"; opacity: 0.6; animation: blink 1s step-end infinite;
  margin-left: 2px;
}

/* In-chat image bubble (from /imagine) */
.chat-bubble.has-image {
  background: transparent !important;
  padding: 0; border-radius: 12px; overflow: hidden;
  max-width: 360px;
}
.chat-bubble-image {
  display: block; width: 100%; height: auto;
  border-radius: 12px;
  border: 1px solid var(--border-default);
}

/* Alternate greetings editor — list of single-line inputs. */
.alt-greetings-disclosure {
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 8px 12px;
  margin-top: 8px;
  font-size: 13px;
}
.alt-greetings-disclosure summary {
  cursor: pointer; color: var(--text-secondary); font-weight: 500;
  list-style-position: inside;
}
.alt-greetings-list {
  display: flex; flex-direction: column;
  gap: 6px; margin-top: 8px;
}
.alt-greeting-row {
  display: flex; gap: 6px; align-items: center;
}
.alt-greeting-input {
  flex: 1 1 auto;
  background: var(--bg-elevated); color: var(--text-primary);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 6px 10px;
  font: inherit; font-size: 12px;
}
.alt-greeting-remove {
  padding: 2px 8px !important;
  font-size: 11px !important;
  color: #f87171 !important;
}

/* Few-shot example dialogues editor — same disclosure pattern as the
   personality sliders. Each row is a {user, assistant} pair. */
.example-dialogues-disclosure {
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 8px 12px;
  margin-top: 8px;
  font-size: 13px;
}
.example-dialogues-disclosure summary {
  cursor: pointer;
  color: var(--text-secondary);
  font-weight: 500;
  list-style-position: inside;
}
.example-dialogues-list {
  display: flex; flex-direction: column;
  gap: 10px; margin-top: 8px;
}
.example-dialogue-row {
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 8px;
  display: flex; flex-direction: column; gap: 6px;
}
.example-dialogue-head {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 11px; color: var(--text-muted);
}
.example-dialogue-num {
  color: var(--text-faint); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em;
  font-size: 10px;
}
.example-dialogue-remove {
  padding: 2px 8px !important;
  font-size: 11px !important;
  color: #f87171 !important;
}
.example-dialogue-row textarea {
  width: 100%; resize: vertical;
  background: var(--bg-base); color: var(--text-primary);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 6px 8px;
  font: inherit; font-size: 12px;
  line-height: 1.4;
}
.example-dialogue-user { border-left: 3px solid #ededed !important; }
.example-dialogue-assistant { border-left: 3px solid #db2777 !important; }

/* Personality sliders — broad-trait sliders inside the character
   creation modal. 6 sliders, each centred = balanced; ends describe
   opposite traits. */
.personality-sliders-disclosure {
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 8px 12px;
  margin-top: 8px;
  font-size: 13px;
}
.personality-sliders-disclosure summary {
  cursor: pointer;
  color: var(--text-secondary);
  font-weight: 500;
  list-style-position: inside;
}
.personality-sliders {
  margin-top: 12px;
  display: flex; flex-direction: column;
  gap: 12px;
}
.personality-slider-row {
  display: flex; flex-direction: column; gap: 4px;
}
.personality-slider-labels {
  display: flex; justify-content: space-between;
  font-size: 11px; color: var(--text-muted);
}
.personality-slider-end.right { text-align: right; }
.personality-slider {
  -webkit-appearance: none;
  width: 100%;
  height: 4px;
  background: linear-gradient(to right, #ededed 0%, #db2777 100%);
  border-radius: 999px;
  outline: none;
  cursor: pointer;
}
.personality-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 18px; height: 18px;
  background: #fff;
  border: 2px solid #ededed;
  border-radius: 50%;
  cursor: pointer;
  transition: transform .1s;
}
.personality-slider::-webkit-slider-thumb:hover { transform: scale(1.1); }
.personality-slider::-moz-range-thumb {
  width: 18px; height: 18px;
  background: #fff;
  border: 2px solid #ededed;
  border-radius: 50%;
  cursor: pointer;
}

/* Character-creation templates row — clickable archetype chips that
   pre-fill the form. Wraps so 8+ items fit on narrower screens. */
.char-template-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 4px;
}
.char-template-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: 999px;
  padding: 6px 12px;
  color: var(--text-secondary);
  font-size: 12px;
  cursor: pointer;
  transition: background .12s, border-color .12s, transform .08s;
}
.char-template-btn:hover {
  background: var(--bg-active);
  border-color: #ededed;
  color: #fff;
  transform: translateY(-1px);
}
.char-template-btn:active { transform: translateY(0); }
.char-template-emoji { font-size: 14px; line-height: 1; }
.char-template-label { font-weight: 500; }

/* Per-message action row + ⋮ menu — Character.AI-style. Always visible
   at 55% opacity beneath each bubble, full opacity on hover. */
.chat-row { position: relative; }
.chat-row-stack {
  display: flex; flex-direction: column;
  align-items: flex-start;
  min-width: 0;
}
.chat-row.user .chat-row-stack { align-items: flex-end; }
.chat-bubble-actions {
  display: flex; gap: 4px;
  margin-top: 4px;
  opacity: 0.55;
  transition: opacity .14s ease;
}
.chat-row:hover .chat-bubble-actions { opacity: 1; }
.chat-bubble-action {
  background: transparent; border: none; color: var(--text-faint);
  width: 24px; height: 24px; border-radius: 50%;
  font-size: 13px; line-height: 1; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background .12s, color .12s, transform .1s;
}
.chat-bubble-action:hover {
  background: var(--bg-active); color: var(--text-primary); transform: scale(1.12);
}
.chat-bubble-menu-wrap { position: relative; }
.chat-bubble-menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 4px;
  min-width: 200px;
  box-shadow: 0 12px 36px rgba(0,0,0,0.55);
  z-index: 80;
  display: flex; flex-direction: column;
  gap: 1px;
}
.chat-row.assistant .chat-bubble-menu { right: auto; left: 0; }
.chat-bubble-menu-item {
  display: flex; align-items: center; justify-content: space-between;
  gap: 18px;
  background: transparent; border: none;
  padding: 8px 12px; border-radius: 8px;
  color: var(--text-secondary);
  font-size: 13px;
  cursor: pointer;
  text-align: left;
  transition: background .1s;
}
.chat-bubble-menu-item:hover { background: #1a1f2b; color: #fff; }
.chat-bubble-menu-item.danger { color: #f87171; }
.chat-bubble-menu-item.danger:hover { background: rgba(239, 68, 68, 0.12); color: #fff; }
.chat-bubble-menu-icon {
  flex: 0 0 auto;
  font-size: 14px;
  color: var(--text-faint);
}
.chat-bubble-menu-item:hover .chat-bubble-menu-icon { color: inherit; }

/* Variants picker — sits under the bubble. Single button shows "↩ N/M";
   click opens a popover listing every variant so the user can revert
   to a specific old reply by clicking it. */
.chat-bubble-variants-wrap {
  position: relative;
  margin-top: 6px;
  display: inline-block;
}
.chat-bubble-variants-btn {
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  color: #c0c5d0;
  padding: 4px 12px;
  font-size: 12px;
  border-radius: 999px;
  cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: background .12s, border-color .12s, color .12s;
}
.chat-bubble-variants-btn:hover {
  background: #1a1f2b; border-color: #ededed; color: #fff;
}
.chat-variants-popover {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 0;
  background: var(--bg-base);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 6px;
  display: flex; flex-direction: column;
  gap: 2px;
  min-width: 320px;
  max-width: 480px;
  max-height: 380px;
  overflow-y: auto;
  box-shadow: 0 12px 36px rgba(0,0,0,0.55);
  z-index: 80;
}
.chat-variants-head {
  font-size: 11px; color: var(--text-faint);
  padding: 6px 10px 8px;
  border-bottom: 1px solid #1a1f2b;
  margin-bottom: 4px;
}
.chat-variants-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 8px 10px;
  background: transparent; border: none;
  border-radius: 8px;
  text-align: left;
  cursor: pointer;
  color: #c0c5d0;
  font-size: 13px; line-height: 1.4;
  transition: background .1s;
}
.chat-variants-item:hover { background: #1a1f2b; }
.chat-variants-item.active {
  background: rgba(237, 237, 237, 0.10);
  border: 1px solid rgba(237, 237, 237, 0.45);
}
.chat-variants-item:disabled { opacity: 0.55; cursor: wait; }
.chat-variants-num {
  flex: 0 0 auto;
  background: var(--bg-active);
  color: var(--text-muted);
  width: 22px; height: 22px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.chat-variants-item.active .chat-variants-num {
  background: var(--pal-burgundy); color: #ededed;
}
.chat-variants-preview {
  flex: 1 1 auto; min-width: 0;
  white-space: normal; word-wrap: break-word;
  color: var(--text-secondary);
}
.chat-variants-tag {
  flex: 0 0 auto;
  font-size: 10px;
  color: var(--text-faint);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: 2px;
}
.chat-variants-item.active .chat-variants-tag {
  color: #ededed;
  font-weight: 600;
}

/* Inline editor inside a chat bubble */
.chat-bubble-edit {
  width: 100%; min-width: 240px;
  background: var(--bg-base); color: var(--text-primary); border: 1px solid #ededed;
  border-radius: 8px; padding: 8px 10px;
  font-family: inherit; font-size: 14px; line-height: 1.4;
  resize: vertical;
}
.chat-bubble-edit-controls {
  display: flex; gap: 6px; justify-content: flex-end;
  margin-top: 6px;
}
.chat-bubble-edit-controls button { padding: 4px 12px; font-size: 12px; }

/* Roleplay markup inside chat bubbles:
     *italics* → action descriptions (smiles softly)
     **bold**  → emphatic words
     (parens)  → softer parenthetical asides */
.chat-bubble .rp-action {
  color: #c0a8ff;            /* soft lavender — distinct from regular text */
  font-style: italic;
  opacity: 0.92;
}
.chat-bubble.user .rp-action { color: #ffe9b8; }   /* warm tone on the user bubble */
.chat-bubble .rp-paren {
  color: var(--text-muted);
  font-style: italic;
}
.chat-bubble.user .rp-paren { color: var(--text-primary); opacity: 0.78; }
.chat-bubble strong { font-weight: 700; }
/* Phase 4 B3 — Long-message collapse. CSS clamps the bubble height and
   paints a fade + Show more pill; click expands. Streaming bubbles never
   get this class — only historical / settled messages do. */
.chat-row.is-collapsible .chat-bubble.assistant {
  max-height: 520px;
  overflow: hidden;
  position: relative;
}
.chat-row.is-collapsible .chat-bubble.assistant::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 80px;
  background: linear-gradient(to bottom, transparent, var(--bg-elevated, #1a1d24) 90%);
  pointer-events: none;
}
.chat-row.is-collapsible.is-expanded .chat-bubble.assistant { max-height: none; }
.chat-row.is-collapsible.is-expanded .chat-bubble.assistant::after { display: none; }
.chat-bubble-expand {
  position: absolute;
  bottom: 8px; left: 50%;
  transform: translateX(-50%);
  background: rgba(255,255,255,0.10);
  color: var(--text-primary);
  border: 1px solid rgba(255,255,255,0.18);
  padding: 4px 12px; border-radius: 999px;
  font-size: 12px; font-weight: 600;
  cursor: pointer;
  z-index: 2;
  backdrop-filter: blur(6px);
}
.chat-bubble-expand:hover { background: rgba(255,255,255,0.16); }
.chat-row.is-collapsible.is-expanded .chat-bubble-expand {
  position: static; transform: none; margin-top: 8px; display: inline-block;
}
body[data-theme="light"] .chat-row.is-collapsible .chat-bubble.assistant::after {
  background: linear-gradient(to bottom, transparent, #ffffff 90%);
}
body[data-theme="light"] .chat-bubble-expand {
  background: #ffffff; color: #1f2937;
  border-color: #e5e7eb;
}
/* Phase 4 B2 — inline `code` + fenced ```code blocks``` in chat bubbles. */
.chat-bubble .rp-code-inline {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.92em;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 4px;
  padding: 1px 5px;
}
.chat-bubble.user .rp-code-inline {
  background: rgba(0,0,0,0.18);
  border-color: rgba(255,255,255,0.18);
}
.chat-bubble .rp-code-block {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.88em;
  background: rgba(0,0,0,0.32);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 8px;
  padding: 10px 12px;
  margin: 8px 0;
  overflow-x: auto;
  white-space: pre;
}
.chat-bubble .rp-code-block code { background: transparent; padding: 0; border: 0; }
.chat-bubble a {
  color: #93c5fd;
  text-decoration: underline;
  text-underline-offset: 2px;
  word-break: break-all;
}
.chat-bubble.user a { color: #fde68a; }
body[data-theme="light"] .chat-bubble .rp-code-inline {
  background: #f3f4f6;
  border-color: #e5e7eb;
  color: #111827;
}
body[data-theme="light"] .chat-bubble .rp-code-block {
  background: #f9fafb;
  border-color: #e5e7eb;
  color: #111827;
}
body[data-theme="light"] .chat-bubble a { color: #2563eb; }
body[data-theme="light"] .chat-bubble.user a { color: #fde68a; }
@keyframes blink { 50% { opacity: 0; } }
.chat-input-bar {
  display: flex; gap: 8px; padding: 12px;
  border-top: 1px solid var(--border-default); background: var(--bg-base);
  /* Respect iOS safe-area inset so the composer doesn't sit under the
     home-indicator strip on Face-ID iPhones. */
  padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
}
.chat-input-bar input,
.chat-input-bar textarea { flex: 1; padding: 10px 12px; font-size: 16px; }
/* Send button: word on desktop, paper-plane icon on mobile. Mirrors
   ChatGPT / CAI / iMessage. The SVG inherits color so it picks up the
   primary button text color automatically. */
#btn-chat-send .send-icon { display: none; vertical-align: middle; }
@media (max-width: 720px) {
  #btn-chat-send .send-text { display: none; }
  #btn-chat-send .send-icon { display: inline-block; }
  #btn-chat-send {
    padding: 10px 14px !important;
    min-width: 44px;
    display: inline-flex; align-items: center; justify-content: center;
  }
}
/* Composer auto-grow: the chat-input is a <textarea> so multi-line drafts
   don't truncate. JS resizes height on input; CSS hides the resize grip,
   pins min-height to one row, and keeps the textarea aligned with the
   surrounding input-bar buttons. */
.chat-input-bar textarea#chat-input {
  resize: none;
  min-height: 40px;
  max-height: 160px;
  line-height: 1.4;
  font-family: inherit;
  overflow-y: auto;
  align-self: flex-end;
}
/* On phones, anchor the composer to the bottom of the chat layout so
   it stays glued to the keyboard's top edge when the keyboard opens. */
@media (max-width: 720px) {
  .chat-input-bar {
    position: sticky; bottom: 0; z-index: 5;
    background: var(--bg-base);
  }
}

/* Phase 4 A3 — Floating scroll-to-bottom button (Chat). Pinned above the
   composer. Hidden by default; JS toggles .visible when the user has
   scrolled up. Tap → smooth scroll to floor. */
.chat-scroll-bottom-btn {
  position: absolute;
  right: 18px;
  bottom: calc(80px + env(safe-area-inset-bottom, 0px));
  width: 40px; height: 40px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(20, 22, 28, 0.92);
  color: var(--text-primary);
  border: 1px solid var(--border-default);
  box-shadow: 0 4px 16px rgba(0,0,0,0.32);
  cursor: pointer;
  z-index: 4;
  opacity: 0; transform: translateY(8px) scale(0.92);
  pointer-events: none;
  transition: opacity 180ms ease, transform 180ms ease, background 160ms ease;
  -webkit-tap-highlight-color: transparent;
}
.chat-scroll-bottom-btn.visible {
  opacity: 1; transform: translateY(0) scale(1); pointer-events: auto;
}
.chat-scroll-bottom-btn:hover { background: rgba(28, 32, 40, 0.96); }
.chat-scroll-bottom-btn:active { transform: scale(0.94); }
body[data-theme="light"] .chat-scroll-bottom-btn {
  background: rgba(255, 252, 247, 0.96);
  color: #2a2a2a;
  border-color: rgba(0,0,0,0.12);
}
@media (max-width: 720px) {
  .chat-scroll-bottom-btn { right: 12px; bottom: calc(74px + env(safe-area-inset-bottom, 0px)); }
}

/* ============ CALL ============ */
.call-body {
  flex: 1; overflow-y: auto; padding: 20px;
}
#call-controls button { margin-left: 6px; }
#btn-call-session-menu {
  font-size: 22px; line-height: 1; padding: 4px 12px;
  color: #c0c5d0;
}
#btn-call-session-menu:hover { color: #ffffff; background: var(--bg-hover); }

/* ============ SETTINGS ============ */
.settings-layout {
  display: grid; grid-template-columns: 1fr; gap: 16px;
}
.avatar-preview {
  width: 64px; height: 64px; border-radius: 8px; object-fit: cover;
  background: var(--bg-base); border: 1px solid var(--border-default); flex: 0 0 auto;
}

/* ============ ADVANCED SECTION ============ */
.advanced-section {
  margin-top: 28px;
  border-top: 1px solid var(--border-default);
  padding-top: 16px;
}
.advanced-section > summary {
  cursor: pointer;
  font-size: 13px;
  color: var(--text-muted);
  padding: 8px 12px;
  border-radius: 8px;
  background: var(--border-subtle);
  user-select: none;
  list-style: none;
}
.advanced-section > summary::-webkit-details-marker { display: none; }
.advanced-section > summary:before {
  content: "▶";
  display: inline-block;
  margin-right: 8px;
  font-size: 10px;
  transition: transform 0.15s;
}
.advanced-section[open] > summary:before { transform: rotate(90deg); }
.advanced-section > summary:hover { background: var(--bg-hover); color: var(--text-primary); }
.advanced-section[open] > summary { color: var(--text-primary); }

/* ============ MODAL ============ */
.modal {
  position: fixed; inset: 0; background: rgba(0,0,0,0.6);
  display: flex; align-items: center; justify-content: center; z-index: 100;
}
/* z-index is also bumped dynamically by JS (_bumpModalZIndex in app.js)
   so any modal opened later sits on top of earlier-opened modals
   regardless of source order. The static defaults below set the floor. */
#sd-busy-overlay       { z-index: 250; }
#lightbox              { z-index: 300; }
.modal-card {
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 12px;
  padding: 24px; width: 520px; max-width: 95vw; max-height: 90vh; overflow-y: auto;
}
.modal-card h2 { margin-top: 0; border: none; font-size: 18px; text-transform: none;
  letter-spacing: 0; color: var(--text-primary); }

/* ============ WIZARD ============ */
.wizard-step { margin-bottom: 16px; }
.wizard-step-label {
  display: block; font-size: 12px; text-transform: uppercase;
  color: var(--text-muted); letter-spacing: 0.06em; margin-bottom: 8px;
}
.wizard-drop {
  background: var(--bg-base); border: 2px dashed var(--border-default); border-radius: 8px;
  padding: 30px; text-align: center; cursor: pointer;
  color: var(--text-muted); transition: border-color .15s, color .15s;
}
.wizard-drop:hover { border-color: #ededed; color: var(--text-primary); }
.wizard-drop.has-file { border-color: #2dd47d; border-style: solid; color: var(--text-primary); }

/* Quick-import disclosure inside New Character modal */
.quick-import {
  border: 1px dashed #2a2a2a; border-radius: 8px;
  padding: 10px 14px; margin-bottom: 12px;
}
.quick-import > summary {
  cursor: pointer; font-size: 13px; color: #ededed;
  user-select: none; list-style: none;
}
.quick-import > summary::-webkit-details-marker { display: none; }
.quick-import textarea {
  width: 100%; min-height: 70px;
}

/* Surprise-me preferences panel */
.surprise-prefs {
  margin: 8px 0 16px 0;
  border: 1px dashed #2a2a2a; border-radius: 8px;
  padding: 10px 14px;
}
.surprise-prefs > summary {
  cursor: pointer; font-size: 13px; color: #b561ff;
  user-select: none; list-style: none;
}
.surprise-prefs > summary::-webkit-details-marker { display: none; }
.pref-group { margin-bottom: 12px; }
.pref-group:last-child { margin-bottom: 0; }
.pref-label {
  font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.06em;
  margin-bottom: 6px;
}
.chip-row {
  display: flex; flex-wrap: wrap; gap: 6px;
}
.pref-chip {
  background: var(--bg-base); color: #c0c5d0; border: 1px solid var(--border-default);
  padding: 4px 10px; border-radius: 12px;
  font-size: 12px; cursor: pointer;
  transition: background .12s, border-color .12s, color .12s;
}
.pref-chip:hover { border-color: #ededed; color: var(--text-primary); }
.pref-chip.active {
  background: #2a2a2a; border-color: #ededed; color: var(--text-primary);
}
.surprise-prefs textarea {
  width: 100%; min-height: 50px; font-size: 12px;
}

/* ============ TAG EDITOR (settings + new-char modal) ============ */
.tag-editor {
  display: flex; flex-direction: column; gap: 8px;
  background: var(--bg-base); border: 1px solid var(--border-default); border-radius: 8px;
  padding: 10px;
}
.tag-editor-chips {
  display: flex; flex-wrap: wrap; gap: 6px; min-height: 22px;
}
.tag-editor-chips:empty::before {
  content: "No tags yet — pick some below or type your own.";
  color: #555; font-size: 12px; font-style: italic;
}
.tag-chip {
  display: inline-flex; align-items: center; gap: 4px;
  background: var(--bg-active); color: var(--text-primary); border: 1px solid #2a2a2a;
  padding: 3px 4px 3px 10px; border-radius: 12px;
  font-size: 12px;
}
.tag-chip-remove {
  background: transparent; border: none; color: var(--text-muted);
  cursor: pointer; padding: 0 4px; font-size: 14px;
  border-radius: 50%;
}
.tag-chip-remove:hover { color: #ff6c6c; }
.tag-editor-input-row { display: flex; gap: 6px; }
.tag-editor-input { flex: 1; }
.tag-editor-add { padding: 5px 10px; font-size: 12px; }
.tag-library-disclosure { margin-top: 4px; }
.tag-library-disclosure > summary {
  cursor: pointer; font-size: 12px; color: var(--text-muted); user-select: none;
  padding: 4px 0;
  list-style: none;
}
.tag-library-disclosure > summary::-webkit-details-marker { display: none; }
.tag-library-groups {
  margin-top: 6px; max-height: 280px; overflow-y: auto;
  display: flex; flex-direction: column; gap: 8px;
}
.tag-group h5 {
  margin: 0 0 4px 0; font-size: 11px; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--text-muted);
}
.library-tag {
  background: var(--bg-base); border: 1px solid var(--border-default); color: #c0c5d0;
  padding: 3px 9px; border-radius: 12px;
  font-size: 11px; cursor: pointer;
}
.library-tag:hover { border-color: #ededed; color: var(--text-primary); }
.library-tag.selected {
  background: #2a2a2a; border-color: #ededed; color: var(--text-primary);
}

/* ============ FILTER BUTTON + POPOVER ============ */
.search-row { display: flex; gap: 8px; align-items: center; }
.search-row .search-input-wrap { flex: 1; max-width: none; }
.filter-btn {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--bg-elevated); border: 1px solid var(--border-default); color: var(--text-primary);
  padding: 8px 14px; border-radius: 8px; cursor: pointer;
  font-size: 13px; flex-shrink: 0;
}
.filter-btn:hover { border-color: #ededed; }
.filter-badge {
  background: var(--pal-burgundy); color: #ededed; font-size: 11px;
  padding: 1px 7px; border-radius: 8px; margin-left: 2px;
}

.active-filters-row {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 10px;
}
.active-filter-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px; border-radius: 12px; font-size: 11px;
  border: 1px solid;
}
.active-filter-chip.include { background: #18241e; border-color: #2dd47d; color: #2dd47d; }
.active-filter-chip.exclude { background: #2a1818; border-color: #ff6c6c; color: #ff6c6c; }
.active-filter-chip-remove {
  background: transparent; border: none; cursor: pointer;
  padding: 0 2px; font-size: 13px; color: inherit; opacity: 0.7;
}
.active-filter-chip-remove:hover { opacity: 1; }

.filter-popover {
  position: absolute; top: 110px; right: 16px; z-index: 60;
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.45);
  width: 480px; max-width: 90vw; max-height: 70vh;
  display: flex; flex-direction: column;
}
.filter-popover-header {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-bottom: 1px solid var(--border-default);
}
.filter-popover-body {
  flex: 1; overflow-y: auto; padding: 12px 14px;
}
.filter-popover-footer {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px; border-top: 1px solid var(--border-default);
}
.filter-tag {
  background: var(--bg-base); border: 1px solid var(--border-default); color: #c0c5d0;
  padding: 3px 9px; border-radius: 12px;
  font-size: 11px; cursor: pointer; user-select: none;
  position: relative;
}
.filter-tag:hover { border-color: #ededed; }
.filter-tag.include {
  background: #18241e; border-color: #2dd47d; color: #2dd47d;
}
.filter-tag.include::before { content: "+ "; }
.filter-tag.exclude {
  background: #2a1818; border-color: #ff6c6c; color: #ff6c6c;
}
.filter-tag.exclude::before { content: "− "; }

/* ============ BUSY OVERLAY ============ */
.busy-overlay {
  position: fixed; inset: 0; z-index: 250;
  background: rgba(14, 15, 19, 0.85);
  display: flex; align-items: center; justify-content: center;
  backdrop-filter: blur(3px);
}
.busy-card {
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 12px;
  padding: 32px 36px; text-align: center; min-width: 280px; max-width: 440px;
}
.busy-spinner {
  width: 40px; height: 40px; margin: 0 auto 16px;
  border: 3px solid var(--border-default); border-top-color: #ededed;
  border-radius: 50%; animation: spin 0.9s linear infinite;
}
.busy-text { font-size: 15px; font-weight: 600; color: var(--text-primary); }
.busy-sub  { font-size: 12px; color: var(--text-muted); margin-top: 8px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ============ AVATAR LIGHTBOX ============ */
.lightbox {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(0, 0, 0, 0.92);
  display: flex; align-items: center; justify-content: center;
  cursor: zoom-out; padding: 40px;
}
.lightbox-img {
  max-width: 90vw; max-height: 90vh;
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
  cursor: default;
  object-fit: contain;
}
.lightbox-close {
  position: absolute; top: 16px; right: 16px;
  background: rgba(255, 255, 255, 0.1); color: #fff; border: none;
  width: 36px; height: 36px; border-radius: 50%;
  font-size: 18px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.lightbox-close:hover { background: rgba(255, 255, 255, 0.2); }
.zoomable { cursor: zoom-in; }
/* Mobile: smaller padding so the image gets more room, and push the
   close button below the iOS notch / status bar. */
@media (max-width: 720px) {
  .lightbox { padding: 12px; }
  .lightbox-img { max-width: 100vw; max-height: 100vh; border-radius: 8px; }
  .lightbox-close {
    top: calc(12px + env(safe-area-inset-top, 0px));
    right: 12px;
    width: 44px; height: 44px;
    background: rgba(0, 0, 0, 0.55);
  }
}

/* ============ CHARACTER-CREATION AGENT (bottom drawer) ============ */
.agent-dock {
  position: fixed; right: 20px; bottom: 0; z-index: 180;
  width: 380px; max-width: calc(100vw - 40px);
  display: flex; flex-direction: column;
  pointer-events: none;
}
.agent-dock > * { pointer-events: auto; }

/* Minimal pill toggle — flat charcoal with a camel hairline on hover.
   No gradient, no animation, no sheen. Editorial pill, not AI sparkle. */
.agent-toggle {
  align-self: flex-end;
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border-default);
  border-bottom: none;
  padding: 9px 18px;
  border-top-left-radius: 12px; border-top-right-radius: 12px;
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
  cursor: pointer; font-size: 13px; font-weight: 500;
  letter-spacing: 0.005em;
  box-shadow: 0 -4px 14px rgba(0,0,0,0.30);
}
.agent-toggle:hover {
  border-color: var(--pal-camel);
  color: var(--pal-camel);
}
.agent-toggle-icon { display: none; }   /* drop the ✨ — keep it minimal */
.agent-toggle-label {
  font-family: "Fraunces", Georgia, serif;
  font-variation-settings: "opsz" 96;
  font-style: italic; font-weight: 400;
  font-size: 14px;
}
.agent-toggle-chev {
  font-size: 9px; opacity: 0.6;
  transition: transform 200ms cubic-bezier(.4,0,.2,1);
}
.agent-dock:not(.collapsed) .agent-toggle-chev { transform: rotate(180deg); }

.agent-panel {
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-bottom: none;
  border-top-left-radius: 12px; border-top-right-radius: 12px;
  display: flex; flex-direction: column;
  height: 460px; max-height: 65vh;
  box-shadow: 0 -16px 36px rgba(0,0,0,0.45);
  overflow: hidden;
  transition: transform .22s cubic-bezier(.4,0,.2,1), opacity .22s ease;
}
.agent-dock.collapsed .agent-panel {
  transform: translateY(100%); opacity: 0; pointer-events: none;
  height: 0; border: none;
}
.agent-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding: 14px 16px 10px;
  border-bottom: 1px solid var(--border-subtle);
}
.agent-title {
  font-family: "Fraunces", Georgia, serif;
  font-variation-settings: "opsz" 144;
  font-style: italic; font-weight: 400;
  font-size: 17px; letter-spacing: -0.01em;
}
.agent-sub {
  font-size: 11px; margin-top: 2px;
  color: var(--text-muted);
}
.agent-header-actions { display: flex; gap: 2px; flex-shrink: 0; }
.agent-header-actions button {
  padding: 4px 8px; font-size: 13px;
  background: transparent; border: none;
  color: var(--text-muted);
}
.agent-header-actions button:hover {
  background: rgba(255,255,255,0.04);
  color: var(--text-primary);
}

.agent-body {
  flex: 1; display: flex; flex-direction: column; min-height: 0;
  position: relative;  /* anchor for the drop overlay */
}
.agent-drop-overlay {
  position: absolute; inset: 0; z-index: 5;
  background: rgba(237, 237, 237, 0.08);    /* faint camel wash */
  border: 1px dashed var(--pal-camel);
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
  backdrop-filter: blur(3px);
}
.agent-drop-card {
  background: var(--bg-elevated);
  color: var(--pal-camel);
  border: 1px solid var(--pal-camel);
  border-radius: 8px;
  padding: 12px 22px;
  font-family: "Fraunces", Georgia, serif;
  font-style: italic; font-weight: 400;
  font-size: 14px;
}

/* Image attachment chip — sits between messages and input, like Claude/ChatGPT */
.agent-attachment-row {
  padding: 8px 14px 0; display: flex; gap: 8px; flex-wrap: wrap;
}
.agent-attachment-chip {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--bg-base); border: 1px solid #2a2a2a; border-radius: 12px;
  padding: 6px 10px 6px 6px; max-width: 100%;
}
.agent-attachment-chip img {
  width: 44px; height: 44px; object-fit: cover; border-radius: 8px;
  background: #232733; flex-shrink: 0;
}
.agent-attachment-label {
  font-size: 12px; color: #c0c5d0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 200px;
}
.agent-attachment-x {
  background: transparent; border: none; color: var(--text-muted);
  cursor: pointer; padding: 2px 6px; border-radius: 50%;
  font-size: 13px; line-height: 1;
}
.agent-attachment-x:hover { background: #2a1818; color: #ff6c6c; }

.agent-icon-btn {
  background: #232733; border: 1px solid #2a2a2a; color: var(--text-primary);
  padding: 0 12px; border-radius: 8px; cursor: pointer;
  font-size: 16px; flex-shrink: 0;
}
.agent-icon-btn:hover { background: #2a2a2a; }

/* History popover */
.agent-history-popover {
  position: absolute; top: 50px; right: 14px; z-index: 6;
  width: 260px; max-height: 320px;
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.5);
  display: flex; flex-direction: column; overflow: hidden;
}
.agent-history-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 12px; border-bottom: 1px solid var(--border-default);
  font-size: 12px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em;
}
.agent-history-header button { padding: 2px 8px; font-size: 12px; text-transform: none; }
.agent-history-list { flex: 1; overflow-y: auto; padding: 4px; }
.agent-history-item {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  border: 1px solid transparent;
}
.agent-history-item:hover { background: var(--bg-hover); }
.agent-history-item.active { background: var(--bg-active); border-color: #2a2a2a; }
.agent-history-item img {
  width: 32px; height: 32px; border-radius: 8px;
  object-fit: cover; background: #232733; flex-shrink: 0;
}
.agent-history-item-meta { flex: 1; min-width: 0; }
.agent-history-item-title {
  font-size: 13px; color: var(--text-primary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.agent-history-item-time {
  font-size: 11px; color: var(--text-muted); margin-top: 1px;
}
.agent-history-item-del {
  background: transparent; border: none; color: #555; cursor: pointer;
  padding: 2px 6px; font-size: 13px; opacity: 0;
}
.agent-history-item:hover .agent-history-item-del { opacity: 1; }
.agent-history-item-del:hover { color: #ff6c6c; }
.agent-history-empty {
  padding: 20px 12px; text-align: center; font-size: 12px; color: var(--text-muted);
}

.agent-messages {
  flex: 1; overflow-y: auto; padding: 12px 14px;
  display: flex; flex-direction: column; gap: 8px;
  font-size: 13px;
}
.agent-msg {
  padding: 8px 12px; border-radius: 8px; line-height: 1.5;
  white-space: pre-wrap; word-wrap: break-word; max-width: 92%;
}
.agent-msg.user      { background: var(--pal-burgundy); color: var(--text-primary); align-self: flex-end; }
.agent-msg.assistant { background: var(--bg-hover); color: var(--text-secondary); align-self: flex-start; }
.agent-msg.system    { background: transparent; color: var(--text-muted);
                       font-size: 12px; font-style: italic; align-self: center; }
.agent-msg.assistant.streaming .agent-msg-text::after {
  content: "▍"; opacity: .6; animation: blink 1s step-end infinite; margin-left: 2px;
}
.agent-bubble-image {
  display: block; max-width: 220px; max-height: 220px;
  border-radius: 8px; margin-bottom: 6px;
  border: 1px solid rgba(255,255,255,0.18);
  cursor: zoom-in;
}
.agent-msg-text:empty { display: none; }
.agent-empty { color: var(--text-muted); font-size: 12px; text-align: center; padding: 24px 12px; }

.agent-input-bar {
  display: flex; gap: 8px; padding: 10px 14px;
  border-top: 1px solid var(--border-default); background: var(--bg-base);
}
.agent-input-bar input { flex: 1; padding: 9px 12px; font-size: 13px; }
.agent-input-bar button { padding: 9px 14px; font-size: 13px; }
.agent-input-bar button:disabled { opacity: .55; cursor: wait; }

.agent-action-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-top: 1px solid #2dd47d;
  background: linear-gradient(90deg, #18241e 0%, #1d2c20 100%);
  animation: agentActionPulse 2s ease-in-out 1;
}
.agent-action-bar button { margin-left: auto; padding: 8px 16px; font-weight: 600; }
.agent-action-bar #agent-use-profile {
  box-shadow: 0 0 0 0 rgba(45, 212, 125, 0.7);
  animation: agentBtnGlow 2.4s ease-out 2;
}
.agent-action-bar #agent-use-profile:disabled {
  animation: none; box-shadow: none;
  background: #1a2a1f; color: #6db395; border-color: #2a4838;
  cursor: default;
}
@keyframes agentActionPulse {
  0%   { background: linear-gradient(90deg, #1d2c20 0%, #2dd47d40 100%); }
  100% { background: linear-gradient(90deg, #18241e 0%, #1d2c20 100%); }
}
@keyframes agentBtnGlow {
  0%   { box-shadow: 0 0 0 0 rgba(45, 212, 125, 0.7); }
  70%  { box-shadow: 0 0 0 12px rgba(45, 212, 125, 0); }
  100% { box-shadow: 0 0 0 0 rgba(45, 212, 125, 0); }
}

@media (max-width: 700px) {
  .agent-dock {
    right: 0; left: 0; width: auto; max-width: none;
    /* Park the Character Creator pill ABOVE the bottom nav instead of
       stacking on top of it. Same offset in both collapsed and
       expanded states so the dock never crashes into the nav. */
    bottom: calc(58px + env(safe-area-inset-bottom, 0px));
  }
  .agent-dock:not(.collapsed) {
    bottom: calc(58px + env(safe-area-inset-bottom, 0px));
  }
  /* Original minimal pill styling — restored. The OG manual-create
     entry point now lives on the Profile page and in the Chats tab
     header, so this pill is purely the AI Character Creator. */
  .agent-toggle {
    border-radius: 12px 12px 0 0;
    background: rgba(20, 24, 30, 0.96);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    padding: 10px 22px;
  }
  .agent-panel {
    height: 80vh; max-height: 80vh; border-radius: 18px 18px 0 0;
    position: relative;
    transition: transform 220ms ease;
  }
  /* Grabber pill — visible cue that the drawer can be swiped down to
     close. JS listens on .agent-header for the drag and calls
     agentCloseDock() past the threshold. */
  .agent-panel::before {
    content: "";
    position: absolute; top: 8px; left: 50%;
    transform: translateX(-50%);
    width: 44px; height: 4px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.25);
    pointer-events: none;
  }
  .agent-header {
    padding-top: 22px !important;  /* clear the grabber pill */
    cursor: grab;
  }
}

/* ============ GROUP CHAT VIEW ============ */
.group-view { width: 100%; padding: 20px 24px; display: flex; flex-direction: column; height: calc(100vh - 56px); }
.group-header {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 12px; margin-bottom: 14px;
}
.group-header h1 { margin: 0; font-size: 22px; }
.group-participants {
  display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px;
}
.group-participant {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--bg-active); border: 1px solid #2a2a2a;
  padding: 4px 12px 4px 4px; border-radius: 12px;
  font-size: 13px;
}
.group-participant-avatar {
  width: 26px; height: 26px; border-radius: 50%;
  object-fit: cover; background: #232733;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; color: var(--text-muted);
}
.group-chat-window {
  flex: 1; display: flex; flex-direction: column; min-height: 0;
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 12px;
  overflow: hidden;
}
.group-speaker-name {
  font-size: 11px; color: var(--text-muted); font-weight: 600;
  margin: 0 4px 2px;
  text-transform: uppercase; letter-spacing: 0.04em;
}

/* Group picker */
.group-pick-list {
  display: flex; flex-direction: column; gap: 4px;
  max-height: 360px; overflow-y: auto;
  margin-bottom: 14px;
}
.group-pick-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  border: 1px solid transparent;
}
.group-pick-item:hover { background: var(--bg-hover); }
.group-pick-item input[type="checkbox"] { margin: 0; }

/* ============ TOAST ============ */
.toast-container {
  position: fixed; bottom: 20px; right: 20px; z-index: 200;
  display: flex; flex-direction: column; gap: 8px; pointer-events: none;
}
.toast {
  background: #232733; color: var(--text-primary);
  padding: 10px 16px 10px 14px;
  border-radius: 8px; box-shadow: 0 6px 18px rgba(0,0,0,0.4);
  border-left: 3px solid #ededed;
  opacity: 0; transform: translateX(24px);
  transition: opacity .22s ease, transform .22s ease;
  font-size: 13px; max-width: 380px;
  pointer-events: auto;
}
.toast.show    { opacity: 1; transform: translateX(0); }
.toast.success { border-color: #2dd47d; }
.toast.error   { border-color: #ff6c6c; }
.toast.info    { border-color: #ededed; }
.toast.warn    { border-color: #f5a524; }
/* On phones, anchor toasts above the mobile bottom-nav so they don't sit
   under the home indicator / nav blur. */
@media (max-width: 700px) {
  .toast-container {
    bottom: calc(76px + env(safe-area-inset-bottom));
    left: 12px; right: 12px;
    align-items: stretch;
  }
  .toast { max-width: none; }
}


/* =========================================================
   LIGHT THEME — overrides applied when body[data-theme="light"].
   Targets the highest-impact selectors that drive the dark feel.
   Anything we miss gracefully falls back to the dark hex; users will
   point those out and we polish over time.
========================================================= */
body[data-theme="light"] {
  --bg-base:        #f9fafb;
  --bg-surface:     #ffffff;
  --bg-elevated:    #ffffff;
  --bg-hover:       #f3f4f6;
  --bg-active:      #eef2ff;
  --text-primary:   #111827;
  --text-secondary: #374151;
  --text-muted:     var(--text-faint);
  --text-faint:     #9ca3af;
  --border-default: #e5e7eb;
  --border-subtle:  #f3f4f6;
  background: #f9fafb;
  color: #111827;
}

/* Page-level surfaces */
body[data-theme="light"] .app-shell,
body[data-theme="light"] .app-shell-main,
body[data-theme="light"] main,
body[data-theme="light"] .gallery {
  background: #f9fafb !important;
  color: #111827;
}
/* Light-mode chat surface — pure white, à la Character.AI. The .chat-messages
   rule inherits from .chat-window (no own bg) so a single override covers
   both. Keeps the chat section visually distinct from the slightly off-white
   gallery / library pages around it. */
body[data-theme="light"] .chat-window {
  background: #ffffff !important;
  color: #111827;
}

/* Sidebar */
body[data-theme="light"] .app-sidebar {
  background: #ffffff !important;
  border-right: 1px solid #e5e7eb !important;
}
body[data-theme="light"] .sidebar-link,
body[data-theme="light"] .sidebar-brand {
  color: #374151 !important;
}
body[data-theme="light"] .sidebar-link:hover,
body[data-theme="light"] .sidebar-brand:hover { background: #f3f4f6 !important; }
body[data-theme="light"] .sidebar-link.active { background: #eef2ff !important; color: #4338ca !important; }
body[data-theme="light"] .sidebar-character-item:hover { background: #f3f4f6 !important; }
body[data-theme="light"] .sidebar-character-item.active { background: #eef2ff !important; }
body[data-theme="light"] .sidebar-brand-mark { color: #4338ca !important; }
/* Right rail / sidebar character labels — default tint is too pale on white. */
body[data-theme="light"] .sidebar-character-name { color: #111827 !important; }
body[data-theme="light"] .sidebar-character-empty { color: #4b5563 !important; }
body[data-theme="light"] .sidebar-section-label,
body[data-theme="light"] .sidebar-section-header { color: #4b5563 !important; }

/* Topbar */
body[data-theme="light"] .topbar {
  background: #ffffff !important;
  border-bottom: 1px solid #e5e7eb !important;
}
body[data-theme="light"] #brand-text,
body[data-theme="light"] .topbar { color: #111827; }

/* Cards */
body[data-theme="light"] .character-card {
  background: #ffffff !important;
  border: 1px solid #e5e7eb !important;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06);
}
body[data-theme="light"] .character-card:hover { border-color: #c7d2fe !important; }
body[data-theme="light"] .char-card-tagline { color: #4b5563 !important; }
body[data-theme="light"] .char-card-credit { color: var(--text-faint) !important; }
body[data-theme="light"] .char-card-stat { color: var(--text-faint) !important; }
body[data-theme="light"] .char-card-menu-btn { background: rgba(255,255,255,0.85) !important; color: #1f2937 !important; }
body[data-theme="light"] .char-card-fav { background: rgba(255,255,255,0.85) !important; color: #1f2937 !important; }

/* Modals */
body[data-theme="light"] .modal { background: rgba(17, 24, 39, 0.45); }
body[data-theme="light"] .modal-card {
  background: #ffffff !important;
  border: 1px solid #e5e7eb !important;
  color: #111827;
}
body[data-theme="light"] .modal-card h2,
body[data-theme="light"] .modal-card label { color: #111827 !important; }
body[data-theme="light"] .modal-card input,
body[data-theme="light"] .modal-card textarea,
body[data-theme="light"] .modal-card select {
  background: #ffffff !important;
  color: #111827 !important;
  border: 1px solid #e5e7eb !important;
}

/* Form fields globally */
body[data-theme="light"] input[type="text"],
body[data-theme="light"] input[type="email"],
body[data-theme="light"] input[type="password"],
body[data-theme="light"] input[type="search"],
body[data-theme="light"] textarea,
body[data-theme="light"] select {
  background: #ffffff !important;
  color: #111827 !important;
  border: 1px solid #e5e7eb !important;
}

/* Chat bubbles — user bubble was previously white-on-grey, unreadable.
   Use an indigo accent like iMessage's blue. Assistant stays card-white. */
body[data-theme="light"] .chat-bubble.user {
  background: #4338ca !important;
  color: #ffffff !important;
  border-color: #4338ca !important;
}
body[data-theme="light"] .chat-bubble.assistant {
  background: #ffffff !important;
  color: #111827 !important;
  border: 1px solid #e5e7eb !important;
}
/* Mobile bottom-nav in light mode — needs darker icon tone or it
   disappears against the cream surface. */
body[data-theme="light"] .mobile-nav-btn { color: #6b7280; }
body[data-theme="light"] .mobile-nav-btn.is-active { color: #4338ca; }

/* Chat input bar + variant button */
body[data-theme="light"] .chat-input-bar {
  background: #ffffff !important;
  border-top: 1px solid #e5e7eb !important;
}
body[data-theme="light"] #chat-input {
  background: #ffffff !important;
  color: #111827 !important;
  border: 1px solid #e5e7eb !important;
}
body[data-theme="light"] .chat-bubble-action { color: var(--text-faint) !important; }
body[data-theme="light"] .chat-bubble-action:hover { background: #f3f4f6 !important; color: #111827 !important; }
body[data-theme="light"] .chat-bubble-menu,
body[data-theme="light"] .chat-bubble-variants-btn,
body[data-theme="light"] .chat-variants-popover {
  background: #ffffff !important;
  border: 1px solid #e5e7eb !important;
  color: #111827 !important;
}
body[data-theme="light"] .chat-bubble-menu-item { color: #1f2937 !important; }
body[data-theme="light"] .chat-bubble-menu-item:hover { background: #f3f4f6 !important; }

/* Gallery tabs + filters */
body[data-theme="light"] .gallery-tab { color: var(--text-faint) !important; }
body[data-theme="light"] .gallery-tab.active { color: #4338ca !important; border-color: #4338ca !important; }
body[data-theme="light"] .filter-btn { background: #ffffff !important; border: 1px solid #e5e7eb !important; color: #1f2937 !important; }

/* Misc text */
body[data-theme="light"] .muted { color: var(--text-faint) !important; }
body[data-theme="light"] h1, body[data-theme="light"] h2, body[data-theme="light"] h3 { color: #111827; }

/* Session menu / popovers */
body[data-theme="light"] .session-menu,
body[data-theme="light"] .vibe-popover,
body[data-theme="light"] .filter-popover {
  background: #ffffff !important;
  border: 1px solid #e5e7eb !important;
  color: #111827 !important;
}
body[data-theme="light"] .menu-session-item:hover { background: #f3f4f6 !important; }
body[data-theme="light"] .menu-session-item.active { background: #eef2ff !important; }
body[data-theme="light"] .menu-session-item .name { color: #111827 !important; }
body[data-theme="light"] .menu-session-item .meta { color: var(--text-faint) !important; }

/* In-chat search bar — sits at the top of the chat-window when toggled. */
.chat-search-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 8px 12px;
  background: var(--bg-elevated);
  border-bottom: 1px solid var(--border-default);
}
.chat-search-bar input[type="search"] {
  flex: 1; min-width: 0;
  background: var(--bg-base);
  color: var(--text-primary);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 13px;
}
.chat-search-counter {
  font-size: 11px; color: var(--text-muted);
  min-width: 56px; text-align: center;
  font-variant-numeric: tabular-nums;
}
.chat-search-bar button { padding: 4px 10px !important; font-size: 12px; }
body[data-theme="light"] .chat-search-bar { background: #ffffff; border-bottom-color: #e5e7eb; }
body[data-theme="light"] .chat-search-bar input[type="search"] {
  background: #ffffff; border-color: #e5e7eb; color: #111827;
}
body[data-theme="light"] .chat-search-counter { color: var(--text-faint); }
/* Highlight matching messages — gradient outline on the bubble */
.chat-row.search-match .chat-bubble {
  outline: 2px solid #ededed;
  outline-offset: 1px;
  box-shadow: 0 0 12px rgba(237, 237, 237, 0.4);
}
.chat-row.search-current .chat-bubble {
  outline-color: #db2777;
  box-shadow: 0 0 18px rgba(219, 39, 119, 0.55);
}

/* Keyboard shortcuts cheatsheet modal */
.shortcut-list {
  display: flex; flex-direction: column;
  gap: 4px;
  margin-top: 8px;
}
.shortcut-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 13px;
  color: var(--text-secondary);
}
.shortcut-row:nth-child(odd) { background: var(--bg-elevated); }
.shortcut-row kbd {
  display: inline-block;
  background: var(--bg-active);
  border: 1px solid #2a2a2a;
  border-bottom-width: 2px;
  border-radius: 4px;
  padding: 2px 7px;
  font-size: 11px;
  font-family: ui-monospace, Consolas, monospace;
  color: var(--text-primary);
  margin-left: 4px;
}
body[data-theme="light"] .shortcut-row { color: #1f2937; }
body[data-theme="light"] .shortcut-row:nth-child(odd) { background: #f3f4f6; }
body[data-theme="light"] .shortcut-row kbd {
  background: #ffffff; border-color: #e5e7eb; color: #111827;
}

/* Theme toggle button itself */
.theme-toggle-btn {
  background: transparent;
  border: 1px solid var(--border-default);
  color: #c0c5d0;
  width: 32px; height: 32px;
  border-radius: 50%;
  font-size: 15px;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background .12s, border-color .12s, color .12s, transform .1s;
}
.theme-toggle-btn:hover {
  background: var(--bg-active); color: #fff; transform: rotate(15deg);
}
body[data-theme="light"] .theme-toggle-btn {
  background: #ffffff;
  border-color: #e5e7eb;
  color: #4338ca;
}
body[data-theme="light"] .theme-toggle-btn:hover {
  background: #eef2ff; border-color: #ededed;
}

/* ============================================================
   STORY MODE — novel-style reader + branching timelines
   ============================================================ */
.story-layout {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 0;
  height: calc(100vh - 60px);
  background: var(--bg-base);
  position: relative;
  transition: grid-template-columns 220ms cubic-bezier(.4,0,.2,1);
}
/* Collapsed: sidebar collapses to zero width, reader expands to fill. */
.story-layout.sidebar-collapsed {
  grid-template-columns: 0 minmax(0, 1fr);
}
.story-sidebar {
  border-right: 1px solid #1f2330;
  background: var(--bg-elevated);
  display: flex; flex-direction: column;
  overflow: hidden;
  transition: opacity 180ms ease, visibility 180ms;
}
.story-layout.sidebar-collapsed .story-sidebar {
  opacity: 0; visibility: hidden;     /* fade out + remove from a11y tree */
}
.story-sidebar-header {
  display: flex; align-items: center; gap: 8px;
  padding: 14px 16px;
  border-bottom: 1px solid #1f2330;
  font-weight: 600; color: var(--text-secondary);
}
.story-sidebar-title { flex: 1; }
.story-sidebar-header button { font-size: 12px; padding: 6px 10px; }
.story-sidebar-collapse-btn {
  background: transparent !important;
  border: none !important;
  padding: 4px !important;
  color: var(--text-muted);
}
.story-sidebar-collapse-btn:hover { color: var(--text-primary); }

/* Floating expand handle — shown only when sidebar is collapsed.
   Sits flush against the left edge of the reader so the user can
   bring the list back without hunting. */
.story-sidebar-expand-btn {
  position: absolute;
  left: 0; top: 14px;
  display: flex; align-items: center; justify-content: center;
  width: 26px; height: 32px;
  border: 1px solid var(--border-default);
  border-left: none;
  border-radius: 0 8px 8px 0;
  background: var(--bg-elevated);
  color: var(--text-muted);
  cursor: pointer; padding: 0;
  z-index: 5;
  transition: background 180ms, color 180ms;
}
.story-sidebar-expand-btn:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.story-list { flex: 1; overflow-y: auto; padding: 8px; }
.story-empty { padding: 16px; color: var(--text-muted); font-size: 13px; line-height: 1.45; }
.story-list-item {
  padding: 10px 12px; border-radius: 8px; cursor: pointer;
  margin-bottom: 4px; border: 1px solid transparent;
  transition: background .12s, border-color .12s;
}
.story-list-item:hover { background: var(--bg-hover); }
.story-list-item.active { background: #1f2535; border-color: #ededed; }
.story-list-item .story-list-title {
  font-weight: 600; color: var(--text-primary); font-size: 14px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.story-list-item .story-list-meta {
  font-size: 11px; color: var(--text-muted); margin-top: 2px;
}
/* Reader pane — wide centered column for prose readability */
.story-reader {
  display: flex; flex-direction: column;
  overflow: hidden; min-width: 0;
}
.story-reader-header {
  padding: 22px 32px 14px;
  border-bottom: 1px solid #1f2330;
}
.story-title-row {
  display: flex; align-items: center; gap: 12px; justify-content: space-between;
}
.story-title-row h2 {
  margin: 0; font-size: 22px; font-weight: 700; color: var(--text-primary);
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
}
.story-actions { display: flex; gap: 6px; flex-shrink: 0; }
.story-actions button {
  font-size: 12px; padding: 6px 12px; border-radius: 8px;
}
/* Mobile: the title row was a single flex line with the action buttons
   overflowing on top of the title. Stack title above actions, allow
   actions to wrap, and let the expand-Stories pill share the bar. */
@media (max-width: 720px) {
  .story-title-row {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
  }
  .story-title-row h2 { font-size: 18px; line-height: 1.25; }
  .story-actions {
    flex-wrap: wrap; gap: 4px;
  }
  .story-actions button {
    font-size: 11px; padding: 6px 8px;
    flex: 1 1 auto;
    min-height: 36px;
  }
  /* The Stories pill / Story button no longer floats over the title —
     it docks above as part of the header. */
  .story-sidebar-expand-btn {
    position: static !important;
    transform: none !important;
    margin: 0 0 10px;
    align-self: flex-start;
  }
  .story-reader-header { padding-top: 8px; }
}
.story-premise {
  margin: 8px 0 0; color: var(--text-muted); font-size: 13px; font-style: italic;
}

/* Cast roster strip — small chips listing every cast member at the top of
   the story view. Clicking the strip opens the cast modal. */
.story-cast-strip {
  display: flex; flex-wrap: wrap; gap: 6px;
  margin-top: 10px;
}
.story-cast-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(237, 237, 237, 0.10);
  border: 1px solid rgba(237, 237, 237, 0.30);
  color: var(--text-secondary);
  border-radius: 999px;
  padding: 4px 10px;
  font-size: 12px;
  cursor: pointer;
}
.story-cast-chip:hover { background: rgba(237, 237, 237, 0.18); }
.story-cast-chip-role {
  color: var(--text-muted); font-style: italic;
}
.story-cast-chip-lead {
  background: rgba(237, 237, 237, 0.15);
  border-color: rgba(237, 237, 237, 0.40);
}
/* Focused chip — the user picked this character to drive the next beat.
   Indigo highlight + ring so it reads clearly against the dim base chip. */
.story-cast-chip-focused {
  background: rgba(99, 102, 241, 0.22) !important;
  border-color: rgba(99, 102, 241, 0.65) !important;
  color: #fff;
  box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.20);
}

/* Cast modal */
.story-cast-modal { max-width: 640px; max-height: 80vh; display: flex; flex-direction: column; }
.story-cast-modal footer { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
.story-cast-picker {
  flex: 1; overflow-y: auto;
  border: 1px solid var(--border-default); border-radius: 8px;
  background: var(--bg-base);
  padding: 4px;
  min-height: 200px;
}
.story-cast-picker-item {
  display: grid; grid-template-columns: auto 36px 1fr; gap: 10px;
  align-items: start;
  padding: 10px; border-radius: 8px;
  border: 1px solid transparent;
}
.story-cast-picker-item:hover { background: rgba(255,255,255,0.03); }
.story-cast-picker-item.is-checked { border-color: rgba(237, 237, 237, 0.4); background: rgba(237, 237, 237, 0.08); }
.story-cast-picker-item.is-lead { opacity: 0.7; cursor: not-allowed; }
.story-cast-picker-avatar {
  width: 36px; height: 36px; border-radius: 50%;
  object-fit: cover; background: var(--bg-hover);
}
.story-cast-picker-meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.story-cast-picker-name { font-weight: 600; color: var(--text-primary); font-size: 13px; }
.story-cast-picker-tag { font-size: 11px; color: var(--text-muted); }
.story-cast-picker-fields { display: flex; gap: 6px; margin-top: 6px; }
.story-cast-picker-fields input {
  flex: 1;
  background: var(--bg-base); border: 1px solid var(--border-default);
  border-radius: 8px; padding: 5px 8px;
  color: var(--text-primary); font-size: 12px; font-family: inherit;
}
.story-cast-picker-fields input:focus { outline: none; border-color: #ededed; }
.story-cast-picker-fields input[disabled] { opacity: 0.4; }
.story-body {
  flex: 1; overflow-y: auto;
  padding: 24px 0;
  background: var(--bg-base);
}
.story-empty-reader {
  padding: 40px 20px;
  color: var(--text-muted);
  text-align: center;
  font-size: 14px;
  display: flex;
  justify-content: center;
  align-items: flex-start;
}
.story-empty-card {
  max-width: 420px;
  width: 100%;
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: 16px;
  padding: 28px 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}
.story-empty-glyph {
  font-size: 38px;
  line-height: 1;
  margin-bottom: 2px;
}
.story-empty-title {
  margin: 0;
  font-size: 18px;
  font-weight: 700;
  color: var(--text-primary);
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  text-transform: none;
  letter-spacing: 0;
  border: none;
}
.story-empty-sub {
  margin: 0;
  color: var(--text-muted);
  font-size: 13.5px;
  line-height: 1.45;
}
.story-empty-cta {
  font-size: 15px;
  padding: 12px 22px;
  border-radius: 10px;
  margin-top: 8px;
  width: 100%;
  max-width: 280px;
  min-height: 44px;          /* iOS HIG minimum tap target */
  -webkit-tap-highlight-color: transparent;
}
.story-empty-hint {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--text-faint);
}
@media (max-width: 720px) {
  .story-empty-reader {
    /* Pull the card up so it sits above the bottom nav, not buried under it.
       safe-area-inset-bottom respects the iOS home-indicator gap. */
    padding: 24px 14px calc(80px + env(safe-area-inset-bottom, 0px));
    min-height: 60vh;
    align-items: center;
  }
  .story-empty-card {
    padding: 24px 18px;
  }
  /* When the empty state is showing, the redundant "Pick a story…" h2 in
     the reader header just steals space — the hero card already carries
     the headline. Hide it on mobile via :has(). */
  .story-reader:has(> #story-body > .story-empty-reader) #story-title-display {
    display: none;
  }
  /* Make the Stories pill stand out as a real button, not a hint. */
  .story-sidebar-expand-btn {
    min-height: 36px;
    padding: 8px 16px !important;
    font-size: 13px !important;
    font-weight: 600;
    border: 1px solid rgba(255,255,255,0.16) !important;
    background: var(--bg-elevated) !important;
    color: var(--text-primary) !important;
    -webkit-tap-highlight-color: transparent;
  }
  /* When the user has zero stories, the "▶ Stories" pill and the
     "Already have one? Tap Stories above" hint are both misleading —
     they imply existing stories. body.has-stories is toggled by
     refreshStories() based on STORY_LIST.length. */
  body:not(.has-stories) .story-sidebar-expand-btn { display: none !important; }
  body:not(.has-stories) .story-empty-hint { display: none !important; }
}
.story-chapter-card {
  max-width: 720px; margin: 0 auto 24px; padding: 0 32px;
}
.story-chapter-header {
  display: flex; align-items: baseline; gap: 12px;
  border-bottom: 1px solid var(--border-default);
  padding-bottom: 8px; margin-bottom: 16px;
}
.story-chapter-num {
  color: #ededed; font-weight: 700; font-size: 12px;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.story-chapter-title {
  font-family: Georgia, serif; color: var(--text-primary); font-size: 18px;
  font-weight: 700; flex: 1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.story-chapter-summary {
  color: var(--text-muted); font-size: 12px; font-style: italic;
  margin: -10px 0 16px;
}
.story-beat {
  position: relative;
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  color: #d8dae0; font-size: 16px; line-height: 1.7;
  margin-bottom: 14px; padding: 6px 8px; border-radius: 8px;
  white-space: pre-wrap; word-wrap: break-word;
}
.story-beat.role-user {
  /* User direction beats — visually subordinate, like stage directions */
  font-family: -apple-system, "Segoe UI", system-ui, sans-serif;
  font-style: italic; color: var(--text-muted); font-size: 14px;
  border-left: 3px solid #ededed; padding-left: 14px;
}
.story-beat.role-narrator {
  /* Narrator prose — the main reading body */
  color: var(--text-primary);
}
.story-beat.role-character {
  color: #f1d68b;  /* warm tint for character-spoken lines */
}
.story-beat:hover { background: rgba(255,255,255,0.025); }
.story-beat-text { white-space: pre-wrap; word-break: break-word; }
/* Hover actions row — mirrors .chat-bubble-actions shape so the muscle
   memory carries over from regular chat. */
.story-beat-actions {
  position: absolute; top: 4px; right: 4px;
  display: flex; gap: 2px;
  opacity: 0; transition: opacity .15s;
}
.story-beat:hover .story-beat-actions { opacity: 1; }
.story-beat-action {
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--border-subtle);
  color: var(--text-muted);
  padding: 4px 8px; border-radius: 8px; font-size: 12px;
  cursor: pointer; line-height: 1;
}
.story-beat-action:hover {
  background: rgba(255,255,255,0.10);
  color: var(--text-primary);
  border-color: var(--border-default);
}
/* ⋮ dropdown — same pattern as chat bubble menu */
.story-beat-menu-wrap { position: relative; display: inline-block; }
.story-beat-menu {
  position: absolute; right: 0; top: calc(100% + 4px);
  min-width: 180px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.4);
  padding: 4px;
  z-index: 50;
}
.story-beat-menu-item {
  width: 100%;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: transparent; border: none; cursor: pointer;
  padding: 7px 10px; border-radius: 8px;
  color: var(--text-secondary); font-size: 13px; text-align: left;
}
.story-beat-menu-item:hover { background: rgba(255,255,255,0.05); color: var(--text-primary); }
.story-beat-menu-item.danger { color: #ff9090; }
.story-beat-menu-icon { font-size: 13px; opacity: 0.75; }

/* Inline edit textarea + actions */
.story-beat-edit-input {
  width: 100%; min-height: 80px;
  background: var(--bg-base); color: var(--text-primary);
  border: 1px solid var(--border-default);
  border-radius: 8px; padding: 10px 12px;
  font-family: inherit; font-size: 14px; line-height: 1.5;
  resize: vertical;
}
.story-beat-edit-actions {
  display: flex; justify-content: flex-end; gap: 8px;
  margin-top: 8px;
}
/* Streaming preview while a narrator turn is in flight */
.story-beat.streaming::after {
  content: "▍"; opacity: 0.6; animation: blink 1s step-end infinite;
  margin-left: 2px;
}
.story-input-bar {
  display: flex; gap: 8px; padding: 14px 32px;
  border-top: 1px solid #1f2330; background: var(--bg-elevated);
}
.story-input-bar textarea {
  flex: 1; resize: vertical; min-height: 44px; max-height: 160px;
  background: var(--bg-hover); border: 1px solid var(--border-default); color: var(--text-primary);
  border-radius: 8px; padding: 10px 12px; font-size: 14px;
  font-family: inherit;
}
.story-input-bar button { flex-shrink: 0; padding: 0 22px; }
/* Story Mode mobile composer — sticky to the bottom of the reader so
   it stays glued to the keyboard, full-bleed padding, 16px font to
   block iOS auto-zoom. Buttons get 44px tap targets. */
@media (max-width: 720px) {
  .story-input-bar {
    position: sticky; bottom: 0; z-index: 5;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
    background: var(--bg-base);
    box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.25);
    flex-wrap: wrap;
  }
  .story-input-bar textarea {
    font-size: 16px;
    min-height: 40px; max-height: 120px;
    flex: 1 1 100%;
    order: -1;
  }
  .story-input-bar button {
    padding: 10px 14px; min-height: 40px;
    font-size: 13px;
  }
}
/* Branch tree modal */
.branch-tree { padding: 8px 0; }
.branch-tree-row {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border-radius: 8px; cursor: pointer;
  margin-bottom: 4px; border: 1px solid transparent;
  transition: background .12s, border-color .12s;
}
.branch-tree-row:hover { background: var(--bg-hover); }
.branch-tree-row.active { background: #1f2535; border-color: #ededed; }
.branch-tree-indent { color: #ededed; font-family: monospace; }
.branch-tree-name { font-weight: 600; color: var(--text-primary); flex: 1; }
.branch-tree-meta { color: var(--text-muted); font-size: 11px; }
/* Light-mode tweaks */
body[data-theme="light"] .story-layout { background: #f9fafb; }
body[data-theme="light"] .story-sidebar { background: #ffffff; border-right-color: #e5e7eb; }
body[data-theme="light"] .story-sidebar-header { color: #111827; border-bottom-color: #e5e7eb; }
body[data-theme="light"] .story-empty,
body[data-theme="light"] .story-empty-reader { color: var(--text-faint); }
body[data-theme="light"] .story-list-item:hover { background: #f3f4f6; }
body[data-theme="light"] .story-list-item.active { background: #eef2ff; border-color: #ededed; }
body[data-theme="light"] .story-list-item .story-list-title { color: #111827; }
body[data-theme="light"] .story-reader-header { border-bottom-color: #e5e7eb; }
body[data-theme="light"] .story-title-row h2 { color: #111827; }
body[data-theme="light"] .story-premise { color: var(--text-faint); }
body[data-theme="light"] .story-body { background: #f9fafb; }
body[data-theme="light"] .story-chapter-header { border-bottom-color: #e5e7eb; }
body[data-theme="light"] .story-chapter-title { color: #111827; }
body[data-theme="light"] .story-chapter-summary { color: var(--text-faint); }
body[data-theme="light"] .story-beat.role-narrator { color: #1f2937; }
body[data-theme="light"] .story-beat.role-user { color: #4b5563; }
body[data-theme="light"] .story-beat.role-character { color: #92400e; }
body[data-theme="light"] .story-input-bar { background: #ffffff; border-top-color: #e5e7eb; }
body[data-theme="light"] .story-input-bar textarea {
  background: #ffffff; color: #111827; border-color: #e5e7eb;
}
body[data-theme="light"] .branch-tree-name { color: #111827; }
body[data-theme="light"] .branch-tree-row:hover { background: #f3f4f6; }
body[data-theme="light"] .branch-tree-row.active { background: #eef2ff; }

/* CYOA path-choice buttons rendered under each narrator beat. They look
   like cards, not buttons — meant to be the obvious next step. */
.story-choices {
  max-width: 720px; margin: 4px auto 28px; padding: 0 32px;
  display: flex; flex-direction: column; gap: 8px;
}
.story-choices-label {
  font-size: 11px; color: var(--text-muted); text-transform: uppercase;
  letter-spacing: 0.08em; margin-bottom: 4px;
}
.story-choice-btn {
  display: flex; align-items: flex-start; gap: 10px;
  background: linear-gradient(135deg, var(--bg-hover) 0%, #232733 100%);
  border: 1px solid var(--border-default); color: var(--text-primary);
  padding: 12px 16px; border-radius: 8px; cursor: pointer;
  text-align: left; font-size: 14px; line-height: 1.45;
  font-family: inherit;
  transition: border-color .15s, background .15s, transform .12s;
}
.story-choice-btn:hover {
  border-color: #ededed; background: linear-gradient(135deg, #1f2535 0%, #2a2a2a 100%);
  transform: translateX(2px);
}
.story-choice-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
.story-choice-num {
  flex-shrink: 0; width: 22px; height: 22px;
  border-radius: 50%; background: var(--pal-burgundy); color: #ededed;
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 12px;
}
.story-choice-text { flex: 1; }
/* Mode picker on new-story modal */
.story-mode-picker { display: flex; flex-direction: column; gap: 8px; }
.story-mode-opt {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px; border: 1px solid var(--border-default); border-radius: 8px;
  cursor: pointer;
  transition: border-color .12s, background .12s;
}
.story-mode-opt:hover { background: var(--bg-hover); }
.story-mode-opt:has(input:checked) { border-color: #ededed; background: #1f2535; }
.story-mode-opt input { margin-top: 4px; }
.story-mode-title { font-weight: 600; color: var(--text-primary); font-size: 14px; }
.story-mode-sub { color: var(--text-muted); font-size: 12px; margin-top: 2px; }
body[data-theme="light"] .story-choice-btn {
  background: #ffffff; color: #111827; border-color: #e5e7eb;
}
body[data-theme="light"] .story-choice-btn:hover {
  background: #eef2ff; border-color: #ededed;
}
body[data-theme="light"] .story-mode-opt { border-color: #e5e7eb; }
body[data-theme="light"] .story-mode-opt:hover { background: #f3f4f6; }
body[data-theme="light"] .story-mode-opt:has(input:checked) { background: #eef2ff; border-color: #ededed; }
body[data-theme="light"] .story-mode-title { color: #111827; }
body[data-theme="light"] .story-mode-sub { color: var(--text-faint); }

/* ============================================================
   ADMIN CONTROL PANEL (Phase 2 #52)
   Sidebar of sub-sections + content pane. Read-only by default,
   destructive actions inline-confirmed.
   ============================================================ */
.admin-layout {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  height: calc(100vh - 60px);
  background: var(--bg-base);
}
.admin-sidebar {
  background: var(--bg-elevated); border-right: 1px solid #1f2330;
  display: flex; flex-direction: column;
}
.admin-sidebar-header {
  display: flex; align-items: center; gap: 10px;
  padding: 18px 20px; font-weight: 700; color: var(--text-primary);
  border-bottom: 1px solid #1f2330;
}
.admin-sidebar-icon { font-size: 20px; }
.admin-nav { padding: 8px; display: flex; flex-direction: column; gap: 2px; }
.admin-nav-link {
  display: flex; align-items: center; gap: 8px;
  background: transparent; border: none; color: var(--text-secondary);
  padding: 10px 12px; border-radius: 8px; cursor: pointer;
  font-size: 14px; text-align: left;
}
.admin-nav-link:hover { background: var(--bg-hover); color: #fff; }
.admin-nav-link.active { background: #1f2535; color: #fff; }
.admin-badge {
  margin-left: auto;
  background: #ef4444; color: #fff;
  font-size: 11px; font-weight: 700;
  padding: 2px 8px; border-radius: 8px;
  min-width: 22px; text-align: center;
}
.admin-content { overflow-y: auto; padding: 28px 36px; }
.admin-pane h1 {
  margin: 0 0 20px; color: var(--text-primary); font-size: 24px; font-weight: 700;
}
.admin-h1-sub { color: var(--text-muted); font-size: 14px; font-weight: 400; margin-left: 8px; }

/* Stat cards on the overview pane */
.admin-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 14px;
}
.admin-stat-card {
  background: linear-gradient(135deg, var(--bg-hover) 0%, #232733 100%);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  padding: 18px 20px;
}
.admin-stat-num {
  font-size: 32px; font-weight: 800; color: var(--text-primary); line-height: 1.1;
}
.admin-stat-lbl {
  font-size: 12px; color: var(--text-muted); text-transform: uppercase;
  letter-spacing: 0.06em; margin-top: 6px;
}
.admin-stat-card.alert { border-color: #ef4444; }
.admin-stat-card.alert .admin-stat-num { color: #ef4444; }

/* Growth chart — line chart on the Admin Overview tab. SVG is hand-rolled
   (no third-party library) so we ship zero extra bytes for this. */
.admin-growth-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: 12px;
  padding: 18px 18px 12px;
  margin: 28px 0 24px;   /* top gap so it doesn't crowd the stat-card grid */
}
.admin-growth-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap; margin-bottom: 6px;
}
.admin-growth-head h2 {
  margin: 0; font-size: 16px; font-weight: 600; color: var(--text-primary);
}
.admin-growth-tabs { display: flex; gap: 4px; }
.admin-growth-tab {
  background: transparent; border: 1px solid transparent;
  color: var(--text-muted); padding: 5px 12px; border-radius: 6px;
  font-size: 12px; font-weight: 500; cursor: pointer;
}
.admin-growth-tab:hover { color: var(--text-primary); background: var(--bg-hover); }
.admin-growth-tab.active {
  background: var(--bg-active); color: var(--text-primary);
  border-color: rgba(255, 255, 255, 0.12);
}
.admin-growth-legend {
  display: flex; gap: 16px; flex-wrap: wrap;
  margin: 4px 0 10px; font-size: 11px; color: var(--text-muted);
}
.admin-growth-legend-item {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 8px; border-radius: 6px;
  transition: background 120ms, opacity 120ms;
  user-select: none;
}
.admin-growth-legend-item:hover { background: var(--bg-hover); }
/* Hidden-series state — dimmed text, faded swatch, strike-through hint. */
.admin-growth-legend-item.admin-growth-legend-off {
  opacity: 0.4;
  text-decoration: line-through;
}
.admin-growth-legend-item.admin-growth-legend-off .admin-growth-swatch {
  opacity: 0.4;
}
.admin-growth-swatch {
  display: inline-block; width: 10px; height: 10px; border-radius: 2px;
}
.admin-growth-chart-wrap {
  width: 100%; height: 220px; position: relative;
}
.admin-growth-chart {
  width: 100%; height: 100%; display: block;
}
.admin-growth-x {
  position: relative; width: 100%; height: 18px; margin-top: 2px;
}
.admin-growth-x-label {
  position: absolute; transform: translateX(-50%);
  font-size: 10px; color: var(--text-muted); white-space: nowrap;
}
/* Custom hover tooltip — shows all three series' values for the bucket
   under the cursor. Cleaner than per-dot browser <title> tooltips. */
.admin-growth-tooltip {
  position: absolute; top: 8px; pointer-events: none;
  min-width: 140px;
  background: rgba(20, 24, 30, 0.96);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 12px;
  color: var(--text-primary);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
  z-index: 5;
}
.admin-growth-tooltip-label {
  font-weight: 600; font-size: 11px;
  color: var(--text-secondary);
  margin-bottom: 6px;
}
.admin-growth-tooltip-row {
  display: grid; grid-template-columns: 12px 1fr auto;
  align-items: center; gap: 6px;
  font-size: 12px; padding: 1px 0;
}
.admin-growth-tooltip-row b { font-weight: 600; }

/* Tables */
.admin-table-wrap {
  background: var(--bg-elevated); border: 1px solid #1f2330; border-radius: 8px;
  overflow: hidden;
}
.admin-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.admin-table thead th {
  background: var(--bg-hover); color: var(--text-secondary); font-weight: 600;
  padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--border-default);
}
.admin-table tbody td {
  padding: 10px 12px; color: var(--text-primary);
  border-bottom: 1px solid var(--bg-hover);
}
.admin-table tbody tr:hover { background: #161922; }
.admin-table tbody tr:last-child td { border-bottom: none; }
.admin-table img.admin-row-avatar {
  width: 28px; height: 28px; border-radius: 8px; object-fit: cover; vertical-align: middle;
}
.admin-row-action {
  background: transparent; border: 1px solid var(--border-default); color: var(--text-secondary);
  padding: 4px 10px; border-radius: 8px; cursor: pointer; font-size: 12px;
  margin-right: 4px;
}
.admin-row-action:hover { background: #2a2a2a; color: #fff; border-color: #ededed; }
.admin-row-action.danger:hover { background: #3a1d24; color: #fff; border-color: #ef4444; }
.admin-toggle {
  cursor: pointer; user-select: none;
}
.admin-toggle.on { color: #5c2222; font-weight: 700; }
.admin-toggle.off { color: var(--text-muted); }

/* Filter bar */
.admin-filter-bar { display: flex; gap: 6px; margin-bottom: 16px; flex-wrap: wrap; }
.admin-filter {
  background: transparent; border: 1px solid var(--border-default); color: var(--text-secondary);
  padding: 6px 14px; border-radius: 999px; cursor: pointer; font-size: 13px;
}
.admin-filter:hover { background: var(--bg-hover); color: #fff; }
.admin-filter.active { background: #1f2535; color: #fff; border-color: #ededed; }

/* Reports list */
.admin-report-card {
  background: var(--bg-elevated); border: 1px solid #1f2330; border-radius: 8px;
  padding: 14px 16px; margin-bottom: 10px;
}
.admin-report-head {
  display: flex; align-items: center; gap: 10px; margin-bottom: 8px;
  font-size: 12px; color: var(--text-muted);
}
.admin-report-status {
  padding: 2px 8px; border-radius: 8px;
  background: var(--border-default); color: var(--text-secondary); font-weight: 600; font-size: 11px;
  text-transform: uppercase;
}
.admin-report-status.open { background: #3a1d24; color: #fca5a5; }
.admin-report-status.reviewing { background: #1f2535; color: #93c5fd; }
.admin-report-status.resolved { background: #1f3528; color: #86efac; }
.admin-report-status.dismissed { background: var(--bg-hover); color: var(--text-muted); }
.admin-report-target {
  font-weight: 600; color: var(--text-primary); font-size: 14px; margin-bottom: 4px;
}
.admin-report-reason { color: var(--text-secondary); font-size: 13px; margin-bottom: 6px; }
.admin-report-detail {
  color: var(--text-secondary); font-size: 13px; line-height: 1.5;
  background: #161922; padding: 8px 12px; border-radius: 8px;
  border-left: 3px solid #ededed;
  margin-bottom: 10px; white-space: pre-wrap;
}
.admin-report-actions { display: flex; gap: 6px; }

.admin-output {
  margin-top: 14px; padding: 12px;
  background: var(--bg-elevated); border: 1px solid #1f2330; border-radius: 8px;
  font-family: monospace; font-size: 12px; color: var(--text-secondary);
  white-space: pre-wrap; word-wrap: break-word;
  min-height: 40px;
}

/* Light mode */
body[data-theme="light"] .admin-layout { background: #f9fafb; }
body[data-theme="light"] .admin-sidebar { background: #ffffff; border-right-color: #e5e7eb; }
body[data-theme="light"] .admin-sidebar-header { color: #111827; border-bottom-color: #e5e7eb; }
body[data-theme="light"] .admin-nav-link { color: #4b5563; }
body[data-theme="light"] .admin-nav-link:hover { background: #f3f4f6; color: #111827; }
body[data-theme="light"] .admin-nav-link.active { background: #eef2ff; color: #4338ca; }
body[data-theme="light"] .admin-pane h1 { color: #111827; }
body[data-theme="light"] .admin-stat-card {
  background: #ffffff; border-color: #e5e7eb;
}
body[data-theme="light"] .admin-stat-num { color: #111827; }
body[data-theme="light"] .admin-stat-lbl { color: var(--text-faint); }
body[data-theme="light"] .admin-table-wrap { background: #ffffff; border-color: #e5e7eb; }
body[data-theme="light"] .admin-table thead th { background: #f9fafb; color: #4b5563; border-bottom-color: #e5e7eb; }
body[data-theme="light"] .admin-table tbody td { color: #111827; border-bottom-color: #f3f4f6; }
body[data-theme="light"] .admin-table tbody tr:hover { background: #f9fafb; }
body[data-theme="light"] .admin-row-action { color: #4b5563; border-color: #e5e7eb; }
body[data-theme="light"] .admin-row-action:hover { background: #eef2ff; color: #4338ca; border-color: #ededed; }
body[data-theme="light"] .admin-filter { color: #4b5563; border-color: #e5e7eb; }
body[data-theme="light"] .admin-filter:hover { background: #f3f4f6; color: #111827; }
body[data-theme="light"] .admin-filter.active { background: #eef2ff; color: #4338ca; border-color: #ededed; }
body[data-theme="light"] .admin-report-card { background: #ffffff; border-color: #e5e7eb; }
body[data-theme="light"] .admin-report-target { color: #111827; }
body[data-theme="light"] .admin-report-reason,
body[data-theme="light"] .admin-report-detail { color: #1f2937; }
body[data-theme="light"] .admin-report-detail { background: #f9fafb; }
body[data-theme="light"] .admin-output { background: #f9fafb; border-color: #e5e7eb; color: #111827; }

/* Banned-words add bar */
.admin-banned-add {
  display: grid;
  grid-template-columns: 1fr 130px 1fr auto;
  gap: 8px; margin-bottom: 16px;
}
.admin-banned-add input,
.admin-banned-add select {
  background: var(--bg-hover); border: 1px solid var(--border-default); color: var(--text-primary);
  border-radius: 8px; padding: 8px 12px; font-size: 13px;
  font-family: inherit;
}
.admin-banned-add input:focus,
.admin-banned-add select:focus { outline: none; border-color: #ededed; }
body[data-theme="light"] .admin-banned-add input,
body[data-theme="light"] .admin-banned-add select {
  background: #ffffff; color: #111827; border-color: #e5e7eb;
}
.admin-severity-pill {
  display: inline-block; padding: 2px 10px; border-radius: 999px;
  font-size: 11px; font-weight: 600; text-transform: uppercase;
}
.admin-severity-pill.block { background: #3a1d24; color: #fca5a5; }
.admin-severity-pill.warn  { background: #3a3019; color: #fcd34d; }

/* ============================================================
   PUBLIC PROFILE PAGE (Phase 1 #18)
   Hero card with avatar + bio + stat tiles, then a character grid.
   ============================================================ */
.profile-layout {
  padding: 28px 36px; overflow-y: auto;
  height: calc(100vh - 60px);
  background: var(--bg-base);
}
.profile-card {
  max-width: 1280px; margin: 0 auto 28px;
  background: linear-gradient(135deg, var(--bg-hover) 0%, #232733 100%);
  border: 1px solid var(--border-default); border-radius: 12px;
  padding: 28px;
}
.profile-head {
  display: flex; gap: 22px; align-items: flex-start;
  margin-bottom: 22px;
}
.profile-avatar {
  width: 110px; height: 110px; border-radius: 50%;
  object-fit: cover; flex-shrink: 0;
  background: var(--bg-hover); border: 2px solid var(--border-default);
}
.profile-avatar:not([src]),
.profile-avatar[src=""] {
  background: linear-gradient(135deg, #ededed 0%, #b561ff 100%);
}
.profile-head-meta { flex: 1; min-width: 0; }
.profile-name {
  margin: 0 0 4px; font-size: 28px; color: var(--text-primary); font-weight: 700;
}
.profile-joined { color: var(--text-muted); font-size: 13px; margin: 0 0 12px; }
.profile-bio {
  color: #d8dae0; font-size: 14px; line-height: 1.55;
  white-space: pre-wrap; word-wrap: break-word;
}
.profile-bio:empty::after {
  content: "No bio yet."; color: var(--text-muted); font-style: italic;
}
.profile-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
.profile-stat-tile {
  background: var(--bg-elevated); border: 1px solid #1f2330; border-radius: 8px;
  padding: 14px; text-align: center;
}
.profile-stat-num {
  font-size: 24px; font-weight: 800; color: var(--text-primary);
}
.profile-stat-lbl {
  font-size: 11px; color: var(--text-muted); text-transform: uppercase;
  letter-spacing: 0.06em; margin-top: 4px;
}
.profile-section-h {
  max-width: 920px; margin: 0 auto 14px;
  color: var(--text-secondary); font-size: 16px; font-weight: 600;
}
.profile-layout .character-grid { max-width: 1180px; margin: 0 auto; }
.char-card-creator-link {
  color: #ededed; text-decoration: none; font-weight: 500;
  cursor: pointer;
}
.char-card-creator-link:hover { text-decoration: underline; color: #a5b4fc; }

body[data-theme="light"] .profile-layout { background: #f9fafb; }
body[data-theme="light"] .profile-card { background: #ffffff; border-color: #e5e7eb; }
body[data-theme="light"] .profile-name { color: #111827; }
body[data-theme="light"] .profile-joined { color: var(--text-faint); }
body[data-theme="light"] .profile-bio { color: #1f2937; }
body[data-theme="light"] .profile-stat-tile { background: #f9fafb; border-color: #e5e7eb; }
body[data-theme="light"] .profile-stat-num { color: #111827; }
body[data-theme="light"] .profile-stat-lbl { color: var(--text-faint); }
body[data-theme="light"] .profile-section-h { color: #4b5563; }
body[data-theme="light"] .char-card-creator-link { color: #4338ca; }
body[data-theme="light"] .char-card-creator-link:hover { color: #3730a3; }

/* ============================================================
   RECOMMENDATIONS RAIL (Phase 1 #19)
   "Because you chatted with X" horizontally-scrolling strip
   ============================================================ */
/* Rec rail — back to a contained editorial card (the "old" styling),
   on the new charcoal palette. Same linen weave as other surfaces so it
   feels like a piece of the same fabric, not a separate-coloured panel. */
.recs-rail {
  position: relative;
  margin: 0 0 28px;
  padding: 18px 22px;
  background-color: var(--bg-elevated);
  background-image:
    repeating-linear-gradient(0deg,
      rgba(255,255,255,0.045) 0px, rgba(255,255,255,0.045) 1px,
      transparent 1px, transparent 4px),
    repeating-linear-gradient(90deg,
      rgba(255,255,255,0.045) 0px, rgba(255,255,255,0.045) 1px,
      transparent 1px, transparent 4px);
  border: 1px solid var(--border-default);
  border-radius: 12px;
}
.recs-rail-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 14px;
}
.recs-rail-title {
  display: inline-block;
  margin: 0; font-size: 12px; font-weight: 700;
  color: #ffffff;
  text-transform: uppercase; letter-spacing: 0.08em;
  background: rgba(255, 255, 255, 0.08);
  padding: 6px 14px;
  border: none;
  border-radius: 0;
}
.recs-rail-title .recs-seed-name {
  color: #ffffff; font-weight: 700;
}
.recs-rail-strip {
  display: flex; gap: 14px;
  overflow-x: auto; overflow-y: hidden;
  padding-bottom: 8px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.10) transparent;
  /* B1 — CAI-style rail snap. Each card is a snap point; scrolling
     finishes locked to a card edge instead of mid-card. scroll-padding
     keeps the edge card flush with the rail's left padding. */
  scroll-snap-type: x mandatory;
  scroll-padding-left: 4px;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}
.recs-card { scroll-snap-align: start; }
.recs-rail-strip::-webkit-scrollbar { height: 6px; }
.recs-rail-strip::-webkit-scrollbar-track { background: transparent; }
.recs-rail-strip::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.10); border-radius: 999px; }
.recs-card {
  flex: 0 0 200px; width: 200px;
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  cursor: pointer;
  overflow: hidden;
}
.recs-card:hover { border-color: rgba(255,255,255,0.20); transform: translateY(-2px); }
.recs-card-banner {
  height: 110px;
  background-size: cover; background-position: center;
  background-color: var(--bg-hover);
}
.recs-card-meta { padding: 10px 12px; }
.recs-card-name {
  font-size: 14px; font-weight: 600; color: var(--text-primary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.recs-card-tagline {
  font-size: 11px; color: var(--text-muted);
  margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.recs-card-shared {
  font-size: 10px; color: var(--text-muted);
  margin-top: 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-weight: 500; letter-spacing: 0.02em;
}

body[data-theme="light"] .recs-rail {
  background: transparent;
  border-top-color: rgba(0,0,0,0.08);
  border-bottom-color: rgba(0,0,0,0.08);
}
body[data-theme="light"] .recs-rail-title {
  color: #111827;
  background: rgba(0, 0, 0, 0.08);
}
body[data-theme="light"] .recs-rail-title .recs-seed-name { color: #4338ca; }
body[data-theme="light"] .recs-card { background: #ffffff; border-color: #e5e7eb; }
body[data-theme="light"] .recs-card:hover { border-color: #ededed; }
body[data-theme="light"] .recs-card-name { color: #111827; }
body[data-theme="light"] .recs-card-tagline { color: var(--text-faint); }
body[data-theme="light"] .recs-card-shared { color: var(--text-muted); }

/* ============================================================
   ACTIVITY FEED + FOLLOW BUTTON (Phase 2 #21)
   ============================================================ */
.feed-layout {
  padding: 28px 36px; overflow-y: auto;
  height: calc(100vh - 60px);
  background: var(--bg-base);
}
/* ============ LIBRARY (book grid) ============ */
.library-layout { padding: 32px 28px; min-height: 100vh; }
.library-container { max-width: 1200px; margin: 0 auto; }
.library-head h1 { color: var(--text-primary); margin: 0 0 4px; }
.library-head p { margin: 0 0 24px; }
.library-search-row { position: relative; margin-bottom: 24px; }
.library-search-row input { width: 100%; padding: 12px 40px 12px 16px; }
.library-search-row input::-webkit-search-cancel-button { display: none; }
.library-search-row .search-clear {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
}
.library-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 22px;
}
.library-card {
  background-color: var(--bg-elevated);
  border: 1px solid var(--border-default);
  border-radius: 8px;
  overflow: hidden; cursor: pointer;
  display: flex; flex-direction: column;
}
.library-card:hover { border-color: rgba(255,255,255,0.18); transform: translateY(-2px); }
.library-card-cover {
  aspect-ratio: 3 / 4;
  background-size: cover; background-position: center;
  background-color: var(--bg-hover);
}
.library-card-cover-fallback {
  width: 100%; height: 100%;
  display: flex; align-items: center; justify-content: center;
  font-family: "Fraunces", Georgia, serif;
  font-style: italic; font-weight: 500;
  font-size: 36px; color: var(--text-muted);
}
.library-card-body { padding: 12px 14px 14px; }
.library-card-title {
  font-family: "Fraunces", Georgia, serif;
  font-weight: 500; font-size: 17px;
  letter-spacing: -0.01em; line-height: 1.2;
  color: var(--text-primary);
  margin: 0 0 4px;
  overflow: hidden; display: -webkit-box;
  -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.library-card-author {
  font-size: 11px; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.06em;
  margin: 0 0 6px;
}
.library-card-desc {
  font-size: 12.5px; color: var(--text-secondary);
  line-height: 1.45;
  overflow: hidden; display: -webkit-box;
  -webkit-line-clamp: 3; -webkit-box-orient: vertical;
}

.feed-container { max-width: 720px; margin: 0 auto; }
.feed-head h1 { color: var(--text-primary); font-size: 24px; margin: 0 0 4px; }
.feed-head .muted { margin: 0 0 22px; }
.feed-item {
  display: flex; gap: 14px; align-items: center;
  background: var(--bg-elevated); border: 1px solid #1f2330; border-radius: 8px;
  padding: 14px; margin-bottom: 10px;
  cursor: pointer;
  transition: border-color .12s, transform .12s;
}
.feed-item:hover { border-color: #ededed; transform: translateY(-1px); }
.feed-item-avatar {
  width: 56px; height: 56px; border-radius: 8px;
  object-fit: cover; flex-shrink: 0;
  background: var(--bg-hover);
}
.feed-item-meta { flex: 1; min-width: 0; }
.feed-item-actor {
  font-size: 12px; color: var(--text-muted); margin-bottom: 2px;
}
.feed-item-actor .actor-name { color: #ededed; font-weight: 600; }
.feed-item-actor .verb { color: var(--text-secondary); font-style: italic; }
.feed-item-name {
  font-weight: 600; color: var(--text-primary); font-size: 15px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.feed-item-tagline {
  font-size: 13px; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.feed-item-when {
  font-size: 11px; color: var(--text-muted); flex-shrink: 0;
}

/* User-authored status update tile (kind=post). The avatar is a wrapper
   div so the gradient fallback can sit behind a centred initial; the
   body is full-width text rather than a one-line ellipsis. */
.feed-item.feed-item-post { cursor: default; align-items: flex-start; }
.feed-item.feed-item-post:hover { transform: none; }
.feed-item-post div.feed-item-avatar { overflow: hidden; }
.feed-item-post div.feed-item-avatar img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.feed-item-post-body {
  color: var(--text-primary); font-size: 14px; line-height: 1.45;
  white-space: pre-wrap; word-break: break-word; margin-top: 4px;
}
.feed-item-del {
  margin-left: 8px; flex-shrink: 0;
  padding: 4px 8px; font-size: 14px;
}

.feed-composer {
  background: var(--bg-elevated); border: 1px solid var(--border-subtle); border-radius: 12px;
  padding: 14px 16px; margin-bottom: 14px;
  transition: border-color 160ms ease, box-shadow 160ms ease;
}
.feed-composer:focus-within {
  border-color: rgba(122, 46, 46, 0.45);
  box-shadow: 0 0 0 3px rgba(122, 46, 46, 0.08);
}
.feed-composer.is-dragover {
  border-color: var(--pal-burgundy, #7a2e2e);
  box-shadow: 0 0 0 3px rgba(122, 46, 46, 0.18);
}
.feed-composer-row { display: flex; gap: 12px; align-items: flex-start; }
.feed-composer-avatar {
  flex: 0 0 44px; width: 44px; height: 44px; border-radius: 50%;
  overflow: hidden; display: flex; align-items: center; justify-content: center;
  color: var(--text-primary); font-weight: 600; font-size: 16px;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
  user-select: none;
}
.feed-composer-avatar img { width: 100%; height: 100%; object-fit: cover; }
.feed-composer-main { flex: 1; min-width: 0; }
.feed-composer textarea {
  width: 100%; background: transparent; border: none; outline: none;
  color: var(--text-primary); font-size: 16px; line-height: 1.45; resize: none;
  min-height: 28px; max-height: 240px; padding: 4px 0;
  font-family: inherit; letter-spacing: -0.005em; overflow-y: auto;
}
.feed-composer textarea::placeholder { color: var(--text-muted); }
.feed-composer-actions {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 10px; gap: 10px;
}
.feed-composer-actions .feed-composer-image-btn { margin-right: auto; }
.feed-composer-actions #feed-post-counter { font-size: 12px; opacity: 0.65; }
.feed-composer-actions #feed-post-counter.is-near-limit { color: #f87171; opacity: 1; }
.feed-composer-actions .primary { padding: 7px 18px; border-radius: 999px; font-size: 14px; font-weight: 600; }
.feed-composer-actions .primary:disabled { opacity: 0.4; cursor: not-allowed; }
body[data-theme="light"] .feed-composer { background: #ffffff; border-color: #e5e7eb; }
body[data-theme="light"] .feed-composer textarea { color: #111827; }
body[data-theme="light"] .feed-item-post-body { color: #1f2937; }

.mention, .hashtag {
  color: var(--pal-burgundy, #7a2e2e);
  cursor: pointer; font-weight: 500;
}
.mention:hover, .hashtag:hover { text-decoration: underline; }
body[data-theme="light"] .mention,
body[data-theme="light"] .hashtag { color: #7a2e2e; }

.feed-tag-banner {
  display: flex; align-items: center; justify-content: space-between;
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  border-radius: 8px; padding: 10px 14px; margin-bottom: 12px;
  font-size: 14px; color: var(--text-primary);
}
.feed-tag-banner button { padding: 4px 12px; border-radius: 999px; font-size: 12px; }

/* Profile-page character cards stretch their meta area to equal height so
   the Share button always sits at the bottom regardless of tagline length. */
#profile-character-grid .character-card { display: flex; flex-direction: column; }
#profile-character-grid .char-card-meta {
  flex: 1; display: flex; flex-direction: column;
}
.char-card-share-btn {
  margin-top: 8px; width: 100%;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 12px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.06); color: #f5f1ea;
  border: 1px solid rgba(255, 255, 255, 0.14);
  font-size: 12.5px; font-weight: 600; cursor: pointer;
  transition: background 120ms ease, transform 120ms ease;
}
.char-card-share-btn:hover {
  background: rgba(255, 255, 255, 0.12);
  transform: translateY(-1px);
}
/* Push the share button below the stats with consistent gap */
#profile-character-grid .char-card-stats { margin-bottom: 10px; }

/* ============ SHARE NEW CHARACTER MODAL ============ */
.share-char-preview {
  display: flex; gap: 12px; align-items: center;
  padding: 12px; margin-bottom: 12px;
  background: var(--bg-base); border: 1px solid var(--border-subtle);
  border-radius: 10px;
}
.share-char-preview img,
.share-char-preview > div:first-child:not(.share-char-meta) {
  flex: 0 0 56px; width: 56px; height: 56px;
  border-radius: 50%; object-fit: cover;
}
#share-char-avatar {
  flex: 0 0 56px; width: 56px; height: 56px;
  border-radius: 50%; object-fit: cover;
}
.share-char-meta { flex: 1; min-width: 0; }
.share-char-name {
  font-weight: 700; color: var(--text-primary); font-size: 15px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.share-char-tagline {
  color: var(--text-muted); font-size: 13px; margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#share-char-body {
  width: 100%; min-height: 80px;
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  border-radius: 8px; padding: 10px 12px;
  color: var(--text-primary); font-family: inherit; font-size: 14px;
  line-height: 1.45; resize: vertical;
}
#share-char-body:focus {
  outline: none; border-color: var(--pal-burgundy, #7a2e2e);
}

/* ============ FEED COMPOSER IMAGE ============ */
.feed-composer-preview {
  position: relative; margin-top: 8px; display: inline-block;
  max-width: 100%;
}
.feed-composer-preview img {
  max-width: 100%; max-height: 240px; border-radius: 12px;
  border: 1px solid var(--border-default);
}
.feed-composer-preview .ghost {
  position: absolute; top: 8px; right: 8px;
  background: rgba(0,0,0,0.6); color: #fff; border: none;
  border-radius: 999px; width: 26px; height: 26px;
  cursor: pointer; font-size: 13px;
}
.feed-composer-actions { gap: 8px; }
.feed-composer-image-btn {
  display: inline-flex; align-items: center; gap: 6px;
  cursor: pointer; padding: 6px 12px 6px 10px; border-radius: 999px;
  font-size: 13px; font-weight: 500;
  color: #f5f1ea;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  transition: background 120ms ease, color 120ms ease, transform 120ms ease;
  user-select: none;
}
.feed-composer-image-btn:hover {
  background: rgba(255, 255, 255, 0.12);
  color: #ffffff;
  transform: translateY(-1px);
}
.feed-composer-image-btn svg { display: block; }
.feed-composer-image-label { line-height: 1; }
.feed-tweet-image-wrap {
  margin-top: 10px; position: relative;
}
/* NSFW gate — wrap the media in an isolating container so the blur only
   applies to the inner element. The pill button sits on top, unblurred. */
.feed-tweet-nsfw-gate {
  position: relative; margin-top: 10px;
}
.feed-tweet-nsfw-blurred {
  filter: blur(28px) brightness(0.55);
  pointer-events: none; user-select: none;
  overflow: hidden; border-radius: 12px;
  transition: filter 320ms ease;
}
.feed-tweet-nsfw-blurred.is-revealed {
  filter: none;
  pointer-events: auto; user-select: auto;
}
/* Twitter-style centered "View NSFW" pill on top of the blurred media */
.feed-tweet-nsfw-pill {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 22px; border-radius: 999px;
  background: rgba(15, 20, 25, 0.9); color: #f5f1ea;
  border: 1px solid rgba(255, 255, 255, 0.18);
  font-size: 13px; font-weight: 600; letter-spacing: 0.02em;
  cursor: pointer;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
  transition: background 160ms ease, transform 160ms ease, box-shadow 160ms ease;
  white-space: nowrap;
}
.feed-tweet-nsfw-pill:hover {
  background: rgba(0, 0, 0, 0.95);
  transform: translate(-50%, -50%) scale(1.04);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55);
}
.feed-tweet-nsfw-pill-icon { font-size: 15px; line-height: 1; }
.feed-tweet-charcard {
  margin-top: 10px;
  border: 1px solid var(--border-default); border-radius: 12px;
  overflow: hidden; background: var(--bg-elevated);
  transition: border-color 160ms ease, transform 160ms ease;
}
.feed-tweet-charcard:hover {
  border-color: rgba(255, 255, 255, 0.18);
}
.feed-tweet-charcard-banner {
  position: relative; aspect-ratio: 16 / 9;
  cursor: pointer; overflow: hidden;
}
.feed-tweet-charcard-banner-bg {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  transition: transform 320ms ease;
}
.feed-tweet-charcard-banner:hover .feed-tweet-charcard-banner-bg {
  transform: scale(1.04);
}
.feed-tweet-charcard-meta {
  padding: 14px 16px;
  display: flex; flex-direction: column; gap: 4px;
}
.feed-tweet-charcard-name {
  font-size: 16px; font-weight: 700; color: var(--text-primary);
  letter-spacing: -0.005em;
}
.feed-tweet-charcard-tagline {
  font-size: 13.5px; color: var(--text-muted); line-height: 1.4;
  margin-bottom: 8px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.feed-tweet-charcard-chat {
  align-self: flex-start;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 18px; border-radius: 999px;
  font-size: 13px; font-weight: 600;
}
.feed-tweet-image {
  display: block;
  width: 100%;
  max-height: 480px;
  object-fit: cover;
  border-radius: 12px; border: 1px solid var(--border-default);
  cursor: pointer; background: var(--bg-base);
}
.feed-tweet-image-broken {
  display: block; padding: 32px 16px; text-align: center;
  border: 1px dashed var(--border-default); border-radius: 12px;
  color: var(--text-muted); font-size: 13px; line-height: 1.5;
  background: rgba(255, 255, 255, 0.02);
}
.feed-tweet-image-broken small {
  display: block; margin-top: 6px; opacity: 0.6;
  word-break: break-all; font-size: 11px;
}
.feed-tweet-preview-comments {
  margin-top: 10px; padding-top: 8px;
  border-top: 1px solid var(--border-subtle);
  display: flex; flex-direction: column; gap: 8px;
}
.feed-tweet-preview-comment {
  display: flex; gap: 8px; align-items: flex-start;
  font-size: 13.5px; line-height: 1.4;
}
.feed-tweet-preview-avatar {
  flex: 0 0 24px; width: 24px; height: 24px; border-radius: 50%;
  overflow: hidden; display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 600; color: var(--text-primary); cursor: pointer;
}
.feed-tweet-preview-avatar img { width: 100%; height: 100%; object-fit: cover; }
.feed-tweet-preview-text {
  flex: 1; min-width: 0;
  background: rgba(255, 255, 255, 0.025);
  border-radius: 14px; padding: 6px 12px;
}
.feed-tweet-preview-name {
  color: var(--text-primary); font-weight: 600; cursor: pointer;
  margin-right: 6px;
}
.feed-tweet-preview-name:hover { text-decoration: underline; }
.feed-tweet-preview-body {
  color: var(--text-primary);
  white-space: pre-wrap; word-break: break-word;
}
.feed-tweet-preview-more {
  background: transparent; border: none; padding: 4px 8px;
  font-size: 12.5px; color: var(--text-muted); cursor: pointer;
  text-align: left; align-self: flex-start;
  border-radius: 999px;
}
.feed-tweet-preview-more:hover { color: var(--pal-burgundy, #7a2e2e); }
body[data-theme="light"] .feed-tweet-preview-text { background: rgba(0, 0, 0, 0.03); }

.profile-cover {
  position: relative; max-width: 1280px; height: 240px;
  margin: 0 auto 16px;
  background: linear-gradient(135deg, #1a1d24 0%, #2a2f3a 100%);
  /* 140% auto ALWAYS — guarantees both-axis pan room and gives the saved
     framing a stable look between drag-mode and view-mode. `cover` would
     fit one axis exactly, killing horizontal pan for landscape images. */
  background-size: 140% auto;
  background-position: 50% 50%;
  background-repeat: no-repeat;
  border-radius: 12px;
  overflow: hidden;
}
.profile-cover-upload {
  position: absolute; bottom: 12px; right: 12px;
  background: rgba(0, 0, 0, 0.55); color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.2);
  padding: 6px 12px; border-radius: 999px;
  font-size: 12px; font-weight: 600; cursor: pointer;
  backdrop-filter: blur(8px);
}
.profile-cover-upload:hover { background: rgba(0, 0, 0, 0.75); }

/* Cover-options 3-dot menu — sits in the corner, opens a small dropdown. */
.profile-cover-menu-wrap {
  position: absolute; bottom: 12px; right: 12px; z-index: 2;
}
.profile-cover-menu-btn {
  width: 32px; height: 32px; padding: 0;
  background: rgba(0, 0, 0, 0.55); color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  font-size: 18px; font-weight: 700; line-height: 1; cursor: pointer;
  backdrop-filter: blur(8px);
  display: flex; align-items: center; justify-content: center;
  transition: background 120ms ease, transform 120ms ease;
}
.profile-cover-menu-btn:hover { background: rgba(0, 0, 0, 0.85); transform: scale(1.06); }
.profile-cover-menu {
  position: absolute; bottom: calc(100% + 6px); right: 0;
  min-width: 200px;
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  border-radius: 10px; padding: 6px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  display: flex; flex-direction: column; gap: 2px;
  animation: popoverIn 140ms ease;
}
.profile-cover.is-cover-dragging { cursor: grab; }
.profile-cover.is-cover-dragging:active { cursor: grabbing; }
.profile-cover-drag-banner {
  position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.75); color: #fff;
  padding: 6px 14px; border-radius: 999px;
  font-size: 12px; font-weight: 600;
  pointer-events: none;
  backdrop-filter: blur(8px);
}
.profile-cover-drag-actions {
  position: absolute; bottom: 12px; right: 12px;
  display: flex; gap: 8px;
}
.profile-cover-drag-actions button {
  padding: 6px 14px; border-radius: 999px; font-size: 12px; font-weight: 600;
}
.profile-cover-drag-actions .ghost {
  background: rgba(0, 0, 0, 0.55); color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.2);
}

/* ============ PROFILE TABS (creator dashboard) ============ */
.profile-tabs {
  display: flex; gap: 4px; padding: 4px;
  background: var(--bg-base); border-radius: 8px;
  margin: 0 auto 18px; max-width: 1280px;
}
.profile-tab {
  flex: 1; background: transparent; border: none;
  color: var(--text-muted); padding: 10px 14px; border-radius: 8px;
  cursor: pointer; font-size: 13px; font-weight: 500;
}
.profile-tab.active { background: var(--bg-active); color: var(--text-primary); }
.profile-tab:hover:not(.active) { color: var(--text-secondary); }
.profile-tab-pane { max-width: 1280px; margin: 0 auto 24px; }
/* Profile mobile polish — tighten the head card, stack avatar+name
   centered, shrink stats to 2x2, scroll the tab strip horizontally. */
@media (max-width: 720px) {
  .profile-layout { padding: 14px 12px; }
  .profile-card { padding: 16px 14px; margin-bottom: 16px; border-radius: 10px; }
  .profile-head {
    flex-direction: column; align-items: center;
    gap: 12px; text-align: center; margin-bottom: 16px;
  }
  .profile-avatar { width: 88px; height: 88px; }
  .profile-name { font-size: 22px; }
  .profile-bio { text-align: left; }
  .profile-stats {
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
  }
  .profile-stat-tile { padding: 10px; }
  .profile-stat-num { font-size: 20px; }
  .profile-tabs {
    overflow-x: auto;
    scrollbar-width: none;
    -ms-overflow-style: none;
    flex-wrap: nowrap;
  }
  .profile-tabs::-webkit-scrollbar { display: none; }
  .profile-tab {
    flex: 0 0 auto;
    white-space: nowrap;
    min-height: 40px;
  }
}

/* When the Persona modal-card is hosted inside the Persona tab pane,
   strip ALL the modal-card chrome so it reads as plain page content like
   the other tabs (no wrapping card, no border, no shadow). */
.modal-card.persona-card-as-tab {
  width: auto !important; max-width: 100% !important;
  margin: 0 !important; padding: 0 !important;
  background: transparent !important;
  border: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  animation: none !important;
  max-height: none !important;
  overflow: visible !important;
}
.modal-card.persona-card-as-tab h2 {
  margin: 0 0 6px;
  font-family: 'Fraunces', Georgia, serif; font-style: italic;
  font-size: 22px; font-weight: 400;
  border: none; text-transform: none; letter-spacing: -0.01em;
  color: var(--text-primary);
}
.modal-card.persona-card-as-tab h3 {
  margin-top: 28px !important;
  font-family: inherit; font-style: normal;
  letter-spacing: 0.06em;
}

/* Persona editor */
#profile-persona-textarea {
  width: 100%; min-height: 140px;
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  border-radius: 8px; padding: 12px 14px;
  color: var(--text-primary); font-family: inherit; font-size: 14px;
  line-height: 1.5; resize: vertical;
}
#profile-persona-textarea:focus { outline: none; border-color: var(--pal-burgundy, #7a2e2e); }

/* Engagement tab */
.engagement-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
}
.engagement-tile {
  background: var(--bg-elevated); border: 1px solid var(--border-subtle);
  border-radius: 12px; padding: 18px 14px; text-align: center;
}
.engagement-num { font-size: 28px; font-weight: 700; color: var(--text-primary); letter-spacing: -0.02em; }
.engagement-lbl { font-size: 11px; color: var(--text-muted); margin-top: 4px; text-transform: uppercase; letter-spacing: 0.06em; }
.engagement-top-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-bottom: 1px solid var(--border-subtle);
}
.engagement-top-row:last-child { border-bottom: none; }
.engagement-top-avatar {
  flex: 0 0 36px; width: 36px; height: 36px; border-radius: 50%;
  overflow: hidden; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-primary); font-weight: 600; font-size: 14px;
}
.engagement-top-avatar img { width: 100%; height: 100%; object-fit: cover; }
.engagement-top-name { flex: 1; color: var(--text-primary); font-weight: 600; cursor: pointer; }
.engagement-top-name:hover { text-decoration: underline; }
.engagement-top-vis { color: var(--text-muted); font-size: 12px; }
.engagement-top-likes { color: #e0245e; font-weight: 700; font-size: 14px; }

/* Public/Private toggle on character cards (profile). Both labels are
   forced to the same widths so every card in a row aligns even when the
   text differs ("Make public" vs "Make private"). margin-top: auto pushes
   this row AND the Share button below it to the bottom of the card —
   guarantees consistent vertical alignment across cards with different
   tagline heights. */
.char-card-public-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-top: auto; padding-top: 10px;
  min-height: 28px;
}
.char-card-public-label {
  flex: 0 0 auto;
  font-size: 11.5px; color: var(--text-muted);
  font-weight: 600;
  white-space: nowrap;
}
.char-card-public-btn {
  flex: 0 0 auto;
  font-size: 11.5px; padding: 4px 12px; border-radius: 999px;
  min-width: 110px;       /* "Make private" is widest — pin to that */
  text-align: center;
}

/* ============ FOLLOWERS / FOLLOWING LIST ============ */
.follow-list-card {
  width: 460px; max-width: 95vw; max-height: 78vh;
  display: flex; flex-direction: column; padding: 0;
}
.follow-list-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-bottom: 1px solid var(--border-subtle);
}
.follow-list-head h2 {
  margin: 0; font-size: 18px; font-weight: 700;
  border: none; text-transform: none; letter-spacing: 0;
}
#follow-list-body {
  overflow-y: auto;
  padding: 4px 0;
}
.follow-list-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 18px;
  border-bottom: 1px solid var(--border-subtle);
  transition: background 120ms ease;
}
.follow-list-row:last-child { border-bottom: none; }
.follow-list-row:hover { background: rgba(255, 255, 255, 0.025); }
.follow-list-avatar {
  flex: 0 0 44px; width: 44px; height: 44px; border-radius: 50%;
  overflow: hidden; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-primary); font-size: 16px; font-weight: 600;
  user-select: none;
}
.follow-list-avatar img { width: 100%; height: 100%; object-fit: cover; }
.follow-list-meta { flex: 1; min-width: 0; cursor: pointer; }
.follow-list-name { font-weight: 700; color: var(--text-primary); font-size: 14px; }
.follow-list-name:hover { text-decoration: underline; }
.follow-list-bio {
  color: var(--text-muted); font-size: 12.5px; margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.follow-list-followbtn {
  flex: 0 0 auto; padding: 6px 16px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600;
}
.profile-follow-counts span:hover b { text-decoration: underline; }

/* ============ IMAGE POSITION PICKER ============ */
.image-position-card { width: 540px; max-width: 95vw; }
.image-position-viewport {
  position: relative; width: 100%;
  aspect-ratio: 16 / 7;       /* default — JS overrides for avatar (1/1) */
  overflow: hidden; border-radius: 12px;
  background: var(--bg-base);
  cursor: grab; user-select: none;
}
.image-position-viewport.is-circle { aspect-ratio: 1 / 1; max-width: 320px; margin: 0 auto; border-radius: 50%; }
.image-position-viewport.is-dragging { cursor: grabbing; }
.image-position-viewport img {
  position: absolute; left: 0; top: 0;
  width: 100%; height: 100%; object-fit: cover;
  object-position: 50% 50%;
  pointer-events: none;
}
.profile-pinned-wrap {
  margin: 24px 0 16px;
  background: var(--bg-elevated); border: 1px solid var(--border-subtle);
  border-radius: 12px; padding: 4px 0 0;
}
.profile-pinned-label {
  padding: 10px 18px 0;
  color: var(--text-muted); font-size: 12px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em;
}

.streak-badge-wrap {
  display: inline-flex; align-items: center; gap: 4px;
  margin-right: 6px; padding: 4px 10px;
  background: rgba(255, 165, 0, 0.10);
  color: #ffb347; border-radius: 999px;
  border: 1px solid rgba(255, 165, 0, 0.22);
  font-size: 12px; font-weight: 700; line-height: 1;
}
.streak-badge-flame { font-size: 14px; }

/* ============ NOTIFICATIONS BELL ============ */
.notif-bell-wrap { position: relative; margin-right: 8px; }
.notif-bell-btn {
  background: transparent; border: none; cursor: pointer;
  font-size: 18px; padding: 6px 8px; border-radius: 8px;
  position: relative; color: var(--text-primary);
}
.notif-bell-btn:hover { background: rgba(255, 255, 255, 0.06); }
.notif-bell-badge {
  position: absolute; top: 2px; right: 2px;
  background: var(--pal-burgundy, #7a2e2e); color: #fff;
  border-radius: 999px; padding: 1px 5px;
  font-size: 10px; font-weight: 700; line-height: 1.3;
  min-width: 16px; text-align: center;
}
.notif-flyout {
  position: absolute; top: calc(100% + 6px); right: 0;
  width: 360px; max-height: 480px; overflow-y: auto;
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  border-radius: 10px;
  box-shadow: 0 14px 36px rgba(0,0,0,0.45);
  z-index: 200;
}
.notif-flyout-head {
  position: sticky; top: 0; z-index: 1;
  background: var(--bg-elevated);
  padding: 12px 14px; font-weight: 700; font-size: 14px;
  border-bottom: 1px solid var(--border-subtle);
}
.notif-row {
  display: flex; gap: 10px; padding: 10px 14px;
  border-bottom: 1px solid var(--border-subtle); cursor: pointer;
  transition: background 120ms ease;
}
.notif-row:hover { background: rgba(255, 255, 255, 0.025); }
.notif-row:last-child { border-bottom: none; }
.notif-row.is-unread { background: rgba(122, 46, 46, 0.06); }
.notif-row-avatar {
  flex: 0 0 36px; width: 36px; height: 36px; border-radius: 50%;
  overflow: hidden; display: flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 600; color: var(--text-primary);
}
.notif-row-avatar img { width: 100%; height: 100%; object-fit: cover; }
.notif-row-body { flex: 1; min-width: 0; font-size: 13px; }
.notif-row-text { color: var(--text-primary); line-height: 1.4; }
.notif-row-snippet {
  margin-top: 3px; color: var(--text-muted); font-style: italic;
  font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.notif-row-time {
  margin-top: 4px; color: var(--text-muted); font-size: 11.5px;
}
body[data-theme="light"] .notif-flyout {
  background: #ffffff; border-color: #e5e7eb;
  box-shadow: 0 14px 36px rgba(0,0,0,0.12);
}
body[data-theme="light"] .notif-row.is-unread { background: rgba(122, 46, 46, 0.04); }

/* ============ FEED SKELETON LOADING ============ */
.feed-tweet-skel { cursor: default; }
.feed-tweet-skel:hover { background: transparent; }
.skel-line { display: block; border-radius: 4px; }
.skel-shimmer {
  background: linear-gradient(90deg,
    rgba(255,255,255,0.04) 0%,
    rgba(255,255,255,0.10) 50%,
    rgba(255,255,255,0.04) 100%);
  background-size: 200% 100%;
  animation: skel-shimmer 1.4s ease-in-out infinite;
}
@keyframes skel-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
body[data-theme="light"] .skel-shimmer {
  background: linear-gradient(90deg,
    rgba(0,0,0,0.04) 0%, rgba(0,0,0,0.08) 50%, rgba(0,0,0,0.04) 100%);
  background-size: 200% 100%;
}

.feed-new-posts-pill {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; padding: 10px 16px; margin-bottom: 12px;
  background: var(--pal-burgundy, #7a2e2e); color: #fff;
  border: none; border-radius: 999px;
  font-size: 13px; font-weight: 600;
  cursor: pointer; box-shadow: 0 4px 14px rgba(122, 46, 46, 0.35);
  transition: transform 160ms ease, box-shadow 160ms ease;
  animation: pillSlideIn 240ms cubic-bezier(.2,.8,.2,1);
}
.feed-new-posts-pill:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(122, 46, 46, 0.45); }
@keyframes pillSlideIn {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}

.feed-empty-intro {
  text-align: center; padding: 28px 12px 18px; color: var(--text-secondary);
}
.feed-empty-intro h3 {
  font-family: 'Fraunces', Georgia, serif; font-style: italic;
  font-size: 24px; font-weight: 400; color: var(--text-primary);
  margin: 0 0 6px; border: none; text-transform: none; letter-spacing: -0.01em;
}
.feed-empty-intro p { margin: 0; font-size: 14px; line-height: 1.5; }
.feed-empty-link {
  cursor: pointer; color: var(--pal-burgundy, #7a2e2e);
  font-weight: 600;
}
.feed-empty-link:hover { text-decoration: underline; }
.feed-suggested-users {
  display: flex; flex-direction: column; gap: 0;
  background: var(--bg-elevated); border: 1px solid var(--border-subtle);
  border-radius: 12px; overflow: hidden;
  margin: 8px 0;
}
.feed-suggested-row {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border-subtle);
}
.feed-suggested-row:last-child { border-bottom: none; }
.feed-suggested-avatar {
  flex: 0 0 44px; width: 44px; height: 44px; border-radius: 50%;
  overflow: hidden; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 16px; font-weight: 600; color: var(--text-primary);
}
.feed-suggested-avatar img { width: 100%; height: 100%; object-fit: cover; }
.feed-suggested-meta { flex: 1; min-width: 0; }
.feed-suggested-name { color: var(--text-primary); font-weight: 700; font-size: 14px; cursor: pointer; }
.feed-suggested-name:hover { text-decoration: underline; }
.feed-suggested-bio {
  color: var(--text-muted); font-size: 12.5px; margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.feed-suggested-follow {
  flex: 0 0 auto; padding: 6px 16px; border-radius: 999px;
  font-size: 13px; font-weight: 600;
}
.feed-suggested-follow.is-following { opacity: 0.6; }

.feed-tabs {
  display: flex; gap: 4px; padding: 4px;
  background: var(--bg-base); border-radius: 8px;
  margin-bottom: 14px;
}
.feed-tab {
  flex: 1; background: transparent; border: none;
  color: var(--text-muted); padding: 8px 14px; border-radius: 8px;
  cursor: pointer; font-size: 13px; font-weight: 500;
}
.feed-tab.active { background: var(--bg-active); color: var(--text-primary); }
.feed-tab:hover:not(.active) { color: var(--text-secondary); }

/* ============================================================
   TWITTER-STYLE POST CARDS (feed posts with comments + likes)
   ============================================================ */
.feed-tweet {
  display: flex; gap: 14px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--border-subtle);
  background: transparent;
  transition: background 160ms ease;
}
.feed-tweet:hover { background: rgba(255, 255, 255, 0.022); }
.feed-tweet-avatar {
  flex: 0 0 48px; width: 48px; height: 48px;
  border-radius: 50%; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-primary); font-weight: 600; font-size: 17px;
  cursor: pointer; user-select: none;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06),
              0 1px 2px rgba(0, 0, 0, 0.18);
  transition: transform 200ms ease;
}
.feed-tweet-avatar:hover { transform: scale(1.04); }
.feed-tweet-avatar img { width: 100%; height: 100%; object-fit: cover; }
.feed-tweet-col { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.feed-tweet-head {
  display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
  font-size: 14px;
}
.feed-tweet-name {
  color: var(--text-primary); font-weight: 700; cursor: pointer;
  letter-spacing: -0.01em;
}
.feed-tweet-name:hover { text-decoration: underline; }
.feed-tweet-dot { color: var(--text-muted); }
.feed-tweet-time { color: var(--text-muted); font-size: 13.5px; cursor: default; }
.feed-tweet-edited {
  color: var(--text-muted); font-size: 12px; font-style: italic;
  margin-left: 6px;
  opacity: 0.7;
}
.feed-tweet-del,
.feed-tweet-edit {
  margin-left: 4px; padding: 4px 10px; font-size: 13px;
  color: var(--text-muted); background: transparent; border: none;
  border-radius: 999px; line-height: 1;
}
.feed-tweet-del { margin-left: auto; }
.feed-tweet-edit:hover { color: var(--text-primary); background: rgba(255, 255, 255, 0.06); }
.feed-tweet-del:hover { color: #f87171; background: rgba(248, 113, 113, 0.10); }
.feed-tweet-body {
  color: var(--text-primary); font-size: 16px; line-height: 1.42;
  white-space: pre-wrap; word-break: break-word;
  letter-spacing: -0.005em;
  margin-top: 2px;
}
.feed-tweet-actions {
  display: flex; gap: 8px; margin-top: 12px; padding-top: 10px;
  max-width: 460px;
  border-top: 1px solid var(--border-subtle);
}
.feed-tweet-action {
  display: inline-flex; align-items: center; gap: 6px;
  background: transparent; border: none;
  padding: 6px 12px 6px 8px; border-radius: 999px; cursor: pointer;
  color: var(--text-muted); font-size: 13px; font-weight: 500;
  transition: color 160ms ease, background 160ms ease;
  flex: 1; justify-content: flex-start; max-width: 120px;
}
.feed-tweet-action-iconwrap {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%;
  transition: background 160ms ease, transform 200ms ease;
}
.feed-tweet-action:hover .feed-tweet-action-iconwrap { background: rgba(255, 255, 255, 0.06); }
.feed-tweet-icon { font-size: 16px; line-height: 1; }
.feed-tweet-like.is-liked { color: #e0245e; }
.feed-tweet-like.is-liked:hover .feed-tweet-action-iconwrap { background: rgba(224, 36, 94, 0.12); }
.feed-tweet-like.is-liked .feed-tweet-action-iconwrap { animation: heartPop 360ms cubic-bezier(.2,.8,.2,1); }
.feed-tweet-reply:hover { color: #7a99ff; }
.feed-tweet-reply:hover .feed-tweet-action-iconwrap { background: rgba(122, 153, 255, 0.12); }
.feed-tweet-like:hover { color: #e0245e; }
.feed-tweet-action-label {
  font-size: 13px; font-weight: 500;
  margin-left: 2px;
}
.feed-tweet-bookmark { color: var(--text-muted); }
.feed-tweet-bookmark:hover { color: #c9a062; }
.feed-tweet-bookmark:hover .feed-tweet-action-iconwrap { background: rgba(201, 160, 98, 0.14); }
.feed-tweet-bookmark.is-bookmarked { color: #c9a062; }
.feed-tweet-bookmark.is-bookmarked .feed-tweet-action-iconwrap { background: rgba(201, 160, 98, 0.10); }

.saved-empty {
  text-align: center; padding: 64px 24px;
  color: var(--text-secondary);
}
.saved-empty-icon { font-size: 56px; margin-bottom: 16px; opacity: 0.6; }
.saved-empty-title {
  font-family: 'Fraunces', Georgia, serif; font-style: italic;
  font-size: 22px; color: var(--text-primary);
  margin-bottom: 8px;
}
.saved-empty-sub {
  color: var(--text-muted); font-size: 14px; line-height: 1.5;
  max-width: 360px; margin: 0 auto;
}

@keyframes heartPop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.35); }
  70%  { transform: scale(0.92); }
  100% { transform: scale(1); }
}

/* Expanded thread */
.feed-tweet-thread {
  margin-top: 8px; padding-top: 10px;
  border-top: 1px dashed var(--border-subtle);
  display: flex; flex-direction: column; gap: 12px;
}
.feed-tweet-reply-row {
  display: flex; gap: 8px; align-items: flex-end;
}
.feed-tweet-reply-input {
  flex: 1; min-height: 38px; max-height: 160px;
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  border-radius: 8px; padding: 8px 10px;
  color: var(--text-primary); font-family: inherit; font-size: 14px;
  line-height: 1.4; resize: vertical;
}
.feed-tweet-reply-input:focus { outline: none; border-color: var(--pal-burgundy, #7a2e2e); }
.feed-tweet-reply-send {
  flex: 0 0 auto; padding: 8px 18px; border-radius: 999px; font-size: 13px;
}
.feed-tweet-comments {
  display: flex; flex-direction: column; gap: 10px;
}
.feed-tweet-comment {
  display: flex; gap: 10px;
  padding: 8px 0;
}
.feed-tweet-comment-avatar {
  flex: 0 0 32px; width: 32px; height: 32px;
  border-radius: 50%; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-primary); font-weight: 600; font-size: 13px;
  cursor: pointer; user-select: none;
}
.feed-tweet-comment-avatar img { width: 100%; height: 100%; object-fit: cover; }
.feed-tweet-comment-col { flex: 1; min-width: 0; }
.feed-tweet-comment-head {
  display: flex; align-items: baseline; gap: 6px;
  font-size: 13px;
}
.feed-tweet-comment-name {
  color: var(--text-primary); font-weight: 600; cursor: pointer;
}
.feed-tweet-comment-name:hover { text-decoration: underline; }
.feed-tweet-comment-body {
  color: var(--text-primary); font-size: 14px; line-height: 1.4;
  white-space: pre-wrap; word-break: break-word; margin-top: 2px;
}
.feed-tweet-comment.is-reply {
  margin-left: 42px;
  border-left: 2px solid var(--border-subtle);
  padding-left: 12px;
}
.feed-tweet-comment-actions {
  margin-top: 4px; display: flex; gap: 12px;
}
.feed-tweet-comment-reply-btn {
  background: transparent; border: none; padding: 2px 6px;
  font-size: 12px; color: var(--text-muted); cursor: pointer;
  border-radius: 999px;
}
.feed-tweet-comment-reply-btn:hover { color: var(--text-primary); background: rgba(255,255,255,0.06); }
.feed-tweet-comment-like-btn {
  display: inline-flex; align-items: center; gap: 4px;
  background: transparent; border: none; padding: 2px 6px;
  font-size: 12px; color: var(--text-muted); cursor: pointer;
  border-radius: 999px;
}
.feed-tweet-comment-like-btn:hover { color: #e0245e; background: rgba(224, 36, 94, 0.08); }
.feed-tweet-comment-like-btn.is-liked { color: #e0245e; }
.feed-tweet-comment-like-icon { font-size: 14px; line-height: 1; display: inline-block; }
.feed-tweet-comment-like-count:empty { display: none; }

.feed-tweet-likedby {
  display: flex; align-items: center; gap: 10px;
  margin-top: 12px; padding: 8px 0;
  font-size: 13.5px; color: var(--text-secondary);
}
.feed-tweet-likedby-stack { display: flex; }
.feed-tweet-likedby-avatar {
  width: 24px; height: 24px; border-radius: 50%;
  overflow: hidden; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 600; color: var(--text-primary);
  border: 2px solid var(--bg-elevated);
  margin-left: -8px;
  transition: transform 160ms ease;
}
.feed-tweet-likedby-avatar:first-child { margin-left: 0; }
.feed-tweet-likedby-avatar:hover { transform: translateY(-1px) scale(1.06); z-index: 1; }
.feed-tweet-likedby-avatar img { width: 100%; height: 100%; object-fit: cover; }
.feed-tweet-likedby-text { color: var(--text-secondary); }
.feed-tweet-likedby-text b { color: var(--text-primary); font-weight: 600; }
.feed-tweet-nested-reply {
  margin-left: 42px; margin-top: 8px;
  display: flex; gap: 8px; align-items: flex-end;
}
.feed-tweet-nested-reply textarea { flex: 1; }
.feed-tweet-nested-reply button { flex: 0 0 auto; padding: 6px 14px; border-radius: 999px; font-size: 13px; }
.feed-tweet-comment-del {
  margin-left: auto; padding: 2px 6px; font-size: 12px;
  color: var(--text-muted); background: transparent; border: none;
  border-radius: 999px;
}
.feed-tweet-comment-del:hover { color: #f87171; background: rgba(248, 113, 113, 0.08); }

.feed-tweet-edited {
  color: var(--text-muted); font-size: 12px; font-style: italic;
  margin-left: 6px;
}
.feed-tweet-edit {
  margin-left: 4px; padding: 2px 8px; font-size: 13px;
  color: var(--text-muted); background: transparent; border: none;
  border-radius: 999px;
}
.feed-tweet-edit:hover { color: var(--text-primary); background: rgba(255, 255, 255, 0.06); }
.feed-tweet-comment-edit {
  margin-left: auto; padding: 2px 6px; font-size: 12px;
  color: var(--text-muted); background: transparent; border: none;
  border-radius: 999px;
}
.feed-tweet-comment-edit:hover { color: var(--text-primary); background: rgba(255, 255, 255, 0.06); }
.feed-tweet-comment-edit + .feed-tweet-comment-del { margin-left: 0; }
.feed-tweet { cursor: pointer; }
.feed-tweet button { cursor: pointer; }

/* Post-detail modal — Twitter status page */
.post-detail-card {
  width: 620px; max-width: 95vw; max-height: 88vh;
  display: flex; flex-direction: column; padding: 0;
}
.post-detail-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border-subtle);
}
.post-detail-head h2 {
  margin: 0; font-size: 18px; font-weight: 700;
  border: none; text-transform: none; letter-spacing: 0;
}
#post-detail-body {
  overflow-y: auto;
  padding: 0;
}
.feed-tweet-detail {
  cursor: default;
  border-bottom: 1px solid var(--border-subtle);
}
.feed-tweet-detail:hover { background: transparent; }
.feed-tweet-body-detail { font-size: 17px; line-height: 1.5; }
.post-detail-composer {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border-subtle);
}
#post-detail-comments {
  padding: 4px 18px 18px;
  display: flex; flex-direction: column; gap: 4px;
}
.post-detail-editor {
  display: flex; flex-direction: column; gap: 8px; margin-top: 4px;
}
.post-detail-edit-input {
  background: var(--bg-elevated); border: 1px solid var(--border-default);
  border-radius: 8px; padding: 8px 10px;
  color: var(--text-primary); font-family: inherit; font-size: 14px;
  line-height: 1.4; resize: vertical; min-height: 60px;
}
.post-detail-edit-input:focus { outline: none; border-color: var(--pal-burgundy, #7a2e2e); }
.post-detail-edit-actions {
  display: flex; gap: 8px; justify-content: flex-end;
}
.post-detail-edit-actions button { padding: 6px 14px; border-radius: 999px; font-size: 13px; }

body[data-theme="light"] .feed-tweet:hover { background: rgba(0, 0, 0, 0.018); }
body[data-theme="light"] .feed-tweet-action:hover { background: rgba(0, 0, 0, 0.04); }
body[data-theme="light"] .post-detail-edit-input {
  background: #ffffff; border-color: #e5e7eb; color: #111827;
}
body[data-theme="light"] .feed-tweet-reply-input {
  background: #ffffff; border-color: #e5e7eb; color: #111827;
}
body[data-theme="light"] .feed-tweet-name,
body[data-theme="light"] .feed-tweet-comment-name { color: #111827; }
body[data-theme="light"] .feed-tweet-body,
body[data-theme="light"] .feed-tweet-comment-body { color: #1f2937; }

/* Follow button + count strip on profile pages */
.profile-action-cluster { display: flex; gap: 8px; flex-shrink: 0; }
.profile-follow-counts {
  display: flex; gap: 18px; margin-top: 12px;
  font-size: 13px; color: var(--text-muted);
}
.profile-follow-counts b { color: var(--text-secondary); font-weight: 700; }
#btn-follow-user.is-following {
  background: transparent; color: var(--text-secondary);
  border: 1px solid #ededed;
}

/* Light mode */
body[data-theme="light"] .feed-layout { background: #f9fafb; }
body[data-theme="light"] .feed-head h1 { color: #111827; }
body[data-theme="light"] .feed-item { background: #ffffff; border-color: #e5e7eb; }
body[data-theme="light"] .feed-item-name { color: #111827; }
body[data-theme="light"] .feed-item-actor .verb { color: #4b5563; }
body[data-theme="light"] .feed-item-actor .actor-name { color: #4338ca; }
body[data-theme="light"] .profile-follow-counts { color: var(--text-faint); }
body[data-theme="light"] .profile-follow-counts b { color: #1f2937; }
body[data-theme="light"] #btn-follow-user.is-following { color: #4338ca; border-color: #ededed; }

/* ============================================================
   MULTI-PERSONA MANAGER (Phase 2 #24)
   ============================================================ */
.persona-list {
  display: flex; flex-direction: column; gap: 8px;
  margin-bottom: 12px;
}
.persona-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  background: var(--bg-elevated); border: 1px solid #1f2330; border-radius: 8px;
  padding: 10px 12px;
}
.persona-row .name {
  font-weight: 600; color: var(--text-primary); font-size: 13px;
}
.persona-row .preview {
  font-size: 12px; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  margin-top: 2px;
}
.persona-row .actions { display: flex; gap: 4px; align-items: center; }
.persona-row button {
  background: transparent; border: 1px solid var(--border-default); color: var(--text-secondary);
  padding: 4px 10px; border-radius: 8px; font-size: 12px; cursor: pointer;
}
.persona-row button:hover { background: #2a2a2a; color: #fff; border-color: #ededed; }
.persona-row button.danger:hover { background: #3a1d24; border-color: #ef4444; }

.persona-add {
  display: grid; gap: 6px;
  background: var(--bg-elevated); border: 1px dashed var(--border-default); border-radius: 8px;
  padding: 10px 12px; margin-bottom: 14px;
}
.persona-add input,
.persona-add textarea {
  background: var(--bg-hover); border: 1px solid var(--border-default); color: var(--text-primary);
  border-radius: 8px; padding: 6px 10px; font-size: 13px;
  font-family: inherit;
}
.persona-add button { justify-self: end; padding: 6px 14px; }

body[data-theme="light"] .persona-row { background: #ffffff; border-color: #e5e7eb; }
body[data-theme="light"] .persona-row .name { color: #111827; }
body[data-theme="light"] .persona-row .preview { color: var(--text-faint); }
body[data-theme="light"] .persona-add { background: #f9fafb; border-color: #e5e7eb; }
body[data-theme="light"] .persona-add input,
body[data-theme="light"] .persona-add textarea {
  background: #ffffff; color: #111827; border-color: #e5e7eb;
}

/* ============================================================
   MACRO PICKER popover (Phase 2 #29)
   Sits next to the chat input. Click 📋 → flyout list of saved
   prompts; click one → drops into the input field.
   ============================================================ */
.macro-pop-wrap { position: relative; flex-shrink: 0; }
#btn-macro-popover { padding: 6px 10px; font-size: 16px; }
.macro-pop {
  position: absolute; bottom: 110%; right: 0;
  width: 280px; max-height: 320px; overflow-y: auto;
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 8px;
  box-shadow: 0 6px 24px rgba(0,0,0,0.45);
  z-index: 50;
  padding: 6px;
}
.macro-pop-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 8px;
  font-size: 12px; color: var(--text-muted); text-transform: uppercase;
  letter-spacing: 0.06em;
  border-bottom: 1px solid #1f2330;
  margin-bottom: 4px;
}
.macro-pop-head button { font-size: 11px; padding: 2px 8px; }
.macro-pop-list { display: flex; flex-direction: column; gap: 2px; }
.macro-pop-item {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none; color: var(--text-primary);
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  font-size: 13px;
}
.macro-pop-item:hover { background: var(--bg-hover); }
.macro-pop-item .label { font-weight: 600; }
.macro-pop-item .preview {
  font-size: 11px; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  margin-top: 2px;
}
.macro-pop-empty {
  padding: 10px; color: var(--text-muted); font-size: 12px; text-align: center;
}

body[data-theme="light"] .macro-pop {
  background: #ffffff; border-color: #e5e7eb;
  box-shadow: 0 6px 24px rgba(0,0,0,0.10);
}
body[data-theme="light"] .macro-pop-head { color: var(--text-faint); border-bottom-color: #e5e7eb; }
body[data-theme="light"] .macro-pop-item { color: #111827; }
body[data-theme="light"] .macro-pop-item:hover { background: #f3f4f6; }
body[data-theme="light"] .macro-pop-item .preview { color: var(--text-faint); }

/* Sidebar legal links (Phase 2 #34) */
.sidebar-legal-links {
  display: flex; gap: 6px; padding: 4px 14px;
  font-size: 11px; color: #5a606e;
}
.sidebar-legal-links a {
  color: inherit; text-decoration: none;
}
.sidebar-legal-links a:hover { color: var(--text-secondary); text-decoration: underline; }
body[data-theme="light"] .sidebar-legal-links { color: #9ca3af; }
body[data-theme="light"] .sidebar-legal-links a:hover { color: #111827; }

/* ============================================================
   VISION INPUT preview (Phase 3 #39)
   When the user attaches an image (📎 / paste / drop), a thumbnail
   pill sits inside the chat input bar with an ✕ to clear.
   ============================================================ */
.chat-image-preview {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 8px 4px 4px;
  background: var(--bg-hover); border: 1px solid var(--border-default); border-radius: 8px;
}
.chat-image-preview img {
  height: 32px; width: 32px; object-fit: cover; border-radius: 4px;
}
.chat-image-preview button { padding: 2px 8px; font-size: 12px; }
.chat-window.drop-target {
  outline: 2px dashed #ededed; outline-offset: -8px;
  background: rgba(237, 237, 237, 0.04);
}
body[data-theme="light"] .chat-image-preview { background: #f3f4f6; border-color: #e5e7eb; }

/* Phase 3 #42 — inline translation panel below a chat bubble */
.chat-bubble-translation {
  margin: 4px 0 8px;
  background: var(--bg-hover); border: 1px solid var(--border-default); border-left: 3px solid #ededed;
  border-radius: 8px; padding: 8px 12px;
  font-size: 13px; color: #d8dae0;
}
.chat-bubble-translation-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; color: var(--text-muted); margin-bottom: 4px;
}
.chat-bubble-translation-head button {
  margin-left: auto; padding: 2px 8px; font-size: 11px;
}
.chat-bubble-translation-body {
  white-space: pre-wrap; word-wrap: break-word; line-height: 1.55;
}
body[data-theme="light"] .chat-bubble-translation {
  background: #ffffff; border-color: #e5e7eb; border-left-color: #ededed;
  color: #1f2937;
}
body[data-theme="light"] .chat-bubble-translation-head { color: var(--text-faint); }

/* ============================================================
   USER AVATAR MENU (richer profile v2 — top-right dropdown)
   ============================================================ */
.user-avatar-btn {
  position: relative;
  width: 36px; height: 36px; border-radius: 50%;
  /* Plain neutral fill when no avatar is set — matches the rest of the
     UI rather than a loud pink/silver gradient. The 👤 fallback char
     centers cleanly on it. */
  background: var(--bg-hover);
  border: 2px solid var(--border-default);
  cursor: pointer; padding: 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-secondary); font-size: 16px;
  transition: transform .12s, border-color .12s;
}
.user-avatar-btn:hover { transform: scale(1.05); border-color: #ededed; }
.user-avatar-btn img {
  width: 100%; height: 100%; object-fit: cover;
}
.user-avatar-btn img:not([src]), .user-avatar-btn img[src=""] { display: none; }
.user-avatar-btn img:not([src]) + #user-avatar-fallback,
.user-avatar-btn img[src=""] + #user-avatar-fallback { display: inline; }
.user-avatar-btn img[src]:not([src=""]) ~ #user-avatar-fallback { display: none; }

/* Fixed-positioned overlay anchored to the viewport's top-right corner.
   Previously `position: absolute` which inherited from the topbar's
   flex context and could shove gallery content sideways when opening.
   Fixed = pure overlay, never affects layout flow. */
.user-menu-flyout {
  position: fixed; top: 56px; right: 14px;
  width: 340px; max-height: calc(100vh - 80px); overflow-y: auto;
  background: var(--bg-elevated); border: 1px solid var(--border-default); border-radius: 12px;
  box-shadow: 0 12px 36px rgba(0,0,0,0.50);
  z-index: 200;
  padding: 10px;
}
.umf-head {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 6px 12px;
  border-bottom: 1px solid #1f2330;
  margin-bottom: 10px;
}
.umf-head img {
  width: 48px; height: 48px; border-radius: 50%;
  object-fit: cover; flex-shrink: 0;
  background: linear-gradient(135deg, #ededed 0%, #b561ff 100%);
}
.umf-head-meta { flex: 1; min-width: 0; }
.umf-name {
  font-weight: 700; color: var(--text-primary); font-size: 14px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.umf-email {
  color: var(--text-muted); font-size: 11px; margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.umf-pencil { padding: 4px 8px; font-size: 12px; flex-shrink: 0; }

.umf-link {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none; color: var(--text-secondary);
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  font-size: 13px; font-family: inherit;
}
.umf-link:hover { background: var(--bg-hover); color: #fff; }
.umf-link.primary {
  background: #1f2535; color: #ededed; font-weight: 600;
  margin-bottom: 10px; text-align: center;
}
.umf-link.primary:hover { background: #2a2a2a; color: #a5b4fc; }

.umf-section { margin-bottom: 10px; }
.umf-section-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 4px 8px;
  font-size: 11px; color: var(--text-muted); text-transform: uppercase;
  letter-spacing: 0.06em;
}
.umf-count {
  background: var(--bg-hover); color: var(--text-secondary); font-weight: 700;
  padding: 1px 8px; border-radius: 8px; font-size: 10px;
  letter-spacing: 0;
}
.umf-tabs {
  display: flex; gap: 4px; padding: 0 4px 6px;
}
.umf-tab {
  background: transparent; border: 1px solid transparent; color: var(--text-muted);
  padding: 3px 10px; border-radius: 999px; cursor: pointer; font-size: 11px;
}
.umf-tab:hover { background: var(--bg-hover); color: var(--text-secondary); }
.umf-tab.active { background: #1f2535; border-color: #ededed; color: #fff; }

.umf-list {
  max-height: 200px; overflow-y: auto;
  padding: 0 4px;
}
.umf-list-item {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px; border-radius: 8px; cursor: pointer;
}
.umf-list-item:hover { background: var(--bg-hover); }
.umf-list-item .av {
  width: 28px; height: 28px; border-radius: 8px; object-fit: cover;
  flex-shrink: 0; background: var(--bg-hover);
}
.umf-list-item .av-circle { border-radius: 50%; }
.umf-list-item .meta { flex: 1; min-width: 0; }
.umf-list-item .name {
  font-size: 13px; color: var(--text-primary); font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.umf-list-item .sub {
  font-size: 11px; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.umf-list-item .badge {
  font-size: 10px; padding: 1px 6px; border-radius: 4px;
  background: #1f2535; color: #ededed;
}
.umf-list-item .badge.private { background: var(--border-default); color: var(--text-secondary); }
.umf-empty { color: var(--text-muted); font-size: 12px; padding: 10px; text-align: center; }

.umf-shortcuts {
  border-top: 1px solid #1f2330; padding-top: 6px; margin-top: 4px;
}

body[data-theme="light"] .user-avatar-btn { border-color: #e5e7eb; }
body[data-theme="light"] .user-menu-flyout {
  background: #ffffff; border-color: #e5e7eb;
  box-shadow: 0 12px 36px rgba(0,0,0,0.12);
}
body[data-theme="light"] .umf-head { border-bottom-color: #e5e7eb; }
body[data-theme="light"] .umf-name { color: #111827; }
body[data-theme="light"] .umf-email { color: var(--text-faint); }
body[data-theme="light"] .umf-link { color: #1f2937; }
body[data-theme="light"] .umf-link:hover { background: #f3f4f6; color: #111827; }
body[data-theme="light"] .umf-link.primary { background: #eef2ff; color: #4338ca; }
body[data-theme="light"] .umf-link.primary:hover { background: #e0e7ff; }
body[data-theme="light"] .umf-section-head { color: var(--text-faint); }
body[data-theme="light"] .umf-count { background: #f3f4f6; color: #1f2937; }
body[data-theme="light"] .umf-tab { color: var(--text-faint); }
body[data-theme="light"] .umf-tab:hover { background: #f3f4f6; color: #111827; }
body[data-theme="light"] .umf-tab.active { background: #eef2ff; color: #4338ca; }
body[data-theme="light"] .umf-list-item:hover { background: #f3f4f6; }
body[data-theme="light"] .umf-list-item .name { color: #111827; }
body[data-theme="light"] .umf-list-item .sub { color: var(--text-faint); }
body[data-theme="light"] .umf-list-item .badge { background: #eef2ff; color: #4338ca; }
body[data-theme="light"] .umf-list-item .badge.private { background: #f3f4f6; color: #4b5563; }
body[data-theme="light"] .umf-shortcuts { border-top-color: #e5e7eb; }

/* Profile-avatar uploader (Edit Profile modal) */
.profile-avatar-uploader {
  display: flex; align-items: center; gap: 14px;
  margin-bottom: 14px;
}
.profile-avatar-preview {
  width: 80px; height: 80px; border-radius: 50%;
  object-fit: cover; flex-shrink: 0;
  background: linear-gradient(135deg, #ededed 0%, #b561ff 100%);
  border: 2px solid var(--border-default);
}
.profile-avatar-preview:not([src]),
.profile-avatar-preview[src=""] {
  background: linear-gradient(135deg, #ededed 0%, #b561ff 100%);
}
.profile-avatar-uploader-controls {
  display: flex; flex-direction: column; gap: 6px;
}
.profile-avatar-uploader-controls button { padding: 6px 14px; font-size: 13px; }
body[data-theme="light"] .profile-avatar-preview { border-color: #e5e7eb; }

/* Group-pick search bar + section heads */
.group-pick-search {
  width: 100%; box-sizing: border-box;
  background: var(--bg-hover); border: 1px solid var(--border-default); color: var(--text-primary);
  border-radius: 8px; padding: 8px 12px; font-size: 13px;
  margin-bottom: 10px;
  font-family: inherit;
}
.group-pick-search:focus { outline: none; border-color: #ededed; }
body[data-theme="light"] .group-pick-search {
  background: #ffffff; color: #111827; border-color: #e5e7eb;
}
.group-pick-section-head {
  font-size: 10px; color: var(--text-muted); text-transform: uppercase;
  letter-spacing: 0.08em; padding: 8px 4px 4px;
}
body[data-theme="light"] .group-pick-section-head { color: var(--text-faint); }
/* Image bubble already styled via .chat-bubble.has-image / .chat-bubble-image */

/* ============================================================
   BROWSER CALL — Phase 3 / Browser-Call rebuild
   Single-card UI with a giant mic button. Status pill on top,
   transcript log on bottom. Designed to feel like FaceTime:
   minimal chrome, character-first.
   ============================================================ */
.bcall-layout {
  display: flex; align-items: center; justify-content: center;
  min-height: calc(100vh - 60px);
  padding: 32px;
  background: radial-gradient(circle at 50% 30%, #1a1d28 0%, var(--bg-base) 70%);
}
.bcall-card {
  display: flex; flex-direction: column; align-items: center; gap: 22px;
  max-width: 520px; width: 100%;
}
.bcall-status {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--text-muted); padding: 4px 14px; border-radius: 999px;
  background: var(--bg-hover); border: 1px solid var(--border-default);
}
.bcall-status.connected   { color: #86efac; border-color: #1f3528; background: #142019; }
.bcall-status.recording   { color: #fca5a5; border-color: #3a1d24; background: #1f1314; }
.bcall-status.thinking    { color: #93c5fd; border-color: #1f2535; background: #14192a; }
.bcall-status.speaking    { color: #fcd34d; border-color: #3a3019; background: #1f1a14; }
.bcall-status.error       { color: #fca5a5; border-color: #ef4444; background: #2a0f12; }

.bcall-mic {
  width: 160px; height: 160px; border-radius: 50%;
  background: linear-gradient(135deg, #ededed 0%, #b561ff 100%);
  border: none; color: #fff; font-size: 64px; cursor: pointer;
  box-shadow: 0 12px 38px rgba(139, 92, 246, 0.5),
              0 0 0 0 rgba(139, 92, 246, 0.45),
              inset 0 2px 0 rgba(255, 255, 255, 0.22);
  transition: transform .15s, box-shadow .15s, background .25s;
}
.bcall-mic:hover { transform: scale(1.04); }
.bcall-mic.recording {
  background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%);
  animation: bcall-pulse 1.6s ease-in-out infinite;
}
@keyframes bcall-pulse {
  0%, 100% { box-shadow: 0 12px 38px rgba(239, 68, 68, 0.5),
                          0 0 0 0  rgba(239, 68, 68, 0.5),
                          inset 0 2px 0 rgba(255, 255, 255, 0.22); }
  50%      { box-shadow: 0 12px 38px rgba(239, 68, 68, 0.5),
                          0 0 0 18px rgba(239, 68, 68, 0),
                          inset 0 2px 0 rgba(255, 255, 255, 0.22); }
}
.bcall-mic:disabled {
  background: var(--border-default); cursor: not-allowed; opacity: 0.6;
  animation: none; transform: none;
}
.bcall-hint { color: var(--text-muted); font-size: 14px; text-align: center; }
.bcall-transcript {
  width: 100%; max-height: 240px; overflow-y: auto;
  background: var(--bg-elevated); border: 1px solid #1f2330; border-radius: 8px;
  padding: 12px 14px; font-size: 13px; line-height: 1.55; color: var(--text-secondary);
  white-space: pre-wrap; word-wrap: break-word;
  font-family: -apple-system, "Segoe UI", system-ui, sans-serif;
}
.bcall-transcript .bcall-line { margin-bottom: 6px; }
.bcall-transcript .bcall-line.user      { color: #93c5fd; }
.bcall-transcript .bcall-line.assistant { color: var(--text-primary); }
.bcall-transcript .bcall-line.system    { color: var(--text-muted); font-style: italic; }
.bcall-transcript:empty { display: none; }

/* Light mode */
body[data-theme="light"] .bcall-layout {
  background: radial-gradient(circle at 50% 30%, #eef2ff 0%, #f9fafb 70%);
}
body[data-theme="light"] .bcall-status {
  background: #ffffff; border-color: #e5e7eb; color: #4b5563;
}
body[data-theme="light"] .bcall-hint { color: var(--text-faint); }
body[data-theme="light"] .bcall-transcript {
  background: #ffffff; border-color: #e5e7eb; color: #1f2937;
}
body[data-theme="light"] .bcall-transcript .bcall-line.assistant { color: #111827; }

/* C3 — Image fade-in. Opt-in via .lazy-fade so we don't blank existing
   inline-styled images. _lazifyImages() in app.js auto-tags every <img>
   on first paint + watches for new ones via MutationObserver. Cached
   images trigger .is-loaded immediately in the same helper, so they
   skip the 250ms fade and feel instant. */
img.lazy-fade {
  opacity: 0;
  transition: opacity 250ms ease;
}
img.lazy-fade.is-loaded {
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  img.lazy-fade { transition: none; }
}

/* A3 — Pull-to-refresh pill. Sits above the scrollable container's top
   edge; transform moves it down as the user pulls. .ready highlights
   when past the trigger threshold; .spinning runs the rotation. */
.ptr-pill {
  position: absolute; top: -36px; left: 50%;
  transform: translateX(-50%);
  width: 36px; height: 36px;
  border-radius: 50%;
  background: rgba(20, 24, 30, 0.9);
  border: 1px solid rgba(255, 255, 255, 0.18);
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
  opacity: 0;
  transition: opacity 120ms ease;
  z-index: 50;
}
.ptr-pill.visible { opacity: 1; }
.ptr-pill.ready  { background: rgba(99, 102, 241, 0.95); border-color: rgba(255, 255, 255, 0.4); }
.ptr-spinner {
  width: 16px; height: 16px;
  border: 2px solid rgba(255, 255, 255, 0.25);
  border-top-color: #fff;
  border-radius: 50%;
}
.ptr-pill.spinning .ptr-spinner { animation: ptr-spin 700ms linear infinite; }
@keyframes ptr-spin {
  to { transform: rotate(360deg); }
}

/* C4 — iOS PWA polish. When the app is launched from the Home Screen
   (display-mode: standalone), the status bar overlays content because
   we use status-bar-style: black-translucent. Push every top-edge bit
   of chrome down by env(safe-area-inset-top) so nothing tucks under
   the notch. The body class is toggled by JS on init for browsers that
   don't support the @media variant (older iOS Safari). */
@media (display-mode: standalone) {
  body { padding-top: env(safe-area-inset-top); }
  .app-sidebar { padding-top: calc(20px + env(safe-area-inset-top)); }
  .chat-header,
  .feed-head,
  .gallery-header,
  .library-head,
  .profile-head { padding-top: calc(env(safe-area-inset-top) + 8px); }
}
body.pwa-standalone { padding-top: env(safe-area-inset-top); }
body.pwa-standalone .app-sidebar { padding-top: calc(20px + env(safe-area-inset-top)); }

/* C5 — Bottom-sheet / centered confirm dialog. Backdrop fades, card
   slides up on mobile (bottom-sheet feel) or scales in on desktop. */
.confirm-back {
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex; align-items: center; justify-content: center;
  z-index: 5000;
  opacity: 0;
  transition: opacity 180ms ease;
}
.confirm-back.open { opacity: 1; }
.confirm-back.closing { opacity: 0; }
.confirm-card {
  background: #1a1d24;
  color: #f5f1ea;
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 16px;
  padding: 22px 22px 18px;
  max-width: 380px; width: calc(100% - 32px);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.55);
  transform: scale(0.96);
  opacity: 0;
  transition: transform 200ms cubic-bezier(0.2, 0.8, 0.2, 1), opacity 180ms ease;
}
.confirm-back.open .confirm-card { transform: scale(1); opacity: 1; }
.confirm-title {
  font-size: 16px; font-weight: 600; margin: 0 0 6px;
}
.confirm-msg {
  font-size: 14.5px; line-height: 1.5; color: #d4d0c9;
  margin-bottom: 18px;
}
.confirm-actions {
  display: flex; gap: 10px; justify-content: flex-end;
}
.confirm-cancel,
.confirm-ok {
  padding: 10px 18px;
  border-radius: 999px;
  font-size: 14px; font-weight: 600;
  border: 1px solid transparent;
  cursor: pointer;
  min-height: 40px;
}
.confirm-cancel {
  background: transparent;
  border-color: rgba(255, 255, 255, 0.16);
  color: #d4d0c9;
}
.confirm-ok.primary { background: #6366f1; color: #fff; }
.confirm-ok.danger  { background: #dc2626; color: #fff; }
.confirm-cancel:hover { background: rgba(255, 255, 255, 0.06); }
.confirm-ok.primary:hover { background: #5557e3; }
.confirm-ok.danger:hover  { background: #b91c1c; }
@media (max-width: 720px) {
  .confirm-back {
    align-items: flex-end;
  }
  .confirm-card {
    width: 100%; max-width: none;
    border-radius: 18px 18px 0 0;
    padding: 22px 20px calc(18px + env(safe-area-inset-bottom, 0px));
    transform: translateY(100%);
  }
  .confirm-back.open .confirm-card { transform: translateY(0); }
  .confirm-cancel, .confirm-ok { min-height: 48px; padding: 12px 20px; flex: 1; }
}

/* B4 — Swipe-to-delete on chat history (and similar lists). The row
   becomes positioning context; .swipe-inner holds the visible content
   and slides left over a red action pane revealed underneath. */
.swipe-row {
  position: relative;
  overflow: hidden;
}
.swipe-row .swipe-inner {
  position: relative;
  background: inherit;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: inherit;
  /* Inherit the row's own padding so content stays in place when not swiped. */
}
.swipe-row .swipe-action {
  position: absolute;
  top: 0; right: 0; bottom: 0;
  width: 80px;
  background: #dc2626;
  color: #fff;
  border: none;
  font-size: 13px; font-weight: 700;
  cursor: pointer;
  z-index: 0;
}
.swipe-row .swipe-action:active { background: #b91c1c; }

/* B5 — Story sidebar as bottom-sheet on mobile. The sidebar becomes a
   fixed-position panel sliding up from the bottom. The .sidebar-collapsed
   class on .story-layout (already toggled by existing JS) controls open
   vs closed: collapsed = sheet is hidden; not collapsed = sheet is up.
   Backdrop is rendered via the sidebar's box-shadow + a ::before on the
   layout that catches taps to dismiss. */
@media (max-width: 720px) {
  .story-layout {
    grid-template-columns: minmax(0, 1fr) !important;
  }
  .story-layout .story-sidebar {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    top: auto;
    z-index: 4000;
    /* Min-height so the bottom sheet always reads as a clear panel — without
       this it collapses to ~120px when the story list is empty and looks
       like nothing happened on tap. Max stays at 75vh so we don't cover
       the whole screen. */
    min-height: 50vh;
    max-height: 75vh;
    border-right: none;
    border-top: 1px solid var(--border-default);
    border-radius: 18px 18px 0 0;
    box-shadow: 0 -10px 40px rgba(0, 0, 0, 0.45);
    transform: translateY(0);
    transition: transform 240ms cubic-bezier(0.2, 0.8, 0.2, 1),
                opacity 200ms ease,
                visibility 200ms;
    opacity: 1; visibility: visible;
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .story-layout.sidebar-collapsed .story-sidebar {
    transform: translateY(100%);
    opacity: 1;        /* ignore desktop's fade — we slide instead */
    visibility: hidden;
  }
  /* Backdrop while the sheet is open. Tap outside the sheet to close. */
  .story-layout:not(.sidebar-collapsed)::before {
    content: "";
    position: fixed; inset: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 3999;
    animation: ptr-spin 0s;  /* placeholder no-op to avoid layout flash */
  }
  /* Reposition the floating expand handle into a centered "Show stories"
     pill at the top of the reader, more thumb-friendly than the corner
     chevron. The collapse button on the sheet itself dismisses. */
  .story-sidebar-expand-btn {
    top: 8px; left: 50% !important;
    transform: translateX(-50%);
    width: auto !important; height: auto !important;
    padding: 6px 14px !important;
    border-radius: 999px !important;
    border-left: 1px solid var(--border-default) !important;
    background: var(--bg-elevated) !important;
    font-size: 12px;
  }
  .story-sidebar-expand-btn::after {
    content: "Stories";
    margin-left: 4px;
  }
}

/* =========================================================
   PHASE 3 — Chat-style story format
   When story.format === "chat", story-body gets .story-format-chat and
   each beat renders as a chat bubble (left/right by speaker, with avatar
   on character bubbles, italic-centered for narrator action lines).
   ========================================================= */
.story-format-chat {
  font-family: -apple-system, "Segoe UI", system-ui, sans-serif !important;
  padding: 16px 14px;
}
.story-format-chat .story-beat {
  font-family: -apple-system, "Segoe UI", system-ui, sans-serif !important;
  display: flex;
  align-items: flex-end;
  gap: 8px;
  margin-bottom: 6px;
  padding: 0;
  background: transparent !important;
  font-size: 14.5px;
  line-height: 1.4;
}
/* User beats — right-aligned bubble */
.story-format-chat .story-beat.role-user {
  flex-direction: row-reverse;
  font-style: normal;
  border-left: none;
  padding-left: 0;
  color: var(--text-primary);
  font-size: 14.5px;
}
.story-format-chat .story-beat.role-user .story-beat-text {
  background: rgba(99, 102, 241, 0.20);
  border: 1px solid rgba(99, 102, 241, 0.35);
  color: var(--text-primary);
  padding: 9px 14px;
  border-radius: 16px 16px 4px 16px;
  max-width: 70%;
  white-space: pre-wrap;
}
/* Character beats — left-aligned bubble, avatar visible */
.story-format-chat .story-beat.role-character {
  color: var(--text-primary);
}
.story-format-chat .story-beat.role-character .story-beat-text {
  background: var(--bg-elevated);
  border: 1px solid var(--border-default);
  padding: 9px 14px;
  border-radius: 16px 16px 16px 4px;
  max-width: 70%;
  white-space: pre-wrap;
}
.story-beat-avatar {
  width: 32px; height: 32px; border-radius: 50%;
  flex-shrink: 0; overflow: hidden;
  background: var(--bg-hover); border: 1px solid var(--border-subtle);
}
.story-beat-avatar img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
/* Narrator beats — centered italic, like a scene direction. No bubble. */
.story-format-chat .story-beat.role-narrator {
  justify-content: center;
  font-style: italic;
  color: var(--text-muted);
  font-size: 13px;
  margin: 10px 0;
}
.story-format-chat .story-beat.role-narrator .story-beat-text {
  background: transparent;
  border: none;
  padding: 0;
  text-align: center;
  max-width: 80%;
}
/* Library card badge for chat-style books — corner tag */
.library-card-cover { position: relative; }
.library-card-badge {
  position: absolute; top: 8px; right: 8px;
  background: rgba(99, 102, 241, 0.92);
  color: #fff;
  font-size: 11px; font-weight: 600;
  padding: 3px 8px;
  border-radius: 999px;
  letter-spacing: 0.02em;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}

/* Inline manga panels — image below the bubble */
.story-beat-image {
  display: block;
  max-width: 100%;
  max-height: 360px;
  border-radius: 12px;
  margin-top: 6px;
  cursor: zoom-in;
}
/* Chapter cards inside chat format keep their chapter heading + summary
   so the book structure is still navigable. Slim the chrome though. */
.story-format-chat .story-chapter-card {
  background: transparent;
  border: none;
  padding: 8px 0;
  margin: 10px 0;
}
.story-format-chat .story-chapter-header {
  border-bottom: 1px solid var(--border-subtle);
  padding-bottom: 6px;
  margin-bottom: 12px;
}

/* =========================================================
   PHASE 4 D1 — Dynamic font-size preference. Body attribute
   data-font-size drives a chat-bubble rem scale. */
body[data-font-size="small"]   .chat-bubble { font-size: 13px; }
body[data-font-size="default"] .chat-bubble { font-size: 15px; }
body[data-font-size="large"]   .chat-bubble { font-size: 17px; line-height: 1.55; }
body[data-font-size="xlarge"]  .chat-bubble { font-size: 19px; line-height: 1.6; }

/* =========================================================
   PHASE 4 D2 — High-contrast mode. Bumps text contrast and adds
   visible borders to bubbles and primary buttons. */
body.pref-high-contrast {
  --text-primary: #ffffff;
  --text-secondary: #f1f5f9;
  --text-muted: #cbd5e1;
  --border-default: #ffffff;
  --border-subtle: rgba(255,255,255,0.55);
}
body.pref-high-contrast .chat-bubble {
  border: 2px solid #ffffff !important;
}
body.pref-high-contrast .primary {
  outline: 1px solid #ffffff;
}
body.pref-high-contrast[data-theme="light"] {
  --text-primary: #000000;
  --text-secondary: #111111;
  --text-muted: #1f2937;
  --border-default: #000000;
  --border-subtle: rgba(0,0,0,0.6);
}
body.pref-high-contrast[data-theme="light"] .chat-bubble {
  border: 2px solid #000000 !important;
}

/* Prefs fieldset inside the Edit Profile modal — modest framing so it
   doesn't compete with the avatar/bio inputs above. */
.prefs-fieldset {
  margin: 14px 0 8px;
  padding: 10px 14px 14px;
  border: 1px solid var(--border-default);
  border-radius: 8px;
}
.prefs-fieldset legend {
  font-size: 12px; color: var(--text-muted);
  padding: 0 6px;
  text-transform: uppercase; letter-spacing: 0.06em;
}
.prefs-row { margin-top: 8px; }
.prefs-toggle {
  display: inline-flex; align-items: center; gap: 8px;
  cursor: pointer; font-size: 14px;
}

/* =========================================================
   PHASE 4 B9 — Visual feedback during long-press hold. JS adds
   .is-long-pressing on touchstart and clears on end/cancel. We use
   a 450ms scale transition so the element visibly "depresses" while
   the user holds, then snaps back if they release before trigger. */
.is-long-pressing {
  transform: scale(0.97);
  transition: transform 350ms cubic-bezier(.4, 0, .2, 1);
  filter: brightness(0.92);
}

/* =========================================================
   PHASE 4 B6 — Global reduced-motion guard. iOS / macOS users with
   "Reduce Motion" enabled in Settings → Accessibility should see the
   UI snap rather than slide. Catches everything we haven't already
   individually guarded (shimmer, ptr-spinner, fade-up, badge pop, etc.)
========================================================= */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .skel-shimmer, .skeleton-banner, .skeleton-line,
  .chat-skel-bubble, .ptr-spinner {
    animation: none !important;
    background-image: none !important;
  }
  .chat-scroll-bottom-btn { transition: opacity 0.001ms !important; }
}

/* =========================================================
   PHASE 4 E3 — Long character names overflow the chat header. Identity
   tile must allow its text to ellipsis instead of pushing the action
   buttons off-screen. */
.chat-header-identity {
  min-width: 0;
}
.chat-header-identity .chat-header-name,
#chat-header-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* =========================================================
   PHASE 4 E2 — Stop iOS Safari from auto-scrolling the page when a
   small search input gets focused near the bottom of the viewport.
   Keeping font-size >= 16px also prevents the zoom-in pinch. We patch
   the gallery + library search bars which were the noisy spots. */
@media (max-width: 720px) {
  #gallery-search,
  #library-search,
  #feed-search,
  .chat-search-bar input,
  input[type="search"] {
    font-size: 16px;
  }
}

