/* App-local styles for Rooms.
 *
 * Everything general — colour, spacing, type, buttons, cards, forms — comes
 * from @ecosystem/design, linked before this file. What remains here is what no
 * other app has: a message transcript, a thread panel beside it, and reactions.
 *
 * Per packages/design/README.md this file may consume semantic tokens but
 * must not redefine any .ds-* component.
 */

/* This app's accent lives in @ecosystem/design — css/app-themes.css, keyed on
   the `data-app` slug the shell puts on <body>. It moved there when the accents
   started being DERIVED from each app's logo rather than chosen per app: the
   ramp, the contrast check and the logo are one decision now, and splitting
   them across six stylesheets is how they drift apart. Repointing a semantic
   token is still the supported extension point — that file is just where this
   particular repointing happens. */

/* --- The room: conversation, and a thread beside it ----------------------- */

.room {
  display: flex;
  gap: var(--ds-space-4);
  flex: 1;
  min-height: 0;
}

/* One conversation, filling the main column: members strip at the top, the
   transcript taking whatever is left, the composer pinned under it. Only the
   transcript scrolls — a transcript that grows the page means the input walks
   off the bottom of the screen as the conversation goes on. */
.conversation {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-3);
  flex: 1;
  min-height: 0;
  min-width: 0;
}

/* The thread panel sits BESIDE the room rather than covering it — the whole
   point of threading is that a side conversation does not displace the place
   it happened. Below the breakpoint there is no room for two columns, so the
   thread takes the screen and the transcript hides behind it. */
.thread {
  display: flex;
  flex-direction: column;
  flex: 0 0 22rem;
  min-height: 0;
  padding: var(--ds-space-3);
  background: var(--ds-surface);
  border: var(--ds-border-width) solid var(--ds-border);
  border-radius: var(--ds-radius-lg);
}
@media (max-width: 64rem) {
  .room:has(.thread:not([hidden])) .conversation { display: none; }
  .thread { flex: 1; }
}

.thread__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: none;
  margin-bottom: var(--ds-space-2);
}
.thread__title {
  margin: 0;
  font-size: var(--ds-text-base);
  font-weight: var(--ds-weight-semibold);
}
.thread__messages {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-3);
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
.thread__count {
  padding-bottom: var(--ds-space-1);
  border-bottom: var(--ds-border-width) solid var(--ds-border);
  font-size: var(--ds-text-xs);
  color: var(--ds-text-muted);
}

.members {
  flex: none;
  padding-bottom: var(--ds-space-3);
  border-bottom: var(--ds-border-width) solid var(--ds-border);
}

.messages {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-3);
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding-right: var(--ds-space-2);
}

/* Pinned under the transcript, and clear of the iOS home indicator. */
.composer {
  flex: none;
  padding-bottom: env(safe-area-inset-bottom, 0);
}

/* --- A message ------------------------------------------------------------ */

/* Stacked rather than the old three-column grid: a message now carries
   reactions and an action row underneath it, and those cannot live in a row
   that also has to keep the timestamp on the baseline of the first line. */
.message {
  display: flex;
  flex-direction: column;
  gap: var(--ds-space-1);
  font-size: var(--ds-text-sm);
  padding: var(--ds-space-1) 0;
}

.message__head {
  display: flex;
  align-items: baseline;
  gap: var(--ds-space-2);
  flex-wrap: wrap;
}
.message__author {
  font-weight: var(--ds-weight-medium);
  color: var(--ds-accent);
  white-space: nowrap;
}
.message__time {
  font-size: var(--ds-text-xs);
  color: var(--ds-text-subtle);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.message__edited {
  font-size: var(--ds-text-xs);
  color: var(--ds-text-subtle);
  font-style: italic;
}

/* Long unbroken strings (URLs, pasted tokens) must not widen the column and
   push the timestamp off the edge. */
.message__body { min-width: 0; overflow-wrap: anywhere; }
.message__body code {
  padding: 0 var(--ds-space-1);
  border-radius: var(--ds-radius-sm);
  background: var(--ds-surface-sunken);
  font-family: var(--ds-font-mono);
  font-size: 0.9em;
}
.message__body a { color: var(--ds-accent); }

.mention {
  padding: 0 var(--ds-space-1);
  border-radius: var(--ds-radius-sm);
  background: var(--ds-accent-subtle);
  color: var(--ds-accent);
  font-weight: var(--ds-weight-medium);
}

/* --- Reactions ------------------------------------------------------------ */

.message__reactions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ds-space-1);
  align-items: center;
}

