/* WA Gateway agent UI -- WhatsApp Web-style theme, layered on top of
   vendor/pico.min.css (MIT) for base form/button resets. Everything else
   (colors, layout, bubbles, avatars, call bar) is custom. No runtime CDN,
   no build step, no external assets -- the chat-pane background doodle is
   an original inline SVG data-URI, not WhatsApp's proprietary asset. */

:root {
  /* WhatsApp Web palette. */
  --wa-header-bg: #008069;       /* top bar / chat header */
  --wa-header-bg-dark: #005c4b;
  --wa-accent: #25d366;          /* unread badges, FAB-style accents */
  --wa-accent-strong: #00a884;   /* links, active/selected accents */
  --wa-app-bg: #f0f2f5;          /* app chrome background */
  --wa-panel-bg: #ffffff;        /* list rows, headers, composer bar */
  --wa-chat-bg: #efeae2;         /* chat pane (beige) */
  --wa-bubble-in: #ffffff;
  --wa-bubble-out: #d9fdd3;
  --wa-list-hover: #f5f6f6;
  --wa-list-selected: #f0f2f5;
  --wa-border: #e9edef;
  --wa-text: #111b21;
  --wa-text-secondary: #667781;
  --wa-danger: #dc2626;
  --wa-success: #25d366;
  --wa-warn: #d97706;
  --wa-tick: #8696a0;
  --wa-tick-read: #53bdeb;
  --wa-input-bg: #ffffff;       /* text inputs (composer, caption, new chat) */

  /* Pico overrides -- theme its buttons/inputs to WhatsApp green so the
     login/picker pages (which lean on Pico's own components) match without
     needing bespoke markup. */
  --pico-primary: var(--wa-header-bg);
  --pico-primary-background: var(--wa-header-bg);
  --pico-primary-hover: var(--wa-header-bg-dark);
  --pico-primary-hover-background: var(--wa-header-bg-dark);
  --pico-primary-underline: rgba(0, 128, 105, 0.5);
  --pico-primary-focus: rgba(0, 168, 132, 0.4);
  --pico-primary-inverse: #fff;

  --wa-accent-dark: var(--wa-header-bg-dark);
  --wa-panel-bg-solid: var(--wa-panel-bg);
  --wa-border-color: var(--wa-border);
}

@media (prefers-color-scheme: dark) {
  :root {
    --wa-header-bg: #202c33;
    --wa-header-bg-dark: #182229;
    --wa-accent: #00a884;
    --wa-accent-strong: #00a884;
    --wa-app-bg: #111b21;
    --wa-panel-bg: #202c33;
    --wa-chat-bg: #0b141a;
    --wa-bubble-in: #202c33;
    --wa-bubble-out: #005c4b;
    --wa-list-hover: #202c33;
    --wa-list-selected: #2a3942;
    --wa-border: #2a3942;
    --wa-text: #e9edef;
    --wa-text-secondary: #8696a0;
    --wa-tick: #8696a0;
    --wa-input-bg: #2a3942;

    --pico-primary: #00a884;
    --pico-primary-background: #00a884;
    --pico-primary-hover: #06cf9c;
    --pico-primary-hover-background: #06cf9c;
    --pico-primary-inverse: #111b21;
  }
}

* { box-sizing: border-box; }
/* The app reads better slightly larger on desktop (users zoomed to 110% by
   hand): zoom the whole UI 1.1x from 900px up. CSS zoom also scales vh
   units, so every viewport-height rule divides by --ui-zoom to still fill
   exactly one window. Phones keep 1x. */
:root { --ui-zoom: 1; }
@media (min-width: 900px) {
  :root { --ui-zoom: 1.1; }
  html { zoom: 1.1; }
}

html, body { height: 100%; }
body {
  margin: 0;
  background: var(--wa-app-bg);
  color: var(--wa-text);
  font-family: "Segoe UI", Helvetica, Arial, ui-sans-serif, system-ui, -apple-system, sans-serif;
}

.muted { color: var(--wa-text-secondary); }
.hidden { display: none !important; }

.form-error {
  color: var(--wa-danger);
  font-size: 0.85rem;
}

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

/* ---------- avatars (colored circle, no photos available) ----------
   A contact with a real display name shows its initial (console.js only
   goes this route when c.display_name is set); a bare phone number/jid
   fallback shows a generic person-silhouette icon instead, same as
   WhatsApp's own unknown-contact avatar -- never a stray leading digit. */

.avatar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: #fff;
  font-weight: 600;
  line-height: 1;
  user-select: none;
}

.avatar-list { width: 49px; height: 49px; font-size: 1.15rem; }
.avatar-chat { width: 40px; height: 40px; font-size: 1rem; }

.avatar-icon-mode.avatar-list .avatar-icon { width: 60%; height: 60%; }
.avatar-icon-mode.avatar-chat .avatar-icon { width: 58%; height: 58%; }
.avatar-icon { fill: #fff; }

/* ---------- shared top bar (picker + console) ---------- */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 16px;
  background: var(--wa-header-bg);
  color: #fff;
}

.topbar h1 {
  font-size: 1.05rem;
  margin: 0;
  color: #fff;
  font-weight: 600;
}

.topbar-left, .topbar-right {
  display: flex;
  align-items: center;
  gap: 10px;
}

.back-link {
  text-decoration: none;
  font-size: 1.1rem;
  color: #fff;
}

.topbar #device-label, .topbar .muted {
  color: rgba(255, 255, 255, 0.75);
}

.topbar button {
  width: auto;
  padding: 6px 12px;
  font-size: 0.8rem;
  margin: 0;
}

.topbar button#logout-btn, .topbar button.secondary.outline {
  --pico-secondary: #fff;
  --pico-secondary-background: transparent;
  --pico-secondary-border: rgba(255, 255, 255, 0.55);
  --pico-secondary-hover: #fff;
  --pico-secondary-hover-background: rgba(255, 255, 255, 0.15);
  --pico-secondary-hover-border: #fff;
  color: #fff;
}

.status-chip {
  font-size: 0.72rem;
  padding: 3px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.2);
  color: #fff;
  white-space: nowrap;
}

