/* This file is for your main application CSS */

/* ── iOS Safari viewport fixes ──────────────────────────────────────────────
   1. overflow-x: clip  — prevents the horizontal "jiggle" where fixed/absolute
      elements that slightly overshoot the viewport make the document scrollable
      side-to-side.  "clip" is used instead of "hidden" because it does NOT
      create a new stacking context, so position:fixed elements still work.
   2. overscroll-behavior: none  — disables iOS rubber-band / elastic bounce on
      the outer document.  Without this, users can drag the page beyond its
      edges, making it look like content extends off-screen.
   Both properties are no-ops on Android/desktop (which don't exhibit these
   behaviours), so they're safe to apply globally. */
html, body {
  overflow-x: clip;
  overscroll-behavior: none;
}

/* ── Mobile WebKit / iOS: LiveView phx-click relies on synthesized "click" events.
   Safari requires elements (or body) to look "interactive" (#168, PR #315). */
.hopara-app-shell {
  display: block;
  min-height: 100%;
}

[phx-click],
[phx-click-away],
[phx-submit],
button,
[type="submit"],
[type="button"],
a[href] {
  cursor: pointer;
  -webkit-tap-highlight-color: rgba(13, 35, 56, 0.15);
}

/* Don't fight text fields */
input,
textarea {
  cursor: text;
  -webkit-tap-highlight-color: rgba(13, 35, 56, 0.08);
}

/* ── Practice-word tap feedback ──────────────────────────────────────────────
   LiveView adds `phx-click-loading` to the tapped element IMMEDIATELY on click,
   before the server round-trip.  Users on slow connections (e.g. Spain → Chicago)
   previously saw nothing for 200-400 ms and tapped again thinking the first tap
   was missed.  The scale + fade below makes the response feel instant. */
span[phx-click="tap_japanese"],
button[phx-click="tap_and_practice"] {
  transition: opacity 0.12s ease, transform 0.12s ease;
}

span[phx-click="tap_japanese"].phx-click-loading,
button[phx-click="tap_and_practice"].phx-click-loading {
  opacity: 0.5;
  transform: scale(0.93);
}

/* ── Tab panels ──────────────────────────────────────────────────────────────
   All panels live in the DOM; CSS controls which one is visible.
   `tab-panel--active` is set by both the server (@tab assign) and instantly
   by JS.add_class/remove_class on click — no show/hide race conditions. */
.tab-panel {
  display: none;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  max-width: 600px;
  width: 100%;
  margin: 0 auto;
  padding: 16px 16px 0;
}

/* !important overrides the inline style="display:none" set by the server on
   inactive panels — ensures the panel is visible even if CSS loads late. */
.tab-panel.tab-panel--active {
  display: block !important;
}

/* Today's chat tab is a flex column so the message list scrolls correctly */
.tab-panel-today {
  padding: 0;
  flex-direction: column;
  overflow: hidden;
}

.tab-panel-today.tab-panel--active {
  display: flex !important;
}

/* ── Tab bar active/inactive states ─────────────────────────────────────────
   Controlled by JS.add_class/remove_class on click so the highlight is instant.
   The server also sets the class on initial render and page reload via @tab. */
