/* ==========================================================================
   Splash screen — covers the viewport instantly on load, independent of
   light/dark mode (always the moody dark treatment), fades out once app.js
   confirms the auth state and the right screen is ready underneath.
   ========================================================================== */
.splash-screen {
  position: fixed;
  inset: 0;
  z-index: 5000;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: #12060f;
  transition: opacity 460ms cubic-bezier(0.22, 1, 0.36, 1), visibility 460ms cubic-bezier(0.22, 1, 0.36, 1);
}
.splash-screen::before {
  content: "";
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(38% 32% at 20% 22%, rgba(255, 122, 69, 0.34), transparent 60%),
    radial-gradient(42% 36% at 82% 78%, rgba(20, 184, 166, 0.32), transparent 60%),
    radial-gradient(30% 26% at 85% 15%, rgba(255, 176, 32, 0.24), transparent 60%);
  filter: blur(10px);
  animation: splash-mesh-drift 9s ease-in-out infinite alternate;
}
.splash-screen.splash-hide {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
@keyframes splash-mesh-drift {
  from { transform: translate(-2%, -1%) scale(1); }
  to   { transform: translate(2%, 2%) scale(1.08); }
}

.splash-floaty {
  position: absolute;
  color: rgba(255, 213, 230, 0.5);
  font-size: 1.3rem;
  pointer-events: none;
  animation: splash-float 6s ease-in-out infinite;
}
.splash-floaty-1 { top: 18%; left: 12%; font-size: 1.6rem; animation-delay: 0s; }
.splash-floaty-2 { top: 28%; right: 14%; font-size: 1.1rem; color: rgba(196, 165, 255, 0.55); animation-delay: 1.1s; }
.splash-floaty-3 { bottom: 24%; left: 18%; font-size: 1rem; animation-delay: 2.2s; }
.splash-floaty-4 { top: 62%; right: 20%; font-size: 1.4rem; color: rgba(196, 165, 255, 0.4); animation-delay: 3.1s; }
.splash-floaty-5 { bottom: 16%; right: 30%; font-size: 0.95rem; animation-delay: 4s; }
@keyframes splash-float {
  0%, 100% { transform: translateY(0) rotate(0deg); opacity: 0.4; }
  50% { transform: translateY(-18px) rotate(10deg); opacity: 0.8; }
}

.splash-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  animation: splash-rise 560ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.splash-badge-ring {
  position: relative;
  width: 92px;
  height: 92px;
  display: grid;
  place-items: center;
  margin-bottom: 6px;
}
.splash-badge-ring::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(from 0deg, #FF7A45, #FFB020, #14B8A6, #FF7A45);
  animation: splash-ring-spin 3.2s linear infinite;
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
  mask: radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
}
.splash-badge-ring::after {
  content: "";
  position: absolute;
  inset: -10px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 122, 69, 0.35), transparent 70%);
  animation: splash-glow-pulse 2.2s ease-in-out infinite;
}
.splash-badge {
  position: relative;
  width: 68px;
  height: 68px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: "Fraunces", Georgia, serif;
  font-weight: 700;
  font-size: 1.7rem;
  color: #fff;
  background: linear-gradient(135deg, #FF7A45 0%, #FFB020 55%, #14B8A6 100%);
  box-shadow: 0 10px 30px rgba(255, 122, 69, 0.45);
}
@keyframes splash-ring-spin { to { transform: rotate(360deg); } }
@keyframes splash-glow-pulse {
  0%, 100% { opacity: 0.5; transform: scale(1); }
  50% { opacity: 0.9; transform: scale(1.12); }
}

.splash-name {
  font-family: "Fraunces", Georgia, serif;
  font-weight: 600;
  font-size: 1.5rem;
  letter-spacing: 0.01em;
  background: linear-gradient(100deg, #ffd7e4 0%, #ff9fc4 25%, #e2b6ff 50%, #ff9fc4 75%, #ffd7e4 100%);
  background-size: 220% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: splash-shimmer 3.2s linear infinite;
}
@keyframes splash-shimmer {
  to { background-position: -220% center; }
}

.splash-tagline {
  color: rgba(255, 230, 240, 0.55);
  font-size: 0.82rem;
  letter-spacing: 0.02em;
  margin-bottom: 10px;
  animation: splash-fade-in 700ms ease 200ms both;
}
@keyframes splash-fade-in {
  from { opacity: 0; } to { opacity: 1; }
}

.splash-orbit {
  position: relative;
  width: 44px;
  height: 44px;
}
.splash-orbit span {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 7px;
  height: 7px;
  margin: -3.5px;
  border-radius: 50%;
  background: #FF7A45;
  box-shadow: 0 0 8px rgba(255, 122, 69, 0.8);
  animation: splash-orbit-spin 1.1s cubic-bezier(0.5, 0, 0.5, 1) infinite;
  transform-origin: 3.5px 3.5px;
}
.splash-orbit span:nth-child(2) { background: #FFB020; box-shadow: 0 0 8px rgba(255, 176, 32, 0.8); animation-delay: -0.36s; }
.splash-orbit span:nth-child(3) { background: #14B8A6; box-shadow: 0 0 8px rgba(20, 184, 166, 0.8); animation-delay: -0.72s; }
@keyframes splash-orbit-spin {
  from { transform: rotate(0deg) translateX(20px) rotate(0deg); }
  to   { transform: rotate(360deg) translateX(20px) rotate(-360deg); }
}

@keyframes splash-rise {
  from { opacity: 0; transform: translateY(10px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .splash-screen::before,
  .splash-floaty,
  .splash-badge-ring::before,
  .splash-badge-ring::after,
  .splash-name,
  .splash-orbit span {
    animation-duration: 2600ms;
  }
}


/* ==========================================================================
   MERA — premium design system
   ========================================================================== */
:root {
  color-scheme: light;
  --bg: #FBF6F8;
  --bg-soft: #F3E9EF;
  --surface: #FFFFFF;
  --surface-2: #FDF7FA;
  --surface-glass: rgba(255, 255, 255, 0.68);
  --ink: #211224;
  --muted: #7A6B78;
  --border: rgba(33, 18, 36, 0.08);
  --border-strong: rgba(33, 18, 36, 0.15);

  --accent: #FF7A45;         /* coral */
  --accent-2: #14B8A6;       /* teal */
  --accent-ink: #211224;     /* dark ink reads better on coral/teal than white (WCAG AA) */
  --accent-text: #CF3B00;    /* deepened coral for readable text/links on light backgrounds */
  --accent-soft: rgba(255, 122, 69, 0.15);
  --violet-soft: rgba(20, 184, 166, 0.14);
  --gradient: linear-gradient(135deg, var(--accent) 0%, #FFB020 55%, var(--accent-2) 100%);
  --gradient-soft: linear-gradient(135deg, rgba(255, 122, 69, 0.16), rgba(20, 184, 166, 0.14));

  --gold: #F5A524;
  --gold-2: #F76B1C;
  --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));

  --success: #17B26A;
  --success-soft: rgba(23, 178, 106, 0.13);
  --danger: #F14A4A;
  --danger-soft: rgba(241, 74, 74, 0.12);

  --shadow-sm: 0 2px 9px rgba(89, 20, 60, 0.053);
  --shadow-md: 0 8px 22px rgba(89, 20, 60, 0.084);
  --shadow-lg: 0 15px 42px rgba(60, 12, 46, 0.13);
  --glow-accent: 0 6px 15px rgba(255, 122, 69, 0.238);
  --glow-gold: 0 6px 14px rgba(247, 107, 28, 0.238);

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --font-display: "Space Grotesk", "Plus Jakarta Sans", "Segoe UI", sans-serif;
  --font-body: "Plus Jakarta Sans", "Segoe UI", Roboto, Arial, sans-serif;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --nav-h: 64px;
  --blur-glass: blur(14px) saturate(130%);
  --page-pad: 14px;
  --vh: 100dvh;
  /* Set from Telegram.WebApp.safeAreaInset / contentSafeAreaInset in app.js.
     Covers the strip Telegram's own native chrome (home indicator, bottom
     panel it sometimes reserves) can occupy inside the Mini App WebView —
     env(safe-area-inset-*) alone doesn't know about this, so every fixed
     bottom element below adds this on top of it, not instead of it. */
  --tg-safe-bottom: 0px;
}

/* True full-screen on every device: fall back to a JS-measured --vh (set in
   app.js from window.innerHeight) for the handful of browsers that don't
   support dvh yet, so the shell never falls short of or overshoots the
   real visible viewport. */
html, body {
  height: 100%;
  margin: 0;
  overscroll-behavior-y: none;
}
#root, .app-shell { height: var(--vh); }

/* Fallback for anyone without JS/localStorage yet — respects OS preference.
   theme.js overrides this instantly by setting data-theme explicitly. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]), :root[data-theme="auto"] {
    color-scheme: dark;
    --bg: #170D1B;
    --bg-soft: #1D1121;
    --surface: #221329;
    --surface-2: #2A1731;
    --surface-glass: rgba(34, 19, 41, 0.62);
    --ink: #F7EFF6;
    --muted: #B3A2B0;
    --border: rgba(255, 255, 255, 0.09);
    --border-strong: rgba(255, 255, 255, 0.18);
    --accent-text: #FF7A45; /* full-strength coral reads fine on a dark background */
    --accent-soft: rgba(255, 122, 69, 0.2);
    --violet-soft: rgba(20, 184, 166, 0.22);
    --success-soft: rgba(31, 200, 128, 0.2);
    --danger-soft: rgba(255, 100, 100, 0.18);
    --shadow-sm: 0 2px 9px rgba(0, 0, 0, 0.24);
    --shadow-md: 0 8px 22px rgba(0, 0, 0, 0.294);
    --shadow-lg: 0 15px 42px rgba(0, 0, 0, 0.396);
  }
}

/* ==========================================================================
   THEMES — explicit picks always win over the OS-preference fallback above.
   Every theme only ever redefines these same tokens, so every component in
   the app (already built entirely on var(--...)) reskins for free — no
   component-level theme logic needed anywhere else in the stylesheet.
   ========================================================================== */

/* Sunshine — the original palette, pinned to light regardless of OS. */
:root[data-theme="sunset"] {
  color-scheme: light;
  --bg: #FBF6F8; --bg-soft: #F3E9EF; --surface: #FFFFFF; --surface-2: #FDF7FA;
  --surface-glass: rgba(255, 255, 255, 0.68);
  --ink: #211224; --muted: #7A6B78;
  --border: rgba(33, 18, 36, 0.08); --border-strong: rgba(33, 18, 36, 0.15);
  --accent: #FF7A45; --accent-2: #14B8A6; --accent-ink: #211224;
  --accent-text: #CF3B00;
  --accent-soft: rgba(255, 122, 69, 0.13); --violet-soft: rgba(20, 184, 166, 0.14);
  --gradient: linear-gradient(135deg, var(--accent) 0%, #FFB020 55%, var(--accent-2) 100%);
  --gradient-soft: linear-gradient(135deg, rgba(255, 122, 69, 0.14), rgba(20, 184, 166, 0.14));
  --gold: #F5A524; --gold-2: #F76B1C; --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));
  --success: #17B26A; --success-soft: rgba(23, 178, 106, 0.13);
  --danger: #F14A4A; --danger-soft: rgba(241, 74, 74, 0.12);
  --shadow-sm: 0 2px 9px rgba(89, 20, 60, 0.053); --shadow-md: 0 8px 22px rgba(89, 20, 60, 0.084);
  --shadow-lg: 0 15px 42px rgba(60, 12, 46, 0.13);
  --glow-accent: 0 6px 15px rgba(255, 122, 69, 0.238); --glow-gold: 0 6px 14px rgba(247, 107, 28, 0.238);
}

/* Midnight — the original dark palette, pinned regardless of OS. */
:root[data-theme="midnight"] {
  color-scheme: dark;
  --bg: #170D1B; --bg-soft: #1D1121; --surface: #221329; --surface-2: #2A1731;
  --surface-glass: rgba(34, 19, 41, 0.62);
  --ink: #F7EFF6; --muted: #B3A2B0;
  --border: rgba(255, 255, 255, 0.09); --border-strong: rgba(255, 255, 255, 0.18);
  --accent: #FF7A45; --accent-2: #14B8A6; --accent-ink: #211224;
  --accent-text: #FF7A45;
  --accent-soft: rgba(255, 122, 69, 0.2); --violet-soft: rgba(20, 184, 166, 0.22);
  --gradient: linear-gradient(135deg, var(--accent) 0%, #FFB020 55%, var(--accent-2) 100%);
  --gradient-soft: linear-gradient(135deg, rgba(255, 122, 69, 0.14), rgba(20, 184, 166, 0.14));
  --gold: #F5A524; --gold-2: #F76B1C; --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));
  --success: #17B26A; --success-soft: rgba(31, 200, 128, 0.2);
  --danger: #F14A4A; --danger-soft: rgba(255, 100, 100, 0.18);
  --shadow-sm: 0 2px 9px rgba(0, 0, 0, 0.24); --shadow-md: 0 8px 22px rgba(0, 0, 0, 0.294);
  --shadow-lg: 0 15px 42px rgba(0, 0, 0, 0.396);
  --glow-accent: 0 6px 15px rgba(255, 122, 69, 0.272); --glow-gold: 0 6px 14px rgba(247, 107, 28, 0.272);
}

/* Neon Nights — dark cyberpunk cyan/magenta. */
:root[data-theme="neon"] {
  color-scheme: dark;
  --bg: #05060F; --bg-soft: #0A0C1B; --surface: #10132A; --surface-2: #151935;
  --surface-glass: rgba(16, 19, 42, 0.6);
  --ink: #EAF6FF; --muted: #8FA3C7;
  --border: rgba(0, 240, 255, 0.14); --border-strong: rgba(0, 240, 255, 0.28);
  --accent: #00E8FF; --accent-2: #FF2FD6; --accent-ink: #06131A;
  --accent-text: #00E8FF;
  --accent-soft: rgba(0, 232, 255, 0.18); --violet-soft: rgba(255, 47, 214, 0.18);
  --gradient: linear-gradient(135deg, #00E8FF 0%, #7B5CFF 50%, #FF2FD6 100%);
  --gradient-soft: linear-gradient(135deg, rgba(0, 232, 255, 0.18), rgba(255, 47, 214, 0.16));
  --gold: #FFD400; --gold-2: #FF9900; --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));
  --success: #23F0A5; --success-soft: rgba(35, 240, 165, 0.18);
  --danger: #FF4D6D; --danger-soft: rgba(255, 77, 109, 0.18);
  --shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.338); --shadow-md: 0 8px 23px rgba(0, 0, 0, 0.385);
  --shadow-lg: 0 15px 44px rgba(0, 0, 0, 0.468);
  --glow-accent: 0 0 32px rgba(0, 232, 255, 0.45); --glow-gold: 0 0 26px rgba(255, 153, 0, 0.4);
}

/* Ocean Breeze — light, clean teal/blue. */
:root[data-theme="ocean"] {
  color-scheme: light;
  --bg: #F2FAFB; --bg-soft: #E3F2F4; --surface: #FFFFFF; --surface-2: #F7FDFE;
  --surface-glass: rgba(255, 255, 255, 0.68);
  --ink: #0B2530; --muted: #59767F;
  --border: rgba(11, 37, 48, 0.08); --border-strong: rgba(11, 37, 48, 0.16);
  --accent: #00B4D8; --accent-2: #0092DF; --accent-ink: #0B2530;
  --accent-text: #007D96;
  --accent-soft: rgba(0, 180, 216, 0.13); --violet-soft: rgba(0, 119, 182, 0.12);
  --gradient: linear-gradient(135deg, #00B4D8 0%, #0096C7 55%, #0092DF 100%);
  --gradient-soft: linear-gradient(135deg, rgba(0, 180, 216, 0.14), rgba(0, 119, 182, 0.14));
  --gold: #FFB703; --gold-2: #FB8500; --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));
  --success: #17B26A; --success-soft: rgba(23, 178, 106, 0.13);
  --danger: #E63946; --danger-soft: rgba(230, 57, 70, 0.12);
  --shadow-sm: 0 2px 9px rgba(11, 37, 48, 0.06); --shadow-md: 0 8px 22px rgba(11, 37, 48, 0.084);
  --shadow-lg: 0 15px 42px rgba(11, 37, 48, 0.13);
  --glow-accent: 0 6px 15px rgba(0, 180, 216, 0.238); --glow-gold: 0 6px 14px rgba(251, 133, 0, 0.238);
}

/* Aurora — dark violet/teal-green gradient sky. */
:root[data-theme="aurora"] {
  color-scheme: dark;
  --bg: #0B0F1A; --bg-soft: #101728; --surface: #151D33; --surface-2: #1B2540;
  --surface-glass: rgba(21, 29, 51, 0.6);
  --ink: #EAF2FF; --muted: #8B9BC0;
  --border: rgba(255, 255, 255, 0.08); --border-strong: rgba(255, 255, 255, 0.16);
  --accent: #7C4DFF; --accent-2: #00845C; --accent-ink: #FFFFFF;
  --accent-text: #9169FF;
  --accent-soft: rgba(124, 77, 255, 0.2); --violet-soft: rgba(0, 229, 160, 0.16);
  --gradient: linear-gradient(135deg, #7C4DFF 0%, #3D8BFF 50%, #00845C 100%);
  --gradient-soft: linear-gradient(135deg, rgba(124, 77, 255, 0.18), rgba(0, 229, 160, 0.14));
  --gold: #FFC857; --gold-2: #FF7A00; --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));
  --success: #00E5A0; --success-soft: rgba(0, 229, 160, 0.18);
  --danger: #FF5C7A; --danger-soft: rgba(255, 92, 122, 0.18);
  --shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.3); --shadow-md: 0 8px 23px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 15px 44px rgba(0, 0, 0, 0.432);
  --glow-accent: 0 0 30px rgba(124, 77, 255, 0.4); --glow-gold: 0 0 24px rgba(255, 122, 0, 0.35);
}

/* Golden Hour — light warm amber/orange. */
:root[data-theme="amber"] {
  color-scheme: light;
  --bg: #FFF8EE; --bg-soft: #FDEFDA; --surface: #FFFFFF; --surface-2: #FFFAF2;
  --surface-glass: rgba(255, 255, 255, 0.68);
  --ink: #2B1B0E; --muted: #886E54;
  --border: rgba(43, 27, 14, 0.08); --border-strong: rgba(43, 27, 14, 0.16);
  --accent: #F5A524; --accent-2: #F76B1C; --accent-ink: #2B1B0E;
  --accent-text: #A16607;
  --accent-soft: rgba(245, 165, 36, 0.16); --violet-soft: rgba(247, 107, 28, 0.14);
  --gradient: linear-gradient(135deg, #FFC24B 0%, #F5A524 55%, #F76B1C 100%);
  --gradient-soft: linear-gradient(135deg, rgba(255, 194, 75, 0.18), rgba(247, 107, 28, 0.14));
  --gold: #FFD166; --gold-2: #E85D04; --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));
  --success: #2D9E5B; --success-soft: rgba(45, 158, 91, 0.13);
  --danger: #D62828; --danger-soft: rgba(214, 40, 40, 0.12);
  --shadow-sm: 0 2px 9px rgba(43, 27, 14, 0.06); --shadow-md: 0 8px 22px rgba(43, 27, 14, 0.084);
  --shadow-lg: 0 15px 42px rgba(43, 27, 14, 0.13);
  --glow-accent: 0 6px 15px rgba(245, 165, 36, 0.238); --glow-gold: 0 6px 14px rgba(232, 93, 4, 0.238);
}

/* Forest — light, earthy green. */
:root[data-theme="forest"] {
  color-scheme: light;
  --bg: #F3F8F1; --bg-soft: #E5F0E1; --surface: #FFFFFF; --surface-2: #F8FBF6;
  --surface-glass: rgba(255, 255, 255, 0.68);
  --ink: #1B2A1C; --muted: #5C775D;
  --border: rgba(27, 42, 28, 0.08); --border-strong: rgba(27, 42, 28, 0.16);
  --accent: #2E7D32; --accent-2: #3B853F; --accent-ink: #FFFFFF;
  --accent-text: #2E7D32;
  --accent-soft: rgba(46, 125, 50, 0.14); --violet-soft: rgba(102, 187, 106, 0.14);
  --gradient: linear-gradient(135deg, #2E7D32 0%, #4C9A4C 55%, #8BC34A 100%);
  --gradient-soft: linear-gradient(135deg, rgba(46, 125, 50, 0.14), rgba(139, 195, 74, 0.14));
  --gold: #C9A227; --gold-2: #8D6E1F; --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));
  --success: #2E7D32; --success-soft: rgba(46, 125, 50, 0.14);
  --danger: #C1442E; --danger-soft: rgba(193, 68, 46, 0.12);
  --shadow-sm: 0 2px 9px rgba(27, 42, 28, 0.06); --shadow-md: 0 8px 22px rgba(27, 42, 28, 0.084);
  --shadow-lg: 0 15px 42px rgba(27, 42, 28, 0.13);
  --glow-accent: 0 6px 15px rgba(46, 125, 50, 0.204); --glow-gold: 0 6px 14px rgba(141, 110, 31, 0.204);
}

/* Cosmic Purple — dark, deep indigo/violet. */
:root[data-theme="cosmic"] {
  color-scheme: dark;
  --bg: #0E0817; --bg-soft: #150F22; --surface: #1B1330; --surface-2: #221A3B;
  --surface-glass: rgba(27, 19, 48, 0.6);
  --ink: #F1EAFB; --muted: #A996C4;
  --border: rgba(255, 255, 255, 0.09); --border-strong: rgba(255, 255, 255, 0.18);
  --accent: #B45CFF; --accent-2: #5C7CFF; --accent-ink: #0E0817;
  --accent-text: #B45CFF;
  --accent-soft: rgba(180, 92, 255, 0.2); --violet-soft: rgba(92, 124, 255, 0.18);
  --gradient: linear-gradient(135deg, #B45CFF 0%, #8C5CFF 50%, #5C7CFF 100%);
  --gradient-soft: linear-gradient(135deg, rgba(180, 92, 255, 0.18), rgba(92, 124, 255, 0.16));
  --gold: #FFC857; --gold-2: #FF7A00; --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));
  --success: #4CD98B; --success-soft: rgba(76, 217, 139, 0.18);
  --danger: #FF5C7A; --danger-soft: rgba(255, 92, 122, 0.18);
  --shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.315); --shadow-md: 0 8px 23px rgba(0, 0, 0, 0.364);
  --shadow-lg: 0 15px 44px rgba(0, 0, 0, 0.446);
  --glow-accent: 0 0 30px rgba(180, 92, 255, 0.42); --glow-gold: 0 0 24px rgba(255, 122, 0, 0.35);
}

/* Monochrome — light, minimal black/white/gray. */
:root[data-theme="mono"] {
  color-scheme: light;
  --bg: #FAFAFA; --bg-soft: #EFEFEF; --surface: #FFFFFF; --surface-2: #F7F7F7;
  --surface-glass: rgba(255, 255, 255, 0.7);
  --ink: #141414; --muted: #6B6B6B;
  --border: rgba(0, 0, 0, 0.08); --border-strong: rgba(0, 0, 0, 0.18);
  --accent: #141414; --accent-2: #555555; --accent-ink: #FFFFFF;
  --accent-text: #141414;
  --accent-soft: rgba(0, 0, 0, 0.06); --violet-soft: rgba(0, 0, 0, 0.05);
  --gradient: linear-gradient(135deg, #333333 0%, #141414 100%);
  --gradient-soft: linear-gradient(135deg, rgba(0, 0, 0, 0.08), rgba(0, 0, 0, 0.04));
  --gold: #B08D57; --gold-2: #8C6D3F; --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));
  --success: #1F8A4C; --success-soft: rgba(31, 138, 76, 0.12);
  --danger: #C63A3A; --danger-soft: rgba(198, 58, 58, 0.12);
  --shadow-sm: 0 2px 9px rgba(0, 0, 0, 0.045); --shadow-md: 0 8px 22px rgba(0, 0, 0, 0.07);
  --shadow-lg: 0 15px 42px rgba(0, 0, 0, 0.115);
  --glow-accent: 0 6px 13px rgba(0, 0, 0, 0.15); --glow-gold: 0 6px 13px rgba(140, 109, 63, 0.204);
}

/* Golden Peach — light, warm peach/gold. */
:root[data-theme="rosegold"] {
  color-scheme: light;
  --bg: #FFF8F3; --bg-soft: #FCEBDD; --surface: #FFFFFF; --surface-2: #FFFAF5;
  --surface-glass: rgba(255, 255, 255, 0.68);
  --ink: #2B1F14; --muted: #856F5D;
  --border: rgba(43, 31, 20, 0.08); --border-strong: rgba(43, 31, 20, 0.16);
  --accent: #F2A65A; --accent-2: #D4AF7A; --accent-ink: #2B1F14;
  --accent-text: #AB5C0D;
  --accent-soft: rgba(242, 166, 90, 0.2); --violet-soft: rgba(212, 175, 122, 0.18);
  --gradient: linear-gradient(135deg, #FFC98C 0%, #F2A65A 50%, #D4AF7A 100%);
  --gradient-soft: linear-gradient(135deg, rgba(255, 201, 140, 0.22), rgba(212, 175, 122, 0.18));
  --gold: #D4AF37; --gold-2: #B8860B; --gradient-gold: linear-gradient(135deg, var(--gold), var(--gold-2));
  --success: #4C9A6A; --success-soft: rgba(76, 154, 106, 0.13);
  --danger: #C1443A; --danger-soft: rgba(193, 68, 58, 0.12);
  --shadow-sm: 0 2px 9px rgba(43, 20, 24, 0.06); --shadow-md: 0 8px 22px rgba(43, 20, 24, 0.084);
  --shadow-lg: 0 15px 42px rgba(43, 20, 24, 0.115);
  --glow-accent: 0 6px 14px rgba(212, 175, 122, 0.272); --glow-gold: 0 6px 13px rgba(184, 134, 11, 0.238);
}

@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;
  }
}

* { box-sizing: border-box; min-width: 0; }
html, body { overflow-x: hidden; }
html { -webkit-tap-highlight-color: transparent; }

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--bg);
  position: relative;
}

/* Soft premium gradient mesh behind the whole app — decorative, fixed,
   never intercepts clicks. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(720px circle at 8% -8%, var(--accent-soft), transparent 60%),
    radial-gradient(640px circle at 100% 8%, var(--violet-soft), transparent 55%),
    radial-gradient(900px circle at 50% 115%, var(--violet-soft), transparent 60%);
  pointer-events: none;
}

h1, h2, h3, h4 { font-family: var(--font-display); margin: 0; letter-spacing: -0.01em; }
button, input, select, textarea { font: inherit; color: inherit; }
button { border: 0; cursor: pointer; background: none; -webkit-tap-highlight-color: transparent; }
a { color: var(--accent-text); }
img { max-width: 100%; display: block; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 6px;
}

/* ==========================================================================
   Layout shell
   ========================================================================== */
.app-shell {
  height: var(--vh);
  width: 100%;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  position: relative;
}

.view-panel { display: none; }
.view-panel.is-active {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  animation: fade-in 260ms var(--ease) both;
  padding: max(var(--page-pad), env(safe-area-inset-top)) var(--page-pad) calc(var(--nav-h) + max(var(--page-pad), env(safe-area-inset-bottom)) + var(--tg-safe-bottom));
}
/* Messages goes truly edge-to-edge (no side padding) on phones so the chat
   surface can fill the screen the way a native messaging app does. On
   larger screens (see the 860px breakpoint further down) it goes back to
   a normal padded page with matches on the side and the thread on the right.
   The bottom still needs to clear the fixed bottom nav, though — otherwise
   the message composer ends up hidden underneath it. */
@media (max-width: 859px) {
  .view-panel[data-view="messages"].is-active {
    padding: 0 0 calc(var(--nav-h) + max(var(--page-pad), env(safe-area-inset-bottom)) + var(--tg-safe-bottom));
  }
}

/* ==========================================================================
   Buttons — tactile, gradient-forward, satisfying to press
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-width: 128px;
  padding: 13px 20px;
  border-radius: 999px;
  font-weight: 700;
  font-size: 0.94rem;
  letter-spacing: 0.01em;
  position: relative;
  overflow: hidden;
  transition: transform 150ms var(--spring), box-shadow 180ms var(--ease), background 180ms ease, opacity 150ms ease, border-color 150ms ease;
}
.btn-icon { width: 18px; height: 18px; flex-shrink: 0; }
.btn:active { transform: scale(0.95); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

.btn-primary {
  background: var(--gradient);
  background-size: 160% 160%;
  color: var(--accent-ink);
  box-shadow: var(--glow-accent);
}
.btn-primary:hover { transform: translateY(-1px); background-position: 100% 0; box-shadow: 0 8px 20px rgba(255, 122, 69, 0.28); }
.btn-primary:active { transform: translateY(0) scale(0.95); }

.btn-secondary {
  background: var(--surface);
  color: var(--ink);
  border: 1.5px solid var(--border-strong);
}
.btn-secondary:hover { border-color: var(--accent-text); color: var(--accent-text); transform: translateY(-1px); }

.btn-ghost {
  background: transparent;
  color: var(--muted);
  border: 1px solid transparent;
}
.btn-ghost:hover { color: var(--accent-text); background: var(--accent-soft); }

.btn-gold {
  background: var(--gradient-gold);
  color: #2b1400;
  box-shadow: var(--glow-gold);
}
.btn-gold:hover { transform: translateY(-1px); box-shadow: 0 8px 18px rgba(247, 107, 28, 0.28); }

.btn-danger {
  background: var(--danger-soft);
  color: var(--danger);
  border: 1.5px solid transparent;
}
.btn-danger:hover { background: var(--danger); color: #fff; transform: translateY(-1px); }

/* Big round tactile discover action buttons */
.btn-icon-round {
  min-width: 0;
  width: 60px;
  height: 60px;
  padding: 0;
  border-radius: 50%;
  flex: 0 0 auto;
}
.btn-icon-round svg { width: 24px; height: 24px; }
.btn-like {
  width: 72px; height: 72px;
  background: var(--gradient);
  color: #fff;
  box-shadow: var(--glow-accent);
}
.btn-like svg { width: 30px; height: 30px; }
.btn-like:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 10px 22px rgba(255, 122, 69, 0.3); }
.btn-like:active { transform: scale(0.92); }
.btn-skip {
  background: var(--surface);
  color: var(--muted);
  border: 1.5px solid var(--border-strong);
}
.btn-skip:hover { color: var(--ink); border-color: var(--border-strong); transform: translateY(-2px); }
.btn-block {
  width: 52px; height: 52px;
  align-self: center;
  background: var(--surface);
  color: var(--danger);
  border: 1.5px solid var(--danger-soft);
}
.btn-block:hover { background: var(--danger-soft); transform: translateY(-2px); }

/* ==========================================================================
   Auth screen — logo, headline, three buttons, floating decor
   ========================================================================== */
.auth-hero {
  position: relative;
  overflow: hidden;
  width: min(100%, 560px);
  margin: 6vh auto 0;
  padding: 48px 32px;
  border-radius: var(--radius-lg);
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
  animation: rise 560ms var(--ease) both;
}

.hero-orb {
  position: absolute;
  top: -160px;
  left: 50%;
  width: 460px;
  height: 460px;
  margin-left: -230px;
  background: var(--gradient);
  opacity: 0.18;
  filter: blur(64px);
  border-radius: 50%;
  animation: drift 14s ease-in-out infinite alternate;
  pointer-events: none;
}
@keyframes drift {
  from { transform: translate(-30px, -10px) scale(1); }
  to   { transform: translate(30px, 20px) scale(1.1); }
}

.floaty {
  position: absolute;
  font-size: 1.4rem;
  color: var(--accent);
  opacity: 0.35;
  pointer-events: none;
  animation: floaty-drift 6s ease-in-out infinite;
}
.floaty-1 { top: 14%; left: 8%; animation-delay: 0s; color: var(--accent); }
.floaty-2 { top: 22%; right: 10%; font-size: 1.1rem; animation-delay: 1.4s; color: var(--accent-2); }
.floaty-3 { bottom: 18%; left: 14%; font-size: 1.1rem; animation-delay: 2.8s; }
@keyframes floaty-drift {
  0%, 100% { transform: translateY(0) rotate(0deg); opacity: 0.3; }
  50% { transform: translateY(-14px) rotate(8deg); opacity: 0.55; }
}

.brand-mark {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 22px;
}
.brand-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  font-weight: 700;
  font-family: var(--font-display);
  background: var(--gradient);
  color: #fff;
  box-shadow: var(--glow-accent);
}
.brand-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.35rem;
  background: var(--gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.auth-hero h1 {
  position: relative;
  margin: 0 0 28px;
  font-weight: 600;
  font-size: clamp(1.8rem, 5vw, 2.5rem);
  line-height: 1.15;
}

.welcome-actions {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 16px;
}
.welcome-actions .btn { width: 100%; }

.welcome-status {
  position: relative;
  min-height: 1.2em;
  margin: 0;
  color: var(--muted);
  font-size: 0.88rem;
}

/* ==========================================================================
   Generic surfaces
   ========================================================================== */
.dashboard-shell {
  width: 100%;
  /* flex-shrink intentionally 0: with min-height:0 + shrink:1, this box could
     be squeezed below its own content's height whenever a view (e.g. the
     Profile page's Account card) is tall enough to need scrolling — content
     doesn't shrink to match, so it just overflowed past the box and under
     the fixed bottom nav, hiding the Log out button behind it. Growing is
     still fine (the messages view overrides with an explicit height:100%
     anyway), it just must never shrink smaller than its content. */
  flex: 1 0 auto;
  margin: 0;
  padding: 0;
  border-radius: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
}
@media (min-width: 860px) {
  .dashboard-shell {
    width: min(100%, 1160px);
    margin: 0 auto;
    padding: 22px;
    border-radius: var(--radius-lg);
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-md);
  }
}
.view-panel[data-view="messages"] .dashboard-shell { height: 100%; display: flex; }
@media (min-width: 860px) {
  .view-panel[data-view="messages"] .dashboard-shell { padding-bottom: 14px; }
}

.panel {
  padding: 18px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
  transition: transform 200ms var(--ease), box-shadow 200ms var(--ease), border-color 200ms ease;
}
.panel:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); border-color: var(--border-strong); }
.panel h3 { margin: 0 0 8px; font-size: 1.02rem; font-weight: 700; font-family: var(--font-body); }
.panel p { margin: 0; color: var(--muted); line-height: 1.6; font-size: 0.93rem; }
.panel-large { grid-column: span 2; }

.dashboard-header, .profile-hero {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  margin-bottom: 12px;
  flex-wrap: wrap;
  flex-shrink: 0;
}

.eyebrow {
  margin: 0 0 2px;
  background: var(--gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 800;
}

.dashboard-header h2, .profile-hero h2, .game-card h2 {
  margin: 0;
  font-weight: 600;
  font-size: clamp(1.15rem, 2vw, 1.5rem);
}

.header-pill, .summary-pill, .notice {
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 9px 14px;
  color: var(--muted);
  font-size: 0.88rem;
}
.notice { border-radius: var(--radius-sm); display: block; }
.notice:empty { display: none; }

.sparks-badge {
  font-weight: 700;
  color: #caa233;
  border-color: rgba(202, 162, 51, 0.4);
  background: rgba(202, 162, 51, 0.1);
  flex-shrink: 0;
}

.sparks-preset-row { display: flex; gap: 8px; margin-top: 6px; flex-wrap: wrap; }
.sparks-preset-btn {
  flex: 1;
  min-width: 74px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 8px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1.5px solid var(--border);
  font-weight: 800;
  font-size: 0.95rem;
  color: var(--ink);
  transition: border-color 150ms ease, transform 150ms var(--spring), background 150ms ease;
}
.sparks-preset-btn small { font-weight: 600; font-size: 0.68rem; color: var(--muted); }
.sparks-preset-btn:hover { border-color: var(--accent); }
.sparks-preset-btn:active { transform: scale(0.95); }
.sparks-preset-btn:disabled { opacity: 0.4; pointer-events: none; }

/* -- chat: gift-sparks icon button + the spark_gift message card -- */
.chat-gift-btn { font-size: 1.05rem; }
.spark-gift-card {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border-radius: 999px;
  background: var(--gradient-gold);
  color: #2b1400;
  font-weight: 800;
  box-shadow: var(--glow-gold);
}
.spark-gift-card.theirs { align-self: flex-start; }
.spark-gift-card.mine { align-self: flex-end; }

.empty-state {
  padding: 26px 16px;
  border-radius: var(--radius-md);
  color: var(--muted);
  background: var(--surface);
  border: 1px dashed var(--border-strong);
  text-align: center;
  animation: fade-in 260ms ease both;
}

/* ==========================================================================
   Discover — the whole page is exactly one screen: header is fixed height,
   the card stage takes every remaining pixel, and the card itself has no
   fixed aspect ratio, so on any device (short phone or huge monitor) it
   simply fills whatever space is left. Nothing here ever scrolls.
   ========================================================================== */
.view-panel[data-view="discover"].is-active { overflow: hidden; }
.view-panel[data-view="discover"] .dashboard-shell {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.discover-stage {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  display: flex;
}
@media (min-width: 600px) {
  .discover-stage { max-width: 560px; }
}
@media (min-width: 860px) {
  .discover-stage { max-width: 640px; }
}

/* Floating chip with today's view/like counter — sits over the top of the
   card instead of taking its own row, so the header stays short. */
.summary-pill {
  position: absolute;
  top: 10px;
  left: 10px;
  right: 10px;
  z-index: 3;
  margin: 0;
  padding: 7px 13px;
  background: rgba(21, 9, 16, 0.55);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: rgba(255, 255, 255, 0.92);
  font-size: 0.76rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
}
.summary-pill:empty { display: none; }

.discover-deck {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  display: flex;
  justify-content: center;
}
/* The summary pill floats above the deck (see .summary-pill) — that only
   works when a photo card is underneath, since its top has no text. When
   the deck is instead showing an empty-state message, the message needs
   its own space below the pill (not stretched/overlapped by it), and it
   should match the pill's width so the two read as one aligned column. */
.discover-deck .empty-state {
  align-self: flex-start;
  width: calc(100% - 20px);
  margin-top: 54px;
}

.profile-card {
  position: relative;
  width: 100%;
  height: 100%;
  margin: 0 auto;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  animation: card-in 360ms var(--spring) both;
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  background-size: cover;
  background-position: center;
}
@keyframes card-in {
  from { opacity: 0; transform: scale(0.94) translateY(20px) rotate(-1.5deg); }
  to   { opacity: 1; transform: scale(1) translateY(0) rotate(0); }
}

.profile-card-photo { background-color: #12060f; }

.profile-card-placeholder {
  background-image: var(--gradient);
  justify-content: center;
}
.profile-card-placeholder .profile-card-overlay {
  position: relative;
  background: linear-gradient(180deg, transparent, rgba(12, 4, 10, 0.55));
}
.profile-card-initial {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 7rem;
  color: rgba(255, 255, 255, 0.35);
}

.profile-card-overlay {
  position: relative;
  z-index: 1;
  width: 100%;
  padding: 20px 18px 92px;
  color: #fff;
  background: linear-gradient(180deg, transparent 0%, rgba(10, 3, 8, 0.35) 45%, rgba(10, 3, 8, 0.86) 100%);
}
.profile-card-overlay h4 {
  margin: 0 0 3px;
  font-size: 1.35rem;
  font-weight: 700;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
}
.profile-card-location {
  margin: 0 0 8px;
  color: rgba(255, 255, 255, 0.82);
  font-size: 0.88rem;
}
.profile-card-bio {
  margin: 0 0 10px;
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.88rem;
  line-height: 1.5;
  word-break: break-word;
  overflow-wrap: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.profile-card-gender-chip {
  display: inline-block;
  padding: 4px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  backdrop-filter: blur(6px);
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: capitalize;
}
.profile-card-overlay .challenge-badge { margin-bottom: 10px; display: inline-flex; }

/* Cupid compatibility insight — sits above the name, same glass-chip
   language as .profile-card-gender-chip. Empty/hidden until loaded. */
.cupid-slot { margin-bottom: 10px; min-height: 0; }
.cupid-score {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px 5px 10px;
  border-radius: 999px;
  background: var(--gradient);
  color: var(--accent-ink);
  font-size: 0.82rem;
  font-weight: 700;
  box-shadow: var(--glow-accent);
}
.cupid-score-icon { font-size: 0.9em; }
.vibe-score { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px 5px 10px; border-radius: 999px; background: var(--gradient); color: var(--accent-ink); font-size: 0.82rem; font-weight: 700; box-shadow: var(--glow-accent); }
.vibe-score-icon { font-size: 0.9em; }
.cupid-summary {
  margin: 8px 0 0;
  font-size: 0.82rem;
  font-style: italic;
  color: rgba(255, 255, 255, 0.88);
  line-height: 1.4;
}
.cupid-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}
.cupid-tag {
  padding: 3px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  backdrop-filter: blur(6px);
  font-size: 0.72rem;
  font-weight: 600;
}
.cupid-loading {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.7);
}

/* Floating action buttons — anchored over the card's bottom edge rather
   than living below it as a separate row. */
.action-row {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 18px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  pointer-events: none; /* the wrapper is click-through; buttons re-enable themselves */
}
.action-row .btn { pointer-events: auto; }
.btn-icon-round {
  background: rgba(21, 9, 16, 0.55);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: #fff;
}
.btn-skip { background: rgba(21, 9, 16, 0.55); color: #fff; border-color: rgba(255, 255, 255, 0.22); }
.btn-block { background: rgba(21, 9, 16, 0.55); color: #ff8080; border-color: rgba(255, 128, 128, 0.35); }

/* ==========================================================================
   Chat — locked-height layout so the page never reflows/jumps as messages
   or threads load; only the inner lists scroll.
   ========================================================================== */
.chat-layout {
  display: flex;
  flex-direction: column;
  gap: 0;
  overflow: hidden;
  height: 100%;
  width: 100%;
}
.chat-sidebar, .chat-panel {
  padding: 14px;
  border-radius: 0;
  background: var(--surface);
  border: 0;
  box-shadow: none;
  min-width: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
@media (min-width: 860px) {
  .chat-layout {
    flex-direction: row;
    grid-template-columns: minmax(240px, 300px) minmax(0, 1fr);
    display: grid;
    gap: 14px;
    height: clamp(460px, calc(100dvh - 200px), 780px);
  }
  .chat-sidebar, .chat-panel {
    padding: 16px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
  }
}
.chat-sidebar h3 { font-size: 0.98rem; font-weight: 700; }
.chat-sidebar-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; flex-shrink: 0; }
.chat-sidebar-head .sparks-badge { padding: 6px 10px; font-size: 0.8rem; }

.thread-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
  flex: 1;
  overflow-y: auto;
  scrollbar-gutter: stable;
  padding-right: 2px;
}

.thread-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 10px;
  text-align: left;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--border);
  transition: border-color 160ms ease, transform 160ms ease, box-shadow 160ms ease;
  flex-shrink: 0;
}
.thread-item:hover { transform: translateX(3px); box-shadow: var(--shadow-sm); border-color: var(--border-strong); }
.thread-copy { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.thread-copy span { color: var(--muted); font-size: 0.86rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.thread-item strong { display: inline-flex; align-items: center; gap: 6px; }
.thread-item.active { border-color: var(--accent-text); box-shadow: 0 0 0 3px var(--accent-soft); background: var(--accent-soft); }

.thread-avatar-wrap { position: relative; display: inline-flex; flex-shrink: 0; }
.thread-avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  flex-shrink: 0;
  object-fit: cover;
  box-shadow: 0 0 0 2px var(--surface-2), 0 0 0 3px var(--border);
}
.thread-avatar-fallback {
  display: grid;
  place-items: center;
  background: var(--gradient);
  color: #fff;
  font-weight: 700;
  font-family: var(--font-display);
  font-size: 1.05rem;
}

.thread-badge.dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--gradient);
  flex-shrink: 0;
}
.thread-badge.pill {
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--gradient);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 800;
  line-height: 1.4;
}

/* ==========================================================================
   Matches page — 3 sub-tabs (Matches / Liked You / Liked), each a scrollable
   list of person cards. Reuses .filter-pills/.filter-pill for the sub-tab
   strip so it matches the segmented-control look already used by the
   discover filters, and the round like/pass buttons deliberately echo
   .btn-like/.btn-skip from the Discover deck (same gesture, smaller scale).
   ========================================================================== */
.matches-subtabs { margin-bottom: 16px; }

.matches-subpanel { animation: fade-in 220ms var(--ease) both; }

.match-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.match-card {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
  transition: transform 180ms var(--spring), box-shadow 180ms var(--ease), border-color 180ms ease;
  animation: fade-in 220ms var(--ease) both;
}
.match-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); border-color: var(--border-strong); }
.match-card:nth-child(2) { animation-delay: 30ms; }
.match-card:nth-child(3) { animation-delay: 60ms; }
.match-card:nth-child(4) { animation-delay: 90ms; }