.status-chip.status-ready { background: var(--wa-success); color: #06301f; }
.status-chip.status-offline { background: var(--wa-danger); color: #fff; }
.status-chip.status-unknown { background: rgba(255, 255, 255, 0.2); color: #fff; }
.status-chip.status-warn { background: var(--wa-warn); color: #fff; }

/* Picker device cards use the same status-chip component but sit on a
   light card, not the green bar -- keep those readable. */
.device-card .status-chip.status-unknown { background: var(--wa-text-secondary); }

/* ---------- login ---------- */

.auth-body {
  display: flex;
  min-height: calc(100vh / var(--ui-zoom));
  background: var(--wa-app-bg);
}

.auth-shell {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.auth-card {
  width: 100%;
  max-width: 360px;
  background: var(--wa-panel-bg);
  padding: 28px 24px;
  border-radius: 10px;
  box-shadow: 0 2px 12px rgba(11, 20, 26, 0.08);
}

.auth-brand {
  text-align: center;
  margin-bottom: 1rem;
}

.auth-logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--wa-header-bg);
  color: #fff;
  font-weight: 700;
  margin-bottom: 10px;
}

.auth-brand h1 {
  font-size: 1.25rem;
  margin: 0 0 4px;
  color: var(--wa-text);
}

.auth-cert-help {
  margin-top: 1.25rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--wa-border);
  text-align: center;
}

.auth-cert-help p {
  font-size: 0.78rem;
  margin: 0 0 4px;
}

.auth-cert-help p:last-child {
  margin-bottom: 0;
}

/* ---------- picker ---------- */

.picker-body { background: var(--wa-app-bg); min-height: calc(100vh / var(--ui-zoom)); min-height: calc(100dvh / var(--ui-zoom)); }

.picker-shell {
  max-width: 900px;
  margin: 0 auto;
  padding: 24px 16px 48px;
}

.device-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
  margin-top: 16px;
}

.device-card {
  display: block;
  padding: 16px;
  border-radius: 10px;
  border: 1px solid var(--wa-border);
  background: var(--wa-panel-bg);
  text-decoration: none;
  color: inherit;
  position: relative;
  transition: border-color 0.15s, transform 0.1s, box-shadow 0.15s;
}

.device-card:hover {
  border-color: var(--wa-accent-strong);
  box-shadow: 0 2px 10px rgba(11, 20, 26, 0.08);
  transform: translateY(-1px);
}

.device-card-title {
  font-weight: 700;
  margin-bottom: 4px;
  color: var(--wa-text);
}

.device-card-id, .device-card-number {
  font-size: 0.8rem;
}

.device-card .status-chip {
  position: absolute;
  top: 14px;
  right: 14px;
}

/* ---------- console: two-pane layout ---------- */

.console-body {
  display: flex;
  flex-direction: column;
  height: calc(100vh / var(--ui-zoom));      /* fallback for browsers without dvh */
  height: calc(100dvh / var(--ui-zoom));     /* dynamic viewport: excludes the mobile address bar so
                         the composer/footer stays pinned to the visible bottom
                         instead of being pushed below the fold */
  background: var(--wa-app-bg);
}

.console-layout {
  display: grid;
  grid-template-columns: 320px 1fr;
  flex: 1;
  min-height: 0;
  /* .console-layout is a <main>, which pico.min.css gives block padding --
     that opened a grey gap between the top bar and the panes and a strip
     below the composer. The panes should sit flush like WhatsApp Web. */
  padding: 0;
}

.conversation-list-pane {
  background: var(--wa-panel-bg);
  border-right: 1px solid var(--wa-border);
  /* .conversation-list-pane is a <nav>, and pico.min.css sets
     nav{display:flex;flex-direction:row} -- which laid the list-header and
     the conversation-list side by side. Force a vertical column and let the
     inner .conversation-list be the only scroller so the header/compose bar
     stay pinned at the top. */
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-height: 0;
  width: 100%;
}

/* The plain div console.js appends rows into (#conversation-list) --
   explicit block+100% so it always spans the full pane width regardless of
   ancestor layout mode (grid at desktop, flex at mobile), which is what
   every row's own width:100% is a percentage OF. */
.conversation-list {
  display: block;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

/* New-chat-by-number affordance: a compact header above the conversation
   list with a compose button, plus an inline number-entry form toggled by
   console.js (wireNewChat). flex-shrink:0 so they never eat into the
   scrollable list height. */
.list-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 13px;
  background: var(--wa-panel-bg);
  border-bottom: 1px solid var(--wa-border);
  flex-shrink: 0;
}
.btn-new-chat {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  flex-shrink: 0;
  border: none;
  cursor: pointer;
  background: var(--wa-header-bg);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  margin: 0;
}
.btn-new-chat:hover { background: var(--wa-header-bg-dark); }
.btn-new-chat svg { width: 20px; height: 20px; fill: currentColor; }
.new-chat-form {
  display: flex;
  gap: 8px;
  align-items: center;
  padding: 10px 13px;
  background: var(--wa-panel-bg);
  border-bottom: 1px solid var(--wa-border);
  flex-shrink: 0;
}
.new-chat-input {
  flex: 1;
  min-width: 0;
  margin: 0;
  height: 38px;
  border-radius: 19px;
  border: none;
  background: var(--wa-input-bg);
  padding: 0 14px;
  font-size: 0.9rem;
  color: var(--wa-text);
  box-shadow: inset 0 0 0 1px var(--wa-border);
}
.new-chat-input:focus { outline: 2px solid var(--wa-accent-strong); outline-offset: -1px; box-shadow: none; }
/* class-scoped (0,2,0) so these outrank pico button[type=submit] width:100%
   (0,1,1) -- same fix pattern as the composer Send button. */
.new-chat-form .new-chat-start,
.new-chat-form .new-chat-cancel {
  margin: 0;
  height: 38px;
  padding: 0 14px;
  border-radius: 19px;
  border: none;
  cursor: pointer;
  font-size: 0.85rem;
  width: auto;
  flex-shrink: 0;
}
.new-chat-form .new-chat-start { background: var(--wa-header-bg); color: #fff; }
.new-chat-form .new-chat-start:hover { background: var(--wa-header-bg-dark); }
.new-chat-form .new-chat-cancel { background: transparent; color: var(--wa-text-secondary); box-shadow: inset 0 0 0 1px var(--wa-border); }
.new-chat-error { padding: 6px 13px 10px; font-size: 0.78rem; color: var(--wa-danger); }

.conversation-empty {
  padding: 16px;
  font-size: 0.85rem;
}

/* Row is 49px avatar + 13px gap + 13px left/right padding = a 75px inset
   for the divider (::after below), matching WhatsApp Web's own list rows:
   avatar left, a flexible two-line block (name+time / snippet+badge) right,
   ~72px comfortable row height, divider indented to start after the
   avatar rather than running full-width. Explicit box-sizing/max-width
   guard against a stray UA/vendor button default shrinking it to
   content-width, which would also cut the ::after divider short (it's
   position:absolute relative to this box). */
.conversation-row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 13px;
  box-sizing: border-box;
  width: 100%;
  max-width: 100%;
  min-height: 72px;
  text-align: left;
  padding: 12px 13px;
  margin: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  border-radius: 0;
  font-size: 0.85rem;
  color: inherit;
}

.conversation-row::after {
  content: "";
  position: absolute;
  left: 75px; /* 13px padding + 49px avatar + 13px gap */
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--wa-border);
}

.conversation-row:hover { background: var(--wa-list-hover); }
.conversation-row.active { background: var(--wa-list-selected); }

.conversation-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
}

.conversation-row-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}