.kotobi-theme-pastel-pink {
  --kotobi-app-bg: #F4E7D1;
  --kotobi-panel-chat: #F4E7D1;
  --kotobi-panel-store: #F4E7D1;
  --kotobi-panel-combos: #F4E7D1;
  --kotobi-panel-leaderboard: #F4E7D1;
  --kotobi-panel-profile: #F4E7D1;
  --kotobi-panel-practice: #F4E7D1;
  --kotobi-chat-bg: radial-gradient(circle at 18% 10%, rgba(248,239,225,0.82) 0%, transparent 36%),
    linear-gradient(180deg, #F4E7D1 0%, #F8EFE1 100%);
  --kotobi-nav-bg: #050201;
  --kotobi-nav-border: rgba(184, 92, 92, 0.35);
  --kotobi-nav-shadow: 0 -14px 34px rgba(34, 29, 28, 0.28);
  --kotobi-tab-active-bg: transparent;
  --kotobi-tab-active: #F4EBDD;
  --kotobi-tab-muted: rgba(244, 235, 221, 0.7);
  --kotobi-chat-action-bg: linear-gradient(135deg, #D0AA7C 0%, #BC8F6A 100%);
  --kotobi-accent: #D0AA7C;
  --kotobi-accent-strong: #846047;
  --kotobi-accent-soft: #F8EFE1;
  --kotobi-teal: #846047;
  --kotobi-card-bg: #F8EFE1;
  --kotobi-card-border: rgba(132, 96, 71, 0.26);
  --kotobi-scene-bg: #f7b997;
  --kotobi-scene-overlay: linear-gradient(90deg, rgba(247, 185, 151, 0.56) 0%, rgba(247, 185, 151, 0.4) 52%, rgba(161, 69, 5, 0.2) 100%);
  --kotobi-scene-text: #2B2523;
  --kotobi-scene-muted: rgba(43, 37, 35, 0.78);
  --kotobi-ai-bubble-bg: #F8EFE1;
  --kotobi-ai-bubble-text: #2B2523;
  --kotobi-player-bubble-bg: linear-gradient(135deg, #2F2926 0%, #3A332F 100%);
  --kotobi-success-bubble-bg: linear-gradient(135deg, #1f6f17 0%, #19630f 100%);
  --kotobi-error-bubble-bg: linear-gradient(135deg, #6b2f2f 0%, #2F2926 100%);
  --kotobi-warning-bubble-bg: linear-gradient(135deg, #846047 0%, #5f4535 100%);
  --kotobi-composer-bg: #f7b997;
  --kotobi-composer-border: rgba(87, 38, 3, 0.28);
  --kotobi-input-bg: #F8EFE1;
  --kotobi-input-border: rgba(208, 170, 124, 0.52);
  --kotobi-input-focus: #D0AA7C;
  --kotobi-secondary-button-bg: rgba(248, 239, 225, 0.66);
  --kotobi-secondary-button-border: rgba(208, 170, 124, 0.5);
  --kotobi-secondary-button-text: #2B2523;
}

.kotobi-app-frame {
  background: var(--kotobi-app-bg);
}

.kotobi-section-panel {
  background: rgba(255,255,255,0.42);
}

.kotobi-section-chat {
  background: var(--kotobi-panel-chat);
}

.kotobi-section-store {
  background: var(--kotobi-panel-store);
}

.kotobi-section-combos {
  background: var(--kotobi-panel-combos);
}

.kotobi-section-leaderboard {
  background: var(--kotobi-panel-leaderboard);
}

.kotobi-section-profile {
  background: var(--kotobi-panel-profile);
}

.kotobi-section-practice {
  background: var(--kotobi-panel-practice);
}

.kotobi-bottom-nav {
  background: var(--kotobi-nav-bg);
  border-top: 1px solid var(--kotobi-nav-border);
  box-shadow: var(--kotobi-nav-shadow);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  min-height: 60px;
}

.kotobi-bottom-nav-grid {
  position: relative;
  max-width: 600px;
  min-height: 50px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
  align-items: end;
}

.tab-btn {
  border: none;
  border-bottom: 3px solid transparent;
  /* !important beats the browser's built-in ButtonText color on Android/iOS */
  color: rgba(255, 255, 255, 0.5) !important;
}
.tab-btn.tab-btn-active {
  border-bottom: 3px solid #1FA1B0;
  color: #B2E4EA !important;
}

.bottom-tab-btn {
  border-bottom: none !important;
  border-radius: 16px;
  color: var(--kotobi-tab-muted) !important;
  font-size: 9px;
  gap: 3px;
  min-height: 42px;
  padding: 6px 2px 4px;
  align-self: end;
}

.bottom-tab-btn.tab-btn-active:not(.bottom-tab-btn-primary) {
  background: var(--kotobi-tab-active-bg) !important;
  color: var(--kotobi-tab-active) !important;
  box-shadow: none;
}

.bottom-tab-btn > span:last-child {
  display: none;
}

.bottom-tab-icon {
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.bottom-tab-icon img {
  width: 22px;
  height: 22px;
  display: block;
}

.bottom-tab-btn img {
  opacity: 0.9;
  filter: invert(93%) sepia(18%) saturate(422%) hue-rotate(334deg) brightness(103%) contrast(92%);
}

.bottom-tab-btn.tab-btn-active img {
  opacity: 1;
  filter: invert(53%) sepia(91%) saturate(1789%) hue-rotate(343deg) brightness(101%) contrast(94%);
}

.kotobi-scene-header {
  background: var(--kotobi-scene-bg) !important;
  border-bottom: 1px solid var(--kotobi-card-border);
  box-shadow: 0 8px 24px rgba(47, 41, 38, 0.16);
}

.kotobi-scene-header-overlay {
  background: var(--kotobi-scene-overlay) !important;
}

.kotobi-scene-header span,
.kotobi-scene-header div {
  text-shadow: none !important;
}

.kotobi-scene-header span[style*="color: white"],
.kotobi-scene-header span[style*="rgba(255,255,255"],
.kotobi-scene-header div[style*="rgba(255,255,255"] {
  color: var(--kotobi-scene-text) !important;
}

.kotobi-scene-header span[style*="rgba(255,255,255,0.78)"],
.kotobi-scene-header div[style*="rgba(255,255,255,0.78)"] {
  color: var(--kotobi-scene-muted) !important;
}

.kotobi-header-pill {
  background: rgba(244, 235, 221, 0.15) !important;
  border: 1px solid rgba(208, 170, 124, 0.36);
  color: var(--kotobi-scene-text) !important;
  box-shadow: 0 2px 8px rgba(47, 41, 38, 0.16);
}

.kotobi-header-button {
  background: rgba(244, 235, 221, 0.18) !important;
  border-color: rgba(208, 170, 124, 0.42) !important;
  color: var(--kotobi-scene-text) !important;
}

.kotobi-header-icon-button {
  color: var(--kotobi-scene-text) !important;
}

.kotobi-chat-scroll {
  background: var(--kotobi-chat-bg) !important;
}

.kotobi-chat-bubble {
  font-size: 9pt !important;
  line-height: 1.45 !important;
  box-shadow: 0 8px 24px rgba(47, 41, 38, 0.1);
}

.kotobi-chat-bubble [style*="font-size"] {
  font-size: inherit !important;
}

.kotobi-chat-message {
  font-size: 9pt;
}

.kotobi-chat-bubble-ai {
  background: var(--kotobi-ai-bubble-bg) !important;
  border: 1px solid rgba(132, 96, 71, 0.18);
  color: var(--kotobi-ai-bubble-text) !important;
}

.kotobi-chat-bubble-translation {
  background: rgba(255, 253, 251, 0.9) !important;
  border-left-color: var(--kotobi-teal) !important;
  color: var(--kotobi-ai-bubble-text) !important;
}

.kotobi-chat-bubble-player {
  background: var(--kotobi-player-bubble-bg) !important;
  color: white !important;
}

.kotobi-chat-bubble-practice-good {
  background: var(--kotobi-success-bubble-bg) !important;
}

.kotobi-chat-bubble-practice-mid {
  background: var(--kotobi-warning-bubble-bg) !important;
}

.kotobi-chat-bubble-practice-low {
  background: var(--kotobi-error-bubble-bg) !important;
}

.kotobi-chat-system-chip {
  font-size: 8pt !important;
  background: #F8EFE1 !important;
  border: 1px solid var(--kotobi-card-border);
  color: #2B2523 !important;
}

.kotobi-chat-composer {
  background: var(--kotobi-composer-bg) !important;
  border-top: 1px solid var(--kotobi-composer-border) !important;
  box-shadow: 0 -8px 24px rgba(47, 41, 38, 0.18);
}

.kotobi-chip-tray {
  background: transparent;
}

.kotobi-choice-chip {
  font-size: 9pt !important;
  line-height: 1.2 !important;
  padding: 5px 10px !important;
  background: rgba(255, 255, 255, 0.88) !important;
  border-color: var(--kotobi-input-border) !important;
  color: #25303b !important;
  box-shadow: 0 2px 8px rgba(47, 41, 38, 0.06);
}

.kotobi-chat-composer .kotobi-choice-chip {
  background: rgba(248, 239, 225, 0.42) !important;
  border-color: rgba(87, 38, 3, 0.24) !important;
  color: #2B2523 !important;
}

.kotobi-chip-tray span {
  font-size: 7.5pt !important;
}

.kotobi-choice-chip-selected,
.kotobi-choice-chip-refresh {
  background: var(--kotobi-accent-soft) !important;
  border-color: rgba(208, 170, 124, 0.52) !important;
  color: var(--kotobi-accent-strong) !important;
}

.kotobi-chat-composer .kotobi-choice-chip-selected,
.kotobi-chat-composer .kotobi-choice-chip-refresh {
  background: #D0AA7C !important;
  border-color: #D0AA7C !important;
  color: #2B2523 !important;
}

.kotobi-choice-chip-disabled {
  background: rgba(243, 244, 246, 0.8) !important;
  color: #9ca3af !important;
}

.kotobi-choice-chip-secondary {
  background: rgba(255, 255, 255, 0.64) !important;
  color: #7f6b76 !important;
}

.kotobi-chat-input-shell {
  background: transparent;
}

.kotobi-chat-form {
  flex-wrap: nowrap;
}

.kotobi-chat-input-wrap {
  min-width: 0;
}

.kotobi-chat-input {
  min-width: 0;
  background: var(--kotobi-input-bg) !important;
  border-color: var(--kotobi-input-border) !important;
  box-shadow: inset 0 0 0 1px rgba(244,235,221,0.42), 0 3px 14px rgba(47, 41, 38, 0.16);
}

.kotobi-chat-input:focus {
  border-color: var(--kotobi-input-focus) !important;
  box-shadow: 0 0 0 3px rgba(208, 170, 124, 0.18), 0 3px 14px rgba(47, 41, 38, 0.16);
}

.kotobi-action-button {
  border-color: var(--kotobi-secondary-button-border) !important;
  box-shadow: 0 4px 12px rgba(47, 41, 38, 0.18);
}

.kotobi-action-button-translate,
.kotobi-action-button-send {
  background: #ffffff !important;
  color: #2B2523 !important;
}

.kotobi-action-button-secondary,
.kotobi-action-button-practice {
  background: #ffffff !important;
  color: var(--kotobi-secondary-button-text) !important;
}

.kotobi-action-button:disabled {
  background: #F8EFE1 !important;
  color: #475569 !important;
  box-shadow: none;
}

.kotobi-action-button img {
  display: block;
}

.kotobi-action-button-send img {
  width: 18px !important;
  height: 18px !important;
  margin: 0;
  transform: translate(9px, 1px);
  filter: invert(19%) sepia(8%) saturate(817%) hue-rotate(338deg) brightness(94%) contrast(90%);
}

.kotobi-action-button-send {
  padding: 0 !important;
  align-items: center !important;
  justify-content: center !important;
}

.kotobi-action-button-send:disabled img {
  filter: invert(38%) sepia(11%) saturate(1629%) hue-rotate(340deg) brightness(87%) contrast(82%);
}

.kotobi-action-button-send:disabled {
  background: #F8EFE1 !important;
  color: #846047 !important;
}

.kotobi-theme-pastel-pink button[disabled],
.kotobi-theme-pastel-pink [style*="background: #e5e7eb"],
.kotobi-theme-pastel-pink [style*="background: #f3f4f6"] {
  color: #475569 !important;
}

@media (max-width: 430px) {
  .kotobi-chat-form {
    flex-wrap: nowrap;
    justify-content: flex-end;
  }

  .kotobi-chat-form:focus-within {
    flex-wrap: wrap;
  }

  .kotobi-chat-form:focus-within .kotobi-chat-input-wrap {
    flex: 0 0 100% !important;
    width: 100%;
  }

  .kotobi-chat-input-shell {
    padding-top: 6px !important;
  }

  .kotobi-action-button {
    width: 38px !important;
    height: 38px !important;
  }

  .kotobi-action-button-translate {
    margin-right: auto;
  }
}

/* ── Shared typing-dots animation used by the NPC "thinking" indicator ──────
   Defined globally so it is available both in the chat tab and in the
   practice bottom-sheet (which renders outside the tab content). */
@keyframes typing {
  0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-4px); }
}

/* ── LiveView toast pill (bottom-center) — slide + fade in ───────────────
   Used by `<div phx-hook="LiveToast">` in JourneyLive. The hook
   auto-dismisses by clearing the `@toast` assign after ~2.8s. */
@keyframes live-toast-in {
  from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

/* ── Streak celebration overlay ──────────────────────────────────────────
   Triggered by :streak_celebration assign + the StreakCelebration JS hook
   (which also drives the canvas confetti burst). Respects reduced motion:
   the keyframes collapse to a simple fade so users who opt out of motion
   still get the reward text without the pop/bounce. */
@keyframes streak-celebration-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes streak-celebration-pop {
  0%   { transform: scale(0.55); opacity: 0; }
  55%  { transform: scale(1.08); opacity: 1; }
  75%  { transform: scale(0.97); }
  100% { transform: scale(1);    opacity: 1; }
}

@keyframes streak-flame-bounce {
  from { transform: translateY(0)    rotate(-4deg) scale(1); }
  to   { transform: translateY(-10px) rotate(5deg)  scale(1.08); }
}

@media (prefers-reduced-motion: reduce) {
  #streak-celebration-overlay,
  #streak-celebration-card,
  #streak-celebration-card > div {
    animation-duration: 0.001s !important;
    animation-iteration-count: 1 !important;
  }
}

/* ── Scene bar animations ────────────────────────────────────────────────
   All animations here are CSS-only so they survive when Lottie is loading,
   when the Lottie asset is missing, and when we ship as a thin iOS / Android
   wrapper (WebKit / Chromium both hardware-accelerate transform + opacity). */

/* Slow diagonal sheen across the scene bar — tiny bit of "alive" feel even
   when no Lottie is loaded. GPU-accelerated (transform only). */
@keyframes scene-sheen {
  0%   { transform: translateX(-60%); }
  100% { transform: translateX(160%); }
}
.scene-bar-sheen {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.scene-bar-sheen::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0;
  left: 0;
  width: 40%;
  background: linear-gradient(
    100deg,
    transparent 0%,
    rgba(255, 255, 255, 0.07) 45%,
    rgba(255, 255, 255, 0.14) 50%,
    rgba(255, 255, 255, 0.07) 55%,
    transparent 100%
  );
  transform: translateX(-60%);
  animation: scene-sheen 7s linear infinite;
}

/* Gentle pulse on the active scene segment in the progress track. */
@keyframes scene-pulse {
  0%, 100% { opacity: 0.9; box-shadow: 0 0 0 0 rgba(255,255,255,0.55); }
  50%      { opacity: 1;   box-shadow: 0 0 6px 1px rgba(255,255,255,0.75); }
}
.scene-dot-active {
  animation: scene-pulse 1.8s ease-in-out infinite;
}

/* Subtle bob for the fallback 🎬 emoji so the thumbnail isn't static when
   a Lottie is missing. */
@keyframes scene-bob {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-2px) rotate(2deg); }
}
.scene-thumb-fallback {
  animation: scene-bob 2.4s ease-in-out infinite;
}

/* ═══════════════════════════════════════════════════════════════════════
   COSMETICS — CHAT BUBBLE EFFECTS, BORDERS, SHAPES, AVATAR FRAMES
   Ported from vision_builder. Everything below is pure CSS so the same
   rules render identically inside an iOS (WKWebView) or Android
   (WebView / Chromium) wrapper — no native bridge required.
   All animations use transform / opacity / filter / box-shadow so they
   are GPU-accelerated and cheap on low-end devices.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── CHAT EFFECTS (aura around the bubble) ───────────────────────────── */
/* Every effect class sits on an *outer wrapper* whose only job is to frame
   the bubble. We paint directly with box-shadow on the wrapper itself —
   no negative-z-index pseudo-elements — so these always compose with the
   bubble's background + border + the page, independent of stacking order. */

.chat-effect-sparkles,
.chat-effect-glow,
.chat-effect-neon,
.chat-effect-fire,
.chat-effect-rainbow {
  position: relative;
  isolation: isolate;
}

/* Sparkles — two drifting emoji floats anchored to the wrapper corners. */
.chat-effect-sparkles::before,
.chat-effect-sparkles::after {
  content: '✨';
  position: absolute;
  font-size: 12px;
  animation: sparkle 2s ease-in-out infinite;
  pointer-events: none;
  z-index: 2;
}
.chat-effect-sparkles::before { top: -8px;    right: 10%; animation-delay: 0s; }
.chat-effect-sparkles::after  { bottom: -8px; left: 15%;  animation-delay: 1s; }
@keyframes sparkle {
  0%, 100% { opacity: 0.3; transform: scale(0.8); }
  50%      { opacity: 1;   transform: scale(1.2); }
}

/* Soft glow — indigo halo that breathes. */
.chat-effect-glow {
  animation: soft-glow 2s ease-in-out infinite;
}
@keyframes soft-glow {
  0%, 100% { box-shadow: 0 0 10px 2px rgba(99,102,241,0.45); }
  50%      { box-shadow: 0 0 22px 4px rgba(99,102,241,0.85); }
}

/* Neon pulse — violet shadow with an intermittent flicker. */
.chat-effect-neon {
  animation: neon-flicker 3s ease-in-out infinite;
}
@keyframes neon-flicker {
  0%, 92%, 100% {
    box-shadow:
      0 0 5px  rgba(168,85,247,0.8),
      0 0 12px rgba(168,85,247,0.6),
      0 0 22px rgba(168,85,247,0.4);
  }
  93% { box-shadow: 0 0 3px rgba(168,85,247,0.4), 0 0 6px rgba(168,85,247,0.3); }
  94%, 96% {
    box-shadow:
      0 0 5px  rgba(168,85,247,0.8),
      0 0 12px rgba(168,85,247,0.6),
      0 0 22px rgba(168,85,247,0.4);
  }
  95% { box-shadow: 0 0 4px rgba(168,85,247,0.5), 0 0 8px rgba(168,85,247,0.4); }
}

/* Fire glow — warm ember shadow beneath and around the bubble. */
.chat-effect-fire {
  animation: fire-ambient-glow 1.2s ease-in-out infinite alternate;
}
@keyframes fire-ambient-glow {
  0%   {
    box-shadow:
      0 2px 12px rgba(255, 88, 0, 0.45),
      0 0 18px   rgba(255,140, 0, 0.35);
  }
  100% {
    box-shadow:
      0 4px 22px rgba(255, 88, 0, 0.75),
      0 0 28px   rgba(255,140, 0, 0.65);
  }
}

/* Rainbow ring — gradient ring kept OUTSIDE the bubble using the
   wrapper's ::before with an "inside-out" mask trick. isolation: isolate
   on the wrapper keeps the ring below sibling content but above the
   page, and the mask hides its centre so the bubble stays readable. */
.chat-effect-rainbow::before {
  content: '';
  position: absolute;
  inset: -4px;
  border-radius: 18px;
  padding: 3px;
  background: linear-gradient(90deg,
    #ef4444, #f97316, #eab308, #22c55e, #3b82f6, #8b5cf6, #ec4899, #ef4444);
  background-size: 200% 100%;
  animation: rainbow-shift 2s linear infinite;
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
          mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  z-index: -1;
  pointer-events: none;
}
@keyframes rainbow-shift {
  0%   { background-position:   0% 50%; }
  100% { background-position: 200% 50%; }
}

/* ── BUBBLE BORDERS ─────────────────────────────────────────────────── */

.border-holographic {
  animation: holo-shimmer 3s linear infinite;
}
@keyframes holo-shimmer {
  0%   { filter: hue-rotate(0deg);   }
  100% { filter: hue-rotate(360deg); }
}

/* ── ANIMATED BUBBLE BACKGROUNDS ───────────────────────────────────── */

.bubble-animated-aurora {
  background-size: 300% 300% !important;
  animation: aurora-shift 8s ease-in-out infinite;
}
@keyframes aurora-shift {
  0%, 100% { background-position:   0% 50%; }
  50%      { background-position: 100% 50%; }
}

.bubble-animated-galaxy {
  animation: galaxy-breathe 6s ease-in-out infinite;
}
@keyframes galaxy-breathe {
  0%, 100% { filter: brightness(1)    saturate(1);   }
  50%      { filter: brightness(1.15) saturate(1.25);}
}

/* ── BUBBLE SHAPE ──────────────────────────────────────────────────── */
/* Every bubble uses the same rounded silhouette — we chose to drop
   user-picked shapes because clip-path/corner variants collided with chat
   effect pseudo-elements and animated borders. */

.bubble-shape-rounded { border-radius: 14px 14px 4px 14px; }

/* ── AVATAR FRAMES ─────────────────────────────────────────────────── */
/* Each frame is a small wrapper that lives around a circular avatar image.
   Uses box-shadow rings instead of `ring-*` utility classes so it works
   without Tailwind. */

.avatar-frame {
  position: relative;
  border-radius: 50%;
  padding: 3px;
  display: inline-block;
  line-height: 0;
}
.avatar-frame > * {
  border-radius: 50%;
  display: block;
}

.avatar-frame-sakura  { background: linear-gradient(135deg,#fbcfe8,#f472b6,#fbcfe8); box-shadow: 0 0 10px rgba(244,114,182,0.45); }
.avatar-frame-gold    { background: linear-gradient(135deg,#fde68a,#fbbf24,#b45309); box-shadow: 0 0 10px rgba(251,191,36,0.55); }
.avatar-frame-neon    { background: #a855f7; box-shadow: 0 0 12px rgba(168,85,247,0.7); animation: frame-pulse 2s ease-in-out infinite; }
.avatar-frame-ocean   { background: linear-gradient(135deg,#22d3ee,#0EA5E9,#167D89); box-shadow: 0 0 10px rgba(34,211,238,0.55); }
.avatar-frame-fire    { background: linear-gradient(135deg,#fb923c,#f97316,#dc2626); box-shadow: 0 0 12px rgba(249,115,22,0.65); animation: frame-flicker 2.5s ease-in-out infinite; }
.avatar-frame-galaxy  { background: linear-gradient(135deg,#1a0033,#4b0082,#800080,#1a0033); box-shadow: 0 0 12px rgba(139,92,246,0.55); }
.avatar-frame-rainbow {
  background: conic-gradient(#ef4444,#f97316,#eab308,#22c55e,#3b82f6,#8b5cf6,#ec4899,#ef4444);
  animation: frame-rotate 3s linear infinite;
}
.avatar-frame-rainbow > * { background: white; }

@keyframes frame-pulse {
  0%, 100% { box-shadow: 0 0 8px  rgba(168,85,247,0.5); }
  50%      { box-shadow: 0 0 18px rgba(168,85,247,0.9); }
}
@keyframes frame-flicker {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.2); }
}
@keyframes frame-rotate {
  to { transform: rotate(360deg); }
}

/* Fallback avatar when we don't have an image — coloured circle with
   initials, used in lieu of a Lottie/GIF the user hasn't picked yet. */
.avatar-initials {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: linear-gradient(135deg, #0EA5E9, #167D89);
  color: white;
  font-weight: 800;
  font-family: inherit;
  user-select: none;
}

/* Decoration overlay sits on top of the avatar — pure emoji/text
   overlay so it works on every platform.

   NOTE: `.avatar-frame > *` above forces `border-radius: 50%; display:
   block` on every direct child. We re-declare those here so the
   overlay stays a small inline-block emoji pinned to the corner
   (otherwise it inherits the circular clipping and gets swallowed by
   the avatar). Stagger horizontally when multiple decorations are
   equipped so a crown + halo + sparkles don't pile on top of each
   other. */
.avatar-overlay {
  position: absolute;
  top: -8px;
  right: -8px;
  font-size: 16px;
  line-height: 1;
  pointer-events: none;
  border-radius: 0 !important;
  display: inline-block !important;
  width: auto !important;
  height: auto !important;
  background: transparent !important;
  z-index: 3;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.35));
}
.avatar-overlay ~ .avatar-overlay         { right: -22px; top: -4px; }
.avatar-overlay ~ .avatar-overlay ~ .avatar-overlay { right: -4px;  top:  10px; }

/* ── CHAT BACKGROUNDS ──────────────────────────────────────────────── */
/* Applied on the chat scroll container so the wallpaper fills the whole
   pane. Each background is a pure CSS gradient (+ optional animation)
   so it renders identically on web and inside iOS / Android WebView
   wrappers with zero extra assets. */

.chat-bg-tokyo {
  background:
    linear-gradient(180deg, rgba(12,9,24,0.92) 0%, rgba(20,10,40,0.85) 60%, rgba(236,72,153,0.35) 100%),
    repeating-linear-gradient(90deg, rgba(236,72,153,0.06) 0 2px, transparent 2px 40px) !important;
  color: #f5f3ff;
}
.chat-bg-sakura {
  background:
    linear-gradient(180deg, #fdf2f8 0%, #fce7f3 60%, #fbcfe8 100%) !important;
}
.chat-bg-ocean {
  background:
    linear-gradient(180deg, #ecfeff 0%, #cffafe 50%, #a5f3fc 100%) !important;
}
.chat-bg-mountain {
  background:
    linear-gradient(180deg, #f8fafc 0%, #e2e8f0 55%, #94a3b8 100%) !important;
}
.chat-bg-stars {
  background:
    radial-gradient(1px 1px at 20% 30%, rgba(255,255,255,0.9) 50%, transparent 51%),
    radial-gradient(1px 1px at 70% 20%, rgba(255,255,255,0.7) 50%, transparent 51%),
    radial-gradient(1px 1px at 40% 70%, rgba(255,255,255,0.8) 50%, transparent 51%),
    radial-gradient(1px 1px at 85% 85%, rgba(255,255,255,0.6) 50%, transparent 51%),
    radial-gradient(1px 1px at 10% 85%, rgba(255,255,255,0.7) 50%, transparent 51%),
    linear-gradient(180deg, #020617 0%, #0f172a 60%, #1e1b4b 100%) !important;
  color: #f8fafc;
}
/* On dark backgrounds, NPC bubbles + translation chips stay readable.
   (Kept intentionally minimal — we don't want to clobber user-picked
   bubble colour cosmetics.) */
.chat-bg-tokyo .bubble-shape-rounded[style*="background: #EEF8F9"],
.chat-bg-stars .bubble-shape-rounded[style*="background: #EEF8F9"] {
  background: rgba(255,255,255,0.08) !important;
  color: #f5f3ff !important;
}
