/* The composer — ticket 08.
 *
 * Every number traces to reference/visual-spec.md §6 as re-measured by 08, and
 * lives in tokens.css. Two states, and they are NOT one boolean (decision 77):
 *
 *   .is-collapsed  the four left glyphs give way to a `>` chevron and the field
 *                  grows left 188 -> 52. Driven by FOCUS.
 *   .has-text      the in-field glyph goes smiley -> magnifier and the trailing
 *                  glyph goes thumbs-up -> send arrow. Driven by CONTENT.
 *
 * One Mobbin capture shows the content swaps with the icons still expanded, so
 * the two must stay independent even though the film only ever sees them
 * together. The collapse is animated, not instant.
 *
 * VERTICAL MODEL. The composer's bottom edge is --composer-anchor above the
 * bottom of the stage: 0 with the keyboard down, and (--stage-h minus
 * --keyboard-top) with it up. Both are hard-coded constants (decision 66) —
 * nothing here reads the viewport, and the stage never moves or resizes.
 * Bottom-pinning to --stage-h alone, which is what the ticket assumed, lets iOS
 * scroll the whole stage up when the keyboard opens and carries the header off
 * the top of the screen; the header is assumed to be in frame (decision 74).
 */

.stage {
  --composer-anchor: 0px;
  --composer-grow: 0px; /* extra field height when the line wraps; JS writes it */
}
.stage.kbd-up {
  --composer-anchor: calc(var(--stage-h) - var(--keyboard-top));
}

.composer {
  position: absolute;
  left: 0;
  bottom: var(--composer-anchor);
  width: var(--stage-w);
  height: calc(var(--composer-field-h) + var(--composer-grow) + var(--composer-bottom-gap));
  /* No top border and no separator — verified by a full-height column scan of
   * the still (visual-spec §6). It may be a translucent material like the
   * header turned out to be (22), but it sits on white with nothing behind it,
   * so flat and translucent are the same pixels here. */
  background: var(--c-thread-bg);
  color: var(--c-composer-accent);
}

/* Every glyph is centred on the field's LAST line box, which is what keeps the
 * row put when the field grows to two lines. --composer-bottom-gap is the 8
 * below the field; --composer-field-h is one line box plus its padding. */
.cbtn {
  position: absolute;
  bottom: calc(var(--composer-bottom-gap) + (var(--composer-field-h) - var(--h)) / 2);
  width: var(--w);
  height: var(--h);
  color: inherit;
}
.cbtn svg {
  display: block;
}

/* ------------------------------------------------------------ left glyphs */

.cbtn--plus    { --w: 22px; --h: 22px; left: var(--composer-plus-left); }
.cbtn--camera  { --w: 24px; --h: 20px; left: var(--composer-camera-left); }
.cbtn--gallery { --w: 22px; --h: 20px; left: var(--composer-gallery-left); }
.cbtn--mic     { --w: 17px; --h: 22px; left: var(--composer-mic-left); }

.cbtn--chevron {
  --w: var(--composer-chevron-w);
  --h: var(--composer-chevron-h);
  left: var(--composer-chevron-left);
}

/* The crossfade. The four glyphs slide a little left as they go, which is what
 * reads as a collapse rather than a swap; the chevron only fades. */
.composer-left {
  transition: opacity var(--composer-collapse-ms) ease,
              transform var(--composer-collapse-ms) cubic-bezier(0.4, 0, 0.2, 1);
  transform-origin: 26px 50%;
}
.composer .cbtn--chevron {
  opacity: 0;
  transition: opacity var(--composer-collapse-ms) ease;
}
.composer.is-collapsed .composer-left {
  opacity: 0;
  transform: translateX(-10px) scale(0.86);
  pointer-events: none;
}
.composer.is-collapsed .cbtn--chevron {
  opacity: 1;
}

/* ------------------------------------------------------------------ field */

