/* ===== Tokens ===== */
:root {
  /* Brand */
  --bs-primary: #a6489c;
  --bs-primary-rgb: 166, 72, 156;
  --bs-secondary: #d0157d;
  --bs-secondary-rgb: 208, 21, 125;

  /* Derived brand accents */
  --app-primary-hover: color-mix(in srgb, var(--bs-primary) 80%, black);
  --app-primary-active: color-mix(in srgb, var(--bs-primary) 65%, black);
  --app-primary-subtle: rgba(var(--bs-primary-rgb), .08);
  --app-primary-subtle-strong: rgba(var(--bs-primary-rgb), .14);

  /* Chat thread. Mirrors the AppColors.chat* block in the customer app so both
     surfaces read as one product. The outgoing bubble is a pale brand tint
     rather than solid primary: on the saturated purple the read and unread
     ticks sat at the same luminance and were indistinguishable. */
  --app-chat-out-bubble: #f6e8f4;
  --app-chat-in-bubble: #ffffff;
  --app-chat-thread-bg: #faf8fa;
  --app-chat-text: #2c2530;
  /* Links inside a bubble. The dark plum rather than the brand magenta, which
     clears only 4.4:1 on the outgoing bubble's tint; this holds above 8:1 on
     both fills. Same value as the app's AppColors.chatLink. */
  --app-chat-link: #6b2a5a;
  /* The headline on a broadcast bubble. Dark enough to clear 3:1 on the
     outgoing bubble's tint; same value as the app's
     AppColors.chatBroadcastTitle. */
  --app-chat-broadcast-title: #6b2a5a;
  --app-chat-out-meta: #8a7a88;
  --app-chat-in-meta: #8a8390;
  --app-chat-divider: #9a939c;
  --app-chat-tick-sent: #b9a6b6;
  --app-chat-tick-read: var(--bs-secondary);
  --app-chat-composer-field: #f4f1f5;
  --app-chat-media-placeholder: #efe9ef;
  --app-chat-error-bg: #fdeef1;
  --app-chat-error-text: #b0455e;
  --app-chat-avatar-bg: #f1e5f0;
  --app-chat-push-off: #c2bcc6;
  --app-chat-push-on: #1eab6b;
  --app-chat-item-selected: #faf5f9;
  /* Lime, matching AppColors.chatSystemBackground/chatSystemText in the app so
     a system note reads the same on both sides of the conversation. */
  --app-chat-system-bg: #eef7d8;
  --app-chat-system-text: #5a7326;

  /* Surfaces */
  --app-body-bg: #f5f6fa;
  --app-surface: #ffffff;
  --app-surface-muted: #f8f8fb;

  /* Text */
  --app-text-muted: #6c6c7a;

  /* Borders / radius / shadow */
  --app-border-color: rgba(103, 103, 103, .14);
  --app-radius-sm: 0.5rem;
  --app-radius-md: 0.75rem;
  --app-radius-lg: 1rem;
  --app-shadow-sm: 0 1px 2px rgba(16, 16, 40, .04);
  --app-shadow-md: 0 4px 16px rgba(16, 16, 40, .06);

  --app-sidebar-width: 240px;
}

/* ===== Base ===== */
body {
  font-family: "Quicksand", sans-serif;
  background-color: var(--app-body-bg);
}

/* ===== Buttons ===== */
.btn-primary {
  --bs-btn-bg: var(--bs-primary);
  --bs-btn-border-color: var(--bs-primary);
  --bs-btn-hover-bg: var(--app-primary-hover);
  --bs-btn-hover-border-color: var(--app-primary-hover);
  --bs-btn-active-bg: var(--app-primary-active);
  --bs-btn-active-border-color: var(--app-primary-active);
}

/* ===== Utility overrides ===== */
.text-primary { color: var(--bs-primary) !important; }
.bg-primary { background-color: var(--bs-primary) !important; }
.border-primary { border-color: var(--bs-primary) !important; }