.conversation-name {
  font-size: 15px;
  font-weight: 600;
  color: var(--wa-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.conversation-time {
  font-size: 12px;
  color: var(--wa-text-secondary);
  flex-shrink: 0;
}

.conversation-row-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}

.conversation-snippet {
  font-size: 14px;
  color: var(--wa-text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.conversation-snippet-empty {
  font-style: italic;
}

.conversation-snippet.snippet-call { display: inline-flex; align-items: center; gap: 5px; }
.conversation-snippet.snippet-call.missed { color: var(--wa-danger); }
.snippet-call-icon {
  display: inline-block;
  width: 13px; height: 13px;
  flex-shrink: 0;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M6.6%2010.8c1.4%202.8%203.8%205.2%206.6%206.6l2.2-2.2c.3-.3.7-.4%201-.2%201.1.4%202.3.6%203.6.6.6%200%201%20.4%201%201V20c0%20.6-.4%201-1%201C10.6%2021%203%2013.4%203%204c0-.6.4-1%201-1h3.5c.6%200%201%20.4%201%201%200%201.2.2%202.4.6%203.6.1.3%200%20.7-.2%201l-2.3%202.2z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M6.6%2010.8c1.4%202.8%203.8%205.2%206.6%206.6l2.2-2.2c.3-.3.7-.4%201-.2%201.1.4%202.3.6%203.6.6.6%200%201%20.4%201%201V20c0%20.6-.4%201-1%201C10.6%2021%203%2013.4%203%204c0-.6.4-1%201-1h3.5c.6%200%201%20.4%201%201%200%201.2.2%202.4.6%203.6.1.3%200%20.7-.2%201l-2.3%202.2z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.unread-badge {
  flex-shrink: 0;
  background: var(--wa-accent);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  border-radius: 999px;
  padding: 4px 7px;
  min-width: 20px;
  text-align: center;
}

.chat-pane {
  display: flex;
  flex-direction: column;
  min-height: 0;
  /* a <section>: pico adds a bottom margin that left a strip under the composer */
  margin: 0;
}

.chat-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--wa-app-bg);
}

.chat-active {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  /* Positioning context for the contact-info overlay (position: absolute). */
  position: relative;
}

.chat-header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  border-bottom: 1px solid var(--wa-border);
  background: var(--wa-panel-bg);
}

.chat-header-info {
  flex: 1;
  min-width: 0;
  /* It's a <button> now (opens the contact-info panel) -- reset the native
     button chrome so it still reads as the plain name/subtitle stack. */
  appearance: none;
  background: transparent;
  border: none;
  margin: 0;
  padding: 0;
  text-align: left;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.chat-avatar[role="button"], #chat-avatar[role="button"] { cursor: pointer; }

/* Contact info: the one place the lead's number is shown. A light overlay
   anchored over the thread, dismissed with its close button. */
.contact-info-panel {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 16px;
  background: rgba(0, 0, 0, 0.25);
}
.contact-info-card {
  width: 100%;
  max-width: 360px;
  margin-top: 8px;
  background: var(--wa-panel-bg);
  border: 1px solid var(--wa-border);
  border-radius: 10px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.28);
  padding: 14px 16px 16px;
}
.contact-info-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.contact-info-name {
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--wa-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.contact-info-close {
  width: auto;
  margin: 0;
  padding: 2px 6px;
  background: transparent;
  border: none;
  color: var(--wa-text-secondary);
  font-size: 1rem;
  cursor: pointer;
}
.contact-info-rows {
  margin: 12px 0 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 6px 16px;
}
.contact-info-rows dt { color: var(--wa-text-secondary); font-size: 0.8rem; }
.contact-info-rows dd {
  margin: 0;
  color: var(--wa-text);
  font-size: 0.9rem;
  word-break: break-all;
}

.conversation-back {
  display: none;
  width: auto;
  margin: 0;
  padding: 4px 8px 4px 0;
  background: transparent;
  color: inherit;
  border: none;
  font-size: 1.2rem;
}

.chat-title {
  font-weight: 600;
  color: var(--wa-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chat-subtitle { font-size: 0.78rem; }

.btn-call {
  height: 40px;
  width: 40px;
  border-radius: 50%;
  margin: 0;
  padding: 0;
  background: transparent;
  color: var(--wa-accent-strong);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  cursor: pointer;
}

.btn-call svg { width: 22px; height: 22px; fill: currentColor; }

.btn-call:hover { background: var(--wa-list-hover); }

/* ---------- messages pane ---------- */

.messages {
  flex: 1;
  overflow-y: auto;
  padding: 16px clamp(12px, 5%, 64px);   /* full-width thread like WhatsApp Web, small side gutter */
  display: flex;
  flex-direction: column;
  gap: 2px;
  background-color: var(--wa-chat-bg);
  /* Original, abstract low-contrast doodle pattern (dots/rings/dashes) --
     not a reproduction of WhatsApp's proprietary chat-background asset. */
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='140'%20height='140'%20viewBox='0%200%20140%20140'%3E%3Cg%20fill='none'%20stroke='%23d3ccbc'%20stroke-width='1.4'%20stroke-linecap='round'%20opacity='0.55'%3E%3Ccircle%20cx='18'%20cy='24'%20r='3'/%3E%3Ccircle%20cx='96'%20cy='14'%20r='2'/%3E%3Cpath%20d='M40%2020%20l8%208%20M52%2016%20l7%207'/%3E%3Cpath%20d='M70%2050%20q10%20-12%2020%200%20q10%2012%2020%200'/%3E%3Ccircle%20cx='118'%20cy='70'%20r='2.5'/%3E%3Cpath%20d='M10%2075%20l9%209%20M24%2072%20l6%206'/%3E%3Ccircle%20cx='58'%20cy='96'%20r='3'/%3E%3Cpath%20d='M100%20104%20q9%20-10%2018%200'/%3E%3Ccircle%20cx='30%20'%20cy='115'%20r='2'/%3E%3Cpath%20d='M120%20124%20l8%208%20M132%20120%20l6%206'/%3E%3C/g%3E%3C/svg%3E");
  background-repeat: repeat;
}

@media (prefers-color-scheme: dark) {
  .messages {
    background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='140'%20height='140'%20viewBox='0%200%20140%20140'%3E%3Cg%20fill='none'%20stroke='%23222e35'%20stroke-width='1.4'%20stroke-linecap='round'%20opacity='0.7'%3E%3Ccircle%20cx='18'%20cy='24'%20r='3'/%3E%3Ccircle%20cx='96'%20cy='14'%20r='2'/%3E%3Cpath%20d='M40%2020%20l8%208%20M52%2016%20l7%207'/%3E%3Cpath%20d='M70%2050%20q10%20-12%2020%200%20q10%2012%2020%200'/%3E%3Ccircle%20cx='118'%20cy='70'%20r='2.5'/%3E%3Cpath%20d='M10%2075%20l9%209%20M24%2072%20l6%206'/%3E%3Ccircle%20cx='58'%20cy='96'%20r='3'/%3E%3Cpath%20d='M100%20104%20q9%20-10%2018%200'/%3E%3Ccircle%20cx='30%20'%20cy='115'%20r='2'/%3E%3Cpath%20d='M120%20124%20l8%208%20M132%20120%20l6%206'/%3E%3C/g%3E%3C/svg%3E");
  }
}

.bubble {
  max-width: 65%;
  padding: 6px 9px 8px;
  border-radius: 7px;
  font-size: 0.9rem;
  line-height: 1.35;
  word-wrap: break-word;
  white-space: pre-wrap;
  box-shadow: 0 1px 0.5px rgba(11, 20, 26, 0.13);
  position: relative;
  margin: 2px 0;
}

.bubble.in {
  align-self: flex-start;
  background: var(--wa-bubble-in);
  border-top-left-radius: 0;
  margin-left: 8px;
}

.bubble.out {
  align-self: flex-end;
  background: var(--wa-bubble-out);
  border-top-right-radius: 0;
  margin-right: 8px;
}

/* Small tail on the top corner, CSS-only (no image asset). */
.bubble.in::before {
  content: "";
  position: absolute;
  top: 0;
  left: -8px;
  width: 8px;
  height: 13px;
  background: var(--wa-bubble-in);
  clip-path: polygon(100% 0, 100% 100%, 0 0);
}

.bubble.out::before {
  content: "";
  position: absolute;
  top: 0;
  right: -8px;
  width: 8px;
  height: 13px;
  background: var(--wa-bubble-out);
  clip-path: polygon(0 0, 0 100%, 100% 0);
}

.bubble-body { display: block; color: var(--wa-text); }

.bubble .meta {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 3px;
  margin-top: 2px;
  margin-left: 10px;
  float: right;
  font-size: 0.68rem;
  color: var(--wa-text-secondary);
  white-space: nowrap;
}

.bubble .tick { display: inline-flex; align-items: center; margin-left: 1px; color: var(--wa-tick); }
.bubble .tick svg { height: 11px; width: auto; fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round; }
.bubble .tick-single svg { width: 16px; }
.bubble .tick-double svg { width: 18px; }
.bubble .tick-failed { color: var(--wa-danger); }
.bubble .tick-failed svg { height: 13px; width: 13px; }
.bubble .tick-failed circle { fill: currentColor; stroke: none; }
.bubble .tick-failed path { stroke: #fff; stroke-width: 1.8; }
.bubble .tick-pending svg { height: 12px; width: 12px; }

/* Pinned to the newest message: no scroll anchoring (see setStickToBottom in console.js). */
.messages.at-bottom { overflow-anchor: none; }

/* Day separators; sticky so the current day's date stays pinned at the top while scrolling. */
.date-divider {           /* top: negative to sit above the pane's 16px padding, just under the header */
  position: sticky; top: -12px; z-index: 2;
  align-self: center; margin: 6px 0 4px; pointer-events: none;
}
.date-divider.covered { visibility: hidden; }
.date-divider span {
  display: inline-block; padding: 3px 9px; border-radius: 6px;
  background: var(--wa-panel-bg); color: var(--wa-text-secondary);
  font-size: 0.68rem; line-height: 1.2;
  box-shadow: 0 1px 0.5px rgba(11, 20, 26, 0.13);
}

.bubble.media-placeholder .bubble-body {
  font-style: italic;
  color: var(--wa-text-secondary);
}

/* ---------- call-log entries (media_type === "call") ---------- */

.call-log-row {
  display: flex;
  justify-content: center;
  margin: 6px 0;
}

.call-log-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.85);
  color: var(--wa-text-secondary);
  font-size: 0.76rem;
  box-shadow: 0 1px 0.5px rgba(11, 20, 26, 0.13);
}

@media (prefers-color-scheme: dark) {
  .call-log-pill { background: rgba(32, 44, 51, 0.85); }
}

.call-log-pill::before {
  content: "";
  display: inline-block;
  width: 14px; height: 14px;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M6.6%2010.8c1.4%202.8%203.8%205.2%206.6%206.6l2.2-2.2c.3-.3.7-.4%201-.2%201.1.4%202.3.6%203.6.6.6%200%201%20.4%201%201V20c0%20.6-.4%201-1%201C10.6%2021%203%2013.4%203%204c0-.6.4-1%201-1h3.5c.6%200%201%20.4%201%201%200%201.2.2%202.4.6%203.6.1.3%200%20.7-.2%201l-2.3%202.2z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M6.6%2010.8c1.4%202.8%203.8%205.2%206.6%206.6l2.2-2.2c.3-.3.7-.4%201-.2%201.1.4%202.3.6%203.6.6.6%200%201%20.4%201%201V20c0%20.6-.4%201-1%201C10.6%2021%203%2013.4%203%204c0-.6.4-1%201-1h3.5c.6%200%201%20.4%201%201%200%201.2.2%202.4.6%203.6.1.3%200%20.7-.2%201l-2.3%202.2z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.call-log-pill.missed {
  color: var(--wa-danger);
}

.call-log-icon {
  font-weight: 700;
}

.call-log-row[data-direction="out"] .call-log-icon::before { content: "\2197"; }
.call-log-row[data-direction="in"] .call-log-icon::before { content: "\2199"; }

/* ---------- composer ---------- */

.composer {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  border-top: 1px solid var(--wa-border);
  background: var(--wa-panel-bg);
  margin: 0;
}

.composer-input-wrap {
  flex: 1;
  min-width: 0;
}

/* #composer input (an ID-qualified selector, specificity 1,1,1) is used
   instead of plain `.composer input` (0,1,1) because vendor/pico.min.css
   ships `input:not([type=checkbox],[type=radio]){width:100%}` at the same
   0,1,1 specificity -- a tie that happened to resolve correctly by source
   order, but is fragile. Being explicitly higher-specificity here removes
   any doubt. */
#composer input {
  margin: 0;
  width: 100%;
  height: 42px;
  border-radius: 21px;
  border: none;
  background: var(--wa-input-bg);
  padding: 0 16px;
  font-size: 0.92rem;
  color: var(--wa-text);
  box-shadow: inset 0 0 0 1px var(--wa-border);
}

#composer input:focus {
  box-shadow: none;
  outline: 2px solid var(--wa-accent-strong);
  outline-offset: -1px;
}

/* #composer .btn-send (specificity 1,1,0) intentionally outranks
   vendor/pico.min.css's `button[type=submit]{width:100%}` (0,1,1) --
   .btn-send alone (0,1,0) previously LOST that fight, since the Send
   button carries type="submit" for form semantics, which stretched it to
   the full composer width and turned border-radius:50% into a giant
   flattened ellipse. flex is also pinned explicitly (flex-basis wins over
   the `width` property for a flex item's main-axis size) as a second,
   independent guard against the same class of bug. */
#composer .btn-send {
  flex: 0 0 42px;
  flex-shrink: 0;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  margin: 0;
  padding: 0;
  border: none;
  background: var(--wa-header-bg);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
}

#composer .btn-send:hover { background: var(--wa-header-bg-dark); }
.btn-send svg { width: 19px; height: 19px; fill: currentColor; flex-shrink: 0; }

.composer-error {
  padding: 0 16px 10px;
  font-size: 0.78rem;
  color: var(--wa-danger);
}

/* ---------- call bar ----------
   A prominent, always-in-flow panel that appears for DIALING /
   INCOMING_RINGING / ACTIVE and hides on IDLE / ENDED (see setCallState in
   console.js). Background/accent shifts per state so an agent can tell
   "ringing out" from "someone's calling in" from "live call" at a glance,
   without reading the status text. */

.call-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 16px;
  padding: 12px 20px;
  background: var(--wa-header-bg);
  color: #fff;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.call-bar.state-dialing {
  background: var(--wa-header-bg);
}