.match-card-avatar {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  flex-shrink: 0;
  object-fit: cover;
  box-shadow: 0 0 0 2px var(--surface-2), 0 0 0 3px var(--border);
}
.match-card-avatar-fallback {
  display: grid;
  place-items: center;
  background: var(--gradient);
  color: #fff;
  font-weight: 700;
  font-family: var(--font-display);
  font-size: 1.15rem;
}

.match-card-copy {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1;
}
.match-card-copy strong {
  font-size: 0.98rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.match-card-copy span {
  color: var(--muted);
  font-size: 0.86rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.match-card-status {
  display: inline-block;
  margin-top: 3px;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.7rem;
  font-weight: 700;
  width: fit-content;
}
.match-card-status.declined { background: var(--danger-soft); color: var(--danger); border-color: transparent; }

/* "Start Chat" in the Matches tab — a normal labeled pill button. */
.match-card-cta {
  min-width: 0;
  padding: 10px 18px;
  font-size: 0.85rem;
  white-space: nowrap;
  flex-shrink: 0;
}

/* "Like back" / "Pass" in the Liked You tab — compact round icon buttons,
   same gesture as the Discover deck's like/skip, scaled down for a list row. */
.match-card-actions { display: flex; gap: 8px; flex-shrink: 0; }
.match-icon-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 150ms var(--spring), box-shadow 160ms ease, border-color 150ms ease, color 150ms ease;
}
.match-icon-btn svg { width: 17px; height: 17px; }
.match-icon-btn:active { transform: scale(0.9); }
.match-icon-btn-like { background: var(--gradient); color: #fff; box-shadow: var(--glow-accent); }
.match-icon-btn-like:hover { transform: translateY(-1px) scale(1.05); }
.match-icon-btn-pass { background: var(--surface); color: var(--muted); border: 1.5px solid var(--border-strong); }
.match-icon-btn-pass:hover { color: var(--ink); border-color: var(--accent-text); transform: translateY(-1px); }

.chat-panel-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-bottom: 14px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.chat-back-btn { display: none; width: 36px; height: 36px; }
.chat-panel-avatar {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--gradient);
  color: #fff;
  font-weight: 700;
  font-family: var(--font-display);
  font-size: 1rem;
  flex-shrink: 0;
  overflow: hidden;
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.chat-panel-avatar:empty { display: none; box-shadow: none; }
.chat-panel-avatar img { width: 100%; height: 100%; object-fit: cover; }
.chat-panel-avatar-wrap { position: relative; display: inline-flex; flex-shrink: 0; }
.chat-panel-name-wrap { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.chat-panel-name { font-weight: 700; font-size: 1.05rem; }
.chat-panel-status {
  font-size: 0.76rem;
  font-weight: 700;
  color: var(--success);
}
.chat-panel-status:empty { display: none; }

/* ==========================================================================
   Presence dot — a small green marker over an avatar showing someone is
   online right now. Reused on thread-list avatars and the open chat
   header's avatar (see chat.js: isOnlineFromPresence()/refreshPresence()).
   ========================================================================== */
.presence-dot {
  position: absolute;
  right: -1px;
  bottom: -1px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--success);
  box-shadow: 0 0 0 2px var(--surface-2);
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 160ms ease, transform 160ms var(--spring);
}
.presence-dot.show { opacity: 1; transform: scale(1); }

.message-feed {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-gutter: stable;
  padding: 14px;
  margin: 0 -4px;
  border-radius: var(--radius-sm);
  background: var(--bg-soft);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.message-bubble {
  width: fit-content;
  max-width: 74%;
  padding: 10px 16px;
  border-radius: 20px;
  line-height: 1.45;
  font-size: 0.95rem;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  word-break: break-word;
  overflow-wrap: break-word;
  white-space: pre-wrap;
  animation: bubble-in 220ms var(--spring) both;
}
@keyframes bubble-in {
  from { opacity: 0; transform: translateY(8px) scale(0.94); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.message-bubble.mine {
  margin-left: auto;
  background: var(--gradient);
  color: #fff;
  border-color: transparent;
  border-bottom-right-radius: 6px;
  box-shadow: 0 6px 18px rgba(255, 122, 69, 0.28);
}
.message-bubble.theirs { margin-right: auto; border-bottom-left-radius: 6px; }

.message-form { display: flex; gap: 8px; margin-top: 12px; flex-shrink: 0; }
.message-form input {
  flex: 1;
  min-width: 0;
  padding: 13px 18px;
  border-radius: 999px;
  border: 1.5px solid var(--border-strong);
  background: var(--surface);
  transition: border-color 160ms ease, box-shadow 160ms ease;
}
.message-form input:focus { outline: none; border-color: var(--accent-text); box-shadow: 0 0 0 4px var(--accent-soft); }
.btn-send { min-width: 0; padding: 13px 20px; flex-shrink: 0; }
.message-meter { margin: 6px 4px 0; color: var(--muted); font-size: 0.8rem; flex-shrink: 0; }

/* ==========================================================================
   Forms
   ========================================================================== */
.auth-form, .profile-form { display: grid; gap: 12px; text-align: left; }
.auth-field { display: grid; gap: 6px; font-size: 0.92rem; }
.auth-field[hidden] { display: none; }
.auth-field span { color: var(--muted); font-weight: 700; font-size: 0.82rem; }

.auth-field input, .auth-field select, .auth-field textarea {
  width: 100%;
  padding: 11px 14px;
  border-radius: 12px;
  border: 1.5px solid var(--border-strong);
  background: var(--surface);
  transition: border-color 160ms ease, box-shadow 160ms ease;
}
.auth-field input:focus, .auth-field select:focus, .auth-field textarea:focus {
  outline: none;
  border-color: var(--accent-text);
  box-shadow: 0 0 0 4px var(--accent-soft);
}

.avatar-picker { display: flex; align-items: center; gap: 14px; }
.avatar-preview {
  width: 64px; height: 64px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-2);
  border: 1px solid var(--border);
  box-shadow: 0 0 0 3px var(--surface), 0 0 0 5px var(--accent-soft);
}
.avatar-preview:not([src]), .avatar-preview[src=""] { visibility: hidden; box-shadow: none; }

.toggle-row {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--ink);
  font-size: 0.92rem;
  cursor: pointer;
  width: fit-content;
}
.toggle-row span { order: 1; color: var(--ink); font-weight: 500; }
.toggle-row input[type="checkbox"] {
  order: 2;
  appearance: none;
  position: relative;
  width: 44px;
  height: 25px;
  border-radius: 999px;
  background: var(--border-strong);
  cursor: pointer;
  flex-shrink: 0;
  transition: background 180ms ease;
}
.toggle-row input[type="checkbox"]::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 21px; height: 21px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  transition: transform 180ms var(--spring);
}
.toggle-row input[type="checkbox"]:checked { background: var(--gradient); }
.toggle-row input[type="checkbox"]:checked::after { transform: translateX(19px); }

.field-status {
  font-style: normal;
  color: var(--success);
  font-weight: 700;
  font-size: 0.78rem;
  opacity: 0;
  transition: opacity 200ms ease;
}
.field-status.show { opacity: 1; }
.field-hint { margin: 2px 0 0; color: var(--muted); font-size: 0.8rem; }

.auth-error { margin: 0; min-height: 1.1em; color: var(--danger); font-size: 0.88rem; }
.auth-error.flash { animation: auth-error-flash 900ms ease; }
@keyframes auth-error-flash {
  0%, 100% { background: transparent; }
  20% { background: rgba(255, 82, 82, 0.18); border-radius: 8px; }
}
.auth-form-actions { display: flex; flex-wrap: wrap; gap: 10px; }

.auth-switch { margin: -4px 0 0; font-size: 0.86rem; color: var(--muted); }
.link-button {
  color: var(--accent-text);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 2px;
  padding: 0;
}
.link-button:disabled { color: var(--muted); text-decoration: none; cursor: default; }

/* ---------------------------------------------------- hybrid auth (OTP) --- */
.auth-step { display: grid; gap: 14px; }
.auth-step[hidden] { display: none; }

/* Choice screen: pick Google or email before seeing any form fields */
.auth-choice { display: grid; gap: 12px; }
.auth-choice[hidden] { display: none; }

.btn-google {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; padding: 13px 16px; border-radius: var(--radius-md);
  border: 1.5px solid var(--border-strong); background: var(--surface);
  color: var(--ink); font-weight: 700; font-size: 0.95rem; cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.btn-google:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08); border-color: var(--border-strong); }
.btn-google:active { transform: translateY(0) scale(0.97); }

.btn-email {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; padding: 13px 16px; border-radius: var(--radius-md);
  border: none; background: var(--gradient); background-size: 160% 160%;
  color: var(--accent-ink); font-weight: 700; font-size: 0.95rem; cursor: pointer;
  box-shadow: var(--glow-accent);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background-position 0.2s ease;
}
.btn-email:hover { transform: translateY(-1px); background-position: 100% 0; box-shadow: 0 8px 20px rgba(255, 122, 69, 0.28); }
.btn-email:active { transform: translateY(0) scale(0.97); }
.btn-email .btn-icon { width: 18px; height: 18px; flex-shrink: 0; }

/* Email/password step, revealed after choosing "Continue with Email" */
.auth-email-section { display: grid; gap: 14px; animation: fade-in 200ms ease both; }
.auth-email-section[hidden] { display: none; }
.auth-back-button {
  display: inline-flex; align-items: center; gap: 6px; width: fit-content;
  padding: 4px 2px; border: none; background: transparent; color: var(--muted);
  font-weight: 700; font-size: 0.86rem; cursor: pointer; transition: color 0.15s ease;
}
.auth-back-button svg { width: 16px; height: 16px; }
.auth-back-button:hover { color: var(--accent-text); }

.auth-divider { display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: 0.82rem; }
.auth-divider::before, .auth-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }

