/* =====================================================================
   Messages App
   Modern iMessage layout and geometry, Retrium OS typography and chrome.
   ===================================================================== */

/* Portrait, phone-shaped: ~1:1.7. Height is clamped against the viewport
   instead of hardcoded so the window never opens taller than the desktop area
   on a short laptop screen. Selector stays a bare id to match the sizing
   convention in css/main.css and to let css/responsive.css override it. */
#messages {
  width: 420px;
  height: min(720px, calc(100vh - 170px));
  max-width: calc(100vw - 48px);
  font-family: "VT323", monospace;
}

/* Maximize keeps the phone silhouette and grows to full height rather than
   stretching into a slab. `.window.maximized` in css/main.css pins inset: 0,
   so an explicit width plus auto margins centers it. These need !important to
   beat the inline width/height that maximizeWindow() writes. */
#messages.window.maximized {
  width: min(560px, 100vw) !important;
  height: 100vh !important;
  margin: 0 auto !important;
}

/* Scoped to the window id so it outranks `.window .content` in css/main.css.
   Height still comes from that rule's title-bar math. */
#messages .msg-app {
  display: flex;
  padding: 0;
  overflow: hidden;
  background: #f0f0f0;
}

/* Two-color transcript, flat fills only. Incoming is a pale mint wash with
   black text, outgoing is the saturated iMessage blue with white text. The
   value asymmetry is what separates the two sides; the 3px black border does
   the structural work, so the fills stay quiet. */
.msg-layout {
  --msg-list-bg: #f0f0f0;
  --msg-row-bg: #e0e0e0;
  --msg-transcript-bg: #f7f7f7;
  --msg-in-bg: #d3f3da;
  --msg-out-bg: #007aff;
  --msg-quiet: #5a5a5a;
  --msg-tone-clay: #c98276;
  --msg-tone-mustard: #d9b45c;
  --msg-tone-teal: #6fa8a0;
  --msg-tone-lavender: #9a93c4;
  --msg-tone-sage: #8f9e72;
  --msg-tone-steel: #5f676e;
  display: flex;
  flex: 1;
  /* min-width: 0 is load-bearing, not defensive. As a flex item this box is
     floored at its own min-content width, and .msg-thread-name is nowrap, so
     the longest sender name made that floor ~429px inside a 414px window —
     the pane was pushed past the right border and the window clipped the
     search field's edge and the last digit of every date. Every flex item on
     the path from here down to the row carries this for the same reason. */
  min-width: 0;
  min-height: 0;
  background: var(--msg-transcript-bg);
}

/* --- Conversation list --- */

/* Single pane at every width: the list and the conversation are alternate
   full-width views, never side by side. `.showing-conversation` on .msg-layout
   is the only thing that swaps them. */
.msg-list {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  flex-direction: column;
  overflow: hidden;
  background: var(--msg-list-bg);
}

.msg-layout.showing-conversation .msg-list {
  display: none;
}

.msg-search {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 10px;
  padding: 14px 18px;
  border-bottom: 2px solid #000;
  background: var(--msg-row-bg);
}

.msg-search-icon {
  flex-shrink: 0;
  color: #000;
  font-size: 22px;
  line-height: 1;
}

.msg-search-input {
  flex: 1;
  min-width: 0;
  padding: 6px 14px;
  border: 3px solid #000;
  /* Same pill as the compose field — Messages already owns the rounded-field
     exception, and a square search bar was the odd one out. */
  border-radius: 19px;
  background: #fff;
  color: #000;
  font-family: "VT323", monospace;
  font-size: 19px;
  line-height: 1.1;
}

.msg-search-input::placeholder {
  color: #8a8a8a;
}

.msg-search-input:focus {
  outline: none;
  box-shadow: inset 0 0 0 2px #000;
}

.msg-count {
  flex-shrink: 0;
  margin: 0;
  padding: 7px 18px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.22);
  background: var(--msg-list-bg);
  color: var(--msg-quiet);
  font-size: 17px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

.msg-threads {
  flex: 1;
  min-width: 0;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  padding: 4px 0 10px;
}

