@layer components {
  /* ═══════════════════════════════════════════════════════════════════
     La afición — live match chat. FAB (festive WC entry) + bottom-sheet
     grada (one-line rolling stream). Festive skin is gated behind
     [data-event-mode="wc2026"] on the controller host; off the pilot the
     FAB falls back to a neutral surface. Reuses the porra-banner gradient +
     pulse keyframe and the openSheet (hidden + .active) mechanism.
     ═══════════════════════════════════════════════════════════════════ */

  /* ── FAB ── */
  .match-chat-fab {
    position: fixed;
    right: var(--space-4);
    bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
    z-index: 60;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    padding: 0;
    border: none;
    border-radius: var(--radius-full);
    /* Default skin: a gradient from the two teams' own colours (home → away),
       set inline on the FAB from the match doc. Festive international-cup
       matches override this with the porra gradient (rule below). When a team
       has no colour, fall back to a strong pink → violet (NOT the green accent —
       too low-contrast for the white icon). */
    background: linear-gradient(
      135deg,
      var(--team-color-home, var(--color-porra-magenta)) 0%,
      var(--team-color-away, var(--color-porra-purple-light)) 100%
    );
    color: #fff;
    box-shadow: var(--shadow-lg);
    cursor: pointer;
    transition: transform var(--duration-fast) var(--easing-default);
  }

  .match-chat-fab[hidden] {
    display: none !important;
  }

  .match-chat-fab:active {
    transform: scale(0.96);
  }

  @media (max-width: 420px) {
    .match-chat-fab {
      width: 52px;
      height: 52px;
    }
  }

  /* Festive World-Cup skin = the canonical porra gradient (porra-banner.css):
     magenta → deep porra purple → cyan. Matches the campaign's identity. */
  [data-event-mode="wc2026"] .match-chat-fab {
    background: linear-gradient(
      115deg,
      var(--color-porra-magenta) 0%,
      var(--color-porra-purple) 58%,
      var(--color-porra-cyan) 112%
    );
    color: #fff;
  }

  .match-chat-fab__icon {
    width: 26px;
    height: 26px;
  }

  /* Forum-style comment count: when the room has messages, the round FAB
     becomes a pill (icon + count). Stays right-anchored, grows leftward. */
  .match-chat-fab--counted {
    width: auto;
    min-width: 0;
    height: 46px;
    padding: 0 14px 0 12px;
    gap: 6px;
  }

  .match-chat-fab--counted .match-chat-fab__icon {
    width: 21px;
    height: 21px;
  }

  @media (max-width: 420px) {
    /* After the plain-FAB 52px rule above, so the counted pill keeps auto width. */
    .match-chat-fab--counted {
      width: auto;
      height: 44px;
      padding: 0 13px 0 11px;
    }
  }

  .match-chat-fab__count {
    font-family: var(--font-display, inherit);
    font-size: 12px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    color: #fff;
  }

  /* ── Backdrop + sheet ── */
  .match-chat-backdrop {
    position: fixed;
    inset: 0;
    z-index: 9998;
    background: rgb(0 0 0 / 55%);
    opacity: 0;
    transition: opacity 0.3s ease-in-out;
  }

  .match-chat-backdrop[hidden] {
    display: none;
  }

  .match-chat-backdrop.active {
    opacity: 1;
    backdrop-filter: blur(2px);
  }

  .match-chat-sheet {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    max-width: var(--content-max-width);
    height: 72vh;
    margin: 0 auto;
    background: var(--color-surface);
    border-radius: 20px 20px 0 0;
    box-shadow: 0 -4px 24px rgb(0 0 0 / 40%);
    transform: translateY(100%);
    transition: transform 0.3s ease-in-out;
    overflow: hidden;
  }

  .match-chat-sheet[hidden] {
    display: none;
  }

  .match-chat-sheet.active {
    transform: translateY(0);
  }

  @media (max-width: 420px) {
    .match-chat-sheet {
      height: 82vh;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .match-chat-sheet {
      transform: none;
      opacity: 0;
      transition: opacity 0.2s ease;
    }

    .match-chat-sheet.active {
      opacity: 1;
    }
  }

  @media (min-width: 1024px) {
    .match-chat-sheet {
      top: 50%;
      bottom: auto;
      left: 50%;
      right: auto;
      max-width: 640px;
      height: 70vh;
      border-radius: 16px;
      opacity: 0;
      transform: translate(-50%, -46%);
      transition:
        opacity 0.2s ease,
        transform 0.2s ease;
    }

    .match-chat-sheet.active {
      opacity: 1;
      transform: translate(-50%, -50%);
    }
  }

  /* ── Header: scoreboard hero (crests + names + score + status) ──
     Mirrors the match nav compact title — only escudos + nombres +
     marcador + estado. No presence count, no message count (both move
     too fast to poll; deferred to a later phase). */
  .match-chat-sheet__header {
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex-shrink: 0;
    padding: var(--space-3) var(--space-4) calc(var(--space-3) + 2px);
    border-bottom: 1px solid var(--color-border-subtle);
  }

  /* Scoreboard hero — bicolor team-colour wash (home left / away right),
     inheriting --team-color-home / --team-color-away from the match wrapper
     (set in match_shell.html.twig from TeamSummaryDto.color). This is what
     makes the chat header read as our match scoreboard nav rather than a flat
     bar; falls back to accent / live when a team has no resolved colour. */
  .match-chat-sheet__header::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
      radial-gradient(
        ellipse 75% 130% at 8% 0%,
        color-mix(in oklab, var(--team-color-home, var(--color-accent)) 32%, transparent) 0%,
        transparent 62%
      ),
      radial-gradient(
        ellipse 75% 130% at 92% 0%,
        color-mix(in oklab, var(--team-color-away, var(--color-live)) 30%, transparent) 0%,
        transparent 62%
      );
  }

  .match-chat-sheet__top {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: var(--space-2);
  }

  .match-chat-sb {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
  }

  .match-chat-sb__side {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 6px;
  }

  .match-chat-sb__side--away {
    justify-content: flex-end;
  }

  .match-chat-sb__crest {
    width: 24px;
    height: 24px;
    object-fit: contain;
    flex-shrink: 0;
  }

  .match-chat-sb__name {
    min-width: 0;
    font-family: var(--font-title);
    font-weight: var(--weight-bold);
    font-size: 14px;
    letter-spacing: 0.2px;
    color: var(--color-text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .match-chat-sb__score {
    flex-shrink: 0;
    font-family: var(--font-title);
    font-weight: var(--weight-bold);
    font-size: 22px;
    line-height: 1;
    color: #fff;
    letter-spacing: 0.5px;
    font-variant-numeric: tabular-nums;
  }

  .match-chat-sheet__substrip {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
  }

  .match-chat-sheet__presence {
    font-family: var(--font-body);
    font-size: 11px;
    color: var(--color-text-muted);
  }

  .match-chat-sheet__close {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: var(--radius-full);
    background: var(--color-surface-sunken);
    color: var(--color-text-secondary);
    cursor: pointer;
  }

  /* ── List + message rows ── */
  .match-chat-sheet__list {
    position: relative; /* positioning context for the message context menu */
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--space-2) 0;
    scrollbar-width: none;
  }

  .match-chat-sheet__list::-webkit-scrollbar {
    display: none;
  }

  /* Twitch-style inline flow: the row is a block and time · crest · nick · body
     flow as inline content, so a long message wraps to the FULL row width on
     its second line instead of staying in a narrow indented column — a big
     vertical-space win on multi-line messages. */
  .match-chat-msg {
    display: block;
    padding: 4px var(--space-2);
    border-bottom: 1px solid var(--color-border-subtle);
    font-family: var(--font-body);
    font-size: 14px;
    line-height: 1.45;
  }

  /* Inline (Twitch-style): bold nick that flows before the body. No ellipsis —
     the body wrapping to full width below absorbs long nicks gracefully. */
  .match-chat-msg__nick {
    font-weight: 700;
    font-size: 12px;
  }

  /* Twitch-style "nick:" — colon stuck right after the name (in the nick's own
     colour), then a space before the message. */
  .match-chat-msg__nick::after {
    content: ":";
    margin-right: 4px;
  }

  .match-chat-msg__body {
    color: #fff;
    overflow-wrap: anywhere;
  }

  /* Emoji-only message → render big (WhatsApp-style), clearly larger than a
     normal one-line message. The nick prefix stays small; only the body grows. */
  .match-chat-msg__body--emoji {
    font-size: 25px;
    line-height: 1.05;
  }

  /* HH:mm in the user's timezone, on the LEFT of the row (time · nick · body).
     The day is shown by the floating date pill, not per-row. */
  .match-chat-msg__time {
    margin-right: 4px;
    font-size: 10px;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
    vertical-align: middle;
  }

  /* Allegiance: the team crest as the avatar before your nick. Fixed 18px slot so
     nicks stay aligned whether the row shows a crest or the neutral dot. */
  .match-chat-msg__avatar {
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: middle;
    margin-right: 4px;
  }

  .match-chat-msg__avatar img {
    width: 18px;
    height: 18px;
    object-fit: contain;
    border-radius: 50%;
  }

  /* Neutral (no side picked): a small nick-coloured dot centred in the slot. */
  .match-chat-msg__avatar--neutral::before {
    content: "";
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--dot, var(--color-text-muted));
  }

  /* No permanent side rail — allegiance reads from the crest avatar; the row
     stays clean (Twitch-style). Tapping a message opens the context menu. */

  /* Highlight the message whose context menu is open. */
  .match-chat-msg.is-ctx {
    background: var(--color-surface-hover);
  }

  /* Reactions mount as chips BELOW the comment — only the emoji with a count
     (the count-0 picker buttons hide; you add/remove via the context menu). */
  .match-chat-reactions--chips {
    padding: 2px var(--space-2) 6px;
  }

  .match-chat-reactions--chips
    .match-chat-react:not(.match-chat-react--mine):has(.match-chat-react__count[hidden]) {
    display: none;
  }

  /* ── Context menu (WhatsApp-Web style): tap a message → emoji react row +
     actions (Copiar · Silenciar · Reportar) in a floating popover clamped to
     the stream. Ported from the grada-modes design. ─────────────────────── */
  .match-chat-ctx {
    position: absolute;
    z-index: 11;
    width: 200px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: 0 14px 36px -8px rgb(0 0 0 / 72%);
    overflow: hidden;
  }

  @media (prefers-reduced-motion: no-preference) {
    .match-chat-ctx {
      animation: ctxpop 0.13s var(--easing-default);
      transform-origin: top center;
    }
  }

  @keyframes ctxpop {
    from {
      opacity: 0;
      transform: scale(0.92);
    }
  }

  .match-chat-ctx__react {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 5px 6px;
    border-bottom: 1px solid var(--color-border-subtle);
  }

  .match-chat-ctx__emoji {
    width: 32px;
    height: 32px;
    display: grid;
    place-items: center;
    border: none;
    background: none;
    font-size: 19px;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: transform var(--duration-fast) var(--easing-default);
  }

  .match-chat-ctx__emoji:active {
    transform: scale(0.85);
  }

  .match-chat-ctx__emoji.on {
    background: color-mix(in oklab, var(--color-accent) 22%, transparent);
  }

  .match-chat-ctx__menu {
    padding: 4px;
  }

  .match-chat-ctx__item {
    display: flex;
    align-items: center;
    gap: 11px;
    width: 100%;
    padding: 9px 10px;
    border: none;
    background: none;
    color: var(--color-text-secondary);
    font-family: var(--font-body);
    font-size: 13px;
    font-weight: 600;
    text-align: left;
    border-radius: 8px;
    cursor: pointer;
  }

  .match-chat-ctx__item:hover,
  .match-chat-ctx__item:active {
    background: var(--color-surface-hover);
  }

  .match-chat-ctx__item--danger {
    color: var(--color-live);
  }

  .match-chat-ctx__ic {
    width: 16px;
    flex-shrink: 0;
    text-align: center;
    font-size: 14px;
  }

  /* ── Side picker: "who are you with?" — team-name options with a live vote
     count, above the composer. Top edge is a home/away % share bar. ─────────── */
  .grada-side {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 9px var(--space-4) 7px;
    background: var(--color-surface);
  }

  /* Collapsed by default — raised by the composer's side chip (toggleSidePicker).
     Author rule needed: `.grada-side { display:flex }` would beat the UA [hidden]. */
  .grada-side[hidden] {
    display: none;
  }

  /* Top edge = home/away vote-share bar; muted until there are votes, then a
     two-colour split at --home-pct (set by the controller). */
  .grada-side::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--color-border-subtle);
  }

  .grada-side--has-votes::before {
    background: linear-gradient(
      90deg,
      var(--team-color-home, var(--color-accent)) 0 var(--home-pct, 50%),
      var(--team-color-away, var(--color-accent)) var(--home-pct, 50%) 100%
    );
  }

  .grada-side__opts {
    display: flex;
    gap: 6px;
  }

  .grada-side__opt {
    flex: 1 1 0;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 34px;
    padding: 4px 10px;
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-full);
    background: var(--color-surface-sunken);
    color: var(--color-text-secondary);
    font-family: var(--font-body);
    font-size: 13px;
    cursor: pointer;
    transition: transform var(--duration-fast) var(--easing-default);
  }

  .grada-side__opt:active {
    transform: scale(0.96);
  }

  .grada-side__crest {
    flex-shrink: 0;
    width: 18px;
    height: 18px;
    object-fit: contain;
  }

  .grada-side__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
  }

  /* Live vote tally chip next to the name. */
  .grada-side__count {
    flex-shrink: 0;
    min-width: 18px;
    padding: 0 5px;
    border-radius: var(--radius-full);
    background: color-mix(in oklab, var(--color-text) 14%, transparent);
    font-size: 11px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: center;
  }

  .grada-side__count[hidden] {
    display: none;
  }

  .grada-side__opt--home.is-active {
    border-color: var(--team-color-home, var(--color-accent));
    background: color-mix(
      in oklab,
      var(--team-color-home, var(--color-accent)) 20%,
      var(--color-surface-sunken)
    );
    color: #fff;
  }

  .grada-side__opt--away.is-active {
    border-color: var(--team-color-away, var(--color-accent));
    background: color-mix(
      in oklab,
      var(--team-color-away, var(--color-accent)) 20%,
      var(--color-surface-sunken)
    );
    color: #fff;
  }

  .grada-side__opt--neutral.is-active {
    border-color: var(--color-accent);
    background: color-mix(in oklab, var(--color-accent) 16%, var(--color-surface-sunken));
    color: var(--color-accent-fg);
  }

  /* Match event → a rounded card centered in the stream (not a one-line row). */
  .match-chat-msg--system {
    justify-content: center;
    padding: 10px var(--space-4);
    border-bottom: none;
  }

  .match-chat-msg__event {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    max-width: 90%;
    padding: 12px 20px;
    border-radius: 16px;
    background: var(--color-surface-sunken);
    border: 1px solid var(--color-border-subtle);
    text-align: center;
  }

  .match-chat-msg__event-label {
    font-family: var(--font-title);
    font-weight: var(--weight-bold);
    font-size: 14px;
    line-height: 1.3;
    color: var(--color-porra-gold);
  }

  /* Emoji reactions clustered under the event label (overlapping bubbles, max 4). */
  .match-chat-msg__reactions {
    display: inline-flex;
    align-items: center;
  }

  .match-chat-msg__reaction {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin-left: -6px;
    border-radius: var(--radius-full);
    background: var(--color-surface);
    border: 1px solid var(--color-border-subtle);
    font-size: 12px;
    line-height: 1;
  }

  .match-chat-msg__reaction:first-child {
    margin-left: 0;
  }

  /* ── Skeleton + empty ── */
  .match-chat-skeleton {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: var(--space-3) var(--space-4);
  }

  .match-chat-skeleton[hidden] {
    display: none;
  }

  .match-chat-skeleton__row {
    height: 13px;
    border-radius: var(--radius-sm);
    background: var(--color-surface-sunken);
  }

  .match-chat-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 100%;
    padding: var(--space-6);
    text-align: center;
    color: var(--color-text-muted);
  }

  .match-chat-empty[hidden] {
    display: none;
  }

  .match-chat-empty__title {
    margin: 4px 0 0;
    font-family: var(--font-title);
    font-size: 15px;
    color: var(--color-text-secondary);
  }

  .match-chat-empty__sub {
    margin: 0;
    font-family: var(--font-body);
    font-size: 13px;
  }

  /* ── Jump-to-latest ── */
  .match-chat-jump {
    position: absolute;
    left: 50%;
    bottom: 128px;
    transform: translateX(-50%);
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 6px 14px;
    border: none;
    border-radius: var(--radius-full);
    background: var(--color-surface-active);
    color: var(--color-accent-fg);
    font-family: var(--font-body);
    font-weight: 700;
    font-size: 12px;
    box-shadow: var(--shadow-md);
    cursor: pointer;
  }

  .match-chat-jump[hidden] {
    display: none;
  }

  /* ── Composer + quick-emoji bar ── */
  .match-chat-composer {
    flex-shrink: 0;
    border-top: 1px solid var(--color-border-subtle);
    background: var(--color-surface);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  /* ── Emoji panel (WhatsApp launcher target) ──
     Ships hidden; the composer's 😊 launcher toggles it. A scrollable grid of
     insert-only emoji chips, docked above the input row. Built to grow into
     GIF / sticker tabs later. */
  .match-chat-emoji-panel {
    border-bottom: 1px solid var(--color-border-subtle);
    background: var(--color-surface);
    max-height: 196px;
    overflow-y: auto;
    scrollbar-width: none;
    animation: match-chat-emoji-in 0.16s ease;
  }

  .match-chat-emoji-panel[hidden] {
    display: none;
  }

  .match-chat-emoji-panel::-webkit-scrollbar {
    display: none;
  }

  @keyframes match-chat-emoji-in {
    from {
      opacity: 0;
      transform: translateY(6px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .match-chat-emoji-panel {
      animation: none;
    }
  }

  .match-chat-emoji-panel__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(40px, 1fr));
    gap: 2px;
    padding: var(--space-2) var(--space-3);
  }

  .match-chat-emoji-panel__chip {
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: var(--radius-md);
    background: transparent;
    font-size: 22px;
    cursor: pointer;
  }

  /* ── Emoji launcher button (composer row) ── */
  .match-chat-composer__emoji {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: var(--radius-full);
    background: var(--color-surface-sunken);
    color: var(--color-text-secondary);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
  }

  .match-chat-composer__emoji--open {
    background: color-mix(in oklab, var(--color-accent) 22%, var(--color-surface-sunken));
  }

  /* Side chip: a crest toggle that raises the side picker (sofascore style). It
     collapses (width + transform) while composing so the input gets full room. */
  .match-chat-composer__side {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: var(--radius-full);
    background: var(--color-surface-sunken);
    cursor: pointer;
    overflow: hidden;
    transition:
      width 0.26s var(--easing-default),
      opacity 0.26s var(--easing-default),
      margin 0.26s var(--easing-default),
      transform 0.26s var(--easing-default);
  }

  /* No chip until you've picked a side (author rule beats the UA [hidden], since
     the base rule sets display:inline-flex). */
  .match-chat-composer__side[hidden] {
    display: none;
  }

  .match-chat-composer__side-badge.match-chat-msg__avatar {
    width: 24px;
    height: 24px;
  }

  .match-chat-composer__side-badge img {
    width: 24px;
    height: 24px;
  }

  .match-chat-composer__side-badge.match-chat-msg__avatar--neutral::before {
    width: 11px;
    height: 11px;
  }

  /* Composing (input focused or non-empty) → the side chip slides out, input grows.
     The negative inline margin swallows the row gap so no empty slot is left. */
  .match-chat-composer--composing .match-chat-composer__side {
    width: 0;
    margin-inline-end: calc(var(--space-2) * -1);
    opacity: 0;
    transform: scale(0.4);
    pointer-events: none;
  }

  @media (prefers-reduced-motion: reduce) {
    .match-chat-composer__side {
      transition: none;
    }
  }

  .match-chat-composer__row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3) var(--space-3);
  }

  .match-chat-composer__input {
    flex: 1;
    min-width: 0;
    height: 40px;
    padding: 0 14px;
    border: none;
    border-radius: var(--radius-full);
    background: var(--color-surface-sunken);
    color: #fff;
    font-family: var(--font-body);
    font-size: 14px;
  }

  .match-chat-composer__input::placeholder {
    color: var(--color-text-muted);
  }

  .match-chat-composer__send {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: var(--radius-full);
    background: var(--color-accent);
    color: var(--color-on-accent);
    cursor: pointer;
  }

  .match-chat-composer__send[disabled] {
    opacity: 0.45;
    cursor: default;
  }

  .match-chat-composer--sending .match-chat-composer__send {
    pointer-events: none;
  }

  .match-chat-composer__input:disabled {
    opacity: 0.7;
    cursor: default;
  }

  /* Gated (anonymous) composer: the input keeps a sign-in nudge placeholder (set
     in JS) but stays focusable — the auth-gate fires on send / Enter, not here. */
  .match-chat-composer--gated .match-chat-composer__input {
    cursor: pointer;
  }

  .match-chat-composer__error {
    margin: 0;
    padding: 0 var(--space-3) var(--space-1);
    font-family: var(--font-body);
    font-size: 12px;
    color: var(--color-live);
  }

  .match-chat-composer__error[hidden] {
    display: none;
  }

  /* ── Emoji chip + launcher interaction ── */
  .match-chat-emoji-panel__chip:active {
    transform: scale(0.86);
  }

  @media (hover: hover) {
    .match-chat-emoji-panel__chip:hover {
      background: var(--color-surface-hover);
    }

    .match-chat-composer__emoji:hover {
      background: var(--color-surface-hover);
    }
  }

  /* ── Optimistic (in-flight) + failed own messages ── */
  .match-chat-msg--pending {
    opacity: 0.55;
  }

  .match-chat-msg--failed {
    box-shadow: inset 2px 0 0 var(--color-live);
  }

  /* Keep a failed row to one line so the grada density holds at 320px even with
     a 280-char body — the retry control takes the __time slot. */
  .match-chat-msg--failed .match-chat-msg__body {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .match-chat-msg__retry {
    flex-shrink: 0;
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: none;
    border-radius: var(--radius-full);
    background: transparent;
    color: var(--color-live);
    cursor: pointer;
  }

  /* ── Surge: a brief gold flash inside the sheet when the score changes. An
     overlay pseudo-element so it never clobbers the sheet's own drop shadow. ── */
  @media (prefers-reduced-motion: no-preference) {
    .match-chat-sheet--surge::after {
      content: "";
      position: absolute;
      inset: 0;
      pointer-events: none;
      border-radius: inherit;
      animation: match-chat-surge 1.2s var(--easing-default);
    }

    @keyframes match-chat-surge {
      0%,
      100% {
        box-shadow: inset 0 0 0 0 transparent;
        opacity: 0;
      }
      30% {
        box-shadow: inset 0 0 60px -10px var(--color-porra-gold);
        opacity: 1;
      }
    }
  }

  /* ── Floating emoji reactions (Instagram-Live): rise + fade off an emoji-only
     message as it flows in live. Overlay over the list; never blocks input. ── */
  .match-chat-floats {
    position: absolute;
    right: 4px;
    bottom: 128px;
    width: 92px;
    height: 52%;
    pointer-events: none;
    overflow: hidden;
    z-index: 3;
  }

  .match-chat-float {
    position: absolute;
    bottom: 0;
    font-size: 26px;
    line-height: 1;
    opacity: 0;
    will-change: transform, opacity;
  }

  @media (prefers-reduced-motion: no-preference) {
    .match-chat-float {
      animation: match-chat-float-up 2.6s var(--easing-default) forwards;
    }
  }

  @keyframes match-chat-float-up {
    0% {
      transform: translateY(0) scale(0.6);
      opacity: 0;
    }
    18% {
      opacity: 0.95;
    }
    100% {
      transform: translateY(-200px) scale(1.15);
      opacity: 0;
    }
  }

  /* ── Event card tint by type (goal/yellow/pen gold, red card, sub/var neutral) ── */
  .match-chat-msg__event--goal,
  .match-chat-msg__event--yellow,
  .match-chat-msg__event--pen {
    border-color: color-mix(in oklab, var(--color-porra-gold) 45%, transparent);
    background: color-mix(in oklab, var(--color-porra-gold) 12%, var(--color-surface-sunken));
  }

  .match-chat-msg__event--red {
    border-color: color-mix(in oklab, var(--color-live) 50%, transparent);
    background: color-mix(in oklab, var(--color-live) 14%, var(--color-surface-sunken));
  }

  .match-chat-msg__event--red .match-chat-msg__event-label {
    color: var(--color-live);
  }

  .match-chat-msg__event--sub .match-chat-msg__event-label,
  .match-chat-msg__event--var .match-chat-msg__event-label {
    color: var(--color-text-secondary);
  }

  /* ── Injected high-signal event (goal / red card) — a compact one-line strip
     with its reaction bar. The rich card lives in the narration tab; here it's a
     tinted line so the moment reads at a glance without becoming a liveblog. ── */
  .match-chat-event {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 6px var(--space-4);
    padding: 8px 12px;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-surface-sunken);
  }

  .match-chat-event--goal {
    border-color: color-mix(in oklab, var(--color-porra-gold) 45%, transparent);
    background: color-mix(in oklab, var(--color-porra-gold) 12%, var(--color-surface-sunken));
  }

  .match-chat-event--red {
    border-color: color-mix(in oklab, var(--color-live) 50%, transparent);
    background: color-mix(in oklab, var(--color-live) 14%, var(--color-surface-sunken));
  }

  .match-chat-event__line {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    font-weight: 700;
    line-height: 1.3;
  }

  .match-chat-event__icon {
    flex-shrink: 0;
    font-size: 15px;
    line-height: 1;
  }

  .match-chat-event__text {
    min-width: 0;
    overflow-wrap: anywhere;
  }

  .match-chat-event--goal .match-chat-event__text {
    color: var(--color-porra-gold);
  }

  .match-chat-event--red .match-chat-event__text {
    color: var(--color-live);
  }

  /* The reaction bar sits left-aligned under the event line (not 90%-centered). */
  .match-chat-event .match-chat-reactions {
    width: auto;
    justify-content: flex-start;
  }

  .match-chat-reactions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
    width: 90%;
  }

  /* Reaction strip docked INSIDE the .lbc event card (integrated look): full
     width of the card body, left-aligned, a hairline separating it from the
     content above. Covers both surfaces — the chat appends the bar inside .lbc,
     and the liveblog ticker renders it there server-side (chat-reactions). */
  .lbc .match-chat-reactions {
    width: auto;
    justify-content: flex-start;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid color-mix(in oklab, var(--color-text) 8%, transparent);
  }

  /* Compact per-message reaction bar (revealed on tapping a message row). */
  .match-chat-reactions--inline {
    width: auto;
    justify-content: flex-start;
    padding: 2px var(--space-4) 8px;
  }

  .match-chat-react {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: 30px;
    padding: 3px 10px;
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-full);
    background: var(--color-surface-sunken);
    color: var(--color-text-secondary);
    font-family: var(--font-body);
    font-size: 13px;
    cursor: pointer;
    transition: transform var(--duration-fast) var(--easing-default);
  }

  .match-chat-react:active {
    transform: scale(0.92);
  }

  .match-chat-react--mine {
    border-color: var(--color-accent);
    background: color-mix(in oklab, var(--color-accent) 18%, var(--color-surface-sunken));
    color: var(--color-accent-fg);
  }

  .match-chat-react__emoji {
    font-size: 15px;
    line-height: 1;
  }

  .match-chat-react__count {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
  }

  .match-chat-react__count[hidden] {
    display: none;
  }

  /* ═══════════════════════════════════════════════════════════════════
     La afición — dedicated /grada activity (full-screen page). Reuses the
     chat body (.match-chat-* list + composer + reactions); adds the hdrB
     hero header + the page shell. Immersive: fixed full viewport (mobile-
     first; desktop refinement lives on the desktop branch).
     ═══════════════════════════════════════════════════════════════════ */
  .grada {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--color-bg);
  }

  /* hdrB hero header — bicolor team wash + nav row + big score + status */
  .grada__header {
    position: relative;
    overflow: hidden;
    flex-shrink: 0;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-surface);
    padding-top: env(safe-area-inset-top, 0px);
  }

  .grada__header::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
      radial-gradient(
        ellipse 70% 130% at 10% 0%,
        color-mix(in oklab, var(--team-color-home, var(--color-accent)) 30%, transparent) 0%,
        transparent 60%
      ),
      radial-gradient(
        ellipse 70% 130% at 90% 0%,
        color-mix(in oklab, var(--team-color-away, var(--color-live)) 28%, transparent) 0%,
        transparent 60%
      );
  }

  .grada__header > * {
    position: relative;
    z-index: 1;
  }

  /* The compact match nav (`.hero-nav is-stuck`) sits inside .grada__header;
     its row layout (flex, 56px, transparent bg) comes from entity-hero.css and
     lets the bicolor wash read through. No sticky positioning here — body.grada-
     page isn't matched by the body.match-page sticky cascade, so the nav is a
     plain flex header row. The .hero-nav__match-title shows because `.is-stuck`
     flips its opacity (entity-hero.css, not body-scoped). */

  /* Wrapper owns the flex space + is the positioning context for the floating
     date pill (which must stay pinned over the top of the stream, not scroll
     with it). */
  .grada__stream-wrap {
    position: relative;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  /* Stream fills the gap between header and composer (reuses the sheet list
     chrome via .match-chat-sheet__list; this just tunes the page padding). */
  .grada__stream {
    flex: 1;
    min-height: 0;
    padding: var(--space-3) 0;
  }

  /* WhatsApp-style floating date pill — fades in over the top of the stream
     while scrolling, showing the day of the topmost visible messages
     (Hoy / Ayer / date). pointer-events:none so it never blocks taps. */
  .match-chat-datepill {
    position: absolute;
    top: 8px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 5;
    padding: 4px 12px;
    border-radius: var(--radius-full);
    background: color-mix(in oklab, var(--color-bg) 80%, transparent);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    /* Lighter rim + soft drop shadow so the pill lifts off the stream. */
    border: 1px solid color-mix(in oklab, #fff 22%, transparent);
    box-shadow: 0 4px 16px -4px rgb(0 0 0 / 50%);
    font-family: var(--font-body);
    font-size: 11px;
    font-weight: 700;
    color: var(--color-text);
    pointer-events: none;
    opacity: 0;
    transition: opacity 200ms ease;
  }

  .match-chat-datepill[hidden] {
    display: none;
  }

  .match-chat-datepill.is-visible {
    opacity: 1;
  }

  @media (prefers-reduced-motion: reduce) {
    .match-chat-datepill {
      transition: none;
    }
  }

  /* Composer pinned to the bottom of the page shell */
  .match-chat-composer--page {
    margin-top: auto;
  }

  /* ── Emoji picker sheet ("+" in the context menu) + report reason sheet ──
     Both are bottom-sheets sharing the openSheet hidden→.active slide-in
     mechanism (no backdrop — they sit over the immersive grada). Ship hidden
     (anti-FOUC); the controller reveals them. Scroll works without a visible
     scrollbar. The picker reuses the composer emoji grid look (DRY); the report
     sheet reuses the surface / radius tokens. ─────────────────────────────── */
  .match-chat-emoji-picker,
  .match-chat-report-modal {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 10000; /* above the chat sheet (9999) */
    display: flex;
    flex-direction: column;
    max-width: var(--content-max-width);
    margin: 0 auto;
    padding: 8px var(--space-4) calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
    background: var(--color-surface);
    border-radius: 20px 20px 0 0;
    box-shadow: 0 -4px 24px rgb(0 0 0 / 40%);
    transform: translateY(100%);
    transition: transform 0.3s ease-in-out;
    overscroll-behavior: contain;
    scrollbar-width: none;
  }

  .match-chat-emoji-picker::-webkit-scrollbar,
  .match-chat-report-modal::-webkit-scrollbar {
    display: none;
  }

  .match-chat-emoji-picker[hidden],
  .match-chat-report-modal[hidden] {
    display: none;
  }

  .match-chat-emoji-picker.active,
  .match-chat-report-modal.active {
    transform: translateY(0);
  }

  @media (prefers-reduced-motion: reduce) {
    .match-chat-emoji-picker,
    .match-chat-report-modal {
      transform: none;
      opacity: 0;
      transition: opacity 0.2s ease;
    }

    .match-chat-emoji-picker.active,
    .match-chat-report-modal.active {
      opacity: 1;
    }
  }

  @media (min-width: 1024px) {
    .match-chat-emoji-picker,
    .match-chat-report-modal {
      max-width: 480px;
      border-radius: 16px;
    }
  }

  /* Drag grip (decorative) — the bottom-sheet affordance, shared shape. */
  .match-chat-emoji-picker__grip,
  .match-chat-report-modal__grip {
    align-self: center;
    width: 36px;
    height: 4px;
    margin-bottom: 10px;
    border-radius: var(--radius-full);
    background: var(--color-border);
  }

  /* ── Emoji picker sheet ── */
  .match-chat-emoji-picker__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
  }

  .match-chat-emoji-picker__title {
    font-family: var(--font-title);
    font-weight: var(--weight-bold);
    font-size: 14px;
    color: var(--color-text-secondary);
  }

  .match-chat-emoji-picker__close {
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: var(--radius-full);
    background: var(--color-surface-sunken);
    color: var(--color-text-secondary);
    cursor: pointer;
  }

  .match-chat-emoji-picker__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
    gap: 4px;
    max-height: 40vh;
    overflow-y: auto;
    scrollbar-width: none;
  }

  .match-chat-emoji-picker__grid::-webkit-scrollbar {
    display: none;
  }

  .match-chat-emoji-picker__chip {
    height: 48px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    background: transparent;
    font-size: 25px;
    cursor: pointer;
    transition: transform var(--duration-fast) var(--easing-default);
  }

  .match-chat-emoji-picker__chip:active {
    transform: scale(0.86);
  }

  /* The viewer's current pick, highlighted like the inline react chip. */
  .match-chat-emoji-picker__chip.is-mine {
    border-color: var(--color-accent);
    background: color-mix(in oklab, var(--color-accent) 18%, var(--color-surface-sunken));
  }

  @media (hover: hover) {
    .match-chat-emoji-picker__chip:hover {
      background: var(--color-surface-hover);
    }

    .match-chat-emoji-picker__close:hover {
      background: var(--color-surface-hover);
    }
  }

  /* ── Report reason sheet ── */
  .match-chat-report-modal__title {
    margin: 0 0 10px;
    font-family: var(--font-title);
    font-weight: var(--weight-bold);
    font-size: 16px;
    color: var(--color-text);
    text-align: center;
  }

  .match-chat-report-modal__reasons {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 50vh;
    overflow-y: auto;
    scrollbar-width: none;
  }

  .match-chat-report-modal__reasons::-webkit-scrollbar {
    display: none;
  }

  .match-chat-report-modal__reason {
    display: flex;
    align-items: center;
    width: 100%;
    padding: 13px 14px;
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
    background: var(--color-surface-sunken);
    color: var(--color-text-secondary);
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
    transition: transform var(--duration-fast) var(--easing-default);
  }

  .match-chat-report-modal__reason:active {
    transform: scale(0.98);
  }

  @media (hover: hover) {
    .match-chat-report-modal__reason:hover {
      background: var(--color-surface-hover);
    }
  }

  .match-chat-report-modal__cancel {
    margin-top: 10px;
    width: 100%;
    padding: 13px;
    border: none;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--color-text-secondary);
    font-family: var(--font-body);
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
  }

  @media (hover: hover) {
    .match-chat-report-modal__cancel:hover {
      background: var(--color-surface-hover);
    }
  }

  /* The context menu's "+" (open the full picker) — a leading marker before the
     quick-set emoji buttons, visually a touch lighter than a glyph. */
  .match-chat-ctx__emoji--more {
    font-size: 22px;
    font-weight: 700;
    color: var(--color-text-secondary);
  }
}