.auth-otp-subtitle { margin: 0; font-size: 0.92rem; color: var(--muted); }
.auth-otp-subtitle strong { color: var(--ink); }

.otp-inputs { display: flex; gap: 8px; justify-content: center; }
.otp-digit {
  width: 44px; height: 52px; text-align: center; font-size: 1.4rem; font-weight: 700;
  border-radius: var(--radius-sm); border: 1.5px solid var(--border-strong);
  background: var(--surface-2); color: var(--ink);
}
.otp-digit:focus { outline: none; border-color: var(--accent-text); box-shadow: 0 0 0 3px var(--accent-soft); }

.auth-resend-line { margin: -6px 0 0; font-size: 0.86rem; color: var(--muted); text-align: center; }

.typing-indicator {
  height: 1.2em;
  margin: 6px 4px 0;
  color: var(--accent-text);
  font-size: 0.82rem;
  font-style: italic;
  font-weight: 600;
  opacity: 0;
  transition: opacity 160ms ease;
}
.typing-indicator.show { opacity: 1; }

/* ==========================================================================
   Profile page
   ========================================================================== */
.profile-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.account-line { margin: 0 0 14px; color: var(--muted); font-size: 0.9rem; }
.profile-summary, .plan-card {
  padding: 14px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border: 1px solid var(--border);
  margin-bottom: 12px;
}
.plan-card p { margin: 0 0 6px; font-size: 0.92rem; color: var(--muted); }
.plan-card p:last-child { margin-bottom: 0; }
.plan-card strong { color: var(--ink); }

