/* Meridian Messages — the ribbon tile, the dock, and the full page.
 *
 * MESSAGES BORROWS THE ACTIVE SUITE'S CHROME, NOT ITS MEANING. The dock is
 * deliberately tinted to fit the page it is on: launcher, header, borders and
 * selected conversation use the current suite accent. Message bubbles and
 * their sent/received meaning stay fixed, so a blue sent bubble never changes
 * meaning between Leave, HR, Audits, Training, SU Records or Workforce.
 *
 * ELEVATION, SPARINGLY. The rest of the app is flat with 1px borders. The dock
 * floats over content so it needs a shadow, but a heavy one makes it look like
 * a third-party widget bolted onto the page. A restrained shadow plus the same
 * 1px border keeps it in the family.
 */

:root {
  /* The z-index scale, named rather than guessed. Page content sits below the
   * dock, the dock below modals, modals below toasts. Written down because the
   * numbers already in this codebase run 1, 2, 5, 30, 50, 60, 100, 200, 300,
   * 1500, 9999 and nobody can hold that in their head. */
  --z-page: 1;
  --z-mdock: 400;
  --z-modal: 1500;
  --z-toast: 9999;

  /* Messages' own accent: ink, not a suite colour. */
  --msg-accent: var(--ink-2);

  /* ── The bubbles ───────────────────────────────────────────────────────
   * iOS uses #007AFF and #34C759. Both look right and both FAIL WCAG AA with
   * white text — 4.02:1 and 2.22:1. These keep the feel and pass at 5.41:1 and
   * 5.19:1, computed rather than claimed: check-connect-bubble-contrast.js
   * reads them back out of this file and does the arithmetic.
   *
   * THE SAME IN DARK MODE, deliberately. A filled bubble carries its own
   * background, so it does not need to follow the canvas — and a bubble that
   * changed colour between themes would make "blue is mine" a thing somebody
   * has to relearn at night. */
  --connect-bubble-sent: #0A66D6;
  --connect-bubble-sent-strong: #0856B5;
  --connect-bubble-sent-ink: #FFFFFF;

  /* RECEIVED FOLLOWS THE PANEL; SENT DOES NOT.
   *
   * The sent bubble is an identity signal — "blue is mine" — so it holds one
   * colour everywhere, which is what the note above is about. The received
   * bubble carries no such meaning: it is simply "not mine", and alignment
   * already says that. So it is free to belong to the panel it sits in, and
   * once the dock started following the page's theme (2026-09-17) it had to:
   * slate is right on charcoal and is a heavy dark slab on a light panel.
   *
   * Light: white on the panel's own grey, dark ink at 16.1:1.
   * Dark:  slate, white ink at 10.4:1 — unchanged from the charcoal design.
   *
   * check-connect-bubble-contrast.js reads each bubble against ITS OWN ink
   * rather than assuming white, and does it per theme. */
  --connect-bubble-received: #FFFFFF;
  --connect-bubble-received-strong: #F0F2F5;
  --connect-bubble-received-ink: #1A1D22;
  /* The hairline that separates a white bubble from a light panel. In dark
     mode the slate does that by itself and this is barely there. */
  --connect-bubble-received-edge: rgba(27, 34, 48, .12);

  /* Unread. One semantic colour, used for the dot and the badge, chosen to
   * read correctly against every suite's page behind it rather than against
   * one. --info is already the platform's "this is a thing, not a problem"
   * blue and carries no suite's meaning. */
  --msg-unread: var(--info);
  --msg-unread-soft: var(--info-soft);
}

/* ── The ribbon tile ─────────────────────────────────────────────────────── */

.tilebtn--messages {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.tilebtn__ic {
  width: 15px;
  height: 15px;
  flex: none;
  color: var(--ink-2);
}

/* ── The dock ────────────────────────────────────────────────────────────── */

.mdock {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: var(--z-mdock);
  display: flex;
  flex-direction: column;
  color: var(--ink);
  font-size: 13px;
}

/* The no-JS state forms carry nothing visible; their buttons live in the dock.
 * They must not take layout space or a tab stop of their own. */
.mdock-form {
  display: contents;
}

/* Collapsed: a launcher bar, about 220 x 44. */
.mdock--collapsed .mdock__launcher {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-width: 200px;
  height: 44px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 6px 20px -8px rgba(15, 31, 27, .28);
  text-align: left;
}

.mdock__launcher:hover { background: var(--surface-2); }

.mdock__launcher:focus-visible,
.mdock__iconbtn:focus-visible {
  outline: 2px solid var(--msg-accent);
  outline-offset: 2px;
}

.mdock__ic { width: 17px; height: 17px; flex: none; color: var(--msg-accent); }
.mdock__launcher-tx { flex: 1; min-width: 0; }

/* Expanded: 360 x 520, both states. */
.mdock__body {
  display: flex;
  flex-direction: column;
  width: 360px;
  height: 520px;
  max-height: calc(100vh - 40px);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
  box-shadow: 0 10px 30px -10px rgba(15, 31, 27, .30);
  overflow: hidden;
}

.mdock__head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 10px 10px 14px;
  border-bottom: 1px solid var(--line-2);
  background: var(--surface-2);
  flex: none;
}

.mdock__title {
  flex: 1;
  min-width: 0;
  margin: 0;
  /* Raised from 13px 2026-09-16: the dock header sat noticeably smaller than
     everything around it and was hard to read at a glance across a desk. */
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mdock__actions { display: flex; align-items: center; gap: 2px; flex: none; }

.mdock__iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: none;
  padding: 0;
  border: 0;
  border-radius: var(--r-chip);
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
}

.mdock__iconbtn:hover { background: var(--sunk); color: var(--ink); }
.mdock__iconbtn svg { width: 20px; height: 20px; }

/* "New conversation", in the dock.
   THE ICON NEEDS ITS OWN SIZE HERE. `.shell .page .btn svg` sizes button icons
   on ordinary pages, but the dock is shell furniture and lives outside .page,
   so that rule never reaches it: the <svg> fell back to the replaced-element
   default of 300x150 and filled the whole panel with a plus sign, pushing the
   label out of the dock. Same trap as .message-about, which is outside .page
   for the same reason. */
.mdock__new { display: inline-flex; align-items: center; justify-content: center; gap: 8px; width: 100%; white-space: nowrap; font-size: 14px; }
.mdock__new svg { width: 18px; height: 18px; flex: none; }

/* The dock's own "start a conversation" step. Direct only; a group goes to the
   full page, because eleven people and a name do not fit a 340px panel. */
/* ── The dock's person picker ─────────────────────────────────────────────
 *
 * Built out of the platform's own tokens, not a native <select>. The control
 * it replaced was the one piece of Messages that looked like a browser default
 * dropped into the page: an OS-drawn widget with its own font, its own focus
 * ring and its own idea of dark mode, sitting inside a panel that is otherwise
 * entirely this application's.
 *
 * Every colour below is a token, so it follows the theme rather than fighting
 * it, and both themes are covered because the tokens are redefined for dark in
 * meridian-tokens.css.
 */
.mdock__start { display: flex; flex-direction: column; gap: 10px; padding: 12px; min-height: 0; overflow-y: auto; }

.mdock__start-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.mdock__start-label { margin: 0; font-size: 13px; font-weight: 700; color: var(--ink); }
.mdock__start-count { margin: 0; font-size: 12px; color: var(--ink-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.mdock__start-count[data-full] { color: var(--warn-icon); font-weight: 700; }

.mdock__start-error {
  margin: 0; padding: 8px 10px;
  border: 1px solid var(--line); border-left: 3px solid var(--danger);
  border-radius: var(--r-chip);
  background: var(--surface-2); color: var(--ink);
  font-size: 12.5px;
}

.mdock__start-filter {
  width: 100%; height: 34px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: var(--r-chip);
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: 13px;
}
.mdock__start-filter::placeholder { color: var(--ink-3); }
.mdock__start-filter:focus-visible { outline: 2px solid var(--msg-accent); outline-offset: 1px; }
.mdock__start-filter[hidden] { display: none; }

/* Chosen people, as chips. */
.mdock__chips { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 0; padding: 0; }
.mdock__chips[hidden] { display: none; }
.mdock__chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 4px 3px 9px;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--msg-unread-soft); color: var(--ink);
  font-size: 12px; max-width: 100%;
}
.mdock__chip > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mdock__chip-x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; flex: none;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--ink-2);
  font-size: 15px; line-height: 1; cursor: pointer;
}
.mdock__chip-x:hover { background: var(--sunk); color: var(--ink); }

/* The list itself. It scrolls; the panel does not. */
.mdock__people {
  flex: 1; min-height: 120px; max-height: 260px; overflow-y: auto;
  border: 1px solid var(--line); border-radius: var(--r-chip);
  background: var(--surface);
  padding: 4px;
}
.mdock__group + .mdock__group { margin-top: 4px; }
.mdock__group[hidden] { display: none; }

/* The department heading sticks, so somebody scrolling a long list always
   knows whose team they are looking at. */
.mdock__group-h {
  position: sticky; top: -4px; z-index: 1;
  margin: 0; padding: 6px 8px 4px;
  background: var(--surface);
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-3);
}

