/* chat/10_lightbox_and_readers.css
 * ------------------------------------------------------------
 * Split 10 of 10 from web/account/css/chat.css (CLAUDE.md §8.16 — see
 * 01_tokens_reset.css's header for the split's background; loaded LAST in
 * chat.html, after the toast/avatar file).
 *
 * Covers: the full-screen media lightbox (lightbox.js, lightbox_stage.js
 * — backdrop, stage, loading spinner, prev/next/close/open-in-tab chrome)
 * and the "who has read it" reader row and its overlay sheet
 * (message_readers_row.js, readers_overlay.js — the overlapping face
 * cluster under a bubble, its hover tooltip, and the full reader list
 * sheet that opens on tap/click).
 * ------------------------------------------------------------ */

/* ===== Lightbox (lightbox.js, lightbox_stage.js) ===== */

.chat-lightbox {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* Closed — nothing inside should be reachable or announced, so removing it
   from the tree entirely is correct (lightbox.js already stops trapping
   focus and restores it on the same transition). */
.chat-lightbox.is-hidden { display: none; }

.chat-lightbox__backdrop { position: absolute; inset: 0; background: var(--chat-scrim); }

.chat-lightbox__dialog {
  position: relative;
  z-index: 1;
  width: 100%; height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  outline: none; /* the dialog itself is programmatically focused (lightbox.js); its own box shows no ring, the chrome buttons below still do */
}

.chat-lightbox__stage {
  max-width: calc(100% - 32px);
  max-height: calc(100% - 32px);
  display: flex;
  align-items: center;
  justify-content: center;
}
.chat-lightbox__image, .chat-lightbox__video { max-width: 100%; max-height: 100%; object-fit: contain; }

.chat-lightbox__loading {
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 3px solid var(--chat-wash-strong);
  border-top-color: var(--chat-read-tick);
  animation: chat-spin .8s linear infinite;
}
@keyframes chat-spin { to { transform: rotate(360deg); } }

.chat-lightbox__failed { color: var(--chat-bubble-muted); font-size: 14px; }

.chat-lightbox__prev, .chat-lightbox__next, .chat-lightbox__close,
.chat-lightbox__opentab {
  position: absolute;
  z-index: 2;
  width: 40px; height: 40px;
  border-radius: 50%;
  background: var(--chat-media-overlay);
  display: flex; align-items: center; justify-content: center;
  font-size: 20px;
}
.chat-lightbox__prev:hover, .chat-lightbox__next:hover, .chat-lightbox__close:hover,
.chat-lightbox__opentab:hover {
  background: var(--chat-scrim);
}
/* A single image has no "other one" to page to — the buttons carry no
   information in that case, so hiding them from the tree (not just
   visually) is correct rather than leaving a focusable no-op control. */
.chat-lightbox__prev.is-hidden, .chat-lightbox__next.is-hidden,
.chat-lightbox__opentab.is-hidden { display: none; }
/* In from the edge, not on it. 14px reads as no inset at all once the picture
   itself reaches the viewport's sides: the disc looks stuck to the frame rather
   than placed on top of the image. The pair keeps its 48px spacing so they stay
   one control-width apart. */
.chat-lightbox__close { top: 18px; right: 22px; }
/* Beside close, not under it: both are chrome about the whole view, and the
   corner is where a reader already looks for that. 40px button + 14px gutter
   puts it exactly one button-width in from the close button. */
.chat-lightbox__opentab { top: 18px; right: 70px; }
.chat-lightbox__prev { left: 14px; top: 50%; transform: translateY(-50%); }
.chat-lightbox__next { right: 14px; top: 50%; transform: translateY(-50%); }

/* Set on the real <body> while the lightbox is open (lightbox.js) — this
   is the one selector in the file that intentionally reaches past
   .chat-shell, because <body> is the element the lightbox actually marks. */
body.chat-lightbox-open { overflow: hidden; }

/* ===== Who has read it: the reader row and its overlay =====
   (ui/message_readers_row.js, ui/readers_overlay.js — group chats only, and
   only under the reader's OWN messages.) */

/* The row of faces IS a button, because a mouse and a keyboard are this
   surface's primary input (it lives in a desktop popup window) and a long-press
   does not exist there — see message_readers_row.js's header. It is styled flat
   so it reads as part of the bubble's meta rather than as a call to action. */
.chat-bubble__readers {
  align-self: flex-end;
  position: relative;
  display: flex;
  align-items: center;
  /* The app's exact inset: 3px above, 4px in from the right, nothing else.
     See chat_group_receipt.dart — the faces sit just under the bubble's
     corner, not a line below it. */
  margin-top: 0;
  padding: 3px 4px 0 0;
  border-radius: 999px;
}
/* The faces overlap the way a "read by" row does everywhere else, so three of
   them cost less width than three avatars: each one after the first slides back
   over the one before, and its border separates them without a second colour.
   The size is overridden from .chat-avatar--sm's own 28px because this row sits
   inside a bubble's meta line, where 28px would be taller than the timestamp
   beside it. */
/* The app advances 12px per 18px avatar (chat_group_receipt.dart's `step`),
   i.e. a 6px overlap — this was -8px, a 10px advance, which spread the cluster
   wider than the app's. */
.chat-bubble__readers .chat-avatar + .chat-avatar { margin-left: -6px; }
.chat-bubble__readers .chat-avatar {
  width: 18px;
  height: 18px;
  font-size: 8px;
  border: 1px solid var(--chat-outgoing-bubble);
}
.chat-bubble__readers:hover,
.chat-bubble__readers:focus-visible { background: var(--chat-wash-soft); }
.chat-bubble__readers-overflow {
  margin-left: 4px;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--chat-bubble-muted);
}