/* Bootstrap ships no min-width utility, and a flex item defaults to a minimum
   size of its content: without this, a long word pushes the row wider than
   its column instead of truncating inside it. */
.min-width-0 { min-width: 0; }

/* ===== App shell ===== */
.app-shell {
  min-height: 100vh;
}

.app-main {
  min-width: 0;
}

.app-content {
  padding: 1rem;
  min-height: 0;
}

/* ===== Sidebar ===== */
.app-sidebar {
  width: var(--app-sidebar-width);
  min-width: var(--app-sidebar-width);
  background: var(--app-surface);
  border-right: 1px solid var(--app-border-color);
  color: var(--app-text-muted);
  padding: 1.25rem 0.75rem;
}

.app-sidebar-brand {
  padding: 0 0.75rem 1.25rem;
  color: var(--bs-primary);
}

.app-sidebar-brand-logo {
  height: 30px;
  width: auto;
  display: block;
}

.app-sidebar-brand-text {
  font-size: 1.1rem;
  font-weight: 700;
}

.app-sidebar-brand-sub {
  color: var(--app-text-muted);
  letter-spacing: 0.08em;
  font-size: 0.7rem;
}

.app-sidebar-nav .nav-link {
  color: var(--app-text-muted);
  border-radius: 0.5rem;
  padding: 0.6rem 0.75rem;
  margin-bottom: 0.25rem;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  border-left: 3px solid transparent;
}

.app-sidebar-nav .nav-link i {
  font-size: 1.1rem;
}

.app-sidebar-nav .nav-link:hover {
  background: var(--app-primary-subtle);
  color: var(--bs-primary);
}

.app-sidebar-nav .nav-link.active {
  background: var(--app-primary-subtle-strong);
  color: var(--bs-primary);
  font-weight: 600;
  border-left-color: var(--bs-primary);
}

/* ===== Navbar ===== */
.app-navbar {
  background: var(--app-surface);
  border-bottom: 1px solid var(--app-border-color);
  min-height: 56px;
}

.app-sidebar-toggle {
  border: 1px solid var(--app-border-color);
}

/* ===== Footer ===== */
.app-footer {
  border-top: 1px solid var(--app-border-color);
  background: var(--app-surface);
}

/* ===== Cards / surfaces ===== */
.card {
  border-color: var(--app-border-color);
  border-radius: var(--app-radius-lg);
  box-shadow: var(--app-shadow-sm);
}

.modal-content {
  border-radius: var(--app-radius-lg);
  box-shadow: var(--app-shadow-md);
}

/* ===== Tables ===== */
.table {
  --bs-table-border-color: var(--app-border-color);
  margin-bottom: 0;
}

.table > thead {
  background-color: var(--app-surface-muted);
}

.table > thead > tr > th {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--app-text-muted);
  font-weight: 600;
  border-bottom: 1px solid var(--app-border-color);
  padding: .75rem 1rem;
}

.table > tbody > tr > td {
  padding: .75rem 1rem;
  vertical-align: middle;
}

.table > tbody > tr:hover {
  background-color: var(--app-surface-muted);
}

/* ===== Chat: rooms list ===== */
.chat-screen { height: calc(100vh - 56px - 41px - 2rem); }

/* Transparent left border on every item so selection doesn't shift the text. */
.chat-item {
  border-left: 3px solid transparent;
  cursor: pointer;
}

.chat-item:hover { background-color: var(--app-surface-muted); }

.chat-item.selected {
  background-color: var(--app-chat-item-selected);
  border-left-color: var(--bs-primary);
}

