@layer components {
  /* ——— Boosts ———
     Fizzy's reactions, on our tokens: a strip of pills under a thing, each a
     face and a word in a fully rounded chip; the trigger a quiet circle at
     the strip's end that turns, in place, into the form — your face, a
     borderless field, the picker, ✓ and ✕. The strip shows its list only
     once there is something in it. */
  .boosts {
    /* One size on every device: fizzy and chalet ship the same chip to a
       phone, and the touch-inflated 2.25rem read enormous beside the lines
       it decorated (user, 2026-08-24). */
    --boost-size: 1.6875rem;

    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--inline-space-half);
    max-inline-size: 100%;
  }

  .boosts__list {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--inline-space-half);

    &:not(:has(.boost)) {
      display: none;
    }
  }

  .boosts__trigger {
    --btn-size: var(--boost-size);
  }

  /* Basecamp's bar (user, 2026-08-23): the rocket, seven one-tap emoji and ⋯.
     It is drawn only inside .boosts__popup (boosts/_boosts), so it is a picker
     row and the float is its frame — the size, gap and padding are all
     emoji-picker.css's, because it is the same surface.

     It is NOT a .boost. It wore the class for the pill's shape, and every pill
     declaration sits later in this file at equal specificity: .boost's gap,
     padding and block-size won on source order, and .boost .btn's 1.25rem
     stuffed 24px faces into 20px discs, which is what read as cramped (user,
     2026-08-30). The popup already draws the canvas, border and radius the
     pill was lending, so dropping the class costs nothing. */
  .boosts__bar {
    display: flex;
    align-items: center;
    gap: var(--inline-space-half);
    padding: var(--block-space-half) var(--inline-space);

    .btn {
      /* A tighter disc than the grid's 1.3: there the halo is the room the
         face grows into on hover, and here nothing scales, so it is only
         space between faces on one line (user, 2026-08-30). */
      --btn-size: calc(var(--text-large) * 1.15);

      font-size: var(--text-large);
    }
  }

  .boosts__popup {
    --popup-area: block-end span-inline-end;
    --popup-try: flip-block, flip-inline, flip-block flip-inline;
  }

  /* While the form stands, the bar or the rocket it replaces steps aside;
     a boost empties the form's frame and they are simply back. */
  .boosts:has(.boost__form) :is(.boosts__bar, .boosts__trigger) {
    display: none;
  }

  /* One pill. The face sits flush at the start, the word after it; an
     emoji-only boost reads at its own size with even padding. */
  .boost {
    display: inline-flex;
    align-items: center;
    gap: 0.25ch;
    block-size: var(--boost-size);
    max-inline-size: 100%;
    padding: 0.1em 0.36em 0.1em 0.12em;
    font-size: var(--text-small);
    color: var(--color-ink);
    background-color: var(--color-canvas);
    border: var(--border);
    border-radius: 4rem;
    position: relative;

    &:has(.boost__content--emoji) {
      padding: 0.1em 0.12em;
    }

    .btn {
      --btn-size: 1.25rem;

      @media (any-hover: none) {
        --btn-size: 2rem;
      }
    }
  }

  .boost__avatar {
    --avatar-size: calc(var(--boost-size) - 0.2em - 2px);

    flex: none;
  }

  .boost__content--emoji {
    font-size: var(--text-medium);
  }

  /* Yours is a button — the browser says so (boost_delete_controller) — and
     says it under the pointer; everybody else's is a word. */
  .boost--deleteable {
    cursor: pointer;

    @media (any-hover: hover) {
      &:not(.boost--revealed):hover {
        background-color: var(--color-surface);
      }
    }
  }

  /* Three classes deep on purpose: buttons.css loads after this file, and
     its icon-button detector (.btn:has(.icon)) already counts two. */
  .boosts .boost .boost__delete {
    --btn-color: var(--color-accent);

    display: none;

    .boost--revealed & {
      display: inline-flex;
    }
  }

  .boost--deleting {
    animation: scale-fade-out 0.2s both;
  }

  /* The form wears the pill's shape and pops in where the trigger stood;
     the ring is the pill's while the field has focus, the field itself draws
     none. */
  .boost__form {
    animation: boost-pop 300ms both;
    transform-origin: left center;

    /* Mizu, not shu: chalet rings its boost form in the selection colour,
       and the accent on a pill reads as an error. */
    &:has(.input:focus) {
      outline: var(--focus-ring-size) solid var(--color-selected-ink);
      outline-offset: -1px;
    }
  }

  .boost__form-label {
    display: inline-flex;
    align-items: center;
    gap: 0.7ch;
    block-size: 100%;
  }

  /* The field draws nothing of its own — not the input's baseline, not its
     focus line — the pill's ring says where you are. */
  .boosts .boost .boost__input,
  .boosts .boost .boost__input:focus {
    inline-size: auto;
    min-inline-size: 3em;
    max-inline-size: 16ch;
    padding: 0 0.25ch;
    font-size: inherit;
    background: transparent;
    border: none;
    box-shadow: none;
    outline: 0;

    @supports (field-sizing: content) {
      field-sizing: content;
    }
  }

  .boosts .boost .boost__submit {
    --btn-color: var(--color-positive);
  }

  .boosts .boost .boost__cancel {
    --btn-color: var(--color-accent);
  }

  /* The picker: fizzy's grid of fifty, ten to a row, six on a narrow shell;
     one grows under the pointer. */
  .boost__picker {
    --popup-area: block-end span-inline-end;

    /* The strip stands at the line's end on a comment and an event, so the
       grid opens the other way there rather than off the sheet's edge. */
    --popup-try: flip-block, flip-inline, flip-block flip-inline;
  }

  /* The popup hangs over the viewport, not the sheet — a top-layer float's
     containing block is the screen (popups.css). On a phone no side of a
     mid-line anchor fits the seven-emoji row, and the overhang panned the
     whole page sideways (user, 2026-08-24): so the bar takes the full row
     under its rocket instead — spanned across the anchor, centred, capped
     by .popup's own screen-wide max. The fifty-emoji picker wears the same
     clamp. */
  @media (width < 35rem) {
    .boosts__popup,
    .boost__picker {
      --popup-area: block-end span-all;
      --popup-try: flip-block;

      justify-self: center;
    }
  }

  /* The line menu's quick grid: Basecamp's eight, four to a row. */
  .quick-boosts {
    display: grid;
    grid-template-columns: repeat(4, auto);
    justify-content: start;
    gap: var(--block-space-half) var(--inline-space);
    padding: var(--block-space-half) var(--inline-space);
    border-block-end: var(--border);
    margin-block-end: var(--block-space-half);

    .btn {
      font-size: var(--text-large);
    }
  }

  /* Fizzy's two: the form popping in, a pill shrinking away. Motion earned
     by something appearing and disappearing (AGENTS.md), nothing else. */
  @keyframes boost-pop {
    0%   { transform: scale(0.85); opacity: 0; }
    50%  { transform: scale(1.15); opacity: 1; }
    100% { transform: scale(1); }
  }

  @keyframes scale-fade-out {
    0%   { transform: scale(1); opacity: 1; }
    100% { transform: scale(0); opacity: 0; }
  }
}
