/* ════════════════════════════════════════════════════════════════════════════
   tokens.css — FUENTE ÚNICA de los tokens de runtime (P12-C1 · triplete P12-C2).
   El hex/rgba vive SOLO acá (regla §8 enmendada). Lo cargan AMBAS superficies:
   el blade surface (<link> antes de @vite) y el panel Filament (renderHook).
   Es la base de la semilla de skins de P12: cambiar un valor acá re-tematiza
   pública + panel sin tocar componentes.

   Colores sólidos = CANALES RGB ("R G B", P12-C2) para habilitar opacity-modifiers
   (bg-primary/10, from-primary/10, etc.): tailwind.config los mapea con
   rgb(var(--x) / <alpha-value>). Consumir SIEMPRE via utility o rgb(var(--x));
   NUNCA `color: var(--x)` directo (no es color válido — es un triplete).
   Bordes y shadows quedan como rgba/compuestos (no se opacity-modifican).

   Dark = default (:root). data-theme="light" = override de los MISMOS tokens.
   El panel Filament togglea dark por CLASE .dark; el panel-theme espeja esa
   clase a data-theme, así ambos sistemas resuelven contra este único set.
   Naming 100% semántico por rol — nunca por hue (nada de --amber).
   ════════════════════════════════════════════════════════════════════════════ */

/* Tipografía tabular — UNA pila (§13.5): el piso, el dealer y el tema del panel la
   alias-an (`--l-mono`). No depende del tema: va en :root a secas. */
:root {
    /* ★★ P68 — LA ESCALA DE REDONDEO, POR ROL (la pasada de coherencia).
       Medido antes de tocar nada: nuestras superficies usaban 4·5·6·7·8·9·10·11·12·14 px para
       tres cosas distintas, y la escala que DESIGN-TOKENS declaraba (8) no la usaba nadie. El
       problema no era el número: era que el mismo rol —una tarjeta— se redondeaba distinto según
       quién hubiera escrito el archivo. Tres valores, cada uno con su razón, y el nombre dice
       CUÁNDO va: nadie tiene que acordarse de un número.
       ⚠️ Los componentes de Filament traen el suyo y no se tocan: la regla es que LO NUESTRO
       hable con una sola voz. */
    --radio-detalle: 6px;   /* lo chico que se apoya sobre otra cosa: insignias, fichas, marcas */
    --radio-control: 8px;   /* lo que se toca: botones, campos, selects, celdas de asiento */
    --radio-tarjeta: 12px;  /* lo que CONTIENE: tarjetas, avisos, paneles, filas-bloque */
    --radio-pildora: 9999px;

    /* ★★ P68 — EL RELLENO DE LAS TARJETAS, TAMBIÉN POR ROL.
       Medido: `.card-h` existía en TRES archivos con tres rellenos distintos (15/18/12, 14/18/12,
       18/20) y la tarjeta elegible de una grilla tenía SEIS variantes (12/14, 13/14, 14, 12/8…).
       Mismo nombre, mismo objeto en pantalla, distinto número según quién escribió el archivo:
       eso no es una decisión de diseño, es inercia. Un valor por rol y el nombre dice cuál. */
    --pad-opcion: 12px 14px;      /* la tarjeta que se elige en una grilla (formato, velocidad…) */
    --pad-cabeza: 14px 18px 12px; /* la cabecera de una tarjeta de hub o escritorio */
    --pad-cuerpo: 4px 18px 16px;  /* su cuerpo — arranca pegado a la cabecera, respira abajo */

    --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
}

:root,
[data-theme='dark'] {
    color-scheme: dark;

    /* Marca (canales RGB) */
    --color-primary: 245 158 11;   /* #f59e0b */
    --color-danger: 220 38 38;     /* #dc2626 */
    --color-success: 16 185 129;   /* #10b981 */
    --color-info: 96 165 250;      /* #60a5fa — estado "programado/futuro" (azul más claro sobre dark) */
    --color-warning: 249 115 22;   /* #f97316 — "con consecuencia": avisos y verbos que cambian algo para todos.
                                      NO es el primario (ámbar): un aviso no puede vestirse de botón principal.
                                      Tres superficies lo consumían sin que existiera (P67 C14a, guardián CssVariablesResolveTest). */

    /* Superficies */
    --surface-base: 10 10 10;      /* #0a0a0a */
    --surface-elevated: 23 23 23;  /* #171717 */

    /* Texto */
    --text-default: 237 237 237;   /* #ededed */
    --text-muted: 163 163 163;     /* #a3a3a3 */
    /* ★ P74 (P70-A7-17, lo que quedó): el terciario pinta rótulos de 11–12 px (texto chico → 4,5:1)
       y daba 3,72:1 acá y 3,31:1 en claro: los dos temas tenían el gris del OTRO. Medido con
       `Contrast`: 5,73:1 sobre el fondo, 5,19:1 sobre la superficie elevada. */
    --text-dim: 138 138 138;       /* #8a8a8a */

    /* Bordes — hairline sobre dark (rgba compuesto, no triplete) */
    --border-default: rgba(255, 255, 255, 0.08);
    --border-strong: rgba(255, 255, 255, 0.14);

    /* Elevación dark = superficie + hairline (sin drop-shadow pesado) */
    --shadow-card: 0 0 0 1px rgba(255, 255, 255, 0.06);
    --shadow-modal: 0 0 0 1px rgba(255, 255, 255, 0.10), 0 24px 48px -12px rgba(0, 0, 0, 0.60);
}