.call-bar.state-incoming {
  background: var(--wa-header-bg);
  animation: call-bar-pulse 1.4s ease-in-out infinite;
}

.call-bar.state-active {
  background: var(--wa-header-bg-dark);
}

@keyframes call-bar-pulse {
  0%, 100% { box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); }
  50% { box-shadow: 0 2px 16px rgba(37, 211, 102, 0.5); }
}

.call-bar-info {
  display: flex;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
  flex: 1 1 auto;
}

.call-peer {
  font-weight: 700;
  font-size: 1.05rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: #fff;
}

.call-status-text {
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.8);
  white-space: nowrap;
}

.call-timer {
  font-variant-numeric: tabular-nums;
  font-size: 0.85rem;
  font-weight: 700;
  padding: 2px 9px;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.15);
  color: #fff;
}

.incoming-banner, .in-call-controls {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* Round icon-style call-control buttons. The button's own text (still set
   by console.js for #btn-mute/#btn-speaker, e.g. "Mute"/"Unmute") stays in
   the accessibility tree (font-size: 0 hides it visually only) while a
   CSS ::before glyph shows the icon -- so no JS changes are needed for the
   icon swap, it reacts purely to the aria-pressed attribute console.js
   already toggles. */
.incoming-banner button,
.in-call-controls button {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  margin: 0;
  padding: 0;
  font-size: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.incoming-banner button::before,
.in-call-controls button::before {
  font-size: 1.3rem;
  line-height: 1;
}

.btn-answer {
  background: var(--wa-success);
  color: #06301f;
  border: none;
}
.btn-answer::before {
  content: "";
  display: inline-block;
  width: 20px; height: 20px;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M6.6%2010.8c1.4%202.8%203.8%205.2%206.6%206.6l2.2-2.2c.3-.3.7-.4%201-.2%201.1.4%202.3.6%203.6.6.6%200%201%20.4%201%201V20c0%20.6-.4%201-1%201C10.6%2021%203%2013.4%203%204c0-.6.4-1%201-1h3.5c.6%200%201%20.4%201%201%200%201.2.2%202.4.6%203.6.1.3%200%20.7-.2%201l-2.3%202.2z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M6.6%2010.8c1.4%202.8%203.8%205.2%206.6%206.6l2.2-2.2c.3-.3.7-.4%201-.2%201.1.4%202.3.6%203.6.6.6%200%201%20.4%201%201V20c0%20.6-.4%201-1%201C10.6%2021%203%2013.4%203%204c0-.6.4-1%201-1h3.5c.6%200%201%20.4%201%201%200%201.2.2%202.4.6%203.6.1.3%200%20.7-.2%201l-2.3%202.2z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.btn-reject {
  background: var(--wa-danger);
  color: #fff;
  border: none;
}
.btn-reject::before { content: "\2715"; }

/* Hang up is the one control that must always be easy to find -- it both
   cancels an outgoing call (DIALING) and ends a live one (ACTIVE). */
.btn-hangup {
  background: var(--wa-danger);
  color: #fff;
  border: none;
}
.btn-hangup::before { content: "\2715"; }

.btn-mute {
  background: rgba(255, 255, 255, 0.15);
  border: none;
  color: #fff;
}

.btn-mute::before { content: "\1F3A4"; }
.btn-mute[aria-pressed="true"] {
  background: #fff;
  color: var(--wa-header-bg-dark);
}
.btn-mute[aria-pressed="true"]::before { content: "\1F507"; }

/* Connect-audio stays a labelled pill (not a round icon button) -- it's a
   one-off fallback action, not a persistent in-call toggle. */
.in-call-controls .btn-connect-audio {   /* scoped: must beat the round 48px call buttons */
  width: auto;
  height: auto;
  white-space: nowrap;
  border-radius: 20px;
  padding: 8px 16px !important;
  font-size: 0.85rem !important;
  font-weight: 600;
  background: #fff;
  color: var(--wa-header-bg-dark);
  border: none;
}
.in-call-controls .btn-connect-audio::before { content: none; }

/* Optimistic "Ending…/Rejecting…/Canceling…" lock (see beginEnding() in
   console.js) -- visibly inert immediately on click, before the WS
   confirms the real end. */
.call-bar button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

/* ---------- phone-width responsiveness ---------- */

@media (max-width: 720px) {
  /* Single-pane mobile behavior, like WhatsApp: show the FULL-SCREEN
     conversation list OR the FULL-SCREEN open chat, never both stacked.
     Flex (not grid) here so whichever pane stays visible stretches to
     fill 100% of .console-layout's height on its own -- no row-sizing
     ambiguity from a 2-item grid with only one explicit row track (the
     previous grid-template-rows:1fr approach left the list pegged to
     roughly the top half of the screen with the empty-chat pane taking
     the rest). */
  .console-layout {
    display: flex;
    flex-direction: column;
  }

  .conversation-list-pane,
  .chat-pane {
    flex: 1;
    min-height: 0;
    width: 100%;
  }

  /* Single-pane show/hide driven by a JS-toggled class
     (.console-layout.chat-open, set/cleared in console.js's
     openConversation() and the #btn-back-to-list handler) rather than the
     CSS relational pseudo-class this replaced -- that selector silently
     drops the whole rule in browsers that don't support it (older
     Safari/Firefox/Chrome), leaving BOTH panes visible at once (each
     squeezed to half the screen by the flex:1 above) instead of erroring,
     which is exactly the "list stuck at half height" bug this fixes.

     Default (no .chat-open): no conversation open, .chat-empty's "Select
     a conversation…" is showing -- hide the chat pane entirely so the
     list alone fills the full screen. */
  .chat-pane {
    display: none;
  }

  /* .chat-open: a conversation is open -- hide the list, chat gets the
     full screen (back button returns via #btn-back-to-list). */
  .console-layout.chat-open .conversation-list-pane {
    display: none;
  }

  .console-layout.chat-open .chat-pane {
    display: flex;
  }

  .conversation-list-pane { border-right: none; }

  .messages { padding: 12px; }

  .bubble { max-width: 85%; }

  .device-grid { grid-template-columns: 1fr; }

  .conversation-back { display: inline-block; }

  .call-bar {
    padding: 10px 14px;
  }

  .call-bar-info { flex-basis: 100%; }

  .incoming-banner, .in-call-controls {
    flex-basis: 100%;
    justify-content: flex-end;
  }
}

/* Anchor a SHORT thread to the bottom (like WhatsApp) without breaking
   scroll-up: `justify-content: flex-end` on an overflow container pushes the
   overflow ABOVE the scroll origin, where it can't be scrolled to (the first
   messages became unreachable once media made threads overflow). An auto top
   margin on the first child does the same bottom-anchoring when content is
   short and collapses to 0 when it overflows, so scrolling stays normal. */
.messages > :first-child { margin-top: auto; }

/* ---------- media bubbles (spec 2026-09-28 §12) ---------- */
.bubble.has-media { padding: 4px 4px 6px; max-width: min(320px, 80%); }
/* Photos/videos fill a fixed-width bubble (as in WhatsApp) so a caption sits
   under the media, set apart from it, instead of widening the bubble past it. */
.bubble.media-image, .bubble.media-video { width: min(330px, 80%); display: flow-root; }  /* flow-root contains the floated .meta */
.bubble.media-image .media-image, .bubble.media-video .media-video { width: 100%; min-height: 120px; }
.bubble.has-media .bubble-body { display: block; padding: 7px 6px 0; }
.bubble.has-media .meta { padding: 0 6px; }
img.media-image, video.media-video {   /* element-scoped: the bubble also carries media-<kind> */
  display: block;
  max-width: 100%;
  max-height: 320px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.06);
}
img.media-image { cursor: zoom-in; object-fit: cover; }
.media-sticker { max-width: 160px; background: transparent; }
.bubble.media-sticker { background: transparent; box-shadow: none; }
.media-audio { display: block; width: 260px; max-width: 100%; }
.media-status {
  padding: 18px 20px;
  font-size: 0.82rem;
  color: var(--wa-text-secondary);
  font-style: italic;
}
.media-status-missing { color: var(--wa-danger); }

.media-doc {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  min-width: 220px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.05);
  color: inherit;
  text-decoration: none;
}
.media-doc-icon { font-size: 1.6rem; line-height: 1; }
.media-doc-info { display: flex; flex-direction: column; min-width: 0; }
.media-doc-name { font-size: 0.9rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.media-doc-meta { font-size: 0.74rem; color: var(--wa-text-secondary); }

.bubble.media-voice { padding: 6px 10px 5px 8px; min-width: 270px; }
.bubble.media-voice .meta {         /* time + ticks share the duration's row */
  position: absolute; right: 10px; bottom: 5px; float: none; margin: 0; padding: 0;
}
.voice-player { display: flex; align-items: center; gap: 12px; padding: 2px 0 0; }
.voice-play {
  width: 40px; height: 40px; flex-shrink: 0;
  margin: 0; padding: 0; border: none; border-radius: 50%;
  background: var(--wa-accent-strong); cursor: pointer; position: relative;
}
.voice-play::before {           /* play triangle */
  content: ""; position: absolute; left: 16px; top: 13px;
  border-style: solid; border-width: 7px 0 7px 11px;
  border-color: transparent transparent transparent #fff;
}
.voice-player.playing .voice-play::before {   /* pause bars */
  left: 14px; top: 13px; width: 4px; height: 14px; border: none;
  background: #fff; box-shadow: 8px 0 0 #fff;
}
.voice-mic {                    /* small mic badge, bottom-right of the play button */
  position: absolute; right: -4px; bottom: -3px;
  width: 17px; height: 17px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--wa-bubble-in); color: var(--wa-accent-strong);
}
.bubble.out .voice-mic { background: var(--wa-bubble-out); }
.voice-mic svg { width: 12px; height: 12px; fill: currentColor; }
.voice-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.voice-track { position: relative; height: 28px; cursor: pointer; }
.voice-wave {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: space-between; gap: 2px;
}
.voice-wave span {
  flex: 1; max-width: 3px; min-height: 3px; border-radius: 2px;
  background: var(--wa-tick); opacity: 0.55;
}
.voice-wave-played { clip-path: inset(0 calc(100% - var(--voice-p, 0%)) 0 0); }
.voice-wave-played span { background: var(--wa-accent-strong); opacity: 1; }
.voice-knob {
  position: absolute; top: 50%; left: var(--voice-p, 0%);
  width: 12px; height: 12px; margin: -6px 0 0 -6px; border-radius: 50%;
  background: var(--wa-accent-strong); pointer-events: none;
}
@media (prefers-color-scheme: dark) {   /* green-on-green is unreadable in dark outgoing bubbles */
  .bubble.out .voice-wave-played span, .bubble.out .voice-knob { background: var(--wa-tick-read); }
  .bubble.out .voice-mic { color: var(--wa-tick-read); }
}
.voice-time {
  font-size: 0.7rem; line-height: 1; color: var(--wa-text-secondary);
  font-variant-numeric: tabular-nums; min-height: 12px;
}

.lightbox {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.85); cursor: zoom-out;
}
.lightbox img { max-width: calc(94vw / var(--ui-zoom)); max-height: calc(94vh / var(--ui-zoom)); object-fit: contain; }

