/* THE ONE CHAT FRAME (docs/design-one-chat-frame.md). Header / thread /
   dock / frame, drawn once for every conversation in the product — the
   peer pane, the meeting thread, the Coach, a rung's interview (in the
   chat route and inside a feed slide), the quiz, the opening, the feedback
   interview and the partner builder's chat. The bubbles, dots, skeletons
   and composer come from thread.css; this sheet is the card around them.

   Loaded by the user shell (index.html, render-blocking beside chat.css)
   and by the partner shell (builder/panel.js). Tokens only, so light and
   dark are one definition, and the partner portal — which carries the same
   app.css tokens — draws the identical frame. */

/* ---------------------------------------------------------------- frame */

/* A bordered card that OWNS its scroll: the thread row is the only thing
   in it that scrolls, the header and the dock stay put, and the host never
   scrolls behind it (the drifting "Skip this one" over the deck's rail was
   a host scrolling behind an unframed dock). Sized by the host — height
   comes from the row or cell it is placed in. */
.chat-frame {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  height: 100%;
  min-height: 0;
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  background: var(--canvas);
  position: relative;
}

/* --------------------------------------------------------------- header */

.chat-head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 18px 12px;
  border-bottom: 1px solid var(--line);
  min-width: 0;
}
.chat-head__names { min-width: 0; flex: 1; }
.chat-head__names h2 {
  font-size: 17px;
  margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: flex; align-items: center; gap: 8px;
}
.chat-head__names h2 .rung { color: var(--accent-text); width: 12px; height: 12px; flex: none; }
.chat-head__title { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* The subline is ONE sentence in the record voice, and never wraps. */
.chat-head__note {
  margin-top: 3px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-head__note:empty { display: none; }

.chat-back {
  flex: none;
  border: 0; background: transparent; color: var(--accent-text);
  font-size: 20px; cursor: pointer; padding: 4px 8px; border-radius: var(--r-s);
  line-height: 26px;
}

/* Header actions: quiet controls on the right. A surface hands in nodes. */
.chat-head > .btn--ghost.btn--sm, .chat-head > .chat-head__act { flex: none; }

/* The ⋯ menu — the rare acts. */
.chat-menu { position: relative; flex: none; }
.chat-menu > button {
  border: 0; background: transparent; color: var(--muted);
  font-size: 18px; letter-spacing: .1em;
  padding: 6px 10px; border-radius: var(--r-s); cursor: pointer;
  transition: background var(--t), color var(--t), transform var(--t);
}
.chat-menu > button:hover { background: var(--surface); color: var(--text); }
.chat-menu__pop {
  position: absolute; right: 0; top: calc(100% + 6px);
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  box-shadow: var(--shadow-2);
  padding: 6px;
  min-width: 220px;
  z-index: 20;
}
.chat-menu__pop button {
  display: block; width: 100%; text-align: left;
  border: 0; background: transparent; color: var(--text);
  font: inherit; font-size: 14px;
  padding: 10px 12px; border-radius: var(--r-s); cursor: pointer;
}
.chat-menu__pop button:hover { background: var(--surface); }
.chat-menu__pop button[aria-busy="true"],
.chat-menu__pop button:disabled { opacity: .55; pointer-events: none; }
.chat-menu__pop .whisper { padding: 4px 12px 8px; font-size: 12px; color: var(--muted); }

/* The header's skeleton bars, before the name arrives. */
.skel--name { display: inline-block; width: 130px; height: 16px; border-radius: 8px; }
.skel--note { display: inline-block; width: 210px; max-width: 55vw; height: 11px; border-radius: 6px; }

/* --------------------------------------------------------------- thread */

/* The thread region is thread.css's .chat-scroll. The frame's own addition
   is the SYSTEM CARD: anything that is not a message from either side. It
   is the terms a conversation happens under, or the record's own note —
   never the coach making reassuring noises. Quiet, bordered, visibly not a
   bubble, the full column wide. */
.chat-sys {
  align-self: stretch;
  margin-top: 10px;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  font-size: 13.5px;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: break-word;
}
.chat-sys + .chat-sys { margin-top: 8px; }
/* The record voice: a resume line, a restart line. */
.chat-sys--quiet {
  align-self: center;
  border: 0;
  padding: 10px 0 4px;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: normal;
}
/* A card that carries structure (a plan, a report): body text, not muted. */
.chat-sys--card { color: var(--text); background: var(--surface); white-space: normal; }
.chat-sys__head {
  margin: 0 0 4px;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--accent-text);
}
.chat-sys p { margin: 0; }
.chat-sys p + p { margin-top: 6px; }

/* The working word beside the dots: for the screen reader while the dots
   move; under reduced motion it is what everyone reads. */
.chat-typing__word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
@media (prefers-reduced-motion: reduce) {
  .msg.dots:has(.chat-typing__word) i { display: none; }
  .chat-typing__word { position: static; width: auto; height: auto; overflow: visible; clip: auto; font-size: 13.5px; }
}

/* ----------------------------------------------------------------- dock */

/* Always at the bottom of the frame, never in flow. The dock carries the
   hairline; the composer inside it does not draw a second one. It keeps
   the composer's height when the composer is absent, so a quiz's choices
   sit where the field would be and the thread does not jump. */
.chat-dock {
  min-width: 0;
  display: flex; flex-direction: column;
  border-top: 1px solid var(--line);
  position: relative;
  z-index: 20;
}
.chat-dock > .chat-compose { border-top: 0; }
.chat-dock--bare { min-height: 70px; justify-content: center; padding-bottom: env(safe-area-inset-bottom, 0px); }

/* The chip row: the PAGE's own controls — Leave, the Coach's review offer,
   a refusal line — directly above the composer, in the column's measure.
   Every chip is the same quiet pill.

   A TURN'S ANSWERS ARE NOT HERE (gate turn-chips, 2026-09-12). They were,
   and the owner ruled they belong to the turn that asked: the answer row is
   in the transcript now, styled by thread.css, mounted by setTurnChips. */
.chat-dock__chips {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  padding: 10px max(20px, (100% - var(--measure)) / 2) 0;
}
.chat-dock--bare .chat-dock__chips { padding-bottom: 12px; }
.chat-dock__chips[hidden] { display: none; }
.chat-dock__chips > button, .chat-dock__chips > a.btn {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--muted);
  border-radius: 999px;
  padding: 8px 16px;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  text-decoration: none;
}
.chat-dock__chips > button:hover, .chat-dock__chips > a.btn:hover { color: var(--text); text-decoration: none; }
.chat-dock__chips > button:disabled { opacity: .6; cursor: default; }
.chat-dock__chips > button[aria-busy="true"] { opacity: .6; }
.chat-dock__chips > .btn--ghost { color: var(--text); }
/* A note in the row (a label, "new messages would not reach them"). */
.chat-dock__note { color: var(--muted); font-size: 13px; line-height: 1.4; }
/* A refusal in the row, in the field's own dialect. */
.chat-dock__chips > .fb-error { flex: 1 1 100%; margin-top: 0; }
/* A surface's own row inside the chips (a decision row, a verify form)
   spans the width and drops its private gutter — the chip row has one. */
.chat-dock__chips > .ob-actions, .chat-dock__chips > .ob-under, .chat-dock__chips > .ob-verify {
  flex: 1 1 100%; padding-inline: 0;
}

/* ---------------------------------------------------------------- phone */

@media (max-width: 760px) {
  .chat-head { padding: 12px 14px 10px; align-items: flex-start; }
  .chat-back { padding-top: 0; padding-bottom: 0; }
  .chat-dock__chips { padding-left: 14px; padding-right: 14px; }
}