.mdock__person {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 8px;
  border-radius: var(--r-chip);
  cursor: pointer;
}
.mdock__person[hidden] { display: none; }
.mdock__person:hover { background: var(--sunk); }
.mdock__person.is-chosen { background: var(--msg-unread-soft); }
.mdock__person.is-capped { opacity: .45; cursor: not-allowed; }
.mdock__person input { flex: none; margin: 0; }
.mdock__person-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.mdock__person-name { font-size: 13px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mdock__person-sub { font-size: 11px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.mdock__start-none { margin: 10px 8px; font-size: 12.5px; color: var(--ink-2); }
.mdock__start-none[hidden] { display: none; }

.mdock__start-name { display: flex; flex-direction: column; gap: 4px; font-size: 12px; font-weight: 700; color: var(--ink-2); }
.mdock__start-name[hidden] { display: none; }
.mdock__start-name input {
  width: 100%; height: 34px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: var(--r-chip);
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: 13px; font-weight: 400;
}
.mdock__start-name input::placeholder { color: var(--ink-3); }

.mdock__start-in { width: 100%; }
.mdock__start-row { display: flex; gap: 8px; justify-content: flex-end; }
.mdock__start-note { margin: 0; font-size: 12px; font-weight: 400; color: var(--ink-3); }

.mdock__filter { padding: 10px 12px; border-bottom: 1px solid var(--line-2); flex: none; }

.mdock__filter-in {
  width: 100%;
  height: 32px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-chip);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 12.5px;
}

.mdock__filter-in:disabled { background: var(--sunk); color: var(--ink-3); cursor: not-allowed; }

.mdock__list,
.mdock__thread { flex: 1; min-height: 0; overflow-y: auto; padding: 12px; }

.mdock__thread:focus-visible { outline: 2px solid var(--msg-accent); outline-offset: -2px; }

.mdock__composer { flex: none; border-top: 1px solid var(--line-2); padding: 10px 12px 12px; }

/* N2 — the standing reminder. Always visible, not dismissible, small. It sits
 * above the composer because that is the moment it is about. */
.mdock__reminder,
.msg-reminder {
  margin: 0 0 8px;
  padding: 7px 9px;
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--warn-icon);
  border-radius: var(--r-chip);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 11.5px;
  line-height: 1.45;
}

.msg-reminder { margin: 14px 0; max-width: 62ch; }

.mdock__empty { margin: 0; color: var(--ink-3); font-size: 12.5px; line-height: 1.5; }

/* ── Unread, never by colour alone ───────────────────────────────────────── */

/* Every unread signal carries a number or a word as well as the colour, and
 * each is announced through the control's accessible name. R4 fills these in
 * with real counts; the rules exist now so the contrast check has something to
 * measure and nobody invents a second style later. */
.mdock__unread {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--msg-unread);
  color: #FFFFFF;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* A mention is the one thing that should pull the eye even when the count is
 * small, so it takes the emphasised style rather than a second colour. */
.mdock__unread--mention { background: var(--danger); }

/* ── Suppression ─────────────────────────────────────────────────────────── */

/* The inspection print views must not carry a chat panel. */
@media print {
  .mdock,
  .mdock-form,
  .tilebtn--messages { display: none !important; }
}

/* Somebody who has asked for less motion gets none of it. */
@media (prefers-reduced-motion: reduce) {
  .mdock, .mdock__body, .mdock__launcher { transition: none !important; }
}

/* Narrow screens: the dock would cover the page it is meant to sit beside. */
/* ON A PHONE THE DOCK STEPS ASIDE (2026-09-21). Stretched across the bottom
 * of a 390px screen it sat on top of the suite bar, so Home and the suites
 * could not be tapped, and it covered the last controls on every page. The
 * top bar's Messages button opens the full Messages page instead, and its
 * unread badge keeps counting. */
@media (max-width: 760px) {
  .mdock { display: none !important; }
}
@media (max-width: 700px) {
  .mdock { right: 12px; bottom: 12px; left: 12px; }
  .mdock__body { width: auto; height: min(70vh, 520px); }
  .mdock--collapsed .mdock__launcher { width: 100%; }
}

/* ── The full page ───────────────────────────────────────────────────────── */

.msg-page {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}

.msg-page__list,
.msg-page__thread { min-width: 0; }

@media (max-width: 900px) {
  .msg-page { grid-template-columns: minmax(0, 1fr); }
}

/* ── Dark ────────────────────────────────────────────────────────────────── */

/* The shadow is the only thing that cannot simply inherit a token: a light
 * shadow over a dark canvas reads as a glow, so it goes deeper and tighter
 * rather than lighter. */
[data-theme="dark"] .mdock--collapsed .mdock__launcher {
  box-shadow: 0 6px 20px -8px rgba(0, 0, 0, .70);
}

[data-theme="dark"] .mdock__body {
  box-shadow: 0 10px 30px -10px rgba(0, 0, 0, .75);
}

[data-theme="dark"] .mdock__unread { color: #0E1416; }

/* ── Conversations, threads and the composer ─────────────────────────────── */

.msg-empty { margin: 0; color: var(--ink-3); font-size: 13px; line-height: 1.5; }

.msg-flash {
  margin: 0 0 16px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--danger);
  border-radius: var(--r-chip);
  background: var(--danger-soft);
  color: var(--ink);
  font-size: 13px;
}

/* ── Conversations, as tiles ──────────────────────────────────────────────
 *
 * They were rows divided by hairlines, which reads as one long list rather than
 * as separate conversations — the thing somebody is actually scanning for is
 * "which chat", and a divider is a weak answer to that. Each one is now an
 * outlined tile with its own initials mark, so one is distinguishable from the
 * next at a glance.
 *
 * STILL NO MESSAGE TEXT. The tile carries a name, a time and a count, exactly
 * as the row did. The dock sits in this state on every page in every suite, and
 * a preview here would be content on permanent display to whoever is standing
 * behind the person using it (rule AU12). Tiles make the list easier to scan;
 * they do not make it say more.
 */
.msg-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }

/* A tile is an <a> on the full page and a <button> in the dock, and both have
   to look identical — so everything a button brings of its own (font, border,
   alignment, width) is reset here rather than assumed. */
.msg-list__form { margin: 0; }
.msg-list__link {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-card);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.msg-list__link:hover { background: var(--surface-2); border-color: var(--line); }
.msg-list__item.is-active .msg-list__link {
  background: var(--sunk);
  border-color: var(--msg-accent);
  font-weight: 600;
}

/* ── The avatar ───────────────────────────────────────────────────────────
 *
 * Initials in a coloured circle. The colour comes from the person's id, so it
 * is the same in the dock, the full page and tomorrow — that stability is the
 * point, and it is why it is not derived from the name (people get married) or
 * from the row's position (which changes on every message).
 *
 * The tone is a CLASS, not an inline colour, so the palette is redefined for
 * dark mode alongside everything else. Eight tones: enough to tell a list
 * apart, few enough that every one can be checked against both canvases.
 *
 * A group is a rounded square, a person is a circle, so the two kinds are told
 * apart without relying on colour at all.
 */
.msg-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: none;
  border-radius: 50%;
  font-size: 12px; font-weight: 700; letter-spacing: .02em;
  /* Letter-spacing pushes the pair off-centre; this pulls it back. Without it
     two identical letters ("II") read as a pause glyph rather than initials. */
  text-indent: .02em;
}
.msg-avatar--group { border-radius: 11px; }