.chat-item__avatar {
  width: 38px;
  height: 38px;
  flex: none;
  border-radius: 50%;
  background: var(--app-chat-avatar-bg);
  color: var(--bs-primary);
  font-size: 0.84rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

.chat-item.selected .chat-item__avatar,
.chat-avatar--solid {
  background: var(--bs-primary);
  color: #fff;
}

/* Header avatar: same circle, one size up. */
.chat-avatar--lg {
  width: 44px;
  height: 44px;
  font-size: 0.94rem;
}

.chat-item__name { font-size: 0.9rem; font-weight: 700; color: var(--app-chat-text); }
.chat-item__time { font-size: 0.72rem; font-weight: 600; color: var(--app-text-muted); flex: none; }
.chat-item.selected .chat-item__time { color: var(--bs-primary); }
.chat-item__preview {
  font-size: 0.81rem;
  color: var(--app-text-muted);
  /* Two lines, then an ellipsis. The tick rides along inside the box so it
     wraps with the text rather than pinning the first line open. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  /* A single unbroken run (a pasted URL) has no break opportunity of its own
     and would otherwise overflow the clamp. */
  overflow-wrap: anywhere;
}

.chat-item__preview .chat-tick { vertical-align: -0.1em; }

/* ===== Chat: thread ===== */
.chat-thread {
  background: var(--app-chat-thread-bg);
}

/* The mock centres the conversation rather than letting bubbles stretch to the
   full width of a desktop console. */
.chat-thread__column {
  max-width: 820px;
  margin: 0 auto;
  width: 100%;
}

.chat-day-divider {
  text-align: center;
  font-size: 0.69rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--app-chat-divider);
  padding: 0.5rem 0;
}

.chat-bubble {
  max-width: 70%;
  width: fit-content;
  padding: 10px 14px 8px;
  color: var(--app-chat-text);
  word-wrap: break-word;
  overflow-wrap: anywhere;
}

/* Outgoing: this agent's own reply. */
.chat-bubble--out {
  background: var(--app-chat-out-bubble);
  border-radius: 16px 16px 5px 16px;
  margin-left: auto;
}

/* Incoming: the customer. White needs the shadow to separate from the
   near-white thread; the tinted outgoing bubble separates on its own. */
.chat-bubble--in {
  background: var(--app-chat-in-bubble);
  border-radius: 16px 16px 16px 5px;
  box-shadow: 0 1px 2px rgba(44, 37, 48, 0.07);
}

/* The message body. Firestore stores it with the line breaks whoever wrote it
   typed — order confirmations in particular are several short lines — and HTML
   would collapse every one of them into a single run. pre-wrap keeps the
   breaks while still wrapping long lines, and the body is trimmed before it is
   rendered so trailing blank lines cannot pad the bubble. */
.chat-bubble__text {
  white-space: pre-wrap;
}

/* A `senderType: system` note, carrying the app's ChatSystemNote colours but
   the panel's own alignment: it sits right, with the outgoing bubbles, because
   here the thread is read from support's side and everything the customer did
   not write belongs on that edge. Held to the bubbles' 70% rather than the
   app's full width, which is only narrow because the app draws it in a
   phone-width column. No meta row, matching the app — a note has no delivery
   state to report. Font size is inherited so it sets the same as the bubbles
   around it; the weight is what marks it as a notice. Rounded rather than a
   capsule for the reason the app gives — the welcome greeting is several
   paragraphs tall, and a pill radius on a block that tall reads as a rendering
   bug. */
.chat-system-note {
  max-width: 70%;
  width: fit-content;
  margin: 8px 0 8px auto;
  padding: 12px 14px;
  border-radius: 16px;
  background: var(--app-chat-system-bg);
  color: var(--app-chat-system-text);
  font-weight: 500;
  line-height: 1.45;
}

/* Pre-wrap belongs to the words, not to the note: the note now also holds a
   meta row, and markup indentation inside a pre-wrap block renders literally. */