.reaction {
  display: inline-flex;
  align-items: center;
  gap: var(--ds-space-1);
  padding: 0 var(--ds-space-2);
  min-height: 1.5rem;
  border: var(--ds-border-width) solid var(--ds-border);
  border-radius: var(--ds-radius-full);
  background: var(--ds-surface);
  color: var(--ds-text-muted);
  font: inherit;
  font-size: var(--ds-text-xs);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.reaction:hover { border-color: var(--ds-border-strong); }
/* Your own reaction is tinted AND outlined, not tinted alone: which ones you
   already pressed has to survive a reader who cannot distinguish the tint. */
.reaction--mine {
  border-color: var(--ds-accent);
  background: var(--ds-accent-subtle);
  color: var(--ds-accent);
}

.reaction-picker { position: relative; display: inline-block; }
.reaction--add {
  list-style: none;
  padding-inline: var(--ds-space-2);
  /* The "+" button only appears once there is something to add it to, or on
     hover — a row of empty add-buttons down a transcript is visual noise. */
  opacity: 0;
}
.reaction--add::-webkit-details-marker { display: none; }
.message:hover .reaction--add,
.message:focus-within .reaction--add,
.reaction-picker[open] .reaction--add { opacity: 1; }

.reaction-picker__menu {
  position: absolute;
  bottom: calc(100% + var(--ds-space-1));
  inset-inline-start: 0;
  z-index: var(--ds-z-dialog);
  display: flex;
  gap: var(--ds-space-1);
  padding: var(--ds-space-1);
  background: var(--ds-surface);
  border: var(--ds-border-width) solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  box-shadow: var(--ds-shadow-lg);
}
.reaction-picker__option {
  border: 0;
  border-radius: var(--ds-radius-sm);
  background: none;
  font-size: var(--ds-text-lg);
  line-height: 1;
  padding: var(--ds-space-1);
  cursor: pointer;
}
.reaction-picker__option:hover { background: var(--ds-surface-hover); }

/* --- Message actions ------------------------------------------------------ */

.message__actions {
  display: flex;
  gap: var(--ds-space-3);
  align-items: center;
}
.message__action {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: var(--ds-text-xs);
  color: var(--ds-text-muted);
  cursor: pointer;
}
.message__action:hover { color: var(--ds-accent); text-decoration: underline; }
.message__action--danger:hover { color: var(--ds-danger); }

/* Edit and Delete hide until hover on a pointer device; the reply/thread
   button never does, because a reply count is information rather than a
   control. Always visible on touch, where there is no hover to reveal them. */
@media (hover: hover) {
  .message__action[data-edit],
  .message__action[data-delete] {
    opacity: 0;
    transition: opacity var(--ds-duration-fast) var(--ds-ease);
  }
  .message:hover .message__action[data-edit],
  .message:hover .message__action[data-delete],
  .message:focus-within .message__action[data-edit],
  .message:focus-within .message__action[data-delete] { opacity: 1; }
}

/* --- Unread ---------------------------------------------------------------- */

/* The line marking where you left off. A rule with a label rather than a
   colour change on the messages themselves, so it reads as a position in the
   transcript rather than as a property of the messages under it. */
.new-divider {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  margin: var(--ds-space-2) 0;
  color: var(--ds-danger);
  font-size: var(--ds-text-xs);
  font-weight: var(--ds-weight-medium);
}
.new-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--ds-danger);
}