.msg-avatar--tone1 { background: #DCE9F7; color: #17456F; }
.msg-avatar--tone2 { background: #DFEFE3; color: #1C5230; }
.msg-avatar--tone3 { background: #F6E5DC; color: #7A3A1B; }
.msg-avatar--tone4 { background: #E9E2F5; color: #452E70; }
.msg-avatar--tone5 { background: #FBE7EE; color: #7A2B46; }
.msg-avatar--tone6 { background: #E1EFF1; color: #14535C; }
.msg-avatar--tone7 { background: #F5EDD9; color: #6B4E12; }
.msg-avatar--tone8 { background: #E6E8EC; color: #33404F; }

/* The same eight, for the dark canvas. Deeper fills with light ink, rather
   than the light palette dimmed — dimming goes muddy and loses the difference
   between tones exactly where there is least contrast to spare. */
[data-theme="dark"] .msg-avatar--tone1 { background: #1D3247; color: #BBD6F2; }
[data-theme="dark"] .msg-avatar--tone2 { background: #1B3524; color: #B6DCC1; }
[data-theme="dark"] .msg-avatar--tone3 { background: #3B2618; color: #E6BE9F; }
[data-theme="dark"] .msg-avatar--tone4 { background: #2B2440; color: #C8BCE6; }
[data-theme="dark"] .msg-avatar--tone5 { background: #3A1F2B; color: #E8B3C6; }
[data-theme="dark"] .msg-avatar--tone6 { background: #143036; color: #A8D4DC; }
[data-theme="dark"] .msg-avatar--tone7 { background: #33290F; color: #DFCB92; }
[data-theme="dark"] .msg-avatar--tone8 { background: #262C34; color: #C3CBD6; }

.msg-list__who { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; line-height: 1.3; }
.msg-list__top, .msg-list__bottom { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.msg-list__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-list__when { flex: none; font-size: 11px; color: var(--ink-3); white-space: nowrap; }
.msg-list__count { color: var(--ink-3); font-size: 11.5px; }

/* The preview. One line, always, and never two. */
.msg-list__preview {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 12px; color: var(--ink-2);
}
.msg-list__preview-who { color: var(--ink-3); }
.msg-list__preview--deleted { font-style: italic; color: var(--ink-3); }
.msg-list__preview--empty { font-style: italic; color: var(--ink-3); }
.msg-list__clip { width: 11px; height: 11px; vertical-align: -1px; }
.msg-list__muted-ic { flex: none; font-size: 12px; color: var(--ink-3); }

/* Unread: bold name AND preview, plus the number. Never weight alone and never
   colour alone. */
.msg-list__item.is-unread .msg-list__name,
.msg-list__item.is-unread .msg-list__preview { font-weight: 700; color: var(--ink); }
.mdock__unread--muted { background: var(--sunk); color: var(--ink-2); }

.msg-list__section {
  margin: 10px 2px 4px;
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3);
}

/* Search over the rows already on the page. */
.msg-list__search { padding: 0 0 8px; }
.msg-list__search[hidden] { display: none; }
.msg-list__search-in {
  width: 100%; height: 32px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: var(--r-chip);
  background: var(--surface); color: var(--ink); font: inherit; font-size: 12.5px;
}
.msg-list__none { margin: 10px 2px; font-size: 12.5px; color: var(--ink-2); }
.msg-list__none[hidden] { display: none; }

/* Row actions. A real <details> menu, so a keyboard and a touch screen reach it
   the same way a mouse does. */
.msg-list__item { position: relative; }
.msg-list__menu { position: absolute; top: 6px; right: 6px; }
.msg-list__menu-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;
  border-radius: var(--r-chip);
  color: var(--ink-3); font-size: 15px; line-height: 1; cursor: pointer;
  list-style: none;
}
.msg-list__menu-btn::-webkit-details-marker { display: none; }
.msg-list__menu-btn:hover, .msg-list__menu[open] .msg-list__menu-btn { background: var(--sunk); color: var(--ink); }
.msg-list__menu-panel {
  position: absolute; right: 0; top: 26px; z-index: 2;
  min-width: 150px; padding: 4px;
  border: 1px solid var(--line); border-radius: var(--r-chip);
  background: var(--surface); box-shadow: 0 6px 20px rgba(0,0,0,.14);
}
.msg-list__menu-panel form { margin: 0; }
.msg-list__menu-panel button {
  display: block; width: 100%; text-align: left;
  padding: 7px 9px; border: 0; border-radius: var(--r-chip);
  background: none; color: var(--ink); font: inherit; font-size: 12.5px; cursor: pointer;
}
.msg-list__menu-panel button:hover { background: var(--sunk); }

/* ── The thread ───────────────────────────────────────────────────────────
 *
 * Bubbles: yours right and blue, everybody else's left and green. Alignment is
 * the primary signal and colour is the second, so neither carries it alone.
 *
 * RUNS. Consecutive messages from the same person within five minutes group
 * together with tighter spacing, and only the LAST bubble of a run gets a tail
 * — a tail on every bubble is what makes a chat look like a comment thread.
 * The run boundaries are worked out on the server, so the dock and the full
 * page cannot disagree about where one ends.
 */
.msg-thread { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }

.msg { display: flex; flex-direction: column; align-items: flex-start; max-width: 100%; }
.msg--mine { align-items: flex-end; }
/* The gap between runs, rather than between every message. */
.msg--run-start { margin-top: 10px; }

.msg__bubble {
  max-width: 78%;
  padding: 8px 12px;
  border-radius: 18px;
  background: var(--connect-bubble-received);
  color: var(--connect-bubble-received-ink);
  line-height: 1.4;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}
/* The sent bubble states its ink rather than inheriting it: the rule above is
   the received bubble's, and its ink is dark in light mode. */
.msg--mine .msg__bubble {
  background: var(--connect-bubble-sent);
  color: var(--connect-bubble-sent-ink);
}

/* The tail, on the last bubble of a run only. */
.msg--run-end .msg__bubble { border-bottom-left-radius: 5px; }
.msg--mine.msg--run-end .msg__bubble { border-bottom-left-radius: 18px; border-bottom-right-radius: 5px; }

/* A withdrawn message is not a bubble. It is a note that something was said
   and taken back, and dressing it as a message would misrepresent it. */
.msg--withdrawn .msg__bubble {
  background: transparent;
  color: var(--ink-3);
  border: 1px dashed var(--line);
  font-style: italic;
}

/* Who, above the first bubble of a received run in a group. */
.msg__runwho { margin: 0 0 2px 12px; font-size: 11px; font-weight: 700; color: var(--ink-2); }

/* When, under the last bubble of a run. */
.msg__when-run { margin: 2px 12px 0; font-size: 10.5px; color: var(--ink-3); }
.msg--mine .msg__when-run { text-align: right; }

/* Status under your own last message. */
.msg__status { margin: 1px 12px 0; font-size: 10.5px; color: var(--ink-3); text-align: right; }

.msg-day, .msg-newline { margin: 10px 0 4px; }

.msg__meta { display: flex; align-items: baseline; gap: 8px; font-size: 11.5px; color: var(--ink-3); }
.msg__who { font-weight: 600; color: var(--ink-2); }
.msg__body { margin: 2px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.5; }

/* A withdrawal leaves a marker, never a gap. A thread that silently closed up
 * would hide that anything had been said at all. */
.msg--withdrawn .msg__body--withdrawn { color: var(--ink-3); font-style: italic; }

.msg__ref {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
  padding: 4px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-chip);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 12px;
  text-decoration: none;
}

.msg__ref:hover { background: var(--sunk); color: var(--ink); }
.msg__ref svg { width: 13px; height: 13px; flex: none; }

.msg__withdraw { display: inline; }
.msg__linkbtn {
  margin-top: 4px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-3);
  font: inherit;
  font-size: 11.5px;
  text-decoration: underline;
  cursor: pointer;
}
.msg__linkbtn:hover { color: var(--ink); }
.msg__linkbtn--danger:hover { color: var(--danger); }

.msg-composer { display: flex; flex-direction: column; gap: 8px; }

.msg-composer__in {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-chip);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  line-height: 1.5;
  resize: vertical;
}

.msg-composer.is-failed .msg-composer__in { border-color: var(--danger); }

.msg-composer__error {
  margin: 0;
  padding: 7px 9px;
  border-radius: var(--r-chip);
  background: var(--danger-soft);
  color: var(--ink);
  font-size: 12px;
}

.msg-composer__row { display: flex; align-items: center; gap: 8px; }
.msg-composer__spacer { flex: 1; }

.msg-composer__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  border: 1px solid var(--line);
  border-radius: var(--r-chip);
  background: var(--surface);
  color: var(--ink-2);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}
.msg-composer__link:hover { background: var(--surface-2); color: var(--ink); }
.msg-composer__link svg { width: 13px; height: 13px; }

.msg-composer__chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  align-self: flex-start;
  padding: 4px 6px 4px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-chip);
  background: var(--surface-2);
  font-size: 12px;
}
.msg-composer__chip[hidden] { display: none; }
.msg-composer__chip-clear {
  border: 0; background: none; color: var(--ink-3);
  font: inherit; font-size: 15px; line-height: 1; cursor: pointer; padding: 0 4px;
}
.msg-composer__chip-clear:hover { color: var(--danger); }

/* ── Records named while writing ──────────────────────────────────────────
 *
 * Suggestions under the box, and a list of what has been linked. The highlight
 * a RECIPIENT sees is rendered server-side (.msg__mention below); a textarea
 * cannot style part of its own value, and the mirrored-div trick that fakes it
 * drifts out of alignment the moment a font metric changes.
 */
.msg-composer__suggest {
  border: 1px solid var(--line); border-radius: var(--r-chip);
  background: var(--surface); padding: 6px; margin-top: 6px;
}
.msg-composer__suggest[hidden] { display: none; }
.msg-composer__suggest-h { margin: 2px 6px 6px; font-size: 11px; color: var(--ink-3); }
.msg-composer__suggest-list { list-style: none; margin: 0; padding: 0; max-height: 180px; overflow-y: auto; }
.msg-composer__suggest-hit {
  display: block; width: 100%; text-align: left;
  padding: 7px 8px; border: 0; border-radius: var(--r-chip);
  background: none; color: var(--ink); font: inherit; font-size: 13px; cursor: pointer;
}
.msg-composer__suggest-hit:hover, .msg-composer__suggest-hit:focus-visible { background: var(--sunk); }

.msg-composer__linked { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 6px 0 0; padding: 0; }
.msg-composer__linked[hidden] { display: none; }
.msg-composer__linked-item {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 2px 4px 2px 8px;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--msg-unread-soft); color: var(--ink); font-size: 12px;
}
.msg-composer__linked-x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 17px; height: 17px; flex: none;
  border: 0; border-radius: 50%; background: transparent; color: var(--ink-2);
  font-size: 14px; line-height: 1; cursor: pointer;
}
.msg-composer__linked-x:hover { background: var(--sunk); color: var(--ink); }

/* A link somebody typed. White on a filled bubble, so underline carries it. */
.msg__link { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.msg__link:hover { text-decoration-thickness: 2px; }

/* The name, inside a sent message. Underlined rather than coloured alone:
   colour is never the only signal (the same rule the unread badge follows). */
.msg__mention {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-style: dotted;
  text-underline-offset: 2px;
  text-decoration-color: var(--msg-unread);
  border-radius: 3px;
  cursor: pointer;
}
.msg__mention:hover, .msg__mention:focus-visible {
  background: var(--msg-unread-soft);
  text-decoration-style: solid;
}

/* The card on a named record. Fixed to the viewport because the thread scrolls
   under it, and above the dock so it is never clipped by the panel it opened
   in. It is a note, not a dialog: no focus trap, no backdrop. */
.msg-card {
  position: fixed;
  z-index: calc(var(--z-mdock) + 1);
  max-width: 260px;
  padding: 9px 11px;
  border: 1px solid var(--line);
  border-radius: var(--r-chip);
  background: var(--surface);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .14);
  pointer-events: none;
}
.msg-card__who { margin: 0; font-size: 13px; font-weight: 700; color: var(--ink); }
.msg-card__what { margin: 2px 0 0; font-size: 11px; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); }
.msg-card__go { margin: 6px 0 0; font-size: 11.5px; color: var(--ink-2); }

/* Silencing a person. One row per person, one form per row. */
.msg-silence { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; max-width: 520px; }
.msg-silence__row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 8px 10px;
  border: 1px solid var(--line-2); border-radius: var(--r-chip);
  background: var(--surface);
}
.msg-silence__row.is-silenced { background: var(--surface-2); border-color: var(--line); }
.msg-silence__who { display: flex; flex-direction: column; min-width: 0; line-height: 1.3; }
.msg-silence__name { font-size: 13px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-silence__sub { font-size: 11px; color: var(--ink-3); }
.msg-silence__row form { margin: 0; flex: none; }

.msg-composer__picker { border: 1px solid var(--line); border-radius: var(--r-chip); padding: 8px; }
.msg-composer__picker[hidden] { display: none; }
.msg-composer__picker-in {
  width: 100%; height: 30px; padding: 0 8px;
  border: 1px solid var(--line); border-radius: var(--r-chip);
  background: var(--surface); color: var(--ink); font: inherit; font-size: 12.5px;
}
.msg-composer__picker-list { list-style: none; margin: 6px 0 0; padding: 0; max-height: 160px; overflow-y: auto; }
.msg-composer__picker-hit {
  display: block; width: 100%; text-align: left;
  padding: 6px 8px; border: 0; border-radius: var(--r-chip);
  background: none; color: var(--ink); font: inherit; font-size: 12.5px; cursor: pointer;
}
.msg-composer__picker-hit:hover { background: var(--surface-2); }
.msg-composer__picker-none { padding: 6px 8px; color: var(--ink-3); font-size: 12.5px; }

.msg-people {
  margin: 0 0 12px; padding-bottom: 10px;
  border-bottom: 1px solid var(--line-2);
  color: var(--ink-3); font-size: 12px;
}

.msg-page__body { max-height: 60vh; overflow-y: auto; }
.msg-page__composer { padding: 12px 16px 16px; border-top: 1px solid var(--line-2); }
.msg-page__membership { display: flex; align-items: flex-start; gap: 16px; margin-top: 12px; flex-wrap: wrap; }

/* "Message about this" — the only thing Messages draws outside its own pages.
   It borrows the platform button wholesale and adds nothing but the gap between
   the icon and the label, so a record header in any suite keeps its own
   spacing. The [hidden] override is here because .btn sets a display of its
   own, which beats the user agent's [hidden] rule (theme.css has the same note
   for .btn). */
.message-about { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; margin-top: 8px; }
/* Sized here rather than left to the host page: the suites this appears in do
   not all share a .btn svg rule, and an unsized <svg> renders at 300x150. */
.message-about svg { width: 15px; height: 15px; flex: none; }
.message-about[hidden] { display: none; }

/* The "About <record>" line on the new-conversation form, when the control was
   used to get there. */
.msg-new__about { margin: 0; font-size: 13px; color: var(--ink-2); max-width: 62ch; }

.msg-new { display: flex; flex-direction: column; gap: 16px; max-width: 620px; }
.msg-new__kind { border: 1px solid var(--line); border-radius: var(--r-chip); padding: 10px 12px; }
.msg-new__kind label { display: block; padding: 3px 0; }
.msg-new__people select, .msg-new__title input { width: 100%; }

/* ── Settings, and the bits R4 added ─────────────────────────────────────── */

.mdock__cap { flex: none; color: var(--ink-3); font-size: 11px; font-variant-numeric: tabular-nums; }

.msg-flash--ok { border-left-color: var(--ok); background: var(--ok-soft); }

.msg-settings { display: flex; flex-direction: column; gap: 22px; max-width: 640px; }
.msg-settings fieldset {
  border: 1px solid var(--line);
  border-radius: var(--r-chip);
  padding: 12px 14px;
  margin: 0;
}
.msg-settings legend { padding: 0 6px; font-weight: 700; font-size: 13px; }
.msg-settings__check { display: block; padding: 4px 0; }
.msg-settings p { margin: 8px 0 0; max-width: 60ch; }
.msg-settings button { margin-top: 10px; }

/* The tone element is functional, never visible. */
#mdock-tone { display: none; }

/* When, not what. The list carries a name, a time and a count — never a
 * preview of the message. See conversation-list.ejs for why. */
.msg-list__when { flex: none; color: var(--ink-3); font-size: 11px; white-space: nowrap; }

/* ── The nudges (R5) ─────────────────────────────────────────────────────────
 *
 * Non-blocking by construction: a sibling of the box, disabling nothing,
 * intercepting nothing. It sits ABOVE the field so a screen reader meets it on
 * the way in rather than after the text has been typed. */
.msg-composer__nudge {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0 0 8px;
  padding: 8px 10px;
  border: 1px solid var(--warn-icon);
  border-radius: var(--r-chip);
  background: var(--warn-soft);
  color: var(--ink);
  font-size: 12px;
  line-height: 1.45;
}

.msg-composer__nudge span { flex: 1; min-width: 0; }

.msg-composer__nudge-act {
  flex: none;
  padding: 3px 8px;
  border: 1px solid var(--warn-icon);
  border-radius: var(--r-chip);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 11.5px;
  cursor: pointer;
  white-space: nowrap;
}

.msg-composer__nudge-act:hover { background: var(--surface-2); }

.msg-composer__nudge-close {
  flex: none;
  padding: 0 2px;
  border: 0;
  background: none;
  color: var(--ink-2);
  font: inherit;
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
}

.msg-composer__nudge-close:hover { color: var(--danger); }

/* A mention, in the thread. Never colour alone — it is also bold. */
.msg__mention { font-weight: 700; color: var(--info); }

.msg-page__membership select { max-width: 220px; }

/* ── R6: filters, search, reading aids ───────────────────────────────────── */

.msg-filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 0 16px 12px; }
.msg-filters fieldset { display: flex; gap: 6px; border: 0; margin: 0; padding: 0; flex-wrap: wrap; }
.msg-filters__chip {
  padding: 3px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 12px;
  text-decoration: none;
}
.msg-filters__chip:hover { background: var(--surface-2); color: var(--ink); }
.msg-filters__chip.is-on { background: var(--ink-2); border-color: var(--ink-2); color: var(--surface); }
.msg-filters__dept select { font-size: 12px; }

.msg-search { display: flex; gap: 8px; margin-bottom: 12px; }
.msg-search input { flex: 1; min-width: 0; }

.msg-results { list-style: none; margin: 12px 0 0; padding: 0; }
.msg-result + .msg-result { border-top: 1px solid var(--line-2); }
.msg-result__link { display: block; padding: 10px 8px; border-radius: var(--r-chip); color: var(--ink); text-decoration: none; }
.msg-result__link:hover { background: var(--surface-2); }
.msg-result__who { display: block; font-size: 11.5px; color: var(--ink-3); }
.msg-result__snippet { display: block; margin: 2px 0; line-height: 1.5; }
.msg-result__snippet mark { background: var(--warn-soft); color: var(--ink); padding: 0 2px; border-radius: 3px; }
.msg-result__when { display: block; font-size: 11px; color: var(--ink-3); }

/* Day separators and the unread boundary. Both are <li role="separator"> so the
 * thread stays one list rather than several. */
.msg-day, .msg-newline { display: flex; align-items: center; gap: 10px; margin: 6px 0; }
.msg-day::before, .msg-day::after,
.msg-newline::before, .msg-newline::after { content: ""; flex: 1; height: 1px; background: var(--line-2); }
.msg-day span { font-size: 11px; color: var(--ink-3); white-space: nowrap; }
.msg-newline::before, .msg-newline::after { background: var(--msg-unread); opacity: .45; }
.msg-newline span { font-size: 11px; font-weight: 700; color: var(--msg-unread); white-space: nowrap; }

.msg__quote {
  display: block;
  margin: 0 0 4px;
  padding: 4px 8px;
  border-left: 3px solid var(--line);
  background: var(--surface-2);
  border-radius: 0 var(--r-chip) var(--r-chip) 0;
  color: var(--ink-3);
  font-size: 11.5px;
  text-decoration: none;
}
.msg__quote:hover { border-left-color: var(--ink-3); color: var(--ink-2); }
.msg__quote-who { font-weight: 600; margin-right: 6px; }
.msg__quote-tx { overflow-wrap: anywhere; }

.msg__reply { display: inline; margin-right: 10px; }
.msg-composer__replying { margin: 0; font-size: 11.5px; color: var(--ink-3); }

.msg-page__head-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-left: auto; }
/* The summary that lived here is a .btn now (it was always meant to be one --
   "rule AU23 turned into a button"). Its old grey 12px rule was removed rather
   than kept: at (0,1,1), loaded after theme.css, it out-ranked .btn and would
   have drawn a button-shaped box with caption-coloured text in it. */
.msg-record-instead ul { margin: 6px 0 0; padding-left: 18px; font-size: 12px; }
.msg-record-instead li { padding: 2px 0; }

/* ── Jump to latest, the skeleton and the inline error ───────────────────
 *
 * All three belong to messages-thread.js and none of them exist with
 * scripting off: a button that scrolls, a placeholder for a fetch and a
 * Retry are meaningless without it, so the markup does not carry them.
 *
 * The jump button floats over the bottom of whichever container is doing
 * the scrolling, which is why that container gets position: relative here
 * rather than in the layout above.
 */
.msg-scrollhost { position: relative; }

.msg-jump {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: 12px; z-index: 3;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border: 1px solid var(--line);
  border-radius: 999px; background: var(--surface); color: var(--ink);
  font-size: 12px; font-weight: 600; cursor: pointer;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.16);
}
.msg-jump::after {
  content: ""; width: 7px; height: 7px; margin-top: -3px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
}
.msg-jump:hover { background: var(--surface-2); }
.msg-jump:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }
/* Unread, so it carries the same blue the badges use. */
.msg-jump--new { background: var(--info); border-color: var(--info); color: #FFFFFF; }
.msg-jump--new:hover { background: var(--info); }

.msg-skeleton { display: flex; flex-direction: column; gap: 8px; padding: 10px 4px; }
.msg-skeleton__line {
  height: 30px; border-radius: var(--r-card); background: var(--sunk);
  animation: msg-skeleton-pulse 1.4s ease-in-out infinite;
}
.msg-skeleton__line:nth-child(2) { width: 72%; animation-delay: 0.15s; }
.msg-skeleton__line:nth-child(3) { width: 55%; align-self: flex-end; animation-delay: 0.3s; }
@keyframes msg-skeleton-pulse { 0%, 100% { opacity: 0.45; } 50% { opacity: 0.9; } }

.msg-error {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 6px 0; padding: 8px 10px; border: 1px solid var(--line);
  border-radius: var(--r-card); background: var(--surface-2);
  font-size: 12px; color: var(--ink-2);
}
.msg-error__retry {
  border: 1px solid var(--line-2); border-radius: var(--r-chip);
  background: var(--surface); color: var(--ink); cursor: pointer;
  padding: 4px 10px; font-size: 12px; font-weight: 600;
}
.msg-error__retry:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .msg-skeleton__line { animation: none; }
}

/* ── "Typing…" ───────────────────────────────────────────────────────────
 *
 * Three dots in a received bubble, on the left, where that person's next
 * message will appear. It carries no name: the poll payload has none to
 * give, and in a group the count goes in a data attribute rather than a
 * sentence naming anybody.
 *
 * aria-hidden, deliberately. A live region announcing "typing" every few
 * seconds to somebody using a screen reader is an interruption without
 * information; the message itself is what gets announced.
 */
.msg--typing { align-items: flex-start; }
.msg__bubble--typing {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 10px 14px; min-height: 0;
  background: var(--connect-bubble-received); border-radius: 18px;
}
.msg__dot {
  width: 6px; height: 6px; border-radius: 50%;
  /* The dots sit inside a received bubble, so they take its ink — white on
     the dark slate, dark on the light one. Pinned to #FFFFFF they vanished
     into the white bubble entirely. */
  background: var(--connect-bubble-received-ink); opacity: 0.55;
  animation: msg-typing-bounce 1.2s ease-in-out infinite;
}
.msg__dot:nth-child(2) { animation-delay: 0.16s; }
.msg__dot:nth-child(3) { animation-delay: 0.32s; }
@keyframes msg-typing-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.55; }
  30% { transform: translateY(-3px); opacity: 1; }
}
/* More than one person, in a group. A number, never a name. */
.msg--typing[data-typing]:not([data-typing=""])::after {
  content: attr(data-typing) " people are typing";
  margin-left: 8px; font-size: 11px; color: var(--ink-3);
}
@media (prefers-reduced-motion: reduce) {
  .msg__dot { animation: none; }
}

