.message__interactive-actions {
  background: var(--color-bg-sunk);
  border: 1px solid var(--color-border);
  border-radius: 10px;
  display: grid;
  gap: 0.6rem;
  margin-block-start: 0.6rem;
  max-inline-size: min(100%, 30rem);
  padding: 0.75rem 0.8rem;
}

.message__interactive-text {
  color: var(--color-text);
  font-weight: 500;
  line-height: 1.35;
  margin: 0;
}

.message__interactive-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}

/* The panel's one status line — waiting for the bot, no reply yet, refused, or
   the reason the controls are off — quiet beneath the controls. */
.message__interactive-status {
  color: var(--color-text-muted);
  font-size: var(--font-size-small);
  line-height: 1.35;
  margin: 0;
}

.message__interactive-form {
  display: contents;
}

/* Inline form fields: a label over its control, the bot's error beneath, each
   field its own row in the panel's grid. Controls reuse the shared .input;
   checkboxes are the app's native ones. */
.message__interactive-field {
  display: grid;
  gap: 0.3rem;
}

.message__interactive-label {
  color: var(--color-text);
  font-size: var(--font-size-small);
  font-weight: 500;
}

.message__interactive-field textarea.input {
  min-block-size: 5rem;
  resize: vertical;
}

.message__interactive-choices {
  border: 0;
  display: grid;
  gap: 0.35rem;
  margin: 0;
  min-inline-size: 0;
  padding: 0;
}

.message__interactive-choice {
  align-items: center;
  display: flex;
  gap: 0.5rem;
}

.message__interactive-field .field-error {
  margin: 0;
}

/* The inline "Are you sure?" a confirming button swaps in for the button row:
   the question above its Yes / No pair, in the panel's own grid rhythm. */
.message__interactive-confirmation {
  display: grid;
  gap: 0.6rem;
}

/* Select menus reuse the shared .input field; size them to match the button row
   and let each span the panel as its own grid row. */
.message__interactive-select {
  min-block-size: 2.5rem;
}

.message__interactive-actions.is-pending .message__interactive-select {
  opacity: 0.55;
}

.message__interactive-action {
  --btn-padding: 0.45em 0.9em;
  /* Link buttons are anchors dressed as the same control. */
  text-decoration: none;
  /* Colour the pending spinner per variant; defaults to the label ink. */
  --interactive-busy-color: var(--color-text);

  font-size: max(16px, 1em);
  min-block-size: 2.5rem;
  position: relative;

  &:focus-visible {
    outline: 2px solid var(--color-selected-dark);
    outline-offset: 2px;
  }

  &:disabled {
    cursor: not-allowed;
  }
}

.message__interactive-action--default {
  --btn-background: var(--color-bg-raised);
  --btn-border-color: var(--color-border-darker);

  &:hover:not(:disabled) {
    --btn-background: var(--color-bg-hover);
  }
}

.message__interactive-action--primary {
  --btn-background: var(--color-accent-brand);
  --btn-border-color: var(--color-accent-brand);
  --btn-color: var(--color-text-reversed);
  --interactive-busy-color: var(--color-text-reversed);

  &:hover:not(:disabled) {
    filter: brightness(0.94);
  }
}

.message__interactive-action--danger {
  --btn-background: var(--color-negative-bg);
  --btn-border-color: var(--color-negative);
  --btn-color: var(--color-negative);
  --interactive-busy-color: var(--color-negative);

  &:hover:not(:disabled) {
    --btn-background: var(--color-bg-negative);
  }
}

/* While one button is submitting, dim the rest of the group so the pending
   choice reads as the active one. */
.message__interactive-actions.is-pending .message__interactive-action:not([aria-busy="true"]) {
  opacity: 0.55;
}

/* The clicked button shows the shared app spinner (see .busy) in place of its
   label until the bot's edit lands. */
.message__interactive-action[aria-busy="true"] {
  color: transparent;
  pointer-events: none;
}

.message__interactive-action[aria-busy="true"]::after {
  --mask: no-repeat radial-gradient(#000 68%, #0000 71%);

  animation: submitting 1s infinite linear;
  aspect-ratio: 8/5;
  background: var(--interactive-busy-color);
  content: "";
  inline-size: 1.25em;
  inset: 50%;
  -webkit-mask: var(--mask), var(--mask), var(--mask);
  mask: var(--mask), var(--mask), var(--mask);
  -webkit-mask-size: 28% 45%;
  mask-size: 28% 45%;
  position: absolute;
  translate: -50% -50%;

  @media (prefers-reduced-motion: reduce) {
    animation-name: pulse-reduced;
  }
}