@keyframes fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
@keyframes rise    { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }

/* ==========================================================================
   Game
   ========================================================================== */
.game-shell { display: grid; place-items: center; min-height: 380px; }
.game-card {
  max-width: 560px;
  text-align: center;
  padding: 36px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.game-card p:last-child { color: var(--muted); margin-top: 8px; }

/* ==========================================================================
   Modals
   ========================================================================== */
.modal-root {
  position: fixed;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(30, 8, 24, 0.5);
  backdrop-filter: blur(8px);
  z-index: 1000;
}
.modal-root.open { display: flex; animation: overlay-in 200ms ease both; }
@keyframes overlay-in { from { opacity: 0; } to { opacity: 1; } }

.modal-card {
  position: relative;
  width: min(100%, 480px);
  max-height: min(88vh, 720px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 26px;
  border-radius: var(--radius-lg);
  background: var(--surface-glass);
  backdrop-filter: var(--blur-glass);
  -webkit-backdrop-filter: var(--blur-glass);
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-lg);
  animation: modal-in 280ms var(--spring) both;
}
.modal-close-x {
  position: absolute;
  top: 16px; right: 16px;
  display: flex; align-items: center; justify-content: center;
  width: 32px; height: 32px;
  border-radius: 50%;
  border: none; background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}
.modal-close-x svg { width: 16px; height: 16px; }
.modal-close-x:hover { color: var(--ink); background: var(--accent-soft); transform: rotate(90deg); }
#authLockModal .modal-close-x, #telegramPromptModal .modal-close-x { display: none; }
@keyframes modal-in {
  from { opacity: 0; transform: translateY(18px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.modal-card h2 { margin: 0 0 6px; padding-right: 34px; font-size: 1.25rem; font-weight: 700; }
.modal-card p { margin: 0 0 18px; color: var(--muted); line-height: 1.6; font-size: 0.92rem; }
#authLockModal .modal-card { text-align: center; }
#authLockModal .auth-form-actions { justify-content: center; }

/* -- Telegram connect prompt -- */
.telegram-prompt-card { text-align: center; }
.telegram-prompt-icon {
  width: 64px; height: 64px;
  margin: 0 auto 16px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: linear-gradient(135deg, #4FB6EE 0%, #229ED9 55%, #1B7FB8 100%);
  color: #fff;
  box-shadow: 0 10px 24px rgba(34, 158, 217, 0.35);
  animation: telegram-icon-pop 420ms var(--spring) both;
}
.telegram-prompt-icon svg { width: 30px; height: 30px; }
@keyframes telegram-icon-pop {
  from { opacity: 0; transform: scale(0.6) rotate(-8deg); }
  to   { opacity: 1; transform: scale(1) rotate(0deg); }
}
.telegram-prompt-card h2 { font-family: var(--font-display); }
.telegram-prompt-card p { max-width: 34ch; margin-left: auto; margin-right: auto; }

.telegram-prompt-features {
  list-style: none;
  margin: 0 0 22px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  text-align: left;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.telegram-prompt-features li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--ink);
}
.telegram-prompt-check {
  flex-shrink: 0;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--success-soft);
  color: var(--success);
}
.telegram-prompt-check svg { width: 13px; height: 13px; }

.telegram-prompt-actions { flex-direction: column; justify-content: stretch; }
.telegram-prompt-actions .btn { width: 100%; }
.telegram-prompt-connect-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: linear-gradient(135deg, #4FB6EE 0%, #229ED9 100%);
  box-shadow: 0 8px 20px rgba(34, 158, 217, 0.32);
}
.telegram-prompt-connect-btn:hover { background: linear-gradient(135deg, #5cc0f5 0%, #2aa8e4 100%); box-shadow: 0 10px 24px rgba(34, 158, 217, 0.4); }
.telegram-prompt-connect-btn svg { width: 17px; height: 17px; }
.telegram-prompt-never { margin: 14px 0 0; text-align: center; }

/* ==========================================================================
   Welcome intro — a short one-time carousel shown after sign-in, once per
   account (see maybeShowIntro()/finishIntro() in app.js). Deliberately
   sequenced after the Telegram prompt rather than shown alongside it: the
   prompt closes (connect / not now / don't show again) and *that* is what
   triggers this to open, so the two never overlap on screen.

   Full-page and deliberately fixed-dark, like the splash screen — it's a
   one-time "arrival" moment, not a settings dialog, so it commits to the
   same moody mesh-gradient treatment regardless of which light/dark theme
   the person has picked, rather than pulling from the theme-relative
   --surface/--ink tokens the rest of the UI uses.
   ========================================================================== */
.intro-overlay {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: #12060f;
  padding: max(22px, env(safe-area-inset-top)) 22px max(22px, env(safe-area-inset-bottom));
}
.intro-overlay.open { display: flex; animation: overlay-in 260ms ease both; }
.intro-overlay::before {
  content: "";
  position: absolute;
  inset: -20%;
  background:
    radial-gradient(38% 32% at 20% 22%, rgba(255, 122, 69, 0.34), transparent 60%),
    radial-gradient(42% 36% at 82% 78%, rgba(20, 184, 166, 0.32), transparent 60%),
    radial-gradient(30% 26% at 85% 15%, rgba(255, 176, 32, 0.24), transparent 60%);
  filter: blur(10px);
  animation: splash-mesh-drift 9s ease-in-out infinite alternate;
}

.intro-floaty {
  position: absolute;
  color: rgba(255, 213, 230, 0.5);
  font-size: 1.3rem;
  pointer-events: none;
  animation: splash-float 6s ease-in-out infinite;
}
.intro-floaty-1 { top: 13%; left: 9%; font-size: 1.8rem; animation-delay: 0s; }
.intro-floaty-2 { top: 20%; right: 11%; font-size: 1.2rem; color: rgba(196, 165, 255, 0.55); animation-delay: 1.1s; }
.intro-floaty-3 { bottom: 28%; left: 12%; font-size: 1.1rem; animation-delay: 2.2s; }
.intro-floaty-4 { top: 68%; right: 14%; font-size: 1.6rem; color: rgba(196, 165, 255, 0.4); animation-delay: 3.1s; }
.intro-floaty-5 { bottom: 18%; right: 24%; font-size: 1rem; animation-delay: 4s; }

.intro-skip {
  position: absolute;
  top: max(18px, env(safe-area-inset-top));
  right: max(18px, env(safe-area-inset-right));
  z-index: 2;
  padding: 7px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.16);
  color: rgba(255, 255, 255, 0.7);
  font-size: 0.78rem;
  font-weight: 700;
  transition: color 150ms ease, background 150ms ease, border-color 150ms ease;
}
.intro-skip:hover { color: #fff; background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.28); }

.intro-shell {
  position: relative;
  z-index: 1;
  width: min(100%, 440px);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.intro-viewport { width: 100%; overflow: hidden; }
.intro-track { display: flex; transition: transform 420ms var(--spring); }
.intro-slide {
  flex: 0 0 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 0 6px;
}

.intro-badge {
  width: 100px;
  height: 100px;
  margin: 0 auto 28px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: #fff;
  animation: intro-badge-pop 480ms var(--spring) both;
}
.intro-badge svg { width: 40px; height: 40px; }
.intro-badge-mark { font-family: "Fraunces", Georgia, serif; font-weight: 700; font-size: 2.5rem; }
.intro-badge-a { background: linear-gradient(135deg, #FF7A45 0%, #FFB020 55%, #14B8A6 100%); box-shadow: 0 16px 36px rgba(255, 122, 69, 0.4); }
.intro-badge-b { background: linear-gradient(135deg, #F5A524 0%, #F76B1C 100%); box-shadow: 0 16px 36px rgba(247, 107, 28, 0.35); }
@keyframes intro-badge-pop {
  from { opacity: 0; transform: scale(0.6) rotate(-8deg); }
  to   { opacity: 1; transform: scale(1) rotate(0deg); }
}

.intro-slide h2 {
  margin: 0 0 14px;
  font-family: "Fraunces", Georgia, serif;
  font-weight: 700;
  font-size: 1.7rem;
  color: #fff;
}
.intro-slide p {
  margin: 0;
  max-width: 33ch;
  color: rgba(255, 233, 243, 0.66);
  line-height: 1.65;
  font-size: 0.98rem;
}

.intro-dots {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin: 38px 0 30px;
}
.intro-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.22);
  transition: width 220ms var(--spring), background 220ms ease;
}
.intro-dot.active { width: 24px; background: linear-gradient(90deg, #FF7A45, #14B8A6); }

.intro-nav { display: flex; align-items: center; width: 100%; }
.intro-nav-btn {
  border-radius: 999px;
  font-size: 0.95rem;
  font-weight: 700;
  transition: transform 150ms var(--spring), box-shadow 160ms ease, background 150ms ease, color 150ms ease;
}
.intro-back-btn {
  flex: 0 0 auto;
  max-width: 0;
  margin-right: 0;
  padding: 15px 0;
  overflow: hidden;
  white-space: nowrap;
  opacity: 0;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid transparent;
  color: rgba(255, 255, 255, 0.75);
  pointer-events: none;
  transition: max-width 360ms var(--spring), margin-right 360ms var(--spring), padding 360ms var(--spring),
              opacity 200ms ease, border-color 220ms ease;
}
.intro-back-btn.show {
  max-width: 110px;
  margin-right: 12px;
  padding: 15px 20px;
  opacity: 1;
  border-color: rgba(255, 255, 255, 0.16);
  pointer-events: auto;
}
.intro-back-btn:hover { background: rgba(255, 255, 255, 0.14); color: #fff; }
.intro-next-btn {
  flex: 1;
  color: #fff;
  background: linear-gradient(135deg, #FF7A45 0%, #FFB020 55%, #14B8A6 100%);
  box-shadow: 0 14px 32px rgba(255, 122, 69, 0.35);
  padding: 15px 22px;
}
.intro-next-btn:hover { transform: translateY(-1px); box-shadow: 0 18px 38px rgba(255, 122, 69, 0.45); }
.intro-next-btn:active { transform: scale(0.97); }

@media (max-width: 380px) {
  .intro-badge { width: 84px; height: 84px; margin-bottom: 22px; }
  .intro-badge svg { width: 34px; height: 34px; }
  .intro-badge-mark { font-size: 2.1rem; }
  .intro-slide h2 { font-size: 1.45rem; }
}

/* ==========================================================================
   Toast
   ========================================================================== */
.mera-toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--nav-h) + 14px);
  transform: translate(-50%, 14px);
  padding: 12px 20px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--bg);
  font-size: 0.88rem;
  font-weight: 600;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms var(--ease), transform 220ms var(--ease);
  z-index: 1200;
  max-width: min(90vw, 420px);
  text-align: center;
}
.mera-toast.show { opacity: 1; transform: translate(-50%, 0); }

/* ==========================================================================
   Bottom nav is hidden on the welcome/auth screen
   ========================================================================== */
.app-shell:has(.view-panel[data-view="gamePlay"].is-active) .bottom-nav,
.app-shell:has(.view-panel[data-view="auth"].is-active) .bottom-nav {
  display: none;
}
.view-panel[data-view="auth"].is-active { padding-bottom: max(var(--page-pad), env(safe-area-inset-bottom)); }
/* The bottom nav is hidden on the gameplay page too (see the rule just
   above), so it shouldn't reserve --nav-h worth of empty space either —
   that space was previously wasted, pushing game content down and
   forcing a scroll that had no reason to exist. */
.view-panel[data-view="gamePlay"].is-active { padding-bottom: max(var(--page-pad), env(safe-area-inset-bottom)); }

.icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border);
  transition: transform 160ms var(--spring), border-color 160ms ease, box-shadow 160ms ease;
}
.icon-btn:hover { transform: translateY(-1px); border-color: var(--accent-text); box-shadow: var(--shadow-sm); }
.icon-btn:active { transform: scale(0.92); }
.icon-btn svg { width: 20px; height: 20px; }
.icon-btn-danger { color: var(--danger); }
.icon-btn-danger:hover { border-color: var(--danger); }

.notif-dot {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--gradient);
  box-shadow: 0 0 0 2px var(--surface);
  opacity: 0;
  transform: scale(0.5);
  transition: opacity 160ms ease, transform 160ms var(--spring);
}
.notif-dot.show {
  opacity: 1;
  transform: scale(1);
  animation: dot-pulse 1.6s ease-in-out infinite;
}
@keyframes dot-pulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--surface), 0 0 0 2px var(--accent-soft); }
  50% { box-shadow: 0 0 0 2px var(--surface), 0 0 0 7px transparent; }
}

.notif-panel-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(30, 8, 24, 0.42);
  z-index: 800;
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease;
}
.notif-panel-backdrop.open { opacity: 1; pointer-events: auto; }

.notif-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(380px, 92vw);
  background: var(--surface-glass);
  backdrop-filter: var(--blur-glass);
  -webkit-backdrop-filter: var(--blur-glass);
  border-left: 1px solid var(--border-strong);
  box-shadow: var(--shadow-lg);
  z-index: 900;
  padding: 20px;
  overflow-y: auto;
  transform: translateX(100%);
  transition: transform 300ms var(--ease);
}
.notif-panel.open { transform: translateX(0); }
.notif-panel-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.notif-panel-head h3 { font-size: 1.1rem; font-weight: 700; }