.msg-thread-row {
  appearance: none;
  display: flex;
  align-items: center;
  gap: 12px;
  box-sizing: border-box;
  /* Buttons default to min-width:auto, which sized the row to its contents and
     shoved the stamp past the window edge. Force the row to stay inside. */
  width: 100%;
  min-width: 0;
  max-width: 100%;
  padding: 13px 16px 13px 14px;
  border: 0;
  border-bottom: 1px solid rgba(0, 0, 0, 0.16);
  background: transparent;
  color: #000;
  font-family: "VT323", monospace;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
}

.msg-thread-row:hover {
  background: #e6e6e6;
}

.msg-thread-row.active,
.msg-thread-row.active:hover {
  background: #000;
  color: #fff;
}

.msg-thread-dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  margin-right: -4px;
  border-radius: 50%;
  background: transparent;
}

.msg-thread-row.unread .msg-thread-dot {
  background: #000;
}

.msg-thread-row.unread.active .msg-thread-dot {
  background: #fff;
}

.msg-avatar {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  /* Large enough that the stick-figure portraits stay readable in the list;
     34px hid the hair and glasses. 2px ring in the list keeps the bigger disc
     from eating the row; the header still uses the heavier ring below. */
  width: 52px;
  height: 52px;
  border: 2px solid #000;
  border-radius: 50%;
  background: #fff;
  color: #000;
  font-size: 20px;
  line-height: 1;
  overflow: hidden;
}

/* Portrait discs use the same chrome as the tone initials; the framing is
   baked into the 320px square file the way dash-avatar.webp is, so cover
   with no object-position is enough. */
.msg-avatar-portrait {
  padding: 0;
  background: #fff;
}

.msg-avatar-portrait img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.msg-thread-row.active .msg-avatar {
  border-color: #fff;
}

/* Header disc is a real button so it can open the contact card without the
   row-click machinery. Resets every UA chrome; the circle is the affordance. */
.msg-avatar-btn {
  appearance: none;
  margin: 0;
  padding: 0;
  font: inherit;
  cursor: pointer;
}

.msg-avatar-btn:focus-visible {
  outline: 2px solid #000;
  outline-offset: 2px;
}

/* One muted tone per sender, assigned in js/messages.js so a person's color is
   fixed. Desaturated on purpose so they sit beside the mint and blue bubbles
   instead of competing with them. Text color is picked per tone rather than
   shared: every pairing here clears 4.5:1 against its background. Steel is the
   only light-on-dark avatar, which is what makes the system sender read as a
   machine rather than a person. Declared after .msg-avatar so it wins on
   source order at equal specificity. */
.msg-tone-clay {
  background: var(--msg-tone-clay);
  color: #000;
}

.msg-tone-mustard {
  background: var(--msg-tone-mustard);
  color: #000;
}

.msg-tone-teal {
  background: var(--msg-tone-teal);
  color: #000;
}

.msg-tone-lavender {
  background: var(--msg-tone-lavender);
  color: #000;
}

.msg-tone-sage {
  background: var(--msg-tone-sage);
  color: #000;
}

.msg-tone-steel {
  background: var(--msg-tone-steel);
  color: #fff;
}

/* VT323 ships a single weight, so font-weight here would only synthesize a
   muddy faux-bold. Hierarchy comes from size, color, and opacity instead. */
.msg-thread-name {
  flex: 1 1 auto;
  min-width: 0;
  padding-right: 8px;
  font-size: 23px;
  line-height: 1.1;
  letter-spacing: 0.3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Emphasis for unread rows is carried by the dot and by full-strength names;
   already-read rows recede instead of unread rows getting heavier. */
.msg-thread-row.read .msg-thread-name {
  opacity: 0.7;
}

.msg-thread-stamp {
  flex: 0 0 auto;
  margin-left: auto;
  font-family: "VT323", monospace;
  font-size: 16px;
  line-height: 1;
  color: var(--msg-quiet);
  opacity: 0.85;
  white-space: nowrap;
}

.msg-thread-row.active .msg-thread-stamp {
  color: #d8d8d8;
}

.msg-empty {
  margin: 0;
  padding: 22px 16px;
  color: var(--msg-quiet);
  font-size: 20px;
  line-height: 1.2;
  text-align: center;
}

/* --- Conversation --- */

.msg-conversation {
  display: none;
  flex: 1;
  min-width: 0;
  min-height: 0;
  flex-direction: column;
  background: var(--msg-transcript-bg);
}

.msg-layout.showing-conversation .msg-conversation {
  display: flex;
}

.msg-conversation-head {
  position: relative;
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  padding: 14px 18px 14px;
  border-bottom: 2px solid #000;
  background: var(--msg-row-bg);
}

.msg-back {
  appearance: none;
  position: absolute;
  left: 16px;
  top: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  margin-top: -17px;
  border: 2px solid #000;
  background: #f0f0f0;
  color: #000;
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.9);
  font-family: "VT323", monospace;
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
}

