/* La barra lateral.
 *
 * Opaca, del color de la paleta y con la silueta de Slack: cabecera con el
 * nombre de la cuenta, el salto como campo, y debajo las secciones en listas
 * de filas de 28px. Los tokens del papel estan remapeados a los de la paleta
 * en colors.css, asi que aqui casi todo es geometria. */
:root {
  --sidebar-inline-space: 0.75rem;
  /* Lo que reserva el final del scroll en movil, donde el rail se convierte
     en la bandeja inferior del cajon (rail.css). En escritorio es cero. */
  --sidebar-tools-height: 0px;
}

@media (max-width: 100ch) {
  :root {
    --sidebar-tools-height: calc(3.6rem + var(--safe-bottom));
  }
}

.sidebar__container {
  block-size: 100dvh;
  display: flex;
  flex-direction: column;
  max-block-size: 100dvh;
  padding-block-end: var(--sidebar-tools-height);
}

/* La cabecera: el nombre de la cuenta, como el del workspace en Slack. En
   movil deja sitio al tirador, que se queda dentro del cajon al abrirlo. */
.sidebar__head {
  align-items: center;
  border-block-end: 1px solid var(--sb-line);
  display: flex;
  flex: none;
  gap: var(--inline-space);
  min-block-size: var(--navbar-height);
  padding-block: calc(var(--block-space-half) + var(--safe-top)) var(--block-space-half);
  padding-inline: calc(var(--sidebar-inline-space) + 0.25rem) var(--sidebar-inline-space);

  @media (max-width: 100ch) {
    padding-inline-start: calc(var(--btn-size) + var(--sidebar-inline-space) + var(--inline-space));
  }
}

.sidebar__title {
  color: var(--sb-text-strong);
  flex: 1;
  font-size: 1.05rem;
  font-weight: 700;
  margin: 0;
  min-inline-size: 0;
}

.sidebar__scroll {
  flex: 1;
  min-block-size: 0;
  overflow-y: auto;
  padding-block-end: var(--block-space);
}

.sidebar__toggle {
  /* El unico control que abre la barra en movil (`display: none` por encima
     del breakpoint). Sobresale por el borde del cajon cerrado y se queda
     dentro de el al abrirlo. */
  inset-block-start: calc(var(--block-space-half) + var(--safe-top));
  inset-inline-end: calc((var(--btn-size) + max(var(--inline-space), 1vw)) * -1);
  position: absolute;
  transition:
    inset-inline-end 300ms ease,
    inset-inline-start 300ms ease,
    border-color 300ms ease,
    background-color 300ms ease;
  z-index: 5;

  #sidebar:where(:not(.open):has(.unread)) & {
    &::after {
      --size: 1em;

      aspect-ratio: 1;
      background-color: var(--color-negative);
      block-size: var(--size);
      border-radius: calc(var(--size) * 2);
      content: "";
      flex-shrink: 0;
      inline-size: var(--size);
      inset-block-start: calc(var(--size) / -4);
      inset-inline-end: calc(var(--size) / -4);
      position: absolute;
    }
  }

  @media (min-width: 100ch) {
    display: none;
  }

  .open & {
    @media (max-width: 100ch) {
      inset-inline-end: auto;
      inset-inline-start: var(--sidebar-inline-space);
    }
  }
}

/* Con la barra a la derecha, el tirador sobresale por el otro borde. */
@media (max-width: 100ch) {
  body.sidebar-end .sidebar__toggle {
    inset-inline: calc((var(--btn-size) + max(var(--inline-space), 1vw)) * -1) auto;
  }

  body.sidebar-end #sidebar.open .sidebar__toggle {
    inset-inline: auto var(--sidebar-inline-space);
  }
}

/* Direct messsages: el formulario de nuevo ping, que sigue usando la tira. */
.directs {
  --btn-border-color: var(--color-border-darker);
  --column-gap: calc(var(--inline-space) / 1.5);

  display: grid;
  grid-auto-columns: minmax(auto, max-content);
  grid-auto-flow: column;
  justify-content: start;
  margin-block-end: var(--block-space-half);
  padding-block: var(--block-space) var(--block-space-half);
  padding-inline: var(--sidebar-inline-space);

  &.directs--new {
    --column-gap: var(--inline-space);
    --row-gap: 2px;

    padding-inline-end: var(--sidebar-inline-space);
  }
}

/* Rooms */
.rooms {
  --column-gap: 0.5em;
  --row-gap: 1px;

  padding-inline: var(--sidebar-inline-space);
}