.composer-field {
  position: absolute;
  bottom: var(--composer-bottom-gap);
  left: var(--composer-field-left-down);
  right: var(--composer-field-right);
  height: calc(var(--composer-field-h) + var(--composer-grow));
  border-radius: var(--composer-field-radius);
  background: var(--c-surface);
  /* The right edge, the in-field glyph and the trailing glyph are in exactly
   * the same place in both states — only this left edge moves. */
  transition: left var(--composer-collapse-ms) cubic-bezier(0.4, 0, 0.2, 1);
}
.composer.is-collapsed .composer-field {
  left: var(--composer-field-left-up);
}

.composer-input {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  outline: 0;
  margin: 0;
  resize: none;
  background: transparent;
  overflow: hidden;
  font: var(--t-placeholder);
  color: var(--c-text);
  caret-color: var(--c-caret);
  /* 10 top and bottom around a 20 line box makes the measured 40 field. */
  padding: 10px var(--composer-field-pad-r) 10px var(--composer-field-pad-x);
  /* app.css turns selection off everywhere; the one field that types needs it
   * back on or iOS drops keystrokes. */
  -webkit-user-select: text;
  user-select: text;
}
.composer-input::placeholder {
  color: var(--c-text-secondary);
  opacity: 1;
}
/* A selection highlight or a loupe in a macro insert is unrecoverable. JS also
 * collapses any selection to the caret; this hides the flash before it does. */
.composer-input::selection {
  background: transparent;
}

/* --------------------------------------------------- in-field and trailing */

/* Both sit at fixed distances from the stage's right edge, not the field's, so
 * they do not move when the field's left edge does. */
.cbtn--infield {
  --w: 22px;
  --h: 22px;
  right: calc(var(--composer-field-right) + var(--composer-infield-right));
}
.cbtn--thumb {
  --w: 22px;
  --h: 23px;
  right: var(--composer-trail-right);
  /* The one glyph that is not centred on the row. Its ink is 627..650 in the
   * still where every 22-tall glyph is 628..650 — they share a BOTTOM edge and
   * the thumb overshoots by 1 at the top, so centring its 23 would drop it half
   * a pixel. Pinned to the same 9 above the field's bottom as the rest. */
  bottom: calc(var(--composer-bottom-gap) + 9px);
}
.cbtn--send {
  --w: 20px;
  --h: 20px;
  right: var(--composer-trail-right);
}

/* The two in-field glyphs occupy the same box so they cross-fade in place. */
.cbtn--infield > * {
  position: absolute;
  inset: 0;
}

/* The send's hit area: a 56 square in the corner, above both trailing glyphs.
 * Invisible, and inert unless there is text — the thumbs-up sends a 👍 in real
 * Messenger and no beat in this film does that. */
.cbtn--send-hit {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 56px;
  height: 56px;
}

/* The content swaps: a short crossfade, independent of the collapse above. */
.cbtn--smiley,
.cbtn--magnifier,
.cbtn--thumb,
.cbtn--send {
  transition: opacity 120ms ease;
}
.cbtn--magnifier,
.cbtn--send {
  opacity: 0;
}
.composer.has-text .cbtn--smiley,
.composer.has-text .cbtn--thumb {
  opacity: 0;
}
.composer.has-text .cbtn--magnifier,
.composer.has-text .cbtn--send {
  opacity: 1;
}

/* The send press. Messenger dips the arrow; the actor needs to see he hit it,
 * and so does the camera. Only ever fires when the send is actually allowed —
 * a refused send (model §7) must not look like a press that did nothing. */
.cbtn--send {
  transition: opacity 120ms ease, transform 90ms ease;
}
.composer.sending .cbtn--send {
  transform: scale(0.82);
}

/* --------------------------------------------------------- the sent bubble */

/* Messenger springs a sent bubble into place. There is no ground truth for
 * this — neither still moves and the recording's only motion is the call
 * transition — so this is invented and needs the director's eye at 13/20.
 * Deliberately short: at macro magnification a long spring reads as a toy. */
@keyframes bubble-land {
  from {
    transform: translateY(9px) scale(0.94);
    opacity: 0.6;
  }
  to {
    transform: none;
    opacity: 1;
  }
}
.bubble--landing {
  animation: bubble-land 220ms cubic-bezier(0.22, 1.1, 0.36, 1);
  transform-origin: 100% 100%;
}