[data-theme='light'] {
    color-scheme: light;

    /* ★★★ P72 (A7-17) — LA MARCA CONSERVA EL HUE Y BAJA EL TONO, PORQUE ACÁ EL FONDO ES CLARO.
       Esto decía «mismo hue en ambos temas» y repetía los VALORES del oscuro: el primario daba
       2,06:1 sobre #fafafa —contra el piso de 3,0 que el propio producto se puso— y el verde de
       éxito 2,43:1. O sea que los 24 blades que pintan texto con `--color-primary` (entre ellos el
       importe adeudado de la Caja) y el anillo de foco quedaban ilegibles en modo claro, que no
       necesita ni un click: el default de Filament es «system».
       Es EXACTAMENTE el defecto que P68 C16 midió y cerró para los TEMAS, en la paleta BASE — la
       que ve todo el panel. Medido con `Contrast` (§13.5): ámbar 4,81:1 · verde 5,25:1. */
    --color-primary: 180 83 9;     /* #b45309 — ámbar 700 */
    --color-danger: 220 38 38;     /* #dc2626 */
    --color-success: 4 120 87;     /* #047857 — esmeralda 700 */
    --color-info: 37 99 235;       /* #2563eb — azul más oscuro sobre light (contraste, como el diseño) */
    --color-warning: 234 88 12;    /* #ea580c — el mismo rol, un escalón más oscuro sobre light */

    /* Superficies invertidas */
    --surface-base: 250 250 250;   /* #fafafa */
    --surface-elevated: 255 255 255; /* #ffffff */

    /* Texto */
    --text-default: 23 23 23;      /* #171717 */
    --text-muted: 82 82 82;        /* #525252 */
    --text-dim: 107 107 107;       /* #6b6b6b — P74 (A7-17): 5,11:1 sobre el fondo, 5,33:1 sobre blanco */

    /* Bordes sobre light */
    --border-default: rgba(0, 0, 0, 0.08);
    --border-strong: rgba(0, 0, 0, 0.14);

    /* Light = sombra suave funcional */
    --shadow-card: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.10);
    --shadow-modal: 0 10px 15px -3px rgba(0, 0, 0, 0.10), 0 4px 6px -4px rgba(0, 0, 0, 0.10);
}

/* ── EL NÚMERO SE ACHICA PARA ENTRAR (P56) ─────────────────────────────────
   El defecto que esto arregla, medido: todos los tamaños de la proyección eran
   `clamp(min, Nvw, max)`, o sea que escalaban con el ANCHO DE LA PANTALLA y no
   con el LARGO DEL NÚMERO. `12 / 45` y `1.250.000 / 2.500.000` recibían el mismo
   tamaño en el mismo casillero, y como la tipografía es tabular el ancho crece
   estrictamente con la cantidad de caracteres: el número se salía de su caja.
   Juan lo vio en sala, y es donde más duele — es la pantalla de la pared.

   Con números de torneo grande la cuenta da que NO ENTRA, no que "puede no
   entrar": las ciegas `1.000.000 / 2.000.000` son 21 caracteres, y a 4.5rem
   (72px) piden 903px contra los ~811px que mide la columna central en 1920.

   El arreglo es EXACTO, no una aproximación, y la razón es la tipografía: IBM
   Plex Mono avanza 0.6em por carácter, siempre. Entonces N caracteres entran
   justo cuando `font-size = ancho_del_contenedor / (N × 0.6)`. Se usa 0.62 para
   dejar margen de redondeo.

   ⚠️ El techo sigue siendo el clamp de hoy (`--tbb-max`), así que un número
   NORMAL se ve EXACTAMENTE igual que antes: el `min()` elige el techo y sólo
   cuando el número no entra manda el otro término. No es un rediseño; es una red
   que aparece únicamente en el caso que rompía.

   ⚠️ `@supports` a propósito: un navegador sin container queries —una tele vieja
   de hotel— descarta el bloque entero y se queda con el clamp, que es lo que hay
   hoy. Degrada a lo anterior, nunca a algo roto.

   Cómo se usa: la CAJA lleva `tbb-fit-box` (es el contenedor que se mide) y el
   NÚMERO lleva `tbb-num` + su escalón; `--tbb-len` lo pone el markup (estático
   con `strlen`, vivo con el helper `fit()` de Alpine). */