.room {
  background-color: var(--color-text-reversed);
  color: var(--color-text);
  font-weight: normal;
  justify-content: start;
  margin-inline-end: auto;
  max-inline-size: 100%;

  .searches-list & {
    border-radius: 0.5em;
  }

  &.unread {
    --btn-border-color: var(--color-text);
    --hover-color: var(--color-text);

    font-weight: 600;

    &:not(:hover) {
      box-shadow: 0 0 0 1px var(--color-text);
    }
  }
}

/* Searches */
.searches {
  #nav {
    align-items: start;
    column-gap: 0;
    padding-inline-end: 0;
  }

  .rooms {
    padding-block-start: var(--block-space);
  }
}

/* Un resultado de búsqueda, esté en la página o en el diálogo.
 *
 * Las dos superficies renderizan el mismo partial de mensaje con el mismo
 * helper, así que lo que un resultado tiene de distinto respecto a un mensaje
 * de sala se declara una vez para las dos y no dos veces. */
:is(.searches, .search__results) {
  .message--formatted .message__room {
    display: block;
    font-size: 0.8rem;
    font-weight: 400;
    overflow: hidden;
    text-overflow: ellipsis;
    visibility: visible;
    white-space: nowrap;

    &::before {
      content: "→";
    }
  }

  /* En estrecho la sala baja a su propia linea. En una sola fila se repartian
     el ancho autor, hora y sala, y el autor quedaba en "Edixo…": en una lista
     de resultados, quien lo dijo es la mitad de lo que se busca. */
  @media (max-width: 100ch) {
    .message--formatted .message__heading {
      flex-wrap: wrap;
    }

    .message--formatted .message__room {
      flex-basis: 100%;
    }
  }

  /* Editar o borrar se hace en la sala, no en una lista de resultados. */
  .message__actions {
    display: none !important;
    visibility: hidden !important;
  }

  /* Cada resultado se enciende al pasar, como una fila de cualquier buscador:
   * dice "esto se puede abrir" sin necesitar un botón. */
  .message {
    border-radius: 0.5em;

    &:hover {
      background-color: var(--color-message-bg);
    }
  }
}

.searches__recents {
  --mask: linear-gradient(to left, oklch(0% 0 0 / 1) 97%, oklch(0% 0 0 / 0) 99%);

  -webkit-mask-image: var(--mask);
  display: none;
  mask-image: var(--mask);
  position: relative;

  @media (max-width: 100ch) {
    display: flex;
  }

  .room {
    max-inline-size: 20ch;

    &:first-child {
      margin-inline-start: var(--inline-space);
    }
  }

  .searches__btn {
    margin-inline-end: var(--inline-space-double);
  }
}

.searches__query {
  --btn-border-radius: 0.5em;

  min-block-size: var(--btn-size);
}

.searches__results {
  padding-block-start: var(--block-space);
}

.searches__input:required:invalid {
  ~ .searches__reset {
    display: none;
    visibility: hidden;
  }
}

/* La X de limpiar era un icono de 14px sin caja: 10x14 de area. En tactil
   crece la caja, no el icono. */
@media (pointer: coarse) {
  .searches__input:valid ~ .searches__reset {
    align-items: center;
    display: inline-flex;
    justify-content: center;
    min-block-size: 44px;
    min-inline-size: 44px;
  }
}

/* Lo buscado, marcado dentro de cada resultado: sin esto, encontrar el término
 * en un mensaje largo es volver a buscar a ojo. */
.search-hit {
  background-color: var(--color-selected);
  border-radius: 0.2em;
  color: inherit;
  padding-inline: 0.05em;
}

.searches__empty {
  margin-inline: auto;
  max-inline-size: 40ch;
}

/* Grupos de la barra lateral
 *
 * La barra lateral se organiza por QUIEN habla -- personas, máquinas, archivo --
 * y no por lo último que pasó. En un chat de operaciones la mayoría de las salas
 * son robots, así que ordenar por actividad reciente pone un aviso de disco por
 * encima de la pregunta de un compañero. */

.alerts-group {
  --row-gap: 1px;

  margin-block-start: var(--block-space);
}

.alerts-quiet__summary {
  color: var(--sb-text-muted);
  cursor: pointer;
  font-weight: normal;
  justify-content: start;
  list-style: none;

  &::-webkit-details-marker {
    display: none;
  }

  &::after {
    content: "▸";
    font-size: 0.8em;
    margin-inline-start: 0.4em;
    transition: transform 150ms ease;
  }

  &:hover,
  &:focus-visible {
    color: var(--sb-text-strong);
  }
}

.alerts-quiet[open] .alerts-quiet__summary::after {
  transform: rotate(90deg);
}

.alerts-quiet__list {
  --row-gap: 1px;

  margin-block-start: 1px;
}