.chat-system-note__text {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* The bubbles' mauve meta reads as dirt on the lime, so the timestamp stays in
   the note's own olive family. .chat-tick sets its own colour, which is what
   keeps a note's receipt the same mark as an outgoing bubble's. */
.chat-system-note .chat-meta { color: color-mix(in srgb, var(--app-chat-system-text) 70%, transparent); }

/* The plum link colour has too little contrast on lime; the note's own text
   colour keeps the underline doing the work of saying "link". */
.chat-system-note .chat-link,
.chat-system-note .chat-link:hover,
.chat-system-note .chat-link:focus { color: inherit; }

/* The headline a broadcast carries and a support reply does not. Sits above
   the body text, which keeps its own colour and weight. */
.chat-bubble__title {
  color: var(--app-chat-broadcast-title);
  font-weight: 700;
  line-height: 1.3;
  margin-bottom: 2px;
}

.chat-meta { font-size: 0.72rem; }
.chat-bubble--out .chat-meta { color: var(--app-chat-out-meta); }
.chat-bubble--in .chat-meta { color: var(--app-chat-in-meta); }

/* A URL an agent or a customer pasted. Underlined as well as coloured: colour
   alone is not an accessible way to say "this is a link", and both bubble fills
   are light enough that the plum reads as ordinary emphasis without it. The
   bubble already wraps on `overflow-wrap: anywhere`, which is what keeps a long
   query string from pushing the bubble past its 70%. */
.chat-link {
  color: var(--app-chat-link);
  text-decoration: underline;
}

.chat-link:hover,
.chat-link:focus {
  color: var(--app-chat-link);
  text-decoration-thickness: 2px;
}

/* ===== Chat: attachments ===== */

/* A media bubble is mostly image, so it shrinks to a frame around one rather
   than keeping the text bubble's breathing room. */
.chat-bubble--media { padding: 4px 4px 6px; }

/* Insets the caption and meta row back to the text bubble's rhythm, since the
   bubble's own padding is now the image's frame. */
.chat-bubble--media .chat-bubble__caption,
.chat-bubble--media .chat-meta { padding: 0 5px; }
.chat-bubble--media .chat-bubble__caption { padding-top: 6px; }

/* With an image above it the headline carries the caption's top inset, so the
   gap it would otherwise open under itself is not needed. */
.chat-bubble--media .chat-bubble__title {
  padding: 6px 5px 0;
  margin-bottom: 0;
}

.chat-media {
  position: relative;
  overflow: hidden;
  border-radius: 13px;
  /* Held by the inline width/height the renderer derives from the stored
     dimensions, so the tile occupies its final size before the image loads and
     the thread does not jump as an agent scrolls. */
  background: var(--app-chat-media-placeholder);
  cursor: zoom-in;
  max-width: 100%;
}

.chat-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* A video tile draws its poster frame like any other still; these two marks are
   the only thing telling an agent it is a video rather than a photo. Shadowed
   rather than sat on a scrim: a poster frame is often bright in the middle, and
   this has to stay legible without dimming the frame it describes. */
.chat-media__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  color: #fff;
  font-size: 2.75rem;
  line-height: 1;
  filter: drop-shadow(0 1px 6px rgb(0 0 0 / 55%));
}

.chat-media__duration {
  position: absolute;
  left: 8px;
  bottom: 8px;
  padding: 1px 6px;
  border-radius: 6px;
  background: rgb(0 0 0 / 45%);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.4;
  pointer-events: none;
}

/* ===== Chat: lightbox ===== */
.chat-lightbox__content {
  background: transparent;
  border: 0;
  align-items: center;
}

.chat-lightbox__image {
  max-width: 100%;
  /* Leaves room for the modal's own margins, so a tall screenshot scales to fit
     rather than scrolling the page behind the backdrop. */
  max-height: 85vh;
  object-fit: contain;
  border-radius: var(--app-radius-md);
}

.chat-lightbox__close {
  position: absolute;
  top: -2.25rem;
  right: 0;
  filter: invert(1) grayscale(1) brightness(2);
  opacity: 0.9;
}

/* ===== Chat: composer ===== */

.chat-tray {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding-bottom: 0.75rem;
}

.chat-tray__item {
  position: relative;
  width: 62px;
  height: 62px;
  flex: none;
  border-radius: 11px;
  overflow: hidden;
  background: var(--app-chat-media-placeholder);
}

