/* ═══════════════════════════════════════════════════════════════════════════
   Leadly PWA — "Sunset" theme
   Visually distinct from any major messaging app. Warm, alive, brand-owned.
   Primary aubergine + coral accent. RTL. Mobile-first.
   ═══════════════════════════════════════════════════════════════════════════ */

* { box-sizing: border-box; margin: 0; padding: 0; }
/* 100dvh = dynamic viewport height. Adjusts as Chrome's URL bar slides
   away on scroll, so the chat fills the actual visible viewport — not
   100vh which leaves a strip cut off below the URL bar. */
html, body { height: 100dvh; overflow: hidden; }
html { -webkit-text-size-adjust: 100%; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Tahoma, "Helvetica Neue", Arial, sans-serif;
  font-size: 15px;
  color: var(--text);
  background: var(--app-bg);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
  /* Safe-area padding is applied directly by .header (top) and the
     composer area (bottom) via @supports(env(...)) below. Applying it
     on body too made body's content box smaller than 100dvh, while
     #root was sized to 100dvh — the overflow was then clipped by
     body's overflow:hidden, silently chopping the bottom of the
     layout on devices that report non-zero safe-area-insets. */
}
button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; }
input, textarea { font-family: inherit; }

/* ─── LEADLY DASHBOARD PALETTE — flipped bubbles ───────────────────────────
   Matches the operator dashboard's identity:
     Navy 900        #0F172A   header (deepest)
     Navy 800        #1E293B   chat background, header gradient end
     Navy 700        #334155   card borders, dividers
     Emerald 500     #10B981   primary brand — Yasmin (incoming) bubbles, send button
     Emerald 400     #22C55E   gradient pair / hover accent
     White           #FFFFFF   patient (outgoing) bubbles
     Slate 50        #F8FAFC   incoming bubble text
     Slate 200       #E2E8F0   subtle text
     Slate 400       #94A3B8   muted text, ticks

   Bubbles flipped vs the original layout:
     - Yasmin (incoming)  = emerald  (the brand-colored side)
     - Patient (outgoing) = white    (the "your cards on dark bg" feel)
   ──────────────────────────────────────────────────────────────────────── */