.avatar-img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }
.avatar.avatar-has-img { overflow: hidden; }

.conversation-snippet.snippet-media { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---------- composer: attach + voice (spec §12) ---------- */
#composer .btn-attach, #composer .btn-mic, #composer .btn-emoji {
  flex: 0 0 42px; width: 42px; height: 42px;
  margin: 0; padding: 0; border: none; border-radius: 50%;
  background: transparent; color: var(--wa-text-secondary);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
#composer .btn-attach:hover, #composer .btn-mic:hover, #composer .btn-emoji:hover { background: var(--wa-list-hover); }
#composer .btn-attach svg, #composer .btn-mic svg, #composer .btn-emoji svg { width: 22px; height: 22px; fill: currentColor; }
#composer .btn-mic { background: var(--wa-header-bg); color: #fff; }
#composer .btn-mic:hover { background: var(--wa-header-bg-dark); }
#composer:not(.has-text) .btn-send { display: none; }
#composer.has-text .btn-mic { display: none; }

.attach-preview, .voice-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 16px; flex-shrink: 0;
  border-top: 1px solid var(--wa-border);
  background: var(--wa-panel-bg);
}
.attach-preview.hidden, .voice-bar.hidden { display: none; }
.attach-preview.sending { opacity: 0.6; pointer-events: none; }
.attach-thumb {
  width: 48px; height: 48px; flex-shrink: 0; border-radius: 6px; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.06); font-size: 1.5rem;
}
.attach-thumb img { width: 100%; height: 100%; object-fit: cover; }
.attach-info { min-width: 0; max-width: 30%; }
.attach-name { font-size: 0.85rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attach-size { font-size: 0.72rem; color: var(--wa-text-secondary); }
.attach-preview .attach-caption {
  flex: 1; min-width: 0; margin: 0; height: 40px; border-radius: 20px; border: none;
  padding: 0 14px; background: var(--wa-input-bg); box-shadow: inset 0 0 0 1px var(--wa-border);
}
.attach-preview .attach-cancel, .voice-bar .voice-cancel {
  width: 36px; height: 36px; flex-shrink: 0; margin: 0; padding: 0;
  border: none; border-radius: 50%; background: transparent; color: var(--wa-text-secondary); cursor: pointer;
}
.attach-preview .attach-send, .voice-bar .voice-send {
  width: 42px; height: 42px; flex-shrink: 0; margin: 0; padding: 0;
  border: none; border-radius: 50%; background: var(--wa-header-bg); color: #fff;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.attach-preview .attach-send svg, .voice-bar .voice-send svg { width: 19px; height: 19px; fill: currentColor; }
.voice-bar .voice-send.hidden, .voice-bar .voice-stop.hidden,
.voice-bar .voice-preview.hidden, .voice-bar .voice-dot.hidden { display: none; }
.voice-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--wa-danger); animation: voice-blink 1s infinite; }
@keyframes voice-blink { 50% { opacity: 0.25; } }
.voice-timer { font-variant-numeric: tabular-nums; min-width: 40px; }
.voice-bar .voice-preview { flex: 1; min-width: 0; height: 36px; }
.voice-bar .voice-stop {
  margin: 0 0 0 auto; width: 42px; height: 42px; flex-shrink: 0; padding: 0;
  border: none; border-radius: 50%; background: var(--wa-danger); cursor: pointer; position: relative;
}
.voice-bar .voice-stop::before {
  content: ""; position: absolute; inset: 14px; border-radius: 2px; background: #fff;
}
#composer.hidden { display: none; }