.msg-back:active {
  background: #000;
  color: #fff;
}

.msg-conversation-id {
  display: flex;
  min-width: 0;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  text-align: center;
}

.msg-avatar-lg {
  width: 72px;
  height: 72px;
  border-width: 3px;
  font-size: 28px;
}

/* Contact card opened from the conversation header. Reuses .message-window
   geometry so phones already have a size; only the body layout lives here. */
.msg-contact-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 18px 18px 16px;
  text-align: center;
  background: #f0f0f0;
}

.msg-contact-photo {
  width: 148px;
  height: 148px;
  margin-bottom: 8px;
  border: 3px solid #000;
  border-radius: 50%;
  background: #fff;
  object-fit: cover;
  box-shadow: 5px 5px 0 rgba(0, 0, 0, 0.9);
}

.msg-contact-name {
  font-family: "VT323", monospace;
  font-size: 26px;
  line-height: 1.05;
  color: #000;
}

.msg-contact-handle {
  margin-bottom: 10px;
  font-family: "VT323", monospace;
  font-size: 16px;
  line-height: 1.1;
  color: var(--msg-quiet);
  overflow-wrap: anywhere;
}

.msg-contact-note-label {
  align-self: stretch;
  margin-top: 4px;
  padding-top: 10px;
  border-top: 2px solid rgba(0, 0, 0, 0.2);
  font-family: "VT323", monospace;
  font-size: 15px;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--msg-quiet);
}

.msg-contact-note {
  margin: 4px 0 0;
  font-family: "VT323", monospace;
  font-size: 20px;
  line-height: 1.25;
  color: #000;
}

.msg-contact-saved {
  margin-top: 8px;
  font-family: "VT323", monospace;
  font-size: 15px;
  line-height: 1.1;
  color: var(--msg-quiet);
}

.msg-conversation-name {
  max-width: 100%;
  font-size: 21px;
  line-height: 1;
  color: #000;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.msg-conversation-handle {
  max-width: 100%;
  font-size: 15px;
  line-height: 1.05;
  color: var(--msg-quiet);
  overflow-wrap: anywhere;
}

/* --- Transcript --- */

.msg-transcript {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 4px 22px 22px;
  background: var(--msg-transcript-bg);
}

.msg-stamp {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 14px 0 10px;
  background: var(--msg-transcript-bg);
  color: var(--msg-quiet);
  font-size: 17px;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 1px;
}

.msg-stamp-day,
.msg-stamp-time {
  font-family: "VT323", monospace;
  color: #000;
}

.msg-stamp-at {
  text-transform: none;
  letter-spacing: 0;
}

.msg-cluster {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding-bottom: 12px;
}