.tbb-fit-box {
    container-type: inline-size;
}

/* Los escalones. El techo se declara UNA sola vez por escalón: es a la vez el
   font-size del fallback y el `--tbb-max` que el `min()` de abajo consume. */
.tbb-stat   { --tbb-max: clamp(1.1rem, 2vw, 2rem);      font-size: var(--tbb-max); }
.tbb-blinds { --tbb-max: clamp(1.5rem, 4vw, 4.5rem);    font-size: var(--tbb-max); }
.tbb-clock  { --tbb-max: clamp(4rem, 13vw, 20rem);      font-size: var(--tbb-max); }

@media (min-width: 1536px) {
    .tbb-blinds { --tbb-max: clamp(1.5rem, 6vw, 4.5rem); }
    .tbb-clock  { --tbb-max: clamp(4rem, 20vw, 20rem); }
}

/* ★ P68 — cuántos puestos se ven a la vez en la proyección. El resto se recorre solo (el carro lo
   mueve Alpine leyendo este número), así que la columna nunca pasa el borde de la pantalla. */
.tbb-premios ul { --tbb-premios-visibles: 8; }

@media (max-width: 767px), (max-height: 700px) {
    .tbb-premios ul { --tbb-premios-visibles: 5; }
}

.tbb-num {
    white-space: nowrap;
}

@supports (width: 1cqi) {
    .tbb-num {
        font-size: min(var(--tbb-max, 2rem), calc(100cqi / (var(--tbb-len, 8) * 0.62)));
    }
}

/* ════════════════════════════════════════════════════════════════════════════
   MOVIMIENTO (P68) — la capa de animación del producto.

   POR QUÉ VIVE ACÁ y no en su propia hoja: `tokens.css` es la ÚNICA hoja que
   cargan las DOS superficies (el blade público y el panel), y hoy la piden 25
   archivos. Una hoja aparte habría que sumarla en los 25 y la próxima
   superficie se olvidaría — el movimiento es un token de runtime igual que el
   color, así que comparte casa con el color.

   ⚠️ Y hay una razón dura: un `@keyframes` dentro del `<style>` de un
   componente LIVEWIRE dispara `MultipleRootElementsDetectedException` en cada
   render (P28 C2: 105 rojos). Los keyframes del producto viven acá y en
   ningún otro lado.

   Nombres por ROL, nunca por número ni por efecto — igual que los colores.
   ════════════════════════════════════════════════════════════════════════════ */

:root {
    /* Duraciones. El rol dice CUÁNDO se usa, así que elegir es leer la lista. */
    --motion-toque: 120ms;      /* el acuse de un click */
    --motion-rapido: 200ms;     /* hover, foco, un color que cambia */
    --motion-entra: 320ms;      /* algo que aparece */
    --motion-asienta: 520ms;    /* algo que llega a su lugar */
    --motion-respiro: 900ms;    /* la espera antes de un momento */

    /* Curvas. Cuatro alcanzan: más variedad se nota como inconsistencia. */
    --ease-sale: cubic-bezier(0.4, 0, 1, 1);
    --ease-entra: cubic-bezier(0, 0, 0.2, 1);
    --ease-natural: cubic-bezier(0.22, 0.61, 0.36, 1);
    --ease-resorte: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* La degradación. Va con `!important` a propósito, y es la ÚNICA excepción a
   la regla de cero-important de la hoja: acá no se está tematizando nada, se
   está honrando una preferencia de accesibilidad del sistema operativo que
   tiene que ganarle a cualquier animación, incluidas las que escriba mañana
   alguien que no leyó esto. Se apaga el movimiento, no el resultado: todo
   termina en su estado final, que es el que importa. */
@media (prefers-reduced-motion: reduce) {
    :root {
        --motion-toque: 1ms;
        --motion-rapido: 1ms;
        --motion-entra: 1ms;
        --motion-asienta: 1ms;
        --motion-respiro: 1ms;
    }

    *,
    *::before,
    *::after {
        animation-duration: 1ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 1ms !important;
        scroll-behavior: auto !important;
    }
}

/* ── LAS MICRO-INTERACCIONES ───────────────────────────────────────────────
   Pulido, no espectáculo: se sienten y no se miran. */

/* El foco SIEMPRE visible. `:where()` para que no le gane a nada por
   especificidad: cualquier componente que quiera su propio foco lo pisa sin
   pelear. Esto no es decoración — es cómo navega el que no usa mouse. */
:where(a, button, [role='button'], input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 2px solid rgb(var(--color-primary));
    outline-offset: 2px;
    border-radius: var(--radio-detalle);
}

/* Levanta al pasar por encima y se hunde al apretar. El hundido importa tanto
   como el levantado: es el acuse de que el click llegó. */
.tbb-eleva {
    transition:
        transform var(--motion-rapido) var(--ease-natural),
        box-shadow var(--motion-rapido) var(--ease-natural),
        border-color var(--motion-rapido) var(--ease-natural);
}

.tbb-eleva:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-card);
}