.chat-tray__item img,
.chat-tray__item video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* The tray tile is 62px, so the thread's 2.75rem glyph would fill it entirely. */
.chat-tray__item .chat-media__play {
  font-size: 1.5rem;
}

.chat-tray__remove {
  position: absolute;
  top: 3px;
  right: 3px;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(44, 37, 48, 0.66);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8rem;
  line-height: 1;
}

.chat-tray__hint {
  font-size: 0.78rem;
  color: var(--app-text-muted);
  line-height: 1.5;
}

.chat-tray__error {
  font-size: 0.78rem;
  color: var(--app-chat-error-text);
  background: var(--app-chat-error-bg);
  border-radius: var(--app-radius-sm);
  padding: 0.55rem 0.75rem;
  width: 100%;
}

.chat-composer__attach {
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: 11px;
  background: var(--app-primary-subtle);
  color: var(--bs-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  font-size: 1.25rem;
}

.chat-composer__attach:hover { background: var(--app-primary-subtle-strong); }

.chat-composer__field {
  border-radius: 999px;
  background: var(--app-chat-composer-field);
  border: 0;
  padding: 0.75rem 1.15rem;
}

.chat-composer__field:focus {
  background: var(--app-chat-composer-field);
  box-shadow: 0 0 0 3px var(--app-primary-subtle);
}

.chat-composer__send {
  width: 44px;
  height: 44px;
  flex: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

/* ===== Chat: push notification status ===== */
.chat-push {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--app-text-muted);
}

/* Grey by default, green only when the customer has a live device token —
   the dot carries the state, the label repeats it for anyone who cannot
   distinguish the two colours. */
.chat-push__dot {
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: 50%;
  background: var(--app-chat-push-off);
}

.chat-push--on .chat-push__dot {
  background: var(--app-chat-push-on);
}

.chat-push__platform {
  font-size: 0.95rem;
  vertical-align: -2px;
}

/* The badge for a guest who has identified themselves by ordering. Its own
   rule rather than .bg-primary-subtle because the theme overrides --bs-primary
   without touching Bootstrap's derived --bs-primary-bg-subtle, so that utility
   would paint the pill Bootstrap blue. */
.chat-status--identified {
  background: var(--app-primary-subtle-strong);
  color: var(--bs-primary);
}

/* ===== Chat: customer identity pills =====
   The row under the customer's name in the conversation header. Deliberately
   monochrome: the only colour in the row belongs to the status badge beside
   them, so an agent's eye lands on guest-vs-registered rather than on four
   equally loud chips. */
.chat-fact {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
  max-width: 100%;
  padding: 0.15rem 0.55rem;
  border: 1px solid var(--app-border-color);
  border-radius: 999px;
  background: var(--app-surface-muted);
  color: var(--app-text-muted);
  font-size: 0.75rem;
  font-weight: 600;
}

.chat-fact i {
  flex: none;
  font-size: 0.9rem;
}

/* A long email must lose its own tail rather than push the order count off the
   row — the count is the fact an agent scans for. */
.chat-fact span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ===== Chat delivery ticks ===== */
.chat-tick {
  font-size: 0.95rem;
  vertical-align: -2px;
  margin-left: 2px;
  color: var(--app-chat-tick-sent);
}

/* renderMessages replaces the whole list's innerHTML, so a CSS transition
   never sees an old value to animate from — the read tick fades itself in on
   mount instead. Since every tick remounts on every rebuild, the fade is
   applied by chat.js only to ticks that have not played it yet. */
.chat-tick--read {
  color: var(--app-chat-tick-read);
}

.chat-tick--read-in {
  animation: chat-tick-in 0.2s ease-in;
}

@keyframes chat-tick-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .chat-tick--read-in { animation: none; }
}

/* ===== Responsive ===== */
@media (max-width: 991.98px) {
  .app-sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 1040;
    transform: translateX(-100%);
    transition: transform 0.2s ease-in-out;
  }

  .app-sidebar.show {
    transform: translateX(0);
    box-shadow: var(--app-shadow-md);
  }
}