@media (prefers-reduced-motion: reduce) {
  .alerts-quiet__summary::after {
    transition: none;
  }
}

/* La puerta al archivo. Una entrada para 254 canales de doce años. */
.history-door {
  color: var(--sb-text-muted);
  justify-content: space-between;
  margin-block-start: var(--block-space-half);

  &:hover,
  &:focus-visible {
    color: var(--sb-text-strong);
  }
}

.history-door__count {
  color: inherit;
  flex-shrink: 0;
  opacity: 0.8;
}

/* Lo que ocultaste
 *
 * Se apoya en <details>, no en JavaScript: el navegador ya sabe plegar, y una
 * seccion que solo se abre y se cierra no necesita un controlador.
 */
.hidden-rooms {
  margin-block-start: var(--block-space-half);

  & > summary {
    color: var(--sb-text-muted);
    justify-content: space-between;
    list-style: none;

    &::-webkit-details-marker { display: none; }

    &:hover,
    &:focus-visible {
      color: var(--sb-text-strong);
    }
  }
}

.hidden-rooms[open] > summary .hidden-rooms__caret {
  transform: rotate(90deg);
}

.hidden-rooms__caret {
  flex-shrink: 0;
  transition: transform 100ms ease;
}

.hidden-rooms__count {
  color: inherit;
  flex-shrink: 0;
  opacity: 0.8;
}

.hidden-rooms__list {
  padding-inline-start: var(--inline-space);
}

.hidden-rooms__item {
  color: var(--sb-text-muted);
  justify-content: space-between;
  padding-block: calc(var(--block-space-half) / 2);

  &:hover {
    color: var(--sb-text);
  }
}

.hidden-rooms__restore {
  flex-shrink: 0;
  padding: 0;
}

/* El salto (⌘K)
 *
 * Con 274 salas ninguna lista cabe, así que llegar a lo que no se ve tiene que
 * costar dos letras. Esto es la navegación principal, no un adorno. Se lee
 * como un campo de busqueda, que es lo que es. */
.jump__open {
  --btn-border-color: var(--sb-line);
  --btn-border-radius: 0.5em;
  --btn-padding: 0.45em 0.7em;

  background-color: var(--sb-hover);
  color: var(--sb-text-muted);
  font-weight: normal;
  inline-size: 100%;
  justify-content: start;
  margin-block: var(--block-space-half) var(--block-space-half);
  max-inline-size: 100%;

  &:hover,
  &:focus-visible {
    --btn-border-color: var(--sb-line-strong);

    color: var(--sb-text-strong);
  }

  img {
    opacity: 0.7;
  }
}

.jump__open-label { flex-grow: 1; text-align: start; }

.jump__kbd {
  border: 1px solid var(--sb-line-strong);
  border-radius: 4px;
  flex-shrink: 0;
  font-family: inherit;
  font-size: 0.7em;
  opacity: 0.8;
  padding: 0.1em 0.35em;

  /* En un móvil no hay ⌘K que pulsar, así que la pista sobra. */
  @media (max-width: 100ch) {
    display: none;
  }
}

/* El dialogo del salto vive en el DOM de la barra pero es papel de la
   conversacion: la clase `surface` (colors.css) le devuelve sus tokens. */
dialog.jump {
  background: transparent;
  border: 0;
  max-block-size: 100dvh;
  max-inline-size: 100dvw;
  padding: 0;

  &::backdrop {
    backdrop-filter: blur(3px);
    background-color: oklch(0% 0 0 / 0.4);
  }
}

.jump__box {
  background-color: var(--color-bg);
  border: 1px solid var(--color-border-darker);
  /* Ver el mismo apunte en search.css: dentro de un `dialog` el color viene del
     UA (`canvastext`), que atiende al `color-scheme` del navegador y no al tema
     elegido en la app. Sin esto, "PERSONAS" y "SALAS" son negro sobre negro en
     tema oscuro. */
  color: var(--color-text);
  border-radius: 0.75em;
  box-shadow: 0 1em 3em oklch(0% 0 0 / 0.25);
  display: flex;
  flex-direction: column;
  inline-size: min(46ch, 92dvw);
  /* Anclado arriba y no centrado: la lista crece hacia abajo, y con el diálogo
   * centrado cada resultado nuevo movería el campo de texto bajo los dedos. */
  margin: 12dvh auto auto;
  max-block-size: 70dvh;
  overflow: hidden;
}

.jump__field {
  border-block-end: 1px solid var(--color-border);
  padding: 0.7em 0.9em;
}

.jump__input {
  background: transparent;
  border: 0;
  flex-grow: 1;
  font-size: 1rem;
  outline: 0;
}

