# Botón

> El botón de cristal fluido: el reflejo persigue al cursor en vez de saltar a él.

Paquete: `@pantherkit/design-system` · Archivo: `src/components/boton.css`

Se importa con:

```css
@import "@pantherkit/design-system/tokens.css";  /* siempre antes */
@import "@pantherkit/design-system/components.css";
```

La pieza se entrega como CSS, no como componente React: se aplica poniendo
las clases en tu propio marcado. No hay import de JavaScript que hacer.

## Qué es

La primera pieza que nace en el sistema y baja a los productos, en vez de al revés. Es cristal, no una pastilla sólida: el mismo material que la barra, y por eso el primario es blanco esmerilado y no blanco plano.

«Fluido» no es adorno del nombre. El reflejo especular no salta a la posición del cursor: la persigue con retardo, y ese retardo es lo que hace que la luz se lea como algo que fluye por dentro del cristal y no como un foco pegado al puntero. Se consigue registrando `--fx`/`--fy` con `@property` —sin registrar, una custom property es un token opaco y no se puede interpolar— y poniéndoles transición.

Se entrega como CSS y no como componente React a propósito: la landing es Astro sin React, y un botón no puede costarle a un sitio estático el peso de un framework. Los productos React envuelven esta misma clase.

## Clases

| Clase | Qué hace |
| --- | --- |
| `.fbtn` | La base. Cristal oscuro sobre tinta: la salida, la acción secundaria. |
| `.fbtn--primario` | La acción principal. Cristal blanco esmerilado con texto tinta: el elemento de más contraste de la página (~13:1), pero del mismo material que el resto. |
| `.fbtn--compacto` | Baja de 44px a 36px de alto. Para barras y fichas, donde el botón convive con texto de tamaño normal y no debe dominar. |

## Mandos

Custom properties que se redefinen desde fuera —con `style` o con una clase
propia— sin tocar el archivo del sistema.

| Propiedad | Por defecto | Qué controla |
| --- | --- | --- |
| `--fx / --fy` | `50% 50%` | La posición del reflejo. Registradas con @property, así que son interpolables y las mueve el guion del puntero. Sin guion se quedan en el centro y el botón funciona igual. |

## El marcado

Esto es exactamente lo que se pinta en la página `/componentes/boton`:
el mismo texto se inyecta ahí como pieza viva y se imprime aquí. No pueden
separarse.

### La jerarquía completa

Un primario por bloque y ni uno más. Dos acciones principales juntas no son dos: son ninguna, porque el ojo ya no sabe cuál es la que importa. El secundario es la salida, y existe para que el primario signifique algo.

```html
<div class="flex flex-wrap items-center gap-3">
  <button type="button" class="fbtn fbtn--primario">Agenda 30 minutos</button>
  <button type="button" class="fbtn">Ver el portafolio</button>
</div>
```

### Compacto, en una barra

En una barra de navegación el botón comparte línea con enlaces de texto. A 44px de alto se convierte en el objeto más pesado de la barra y la desequilibra; a 36px sigue siendo el elemento de más contraste sin gritar.

```html
<div class="flex flex-wrap items-center gap-4">
  <a href="/componentes" class="text-sm text-text-secondary">Componentes</a>
  <a href="/tokens" class="text-sm text-text-secondary">Tokens</a>
  <button type="button" class="fbtn fbtn--primario fbtn--compacto">Hablemos</button>
</div>
```

### Sobre un elemento que navega de verdad

`.fbtn` no aporta semántica ni foco: es material. Si la acción navega, es un `<a href>`; si dispara algo en la página, es un `<button type="button">`. Un `<div class="fbtn">` se ve idéntico y es invisible para el teclado y para un lector de pantalla.

```html
<a href="/componentes/cristal" class="fbtn">Ir al cristal</a>
```

## Cuándo NO usarla

La parte que más valor tiene. Cada una está aquí porque costó algo.

### Dos primarios en el mismo bloque.

El primario es el único elemento de la página con contraste de papel sobre tinta. Repetido, deja de señalar. Si de verdad hay dos acciones igual de importantes, el problema está en la sección, no en el botón.

### A todo el ancho del contenedor.

Un botón estirado se lee como una barra, no como una decisión. Por eso la ficha de proyecto le pone `align-self: flex-start` a su CTA en vez de dejarlo crecer.

### Sobre fondo claro.

El material está calculado sobre tinta: el velo, el filo (luz arriba, sombra abajo) y el `saturate(180%)` suponen que hay oscuridad detrás. Sobre papel el cristal oscuro se convierte en una mancha y el primario —texto tinta sobre blanco esmerilado— pierde el contraste que lo justifica.

### Como enlace dentro de un párrafo.

Eso no es una acción, es una referencia. Va con `--color-link`, que es el azul que sí cumple contraste sobre tinta (el de marca no llega; el porqué está en /tokens). El botón interrumpe la lectura a propósito; dentro de la prosa esa interrupción no la pide nadie.

### Pintado de naranja.

En este sistema el naranja significa punto de decisión y hay presupuesto de uno por sección. El botón ya es el punto de decisión por forma y contraste: teñirlo gasta el presupuesto sin añadir información.

## Tokens de los que depende

Si `tokens.css` no está importado antes, estas variables no existen y la
pieza se pinta con los valores iniciales del navegador —que no es un fallo
visible, es una pieza silenciosamente rota.

- `--ease-spring`
- `--dur-fast`
- `--dur-slow`
- `--color-text-primary`
- `--color-bg-primary`
- `--color-bg-surface-2`

## Qué queda cuando algo falla

- Sin el guion del puntero el botón funciona entero, con la luz centrada. El guion son dos líneas y no es requisito.
- Sin `backdrop-filter` (`@supports not`) el fondo cae a `--color-bg-surface-2` sólido. Un velo translúcido sin desenfoque detrás no es cristal, es un rectángulo turbio.
- Con `prefers-reduced-motion` se va el hundido al pulsar, pero el reflejo sigue encendiéndose al enfocar. Se va el movimiento, no la señal.

## Accesibilidad

- `:focus-visible` enciende el mismo reflejo y el mismo filo que `:hover`: quien navega con teclado ve exactamente lo que ve quien usa ratón.
- `.fbtn` mide 2.75rem = 44px de alto, el mínimo de superficie táctil.
- La clase no da rol ni foco. El elemento tiene que ser `<button>` o `<a href>` de verdad.

## Lo que el sistema todavía no resuelve

Valores literales y huecos conocidos. Se escriben para que nadie los
confunda con una decisión.

- `.fbtn--compacto` baja a 2.25rem = 36px, por debajo del mínimo táctil de 44px. En una barra de escritorio se justifica; en móvil habría que envolverlo en un objetivo mayor. La regla no está escrita en el paquete.
- No hay estado deshabilitado. `:disabled` no está contemplado en `boton.css`, así que un botón inerte hoy se ve idéntico a uno vivo.

---

Versión viva: <https://design.wearefaber.com/componentes/boton>
Índice de componentes: </componentes.md>
