/* ============================================================================
   Juicy — Dashboard Design System · BUTTON
   ----------------------------------------------------------------------------
   Figma: sección Buttons (9:3119). 144 variantes:
     Color (9) × Size (Regular|Big) × Style (Fill|Outline)
              × Icon Position (None|Leading) × Shape (Rect|Pill)

   Los tonos NO viven aquí: se componen con .tone-* (ver tone.css).
     <button class="btn tone-primary">Guardar</button>
     <button class="btn btn--outline btn--round tone-error">Eliminar</button>
     <button class="btn btn--wide btn--icon-leading tone-primary"><svg …>Crear</button>

   OJO: en Figma el Button está cableado a PRIMITIVOS (`ui/500`, `neutral/white`)
   y solo Disabled usa la semántica — al revés que el Icon Button, que sí usa
   `action/*`. Aquí se consume la SEMÁNTICA a propósito: el valor resuelto es
   idéntico, pero así cambiar `action/primary/default` sí mueve el botón.
   ============================================================================ */

/* Tono por defecto en :where() — especificidad CERO, para que cualquier .tone-*
   lo gane sin depender del orden de carga de los archivos. Declararlo dentro de
   `.btn` empata (0,1,0) con `.tone-error` y gana el que se cargue después. */
:where(.btn) {
  --tone-fill: var(--action-primary-default);
  --tone-fg:   var(--action-primary-text);
  --tone-line: var(--tone-fill);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;

  height: var(--control-md);
  padding-inline: 20px;
  /* El vertical se declara aunque sea 0. La altura manda (nota de abajo), pero un
     `<button class="btn">` llega con el `padding: 1px 6px` del navegador y ese 1px
     de arriba y abajo sobrevivía —`padding-inline` no lo pisa—, así que el mismo
     botón medía distinto según se escribiera `<span>` (dashboard PHP) o `<button>`
     (front nuevo, para que se alcance con Tab). Medido con el espejo en "Ejecutar".
     `text-align` es el mismo caso: el navegador centra el texto de un button y en un
     span se hereda del contexto. Es INERTE en las dos formas (la caja es inline-flex
     con `justify-content: center`) y se declara para que midan igual, en vez de
     dejar una diferencia que hay que volver a explicar cada vez que se mide. */
  padding-block: 0;
  text-align: center;
  border: 0;
  border-radius: var(--radius-md);

  background: var(--tone-fill);
  color: var(--tone-fg);

  font-size: 13px;
  font-weight: 500;
  line-height: normal;
  letter-spacing: 1px;
  text-transform: uppercase;
  white-space: nowrap;

  overflow: clip;
  position: relative;  /* contexto para .btn::after (spinner de .loading, abajo) */
  cursor: pointer;
  text-decoration: none;
  transition: background-color .3s;
}

/* Figma declara padding vertical 12 con altura fija 40: con texto de 13px el
   alto de línea es 16 y 12+16+12 cae en 40 exactos. La altura manda porque el
   icono de 20px no cabría en esos 16px de contenido. */

.btn:focus-visible {
  outline: 2px solid var(--border-focus);
  outline-offset: 2px;
}

/* ---- Style --------------------------------------------------------------- */

/* Trazo por box-shadow inset, no por `border`: en Figma el stroke va por DENTRO
   (Outline y Fill miden lo mismo) y un `border` sumaría al ancho. */
.btn--outline {
  background: transparent;
  box-shadow: inset 0 0 0 var(--stroke) var(--tone-line);
  color: var(--tone-line);
}

.btn--ghost {
  background: transparent;
  color: var(--tone-line);
}

/* Hover de las tres variantes. El sólido oscurece; outline y ghost se RELLENAN.
   No lo inventa el DS: el dashboard ya lo hacía (`.button.ghost_button:hover`
   y `.button.clear_button:hover`), y es lo correcto — un control transparente
   necesita un cambio de estado más fuerte que un tinte para leerse. */
.btn:hover { background: var(--tone-hover); }

.btn--outline:hover,
.btn--ghost:hover {
  background: var(--tone-fill);
  color: var(--tone-fg);
}

/* Escape para cuando el relleno del hover estorba (el dashboard lo llamaba
   `hover_clear`): el control se queda transparente. */