/* The hover preview ("Read by Anna, Bo +2"). Present in the DOM always, shown
   ONLY where a hover really exists: on a touch screen the same gesture is
   already a tap that opens the full list, and a tooltip appearing under a
   finger is noise. Gated on the pointer's capabilities rather than on the user
   agent, which lies. Keyboard focus gets it too, so the fast path is not
   mouse-only. */
.chat-bubble__readers-tip { display: none; }
@media (hover: hover) and (pointer: fine) {
  .chat-bubble__readers-tip {
    display: block;
    position: absolute;
    bottom: calc(100% + 4px);
    right: 0;
    z-index: 5;
    white-space: nowrap;
    padding: 4px 8px;
    border-radius: 6px;
    background: var(--chat-composer-bg);
    color: var(--chat-bubble-text);
    font-size: 11.5px;
    /* Hidden but laid out, so revealing it cannot shift anything. Not
       `display:none` here: a transition from it would not animate, and a
       0-opacity element still must not swallow the click meant for the button
       underneath — hence pointer-events. */
    opacity: 0;
    pointer-events: none;
    transition: opacity .12s ease-out;
  }
  .chat-bubble__readers:hover .chat-bubble__readers-tip,
  .chat-bubble__readers:focus-visible .chat-bubble__readers-tip { opacity: 1; }
}

/* The overlay. Deliberately the same chrome as .chat-lightbox above — one
   modal behaviour on this surface, not two (readers_overlay.js's header). */
.chat-readers {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
/* Closed — removed from the tree entirely, so nothing inside is reachable or
   announced (the same reasoning .chat-lightbox.is-hidden states). */
.chat-readers.is-hidden { display: none; }
.chat-readers__backdrop { position: absolute; inset: 0; background: var(--chat-scrim); }

/* A sheet rising from the bottom rather than a centred box: it is a list of
   people of unknown length, and the composer's own edge is where this surface's
   other bottom-anchored content already sits. */
.chat-readers__dialog {
  position: relative;
  z-index: 1;
  width: 100%;
  max-height: 70%;
  display: flex;
  flex-direction: column;
  /* Held to the same 400px column the whole surface is (see the file header):
     the overlay is position:fixed, so without this the sheet would span a wide
     desktop viewport while the chat it belongs to stayed a phone-width strip. */
  max-width: 400px;
  background: var(--chat-composer-bg);
  border-top-left-radius: 14px;
  border-top-right-radius: 14px;
  outline: none; /* programmatically focused (readers_overlay.js); the buttons inside keep their own ring */
}
.chat-readers__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 14px 8px;
}
.chat-readers__title {
  font-size: 14px;
  font-weight: 800;
  color: var(--chat-bubble-text);
}
.chat-readers__close {
  font-size: 20px;
  line-height: 1;
  padding: 2px 6px;
  color: var(--chat-bubble-muted);
}
/* The one scrolling part: the list, never the sheet's chrome. */
.chat-readers__body {
  overflow-y: auto;
  padding: 0 14px 16px;
}
.chat-readers__section + .chat-readers__section { margin-top: 14px; }
/* The two halves are told apart by their own headings — read as words, not as
   colours — and separated by a rule so the boundary survives a long list
   scrolling past the heading. */
.chat-readers__section-title {
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--chat-bubble-muted);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--chat-wash-medium);
}
.chat-readers__row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 0;
}
.chat-readers__person {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.chat-readers__name {
  font-size: 13.5px;
  color: var(--chat-bubble-text);
  /* One line, elided: a very long display name must not push the time out of
     the row or wrap it onto three lines. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chat-readers__time { font-size: 11px; color: var(--chat-bubble-muted); }