.tbb-eleva:active {
    transform: translateY(0) scale(0.985);
    transition-duration: var(--motion-toque);
}

/* Aparecer. Sale desde abajo un pelo — lo justo para que el ojo registre que
   algo llegó, sin que la página salte. */
@keyframes tbb-entra {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

.tbb-entra {
    animation: tbb-entra var(--motion-entra) var(--ease-entra) both;
}

/* ── EL PREMIO QUE SE TACHA ────────────────────────────────────────────────
   La línea se DIBUJA de izquierda a derecha en vez de aparecer entera: así se
   lee como "esto acaba de pasar" y no como "esto siempre estuvo así", que es
   justo la diferencia que la pantalla tiene que comunicar. */
@keyframes tbb-tacha {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
}

.tbb-tacha {
    animation: tbb-tacha var(--motion-asienta) var(--ease-natural) both;
    transform-origin: left center;
}

/* ── LA CEREMONIA DEL SOBRE (P68) ──────────────────────────────────────────
   El reveal del mystery es el momento más emocionante de la noche para el que
   lo abre, y se vive como tal: ocupa la pantalla, difumina lo de atrás, brilla
   y hace ruido. Antes era un golpecito de medio segundo en un rincón.

   UNA sola ceremonia para las DOS superficies (Regla 31): la pantalla del
   jugador y la proyección de la sala. Entre las dos sólo cambia la escala, si
   se nombra al cazador, y si hay cola.

   Todo se mide en `--cer-escala`: agrandarla para la sala es UN número. */

.tbb-cer {
    --cer-escala: 1;
    position: fixed;
    inset: 0;
    z-index: 90;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.tbb-cer--sala {
    --cer-escala: 2.1;
    cursor: default;
}

/* El fondo. Difuminado Y oscurecido: sólo oscurecer deja el texto de atrás
   legible y compitiendo; sólo difuminar deja la pantalla clara y el sobre no
   despega. Los dos juntos hacen que exista UNA sola cosa en la pantalla. */
.tbb-cer-fondo {
    position: absolute;
    inset: 0;
    background: rgb(var(--surface-base) / 0.82);
    backdrop-filter: blur(16px) saturate(0.6);
    -webkit-backdrop-filter: blur(16px) saturate(0.6);
    animation: tbb-cer-fondo var(--motion-entra) var(--ease-entra) both;
}

@keyframes tbb-cer-fondo {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.tbb-cer-chispas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 4;
}

.tbb-cer-escena {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* El hueco negativo es a propósito: la tarjeta sale HACIA ARRIBA del sobre, así que el
       nombre del cazador tiene que subir con ella o queda flotando en el vacío. */
    gap: calc(-44px * var(--cer-escala));
    perspective: calc(900px * var(--cer-escala));
    text-align: center;
    /* ⚠️ El relleno de arriba va DESPUÉS de la forma corta, no antes: `padding: 24px` pisa un
       `padding-top` declarado más arriba y el ajuste se pierde sin que nada avise.
       Por qué existe: la carta sube con un `transform`, que NO ocupa lugar en el layout, así que
       la caja se centra por el sobre y el nombre y el conjunto queda alto. Esto lo compensa. */
    padding: 24px;
    padding-top: calc(24px + 86px * var(--cer-escala));
}

/* ── El halo y los rayos ──
   Lo que convierte una tarjeta en un premio. El halo late durante el baile y
   estalla al abrirse; los rayos giran despacio atrás de todo. */
.tbb-cer-halo {
    position: absolute;
    left: 50%;
    top: calc(50% - 30px * var(--cer-escala));
    width: calc(360px * var(--cer-escala));
    height: calc(360px * var(--cer-escala));
    margin: calc(-180px * var(--cer-escala));
    border-radius: 50%;
    background: radial-gradient(circle,
        rgb(var(--color-primary) / 0.38) 0%,
        rgb(var(--color-primary) / 0.14) 38%,
        transparent 68%);
    z-index: 0;
    pointer-events: none;
    animation: tbb-cer-halo-late 1600ms var(--ease-natural) infinite;
}

@keyframes tbb-cer-halo-late {
    0%, 100% { opacity: 0.55; transform: scale(0.92); }
    50%      { opacity: 0.95; transform: scale(1.06); }
}

.tbb-cer[data-fase='abre'] .tbb-cer-halo,
.tbb-cer[data-fase='revela'] .tbb-cer-halo,
.tbb-cer[data-fase='sale'] .tbb-cer-halo {
    animation: tbb-cer-halo-estalla 1100ms var(--ease-entra) both;
}

@keyframes tbb-cer-halo-estalla {
    0%   { opacity: 1; transform: scale(0.9); }
    45%  { opacity: 1; transform: scale(1.5); }
    100% { opacity: 0.7; transform: scale(1.25); }
}

.tbb-cer-rayos {
    position: absolute;
    left: 50%;
    top: calc(50% - 30px * var(--cer-escala));
    width: calc(560px * var(--cer-escala));
    height: calc(560px * var(--cer-escala));
    margin: calc(-280px * var(--cer-escala));
    border-radius: 50%;
    z-index: 0;
    pointer-events: none;
    opacity: 0.14;
    background: repeating-conic-gradient(
        from 0deg,
        rgb(var(--color-primary) / 0.55) 0deg 3deg,
        transparent 3deg 30deg);
    mask-image: radial-gradient(circle, transparent 26%, #000 40%, transparent 62%);
    -webkit-mask-image: radial-gradient(circle, transparent 26%, #000 40%, transparent 62%);
    animation: tbb-cer-rayos 14s linear infinite;
}

@keyframes tbb-cer-rayos {
    to { transform: rotate(360deg); }
}

/* ── El sobre ── */
.tbb-cer-sobre {
    position: relative;
    z-index: 2;
    width: calc(200px * var(--cer-escala));
    height: calc(136px * var(--cer-escala));
    transform-style: preserve-3d;
    animation: tbb-cer-llega var(--motion-asienta) var(--ease-resorte) both;
}

@keyframes tbb-cer-llega {
    from { opacity: 0; transform: scale(0.3) translateY(50px) rotate(-12deg); }
    to   { opacity: 1; transform: none; }
}

/* El baile: se sacude cada vez más fuerte, como algo que está por abrirse
   solo. Tres vaivenes y para — más se vuelve gracioso en vez de emocionante. */
.tbb-cer[data-fase='baila'] .tbb-cer-sobre {
    animation: tbb-cer-baila var(--motion-respiro) var(--ease-natural) both;
}

@keyframes tbb-cer-baila {
    0%   { transform: rotate(0deg) scale(1); }
    12%  { transform: rotate(-5deg) scale(1.02); }
    26%  { transform: rotate(6deg) scale(1.04); }
    40%  { transform: rotate(-7deg) scale(1.06); }
    54%  { transform: rotate(8deg) scale(1.08); }
    68%  { transform: rotate(-9deg) scale(1.11); }
    84%  { transform: rotate(7deg) scale(1.14); }
    100% { transform: rotate(0deg) scale(1.16); }
}

.tbb-cer-cuerpo {
    position: absolute;
    inset: 0;
    border-radius: calc(12px * var(--cer-escala));
    background:
        linear-gradient(158deg,
            rgb(var(--color-primary) / 0.05) 0%,
            rgb(var(--color-primary) / 0.28) 100%),
        rgb(var(--surface-elevated));
    border: calc(2px * var(--cer-escala)) solid rgb(var(--color-primary) / 0.6);
    box-shadow:
        0 0 calc(70px * var(--cer-escala)) rgb(var(--color-primary) / 0.35),
        inset 0 calc(-18px * var(--cer-escala)) calc(30px * var(--cer-escala)) rgb(var(--surface-base) / 0.6),
        var(--shadow-modal);
    overflow: hidden;
}

/* El signo de pregunta: es lo que lo vuelve EL SOBRE DEL MYSTERY y no un
   sobre cualquiera. Se apaga cuando se abre, porque ya no hay misterio. */
.tbb-cer-cuerpo::before {
    content: '?';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    padding-bottom: 6%;
    font-family: var(--font-mono);
    /* Va ABAJO y no al centro: la solapa cerrada tapa la mitad de arriba, así que un signo
       centrado queda cortado por la punta de la V. Acá cae en la franja que se ve. */
    font-size: calc(2.5rem * var(--cer-escala));
    font-weight: 700;
    color: rgb(var(--color-primary) / 0.75);
    text-shadow: 0 0 calc(24px * var(--cer-escala)) rgb(var(--color-primary) / 0.6);
    transition: opacity var(--motion-rapido) var(--ease-sale);
}

.tbb-cer[data-fase='abre'] .tbb-cer-cuerpo::before,
.tbb-cer[data-fase='revela'] .tbb-cer-cuerpo::before,
.tbb-cer[data-fase='sale'] .tbb-cer-cuerpo::before {
    opacity: 0;
}

/* La solapa. Cerrada tapa la mitad de arriba; al abrirse gira sobre su borde
   superior y queda parada hacia atrás. */
.tbb-cer-solapa {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 60%;
    transform-origin: top center;
    transform-style: preserve-3d;
    background:
        linear-gradient(200deg,
            rgb(var(--color-primary) / 0.34) 0%,
            rgb(var(--color-primary) / 0.06) 100%),
        rgb(var(--surface-elevated));
    border: calc(2px * var(--cer-escala)) solid rgb(var(--color-primary) / 0.6);
    border-radius: calc(12px * var(--cer-escala)) calc(12px * var(--cer-escala)) 0 0;
    clip-path: polygon(0 0, 100% 0, 50% 100%);
    z-index: 3;
}

.tbb-cer[data-fase='abre'] .tbb-cer-solapa,
.tbb-cer[data-fase='revela'] .tbb-cer-solapa,
.tbb-cer[data-fase='sale'] .tbb-cer-solapa {
    animation: tbb-cer-solapa var(--motion-asienta) var(--ease-natural) both;
}

@keyframes tbb-cer-solapa {
    from { transform: rotateX(0deg); }
    to   { transform: rotateX(-168deg); }
}

/* La luz que sale del sobre abierto: dice "acá adentro hay algo". */
.tbb-cer-luz {
    position: absolute;
    left: 50%;
    top: 42%;
    width: calc(34px * var(--cer-escala));
    height: calc(34px * var(--cer-escala));
    margin: calc(-17px * var(--cer-escala));
    border-radius: 50%;
    background: rgb(var(--color-primary));
    opacity: 0;
    z-index: 2;
}

.tbb-cer[data-fase='abre'] .tbb-cer-luz,
.tbb-cer[data-fase='revela'] .tbb-cer-luz,
.tbb-cer[data-fase='sale'] .tbb-cer-luz {
    animation: tbb-cer-luz 1300ms var(--ease-entra) both;
}

@keyframes tbb-cer-luz {
    0%   { opacity: 0; box-shadow: 0 0 0 0 rgb(var(--color-primary) / 0.7); }
    28%  { opacity: 1; box-shadow: 0 0 calc(80px * var(--cer-escala)) calc(26px * var(--cer-escala)) rgb(var(--color-primary) / 0.55); }
    100% { opacity: 0; box-shadow: 0 0 calc(150px * var(--cer-escala)) calc(50px * var(--cer-escala)) rgb(var(--color-primary) / 0); }
}

/* ── LA CARTA QUE SALE DEL SOBRE Y GIRA ──
   Es el corazón de la ceremonia y la parte que decide si emociona o no.

   El monto NO aparece: sale IMPRESO en una carta que se saca del sobre. Y la
   carta sale **boca abajo**, se queda quieta un instante, y recién ahí gira.
   Ese instante de silencio es el que hace el momento: la subida es la
   expectativa, el giro es el premio. Es lo que hacen las mesas televisadas, y
   funciona porque separa "está pasando algo" de "esto es lo que te tocó".

   La carta es MÁS ANGOSTA que el sobre —una más ancha no pudo haber estado
   adentro, y el ojo lo nota aunque no sepa por qué— y CRECE al presentarse.

   El z-index salta de golpe en el fotograma en que la carta libra la boca del
   sobre: antes va detrás del cuerpo, después adelante. No se interpola, y no
   tiene que hacerlo. */
.tbb-cer-tarjeta {
    position: absolute;
    left: 50%;
    top: 50%;
    width: calc(164px * var(--cer-escala));
    height: calc(112px * var(--cer-escala));
    margin: calc(-56px * var(--cer-escala)) calc(-82px * var(--cer-escala));
    perspective: calc(1000px * var(--cer-escala));
    opacity: 0;
    z-index: 1;
}

.tbb-cer[data-fase='revela'] .tbb-cer-tarjeta,
.tbb-cer[data-fase='sale'] .tbb-cer-tarjeta {
    animation: tbb-cer-sale-del-sobre var(--motion-asienta) var(--ease-resorte) both;
}

@keyframes tbb-cer-sale-del-sobre {
    0%   { opacity: 0; z-index: 1; transform: translateY(calc(14px * var(--cer-escala))) scale(0.62); }
    30%  { opacity: 1; z-index: 1; transform: translateY(calc(-16px * var(--cer-escala))) scale(0.78); }
    31%  { z-index: 4; }
    72%  { opacity: 1; z-index: 4; transform: translateY(calc(-86px * var(--cer-escala))) scale(1.42) rotate(-2deg); }
    100% { opacity: 1; z-index: 4; transform: translateY(calc(-78px * var(--cer-escala))) scale(1.35) rotate(0deg); }
}

/* El giro. Arranca DESPUÉS de que la carta terminó de subir, con un respiro en
   el medio: sin esa pausa las dos cosas se leen como un solo movimiento y el
   momento se pierde. */
.tbb-cer-carta {
    position: absolute;
    inset: 0;
    transform-style: preserve-3d;
    transform: rotateY(0deg);
}

.tbb-cer[data-fase='revela'] .tbb-cer-carta,
.tbb-cer[data-fase='sale'] .tbb-cer-carta {
    animation: tbb-cer-gira 560ms var(--ease-natural) 620ms both;
}

@keyframes tbb-cer-gira {
    from { transform: rotateY(0deg); }
    to   { transform: rotateY(180deg); }
}

.tbb-cer-dorso,
.tbb-cer-frente {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: calc(9px * var(--cer-escala));
    border-radius: calc(11px * var(--cer-escala));
    border: calc(2px * var(--cer-escala)) solid rgb(var(--color-primary) / 0.75);
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    box-shadow:
        0 calc(18px * var(--cer-escala)) calc(40px * var(--cer-escala)) rgb(0 0 0 / 0.45),
        0 0 calc(50px * var(--cer-escala)) rgb(var(--color-primary) / 0.3);
}

/* El dorso: la marca sobre un rayado fino, como el reverso de una carta. */
.tbb-cer-dorso {
    background:
        repeating-linear-gradient(
            -45deg,
            rgb(var(--color-primary) / 0.16) 0 calc(2px * var(--cer-escala)),
            transparent calc(2px * var(--cer-escala)) calc(7px * var(--cer-escala))),
        linear-gradient(165deg,
            rgb(var(--color-primary) / 0.14) 0%,
            rgb(var(--color-primary) / 0.04) 100%),
        rgb(var(--surface-elevated));
}

.tbb-cer-dorso svg {
    width: calc(46px * var(--cer-escala));
    height: calc(46px * var(--cer-escala));
    color: rgb(var(--color-primary) / 0.85);
    filter: drop-shadow(0 0 calc(14px * var(--cer-escala)) rgb(var(--color-primary) / 0.55));
}

.tbb-cer-frente {
    transform: rotateY(180deg);
    container-type: inline-size;
    background:
        linear-gradient(165deg,
            rgb(var(--color-primary) / 0.10) 0%,
            rgb(var(--color-primary) / 0.24) 100%),
        rgb(var(--surface-elevated));
}

/* Las dos rayitas que enmarcan el número: es lo que la vuelve una FICHA de
   premio y no un rectángulo con un número adentro. */
.tbb-cer-frente::before,
.tbb-cer-frente::after {
    content: '';
    width: 46%;
    height: calc(1.5px * var(--cer-escala));
    background: rgb(var(--color-primary) / 0.45);
    border-radius: 2px;
}

.tbb-cer-monto {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
    font-size: calc(1.55rem * var(--cer-escala));
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1;
    color: rgb(var(--color-success));
    text-shadow: 0 0 calc(26px * var(--cer-escala)) rgb(var(--color-success) / 0.5);
    white-space: nowrap;
}

/* EL MONTO SE ACHICA PARA ENTRAR, con la misma aritmética exacta que el reloj de la proyección
   (P56): IBM Plex Mono avanza 0,6em por carácter, así que N caracteres entran justo cuando el
   cuerpo es ancho/(N × 0,62). Sin esto, un premio de siete cifras se sale de la ficha en un
   teléfono chico — y no falla ruidosamente, sólo se ve mal.
   El tope sigue siendo el tamaño de arriba: un monto normal se ve idéntico. */
@supports (width: 1cqi) {
    .tbb-cer-monto {
        font-size: min(
            calc(1.55rem * var(--cer-escala)),
            calc(86cqi / (var(--tbb-len, 8) * 0.62))
        );
    }
}

/* La onda: un anillo que se expande en el instante exacto en que la carta
   termina de girar. Es el golpe que marca el momento. */
.tbb-cer-onda {
    position: absolute;
    left: 50%;
    top: calc(50% - 78px * var(--cer-escala));
    width: calc(180px * var(--cer-escala));
    height: calc(180px * var(--cer-escala));
    margin: calc(-90px * var(--cer-escala));
    border-radius: 50%;
    border: calc(3px * var(--cer-escala)) solid rgb(var(--color-primary));
    opacity: 0;
    z-index: 3;
    pointer-events: none;
}

.tbb-cer[data-fase='revela'] .tbb-cer-onda,
.tbb-cer[data-fase='sale'] .tbb-cer-onda {
    animation: tbb-cer-onda 700ms var(--ease-entra) 900ms both;
}

@keyframes tbb-cer-onda {
    from { opacity: 0.85; transform: scale(0.35); border-width: calc(4px * var(--cer-escala)); }
    to   { opacity: 0; transform: scale(2.4); border-width: 0; }
}

.tbb-cer-cazador {
    position: relative;
    z-index: 3;
    font-size: calc(1.05rem * var(--cer-escala));
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: rgb(var(--text-default));
    opacity: 0;
}

.tbb-cer[data-fase='revela'] .tbb-cer-cazador,
.tbb-cer[data-fase='sale'] .tbb-cer-cazador {
    animation: tbb-entra var(--motion-entra) var(--ease-entra) 200ms both;
}

/* La salida: se va entera, sin desarmarse por partes. */
.tbb-cer[data-fase='sale'] {
    animation: tbb-cer-sale var(--motion-entra) var(--ease-sale) both;
}

@keyframes tbb-cer-sale {
    from { opacity: 1; }
    to   { opacity: 0; }
}

/* Alpine: lo que todavía no se hidrató no se muestra. Vive acá porque lo necesitan todas las
   superficies con islas Alpine, y repetirlo en cada partial era la copia número tres. */
[x-cloak] { display: none !important; }

/* ── EL LARGO DE LÍNEA (P68) ───────────────────────────────────────────────
   Un párrafo de prosa corrida se lee peor cuanto más largo es el renglón: el
   ojo pierde el salto de línea y hay que releer. La medida cómoda está entre
   60 y 75 caracteres, así que el tope se escribe en `ch` —que es el ancho del
   carácter de la fuente en uso— y no en píxeles: cambiar el cuerpo del texto
   no rompe la medida.

   Va sobre PROSA. Una tabla, un número grande o una fila de tarjetas usan todo
   el ancho que tengan: ahí el ojo no está leyendo renglones. */
.tbb-lectura {
    max-width: 68ch;
}

/* ── LAS TARJETAS DE PLAN, ALINEADAS FILA POR FILA (P68) ───────────────────
   Cada tarjeta era una columna suelta, así que el precio caía a tres alturas
   distintas: la insignia de «popular» empuja sólo a una, y las descripciones
   ocupan uno, dos o tres renglones según el plan. Con `subgrid` las filas las
   define la grilla de afuera y valen para las cuatro, así que el precio, la
   lista y el botón quedan a la misma altura POR CONSTRUCCIÓN — sin un
   `min-height` a ojo que tape el caso medido y se rompa con el texto que venga.

   Las seis filas son: insignia · nombre · descripción · precio · lista · botón.
   La quinta se estira, que es lo que hace que el botón quede abajo de todo. */
@supports (grid-template-rows: subgrid) {
    @media (min-width: 640px) {
        .tbb-planes {
            grid-template-rows: auto auto auto auto 1fr auto;
        }

        /* ⚠️ El selector va con el padre a propósito: la tarjeta trae `flex flex-col` de
           utilidades, que se cargan DESPUÉS de esta hoja y con la misma especificidad le
           ganarían por orden. Con el padre delante gana por especificidad y no por suerte. */
        .tbb-planes > .tbb-plan {
            display: grid;
            grid-row: span 6;
            grid-template-rows: subgrid;
            gap: 0;
        }
    }
}