/* ---------- console header (WhatsApp Web style: no app bar, the list pane
   carries the title, device, status and log-out) ---------- */
.list-header { padding: 12px 12px 12px 16px; min-height: 60px; gap: 8px; }
.list-brand { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.list-header-title { font-size: 1.35rem; font-weight: 700; color: var(--wa-text); }
.list-device { font-size: 0.8rem; color: var(--wa-text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.list-header-actions { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.list-header .status-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 0.7rem; padding: 2px 8px; border-radius: 999px;
  background: var(--wa-app-bg); color: var(--wa-text-secondary);
}
.list-header .status-chip::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.list-header .status-chip.status-ready { background: rgba(37, 211, 102, 0.14); color: #0a7c3e; }
.list-header .status-chip.status-offline { background: rgba(220, 38, 38, 0.12); color: var(--wa-danger); }
.list-header .status-chip.status-warn { background: rgba(217, 119, 6, 0.14); color: var(--wa-warn); }
.icon-btn {
  width: 38px; height: 38px; margin: 0; padding: 0; border: none; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--wa-text-secondary); cursor: pointer;
}
.icon-btn:hover { background: var(--wa-list-hover); color: var(--wa-text); }
.icon-btn svg { width: 22px; height: 22px; fill: currentColor; }

/* New chat: floating button at the bottom of the chat list (WhatsApp app
   style); its number form opens as a bar at the bottom, hiding the button. */
.conversation-list-pane { position: relative; }
.conversation-list { padding-bottom: 84px; }
.conversation-list-pane .btn-new-chat {
  position: absolute; right: 18px; bottom: 18px; z-index: 3;
  width: 54px; height: 54px; border-radius: 16px;
  background: var(--wa-accent-strong);
  box-shadow: 0 2px 8px rgba(11, 20, 26, 0.28);
}
.conversation-list-pane .btn-new-chat:hover { background: var(--wa-header-bg); }
.conversation-list-pane .btn-new-chat svg { width: 24px; height: 24px; }
.new-chat-form:not(.hidden) ~ .btn-new-chat { display: none; }
.conversation-list-pane .new-chat-form { border-top: 1px solid var(--wa-border); border-bottom: none; }

.conversation-back svg { width: 22px; height: 22px; fill: currentColor; display: block; }

/* Send in flight: the button is locked (see the composer submit handler). */
#composer .btn-send:disabled, #composer.sending .btn-send { opacity: 0.55; cursor: default; }

/* Failed outgoing message: retry control under the bubble text. */
.bubble .retry-btn {
  display: flex; align-items: center; gap: 4px; clear: both;
  margin: 4px 0 0; padding: 2px 0; width: auto;
  background: none; border: none; cursor: pointer;
  font-size: 0.74rem; font-weight: 600; color: var(--wa-danger);
}
.bubble .retry-btn:hover span { text-decoration: underline; }
.bubble .retry-btn:disabled { color: var(--wa-text-secondary); cursor: default; text-decoration: none; }
.bubble .retry-btn svg { width: 14px; height: 14px; fill: currentColor; }

/* New contact form (name + number), opened by the floating button. */
.conversation-list-pane .new-chat-form { flex-direction: column; align-items: stretch; gap: 8px; padding: 12px 14px 14px; }
.new-chat-title { font-weight: 600; font-size: 0.95rem; color: var(--wa-text); }
.new-chat-form .new-chat-input { width: 100%; margin: 0; }
.new-chat-actions { display: flex; justify-content: flex-end; gap: 8px; }
.new-chat-actions button { width: auto; }
.new-chat-form.checking .new-chat-input { opacity: 0.6; }

/* ---------- emoji picker (above the composer, like WhatsApp) ---------- */
#composer .btn-emoji[aria-expanded="true"] { color: var(--wa-accent-strong); }
.emoji-panel {
  display: flex; flex-direction: column; flex-shrink: 0; height: 300px;
  background: var(--wa-panel-bg); border-top: 1px solid var(--wa-border);
}
.emoji-panel.hidden { display: none; }
.emoji-tabs {
  display: flex; gap: 2px; padding: 4px 10px 0; flex-shrink: 0;
  border-bottom: 1px solid var(--wa-border); overflow-x: auto; scrollbar-width: none;
}
.emoji-tab {
  flex: 0 0 auto; width: 44px; height: 38px; margin: 0; padding: 0;
  font-size: 20px; line-height: 1; background: none; border: none; border-radius: 0;
  border-bottom: 3px solid transparent; cursor: pointer; opacity: 0.55; filter: grayscale(0.7);
  transition: none;   /* pico animates buttons; tab switches should be instant */
}
.emoji-tab:hover { opacity: 0.85; }
.emoji-tab[aria-selected="true"] { opacity: 1; filter: none; border-bottom-color: var(--wa-accent-strong); }
.emoji-cat-label { font-size: 0.75rem; color: var(--wa-text-secondary); padding: 8px 16px 2px; flex-shrink: 0; }
.emoji-grid {
  flex: 1; min-height: 0; overflow-y: auto; padding: 2px 10px 10px;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(42px, 1fr)); align-content: start;
}
.emoji-cell {
  width: auto; height: 42px; margin: 0; padding: 0;
  font-size: 26px; line-height: 42px; text-align: center;
  background: none; border: none; border-radius: 8px; cursor: pointer; transition: none;
}
.emoji-cell:hover, .emoji-cell:focus-visible { background: var(--wa-list-hover); }
.emoji-empty { grid-column: 1 / -1; padding: 24px 6px; color: var(--wa-text-secondary); font-size: 0.85rem; }
@media (max-width: 700px) { .emoji-panel { height: 250px; } .emoji-tab { width: 40px; } }

/* ---------- reactions (display only) ---------- */
.bubble.has-reactions { margin-bottom: 18px; }
.reaction-pill {
  position: absolute; bottom: -16px; z-index: 1;
  display: inline-flex; align-items: center; gap: 3px;
  padding: 1px 6px; font-size: 0.85rem; line-height: 1.45; white-space: nowrap;
  background: var(--wa-panel-bg); border: 1px solid var(--wa-border); border-radius: 12px;
  box-shadow: 0 1px 2px rgba(11, 20, 26, 0.18); cursor: default;
}
.bubble.in .reaction-pill { left: 10px; }
.bubble.out .reaction-pill { right: 10px; }
.reaction-pill .reaction-count { font-size: 0.7rem; color: var(--wa-text-secondary); }
.reaction-pill { font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Twemoji Mozilla", sans-serif; color: var(--wa-text); }

/* ---------- replies ---------- */
/* Reply action floats on the bubble's OUTER side (WhatsApp Web hover-action
   style) instead of overlapping the message text: right side for incoming,
   left side for outgoing, vertically centered on the bubble. */
.reply-action-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 28px;
  height: 28px;
  padding: 0;
  margin: 0;
  border: 1px solid var(--wa-border);
  border-radius: 50%;
  background: var(--wa-panel-bg);
  box-shadow: 0 1px 2px rgba(11, 20, 26, 0.18);
  color: var(--wa-text-secondary);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}
.bubble.in .reply-action-btn { right: -14px; }
.bubble.out .reply-action-btn { left: -14px; right: auto; }
.reply-action-btn svg { width: 16px; height: 16px; fill: currentColor; }
/* Desktop: reveal on hover. Touch: reveal on tap (console.js toggles
   .show-actions on the bubble). */
.bubble:hover .reply-action-btn,
.bubble.show-actions .reply-action-btn,
.reply-action-btn:focus-visible { opacity: 1; pointer-events: auto; }

/* ---------- quotes (replied-to message), WhatsApp style ---------- */
.quote {
  --quote-accent: #7f66ff;             /* the contact (WhatsApp's name colour) */
  display: flex; align-items: stretch; gap: 8px;
  min-height: 42px; max-width: 100%; min-width: 0;
  margin: 0 0 5px; padding: 0 0 0 9px; overflow: hidden;
  border: none; border-left: 4px solid var(--quote-accent); border-radius: 7px;
  background: rgba(11, 20, 26, 0.05);
  color: var(--wa-text); text-align: left; font-weight: 400; box-shadow: none;
  font-size: 0.82rem; line-height: 1.3; white-space: normal;
}
.quote.quote-me { --quote-accent: #06a884; }
.bubble.out .quote { background: rgba(11, 20, 26, 0.06); }
.quote-text { flex: 1; min-width: 0; padding: 5px 8px 6px 0; }
.quote-sender {
  color: var(--quote-accent); font-weight: 600; font-size: 0.8rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.quote-body {
  display: flex; align-items: center; gap: 4px; min-width: 0;
  color: var(--wa-text-secondary);
}
.quote-icon { width: 15px; height: 15px; flex-shrink: 0; fill: currentColor; }
.quote-snippet {
  overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; word-break: break-word;
}
.quote-thumb {
  width: 56px; height: 56px; flex-shrink: 0; align-self: center;
  object-fit: cover; border-radius: 0 6px 6px 0; background: rgba(11, 20, 26, 0.08);
}
.quote:has(.quote-thumb) { min-height: 56px; }
/* Pico styles anything focusable/role=button like a button -- keep quotes flat. */
.bubble .quote.reply-preview { width: auto; }
.reply-preview.jumpable { cursor: pointer; }
.reply-preview.jumpable:hover { background: rgba(11, 20, 26, 0.08); }
.reply-preview.jumpable:focus-visible { outline: 2px solid var(--wa-accent-strong); outline-offset: 1px; }
.bubble.has-media .quote.reply-preview { margin: 0 0 5px; }
@media (prefers-color-scheme: dark) {
  .quote { background: rgba(0, 0, 0, 0.18); --quote-accent: #a791ff; }
  .quote.quote-me { --quote-accent: #06cf9c; }
  .bubble.out .quote { background: rgba(0, 0, 0, 0.16); }
  .reply-preview.jumpable:hover { background: rgba(0, 0, 0, 0.26); }
}

/* "Replying to" bar above the composer: the same quote, WhatsApp style. */
.reply-preview-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 12px 0 16px; flex-shrink: 0;
  background: var(--wa-panel-bg); border-top: 1px solid var(--wa-border);
}
.reply-preview-bar.hidden { display: none; }
.reply-bar-quote { flex: 1; min-width: 0; }
.reply-bar-quote .quote { margin: 0; min-height: 52px; background: var(--wa-app-bg); }
.reply-bar-quote .quote-snippet { -webkit-line-clamp: 1; }
.reply-bar-quote .quote-thumb { width: 52px; height: 52px; }
@media (prefers-color-scheme: dark) { .reply-bar-quote .quote { background: #2a3942; } }
.reply-preview-cancel {
  width: 36px; height: 36px; flex-shrink: 0; margin: 0; padding: 0;
  border: none; border-radius: 50%; background: transparent; color: var(--wa-text-secondary);
  display: flex; align-items: center; justify-content: center; cursor: pointer; transition: none;
}
.reply-preview-cancel svg { width: 22px; height: 22px; fill: currentColor; }
.reply-preview-cancel:hover, .reply-preview-cancel:focus-visible { background: var(--wa-list-hover); color: var(--wa-text); }

/* Replies unavailable (WhatsApp updated; see registry.check_reply_support). */
.list-header .status-chip.replies-chip { background: rgba(217, 119, 6, 0.14); color: var(--wa-warn); cursor: help; }

/* Quoted strip -> jump to the original message (WhatsApp behaviour). */
@keyframes bubble-flash {
  0%, 40% { box-shadow: 0 0 0 3px var(--wa-accent-strong), 0 1px 0.5px rgba(11, 20, 26, 0.13); }
  100% { box-shadow: 0 1px 0.5px rgba(11, 20, 26, 0.13); }
}
.bubble.flash-highlight { animation: bubble-flash 1.8s ease-out; }

/* ---------- "go to latest" floating button ---------- */
.scroll-bottom-anchor { position: relative; height: 0; flex-shrink: 0; z-index: 4; }
.scroll-bottom-btn {
  position: absolute; right: 18px; bottom: 14px;
  width: 44px; height: 44px; margin: 0; padding: 0; border: none; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--wa-panel-bg); color: var(--wa-text-secondary);
  box-shadow: 0 1px 4px rgba(11, 20, 26, 0.28); cursor: pointer; transition: none;
}
.scroll-bottom-btn.hidden { display: none; }
.scroll-bottom-btn:hover { color: var(--wa-text); }
.scroll-bottom-btn svg { width: 28px; height: 28px; fill: currentColor; }
.scroll-bottom-badge {
  position: absolute; top: -7px; left: -7px;
  min-width: 21px; height: 21px; padding: 0 5px; border-radius: 11px;
  background: var(--wa-accent); color: #fff;
  font-size: 0.72rem; font-weight: 600; line-height: 21px; text-align: center;
}
.scroll-bottom-badge.hidden { display: none; }

/* ---------- send progress (above the composer) ---------- */
.send-progress {
  display: flex; align-items: center; gap: 10px; flex-shrink: 0;
  padding: 6px 16px 0; background: var(--wa-panel-bg);
  font-size: 0.74rem; color: var(--wa-text-secondary);
}
.send-progress.hidden { display: none; }
.send-progress-label { flex-shrink: 0; min-width: 9em; }
.send-progress-track {
  flex: 1; height: 4px; border-radius: 2px; overflow: hidden;
  background: var(--wa-border);
}
.send-progress-fill { height: 100%; width: 0; border-radius: 2px; background: var(--wa-accent-strong); }
.send-progress.done .send-progress-label { color: var(--wa-accent-strong); }
.send-progress.failed .send-progress-label { color: var(--wa-danger); }
.send-progress.failed .send-progress-fill { background: var(--wa-danger); }
#composer.sending .btn-mic:disabled, .attach-send:disabled, .voice-send:disabled { opacity: 0.55; cursor: default; }

/* ---------- call mode ---------- */
.call-backdrop { position: fixed; inset: 0; z-index: 900; background: rgba(11, 20, 26, 0.55); }
.call-backdrop.hidden { display: none; }
/* Ringing: the call bar becomes a centred card above the dimmed page. */
body.call-ringing .call-bar {
  position: fixed; z-index: 901; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(360px, calc(100vw - 32px));
  flex-direction: column; align-items: center; justify-content: center; text-align: center;
  gap: 22px; padding: 30px 24px 26px; border-radius: 18px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
}
body.call-ringing .call-bar-info { flex-direction: column; align-items: center; gap: 6px; flex: 0 0 auto; }
body.call-ringing .call-peer { font-size: 1.45rem; white-space: normal; }
body.call-ringing .incoming-banner { gap: 56px; }
body.call-ringing .incoming-banner button { width: 64px; height: 64px; }
body.call-ringing .incoming-banner button::before { width: 26px; height: 26px; }
/* On a call: phone actions locked, reading stays available. */
body.call-mode .reply-action-btn { display: none !important; }
body.call-mode .retry-btn { opacity: 0.45; pointer-events: none; }
body.call-mode #composer .btn-attach:disabled,
body.call-mode #composer .btn-mic:disabled,
body.call-mode .btn-new-chat:disabled,
body.call-mode .btn-call:disabled { opacity: 0.45; cursor: not-allowed; }

.acting-banner { position: sticky; top: 0; z-index: 50; display: flex; gap: 1rem; align-items: center;
  justify-content: center; padding: .4rem 1rem; background: #7a1fa2; color: #fff; }
.acting-banner button { margin: 0; padding: .2rem .8rem; width: auto; }

/* Pico's own theme block (:root:not([data-theme=dark])) is more specific than
   the :root overrides at the top of this file, so its default blue won on the
   login/picker pages. Setting the variables on <body> wins by inheritance. */
body {
  --pico-primary: var(--wa-accent-strong);
  --pico-primary-background: var(--wa-accent-strong);
  --pico-primary-border: var(--wa-accent-strong);
  --pico-primary-hover: #008f72;
  --pico-primary-hover-background: #008f72;
  --pico-primary-hover-border: #008f72;
  --pico-primary-focus: rgba(0, 168, 132, 0.25);
  --pico-primary-underline: rgba(0, 168, 132, 0.5);
  --pico-primary-inverse: #fff;
  --pico-form-element-focus-color: var(--wa-accent-strong);
}
@media (prefers-color-scheme: dark) {
  body { --pico-primary-hover: #06cf9c; --pico-primary-hover-background: #06cf9c; --pico-primary-inverse: #111b21; }
}

/* New-contact inputs: Pico's 1rem/1.25rem padding left too little room for
   the placeholder once the UI is 1.1x (it was cut off). */
.new-chat-form .new-chat-input { padding: .55rem .85rem; font-size: .95rem; height: auto; }
