@layer components {
  .composer { flex: none; padding: 8px var(--gutter) max(14px, var(--safe-bottom)); margin: 0; }
  .composer-notice:not(:empty) { flex: none; padding: 0 var(--gutter); }
  .composer-box { position: relative; border: 1px solid var(--input); border-radius: 10px; background: var(--card); padding: 8px 10px 6px; }
  .composer-box:focus-within { border-color: var(--jx-accent); box-shadow: 0 0 0 3px var(--ring); }
  .composer-input {
    display: block; width: 100%; border: 0; outline: none; resize: none; background: transparent; color: var(--foreground);
    font: inherit; font-size: 13px; line-height: 1.5; max-height: 40dvh; overflow-y: auto;
  }
  .composer-input::placeholder { color: var(--muted-foreground); }
  /* A textarea the rich field replaces has its padding, none: the composer keeps its height through the swap. */
  [data-composer-rich="true"] .composer-box textarea.composer-input { padding: 0; }
  .composer-input[hidden] { display: none; }
  /* The rich field: the textarea's box, two lines tall when empty; its hint is drawn from aria-placeholder. */
  .composer-input--rich { min-height: 3em; white-space: pre-wrap; overflow-wrap: anywhere; cursor: text; }
  .composer-input--rich p { margin: 0; }
  .composer-input--rich[data-empty][aria-placeholder]::before {
    content: attr(aria-placeholder) / ""; position: absolute; color: var(--muted-foreground); pointer-events: none;
  }
  .composer-input--rich .mention { user-select: all; }
  /* A custom emoji in the rich field: an atom as tall as the text line, selected whole like a pill. */
  .composer-input--rich .composer-emoji-node { display: inline-block; vertical-align: -5px; line-height: 0; user-select: all; }
  .composer-input--rich .composer-emoji-node.ProseMirror-selectednode { outline: 2px solid var(--jx-accent); outline-offset: 1px; border-radius: 3px; }
  /* A pill the arrow keys, a tap or a click selected: ProseMirror hides the caret then, so the outline is the marker. */
  .composer-input--rich .mention.ProseMirror-selectednode { outline: 2px solid var(--jx-accent); outline-offset: 1px; }
  .composer-foot { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
  .composer-foot .hint { flex: 1; }
  .composer-foot .hint kbd {
    padding: 0 5px; border: 1px solid var(--border); border-radius: 5px; background: var(--surface);
    font: inherit; font-size: 13px; color: var(--muted-foreground);
  }
  .composer-quote, .composer-confirm {
    display: flex; align-items: center; gap: 8px; margin-bottom: 6px; padding: 6px 10px;
    border: 1px solid var(--border); border-left: 2px solid var(--jx-accent); border-radius: 9px;
    background: var(--surface); color: var(--muted-foreground);
  }
  .composer-quote[hidden] { display: none; }
  .composer-quote-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* A choice waiting for the author: amber. */
  .composer-confirm {
    flex-direction: column; align-items: flex-start; margin: 8px 0 0;
    border-color: var(--jx-wait); background: var(--jx-wait-soft); color: var(--foreground);
  }
  .composer-confirm p { margin: 0; }
  .composer-error { margin: 6px 0 0; color: var(--jx-no); }
  .composer-returned { margin: 0 0 6px; color: var(--muted-foreground); font-size: var(--text-meta); }
  .composer-lost {
    margin: 0 var(--gutter) 10px; padding: 8px 10px; border: 1px solid var(--jx-no); border-radius: 9px;
    background: var(--jx-no-soft); color: var(--foreground); font-size: var(--text-meta);
  }
  .composer-lost p { margin: 0; }
  .composer-lost-text { margin-top: 6px; white-space: pre-wrap; overflow-wrap: anywhere; user-select: text; }
  .message-edit { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
  .message-edit .composer-input {
    border: 1px solid var(--input); border-radius: 8px; background: var(--card); padding: 6px 8px;
  }
  .message-edit .composer-input--rich { min-height: calc(4.5em + 14px); }
  .message-edit .composer-input:focus { border-color: var(--jx-accent); box-shadow: 0 0 0 3px var(--ring); }

  /* Files joined before sending: one chip each, above the field. */
  .composer-files { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 6px; padding: 0; }
  .composer-files:empty { display: none; }
  .composer-becomes {
    display: flex; gap: 6px; align-items: flex-start; margin: 0 0 6px; font-size: 13px; color: var(--muted-foreground);
  }
  .composer-becomes[hidden] { display: none; }
  .composer-becomes svg { flex: none; margin-top: 1px; }
  .composer-becomes span { min-width: 0; overflow-wrap: anywhere; }
  .attachment-chip {
    position: relative; display: flex; align-items: center; gap: 8px; max-width: 280px; min-width: 0;
    padding: 6px 6px 6px 10px; overflow: hidden;
    border: 1px solid var(--border); border-radius: 9px; background: var(--card); font-size: 13px;
  }
  .attachment-chip-icon { flex: none; display: inline-flex; color: var(--muted-foreground); }
  .attachment-chip-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
  .attachment-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; color: var(--foreground); }
  .attachment-chip-meta { color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
  .attachment-chip-becomes { color: var(--muted-foreground); overflow-wrap: anywhere; }
  /* The share choice, a word on a neutral ground: readable in both themes without a colour of its own. */
  .attachment-chip-share {
    align-self: flex-start; padding: 0 6px; border-radius: 999px; background: var(--muted); color: var(--foreground);
    font-size: 13px; font-weight: 500; line-height: 18px;
  }
  .attachment-chip-share:empty { display: none; }
  .attachment-chip-meta:empty, .attachment-chip-becomes:empty, .attachment-chip-error:empty { display: none; }
  .attachment-chip-error { color: var(--jx-no); }
  .attachment-chip[data-state="failed"] { border-color: color-mix(in oklch, var(--jx-no) 45%, transparent); background: var(--jx-no-soft); }
  .attachment-chip[data-state="failed"] .attachment-chip-icon { color: var(--jx-no); }
  /* The upload's progress, a line along the chip's foot. */
  .attachment-chip-progress { position: absolute; left: 0; bottom: 0; height: 2px; width: var(--progress, 0%); background: var(--primary); }
  .attachment-chip:not([data-state="uploading"]) .attachment-chip-progress { display: none; }
  .attachment-chip-remove {
    flex: none; display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0;
    border: 0; border-radius: 6px; background: transparent; color: var(--muted-foreground); cursor: pointer;
  }
  .attachment-chip-remove:is(:hover, :active) { background: var(--accent); color: var(--foreground); }
  .attachment-chip-remove:focus-visible { outline: 2px solid var(--jx-accent); outline-offset: 1px; }
  /* Inside the field's frame, above the text: one place for what the message will carry. */
  .composer-box > .composer-files { margin: 0 0 8px; }
  /* An image's chip is the image: its name and progress stay in the text, for screen readers, out of sight. */
  .attachment-chip-image, .attachment-chip-tag { display: none; }
  .attachment-chip--image { height: 72px; min-width: 56px; max-width: 160px; padding: 0; gap: 0; border-radius: 8px; background: var(--muted); }
  .attachment-chip--image .attachment-chip-image:not([hidden]) { display: block; height: 100%; width: auto; max-width: 160px; object-fit: cover; }
  .attachment-chip--image .attachment-chip-icon { display: none; }
  .attachment-chip--image .attachment-chip-text {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  .attachment-chip--image .attachment-chip-tag:not(:empty) {
    display: block; position: absolute; left: 4px; bottom: 4px; padding: 0 5px; border-radius: 4px;
    background: oklch(0 0 0 / 0.62); color: oklch(1 0 0); font-size: 13px; font-weight: 600; line-height: 18px;
  }
  .attachment-chip--image[data-state="uploading"] .attachment-chip-image { opacity: 0.55; }
  .attachment-chip--image .attachment-chip-progress { height: 3px; }
  /* Refused: a red frame and a word on it, never the colour alone. */
  .attachment-chip--image[data-state="failed"] { border-color: var(--jx-no); background: var(--muted); }
  .attachment-chip--image[data-state="failed"] .attachment-chip-image { opacity: 0.35; filter: grayscale(1); }
  .attachment-chip--image[data-state="failed"] .attachment-chip-tag:not(:empty) {
    right: 4px; text-align: center; background: var(--jx-no); color: var(--background);
  }
  .attachment-chip--image .attachment-chip-remove {
    position: absolute; top: 4px; right: 4px; border: 1px solid var(--border); border-radius: 50%;
    background: color-mix(in oklch, var(--background) 88%, transparent); color: var(--foreground); box-shadow: var(--shadow-xs);
  }
  .attachment-chip--image .attachment-chip-remove:is(:hover, :active) { background: var(--background); }
  .composer-attach { margin-left: -6px; }
  .composer-attach svg { width: 15px; height: 15px; }
  /* The names of a message still sending, greyed with it. */
  .message-files.is-pending {
    list-style: none; display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 0; padding: 0; font-size: 13px;
  }
  .message-files.is-pending[hidden] { display: none; }
  .message-files.is-pending .message-file {
    max-width: 280px; padding: 4px 9px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    border: 1px dashed var(--border); border-radius: 8px; color: var(--muted-foreground);
  }
  /* Where a file may be let go: a dashed frame and what dropping does. */
  [data-attachments-zone].is-dropping { position: relative; outline: 2px dashed var(--primary); outline-offset: -6px; }
  [data-attachments-zone].is-dropping::after {
    content: attr(data-drop-label); position: absolute; inset: 6px; z-index: 5; pointer-events: none;
    display: flex; align-items: center; justify-content: center; border-radius: 10px;
    background: color-mix(in oklch, var(--background) 80%, transparent); color: var(--foreground); font-size: 14px; font-weight: 500;
  }

  /* Tools for a finger only ("@", photos) and the send button's arrow: the desktop keeps its words. */
  .composer-mention, .composer-photo, .composer-send > svg { display: none; }

  /* Touch screens: the hint's keyboard shortcuts do not apply; under the text, the tools as 44 px icons side by side
     (their names kept for screen readers) and a round send button. */
  @media (pointer: coarse) {
    /* Wraps when the tools no longer fit (320 px): they keep their 44 px, the send button stays at the end. */
    .composer-foot { flex-wrap: wrap; gap: 2px 0; margin-top: 2px; }
    .composer-foot > .hint:not(.hint--status) { display: none; }
    .composer-foot > .hint--status { min-width: 0; padding-inline: 6px; overflow-wrap: anywhere; }
    .composer-foot > [type=submit] { margin-left: auto; }
    /* A 2 px gap: two neighbouring tools never share the pixel their edge falls on. */
    .composer-tool { display: inline-flex; width: var(--tap); height: var(--tap); flex: none; margin: 0 2px 0 0; padding: 0; }
    .composer-tool svg { width: 20px; height: 20px; }
    .attachment-chip--image { height: 64px; max-width: 132px; }
    .attachment-chip--image .attachment-chip-image:not([hidden]) { max-width: 132px; }
    .attachment-chip--image .attachment-chip-remove { top: 2px; right: 2px; width: 32px; height: 32px; }
    .composer-tool > span, .composer-send > span {
      position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
    }
    .composer-send { width: 36px; height: 36px; padding: 0; border-radius: 999px; }
    .composer-send > svg { display: block; width: 18px; height: 18px; }
  }
}