.msg-row {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.msg-row.in {
  align-items: flex-start;
}

.msg-row.out {
  align-items: flex-end;
}

.msg-row.run-end {
  margin-bottom: 9px;
}

/* Rounded bubble geometry is an intentional iMessage borrowing; the inner
   corner of a grouped run tightens the way iMessage groups its bubbles. */
.msg-bubble {
  position: relative;
  max-width: 74%;
  padding: 6px 13px 7px;
  border: 3px solid #000;
  border-radius: 19px;
  background: var(--msg-in-bg);
  color: #000;
  font-size: 21px;
  line-height: 1.26;
  overflow-wrap: anywhere;
}

.msg-row.out .msg-bubble {
  background: var(--msg-out-bg);
  color: #fff;
}

.msg-row.in:not(.run-start) .msg-bubble {
  border-top-left-radius: 7px;
}

.msg-row.in:not(.run-end) .msg-bubble {
  border-bottom-left-radius: 7px;
}

.msg-row.out:not(.run-start) .msg-bubble {
  border-top-right-radius: 7px;
}

.msg-row.out:not(.run-end) .msg-bubble {
  border-bottom-right-radius: 7px;
}

/* Inverted highlight so lore tokens stay legible on the pale mint fill and
   the saturated blue alike. A white chip washes out against the mint. */
.msg-bubble strong {
  padding: 0 3px;
  background: #000;
  color: #fff;
  font-weight: normal;
}

/* A photo attachment. No shipped thread carries one at the moment — the café
   photograph these rules were written for moved into the Journal — but the
   capability is kept on purpose alongside `renderEntryPhoto()` in
   js/messages.js, because a story-driven thread will want pictures again.
   Do not sweep these two rules as unused.

   The bubble tightens to a thin frame so the fill reads as
   a border around the image rather than as padding under it, and the frame is
   what connects the photo to the tail below it. Width stays a percentage, so
   the photo shrinks with the window instead of overflowing it at 366px or on a
   phone. Photos get a little more of the pane than text does, because a
   274px-wide bubble of prose is comfortable and a 274px-wide photo is a
   thumbnail. */
.msg-bubble.has-photo {
  max-width: 82%;
  padding: 4px;
}

/* border-radius: inherit copies the bubble's computed corners, so the photo
   follows the same tightening a grouped run applies without restating any of
   it. The width/height attributes in js/messages.js give the element its
   intrinsic ratio, which reserves the row's height before the lazily loaded
   file arrives — without them the transcript would jump as the photo lands. */
.msg-photo {
  display: block;
  width: 100%;
  height: auto;
  border-radius: inherit;
}

/* Bubble tail, drawn only on the final message of a run. Same rotated-square
   idiom as Morphy's speech bubble in css/trash.css. */
.msg-row.run-end .msg-bubble::after {
  content: "";
  position: absolute;
  bottom: -8px;
  width: 14px;
  height: 14px;
  border-right: 3px solid #000;
  border-bottom: 3px solid #000;
  border-bottom-right-radius: 3px;
  transform: rotate(45deg);
}

.msg-row.in.run-end .msg-bubble::after {
  left: 7px;
  background: var(--msg-in-bg);
}

.msg-row.out.run-end .msg-bubble::after {
  right: 7px;
  background: var(--msg-out-bg);
}

.msg-tapback {
  position: absolute;
  top: -15px;
  min-width: 26px;
  padding: 1px 5px 2px;
  border: 3px solid #000;
  border-radius: 13px;
  background: #fff;
  color: #000;
  font-family: "VT323", monospace;
  font-size: 17px;
  line-height: 1.05;
  text-align: center;
}

.msg-row.in .msg-tapback {
  right: -14px;
}

.msg-row.out .msg-tapback {
  left: -14px;
}

.msg-receipt {
  padding: 0 4px;
  color: var(--msg-quiet);
  font-family: "VT323", monospace;
  font-size: 16px;
  line-height: 1;
  letter-spacing: 1px;
  text-transform: uppercase;
}

/* --- Compose bar --- */

.msg-compose {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 10px;
  padding: 12px 18px;
  border-top: 2px solid #000;
  background: var(--msg-row-bg);
}

.msg-compose-field {
  flex: 1;
  min-width: 0;
  padding: 6px 14px;
  border: 3px solid #000;
  border-radius: 19px;
  background: #fff;
  color: #000;
  font-family: "VT323", monospace;
  font-size: 20px;
  line-height: 1.2;
}

.msg-compose-field::placeholder {
  color: #8a8a8a;
}

.msg-compose-send {
  appearance: none;
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 3px solid #000;
  border-radius: 50%;
  background: #f0f0f0;
  color: #000;
  font-family: "VT323", monospace;
  font-size: 22px;
  line-height: 1;
}

.msg-compose-field:disabled,
.msg-compose-send:disabled {
  color: #8a8a8a;
  cursor: not-allowed;
}

/* --- Retro scrollbars --- */

.msg-threads,
.msg-transcript {
  scrollbar-width: auto;
  scrollbar-color: #9a9a9a #ececec;
}

.msg-threads::-webkit-scrollbar,
.msg-transcript::-webkit-scrollbar {
  width: 13px;
}

.msg-threads::-webkit-scrollbar-track,
.msg-transcript::-webkit-scrollbar-track {
  border: 2px solid #000;
  background: #ececec;
}

.msg-threads::-webkit-scrollbar-thumb,
.msg-transcript::-webkit-scrollbar-thumb {
  border: 2px solid #000;
  background: #9a9a9a;
}