.unread-pill {
  margin-inline-start: auto;
  flex: none;
  min-width: 1.25rem;
  padding: 0 var(--ds-space-1);
  border-radius: var(--ds-radius-full);
  background: var(--ds-accent);
  color: var(--ds-on-accent);
  font-size: var(--ds-text-xs);
  font-weight: var(--ds-weight-semibold);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
/* An unread channel is bolder as well as badged — the count is the detail,
   "there is something here" is the thing you scan for. */
.ds-nav__item--unread { font-weight: var(--ds-weight-semibold); }

/* --- Search ---------------------------------------------------------------- */

.search { width: min(18rem, 32vw); }
@media (max-width: 30rem) {
  .search { width: 8rem; }
}

.search-results { overflow-y: auto; }

.search-result {
  display: block;
  padding: var(--ds-space-3);
  border: var(--ds-border-width) solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  background: var(--ds-surface);
  color: var(--ds-text);
  text-decoration: none;
  font-size: var(--ds-text-sm);
}
.search-result:hover { border-color: var(--ds-border-strong); color: var(--ds-text); }
.search-result__head {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ds-space-2);
  align-items: baseline;
  margin-bottom: var(--ds-space-1);
}
.search-result__channel {
  font-weight: var(--ds-weight-semibold);
  color: var(--ds-text);
}

.ds-nav__empty {
  padding: var(--ds-space-1) var(--ds-space-2);
  margin: 0;
  font-size: var(--ds-text-xs);
  color: var(--ds-text-subtle);
}
.ds-nav__item--muted { color: var(--ds-text-muted); }

/* --- Mentions --------------------------------------------------------------
   The second tier of unread: something happened in a channel, versus somebody
   is talking to YOU. Without the distinction every busy channel looks equally
   urgent and none of them are — see docs/strategy/competitive.md.
-------------------------------------------------------------------------- */

/* A mention of you reads differently from a mention of anybody else. Scrolling
   a busy channel, the question is never "was somebody mentioned". */
.mention--you {
  background: var(--ds-warning-subtle);
  color: var(--ds-warning);
}

/* The whole message, not just the handle: the point is that it is findable
   while scrolling past, before you have read a word of it. */
.message--for-you {
  border-left: 2px solid var(--ds-warning);
  padding-left: var(--ds-space-3);
  margin-left: calc(var(--ds-space-3) * -1);
}

.unread-pill--mention { background: var(--ds-warning); color: var(--ds-text-inverted); }
.ds-nav__item--mention { font-weight: var(--ds-weight-semibold); }

/* --- The mention picker ----------------------------------------------------
   A mention only notifies if the handle is spelled exactly right, so this is
   correctness rather than convenience: a composer that makes you remember
   handles produces mentions that silently fail.
-------------------------------------------------------------------------- */

.composer__row { position: relative; }

.mention-menu {
  position: absolute;
  bottom: calc(100% + var(--ds-space-2));
  inset-inline-start: 0;
  z-index: var(--ds-z-dialog);
  width: min(20rem, 100%);
  max-height: 14rem;
  overflow-y: auto;
  padding: var(--ds-space-1);
  border: var(--ds-border-width) solid var(--ds-border);
  border-radius: var(--ds-radius-md);
  background: var(--ds-surface);
  box-shadow: var(--ds-shadow-lg);
}

.mention-menu__item {
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  width: 100%;
  padding: var(--ds-space-2);
  border: 0;
  border-radius: var(--ds-radius-sm);
  background: transparent;
  color: var(--ds-text);
  font: inherit;
  font-size: var(--ds-text-sm);
  text-align: start;
  cursor: pointer;
}
/* Selection follows the keyboard, so aria-selected is what is styled — the
   mouse moves the selection rather than painting a competing highlight. */
.mention-menu__item[aria-selected="true"] { background: var(--ds-accent-subtle); }
.mention-menu__name { font-weight: var(--ds-weight-medium); }
.mention-menu__handle { margin-inline-start: auto; color: var(--ds-text-muted); font-size: var(--ds-text-xs); }

/* --- What this channel is about -------------------------------------------
   The channel→client link, sitting under the member row rather than in the
   topbar: rule 10f, and the bar already holds its one action.

   Sized here rather than with a `ds-input--sm` modifier, because there is no
   such modifier — `.ds-input` has one size, and rule 5 forbids an app adding a
   variant to a shared component. This narrows one instance of it, which is a
   layout decision about this row and nobody else's. */
.channel-client__select {
  width: auto;
  max-width: 14rem;
  font-size: var(--ds-text-sm);
}