/* ── The composer: a round send, and a reply that says what it replies to ─ */
.msg-composer__send {
  flex: 0 0 34px; width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: var(--connect-bubble-sent); color: #FFFFFF;
}
.msg-composer__send:hover { background: var(--connect-bubble-sent-strong); }
.msg-composer__send:focus-visible { outline: 2px solid var(--info); outline-offset: 2px; }
/* Nothing written yet: still pressable, because a message can be a file on
   its own, and a disabled button that silently refuses is worse than one that
   tells you what is missing. */
.msg-composer__send svg { display: block; }

.msg-composer__replying {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0 0 6px; padding: 6px 8px;
  border-radius: var(--r-card); background: var(--surface-2);
}
.msg-composer__replying-bar {
  flex: 0 0 3px; align-self: stretch; border-radius: 2px;
  background: var(--connect-bubble-sent);
}
.msg-composer__replying-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.msg-composer__replying-who { font-size: 11px; font-weight: 600; color: var(--ink-2); }
.msg-composer__replying-line {
  font-size: 12px; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.msg-composer__replying-x {
  flex: 0 0 auto; color: var(--ink-3); text-decoration: none;
  font-size: 18px; line-height: 1; padding: 0 2px;
}
.msg-composer__replying-x:hover { color: var(--danger); }

/* Autogrow sets the height from script; this is the floor and the feel. */
.msg-composer__in { resize: none; transition: height 0.08s ease-out; }
@media (prefers-reduced-motion: reduce) {
  .msg-composer__in { transition: none; }
}

/* Edited, and it says so for good. Beside the run timestamp, in the same
   quiet grey: this is a fact about the message, not a warning about it. */
.msg__edited { margin: 2px 0 0; font-size: 11px; color: var(--ink-3); }
.msg--mine .msg__edited { text-align: right; }
.msg-composer--editing .msg-composer__in { outline: 2px solid var(--info); outline-offset: 1px; }

/* ── A phone ─────────────────────────────────────────────────────────────
 *
 * Below 480px the pop-up stops being a pop-up. A 360px-wide panel floating
 * over a 375px-wide page is a panel with no page left around it, so the
 * expanded dock takes the whole screen — which is what every messaging app
 * on a phone does, and for the same reason.
 *
 * COLLAPSED IT STAYS SMALL. The launcher is a bar at the bottom, not a
 * full-screen takeover of a page somebody is reading.
 *
 * safe-area-inset-bottom keeps the composer clear of the home indicator on
 * an iPhone; it is zero everywhere else, so it costs nothing.
 */
@media (max-width: 480px) {
  .mdock:not(.mdock--collapsed) {
    position: fixed; inset: 0; left: 0; right: 0; top: 0; bottom: 0;
    z-index: 1100;
  }
  .mdock:not(.mdock--collapsed) .mdock__body {
    width: 100%; height: 100%; max-height: none;
    border-radius: 0; border-left: 0; border-right: 0; border-bottom: 0;
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .mdock--collapsed { inset: auto 12px 12px 12px; }

  /* Touch targets. 34px is fine under a mouse and small under a thumb. */
  .mdock__iconbtn,
  .msg-composer__send { min-width: 40px; min-height: 40px; }

  /* A bubble that can grow to 78% of a 1200px page is a wall of text on a
     phone; on a narrow screen it may have nearly all of the width. */
  .msg__bubble { max-width: 90%; }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * THE CHARCOAL LOOK (2026-09-17)
 *
 * Asked for: "change the whole colour tone of the messages section to make it
 * more dark grey to stand out a bit ... make it look much nicer". Everything
 * below this line is that change, in one place.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ── [hidden] means hidden ──────────────────────────────────────────────────
 *
 * THE "COULD NOT LOAD EARLIER MESSAGES" BOX WAS NEVER AN ERROR. The skeleton,
 * the error and the jump button are built hidden by messages-thread.js, but
 * each class sets its own display, and a class selector beats the browser's
 * [hidden] rule. So all three sat on screen from the moment a thread opened,
 * whether or not anything had failed. The same trap drew an empty blue circle
 * on every conversation tile: the unread badge, hidden when there is nothing
 * unread, painted anyway. Each gets its own override. */
.msg-skeleton[hidden],
.msg-error[hidden],
.msg-jump[hidden],
.mdock__unread[hidden] { display: none; }

/* ── One palette, scoped to Messages ───────────────────────────────────────
 *
 * The dock and the full page redefine the platform's own tokens, so every
 * control inside them — lists, inputs, buttons, the error box — follows
 * without a rule of its own.
 *
 * IT FOLLOWS THE PAGE'S THEME (changed 2026-09-17). This block used to be
 * charcoal in BOTH themes, on the reasoning that a panel which changed
 * between day and night is one more thing to relearn. In practice that put a
 * near-black dock on top of a white HR page, which did not read as part of
 * the product at all — it read as something else's window parked on top. So
 * the dock now takes the page's theme and sits ONE STEP DARKER than the
 * surface behind it: enough separation to be a panel, not enough to be a
 * different application. The charcoal is still exactly what it was, under
 * the dark-theme block below.
 *
 * Light: text tokens against --surface (#E9ECF1) — ink 14.3:1, ink-2 6.8:1,
 * ink-3 4.9:1. Dark: against #1F2228 — ink 15.4:1, ink-2 9.1:1, ink-3 5.3:1.
 * Not estimated: check-connect-dock-contrast.js reads these values back out
 * of this file and redoes the arithmetic, and it is the same script that
 * asserts the light dock is actually darker than the page behind it. */
.mdock,
.msg-page {
  color-scheme: light;
  --canvas: #DCE0E7;
  --surface: #E9ECF1;
  --surface-2: #E0E4EA;
  --surface-3: #D6DBE3;
  --sunk: #DCE0E7;
  --ink: #1A1D22;
  --ink-2: #4A515B;
  --ink-3: #5F6672;
  --line: #C9CFD8;
  --line-2: #D9DEE5;
  --info: #1A66C2;
  --info-soft: rgba(26, 102, 194, .12);
  --danger: #B3372B;
  --danger-soft: rgba(179, 55, 43, .12);
  --warn-icon: #8A6100;
  --warn-soft: rgba(138, 97, 0, .14);
  --ok: #2E7D4F;
  --ok-soft: rgba(46, 125, 79, .13);
  --msg-accent: #4A515B;
  --msg-unread: #1A66C2;
  --msg-unread-soft: rgba(26, 102, 194, .12);
  --msg-glow: rgba(26, 102, 194, .16);
  /* The panel's own floor, a step under --surface so the thread reads as
     recessed into the dock rather than level with its chrome. */
  --msg-thread-bg:
    radial-gradient(120% 60% at 0% 0%, rgba(26, 102, 194, .05), transparent 60%),
    radial-gradient(90% 50% at 100% 100%, rgba(46, 125, 79, .04), transparent 60%),
    #E2E6ED;
  /* How heavy the dock's drop shadow is. A shadow tuned for a dark canvas is
     a smear on a light one. */
  --mdock-lift: rgba(27, 34, 48, .22);
  /* White on the deep light-mode --info. */
  --msg-chip-on-ink: #FFFFFF;
  color: var(--ink);
}

[data-theme="dark"] .mdock,
[data-theme="dark"] .msg-page {
  color-scheme: dark;
  --canvas: #16181D;
  --surface: #1F2228;
  --surface-2: #282C33;
  --surface-3: #30353D;
  --sunk: #16181D;
  --ink: #EDEFF2;
  --ink-2: #B9BFC8;
  --ink-3: #9098A4;
  --line: #3A3F48;
  --line-2: #2E3239;
  --info: #6AAEF2;
  --info-soft: rgba(106, 174, 242, .16);
  --danger: #F2786B;
  --danger-soft: rgba(242, 120, 107, .14);
  --warn-icon: #EAB34D;
  --warn-soft: rgba(234, 179, 77, .14);
  --ok: #5FC08A;
  --ok-soft: rgba(95, 192, 138, .14);
  --msg-accent: #C9CED6;
  --msg-unread: #6AAEF2;
  --msg-unread-soft: rgba(106, 174, 242, .16);
  --msg-glow: rgba(106, 174, 242, .18);
  --msg-thread-bg:
    radial-gradient(120% 60% at 0% 0%, rgba(106, 174, 242, .07), transparent 60%),
    radial-gradient(90% 50% at 100% 100%, rgba(95, 192, 138, .04), transparent 60%),
    #17191E;
  --mdock-lift: rgba(0, 0, 0, .6);
  /* Near-black on the pale dark-mode --info. */
  --msg-chip-on-ink: #0E1416;

  /* The received bubble goes back to slate on charcoal. The sent blue and its
     white ink are deliberately NOT here: they are the same in both themes. */
  --connect-bubble-received: #3A404A;
  --connect-bubble-received-strong: #30353E;
  --connect-bubble-received-ink: #FFFFFF;
  --connect-bubble-received-edge: rgba(255, 255, 255, .06);
}

/* Avatars follow the dock, and the dock now follows the page (2026-09-17).
   These are the deep tones, for the charcoal panel. They used to apply in
   BOTH themes — correct while the dock was always charcoal, and wrong the
   moment it was not: a light panel got eight dark discs in it, which is the
   one thing in the dock that still looked like it came from somewhere else.
   The light tones are the platform's own, at the top of this file. */
[data-theme="dark"] :is(.mdock, .msg-page) .msg-avatar--tone1 { background: #1D3247; color: #BBD6F2; }
[data-theme="dark"] :is(.mdock, .msg-page) .msg-avatar--tone2 { background: #1B3524; color: #B6DCC1; }
[data-theme="dark"] :is(.mdock, .msg-page) .msg-avatar--tone3 { background: #3B2618; color: #E6BE9F; }
[data-theme="dark"] :is(.mdock, .msg-page) .msg-avatar--tone4 { background: #2B2440; color: #C8BCE6; }
[data-theme="dark"] :is(.mdock, .msg-page) .msg-avatar--tone5 { background: #3A1F2B; color: #E8B3C6; }
[data-theme="dark"] :is(.mdock, .msg-page) .msg-avatar--tone6 { background: #143036; color: #A8D4DC; }
[data-theme="dark"] :is(.mdock, .msg-page) .msg-avatar--tone7 { background: #33290F; color: #DFCB92; }
[data-theme="dark"] :is(.mdock, .msg-page) .msg-avatar--tone8 { background: #262C34; color: #C3CBD6; }

/* The unread badge: a number on the sent-bubble blue, white text at 5.4:1. */
:is(.mdock, .msg-page) .mdock__unread,
[data-theme="dark"] :is(.mdock, .msg-page) .mdock__unread {
  background: var(--connect-bubble-sent);
  color: #FFFFFF;
  box-shadow: 0 0 0 2px var(--surface);
}
:is(.mdock, .msg-page) .mdock__unread--muted { background: var(--surface-3); color: var(--ink-2); }
:is(.mdock, .msg-page) .mdock__unread--mention { background: #C4402F; }

/* Buttons that take the platform's light-page colours are re-inked here. */
.mdock .btn--secondary,
.shell .page .msg-page .btn--secondary {
  background: var(--surface-2);
  border-color: var(--line);
  color: var(--ink);
}
.mdock .btn--secondary:hover,
.shell .page .msg-page .btn--secondary:hover {
  background: var(--surface-3);
  border-color: var(--ink-3);
  color: #FFFFFF;
}

/* ── The launcher ──────────────────────────────────────────────────────── */
/* The fallback accent, for a page whose suite the footer did not recognise
   (it sends "operations"). Every named suite below maps to tokens that are
   already theme-aware, so only this one has to state both. */
.mdock {
  --mdock-accent: #2D6D9B;
  --mdock-accent-2: #235478;
  --mdock-accent-soft: #E3EDF5;
}
/* Dark: the dark blue above all but vanished on the dark pill (KI-005); the named suites' own dark tokens are
   light (meridian-tokens.css), so the fallback follows them, on dark --info. */
[data-theme="dark"] .mdock {
  --mdock-accent: #5AA5D6;
  --mdock-accent-2: #5AA5D6;
  --mdock-accent-soft: #12293B;
}
.mdock[data-mdock-accent="leave"] { --mdock-accent: var(--leave); --mdock-accent-2: var(--leave-2); --mdock-accent-soft: var(--leave-soft); }
.mdock[data-mdock-accent="hr"] { --mdock-accent: var(--hr); --mdock-accent-2: var(--hr-2); --mdock-accent-soft: var(--hr-soft); }
.mdock[data-mdock-accent="audits"] { --mdock-accent: var(--audits); --mdock-accent-2: var(--audits-2); --mdock-accent-soft: var(--audits-soft); }
.mdock[data-mdock-accent="training"] { --mdock-accent: var(--training); --mdock-accent-2: var(--training-2); --mdock-accent-soft: var(--training-soft); }
.mdock[data-mdock-accent="su"] { --mdock-accent: var(--su); --mdock-accent-2: var(--su-2); --mdock-accent-soft: var(--su-soft); }
.mdock[data-mdock-accent="policies"] { --mdock-accent: var(--policies); --mdock-accent-2: var(--policies-2); --mdock-accent-soft: var(--policies-soft); }
.mdock[data-mdock-accent="workforce"] { --mdock-accent: var(--workforce); --mdock-accent-2: var(--workforce-2); --mdock-accent-soft: var(--workforce-soft); }
.mdock--collapsed .mdock__launcher,
[data-theme="dark"] .mdock--collapsed .mdock__launcher {
  position: relative;
  min-width: 184px;
  height: 44px;
  padding: 0 16px 0 14px;
  border: 1px solid color-mix(in srgb, var(--mdock-accent) 38%, var(--line));
  border-radius: 999px;
  /* The suite's accent over the dock's own surfaces rather than over a fixed
     charcoal, so the pill follows the page's theme with it. */
  background: linear-gradient(180deg, color-mix(in srgb, var(--mdock-accent) 24%, var(--surface-2)), color-mix(in srgb, var(--mdock-accent) 13%, var(--surface)));
  color: var(--ink);
  box-shadow: 0 12px 28px -12px var(--mdock-lift), 0 1px 0 rgba(255, 255, 255, .05) inset;
  transition: transform .15s ease, box-shadow .15s ease;
}
.mdock__launcher:hover {
  background: linear-gradient(180deg, color-mix(in srgb, var(--mdock-accent) 31%, var(--surface-3)), color-mix(in srgb, var(--mdock-accent) 18%, var(--surface-2)));
  transform: translateY(-1px);
}
/* Icon, word and unread count in one row, evenly spaced (Yusuf, 2026-10-12,
   item 0y: the word was centred absolutely, so the count sat on top of it).
   The word takes the room between them; the count ends the pill. */
.mdock--collapsed .mdock__launcher { gap: 10px; justify-content: flex-start; }
.mdock__launcher-tx { flex: 1 1 auto; min-width: 0; text-align: left; line-height: 1.2; white-space: nowrap; }
/* Lined up by what the eye sees, not by the boxes (item 0y, his second
   word: "make the icons and the messages are all in line"): the word's
   capitals sit 1px above its box's middle and the bubble (its tail aside)
   half a pixel below, so each is moved onto the pill's middle line --
   measured on the drawn pixels by check:connect-launcher-ui, in Instrument
   Sans (KI-019, 13/10/2026: the 2px first set here was measured in a
   fallback font, the check's pages missing the web font). */
.mdock--collapsed .mdock__launcher-tx { transform: translateY(1px); }
.mdock--collapsed .mdock__launcher .mdock__ic { transform: translateY(-0.5px); }
.mdock__launcher .mdock__unread,
[data-theme="dark"] .mdock__launcher .mdock__unread { flex: none; margin-left: 2px; box-shadow: none; line-height: 1; }
/* The bubble in the suite's deep colour (its lighter -2 shade measured under 3:1 on the pill: SU and Leave light,
   HR dark -- KI-005); on a dark pill a quarter lighter again. */
.mdock__ic { color: var(--mdock-accent); }
[data-theme="dark"] .mdock__ic { color: color-mix(in srgb, var(--mdock-accent) 75%, #FFFFFF); }
.mdock__launcher:focus-visible,
.mdock__iconbtn:focus-visible { outline-color: var(--mdock-accent-2); }

/* ── The panel ─────────────────────────────────────────────────────────── */
.mdock__body,
[data-theme="dark"] .mdock__body {
  border: 1px solid color-mix(in srgb, var(--mdock-accent) 30%, var(--line));
  border-radius: 18px;
  background: var(--surface);
  box-shadow: 0 28px 56px -20px var(--mdock-lift), 0 2px 8px color-mix(in srgb, var(--mdock-lift) 45%, transparent);
}
.mdock__head {
  padding: 9px 10px 9px 16px;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, color-mix(in srgb, var(--mdock-accent) 19%, var(--surface-2)), color-mix(in srgb, var(--mdock-accent) 10%, var(--surface)));
}
.mdock__title { color: var(--ink); }
.mdock--list .mdock__head,
.mdock--new .mdock__head { position: relative; }
.mdock--list .mdock__title,
.mdock--new .mdock__title {
  position: absolute;
  left: 50%;
  max-width: calc(100% - 150px);
  overflow: hidden;
  text-align: center;
  text-overflow: ellipsis;
  transform: translateX(-50%);
  white-space: nowrap;
  pointer-events: none;
}
.mdock__cap { color: var(--ink-3); }
.mdock__iconbtn { color: var(--ink-2); border-radius: 10px; }
/* A wash of the panel's own ink, so the hover darkens on a light dock and
   lightens on a dark one instead of always reaching for white. */
.mdock__iconbtn:hover { background: color-mix(in srgb, var(--ink) 10%, transparent); color: var(--ink); }
.mdock__filter { border-bottom-color: var(--line-2); }
.mdock__composer { background: var(--surface); border-top-color: var(--line-2); }

.mdock__thread { background: radial-gradient(110% 65% at 100% 0, color-mix(in srgb, var(--mdock-accent) 13%, transparent), transparent 68%), var(--msg-thread-bg); }
.msg-page__body { background: var(--msg-thread-bg); }
.msg-page__body { padding: 16px 18px; max-height: 62vh; }

/* ── The conversation list ─────────────────────────────────────────────── */
.msg-list { gap: 6px; }
.msg-list__link {
  padding: 10px 12px;
  border: 1px solid transparent;
  border-radius: 14px;
  background: var(--surface-2);
  transition: background .12s ease, border-color .12s ease;
}
.msg-list__link:hover { background: var(--surface-3); border-color: var(--line); }
.msg-list__item.is-active .msg-list__link {
  background: var(--surface-3);
  border-color: color-mix(in srgb, var(--mdock-accent-2) 45%, transparent);
  box-shadow: inset 3px 0 0 var(--mdock-accent-2);
}
.msg-list__item.is-unread .msg-list__link {
  background: linear-gradient(90deg, color-mix(in srgb, var(--mdock-accent) 12%, transparent), transparent 70%), var(--surface-2);
}
.msg-list__name { font-weight: 600; }
.msg-avatar { width: 38px; height: 38px; box-shadow: 0 0 0 2px rgba(255, 255, 255, .05); }
.msg-list__section { color: var(--ink-3); }

/* The row menu shows when it is wanted: on hover, on focus, or when open. It
   sits over the tile's right edge rather than on top of the time. */
.msg-list__menu {
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  opacity: 0;
  transition: opacity .12s ease;
}
.msg-list__item:hover .msg-list__menu,
.msg-list__menu:focus-within,
.msg-list__menu[open] { opacity: 1; }
.msg-list__menu-btn { background: var(--surface-3); color: var(--ink-2); }
.msg-list__menu-panel { background: var(--surface-2); border-color: var(--line); box-shadow: 0 12px 28px -10px rgba(0, 0, 0, .6); }
.msg-list__menu-panel button:hover { background: var(--surface-3); }
@media (hover: none) {
  .msg-list__menu { opacity: 1; top: 6px; transform: none; }
}

/* ── The thread ────────────────────────────────────────────────────────── */

/* The bubble and its menu move together. The width limit moves from the
   bubble to the pair, so the three-dot button has room beside it and the
   bubble does not reflow when hovering reveals it. */
.msg__wrap {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  max-width: 80%;
}
.msg--mine .msg__wrap { align-items: flex-end; }
.msg__wrap .msg__bubble { max-width: 100%; }

.msg__bubble {
  padding: 8px 13px;
  border-radius: 20px;
  font-size: 13.5px;
  box-shadow: 0 1px 1px rgba(0, 0, 0, .22);
}
.msg:not(.msg--mine) .msg__bubble { border: 1px solid var(--connect-bubble-received-edge); }
.msg--mine .msg__bubble {
  background: linear-gradient(180deg, #1470E0 0%, var(--connect-bubble-sent) 100%);
  color: var(--connect-bubble-sent-ink);
  box-shadow: 0 1px 1px rgba(0, 0, 0, .25), 0 6px 16px -10px rgba(10, 102, 214, .9);
}
.msg--run-end .msg__bubble { border-bottom-left-radius: 6px; }
.msg--mine.msg--run-end .msg__bubble { border-bottom-left-radius: 20px; border-bottom-right-radius: 6px; }
.msg--withdrawn .msg__bubble,
.msg--mine.msg--withdrawn .msg__bubble {
  background: transparent;
  border: 1px dashed var(--line);
  box-shadow: none;
  color: var(--ink-3);
}

/* A record named inside a bubble keeps the bubble's text colour: bold and the
   dotted underline carry it. Blue on a blue bubble was barely readable. */
.msg__bubble .msg__mention { color: inherit; text-decoration-color: currentColor; }

/* ── The message menu ─────────────────────────────────────────────────── */

/* SHOWS ON THE MESSAGE IT ACTS ON, not on all of them at once. A dot menu
   beside every bubble reads as part of the message rather than as a control,
   and forty of them down a thread is forty things to look past.
   `.msg-list__menu` above does the same for a conversation row; this is that
   rule applied to a bubble.
   Three ways in, because hover is only one of them:
     :hover           — the pointer case, and the one that was asked for;
     :focus-within    — the keyboard case. opacity (not display or visibility)
                        is what makes this work: the button stays in the tab
                        order while invisible, so tabbing to it reveals it
                        rather than skipping it;
     [open]           — so the menu does not vanish out from under the pointer
                        when it moves off the bubble to reach the panel. */
.msg__menu {
  position: absolute;
  top: 50%;
  right: -34px;
  z-index: 3;
  transform: translateY(-50%);
  opacity: 0;
  transition: opacity .12s ease;
}
.msg:hover .msg__menu,
.msg__wrap:focus-within .msg__menu,
.msg__menu:focus-within,
.msg__menu[open] { opacity: 1; }

/* A touch screen has no hover at all, so the menu would be unreachable by the
   rule above. It stays put there — the same exception .msg-list__menu makes. */
@media (hover: none) {
  .msg__menu { opacity: 1; }
}
.msg--mine .msg__menu { right: auto; left: -34px; }
.msg__menu-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0 0 3px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--ink-2);
  cursor: pointer;
  font-size: 20px;
  line-height: 1;
  list-style: none;
}
.msg__menu-btn::-webkit-details-marker { display: none; }
.msg__menu-btn::marker { content: ''; }
.msg__menu-btn:hover,
.msg__menu[open] .msg__menu-btn { background: color-mix(in srgb, var(--mdock-accent) 45%, var(--surface-3)); color: #FFFFFF; }
.msg__menu-btn:focus-visible { outline: 2px solid var(--mdock-accent-2); outline-offset: 2px; }
.msg__menu-panel {
  position: absolute;
  top: 32px;
  right: 0;
  z-index: 4;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-2);
  box-shadow: 0 8px 18px -8px rgba(0, 0, 0, .7);
}
.msg--mine .msg__menu-panel { right: auto; left: 0; }
.msg__menu-panel form,
.msg__menu-panel .msg__reply,
.msg__withdraw { display: contents; margin: 0; }

.msg__act {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  text-decoration: none;
  transition: background .1s ease, color .1s ease;
}
.msg__act svg { width: 15px; height: 15px; flex: none; }
.msg__act:hover { background: var(--surface-3); color: #FFFFFF; }
.msg__act:focus-visible { outline: 2px solid var(--mdock-accent-2); outline-offset: 1px; }
.msg__act--danger:hover { background: var(--danger-soft); color: var(--danger); }
.msg__act.is-done { color: var(--ok); }


/* ── When, edited, seen: one quiet line ────────────────────────────────── */
.msg__metaline {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 3px 10px 0;
  font-size: 10.5px;
  color: var(--ink-3);
}
.msg--mine .msg__metaline { justify-content: flex-end; }
.msg__metaline > p { margin: 0; }
.msg__metaline > p + p::before { content: "·"; margin-right: 6px; color: var(--ink-3); }
.msg__metaline .msg__when-run,
.msg__metaline .msg__edited,
.msg__metaline .msg__status { margin: 0; text-align: inherit; }
.msg__metaline .msg__status { color: var(--info); font-weight: 600; }

/* ── Separators, the top of the thread, and new arrivals ───────────────── */
.msg-day span {
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.msg-newline span { padding: 2px 8px; border-radius: 999px; background: var(--info-soft); }

.msg-start { align-self: center; margin: 2px 0 12px; }
.msg-start span {
  display: inline-block;
  padding: 4px 12px;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--ink-3);
  font-size: 11px;
}

.msg-skeleton__line { background: var(--surface-2); }

/* The jump button sits inside the scrolling area, after the messages, and
   sticks to the bottom of what is visible — so it floats over the thread and
   never over the composer. */
.msg-jump {
  position: sticky;
  left: auto;
  bottom: 10px;
  transform: none;
  display: flex;
  width: max-content;
  margin: 8px auto 0;
  background: var(--surface-3);
  border-color: var(--line);
  color: var(--ink);
  box-shadow: 0 8px 20px -8px rgba(0, 0, 0, .7);
}
.msg-jump:hover { background: var(--surface-3); }
.msg-jump--new,
.msg-jump--new:hover { background: var(--connect-bubble-sent); border-color: var(--connect-bubble-sent); color: #FFFFFF; }

@keyframes msg-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}
.msg--fresh { animation: msg-in .22s ease-out both; }

/* ── The composer ──────────────────────────────────────────────────────── */
.msg-composer__in {
  padding: 9px 13px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--sunk);
  color: var(--ink);
}
.msg-composer__in::placeholder { color: var(--ink-3); }
.msg-composer__in:focus {
  outline: none;
  border-color: rgba(106, 174, 242, .7);
  box-shadow: 0 0 0 3px var(--msg-glow);
}
.msg-composer__send {
  background: linear-gradient(180deg, #1470E0, var(--connect-bubble-sent));
  box-shadow: 0 6px 14px -6px rgba(10, 102, 214, .9);
  transition: transform .12s ease;
}
.msg-composer__send:hover { transform: scale(1.06); }

/* ── The full page ─────────────────────────────────────────────────────── */
/* The full page is the dock's chrome at a different size, so it follows the
   theme the same way. These four were missed when the dock was moved off
   charcoal: the heading stayed near-white and landed on the light panel at
   1.09:1. */
.shell .page .msg-page .panel { box-shadow: 0 18px 40px -24px var(--mdock-lift); }
.shell .page .msg-page .panel__head {
  border-bottom-color: var(--line);
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  color: var(--ink);
}
.msg-page .t-h3,
.msg-page h2 { color: var(--ink); }
.msg-page .text-muted,
.msg-page .t-sm { color: var(--ink-3); }
/* :not(.btn) because this out-ranks .btn--primary/.btn--secondary (0,1,1
   against 0,1,0, and it loads later) -- without it every summary drawn as a
   button on this page would lose its button ink to caption grey. */
.msg-page summary:not(.btn) { color: var(--ink-2); cursor: pointer; }
.msg-page select,
.msg-page input[type="text"],
.msg-page input[type="search"] {
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--sunk);
  color: var(--ink);
}
.msg-record-instead a,
.msg-page .msg-empty a { color: #8EC1F5; }
.msg-filters__chip { background: var(--surface-2); border-color: var(--line); color: var(--ink-2); }
.msg-filters__chip:hover { background: var(--surface-3); color: var(--ink); }
/* The ink on the selected chip has to follow --info, which is a deep blue in
   light and a pale one in dark — so a single literal is wrong in one of them.
   It was #0E1416, which is right on the pale dark-mode blue and 3.29:1 on the
   light one. */
.msg-filters__chip.is-on { background: var(--info); border-color: var(--info); color: var(--msg-chip-on-ink); }
.msg-page__composer { background: var(--surface); }
.msg-people { color: var(--ink-3); border-bottom-color: var(--line-2); }

@media (prefers-reduced-motion: reduce) {
  .msg--fresh,
  .msg-list__link,
  .mdock__launcher,
  .msg-composer__send { animation: none; transition: none; }
  .mdock__launcher:hover,
  .msg-composer__send:hover { transform: none; }
}

/* Presence on a direct conversation's avatar (2026-09-25): green active now,
   orange away, red offline -- bottom right, ringed in the panel's own colour so
   it reads on any avatar tone. The row's accessible name says it in words. */
.msg-avatar { position: relative; }
.msg-presence {
  position: absolute; right: -2px; bottom: -2px;
  width: 10px; height: 10px; border-radius: 50%;
  border: 2px solid var(--surface); box-sizing: content-box;
}
.msg-presence--active { background: var(--ok, #2E794D); }
.msg-presence--away { background: #E8820C; }
.msg-presence--offline { background: var(--danger, #B0332A); }

/* ── Images (2026-09-26): PNG only, pasted or attached ───────────────────── */
.msg-composer__attach {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px; border-radius: 999px; cursor: pointer;
  color: var(--ink-2); font-size: 13px; line-height: 1;
}
.msg-composer__attach:hover { background: var(--connect-bubble-received-strong); color: var(--ink); }
.msg-composer__attach:focus-within { outline: 2px solid var(--info); outline-offset: 2px; }
/* The compact dock is narrow: the icon alone, its name kept for screen readers via title. */
.mdock .msg-composer__attach-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.msg-composer__image {
  display: flex; align-items: center; gap: 10px;
  margin: 6px 0; padding: 6px 8px;
  border: 1px solid var(--line); border-radius: 10px;
}
.msg-composer__image[hidden] { display: none; }
.msg-composer__image img { max-width: 96px; max-height: 64px; border-radius: 6px; object-fit: cover; }
.msg-composer__image-name { flex: 1 1 auto; min-width: 0; font-size: 12px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-composer__image-x {
  flex: 0 0 auto; width: 26px; height: 26px; border: 0; border-radius: 50%;
  background: transparent; color: var(--ink-3); font-size: 18px; cursor: pointer;
}
.msg-composer__image-x:hover { background: var(--connect-bubble-received-strong); }
.msg__bubble--image { padding: 4px; }
.msg__bubble--image .msg__body { padding: 4px 8px 4px; }
.msg__image { display: block; }
.msg__image img {
  display: block; max-width: min(320px, 100%); max-height: 320px;
  border-radius: 10px; object-fit: contain; background: var(--connect-bubble-received-strong);
}
.mdock .msg__image img { max-width: 100%; max-height: 220px; }