/* ==========================================================================
   Navigation — mobile: fixed bottom bar · desktop: fixed left sidebar
   ========================================================================== */
.bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  height: calc(var(--nav-h) + env(safe-area-inset-bottom) + var(--tg-safe-bottom));
  padding-bottom: calc(env(safe-area-inset-bottom) + var(--tg-safe-bottom));
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding-left: 4px;
  padding-right: 4px;
  border-radius: 0;
  background: var(--surface-glass);
  backdrop-filter: var(--blur-glass);
  -webkit-backdrop-filter: var(--blur-glass);
  border: 0;
  border-top: 1px solid var(--border);
  box-shadow: none;
  z-index: 500;
}
.nav-brand { display: none; }
.nav-indicator {
  position: absolute;
  left: 4px;
  top: 6px;
  width: calc((100% - 8px) / 5);
  height: calc(var(--nav-h) - 12px);
  border-radius: var(--radius-sm);
  background: var(--gradient-soft);
  transform: translateX(0);
  transition: transform 300ms var(--spring);
  pointer-events: none;
  z-index: 0;
}
.bottom-nav:has(.nav-chip:nth-of-type(2).active) .nav-indicator { transform: translateX(100%); }
.bottom-nav:has(.nav-chip:nth-of-type(3).active) .nav-indicator { transform: translateX(200%); }
.bottom-nav:has(.nav-chip:nth-of-type(4).active) .nav-indicator { transform: translateX(300%); }
.bottom-nav:has(.nav-chip:nth-of-type(5).active) .nav-indicator { transform: translateX(400%); }

.nav-chip {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  flex: 1;
  height: 100%;
  border-radius: 16px;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 700;
  transition: color 180ms ease;
}
.nav-icon { width: 22px; height: 22px; transition: transform 180ms var(--spring); position: relative; }
.nav-chip.active { color: var(--accent-text); }
.nav-chip.active .nav-icon { transform: translateY(-1px) scale(1.1); }
.nav-chip:active .nav-icon { transform: scale(0.88); }

.nav-badge {
  position: absolute;
  top: 2px;
  left: 50%;
  margin-left: 4px;
  min-width: 16px;
  padding: 1px 4px;
  border-radius: 999px;
  background: var(--gradient);
  color: #fff;
  font-size: 0.62rem;
  font-weight: 800;
  line-height: 1.4;
  text-align: center;
  opacity: 0;
  transform: scale(0.6);
  transition: opacity 160ms ease, transform 160ms var(--spring);
}
.nav-badge.show { opacity: 1; transform: scale(1); }

/* Plain red dot variant — no digits, just "there's something new here".
   Used for Connections (a like or a new match), as opposed to the
   Messages badge above which shows an actual unread count. */