.btn--no-hover-fill:hover {
  background: transparent;
  color: var(--tone-line);
}

/* ---- Width --------------------------------------------------------------- */

/* Era `Size=Big` en Figma. NO es un tamaño: mide 40 de alto igual que Regular —
   lo único que cambia es el padding horizontal (20 → 48). Ver nota 2. */
.btn--wide {
  padding-inline: 48px;
}

/* ---- Shape --------------------------------------------------------------- */

.btn--round {
  border-radius: var(--radius-round);
}

/* ---- Añadidos al aterrizar el dashboard (2026-07-16) ----------------------
   Estos tres NO salen del Figma: salen de botones que el dashboard usa de
   verdad y que el DS no tenía. Se les da nombre aquí en vez de dejarlos como
   clases sueltas del CSS viejo. */

/* Ocupa todo el ancho del contenedor. NO confundir con `--wide`, que solo
   ensancha el padding: son cosas distintas y el parecido del nombre es una
   trampa. En el dashboard esto era `fullwidth_button` (21 usos, width:100%);
   migrarlo a `--wide` habría dejado de estirar 21 botones sin dar error. */
.btn--full {
  width: 100%;
}

/* NO existe un `--lg`. Todos los botones miden 40 (`--control-md`), sin
   excepción. Aquí hubo uno de 50px entre 0.7.0 y 0.7.4, para acomodar el
   `big_botton` del dashboard — y fue un error doble:
     · La nota 2 de este mismo archivo YA decía que `Size=Big` del Figma es un
       nombre equivocado (los dos miden 40; lo que cambia es el padding
       horizontal) y que por eso se renombró a `--wide`. Lo escribí, y dos horas
       después creé el `--lg` que contradecía mi propia nota.
     · Ni siquiera reproducía el original: `big_botton` daba 45 (10 de base +
       15+15), no 50. Estaba mal hasta contra lo que copiaba.
   Sus 19 usos eran todos `btn--full btn--lg btn--round`: `--round` ya da la
   pastilla y `--full` el ancho. `--lg` no aportaba nada más que romper la regla.
*/

/* Botón callado: el color de la superficie, contenido oscuro. NO es un tono —
   su fondo es neutral/200 y los tonos neutrales del DS son 500/400/300, así que
   no hay a cuál mapearlo. Es un botón del color del fondo, no de un rol; por eso
   vive aquí como variante y no en tone.css. En el dashboard era
   `light_gray_button` (24 usos). */
.btn--quiet {
  --tone-fill: var(--surface-sunken);
  --tone-fg:   var(--text-primary);
}

/* ---- Icon ---------------------------------------------------------------- */
.btn__icon {
   font-size: 18px;
}

/* Regular + Leading mide 20/26 en Figma (asimétrico); Big + Leading mide 48/48.
   Transcrito tal cual — ver nota 3. */
.btn--icon-leading:not(.btn--wide) {
  padding-left: 20px;
  padding-right: 26px;
}

/* ---- Cargando ------------------------------------------------------------
   Estado real del dashboard que el Figma no contempla: al enviar un formulario
   el botón se vacía de texto y gira un spinner. Se porta tal cual (mismo
   tamaño, misma animación) — solo cambia que el color sale de `--tone-fg` en
   vez de `--btnTextColor`.
   Se activa poniendo `.loading` en un ANCESTRO, no en el botón: así el que
   dispara el envío no necesita conocer al botón. El `position:relative` que el
   spinner necesita ya vive en la base `.btn` (arriba). */
.btn::after {
  content: '';
  position: absolute;
  top: calc(50% - 8px);
  left: calc(50% - 8px);
  width: 13px;
  height: 13px;
  border-radius: 50%;
  border: 3px solid var(--tone-fg);
  border-left-color: transparent;
  opacity: 0;
  animation: btnSpin 1s infinite ease;
  transition: opacity .2s;
}

.loading .btn { color: transparent; opacity: .9; pointer-events: none; }
.loading .btn::after { opacity: 1; }

@keyframes btnSpin { to { transform: rotate(360deg); } }

/* ---- Disabled ------------------------------------------------------------ */