.jump__close { --btn-size: 1.8em; flex-shrink: 0; }

.jump__results {
  overflow-y: auto;
  padding: 0.4em;
}

.jump__section {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  margin: 0.5em 0 0.2em;
  opacity: 0.5;
  padding-inline-start: 0.6em;
  text-transform: uppercase;
}

.jump__result {
  /* La foto, del tamaño de la fila. `.avatar` va en la propia <img> aquí, así
     que el tamaño se hereda desde la fila. */
  --avatar-size: 1.75rem;

  align-items: center;
  background: transparent;
  border: 0;
  border-radius: 0.5em;
  color: var(--color-text);
  cursor: pointer;
  display: flex;
  font-size: 0.95rem;
  gap: 0.6em;
  inline-size: 100%;
  padding: 0.45em 0.6em;
  text-align: start;
  text-decoration: none;

  /* button_to envuelve el botón en un form; sin esto cada resultado de persona
   * arrastraría el margen del formulario y la lista quedaría desigual. */
  form:has(&) { margin: 0; }
}

/* Marcado con el teclado y con el ratón a la vez: la clase la pone Stimulus al
 * moverse con las flechas, y :hover cubre el ratón. Mismo aspecto para los dos,
 * porque son la misma cosa: "esto es lo que va a pasar si sigues". */
.jump__result--on,
.jump__result:hover,
.jump__result:focus-visible {
  background-color: var(--color-selected);
  outline: 0;
}

.jump__name { flex-grow: 1; }

.jump__hash {
  flex-shrink: 0;
  inline-size: 28px;
  opacity: 0.45;
  text-align: center;
}

.jump__meta {
  flex-shrink: 0;
  font-size: 0.78em;
  opacity: 0.6;
}

.jump__empty { padding: 0.8em; }

.jump__legend {
  border-block-start: 1px solid var(--color-border);
  padding: 0.5em 0.9em;

  @media (max-width: 100ch) {
    display: none;
  }
}

/* Presencia
 *
 * Quién está conectado. Con treinta personas es la diferencia entre preguntar y
 * esperar, y hasta ahora los avatares no lo decían. */
.presence {
  aspect-ratio: 1;
  background-color: var(--color-positive);
  /* El borde del color del fondo separa el punto del avatar: sin él, sobre una
   * foto clara desaparece. */
  border: 2px solid var(--color-bg);
  border-radius: 50%;
  block-size: 0.85em;
  inline-size: 0.85em;
  inset: auto -1px -1px auto;
  position: absolute;
}

/* Los pings, en lista vertical con nombres.
 *
 * Como los mensajes directos de cualquier plataforma grande: una fila por
 * conversación, con nombre legible. La recencia ordena (sorted-list); lo sin
 * leer va en negrita con su punto, así que queda arriba y además se ve. */
.pings--list {
  --row-gap: 1px;

  padding-block: var(--block-space) var(--block-space-half);
  padding-inline: var(--sidebar-inline-space);
}

.pings__header,
.rooms__header {
  margin-block-end: 0.2em;
  padding-inline: 0.5em 0.15em;
}

/* Las filas del pliegue cuelgan de <details> y no del contenedor con .gap, asi
   que al abrir "Ver mas" salian pegadas mientras las visibles respiraban. */
.pings__more [data-ping-overflow-target="hidden"] > .ping-row {
  margin-block-start: var(--row-gap);
}

/* El + de la sección, pequeño y quieto en la cabecera. */
.pings__add,
.rooms__add {
  --btn-size: 1.6em;
  --btn-border-size: 0;

  background-color: transparent;
  opacity: 0.7;

  &:hover,
  &:focus-visible {
    background-color: var(--sb-hover);
    opacity: 1;
  }
}

/* Ojo: nada de `&__sufijo` anidado -- el nesting de CSS nativo no concatena
 * nombres como Sass, y la regla se pierde en silencio. Selectores completos. */
.ping-row {
  --avatar-size: 1.35rem;

  align-items: center;
  border-radius: 0.4em;
  color: var(--sb-text);
  display: flex;
  gap: 0.6em;
  min-block-size: 1.75rem;
  padding: 0.15em 0.5em;
  text-decoration: none;

  .avatar img {
    border-radius: 0.3rem;
  }

  .avatar--icon {
    --avatar-size: 1.5rem;

    border-color: var(--sb-line-strong);
    font-size: 0.7rem;
  }

  &:hover,
  &:focus-visible {
    background-color: var(--sb-hover);
    color: var(--sb-text-strong);
    outline: 0;
  }
}