.nav-badge-dot {
  min-width: 0;
  width: 10px;
  height: 10px;
  padding: 0;
  top: 0;
  left: auto;
  right: 6px;
  margin-left: 0;
  background: var(--danger, #E03D3D);
  box-shadow: 0 0 0 2px var(--surface);
}

/* Tablet */
@media (min-width: 720px) {
  :root { --page-pad: 24px; }
}

/* Desktop: sidebar navigation replaces the bottom bar entirely */
@media (min-width: 1100px) {
  :root { --nav-h: 0px; }
  .view-panel.is-active {
    padding: max(40px, env(safe-area-inset-top)) 40px 40px 132px;
    max-width: 1320px;
    margin: 0 auto;
    width: 100%;
  }
  .auth-hero { margin-top: 8vh; }

  .bottom-nav {
    position: fixed;
    left: 20px;
    right: auto;
    top: 20px;
    bottom: 20px;
    height: auto;
    width: 88px;
    flex-direction: column;
    justify-content: flex-start;
    gap: 6px;
    padding: 20px 0;
    border-radius: var(--radius-lg);
  }
  .nav-brand {
    display: block;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1rem;
    margin-bottom: 18px;
    background: var(--gradient);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  .nav-indicator { left: 8px; right: 8px; top: 0; height: 64px; width: auto !important; transform: translateY(0); }
  .bottom-nav:has(.nav-chip:nth-of-type(2).active) .nav-indicator { transform: translateY(100%); }
  .bottom-nav:has(.nav-chip:nth-of-type(3).active) .nav-indicator { transform: translateY(200%); }
  .bottom-nav:has(.nav-chip:nth-of-type(4).active) .nav-indicator { transform: translateY(300%); }
  .bottom-nav:has(.nav-chip:nth-of-type(5).active) .nav-indicator { transform: translateY(400%); }
  .nav-chip { flex: none; width: 72px; height: 64px; font-size: 0.7rem; }
  .mera-toast { bottom: 24px; left: calc(50% + 44px); }
  .chat-layout { height: clamp(460px, calc(100dvh - 180px), 820px); }
}

/* Small phones */
@media (max-width: 420px) {
  :root { --page-pad: 12px; }
  .auth-hero { padding: 36px 20px; margin-top: 3vh; }
  .btn { min-width: 0; }
  .btn-like { width: 64px; height: 64px; }
  .btn-icon-round { width: 52px; height: 52px; }
  .btn-send-label { display: none; }
  .btn-send { padding: 13px 16px; }
}

@media (max-width: 859px) {
  .profile-grid { grid-template-columns: 1fr; }
  .panel-large { grid-column: auto; }

  .chat-layout {
    position: relative;
    overflow: hidden;
    height: 100%;
  }
  .chat-sidebar, .chat-panel {
    position: absolute;
    inset: 0;
    width: 100%;
    transition: transform 280ms var(--ease), opacity 200ms ease;
  }
  .chat-sidebar {
    transform: translateX(0);
    opacity: 1;
  }
  .chat-panel {
    transform: translateX(100%);
    opacity: 0;
    pointer-events: none;
  }
  .chat-layout.show-conversation .chat-sidebar {
    transform: translateX(-100%);
    opacity: 0;
    pointer-events: none;
  }
  .chat-layout.show-conversation .chat-panel {
    transform: translateX(0);
    opacity: 1;
    pointer-events: auto;
  }
  .chat-back-btn { display: inline-flex; }
}

/* ==========================================================================
   Discover filters — small icon trigger + a modal that stays out of the
   way of the deck itself, so the discover page's own look is untouched
   until someone actually opens it.
   ========================================================================== */
.dashboard-header-actions { display: flex; align-items: center; gap: 10px; }
.dashboard-header-actions .icon-btn { flex-shrink: 0; }

/* -- admin: all users -- */
.admin-card { text-align: left; }
.admin-search-input {
  width: 100%;
  padding: 10px 14px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--ink);
  font-size: 0.9rem;
  margin-bottom: 8px;
}
#adminUserCount { margin: 0 0 12px; font-size: 0.78rem; }
.admin-user-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 50vh;
  overflow-y: auto;
  margin-bottom: 16px;
}
.admin-user-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.admin-user-avatar {
  width: 40px; height: 40px;
  border-radius: 50%;
  object-fit: cover;
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  background: var(--gradient-soft);
  font-weight: 700; color: var(--ink);
}
.admin-user-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.admin-user-info strong { font-size: 0.9rem; display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.admin-user-username { font-weight: 500; color: var(--muted); font-size: 0.8rem; }
.admin-user-meta { font-size: 0.76rem; color: var(--muted); }
.admin-user-badges { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px; }
.admin-badge {
  font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em;
  padding: 2px 7px; border-radius: 999px;
}
.admin-badge-hidden { background: rgba(255, 255, 255, 0.1); color: var(--muted); }
.admin-badge-warn { background: rgba(224, 165, 0, 0.18); color: #e0a500; }
.admin-badge-gold { background: rgba(255, 210, 74, 0.18); color: #ffd24a; }
.admin-badge-accent { background: var(--accent-soft); color: var(--accent-text); }

.filter-card { text-align: left; }
.filter-block { margin-bottom: 20px; }
.filter-block:last-of-type { margin-bottom: 4px; }
.filter-label {
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: var(--muted);
  font-weight: 700;
  font-size: 0.82rem;
  margin-bottom: 10px;
}
.filter-label strong { color: var(--ink); font-weight: 800; }

/* Dual-thumb age slider: one visual track+fill, two transparent range
   inputs stacked on top so both thumbs stay independently draggable. */
.dual-range { position: relative; height: 28px; }
.dual-range-track {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 5px;
  margin-top: -2.5px;
  border-radius: 999px;
  background: var(--border-strong);
}
.dual-range-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: 999px;
  background: var(--gradient);
}
.dual-range input[type="range"] {
  position: absolute;
  inset: 0;
  width: 100%;
  margin: 0;
  background: transparent;
  appearance: none;
  -webkit-appearance: none;
  pointer-events: none; /* only the thumb itself should be interactive */
}
.dual-range input[type="range"]::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  pointer-events: auto;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #fff;
  border: 3px solid var(--accent);
  box-shadow: var(--shadow-sm);
  cursor: grab;
  margin-top: -1px;
}
.dual-range input[type="range"]::-moz-range-thumb {
  pointer-events: auto;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: #fff;
  border: 3px solid var(--accent);
  box-shadow: var(--shadow-sm);
  cursor: grab;
}
.dual-range input[type="range"]::-webkit-slider-runnable-track { background: transparent; }
.dual-range input[type="range"]::-moz-range-track { background: transparent; }
.dual-range input[type="range"]:active::-webkit-slider-thumb { cursor: grabbing; transform: scale(1.08); }

.filter-pills { display: flex; flex-wrap: wrap; gap: 8px; }
.filter-pill {
  padding: 9px 16px;
  border-radius: 999px;
  background: var(--surface);
  border: 1.5px solid var(--border-strong);
  color: var(--muted);
  font-weight: 700;
  font-size: 0.88rem;
  transition: transform 150ms var(--spring), border-color 150ms ease, background 150ms ease, color 150ms ease;
}
.filter-pill:hover { transform: translateY(-1px); border-color: var(--accent-text); color: var(--ink); }
.filter-pill.active {
  background: var(--gradient);
  border-color: transparent;
  color: #fff;
  box-shadow: var(--glow-accent);
}

/* Small red "something new" dot inline in a pill's label — e.g. a fresh
   like or a new connection on the Connections subtabs. Reserves its
   layout space always so pill width doesn't jump when it appears. */
.tab-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-left: 6px;
  border-radius: 50%;
  background: var(--danger, #E03D3D);
  vertical-align: middle;
  opacity: 0;
  transform: scale(0.5);
  transition: opacity 160ms ease, transform 160ms var(--spring);
}
.tab-dot.show { opacity: 1; transform: scale(1); }
.filter-pill.active .tab-dot { background: #fff; }

/* ==========================================================================
   Country picker — reused by signup, profile editing, and the discover
   filter. A plain text input with a floating suggestion list underneath.
   ========================================================================== */
.country-field { position: relative; }
.country-suggest {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  z-index: 20;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
  max-height: 220px;
  overflow-y: auto;
  display: none;
  flex-direction: column;
  padding: 6px;
}
.country-suggest.show { display: flex; }
.country-suggest-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 9px 12px;
  border-radius: 10px;
  font-size: 0.9rem;
  transition: background 120ms ease;
}
.country-suggest-item:hover,
.country-suggest-item:focus-visible { background: var(--accent-soft); }
.auth-field input.invalid { border-color: var(--danger); }

/* ==========================================================================
   Chat: reply quotes, edited tag, deleted placeholder, long-press feedback
   ========================================================================== */
.message-bubble.pressing { transform: scale(0.97); filter: brightness(0.97); }
.message-bubble { user-select: none; -webkit-user-select: none; touch-action: pan-y; }

.message-reply-quote {
  display: block;
  margin-bottom: 5px;
  padding: 5px 9px;
  border-left: 3px solid rgba(255, 255, 255, 0.6);
  background: rgba(255, 255, 255, 0.14);
  border-radius: 8px;
  font-size: 0.82rem;
  opacity: 0.9;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.message-bubble.theirs .message-reply-quote {
  border-left-color: var(--accent-text);
  background: var(--accent-soft);
  color: var(--muted);
}

.message-edited-tag {
  display: inline-block;
  margin-left: 6px;
  font-size: 0.72rem;
  opacity: 0.7;
  font-style: italic;
}

/* Per-bubble timestamp + (mine-only) delivery/read receipt, WhatsApp-style
   double check marks. Sits bottom-right of every bubble, including the
   game-invite and spark-gift cards. */
.message-meta {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  margin-top: 3px;
  font-size: 0.68rem;
  line-height: 1;
  opacity: 0.75;
  user-select: none;
}
.message-bubble.theirs .message-meta,
.message-bubble.theirs .message-time { color: var(--muted); }
.message-time { white-space: nowrap; }
.message-ticks { display: inline-flex; align-items: center; color: rgba(255, 255, 255, 0.7); }
.message-ticks svg { display: block; }
.message-ticks .message-ticks-second { opacity: 0; transform: translateX(-3px); transition: opacity 160ms ease, transform 160ms ease; }
.message-ticks.sent .message-ticks-second { opacity: 0; }
.message-ticks.seen { color: #34C7F1; }
.message-ticks.seen .message-ticks-second { opacity: 1; transform: translateX(0); }
/* Cards (game invite / spark gift) aren't tinted by .mine's gradient text
   colour the same way a plain bubble is, so give their meta row its own
   readable tone instead of inheriting near-invisible defaults. */
.game-invite-card .message-meta,
.spark-gift-card .message-meta { opacity: 0.65; margin-top: 6px; }
.game-invite-card.theirs .message-ticks,
.spark-gift-card.theirs .message-ticks { display: none; }

.message-bubble.deleted {
  background: transparent;
  border-style: dashed;
  box-shadow: none;
}
.message-bubble.deleted .message-meta { justify-content: flex-start; margin-top: 4px; }
.message-deleted-label {
  color: var(--muted);
  font-style: italic;
  font-size: 0.88rem;
}

/* -- reply/edit composer strip, above the message input -- */
.composer-context[hidden] { display: none; }
.composer-context {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  margin-top: 8px;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
}
.composer-context-copy { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.composer-context-label { font-size: 0.74rem; font-weight: 800; color: var(--accent-text); text-transform: uppercase; letter-spacing: 0.04em; }
.composer-context-snippet { font-size: 0.86rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.composer-context-cancel { width: 30px; height: 30px; flex-shrink: 0; }

/* -- icebreaker chips (Agent 2) -- */
.icebreaker-chips[hidden] { display: none; }
.icebreaker-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 4px 2px 10px;
}
.icebreaker-chip {
  max-width: 100%;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--accent-soft);
  color: var(--ink);
  font-size: 0.82rem;
  font-weight: 600;
  text-align: left;
  white-space: normal;
  line-height: 1.3;
  cursor: pointer;
  transition: transform 120ms ease, background 120ms ease;
}
.icebreaker-chip:hover { background: var(--violet-soft); transform: translateY(-1px); }
.icebreaker-chip:active { transform: scale(0.97); }
.icebreaker-chip-loading {
  font-size: 0.8rem;
  color: var(--muted);
  padding: 7px 2px;
}

/* -- press-and-hold action menu -- */
.message-action-menu {
  position: fixed;
  z-index: 1100;
  display: none;
  flex-direction: column;
  min-width: 170px;
  padding: 6px;
  border-radius: var(--radius-md);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: scale(0.94);
  transition: opacity 160ms var(--ease), transform 160ms var(--spring);
}
.message-action-menu.open { display: flex; opacity: 1; transform: scale(1); }
.message-action-item[hidden] { display: none; }
.message-action-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 10px;
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--ink);
  transition: background 120ms ease;
}
.message-action-item svg { width: 18px; height: 18px; flex-shrink: 0; }
.message-action-item:hover { background: var(--surface-2); }
.message-action-item.message-action-danger { color: var(--danger); }
.message-action-item.message-action-danger:hover { background: var(--danger-soft); }

/* ==========================================================================
   Arcade — hub, modal, Snake HUD/D-pad, Chess board, lobby/result overlays
   ========================================================================== */
.arcade-hub-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
@media (max-width: 820px) { .arcade-hub-grid { grid-template-columns: 1fr; } }

.challenge-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--gradient-gold);
  color: #2b1400;
  font-weight: 800;
  font-size: 0.86rem;
  box-shadow: var(--glow-gold);
  transition: transform 150ms var(--spring);
}
.challenge-badge:hover { transform: translateY(-2px) scale(1.02); }
.challenge-badge:active { transform: scale(0.96); }
.challenge-badge-progress {
  display: block;
  margin-top: 4px;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--muted);
}

.chat-challenge-btn { width: 36px; height: 36px; font-size: 1rem; }
.chat-icebreaker-btn { width: 36px; height: 36px; font-size: 1rem; }

/* -- the modal itself: always dark, regardless of light/dark mode -- */
.arcade-modal-root { background: rgba(8, 4, 10, 0.6); backdrop-filter: blur(8px); padding: 0; }
.arcade-modal-card {
  position: relative;
  width: 100%;
  height: var(--vh);
  max-height: var(--vh);
  overflow-y: auto;
  border-radius: 0;
  background: #150910;
  border: 0;
  box-shadow: none;
  color: #f7eff6;
  padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
  animation: modal-in 260ms var(--spring) both;
}
@media (min-width: 720px) {
  .arcade-modal-root { padding: 20px; }
  .arcade-modal-card {
    width: min(94vw, 460px);
    height: auto;
    max-height: 88vh;
    border-radius: var(--radius-lg);
    border: 1px solid rgba(255, 255, 255, 0.1);
    box-shadow: var(--shadow-lg);
    padding: 18px;
  }
}
.arcade-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.1rem;
}
.arcade-modal-head .icon-btn { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.14); color: #fff; }

.arcade-hud {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  font-size: 0.9rem;
  color: rgba(247, 239, 246, 0.85);
}
.arcade-score strong { color: #fff; }
.arcade-timer { font-variant-numeric: tabular-nums; color: var(--accent-text); font-weight: 700; }

/* -- chess Final Boss dual clock — 20 min AI thinking time, 20 min player
   move time; whichever side's clock runs out first loses (see games.js
   ChessGame._tickBossClock). -- */
.chess-clocks { display: flex; gap: 8px; margin-bottom: 8px; }
.chess-clock {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 7px 12px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1.5px solid var(--border);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 0.92rem;
  color: var(--muted);
  transition: border-color 150ms ease, background 150ms ease, color 150ms ease;
}
.chess-clock-label { font-size: 0.72rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.8; }
.chess-clock-active {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--ink);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.chess-clock-low { color: var(--danger); border-color: var(--danger); background: var(--danger-soft); }

#arcadeCanvas {
  display: block;
  margin: 0 auto;
  width: 100%;
  max-width: 320px;
  aspect-ratio: 1;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.12);
}

.arcade-touchpad { display: flex; flex-direction: column; align-items: center; gap: 6px; margin-top: 14px; }
.arcade-dpad-row { display: flex; gap: 6px; }
.arcade-dpad-btn {
  width: 46px; height: 46px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: #fff;
  font-size: 1.2rem;
  transition: background 120ms ease, transform 120ms var(--spring);
}
.arcade-dpad-btn:active { background: var(--accent); transform: scale(0.92); }

.arcade-game-picker { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; padding: 20px 0; }

/* -- chess board: pure CSS grid, tap-to-move -- */
.chess-board {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  width: 100%;
  max-width: 360px;
  aspect-ratio: 1;
  margin: 0 auto;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.14);
}
.chess-square { position: relative; aspect-ratio: 1; display: grid; place-items: center; }
/* Bug fix: previously nothing visually or functionally blocked input while
   the AI was computing its reply, so a fast tap during that window could
   select/move the AI's own pieces. _myTurn()/_setAiThinking() in games.js
   now gate the click handler itself; this class is the visible half of
   that fix — dim the board and swallow pointer events for the duration. */