.btn:disabled,
.btn[disabled] {
  --tone-fill: var(--action-inactive-default);
  --tone-fg:   var(--action-inactive-text);
  --tone-line: var(--action-inactive-text);
  cursor: not-allowed;
  pointer-events: none;
}

/* Apagado PERO clickeable. El dashboard lo llamaba `semidisabled` y lo usa para
   botones que hay que poder pulsar aunque parezcan inertes (p.ej. para que el
   propio click explique por qué no se puede). No está en Figma. */
.btn--muted {
  --tone-fill: var(--action-inactive-default);
  --tone-fg:   var(--action-inactive-text);
  --tone-line: var(--action-inactive-text);
  opacity: .5;
}

/* ============================================================================
   NOTAS

   1. Los botones de Figma bindean `ui/500` / `neutral/white` (PRIMITIVOS) en
      lugar de `action/primary/default` / `action/primary/text`. Solo Disabled
      usa la semántica. El valor resuelto coincide, así que este archivo se ve
      idéntico — pero allá la capa `Tokens` está desconectada del Button:
      cambiar `action/*` no movería nada. Vale la pena re-bindear.

   2. `Size = Regular | Big` es un nombre equivocado: ambos miden 40 de alto.
      La propiedad es padding horizontal, no tamaño. Renombrado a `--wide` para
      dejar `size` libre y que signifique lo mismo que en el Icon Button (la
      altura real: 40 / 30). Hoy el Button no tiene variante de 30.

   3. Regular + Leading: padding 20 izq / 26 der. Su hermano Big + Leading es
      48/48 simétrico. Los 6px no tienen explicación óptica (el texto es
      UPPERCASE con letter-spacing 1px, que ya añade aire a la derecha).
      Casi seguro dedazo. Transcrito; dime y lo dejo en 20/20.

   4. NO hay estados hover/active/pressed en el Figma — ni una variante, ni un
      token `action/…/hover`. Un botón sin hover no es un botón.
      RESUELTO en tone.css con `--tone-hover: color-mix(fill 86%, black)`. Ojo
      con la historia: el producto ya tenía hovers, pero SIN convención — tres
      valores a mano con ΔE 7.9 / 9.9 / 30.0 respecto a su reposo. La fórmula
      no le pone nombre a una regla que existía, la INVENTA, y unifica los tres.
      Ver la nota Hover de tone.css.

   5. :focus-visible no está en el Figma. Añadido con `border/focus`
      (neutral/600), un token que existe y no usa nadie. Requisito de
      accesibilidad, no invención de color.

   6. Contraste: los rellenos de Figma REPRUEBAN AA tal como están diseñados.
      Arreglado en tone.css (ver su nota RELLENOS) — success 2.62→5.41,
      error 3.76→5.52, information 3.24→4.57, warning 2.26→6.98 invirtiendo el
      texto. OJO: "el 600 lo arregla" era un atajo mío y es falso para warning.

      LO QUE SIGUE SIN ARREGLO, y es decisión del dueño (2026-07-16: "dejarlo
      en 2.54 y seguir"): `primary` = cyan ui/500 con blanco da 2.54, y
      `secondary` = morado ui/400 da 4.05. Los dos por lo mismo — `ui` NO es
      una rampa de un tono (ui/700 es naranja), así que no hay a dónde bajarse.
      Las salidas medidas eran: texto oscuro sobre el cyan (6.20, que es lo que
      el propio producto ya hace con el ámbar) o bajar el cyan a ~70% (#007E84,
      4.86, pero ΔE 20.9: ya es otro color). Sin decidir, a propósito: es la
      marca y no la cambia el DS por su cuenta.

   7. Los anchos de Figma (100/156/134/184) NO son del componente: el nodo
      `Button Text` (9:3629) tiene ancho FIJO de 60px, y "BUTTON" en Montserrat
      Medium 13px/ls 1px mide 62.69px reales — el texto no cabe en su caja por
      2.7px y el overflow:clip lo tapa. Aquí el botón abraza su texto, que es lo
      correcto con etiquetas reales. NO cuadrar el CSS contra esos 100px.
      El resto de la caja sí verificado exacto: x=20 → padding-inline 20;
      y=12 + línea 16 + 12 = 40; radius 5.
   ============================================================================ */