.ping-row__name {
  flex-grow: 1;
  font-weight: normal;
}

.ping-row.unread {
  color: var(--sb-text-strong);
}

.ping-row.unread .ping-row__name {
  font-weight: 700;
}

/* Un punto y no un número: Campfire guarda unread_at, una marca de tiempo, no
 * un contador. Inventar la cifra seria mentir sobre el dato que hay. */
.ping-row__unread {
  aspect-ratio: 1;
  background-color: var(--sb-badge);
  block-size: 0.55em;
  border-radius: 50%;
  flex-shrink: 0;
  inline-size: 0.55em;
}

/* Un grupo se distingue por cuántos son, en la esquina del avatar. */
.ping-row__count {
  background-color: var(--sb-bg);
  border: 1px solid var(--sb-line-strong);
  border-radius: 0.5em;
  color: var(--sb-text);
  font-size: 0.55rem;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  inset: auto -0.45em -0.35em auto;
  line-height: 1;
  padding: 0.15em 0.3em;
  position: absolute;
}

/* La puerta al directorio, al final de la lista. */
.direct__everyone-count {
  border: 1px dashed var(--sb-line-strong);
  font-size: 0.7rem;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.direct__everyone,
.pings__more-summary {
  color: var(--sb-text-muted);
}

/* El pliegue de los pings
 *
 * <details> y no JavaScript: el navegador ya sabe plegar. Lo unico que necesita
 * codigo es sacar del pliegue un ping que recibe mensaje, y eso lo hace
 * ping_overflow_controller.
 */
.pings__more {
  & > summary {
    list-style: none;

    &::-webkit-details-marker { display: none; }
  }

  &[open] > summary {
    opacity: 0.6;
  }
}

.pings__more-count {
  border: 1px dashed var(--sb-line-strong);
  font-size: 0.7rem;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

/* Cabeceras de sección de la barra, como las de cualquier plataforma grande:
 * pequeñas, en mayúsculas, sin competir con las filas. */
.rooms__heading {
  color: var(--sb-text-muted);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  margin: 0;
  text-transform: uppercase;
}

/* Filas planas en la barra: una fila que se enciende al pasar y se marca
 * cuando estás dentro. Solo dentro de #sidebar: fuera (los recientes del
 * buscador en móvil) el pill sigue. */
#sidebar .room {
  --btn-border-size: 0;
  --hover-size: 0;

  background-color: transparent;
  border-radius: 0.4em;
  box-shadow: none;
  color: var(--sb-text);
  font-weight: normal;
  inline-size: 100%;
  margin-inline-end: 0;
  max-inline-size: 100%;
  min-block-size: 1.75rem;
  padding: 0.15em 0.5em;

  &:hover,
  &:focus-visible {
    background-color: var(--sb-hover);
    color: var(--sb-text-strong);
  }

  &.unread {
    color: var(--sb-text-strong);
    font-weight: 700;

    &:not(:hover) {
      box-shadow: none;
    }

    &::after {
      aspect-ratio: 1;
      background-color: var(--sb-badge);
      block-size: 0.55em;
      border-radius: 50%;
      content: "";
      flex-shrink: 0;
      inline-size: 0.55em;
      margin-inline-start: auto;
    }
  }
}

/* En tactil las filas de la barra miden 44px, como el resto de areas de
 * pulsacion (buttons.css). A 1.75rem eran 28px de alto con 1-2px entre una y
 * otra: en el telefono se abria la sala de al lado. Con raton no cambia nada. */
@media (pointer: coarse) {
  #sidebar .room,
  .ping-row {
    min-block-size: 44px;
  }
}

.room__hash {
  flex-shrink: 0;
  font-weight: 400;
  inline-size: 1em;
  opacity: 0.6;
  text-align: center;

  img {
    display: block;
    filter: invert(calc(var(--icon-invert) * 100%));
    inline-size: 0.9em;
  }
}

/* La sala abierta, marcada en la barra con el acento. La clase la pone
 * rooms_list_controller al navegar; el color aguanta el hover para que la
 * marca no parpadee. El :is() iguala la especificidad de la regla de fila de
 * arriba para poder ganarle por orden. */
#sidebar :is(.room, .ping-row).room--active,
#sidebar :is(.room, .ping-row).room--active:hover,
#sidebar :is(.room, .ping-row).room--active:focus-visible {
  background-color: var(--sb-active);
  color: var(--sb-active-text);
  font-weight: 600;

  .room__hash,
  .ping-row__name {
    opacity: 1;
  }

  .ping-row__count {
    background-color: var(--sb-active);
    border-color: var(--sb-active-text);
    color: var(--sb-active-text);
  }
}