.chess-board.ai-thinking {
  pointer-events: none;
  opacity: 0.6;
  filter: saturate(0.7);
  transition: opacity .15s ease, filter .15s ease;
}
.chess-square.light { background: #efe3e8; }
.chess-square.dark { background: #7a4a63; }
.chess-square.last-move::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(255, 205, 60, 0.35);
}
.chess-square.in-check::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle, rgba(255, 61, 61, 0.75), rgba(255, 61, 61, 0.15) 70%);
}
.chess-square.selected::after {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: 6px;
  border: 2px solid var(--accent);
}
.chess-square.legal-target::after {
  content: "";
  position: absolute;
  width: 22%;
  height: 22%;
  border-radius: 50%;
  background: rgba(255, 122, 69, 0.55);
}
.chess-square.legal-capture::after {
  content: "";
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  border: 3px solid rgba(255, 122, 69, 0.75);
  background: transparent;
}
.chess-piece { position: relative; font-size: clamp(1.4rem, 6vw, 2rem); line-height: 1; user-select: none; transition: transform 120ms var(--spring); }
.chess-piece.chess-white { color: #fff; filter: drop-shadow(0 1px 1px rgba(0,0,0,0.5)); }
.chess-piece.chess-black { color: #1a1a1a; filter: drop-shadow(0 1px 1px rgba(255,255,255,0.25)); }
.chess-board-wrap { position: relative; }
.chess-hint-toggle { cursor: pointer; font-weight: 700; color: var(--accent-text); }
.chess-tray { display: flex; justify-content: center; min-height: 22px; }
.chess-captured { display: flex; flex-wrap: wrap; gap: 2px; justify-content: center; }
.captured-piece { font-size: 1rem; line-height: 1; opacity: 0.85; }
.captured-piece.chess-white { color: #fff; }
.captured-piece.chess-black { color: #1a1a1a; text-shadow: 0 0 2px rgba(255,255,255,0.4); }
.chess-promo-overlay[hidden] { display: none; }
.chess-promo-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(8, 4, 10, 0.72);
  border-radius: 10px;
  z-index: 3;
}
.chess-promo-card { text-align: center; color: #fff; }
.chess-promo-card p { margin: 0 0 10px; font-weight: 700; }
.chess-promo-options { display: flex; gap: 10px; }
.chess-promo-btn {
  width: 52px; height: 52px;
  font-size: 1.8rem;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: #fff;
  transition: transform 120ms var(--spring), background 120ms ease;
}
.chess-promo-btn:hover { background: var(--accent); transform: translateY(-2px); }

/* -- connect four: pure CSS grid, tap-a-column-to-drop. Disc colors are a
   fixed neon red-vs-cyan/purple signature independent of the site theme —
   same treatment chess's own black/white pieces get — since the whole
   arcade modal is already locked to a dark backdrop regardless of
   light/dark mode (see the note above .arcade-modal-card).

   Sizing: the board is bounded by BOTH available width and available
   height (the classic `width: min(100%, calc(availableHeight * ratio))`
   trick), never just width — a 7-wide/6-tall grid sized purely off width
   is routinely taller than a phone's viewport once the header/status row
   are accounted for, which pushed the whole gameplay page into a
   scrollbar. --c4-chrome below is a deliberately generous estimate of
   everything else on the gameplay page (back/close header, status row,
   the view-panel's own padding, doubled up because .view-panel and
   .gameplay-shell each reserve safe-area insets separately) so the board
   settles a little smaller rather than risking overflow. -- */
.c4-board-wrap {
  position: relative;
  display: flex;
  justify-content: center;
  --c4-chrome: calc(210px + (env(safe-area-inset-top, 0px) * 2) + (env(safe-area-inset-bottom, 0px) * 2));
}
.c4-board {
  position: relative; display: grid; gap: clamp(4px, 1.2vw, 8px);
  grid-template-columns: repeat(7, 1fr);
  width: min(100%, 420px, calc((var(--vh) - var(--c4-chrome)) * 7 / 6));
  background: linear-gradient(180deg, #14101f, #0c0a16);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-md);
  padding: clamp(6px, 2vw, 12px);
  box-shadow: inset 0 0 40px rgba(0, 0, 0, 0.5);
}
.c4-hit-layer { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(7, 1fr); z-index: 6; }
.c4-col-hit { position: relative; cursor: pointer; }
.c4-col-hover {
  position: absolute; top: 0; left: 4px; right: 4px; height: 100%;
  background: linear-gradient(180deg, rgba(255, 31, 77, 0.35), transparent 40%);
  opacity: 0; transition: opacity 150ms ease; border-radius: 8px; pointer-events: none;
}
.c4-col-hit:hover .c4-col-hover { opacity: 1; }
.c4-board.c4-locked .c4-col-hover { opacity: 0 !important; }
.c4-board.c4-locked .c4-hit-layer { cursor: default; }
.c4-cell {
  position: relative; width: 100%; aspect-ratio: 1 / 1; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #17111f, #08060d 70%);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.8), inset 0 0 0 2px rgba(255, 255, 255, 0.03);
  overflow: hidden;
}
.c4-disc { position: absolute; inset: 6%; border-radius: 50%; transform: translateY(-420px); opacity: 0; }
.c4-disc.c4-drop { animation: c4-drop-in var(--c4-fall-time, 0.5s) cubic-bezier(.5, .05, .6, 1.3) forwards; }
@keyframes c4-drop-in {
  0% { transform: translateY(-420px); opacity: 1; }
  75% { transform: translateY(0); opacity: 1; }
  85% { transform: translateY(-6%); }
  100% { transform: translateY(0); opacity: 1; }
}
.c4-disc.c4-player {
  background: radial-gradient(circle at 35% 30%, #ff8aa4, #ff1f4d 55%, #8a0022 100%);
  box-shadow: 0 0 14px rgba(255, 31, 77, 0.65), inset 0 0 8px rgba(255, 255, 255, 0.35);
}
.c4-disc.c4-ai {
  background: radial-gradient(circle at 35% 30%, #b3faff, #00eaff 55%, #005e6b 100%);
  box-shadow: 0 0 14px rgba(0, 234, 255, 0.55), inset 0 0 8px rgba(255, 255, 255, 0.35);
}
/* Live 1v1 matches use classic red/gold Connect Four colors instead of the
   AI's cyan theming — a human opponent isn't "the AI", so it shouldn't look
   like one. Player 1 (c4-player, red) and Player 2 (c4-p2, gold) are fixed
   to the seat, not the viewer — see the comment atop Connect4Game.mountLive
   in connect4.js. */
.c4-disc.c4-p2 {
  background: radial-gradient(circle at 35% 30%, #fff3b0, #ffb020 55%, #7a4a00 100%);
  box-shadow: 0 0 14px rgba(255, 176, 32, 0.6), inset 0 0 8px rgba(255, 255, 255, 0.35);
}
.c4-boss-mode[data-phase="1"] .c4-disc.c4-ai { background: radial-gradient(circle at 35% 30%, #b3faff, #00eaff 55%, #005e6b 100%); box-shadow: 0 0 16px rgba(0, 234, 255, 0.55), inset 0 0 8px rgba(255, 255, 255, 0.35); }
.c4-boss-mode[data-phase="2"] .c4-disc.c4-ai { background: radial-gradient(circle at 35% 30%, #f0c8ff, #b026ff 55%, #33005c 100%); box-shadow: 0 0 16px rgba(176, 38, 255, 0.6), inset 0 0 8px rgba(255, 255, 255, 0.35); }
.c4-boss-mode[data-phase="3"] .c4-disc.c4-ai { background: radial-gradient(circle at 35% 30%, #ffd0f6, #ff2bd6 55%, #5c0048 100%); box-shadow: 0 0 18px rgba(255, 43, 214, 0.65), inset 0 0 8px rgba(255, 255, 255, 0.35); }
.c4-disc.c4-wall {
  transform: none; opacity: 1;
  background: repeating-linear-gradient(135deg, #3a3f56, #3a3f56 4px, #2a2e40 4px, #2a2e40 8px);
  box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.7), 0 0 0 2px rgba(255, 255, 255, 0.03);
}
.c4-cell.c4-win .c4-disc { animation: c4-win-pulse 900ms ease infinite; }
@keyframes c4-win-pulse { 0%, 100% { filter: brightness(1); } 50% { filter: brightness(1.6); } }

.c4-hearts { display: flex; gap: 4px; }
.c4-heart { font-size: 1.1rem; filter: drop-shadow(0 0 6px rgba(0, 234, 255, 0.5)); transition: transform 200ms ease; }
.c4-heart.c4-heart-lost { animation: c4-heart-break 600ms ease forwards; }
@keyframes c4-heart-break {
  0% { transform: scale(1) rotate(0); opacity: 1; }
  30% { transform: scale(1.3) rotate(-10deg); }
  60% { transform: scale(0.8) rotate(12deg); opacity: 0.6; }
  100% { transform: scale(0.2) rotate(30deg); opacity: 0; }
}
#arcadeGameContainer.c4-shake { animation: c4-shake 400ms ease; }
@keyframes c4-shake {
  10%, 90% { transform: translateX(-2px); } 20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-8px); } 40%, 60% { transform: translateX(8px); }
}

/* level picker: reuses .filter-pill, just adds lock/clear affordances */
.c4-level-picker { max-width: 420px; margin: 0 auto; }
.filter-pill.c4-level-pill { flex: 1 1 auto; }
.filter-pill.c4-level-pill:disabled { opacity: 0.4; cursor: not-allowed; transform: none; }
.filter-pill.c4-level-cleared { border-color: #21e6a1; color: #21e6a1; }
.filter-pill.c4-boss-pill { flex-basis: 100%; border-color: #00eaff; color: #00eaff; font-weight: 800; }
.filter-pill.c4-boss-pill.c4-level-cleared { border-color: #ffb020; color: #ffb020; }

/* -- lobby / result overlays -- */
.arcade-lobby-overlay[hidden], .arcade-result-overlay[hidden] { display: none; }
.arcade-lobby-overlay, .arcade-result-overlay {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 40px 16px;
  text-align: center;
}
.arcade-lobby-overlay p { color: rgba(247, 239, 246, 0.85); font-size: 1rem; }
.arcade-result-overlay p { font-size: 1.05rem; font-weight: 600; }

/* ==========================================================================
   Games page — 3 sub-tabs (Arcade / My Challenge / Duels), same pill
   pattern as Connections. Arcade hero banner + grid styled here; My
   Challenge's empty state / summary card and Duels' cards follow below.
   ========================================================================== */
.games-subtabs { margin-bottom: 16px; }
.games-subpanel { animation: fade-in 220ms var(--ease) both; }
.games-subpanel[hidden] { display: none; }

.arcade-hero {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 20px 22px;
  margin-bottom: 16px;
  border-radius: var(--radius-lg, 20px);
  background: var(--gradient);
  color: #fff;
  overflow: hidden;
  isolation: isolate;
}
.arcade-hero-eyebrow {
  margin: 0 0 4px;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.85;
}
.arcade-hero-copy h3 { margin: 0; font-size: 1.15rem; line-height: 1.3; max-width: 30ch; }
.arcade-hero-glow {
  position: absolute;
  inset: -40% -10% auto auto;
  width: 220px;
  height: 220px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, 0.35), transparent 70%);
  z-index: -1;
  animation: arcade-hero-glow-drift 6s ease-in-out infinite alternate;
}
@keyframes arcade-hero-glow-drift {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(-18px, 14px) scale(1.15); }
}

/* ==========================================================================
   My Challenge — empty state (instructions + CTA), the horizontal summary
   card once one's set, and the shared add/edit form.
   ========================================================================== */
.challenge-empty-state {
  padding: 28px 22px;
  border-radius: var(--radius-lg, 16px);
  background: var(--gradient-soft);
  border: 1px solid var(--border);
  text-align: center;
}
.challenge-empty-icon {
  display: inline-grid;
  place-items: center;
  width: 60px;
  height: 60px;
  margin-bottom: 12px;
  font-size: 1.8rem;
  border-radius: 18px;
  background: var(--gradient-gold);
  box-shadow: 0 8px 18px rgba(245, 165, 36, 0.28);
}
.challenge-empty-state h3 { margin: 0 0 8px; font-size: 1.2rem; }
.challenge-empty-state > p { margin: 0 auto 22px; max-width: 42ch; color: var(--muted); line-height: 1.5; }
.challenge-how-it-works {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 40ch;
  margin: 0 auto 24px;
  text-align: left;
}
.challenge-how-step { display: flex; align-items: flex-start; gap: 12px; }
.challenge-how-step-num {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--gradient);
  color: #fff;
  font-size: 0.78rem;
  font-weight: 800;
}
.challenge-how-step p { margin: 0; font-size: 0.88rem; line-height: 1.45; color: var(--ink); }
.challenge-add-btn { padding-left: 24px; padding-right: 24px; }

.challenge-gate-card-wrap[hidden] { display: none; }
.challenge-gate-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px;
  border-radius: var(--radius-lg, 16px);
  background: var(--gradient-gold);
  box-shadow: 0 8px 20px rgba(245, 165, 36, 0.24);
}
.challenge-gate-card-icon {
  font-size: 1.8rem;
  flex-shrink: 0;
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
  border-radius: 14px;
  background: rgba(43, 20, 0, 0.14);
}
.challenge-gate-card-copy { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.challenge-gate-card-copy strong { color: #2b1400; font-size: 0.95rem; }
.challenge-gate-card-copy span { color: rgba(43, 20, 0, 0.75); font-size: 0.85rem; line-height: 1.35; }
.challenge-gate-card-actions { display: flex; gap: 8px; flex-shrink: 0; }
.challenge-gate-card-actions .icon-btn { background: rgba(43, 20, 0, 0.1); border-color: rgba(43, 20, 0, 0.18); color: #2b1400; }
.challenge-gate-card-actions .icon-btn:hover { border-color: rgba(43, 20, 0, 0.32); }

.challenge-form-wrap[hidden] { display: none; }
.challenge-form-wrap {
  padding: 18px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
  animation: fade-in 220ms var(--ease) both;
}

/* ==========================================================================
   Duels — horizontal cards for every OTHER person's Challenge Gate this
   player has started attempting (see game.js's Duels section / migration
   33's challenge_duels table).
   ========================================================================== */
.duels-intro { margin: 0 0 16px; color: var(--muted); font-size: 0.9rem; }
.duels-list { display: flex; flex-direction: column; gap: 12px; }
.duel-card {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--radius-md);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}
.duel-card-avatar { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.duel-card-avatar-fallback {
  display: grid; place-items: center;
  background: var(--gradient); color: #fff; font-weight: 800; font-size: 1.1rem;
}
.duel-card-copy { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 140px; }
.duel-card-copy strong { font-size: 0.98rem; }
.duel-card-target { font-size: 0.82rem; color: var(--muted); }
.duel-card-record { font-size: 0.78rem; font-weight: 700; display: flex; gap: 6px; }
.duel-card-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

.duel-card-changed { border-color: var(--danger); background: var(--danger-soft, rgba(241, 74, 74, 0.08)); }
.duel-card-changed-banner { flex-basis: 100%; padding-top: 10px; border-top: 1px dashed var(--border-strong); }
.duel-card-changed-banner p { margin: 0 0 10px; font-size: 0.86rem; font-weight: 700; color: var(--danger); }
.duel-card-changed-actions { display: flex; gap: 8px; }

.game-cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: 14px;
}
.game-card-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 22px 18px;
  min-height: 156px;
  border-radius: var(--radius-md);
  background: var(--gradient-soft);
  border: 1px solid var(--border);
  text-align: left;
  overflow: hidden;
  transition: transform 180ms var(--spring), box-shadow 180ms ease, border-color 180ms ease;
}
.game-card-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(120% 90% at 100% 100%, var(--accent-soft), transparent 60%);
  pointer-events: none;
  transition: opacity 180ms ease;
}
.game-card-tile:hover { transform: translateY(-4px) scale(1.015); box-shadow: var(--shadow-md); border-color: var(--border-strong); }
.game-card-tile:hover::after { opacity: 1.3; }
.game-card-tile:active { transform: scale(0.98); }
.game-card-icon {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  font-size: 1.8rem;
  line-height: 1;
  border-radius: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  transition: transform 180ms var(--spring);
}
.game-card-tile:hover .game-card-icon { transform: scale(1.08) rotate(-4deg); }
.game-card-title { font-size: 1.05rem; font-weight: 700; }
.game-card-stats {
  font-size: 0.74rem;
  font-weight: 700;
  color: var(--muted);
  display: flex;
  gap: 6px;
}
.game-card-stats .stat-win { color: var(--success); }
.game-card-stats .stat-loss { color: var(--danger); }
.game-card-cta {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--gradient);
  color: #fff;
  font-size: 0.8rem;
  font-weight: 700;
  box-shadow: 0 4px 12px rgba(255, 122, 69, 0.28);
  transition: transform 150ms var(--spring);
}
.game-card-tile:hover .game-card-cta { transform: translateX(2px); }
.game-card-cta span { transition: transform 150ms var(--spring); }
.game-card-tile:hover .game-card-cta span { transform: translateX(2px); }
/* Hidden-from-everyone-but-admins state: still visible to admins in the
   grid (so it can be managed) but reads clearly as "not open yet" rather
   than a normal playable tile. Regular players never see this at all —
   the tile isn't rendered as playable and clicking is a no-op toast. */
.game-card-tile.is-maintenance { opacity: 0.7; }
.game-card-tile.is-maintenance .game-card-icon { filter: grayscale(0.7); }
.game-card-cta-maintenance {
  background: var(--surface-2);
  color: var(--muted);
  border: 1px dashed var(--border-strong);
  box-shadow: none;
}
.game-card-admin-toggle {
  position: absolute;
  top: 10px; right: 10px;
  width: 26px; height: 26px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.85rem;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--border);
  backdrop-filter: blur(3px);
  transition: transform 120ms var(--spring), background 120ms ease;
}
.game-card-admin-toggle:hover { transform: scale(1.08); }
.game-card-admin-toggle.is-locked { background: rgba(224, 61, 61, 0.25); border-color: rgba(224, 61, 61, 0.4); }

/* In-modal "who do you want to play?" chooser — the step that now lives
   *inside* the game itself, right after tapping a tile. */
.opponent-picker { display: flex; flex-direction: column; gap: 10px; padding: 6px 0 2px; }
.opponent-picker-lead { margin: 0 0 4px; font-weight: 700; font-size: 1rem; }
.opponent-picker-option {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 14px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
  text-align: left;
  transition: transform 150ms var(--spring), border-color 150ms ease, box-shadow 150ms ease;
}
.opponent-picker-option:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); border-color: var(--border-strong); }
.opponent-picker-icon { font-size: 1.6rem; flex-shrink: 0; }
.opponent-picker-copy { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.opponent-picker-copy strong { font-size: 0.98rem; }
.opponent-picker-copy span:last-child { color: var(--muted); font-size: 0.83rem; }
.opponent-picker-chevron { font-size: 1.3rem; color: var(--accent-text); flex-shrink: 0; }

.arcade-picker-hint { text-align: center; color: rgba(247, 239, 246, 0.75); padding: 24px 12px; }
.arcade-friend-list { display: flex; flex-direction: column; gap: 8px; padding: 8px 0; }
.arcade-friend-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: #fff;
  text-align: left;
  transition: background 120ms ease;
}
.arcade-friend-item:hover { background: rgba(255, 255, 255, 0.12); }
.arcade-friend-item img, .arcade-friend-fallback {
  width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0; object-fit: cover;
}
.arcade-friend-fallback { display: grid; place-items: center; background: var(--gradient); font-weight: 700; font-size: 0.9rem; }


.arcade-victory-composer { display: flex; flex-direction: column; gap: 8px; width: 100%; margin-top: 4px; }
.arcade-rematch-offer { display: flex; flex-direction: column; gap: 8px; width: 100%; margin-top: 4px; text-align: center; }
.arcade-victory-row { display: flex; gap: 8px; width: 100%; }
.gamehost-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.gamehost-chips:empty { display: none; }
.gamehost-chip {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.2);
  color: #fff;
}
.gamehost-chip:hover { background: rgba(255, 255, 255, 0.18); }
.gamehost-chips .icebreaker-chip-loading { color: rgba(247, 239, 246, 0.75); }
.arcade-victory-input {
  flex: 1;
  min-width: 0;
  padding: 10px 14px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
}
.arcade-result-extra.btn { width: 100%; }

/* ==========================================================================
   Gameplay page — its own view-panel (not a modal), so leaving mid-match
   never destroys anything. Deliberately dark/immersive like the old modal.
   ========================================================================== */
.gameplay-shell {
  background: #150910;
  color: #f7eff6;
  border-radius: var(--radius-lg);
  padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
  min-height: 100%;
}
.gameplay-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}
.gameplay-head .icon-btn { background: rgba(255, 255, 255, 0.08); border-color: rgba(255, 255, 255, 0.14); color: #fff; flex-shrink: 0; }
.gameplay-title { font-family: var(--font-display); font-weight: 700; font-size: 1.1rem; flex: 1; min-width: 0; }
.gameplay-subtext[hidden] { display: none; }
.gameplay-subtext { margin: 2px 0 10px; font-size: 0.82rem; color: rgba(247, 239, 246, 0.65); text-align: center; }

/* Pause-vs-close confirmation opened by the gameplay header's X button. */
.game-exit-overlay[hidden] { display: none; }
.game-exit-overlay {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: rgba(10, 4, 9, 0.6);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.game-exit-card {
  width: 100%;
  max-width: 340px;
  background: #1c0f18;
  color: #f7eff6;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--radius-lg);
  padding: 20px;
  text-align: center;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
}
.game-exit-title { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; margin: 0 0 6px; }
.game-exit-sub { font-size: 0.83rem; color: rgba(247, 239, 246, 0.7); margin: 0 0 16px; }
.game-exit-actions { display: flex; flex-direction: column; gap: 8px; }
.game-exit-actions .btn { width: 100%; }
.game-exit-actions .btn-ghost { color: rgba(247, 239, 246, 0.75); }
.game-exit-actions .btn-ghost:hover { color: #fff; background: rgba(255, 255, 255, 0.08); }

.game-resume-banner[hidden] { display: none; }
.game-resume-banner {
  position: fixed;
  left: 50%;
  bottom: calc(var(--bottom-nav-height, 64px) + 14px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  border-radius: 999px;
  background: #1c0f18;
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow: var(--shadow-lg);
  animation: fade-in 220ms var(--ease) both;
  max-width: calc(100vw - 24px);
}
.game-resume-icon { font-size: 1.1rem; }
.game-resume-cta { font-weight: 700; color: var(--accent-text); flex-shrink: 0; }
#gameResumeText { font-size: 0.86rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.paused-games-wrap[hidden] { display: none; }
.paused-games-wrap { margin-bottom: 16px; }
.paused-games-heading { font-size: 0.9rem; color: var(--muted); margin: 0 0 8px; }
.paused-games-list { display: flex; flex-direction: column; gap: 8px; }
.paused-game-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  border-radius: var(--radius-md);
  background: var(--gradient-soft);
  border: 1px solid var(--border);
  text-align: left;
  transition: transform 150ms var(--spring), box-shadow 150ms ease;
}
.paused-game-item:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); }
.paused-game-icon { font-size: 1.4rem; flex-shrink: 0; }
.paused-game-copy { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.paused-game-copy strong { font-size: 0.95rem; }
.paused-game-copy span { color: var(--muted); font-size: 0.8rem; }
.paused-game-chevron { color: var(--accent-text); font-size: 1.2rem; flex-shrink: 0; }
.paused-game-item.paused-game-live { border-color: var(--accent-text); }

/* ==========================================================================
   Game invite chat card — a live-challenge invite rendered inline in the
   thread instead of only a bell notification.
   ========================================================================== */
.game-invite-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: min(86%, 320px);
  padding: 12px 14px;
}
.game-invite-head { display: flex; align-items: center; gap: 10px; }
.game-invite-icon { font-size: 1.5rem; flex-shrink: 0; }
.game-invite-copy strong { font-size: 0.92rem; line-height: 1.3; }
.game-invite-actions { display: flex; gap: 8px; }
.game-invite-actions .btn { flex: 1; padding: 8px 10px; font-size: 0.85rem; min-width: 0; }
.game-invite-status { margin: 0; font-size: 0.82rem; color: var(--muted); font-style: italic; }

/* ==========================================================================
   Profile page — big centered avatar header + VIP-style promo banner,
   our own take on the reference's profile/VIP block layout
   ========================================================================== */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

.profile-hero-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 4px;
  padding: 8px 0 20px;
}
.profile-hero-avatar-wrap { position: relative; margin-bottom: 10px; }
.profile-hero-avatar {
  width: 108px;
  height: 108px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--gradient);
  box-shadow: 0 0 0 4px var(--surface), 0 0 0 7px var(--accent-soft), var(--shadow-md);
}
.profile-hero-avatar:not([src]), .profile-hero-avatar[src=""] {
  background: var(--gradient);
}
.profile-hero-avatar-edit {
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--gradient);
  color: #fff;
  box-shadow: var(--glow-accent);
  cursor: pointer;
  border: 3px solid var(--surface);
}
.profile-hero-avatar-edit svg { width: 16px; height: 16px; }
.profile-hero-header h2 { font-size: 1.4rem; font-weight: 700; }
.profile-hero-meta { color: var(--muted); font-size: 0.9rem; }
.profile-hero-meta strong { color: var(--ink); }

.profile-hero-header-view { padding-bottom: 22px; }

/* -- ordered action list: Activate Premium → Edit profile → Visible in Discover -- */
.profile-action-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; }
.profile-action-btn {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 15px 16px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
  text-align: left;
  color: var(--ink);
  transition: transform 150ms var(--spring), border-color 150ms ease, box-shadow 150ms ease;
}
.profile-action-btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); border-color: var(--border-strong); }
.profile-action-btn:active { transform: scale(0.99); }
.profile-action-btn[hidden] { display: none; }
.profile-action-icon {
  width: 38px; height: 38px;
  flex-shrink: 0;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--gradient-soft);
  color: var(--accent-text);
}
.profile-action-icon svg { width: 18px; height: 18px; }
.profile-action-gold .profile-action-icon { background: var(--gradient-gold); color: #2b1400; }
.profile-action-danger .profile-action-icon { background: var(--danger-soft); color: var(--danger); }
.profile-action-danger:hover { border-color: var(--danger); box-shadow: 0 6px 18px rgba(241, 74, 74, 0.16); }
.profile-action-danger:hover .profile-action-icon { background: var(--danger); color: #fff; }
.profile-action-danger:hover strong { color: var(--danger); }
.profile-action-copy { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.profile-action-copy strong { font-size: 0.98rem; font-weight: 700; }
.profile-action-subtext { color: var(--muted); font-size: 0.82rem; }
.profile-action-chevron { font-size: 1.3rem; color: var(--muted); flex-shrink: 0; }

.telegram-disconnect-btn {
  align-self: flex-start;
  margin: -4px 0 0 4px;
  padding: 2px 4px;
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color 150ms ease;
}
.telegram-disconnect-btn:hover { color: var(--danger); }
.telegram-disconnect-btn[hidden] { display: none; }

.profile-toggle-pill {
  flex-shrink: 0;
  width: 44px; height: 26px;
  border-radius: 999px;
  background: var(--border-strong);
  position: relative;
  transition: background 180ms ease;
}
.profile-toggle-knob {
  position: absolute;
  top: 3px; left: 3px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: transform 180ms var(--spring);
}
.profile-action-btn.is-on .profile-toggle-pill { background: var(--gradient); }
.profile-action-btn.is-on .profile-toggle-knob { transform: translateX(18px); }

/* -- live "days · hrs · min · sec" countdown to premium expiry -- */
.countdown-card {
  padding: 16px;
  margin-bottom: 16px;
  border-radius: var(--radius-md);
  background: var(--surface-2);
  border: 1px solid var(--border);
  text-align: center;
}
.countdown-card[hidden] { display: none; }
.countdown-label { margin: 0 0 10px; color: var(--muted); font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700; }
.countdown-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.countdown-unit {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 4px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  border: 1px solid var(--border);
}
.countdown-unit span { font-family: var(--font-display); font-size: 1.3rem; font-weight: 700; color: var(--ink); }
.countdown-unit small { color: var(--muted); font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.05em; }

.account-panel { margin-top: 4px; }

/* -- Edit profile page -- */
.edit-profile-header { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.edit-profile-header h2 { font-size: 1.2rem; font-weight: 700; }
.edit-profile-avatar-wrap { display: flex; justify-content: center; margin-bottom: 18px; }

.plan-banner {
  position: relative;
  padding: 18px;
  margin-bottom: 16px;
  border-radius: var(--radius-md);
  background: linear-gradient(135deg, rgba(245, 165, 36, 0.14), rgba(247, 107, 28, 0.08));
  border: 1px solid rgba(245, 165, 36, 0.3);
  overflow: hidden;
}
.plan-banner-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; font-family: var(--font-display); font-size: 1.05rem; }
.plan-banner-icon {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--gradient-gold);
  color: #2b1400;
  flex-shrink: 0;
}
.plan-banner-icon svg { width: 18px; height: 18px; }
.plan-badge-pill {
  display: inline-block;
  padding: 2px 9px;
  margin-left: 4px;
  border-radius: 999px;
  background: var(--gradient-gold);
  color: #2b1400;
  font-size: 0.68rem;
  font-weight: 800;
  vertical-align: middle;
}
.plan-badge-pill.is-active { background: linear-gradient(135deg, var(--success), #0f8f55); color: #fff; }
.plan-banner .plan-card { background: transparent; border: 0; padding: 0; margin-bottom: 10px; }
.plan-banner #premiumButton { width: 100%; }

/* ==========================================================================
   Smooth theme swap — only affects surfaces that don't already declare
   their own transition (buttons, nav, etc. keep their existing motion
   untouched since a more specific rule always wins the whole property).
   ========================================================================== */
body, .app-shell, .panel, .modal-card, .notif-panel, .bottom-nav,
.header-pill, .summary-pill, .notice, .discover-deck, .chat-sidebar, .chat-panel,
.thread-item, .message-bubble, .plan-banner, .challenge-gate-card, .duel-card {
  transition: background-color 260ms ease, border-color 260ms ease, box-shadow 260ms ease, color 200ms ease;
}

/* ==========================================================================
   Theme picker — a grid of tappable swatches inside a slide-out panel that
   reuses the same .notif-panel shell (open/close plumbing lives in theme.js
   and mirrors the existing notification panel exactly).
   ========================================================================== */
.theme-swatch-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-top: 4px;
}
.theme-swatch {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px;
  border-radius: var(--radius-md);
  border: 1.5px solid var(--border);
  background: var(--surface-2);
  cursor: pointer;
  text-align: left;
  transition: transform 160ms var(--spring), border-color 160ms ease, box-shadow 160ms ease;
}
.theme-swatch:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); }
.theme-swatch:active { transform: scale(0.97); }
.theme-swatch.active {
  border-color: var(--accent-text);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.theme-swatch-orb {
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.25);
}
.theme-swatch-copy {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.theme-swatch-name {
  font-size: 0.85rem;
  font-weight: 700;
  font-family: var(--font-display);
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.theme-swatch-desc {
  font-size: 0.72rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.theme-swatch-check {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--gradient);
  color: #fff;
  display: none;
  align-items: center;
  justify-content: center;
  font-size: 0.62rem;
}
.theme-swatch.active .theme-swatch-check { display: flex; }

#themePanel .notif-panel-head p {
  margin: 2px 0 0;
  font-size: 0.82rem;
  color: var(--muted);
}

/* ==========================================================================
   Side FAB — a single collapsed corner button; tapping it fans the theme
   picker out above it instead of leaving a separate circle permanently
   pinned over the page content.
   ========================================================================== */
.side-fab-group {
  position: fixed;
  right: max(16px, env(safe-area-inset-right));
  bottom: calc(var(--nav-h) + max(20px, env(safe-area-inset-bottom)) + var(--tg-safe-bottom));
  z-index: 600;
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: 14px;
}
.app-shell:has(.view-panel[data-view="auth"].is-active) .side-fab-group {
  bottom: calc(max(20px, env(safe-area-inset-bottom)) + var(--tg-safe-bottom));
}
/* Inside an open chat conversation (mobile), the "+" speed-dial has nothing
   useful to add over the message thread/composer and just sits in the way —
   hide it while chat.js has #chatLayout in its "show-conversation" state. */
.app-shell:has(#chatLayout.show-conversation) .side-fab-group {
  display: none;
}
@media (min-width: 1100px) {
  .side-fab-group { bottom: max(28px, env(safe-area-inset-bottom)); }
}

.fab-main {
  position: relative;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background: var(--gradient);
  border: 1px solid rgba(255, 255, 255, 0.25);
  box-shadow: var(--glow-accent);
  z-index: 2;
  transition: transform 200ms var(--spring), box-shadow 160ms ease;
}
.fab-main svg { width: 22px; height: 22px; transition: transform 220ms var(--spring); }
.fab-main:active { transform: scale(0.9); }
/* The "+" rotates into an "×" once the dial is open, so the same icon reads
   as both "add options" and "close options" without swapping markup. */
.side-fab-group.open .fab-main svg { transform: rotate(135deg); }

.theme-fab {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background: var(--surface-2, #2a2530);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  opacity: 0;
  transform: scale(0.4);
  pointer-events: none;
  transition: transform 200ms var(--spring), opacity 160ms ease;
}
.theme-fab svg { width: 20px; height: 20px; }

.side-fab-group.open .theme-fab {
  opacity: 1;
  transform: scale(1);
  pointer-events: auto;
}
.side-fab-group.open .theme-fab:active { transform: scale(0.88); }