:root {
  /* Background — deep navy, matching dashboard body */
  --app-bg: #1E293B;
  --chat-bg: #1E293B;
  /* Pattern: subtle emerald + white micro-dots on the navy */
  --chat-pattern: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 60 60'%3E%3Ccircle cx='30' cy='30' r='1' fill='%2310B981' opacity='0.08'/%3E%3Ccircle cx='10' cy='50' r='0.8' fill='%23ffffff' opacity='0.04'/%3E%3Ccircle cx='50' cy='10' r='0.8' fill='%2322C55E' opacity='0.06'/%3E%3C/svg%3E");

  /* Header — deepest navy gradient */
  --header-bg: linear-gradient(135deg, #0F172A 0%, #1E293B 100%);
  --header-bg-solid: #0F172A;
  --header-text: #ffffff;
  --header-icon: rgba(255,255,255,0.92);

  /* INCOMING (Yasmin) — emerald green, the brand-colored side */
  --bubble-in: linear-gradient(135deg, #10B981 0%, #22C55E 100%);
  --bubble-in-solid: #10B981;
  --bubble-in-text: #ffffff;
  --bubble-in-border: rgba(16, 185, 129, 0.25);

  /* OUTGOING (patient) — white cards, like the dashboard cards on dark bg */
  --bubble-out: linear-gradient(135deg, #ffffff 0%, #F8FAFC 100%);
  --bubble-out-solid: #ffffff;
  --bubble-out-text: #0F172A;
  --bubble-out-border: rgba(255, 255, 255, 0.4);

  /* Layered shadows — emerald glow on the incoming/Yasmin side now */
  --bubble-shadow:
    0 1px 2px rgba(16, 185, 129, 0.18),
    0 4px 12px rgba(16, 185, 129, 0.12),
    0 8px 24px rgba(16, 185, 129, 0.08);
  --bubble-shadow-out:
    0 1px 2px rgba(0, 0, 0, 0.18),
    0 4px 12px rgba(0, 0, 0, 0.14),
    0 8px 24px rgba(0, 0, 0, 0.08);

  /* Typography — white on navy by default */
  --text: #F8FAFC;
  --text-muted: #CBD5E1;
  --text-light: #94A3B8;

  /* Composer — darker navy card on the navy bg */
  --input-bg: #334155;
  --input-border: rgba(148, 163, 184, 0.18);
  --input-shadow:
    0 2px 8px rgba(0, 0, 0, 0.18),
    inset 0 0 0 1px rgba(148, 163, 184, 0.12);

  /* Send button — emerald, matching the dashboard's "+ حجز جديد" button */
  --send-btn: linear-gradient(135deg, #10B981 0%, #22C55E 100%);
  --send-btn-solid: #10B981;
  --send-btn-glow: 0 4px 16px rgba(16, 185, 129, 0.4);

  /* Read-receipt — emerald to match brand */
  --tick: #94A3B8;
  --tick-read: #10B981;

  --divider: rgba(148, 163, 184, 0.12);
  --backdrop: rgba(15, 23, 42, 0.7);
  --modal-bg: #1E293B;
  --link: #34D399;
}

@media (prefers-color-scheme: dark) {
  :root {
    /* Same palette — the dashboard scheme IS dark-mode by default */
    --app-bg: #0F172A;
    --chat-bg: #0F172A;
    --chat-pattern: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 60 60'%3E%3Ccircle cx='30' cy='30' r='1' fill='%2310B981' opacity='0.1'/%3E%3Ccircle cx='10' cy='50' r='0.8' fill='%23ffffff' opacity='0.05'/%3E%3Ccircle cx='50' cy='10' r='0.8' fill='%2322C55E' opacity='0.08'/%3E%3C/svg%3E");

    --header-bg: linear-gradient(135deg, #020617 0%, #0F172A 100%);
    --header-bg-solid: #020617;

    --bubble-in: linear-gradient(135deg, #059669 0%, #16A34A 100%);
    --bubble-in-solid: #059669;
    --bubble-in-text: #ffffff;
    --bubble-in-border: rgba(16, 185, 129, 0.3);

    --bubble-out: linear-gradient(135deg, #F1F5F9 0%, #E2E8F0 100%);
    --bubble-out-solid: #F1F5F9;
    --bubble-out-text: #0F172A;
    --bubble-out-border: rgba(255, 255, 255, 0.3);

    --bubble-shadow:
      0 1px 2px rgba(0, 0, 0, 0.4),
      0 4px 12px rgba(0, 0, 0, 0.25),
      0 8px 24px rgba(16, 185, 129, 0.12);
    --bubble-shadow-out:
      0 1px 2px rgba(0, 0, 0, 0.4),
      0 4px 12px rgba(0, 0, 0, 0.25),
      0 8px 24px rgba(0, 0, 0, 0.15);

    --text: #F8FAFC;
    --text-muted: #CBD5E1;
    --text-light: #64748B;

    --input-bg: #1E293B;
    --input-border: rgba(148, 163, 184, 0.15);
    --input-shadow:
      0 2px 8px rgba(0, 0, 0, 0.3),
      inset 0 0 0 1px rgba(148, 163, 184, 0.1);

    --send-btn: linear-gradient(135deg, #10B981 0%, #22C55E 100%);
    --send-btn-solid: #10B981;
    --send-btn-glow: 0 4px 16px rgba(16, 185, 129, 0.45);

    --divider: rgba(148, 163, 184, 0.1);
    --modal-bg: #1E293B;
    --link: #34D399;
  }
}
[data-theme="light"] {
  /* "Light" mode reverts to white card-bg with green incoming + dark outgoing.
     Kept available but the dashboard's actual scheme is dark — most users
     should see the default. */
  --app-bg: #F8FAFC;
  --chat-bg: #F8FAFC;
  --bubble-in: linear-gradient(135deg, #10B981 0%, #22C55E 100%);
  --bubble-in-solid: #10B981;
  --bubble-in-text: #ffffff;
  --bubble-out: linear-gradient(135deg, #ffffff 0%, #F1F5F9 100%);
  --bubble-out-solid: #ffffff;
  --bubble-out-text: #0F172A;
  --text: #0F172A;
  --text-muted: #475569;
  --input-bg: #ffffff;
  --modal-bg: #ffffff;
}
[data-theme="dark"] {
  --app-bg: #0F172A;
  --chat-bg: #0F172A;
  --header-bg: linear-gradient(135deg, #020617 0%, #0F172A 100%);
  --header-bg-solid: #020617;
  --bubble-in: linear-gradient(135deg, #059669 0%, #16A34A 100%);
  --bubble-in-solid: #059669;
  --bubble-in-text: #ffffff;
  --bubble-out: linear-gradient(135deg, #F1F5F9 0%, #E2E8F0 100%);
  --bubble-out-solid: #F1F5F9;
  --bubble-out-text: #0F172A;
  --text: #F8FAFC;
  --text-muted: #CBD5E1;
  --text-light: #64748B;
  --input-bg: #1E293B;
  --modal-bg: #1E293B;
}

/* ─── BOOT LOADER (visible until React mounts) ─────────────────────────── */
.boot-loader {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  height: 100vh; background: var(--app-bg); gap: 16px;
}
.boot-spinner {
  width: 36px; height: 36px; border-radius: 50%;
  border: 3px solid rgba(16, 185, 129, 0.15);
  border-top-color: #10B981;
  animation: spin 0.8s linear infinite;
}
.boot-text { color: var(--text-muted); font-size: 14px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ─── ROOT APP CONTAINER ──────────────────────────────────────────────── */
#root {
  height: 100vh; height: 100dvh;
  display: flex; flex-direction: column;
}
.app {
  height: 100%;
  display: flex; flex-direction: column;
  background: var(--chat-bg);
  background-image: var(--chat-pattern);
  position: relative;
  overflow: hidden;
}

/* ─── AMBIENT FLOATING ORBS ────────────────────────────────────────────────
   Two soft blurred gradient blobs that drift slowly behind the chat. Gives
   the interface a "living" quality without animating any actual UI element.
   ::before is the coral orb, ::after is the aubergine orb. They move on
   different cycles so the composition never repeats exactly.
   ──────────────────────────────────────────────────────────────────────── */
.app::before {
  content: "";
  position: absolute;
  top: -10%;
  right: -15%;
  width: 50vw;
  height: 50vw;
  max-width: 400px;
  max-height: 400px;
  background: radial-gradient(circle at center,
    rgba(16, 185, 129, 0.22) 0%,
    rgba(34, 197, 94, 0.10) 40%,
    transparent 70%);
  filter: blur(40px);
  pointer-events: none;
  z-index: 0;
  animation: orbDriftA 22s ease-in-out infinite;
}
.app::after {
  content: "";
  position: absolute;
  bottom: 15%;
  left: -10%;
  width: 45vw;
  height: 45vw;
  max-width: 380px;
  max-height: 380px;
  background: radial-gradient(circle at center,
    rgba(30, 41, 59, 0.18) 0%,
    rgba(15, 23, 42, 0.08) 40%,
    transparent 70%);
  filter: blur(45px);
  pointer-events: none;
  z-index: 0;
  animation: orbDriftB 28s ease-in-out infinite;
}
@keyframes orbDriftA {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(-8%, 12%) scale(1.12); }
  66%      { transform: translate(5%, 6%) scale(0.92); }
}
@keyframes orbDriftB {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(10%, -8%) scale(0.95); }
  66%      { transform: translate(-6%, 10%) scale(1.1); }
}
@media (prefers-color-scheme: dark) {
  .app::before {
    background: radial-gradient(circle at center,
      rgba(16, 185, 129, 0.14) 0%,
      rgba(34, 197, 94, 0.06) 40%,
      transparent 70%);
  }
  .app::after {
    background: radial-gradient(circle at center,
      rgba(30, 41, 59, 0.25) 0%,
      rgba(15, 23, 42, 0.12) 40%,
      transparent 70%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .app::before, .app::after { animation: none; }
}
/* The chat content needs to stay above the orbs */
.header, .messages, .composer-area, .typing-row { position: relative; z-index: 1; }

/* ─── HEADER ──────────────────────────────────────────────────────────── */
.header {
  flex-shrink: 0;
  background: var(--header-bg);
  color: var(--header-text);
  padding: 14px 16px;
  display: flex; align-items: center; gap: 12px;
  box-shadow:
    0 1px 3px rgba(15, 23, 42, 0.2),
    0 4px 16px rgba(15, 23, 42, 0.08);
  position: sticky;
  top: 0;
  z-index: 10;
  /* Backdrop-blur gives the "frosted glass app header" feel — content
     scrolling under shows through subtly, like iOS Mail / Telegram /
     iMessage. Falls back gracefully on browsers without support. */
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
}
.header-avatar {
  width: 44px; height: 44px; border-radius: 50%;
  background: linear-gradient(135deg, #10B981 0%, #22C55E 100%);
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 19px;
  font-family: 'Geist', -apple-system, sans-serif;
  color: #ffffff;
  flex-shrink: 0;
  overflow: hidden;
  box-shadow:
    0 0 0 2px rgba(16, 185, 129, 0.25),
    0 2px 8px rgba(16, 185, 129, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.2);
  letter-spacing: 0;
}
.header-avatar img { width: 100%; height: 100%; object-fit: cover; }
.header-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.header-name {
  font-weight: 700; font-size: 16px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  letter-spacing: 0.01em;
  line-height: 1.2;
}
.header-status {
  font-size: 12px;
  opacity: 0.85;
  display: flex; align-items: center; gap: 8px;
  flex-wrap: nowrap;
  overflow: hidden;
  white-space: nowrap;
}
.status-dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
  /* RTL: the dot sits to the LEFT of "clinic name · status" inline flow.
     The animated outer glow extends ~4px past the dot's box, which used
     to clip into the clinic-name text on the start side. The extra
     inline-start margin gives the glow breathing room.  */
  margin-inline-start: 4px;
}
.status-dot.online {
  background: #4ade80;
  box-shadow: 0 0 0 2px rgba(74, 222, 128, 0.25),
              0 0 8px rgba(74, 222, 128, 0.5);
  animation: statusPulse 2.4s ease-in-out infinite;
}
.status-dot.offline {
  background: #94a3b8;
  opacity: 0.6;
}
@keyframes statusPulse {
  0%, 100% { box-shadow: 0 0 0 2px rgba(74, 222, 128, 0.25), 0 0 8px rgba(74, 222, 128, 0.5); }
  50%      { box-shadow: 0 0 0 4px rgba(74, 222, 128, 0.12), 0 0 12px rgba(74, 222, 128, 0.7); }
}
.status-sep { opacity: 0.5; }
.status-label { opacity: 0.85; }
.header-actions { display: flex; gap: 4px; }
.header-btn {
  width: 38px; height: 38px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: var(--header-icon);
  font-size: 18px;
  transition: background 0.18s, transform 0.12s;
}
.header-btn:hover { background: rgba(255,255,255,0.14); }
.header-btn:active { background: rgba(255,255,255,0.22); transform: scale(0.94); }

.clinic-switcher {
  cursor: pointer;
  padding: 1px 4px;
  border-radius: 4px;
  transition: background 0.15s;
  font-weight: 500;
}
.clinic-switcher:hover { background: rgba(255,255,255,0.1); }
.clinic-switcher-arrow {
  display: inline-block; transition: transform 0.2s;
  font-size: 10px; opacity: 0.6;
}

/* ─── MESSAGES AREA ─────────────────────────────────────────────────── */
.messages {
  flex: 1;
  /* CRITICAL: min-height: 0 lets this flex item shrink below its content's
     intrinsic size. Without it, flex items default to min-height: auto
     and refuse to shrink below content height — which means a tall chat
     of messages would push the composer (and any reply-strip rendered
     above it as a sibling flex item) below the viewport. With
     min-height: 0, .messages becomes scrollable when content overflows,
     and everything below it always stays in view. May 19, 2026 fix. */
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  /* padding: 12px top/6% sides/12px bottom was too tight — the last
     bubble was kissing the composer. May 19, 2026 fix: bumped bottom
     padding to 18px (+6px) for a small but noticeable breathing room
     between Yasmin's last bubble and the input area. */
  padding: 12px 6% 18px;
  display: flex; flex-direction: column;
  -webkit-overflow-scrolling: touch;
  scroll-behavior: smooth;
  /* Disable pull-down-to-refresh (web-y feel) and stop scroll-chaining
     to the parent. App-style: scrolling the chat doesn't bounce the
     whole page. */
  overscroll-behavior: contain;
}
.messages-inner {
  display: flex; flex-direction: column; gap: 2px;
  /* Bottom-anchor: messages stack from the bottom up, like WhatsApp /
     iMessage. With 1 message, the bubble sits just above the input
     area instead of leaving a huge void between the header and the
     message. As more messages come in, they fill upward. */
  margin-top: auto;
  min-height: 0;
}

/* Day divider
   The app's default is dark mode (it activates via @media
   prefers-color-scheme OR [data-theme="dark"]). Both paths need to be
   covered, otherwise the OS-dark-mode case ended up with a light pill
   AND light text — invisible. Pill background and text color now both
   adapt to the active theme. */
.day-divider {
  /* The app's base palette is ALREADY dark (see :root at line ~60). The
     previous attempt at light/dark theme branching produced an invisible
     pill in OS-dark-mode (background became the same colour as the chat
     bg). The app is effectively dark-only, so the pill is unconditional:
     bright opaque white pill, black text. Maximum contrast against the
     navy chat background, no theme media queries to misfire. */
  align-self: center;
  background: #FFFFFF;
  color: #000000;
  font-size: 12px;
  font-weight: 600;
  padding: 5px 14px;
  border-radius: 12px;
  margin: 14px auto 10px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
  border: 1px solid rgba(255, 255, 255, 0.4);
  letter-spacing: 0.02em;
}

/* ─── MESSAGE BUBBLES ─────────────────────────────────────────────────────
   Bubblier than WhatsApp: larger radius (18px), gradient fills, layered
   shadows. Spring-in animation gives every bubble a "pop into life" feel.
   ──────────────────────────────────────────────────────────────────────── */
.msg-row {
  display: flex; max-width: 100%;
  margin-bottom: 6px;
  /* Spring-in animation. The slight overshoot (1.08 → 1.0) is what creates
     the "bouncy, alive" feel — each new message lands with character. */
  animation: bubblePop 0.42s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.msg-row.outgoing { justify-content: flex-end; }
.msg-row.incoming { justify-content: flex-start; }
.msg-row.system { justify-content: center; margin: 10px 0; }

@keyframes bubblePop {
  0%   { transform: scale(0.82) translateY(8px); opacity: 0; }
  60%  { transform: scale(1.04) translateY(0); opacity: 1; }
  100% { transform: scale(1) translateY(0); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .msg-row { animation: fadeIn 0.2s ease; }
}

.msg-bubble {
  max-width: 75%;
  padding: 10px 14px 12px 14px;
  border-radius: 20px;
  position: relative;
  word-wrap: break-word;
  overflow-wrap: break-word;
  line-height: 1.5;
  font-size: 14.5px;
  /* The "alive" element: very subtle vertical breathe on the gradient */
  background-attachment: scroll;
}

.msg-row.outgoing .msg-bubble {
  background: var(--bubble-out);
  color: var(--bubble-out-text);
  box-shadow: var(--bubble-shadow-out);
  /* Tail on the corner closest to the sender's side */
  border-top-right-radius: 6px;
  border: 1px solid var(--bubble-out-border);
}
.msg-row.incoming .msg-bubble {
  background: var(--bubble-in);
  color: var(--bubble-in-text);
  box-shadow: var(--bubble-shadow);
  border-top-left-radius: 6px;
  border: 1px solid var(--bubble-in-border);
}

/* RTL: tails flip to the inside */
[dir="rtl"] .msg-row.outgoing .msg-bubble {
  border-top-right-radius: 20px;
  border-top-left-radius: 6px;
}
[dir="rtl"] .msg-row.incoming .msg-bubble {
  border-top-left-radius: 20px;
  border-top-right-radius: 6px;
}

.msg-text { white-space: pre-wrap; }
.msg-text a { color: var(--link); text-decoration: none; word-break: break-all; font-weight: 500; }
.msg-text a:hover { text-decoration: underline; }
/* Make outgoing-bubble links readable on coral background */
.msg-row.outgoing .msg-text a { color: #ECFDF5; text-decoration: underline; }

.msg-meta {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 10.5px;
  /* Dark base color so timestamps are readable on the white outgoing
     bubble. The incoming-bubble override below uses a different dark
     value that reads correctly on the green gradient. */
  color: rgba(15, 23, 42, 0.7);
  margin-right: 4px;
  margin-left: 4px;
  margin-top: 4px;
  float: left;
  margin-bottom: -4px;
  padding-top: 1px;
  font-weight: 600;
}
/* Incoming (green) bubble: use a dark slate that contrasts the green
   gradient. Pure black would be too harsh next to the white message text;
   ~75% slate is dark enough to be readable, soft enough not to fight the
   message body for attention. */
.msg-row.incoming .msg-meta { color: rgba(15, 23, 42, 0.85); }
[dir="rtl"] .msg-meta { float: left; }

.msg-time { font-size: 10.5px; }
.msg-ticks {
  display: inline-flex; align-items: center;
  margin-right: 2px; margin-left: 2px;
}
.msg-ticks svg { width: 16px; height: 11px; }
/* Outgoing bubble in this PWA is WHITE/light (--bubble-out is #F1F5F9 →
   #E2E8F0), NOT green like classic WhatsApp. That means ticks rendered
   in white were invisible on the white bubble. Stroke a neutral slate
   so the single/double tick reads cleanly, and use the brand emerald
   for the read state. */
.msg-ticks svg path { stroke: #64748B; }              /* slate-500 — visible on white bubble */
.msg-ticks.read svg path { stroke: #53BDEB; }         /* WhatsApp blue — classic read indicator */
/* Incoming bubbles never render ticks (the JSX only renders for
   `outgoing`), so the rules below are dead weight, but kept for any
   future system-message reuse. */
.msg-row.incoming .msg-ticks svg path { stroke: var(--tick); }
.msg-row.incoming .msg-ticks.read svg path { stroke: var(--tick-read); }

/* System / informational message */
.msg-row.system .msg-bubble {
  background: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: var(--text-muted);
  font-size: 12.5px;
  padding: 6px 16px;
  border-radius: 14px;
  max-width: 85%;
  text-align: center;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.06);
  border: 1px solid rgba(15, 23, 42, 0.05);
}
[data-theme="dark"] .msg-row.system .msg-bubble {
  background: rgba(15, 23, 42, 0.7);
  border-color: rgba(255, 255, 255, 0.04);
}

/* ─── INLINE VERIFY PROMPT ─────────────────────────────────────────────
   The OTP-verify card used to be a modal overlay. Now it renders inside
   a chat bubble. The widget below is the bordered actionable block that
   sits beneath the message text — same visual language as the install
   prompt but green-accented to feel like a "do this next" step.
*/
.verify-inline {
  margin-top: 10px;
  padding: 14px;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 12px;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.verify-inline-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 14.5px;
  color: #ffffff;
  margin-bottom: 8px;
}
.verify-inline-icon {
  font-size: 18px;
  line-height: 1;
}
.verify-inline-body {
  font-size: 13.5px;
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.96);
  margin-bottom: 10px;
}
.verify-inline-code-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 8px;
  margin-bottom: 10px;
}
.verify-inline-code-label {
  font-size: 12.5px;
  color: rgba(255, 255, 255, 0.85);
}
.verify-inline-code {
  font-family: -apple-system, "Geist Mono", "SF Mono", Menlo, monospace;
  font-size: 18px;
  font-weight: 800;
  letter-spacing: 0.15em;
  color: #ffffff;
  direction: ltr;
}
.verify-inline-instructions {
  font-size: 13px;
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.92);
  margin-bottom: 12px;
}
.verify-inline-instructions strong { color: #ffffff; font-weight: 700; }
.verify-inline-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 12px 16px;
  background: #ffffff;
  color: #128C7E;
  font-size: 15px;
  font-weight: 700;
  border-radius: 10px;
  text-decoration: none;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.15);
  transition: transform 0.12s;
}
.verify-inline-btn:hover { transform: translateY(-1px); }
.verify-inline-btn:active { transform: translateY(0) scale(0.98); }
.verify-inline-footnote {
  margin-top: 10px;
  text-align: center;
  font-size: 12px;
  color: rgba(255, 255, 255, 0.78);
  line-height: 1.6;
}

/* ─── INSTALL-PROMPT WIDGET ─────────────────────────────────────────────
   Renders inline below the install-prompt message body. Position:relative
   on the wrapper so the absolute-positioned X dismiss can sit in the corner.
*/
.install-prompt-widget {
  position: relative;
  margin-top: 10px;
  padding: 14px 14px 12px 14px;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: 12px;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.install-prompt-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 12px 18px;
  background: #ffffff;
  color: #059669;
  font-size: 15px;
  font-weight: 700;
  border: none;
  border-radius: 10px;
  cursor: pointer;
  transition: transform 0.12s, box-shadow 0.2s;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12);
  font-family: inherit;
}
.install-prompt-btn:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18); }
.install-prompt-btn:active { transform: translateY(0) scale(0.98); }
.install-prompt-icon { font-size: 18px; line-height: 1; }

.install-prompt-ios-steps {
  color: #ffffff;
  font-size: 13.5px;
  line-height: 1.7;
  padding-left: 4px;
}
.install-prompt-ios-title {
  font-weight: 700;
  margin-bottom: 8px;
  color: #ffffff;
}
.install-prompt-ios-list {
  margin: 0;
  padding-right: 18px;
  list-style: arabic-indic;
}
.install-prompt-ios-list li { margin-bottom: 4px; }
.install-prompt-ios-list strong { font-weight: 700; }

.install-prompt-fallback {
  color: rgba(255, 255, 255, 0.92);
  font-size: 13.5px;
  line-height: 1.7;
}

.install-prompt-installed {
  margin-top: 10px;
  padding: 10px 14px;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 10px;
  color: #ffffff;
  font-size: 13.5px;
  font-weight: 600;
  text-align: center;
}

.install-prompt-dismiss {
  position: absolute;
  top: 6px;
  left: 6px;       /* RTL: X sits at the start (top-left of the bubble in LTR terms,
                       which in RTL reads as top-right of the visual layout) */
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  opacity: 0.85;
  transition: opacity 0.15s, background 0.15s;
}
.install-prompt-dismiss:hover {
  opacity: 1;
  background: rgba(255, 255, 255, 0.28);
}
.install-prompt-dismiss svg { width: 14px; height: 14px; }
[dir="rtl"] .install-prompt-dismiss { left: auto; right: 6px; }

/* Image in bubble */
.msg-image {
  max-width: 100%;
  max-height: 280px;
  border-radius: 6px;
  display: block;
  margin: -2px -3px 4px;
  cursor: pointer;
}

/* Voice message */
.msg-voice {
  display: flex; align-items: center; gap: 10px;
  padding: 4px 0;
  min-width: 180px;
}
.msg-voice-btn {
  width: 32px; height: 32px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,0,0,0.05);
  flex-shrink: 0;
  font-size: 14px;
}
[data-theme="dark"] .msg-voice-btn { background: rgba(255,255,255,0.1); }
.msg-voice-waveform {
  flex: 1;
  height: 24px;
  display: flex; align-items: center; gap: 2px;
}
.msg-voice-waveform div {
  width: 2px;
  background: var(--text-muted);
  border-radius: 1px;
}
.msg-voice-duration {
  font-size: 11px;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* Typing indicator */
.typing-row {
  display: flex; justify-content: flex-start;
  margin-bottom: 6px;
  animation: fadeIn 0.25s ease;
}
.typing-bubble {
  background: var(--bubble-in);
  border-radius: 20px;
  border-top-left-radius: 6px;
  padding: 12px 16px;
  display: flex; gap: 5px;
  box-shadow: var(--bubble-shadow);
  border: 1px solid var(--bubble-in-border);
}
[dir="rtl"] .typing-bubble {
  border-top-left-radius: 20px;
  border-top-right-radius: 6px;
}
.typing-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: linear-gradient(135deg, #10B981 0%, #22C55E 100%);
  animation: typingBounce 1.3s infinite ease-in-out;
  box-shadow: 0 1px 3px rgba(16, 185, 129, 0.3);
}
.typing-dot:nth-child(1) { animation-delay: 0s; }
.typing-dot:nth-child(2) { animation-delay: 0.18s; }
.typing-dot:nth-child(3) { animation-delay: 0.36s; }
@keyframes typingBounce {
  0%, 60%, 100% { transform: translateY(0) scale(0.9); opacity: 0.5; }
  30% { transform: translateY(-7px) scale(1.1); opacity: 1; }
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

/* ─── COMPOSER ────────────────────────────────────────────────────────── */
/* The composer is a defensive flex-row: input wrap on one side, action
   button on the other, always on a single line. The redundant
   `flex-direction: row` and `flex-wrap: nowrap` are stated explicitly so
   no cascade or browser quirk can flip the row into a column or wrap
   the button onto a new line. The action button has an explicit
   `flex: 0 0 48px` so it never grows or shrinks. The input wrap and the
   textarea inside it both get `min-width: 0` so they can shrink below
   their intrinsic content size (the textarea's default `cols=20` gives
   it a min-content width of ~200px otherwise, which on narrow viewports
   can push the action button off the row entirely). */
.composer {
  flex-shrink: 0;
  padding: 10px 12px 14px 12px;
  background: var(--app-bg);
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: flex-end;
  gap: 10px;
  position: relative;
}
.composer-input-wrap {
  flex: 1 1 auto;
  min-width: 0;
  background: var(--input-bg);
  border-radius: 26px;
  padding: 10px 16px;
  display: flex; align-items: center; gap: 8px;
  min-height: 46px;
  box-shadow: var(--input-shadow);
  transition: box-shadow 0.2s;
}
.composer-input-wrap:focus-within {
  box-shadow:
    0 2px 12px rgba(16, 185, 129, 0.12),
    inset 0 0 0 1.5px rgba(16, 185, 129, 0.35);
}
.composer-input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  color: var(--text);
  font-size: 15px;
  resize: none;
  max-height: 120px;
  line-height: 1.4;
  padding: 4px 0;
  font-family: inherit;
}
.composer-input::placeholder { color: var(--text-light); }
.composer-attach, .composer-emoji {
  width: 26px; height: 26px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-muted);
  font-size: 20px;
  flex-shrink: 0;
  transition: color 0.15s, transform 0.12s;
}
.composer-attach:hover, .composer-emoji:hover {
  color: #10B981;
  transform: scale(1.08);
}

.composer-action {
  flex: 0 0 48px;
  width: 48px; height: 48px; border-radius: 50%;
  background: var(--send-btn);
  color: white;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px;
  box-shadow: var(--send-btn-glow);
  transition: transform 0.12s, box-shadow 0.2s;
  /* Gentle "ready to send" breathing — barely-perceptible scale wobble.
     This is the most direct way to make the UI feel "alive". */
  animation: sendBreathe 3.5s ease-in-out infinite;
}
@keyframes sendBreathe {
  0%, 100% { transform: scale(1); box-shadow: var(--send-btn-glow); }
  50%      { transform: scale(1.04); box-shadow: 0 6px 20px rgba(16, 185, 129, 0.45); }
}
.composer-action:hover {
  transform: scale(1.06);
  box-shadow: 0 6px 24px rgba(16, 185, 129, 0.5);
}
.composer-action:active {
  transform: scale(0.92);
  animation: none;
}
.composer-action:disabled {
  opacity: 0.45;
  animation: none;
  box-shadow: none;
}
@media (prefers-reduced-motion: reduce) {
  .composer-action { animation: none; }
}

/* Recording state */
.composer.recording {
  background: linear-gradient(135deg, #ECFDF5 0%, #D1FAE5 100%);
}
[data-theme="dark"] .composer.recording {
  background: linear-gradient(135deg, #064E3B 0%, #022C22 100%);
}
.recording-indicator {
  flex: 1;
  display: flex; align-items: center; gap: 12px;
  padding: 12px;
  color: var(--text);
}
.recording-pulse {
  width: 12px; height: 12px; border-radius: 50%;
  background: #10B981;
  box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7);
  animation: recordPulse 1.2s infinite;
}
@keyframes recordPulse {
  0%   { opacity: 1; box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.6); }
  70%  { opacity: 0.6; box-shadow: 0 0 0 12px rgba(16, 185, 129, 0); }
  100% { opacity: 1; box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}
.recording-time { font-variant-numeric: tabular-nums; }
.recording-hint { color: var(--text-muted); font-size: 13px; }

/* ─── ATTACHMENT MENU ────────────────────────────────────────────────── */
.attach-menu-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.3);
  z-index: 50;
  animation: fadeIn 0.15s;
}
.attach-menu {
  position: fixed;
  bottom: 70px;
  left: 12px;
  right: 12px;
  background: var(--modal-bg);
  border-radius: 14px;
  padding: 14px;
  z-index: 51;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(70px, 1fr));
  gap: 8px;
  box-shadow: 0 4px 24px rgba(0,0,0,0.2);
  animation: slideUp 0.2s ease;
}
@keyframes slideUp {
  from { transform: translateY(20px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
.attach-item {
  display: flex; flex-direction: column;
  align-items: center; gap: 6px;
  padding: 12px 6px;
  border-radius: 10px;
  transition: background 0.15s;
}
.attach-item:hover { background: rgba(0,0,0,0.04); }
[data-theme="dark"] .attach-item:hover { background: rgba(255,255,255,0.04); }
.attach-icon {
  width: 48px; height: 48px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 22px;
  color: white;
}
.attach-icon.image    { background: linear-gradient(135deg, #10B981, #22C55E); }
.attach-icon.camera   { background: linear-gradient(135deg, #1E293B, #334155); }
.attach-icon.document { background: linear-gradient(135deg, #0F172A, #1E293B); }
.attach-item-label {
  font-size: 12px;
  color: var(--text);
}

/* ─── SWITCH CLINIC DROPDOWN ─────────────────────────────────────────── */
.clinic-dropdown-backdrop {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.3);
  z-index: 50;
  animation: fadeIn 0.15s;
}
.clinic-dropdown {
  position: fixed;
  top: 64px;
  left: 12px;
  right: 12px;
  background: var(--modal-bg);
  border-radius: 12px;
  padding: 8px 0;
  z-index: 51;
  box-shadow: 0 8px 32px rgba(0,0,0,0.2);
  animation: slideDown 0.2s ease;
  max-height: 60vh;
  overflow-y: auto;
}
@keyframes slideDown {
  from { transform: translateY(-10px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
.clinic-dropdown-header {
  padding: 12px 16px 8px;
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 500;
  letter-spacing: 0.3px;
  text-transform: uppercase;
}
.clinic-item {
  padding: 12px 16px;
  display: flex; align-items: center; gap: 12px;
  cursor: pointer;
  transition: background 0.15s;
}
.clinic-item:hover { background: rgba(15, 23, 42, 0.05); }
[data-theme="dark"] .clinic-item:hover { background: rgba(255,255,255,0.04); }
.clinic-item.active {
  background: rgba(16, 185, 129, 0.08);
}
.clinic-item-avatar {
  width: 40px; height: 40px; border-radius: 50%;
  background: linear-gradient(135deg, #10B981 0%, #22C55E 100%);
  color: white;
  display: flex; align-items: center; justify-content: center;
  font-weight: 600;
  flex-shrink: 0;
  overflow: hidden;
  box-shadow: 0 2px 6px rgba(16, 185, 129, 0.18);
}
.clinic-item-avatar img { width: 100%; height: 100%; object-fit: cover; }
.clinic-item-name { flex: 1; color: var(--text); }
.clinic-item-check { color: #10B981; font-size: 18px; }

/* ─── IMAGE PREVIEW MODAL ───────────────────────────────────────────── */
.image-modal {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.95);
  z-index: 100;
  display: flex; align-items: center; justify-content: center;
  animation: fadeIn 0.2s;
}
.image-modal img {
  max-width: 100%; max-height: 100%;
  object-fit: contain;
}
.image-modal-close {
  position: absolute;
  top: 12px; right: 12px;
  width: 40px; height: 40px;
  border-radius: 50%;
  background: rgba(0,0,0,0.5);
  color: white;
  display: flex; align-items: center; justify-content: center;
  font-size: 22px;
}

/* ─── ATTRIBUTION (very subtle) ─────────────────────────────────────── */
.powered-by {
  text-align: center;
  font-size: 10px;
  color: var(--text-light);
  opacity: 0.5;
  padding: 2px 0 4px;
  background: var(--app-bg);
  flex-shrink: 0;
}
.powered-by a { color: inherit; text-decoration: none; }

/* ─── CONNECTION STATUS BANNER ──────────────────────────────────────── */
.conn-banner {
  background: #fff3cd;
  color: #856404;
  text-align: center;
  font-size: 13px;
  padding: 6px;
  border-bottom: 1px solid #ffeaa7;
}
.conn-banner-error {
  background: #fee2e2;
  color: #991b1b;
  border-bottom: 1px solid #fecaca;
  cursor: pointer;
  font-weight: 600;
  padding: 10px 6px;
}
[data-theme="dark"] .conn-banner {
  background: #5a4a1f;
  color: #ffe082;
  border-color: #6e5a25;
}
[data-theme="dark"] .conn-banner-error {
  background: #5b1d1d;
  color: #fecaca;
  border-color: #6e2525;
}

/* ─── UPLOAD PROGRESS BAR ───────────────────────────────────────────── */
.upload-progress {
  height: 3px;
  background: rgba(0,0,0,0.06);
  position: relative;
  overflow: hidden;
}
.upload-progress-bar {
  position: absolute;
  inset: 0;
  background: var(--send-btn);
  width: 0%;
  transition: width 0.2s;
}

/* ─── INLINE LINKS IN MESSAGES ──────────────────────────────────────── */
.msg-text {
  /* word-break for very long URLs */
  overflow-wrap: anywhere;
}

/* ─── ACCESSIBILITY ─────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* iOS safe-area insets */
@supports (padding: env(safe-area-inset-bottom)) {
  /* Apply safe-area-bottom on the .composer-area wrapper rather than the
     inner .composer, so the inset sits at the very bottom of the block.
     When a reply-strip is present the strip lives above the composer
     inside .composer-area, and the safe-area space stays where it
     belongs — between the composer's bottom edge and the device's
     gesture / home-indicator area. */
  .composer-area { padding-bottom: max(0px, env(safe-area-inset-bottom)); }
  .header { padding-top: max(10px, env(safe-area-inset-top)); }
}

/* ─── VERIFICATION MODAL ────────────────────────────────────────────── */
.verify-overlay {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.85);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  animation: fadeIn 0.25s ease;
}
.verify-card {
  background: linear-gradient(135deg, #1E293B 0%, #334155 100%);
  border: 1px solid rgba(16, 185, 129, 0.2);
  border-radius: 24px;
  padding: 32px 28px;
  max-width: 420px;
  width: 100%;
  text-align: center;
  box-shadow:
    0 20px 60px rgba(0, 0, 0, 0.5),
    0 0 80px rgba(16, 185, 129, 0.08);
  animation: verifyCardIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  position: relative;
}
/* Close (X) button — top-left in RTL. Lets the patient bail out of the
   verify flow if it's stuck or they want to retry with a different
   number. Without this they were trapped. */
.verify-close {
  position: absolute;
  top: 12px;
  left: 12px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
  transition: background 0.15s, transform 0.1s, color 0.15s;
  z-index: 1;
}
.verify-close:hover {
  background: rgba(255, 255, 255, 0.15);
  color: #fff;
}
.verify-close:active {
  transform: scale(0.92);
}
.verify-close svg { width: 16px; height: 16px; }
@keyframes verifyCardIn {
  0%   { transform: scale(0.85) translateY(20px); opacity: 0; }
  60%  { transform: scale(1.03) translateY(0); opacity: 1; }
  100% { transform: scale(1) translateY(0); opacity: 1; }
}
.verify-icon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: linear-gradient(135deg, #10B981, #22C55E);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
  font-weight: 700;
  margin: 0 auto 16px;
  box-shadow: 0 8px 24px rgba(16, 185, 129, 0.35);
  animation: verifyIconPulse 2.5s ease-in-out infinite;
}
@keyframes verifyIconPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.06); box-shadow: 0 12px 32px rgba(16, 185, 129, 0.5); }
}
.verify-title {
  color: #F8FAFC;
  font-size: 20px;
  font-weight: 700;
  margin: 0 0 12px;
  line-height: 1.3;
}
.verify-body {
  color: #CBD5E1;
  font-size: 14.5px;
  line-height: 1.6;
  margin: 0 0 20px;
}
.verify-body strong {
  color: #34D399;
  font-weight: 600;
  font-family: -apple-system, "Geist Mono", monospace;
  direction: ltr;
  display: inline-block;
}
.verify-code-display {
  background: rgba(15, 23, 42, 0.6);
  border: 1.5px dashed rgba(16, 185, 129, 0.4);
  border-radius: 14px;
  padding: 16px 12px;
  margin: 0 0 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}
.verify-code-label {
  color: #94A3B8;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 600;
}
.verify-code {
  color: #34D399;
  font-size: 28px;
  font-weight: 800;
  letter-spacing: 0.15em;
  font-family: -apple-system, "Geist Mono", "SF Mono", Menlo, monospace;
  direction: ltr;
}
.verify-wa-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  background: linear-gradient(135deg, #25D366 0%, #128C7E 100%);
  color: white;
  font-size: 15.5px;
  font-weight: 700;
  padding: 14px 20px;
  border-radius: 14px;
  text-decoration: none;
  box-shadow: 0 6px 20px rgba(37, 211, 102, 0.35);
  transition: transform 0.12s, box-shadow 0.2s;
  margin-bottom: 16px;
}
.verify-instructions {
  color: #CBD5E1;
  font-size: 14px;
  line-height: 1.7;
  margin: 0 0 14px 0;
  padding: 12px 14px;
  background: rgba(37, 211, 102, 0.08);
  border: 1px solid rgba(37, 211, 102, 0.18);
  border-radius: 12px;
}
.verify-instructions strong {
  color: #34D399;
  font-weight: 700;
}
.verify-wa-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 8px 28px rgba(37, 211, 102, 0.45);
}
.verify-wa-btn:active {
  transform: translateY(0) scale(0.98);
}
.verify-status {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: #94A3B8;
  font-size: 13.5px;
  margin-bottom: 12px;
}
.verify-status-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #10B981;
  animation: verifyStatusPulse 1.4s ease-in-out infinite;
  box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4);
}
@keyframes verifyStatusPulse {
  0%   { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.5); }
  70%  { box-shadow: 0 0 0 8px rgba(16, 185, 129, 0); }
  100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}
.verify-footnote {
  color: #64748B;
  font-size: 12px;
  line-height: 1.55;
  margin: 0;
}
.verify-retry-btn {
  background: linear-gradient(135deg, #10B981, #22C55E);
  color: white;
  font-size: 15px;
  font-weight: 700;
  padding: 12px 32px;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(16, 185, 129, 0.3);
  cursor: pointer;
  transition: transform 0.12s;
}
.verify-retry-btn:active {
  transform: scale(0.96);
}

/* ═══════════════════════════════════════════════════════════════════════════
   SUGGESTED REPLY CHIPS — empty-state nudges
   ───────────────────────────────────────────────────────────────────────────
   Sit just above the composer on the empty state (Yasmin's opener visible,
   patient hasn't typed). Horizontal row, scrollable if overflow. Tap a chip
   to send that text as a patient message — chips then disappear forever
   for this session. Keeps the chat from feeling dead/empty on first open.
   ═══════════════════════════════════════════════════════════════════════════ */
.suggested-chips {
  flex-shrink: 0;
  padding: 4px 6% 8px;
  display: flex;
  gap: 8px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  position: relative;
  z-index: 1;
}
.suggested-chips::-webkit-scrollbar { display: none; }
.suggested-chip {
  flex-shrink: 0;
  padding: 9px 16px;
  background: rgba(255, 255, 255, 0.9);
  border: 1.5px solid rgba(16, 185, 129, 0.25);
  border-radius: 20px;
  color: #047857;
  font-size: 13.5px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: transform 0.12s, background 0.15s, border-color 0.15s, box-shadow 0.15s;
  white-space: nowrap;
  scroll-snap-align: start;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.06);
}
.suggested-chip:hover {
  background: #ECFDF5;
  border-color: #10B981;
  box-shadow: 0 4px 12px rgba(16, 185, 129, 0.15);
}
.suggested-chip:active {
  transform: scale(0.96);
  background: #D1FAE5;
}
/* Dark mode — applies if either (a) the app has explicitly set
   data-theme="dark" on a parent, or (b) the user's OS is set to dark mode.
   Two separate blocks because you can't comma-combine a selector with an
   at-rule in CSS. */
[data-theme="dark"] .suggested-chip {
  background: rgba(30, 41, 59, 0.85);
  border-color: rgba(16, 185, 129, 0.35);
  color: #34D399;
}
[data-theme="dark"] .suggested-chip:hover {
  background: rgba(16, 185, 129, 0.18);
}
@media (prefers-color-scheme: dark) {
  .suggested-chip {
    background: rgba(30, 41, 59, 0.85);
    border-color: rgba(16, 185, 129, 0.35);
    color: #34D399;
  }
  .suggested-chip:hover {
    background: rgba(16, 185, 129, 0.18);
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LOADING SKELETON — replaces spinner during initial chat load
   ═══════════════════════════════════════════════════════════════════════════ */
.skeleton-bubble {
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0.04) 0%,
    rgba(255, 255, 255, 0.10) 50%,
    rgba(255, 255, 255, 0.04) 100%
  );
  background-size: 200% 100%;
  animation: skeletonShimmer 1.4s ease-in-out infinite;
  border-radius: 18px;
  height: 56px;
  margin-bottom: 8px;
  max-width: 70%;
}
.skeleton-bubble:nth-child(1) { width: 55%; align-self: flex-start; }
.skeleton-bubble:nth-child(2) { width: 65%; align-self: flex-start; }
.skeleton-bubble:nth-child(3) { width: 45%; align-self: flex-end; }
@keyframes skeletonShimmer {
  0%   { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PWA standalone-mode hardening
   ───────────────────────────────────────────────────────────────────────────
   Rules below apply only when running as an installed PWA. The body gets
   `is-standalone` from the React side (see App.jsx — body-class hook on
   isStandalone). They make the installed app feel less like a webpage:

   - Chrome elements (header, composer) don't get accidentally text-selected
     when the user long-presses to interact with them.
   - The whole document doesn't allow text dragging (which highlights random
     UI in a way that breaks immersion).
   - Message bubbles KEEP user-select: text — patients need to copy clinic
     phone numbers, instructions, etc. The override is explicit.
   - Tap highlight is already transparent globally (see body rule at top)
     but we double-down here for tappable buttons on standalone, in case
     a future style change loosens the global rule.
   ═══════════════════════════════════════════════════════════════════════════ */
body.is-standalone {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
body.is-standalone .messages,
body.is-standalone .bubble,
body.is-standalone .messages-inner,
body.is-standalone textarea,
body.is-standalone input {
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}
body.is-standalone button,
body.is-standalone .chat-header,
body.is-standalone .composer-area,
body.is-standalone .composer {
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SWIPE-TO-REPLY (May 18, 2026)
   Quote header on bubbles, reply strip above the composer, swipe affordance
   icon revealed under the bubble during the drag, scroll-to-quoted flash.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Quote header inside a bubble (when msg.replyTo is set) ─────────────── */
.msg-quote {
  display: flex;
  align-items: stretch;
  gap: 8px;
  margin-bottom: 6px;
  padding: 6px 8px;
  border-radius: 6px;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.16);
  transition: background 0.15s ease;
}
.msg-quote:hover { background: rgba(255, 255, 255, 0.24); }
.msg-row.outgoing .msg-quote {
  /* On the white outgoing bubble, use a dark-tinted quote background
     so the colored side-bar still pops against the bubble. */
  background: rgba(15, 23, 42, 0.06);
}
.msg-row.outgoing .msg-quote:hover { background: rgba(15, 23, 42, 0.10); }
.msg-quote-bar {
  width: 3px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.7);
  flex-shrink: 0;
}
.msg-row.outgoing .msg-quote-bar { background: #10B981; }
.msg-quote-content {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}
.msg-quote-label {
  font-size: 11px;
  font-weight: 600;
  margin-bottom: 2px;
  opacity: 0.85;
}
.msg-quote-text {
  font-size: 12.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0.95;
  line-height: 1.4;
}

/* ── Reply affordance: icon revealed under the bubble during swipe ──────── */
.msg-row {
  position: relative;
}
.reply-affordance {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(16, 185, 129, 0.18);
  color: #10B981;
  pointer-events: none;
  z-index: 0;
  animation: replyAffordancePulse 0.3s ease-out;
}
.reply-affordance.left  { left: 8px;  }
.reply-affordance.right { right: 8px; }
[dir="rtl"] .reply-affordance.left  { left: auto; right: 8px; }
[dir="rtl"] .reply-affordance.right { right: auto; left: 8px; }
@keyframes replyAffordancePulse {
  from { opacity: 0; transform: translateY(-50%) scale(0.6); }
  to   { opacity: 1; transform: translateY(-50%) scale(1); }
}

/* Slight visual feedback on long-press hold */
.msg-bubble.pressed {
  filter: brightness(0.95);
}

/* ── Composer area + reply strip ─────────────────────────────────────────
   .composer-area is the single bottom block that contains the optional
   reply-strip on top of the always-present .composer. By wrapping these
   in one container, the parent (.app) flex column allocates ONE stable
   block of space for the whole bottom — and .composer's own flex-row
   layout (input wrap on one side, action button on the other) is fully
   isolated from whether a reply strip is active. The strip can appear
   and disappear without ever touching the composer's internal flex.

   flex-shrink: 0 on .composer-area means the bottom area never gets
   squeezed by the messages list; min-height: 0 on .messages (above)
   ensures the messages list shrinks first when space is tight. */
.composer-area {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  background: var(--app-bg);
  border-top: 1px solid var(--divider);
  position: relative;
  z-index: 1;
}
/* The composer's border-top now lives on .composer-area so the divider
   sits ABOVE the reply-strip when one is present. .composer itself no
   longer carries that border. */
.composer-area > .composer {
  border-top: none;
}

.reply-strip {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  margin: 8px 8px 0 8px;
  border-radius: 10px;
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  box-shadow: var(--input-shadow);
  animation: replyStripIn 0.18s ease-out;
}
@keyframes replyStripIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.reply-strip-bar {
  width: 3px;
  align-self: stretch;
  border-radius: 2px;
  background: #10B981;
  flex-shrink: 0;
}
.reply-strip-content {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}
.reply-strip-label {
  font-size: 11px;
  font-weight: 600;
  color: #10B981;
  margin-bottom: 2px;
}
.reply-strip-text {
  font-size: 13px;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.4;
}
.reply-strip-cancel {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: none;
  background: rgba(148, 163, 184, 0.12);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.15s ease;
}
.reply-strip-cancel:hover { background: rgba(148, 163, 184, 0.22); }
.reply-strip-cancel svg { width: 16px; height: 16px; }

/* ── Scroll-to-quoted flash highlight ───────────────────────────────────── */
/* When the user taps a quote header, the original message scrolls into view
   and gets a brief emerald glow so they know which one was being referenced. */
.msg-flash .msg-bubble {
  animation: msgFlash 1.2s ease-out;
}
@keyframes msgFlash {
  0%   { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.55); }
  30%  { box-shadow: 0 0 0 6px rgba(16, 185, 129, 0.35); }
  100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}

/* Reduce-motion users get an instant highlight, no animation */
@media (prefers-reduced-motion: reduce) {
  .reply-affordance { animation: none; }
  .reply-strip      { animation: none; }
  .msg-flash .msg-bubble { box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.45); }
}

/* ── Deleted-image placeholder (May 18, 2026) ──────────────────────────── */
/* Renders in place of an <img> when a doctor has hard-deleted the photo.
   Both the patient PWA history hydration and the live WS image_deleted
   event set msg.imageDeleted = true, which trips this branch in
   MessageBubble. Visual: a muted grey card with a trash icon + Arabic
   "deleted" text. Sized to roughly match the empty space a small image
   would occupy so the layout doesn't jump if the deletion happens while
   the chat is open. */
.msg-image-deleted {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 64px;
  padding: 16px 18px;
  margin: -2px -3px 4px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.04);
  border: 1px dashed rgba(0, 0, 0, 0.18);
  color: rgba(0, 0, 0, 0.55);
  font-size: 14px;
  /* On dark bubbles the same colors get inverted by the parent bubble's
     theme rule below (.msg-row.assistant .msg-image-deleted etc). */
}
.msg-image-deleted-icon {
  font-size: 18px;
  line-height: 1;
  opacity: 0.85;
}
.msg-image-deleted-text {
  font-weight: 500;
}

/* Dark-bubble variant: user-side bubbles are emerald, the placeholder
   should stay legible against that background. We invert the colors. */
.msg-row.user .msg-image-deleted {
  background: rgba(255, 255, 255, 0.15);
  border-color: rgba(255, 255, 255, 0.30);
  color: rgba(255, 255, 255, 0.85);
}

/* ─── PUSH NOTIFICATIONS BANNER ─────────────────────────────────────────
   Shown inside the messages list (not as a sticky overlay) so it scrolls
   with chat history — patients reading older messages don't get a banner
   sitting over their content. Tone-matched to the dark chat surface.
   Appears only after the patient has been actively using the app and
   the permission state is still "default". */

.push-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  background: rgba(74, 222, 128, 0.08);
  border: 1px solid rgba(74, 222, 128, 0.22);
  border-radius: 14px;
  padding: 12px 14px;
  margin: 10px 6% 18px;
  color: #E2E8F0;
}
.push-banner-icon {
  font-size: 22px;
  flex-shrink: 0;
  line-height: 1;
}
.push-banner-body {
  flex: 1;
  min-width: 0;
}
.push-banner-title {
  font-size: 0.95rem;
  font-weight: 600;
  margin-bottom: 2px;
  color: #F1F5F9;
}
.push-banner-sub {
  font-size: 0.78rem;
  color: #94A3B8;
  line-height: 1.45;
}
.push-banner-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}
.push-banner-enable {
  background: #4ADE80;
  color: #0F172A;
  border: none;
  border-radius: 10px;
  padding: 8px 14px;
  font-weight: 700;
  font-size: 0.85rem;
  cursor: pointer;
  font-family: inherit;
  transition: opacity 0.15s;
}
.push-banner-enable:hover { opacity: 0.9; }
.push-banner-enable:disabled { opacity: 0.55; cursor: default; }
.push-banner-dismiss {
  background: transparent;
  color: #94A3B8;
  border: none;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 6px;
}
.push-banner-dismiss:hover { color: #E2E8F0; background: rgba(255,255,255,0.05); }
