/* ============================================================================
   Faro — hoja de estilo de la maqueta.

   Reparto de trabajo con Tailwind: Tailwind (CDN) cubre utilidades sueltas en
   el marcado estático. Todo lo estructural y todo lo que cambia en tiempo de
   ejecución vive acá, seleccionado por [data-estado] y no por clases.

   Ese reparto no es capricho. El CDN de Tailwind compila en el navegador y
   vuelve a compilar cada vez que aparece una clase nueva en el DOM; si el
   estado de las tareas se pintara con clases de Tailwind, el televisor
   recompilaría CSS en medio de cada animación. Con atributos, el observador de
   Tailwind no tiene nada que hacer después del primer pintado. Y si la red del
   televisor falla y el CDN no carga, el tablero sigue entero.

   Reglas de rendimiento (SoC de televisor):
     - Se anima únicamente transform y opacity.
     - Sin backdrop-filter, sin sombras animadas, sin filtros animados.
   ========================================================================== */

/* --- Tipografía autohospedada -------------------------------------------- */
/* Palo seco geométrico, altura de x generosa: es lo que se lee a 3 metros.
   Autohospedada, nunca de un CDN de terceros: la red del televisor es lenta y
   el CDN puede fallar justo a la hora de bañarse.

   Tal como está, usa la fuente si ya está instalada en el sistema y si no cae a
   la pila de abajo (en webOS, LG Smart UI). Cuando dejes el archivo en
   assets/fonts/faro-sans.woff2, descomentá la línea del url — está comentada a
   propósito para que el televisor no pida un archivo que no existe y ensucie la
   consola con un 404. Ver assets/fonts/LEEME.md. */
@font-face {
  font-family: 'Faro Sans';
  src: local('Outfit'), local('Inter');
  /* src: local('Outfit'), local('Inter'), url('../fonts/faro-sans.woff2') format('woff2'); */
  font-weight: 100 900;
  font-display: swap;
}

:root {
  /* Paleta. Base azul-pizarra profundo, no negro puro: el negro puro con
     elementos brillantes es agresivo de noche y agrava el burn-in. */
  --fondo: #16202E;
  --fondo-carril: #1F2C3D;
  --texto: #F2F6FA;
  --texto-suave: #8FA3B8;
  --luz: #FFD166;

  /* El anillo de foco NO usa el ámbar: el ámbar es de la luz y de nada más. */
  --anillo: #F2F6FA;

  /* Verde de éxito. Uno solo para los cuatro: verde = hecho, en todo el tablero,
     que es lo que un chico de 6 aprende de una. Se eligió bien separado del
     turquesa de identidad de Sil para que no se confundan. */
  --exito: #4ADE80;

  /* "Falta que un adulto pase". Ácido a propósito: el ámbar de la luz es
     cálido, y confundirlos daría el mensaje contrario. */
  --espera: #FFEA00;

  /* Cómo salió una tarea ya calificada: entera (verde), a medias (ámbar) o sin
     puntos (coral). Son los mismos tres del panel, para que la tele y el
     celular no digan lo mismo con colores distintos. */
  --ambar: #F59E0B;
  --coral: #FB7185;

  /* Rebote. La misma curva para todo lo que celebra, así los efectos se sienten
     parte de un solo movimiento y no de cinco sueltos. */
  --rebote: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* Multiplicador global de tipografía. Se ajusta con las teclas 3 y 4 sobre
     el televisor real y se persiste. */
  --escala: 1;

  /* Escala para 1080p a 3 metros. Base en vh para que los cuatro carriles
     entren sin scroll también en el viewport recortado de webOS (~950px). */
  --t-reloj:    calc(clamp(3.5rem,  9.5vh, 7.5rem) * var(--escala));
  --t-crono:    calc(clamp(3rem,    9vh,   6rem)   * var(--escala));
  --t-nombre:   calc(clamp(1.75rem, 4.6vh, 3.25rem) * var(--escala));
  --t-tarea:    calc(clamp(1.3rem,  2.9vh, 2.05rem) * var(--escala));
  --t-etiqueta: calc(clamp(1.25rem, 2.5vh, 1.6rem) * var(--escala));
  --t-min:      calc(1.25rem * var(--escala));   /* mínimo absoluto: 20px */

  --radio: 1rem;
  --gap: clamp(0.5rem, 1.1vh, 1rem);

  /* Ancho de las canaletas laterales de cada carril, donde van los rótulos de
     "hay más tareas para ese lado". */
  --canaleta: clamp(2.1rem, 3vw, 3.4rem);

  /* Aire vertical que la tira desplazable se toma por fuera de su marco para que
     el anillo de foco no se recorte. Lo usan la tira y los degradados de borde,
     que tienen que cubrir exactamente la misma franja. */
  --tira-aire: 14px;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;               /* el tablero nunca hace scroll */
  background: var(--fondo);
  color: var(--texto);
}

body {
  font-family: 'Faro Sans', system-ui, 'LG Smart UI', 'Segoe UI', Roboto,
               'Helvetica Neue', Arial, sans-serif;
  font-size: var(--t-etiqueta);
  line-height: 1.15;
  -webkit-font-smoothing: antialiased;
  /* Nada de selección de texto ni de resaltado táctil en un televisor. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  cursor: default;
}

/* Los números nunca saltan al animarse. */
.cifras { font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1; }

/* Los emoji necesitan su propia pila: si el televisor no trae una fuente de
   emoji en color, al menos cae a la monocroma en lugar de a un cuadrito. */
.emoji {
  font-family: 'Noto Color Emoji', 'Segoe UI Emoji', 'Apple Color Emoji',
               'Noto Emoji', sans-serif;
  font-weight: 400;
  line-height: 1;
}

/* ============================================================================
   Foco
   ========================================================================== */

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
  text-align: left;
}

/* :focus, NO :focus-visible. En un televisor el anillo se ve siempre. */
button:focus { outline: none; }

.enfocable:focus {
  /* Borde de 6px + halo suave, con box-shadow para no provocar reflow.
     La sombra es estática; lo único que se anima es el transform.

     Sin sombra difuminada: el anillo tiene que caber dentro del relleno de la
     tira desplazable para que no se recorte contra el borde, y de paso una
     sombra nítida es más barata de pintar que una con blur, que en el SoC del
     televisor se nota. */
  box-shadow:
    0 0 0 6px var(--anillo),
    0 0 0 12px rgba(242, 246, 250, 0.18);
  transform: scale(1.03);
  z-index: 30;
}

.enfocable {
  position: relative;
  transform: scale(1);
  transition: transform 130ms ease-out;
  will-change: transform;
}

/* ============================================================================
   Estructura
   ========================================================================== */

#app { height: 100%; }

.shell {
  position: relative;
  height: 100%;
  /* Margen de seguridad del 5%: los televisores recortan los bordes. */
  padding: 2.6vh 2.6vw;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  overflow: hidden;
}

/* --- Cabecera: la meta familiar es el titular, no un accesorio ------------ */

.cabecera {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.4vw, 2.5rem);
  padding: 0 clamp(0.5rem, 1vw, 1.25rem);
}

.momento { flex: 0 0 auto; }

.reloj {
  font-size: var(--t-reloj);
  font-weight: 300;
  line-height: 0.95;
  letter-spacing: -0.02em;
  color: var(--texto);
}

.fecha {
  margin-top: 0.3em;
  font-size: var(--t-min);
  color: var(--texto-suave);
  letter-spacing: 0.06em;
  white-space: nowrap;
}

/* Solo la inicial. Con text-transform: capitalize salía "Jueves 30 De Julio". */
.fecha::first-letter, .reposo__fecha::first-letter { text-transform: uppercase; }

.faro-bloque { flex: 1 1 auto; min-width: 0; }

.faro-fila {
  display: flex;
  align-items: baseline;
  gap: clamp(0.6rem, 1.4vw, 1.5rem);
  margin-bottom: 0.5vh;
}

.faro-titulo {
  font-size: var(--t-nombre);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.faro-premio {
  font-size: var(--t-etiqueta);
  color: var(--texto-suave);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.faro-cifra {
  flex: 0 0 auto;
  font-size: var(--t-nombre);
  font-weight: 600;
}

/* El faro de la cabecera.
   La torre está SIEMPRE a la vista; lo que se apaga y se enciende es el haz.
   Con el emoji había que aclarar el dibujo entero, que se leía como "el faro
   está a medias"; acá el faro está siempre y la luz se prende, que es
   literalmente lo que dice la metáfora. */
.faro-icono {
  flex: 0 0 auto;
  align-self: center;
  width: calc(var(--t-nombre) * 1.7);
  height: calc(var(--t-nombre) * 1.7);
  --haz-opacidad: 0.16;
  transform: scale(1);
  transition: opacity 600ms ease-out;
}

/* La opacidad del haz no se puede transicionar desde acá: vive dentro del árbol
   de <use> y sólo llega como variable. El cambio es instantáneo y está bien,
   porque justo después el ícono da un pulso que se lleva la atención. */
.faro-encendido .faro-icono { --haz-opacidad: 1; }
.faro-encendido .faro-icono.pulso,
.faro-icono.pulso { animation: pulso-faro 900ms ease-out 1; }

/* --- Barras de progreso -------------------------------------------------- */
/* Crecen con transform: scaleX. Animar width provoca layout en cada frame. */

.barra {
  position: relative;
  height: clamp(0.6rem, 1.5vh, 1.1rem);
  border-radius: 999px;
  background: rgba(143, 163, 184, 0.18);
  overflow: hidden;
}

.barra__relleno {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: var(--miembro, var(--texto));
  transform-origin: left center;
  transform: scaleX(var(--p, 0));
  transition: transform 750ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

.barra--faro { height: clamp(0.8rem, 2vh, 1.5rem); }
.barra--faro .barra__relleno { background: linear-gradient(90deg, #5B7CA8, #9FC0E0); }
.faro-encendido .barra--faro .barra__relleno { background: linear-gradient(90deg, #C9A24B, var(--luz)); }

/* --- Zona de carriles ---------------------------------------------------- */

.zona {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

/* Contenedor de los carriles. display:contents para que los cuatro carriles
   participen directamente del flex de .zona, que es quien posiciona la luz.
   Va acá y no como utilidad de Tailwind: si el CDN no carga, el tablero tiene
   que seguir armado. */
#carriles { display: contents; }

.carril {
  position: relative;
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 1.6vw, 1.75rem);
  padding: 0 clamp(0.75rem, 1.4vw, 1.5rem);
  border-radius: var(--radio);
  /* Un paso más claro que el fondo: separa sin necesidad de líneas. */
  background: var(--fondo-carril);
  /* El anillo de foco de los botones no se puede recortar. */
  overflow: visible;
  z-index: 1;
}

/* Filo de identidad del miembro. Estático. */
.carril::before {
  content: '';
  position: absolute;
  left: 0;
  top: 12%;
  bottom: 12%;
  width: 6px;
  border-radius: 999px;
  background: var(--miembro);
  opacity: 0.9;
}

/* --- Identidad del miembro ----------------------------------------------- */

/* Un poco más ancha que antes para que los siete días de la semana entren
   cómodos debajo de la barra. Lo que cede va a la tira de tareas, que se
   desplaza igual. */
.identidad {
  flex: 0 0 clamp(14rem, 17%, 20rem);
  display: flex;
  align-items: center;
  gap: clamp(0.5rem, 1vw, 1rem);
  min-width: 0;
}

.avatar { font-size: calc(var(--t-nombre) * 1.15); }

.identidad__cuerpo { flex: 1 1 auto; min-width: 0; }

.identidad__nombre {
  font-size: var(--t-nombre);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}

.identidad__progreso {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 0.6vh;
}

.identidad__progreso .barra { flex: 1 1 auto; }

/* Solo porcentaje hacia la meta propia. Nunca puntos absolutos: con cuatro
   carriles a la vista, los puntos crudos desmoralizan al de 6. */
/* Puntos del día, no porcentaje: 3/12 es concreto y un chico de 6 cuenta
   antes de lo que interpreta un porcentaje. No reintroduce la comparación que
   teme el punto 3.5, porque cada uno mide contra su propia meta: los
   denominadores son distintos y los números no se comparan entre carriles.
   El acumulado de la semana vive en el modal de premios. */
.identidad__puntos {
  flex: 0 0 auto;
  font-size: var(--t-etiqueta);
  font-weight: 700;
  min-width: 4.2em;
  text-align: right;
  white-space: nowrap;
}

.identidad__puntos b { font-weight: 800; }
.identidad__puntos span { color: var(--texto-suave); font-weight: 600; }

/* --- Tareas -------------------------------------------------------------- */

/* --- La tira de tareas ---------------------------------------------------- */
/* Cada miembro puede tener la cantidad de tareas que quiera: uno diez, otro
   seis, otro tres. Entran las tres primeras y las demás se alcanzan con
   izquierda y derecha, que desplazan la tira.

   El marco no se desplaza: es el que sostiene los degradados de borde y los
   indicadores de "hay más", que si vivieran dentro de la tira se irían con el
   desplazamiento. */

.tareas-marco {
  flex: 1 1 auto;
  min-width: 0;
  position: relative;
  /* Más alto que antes: el texto ahora baja de línea en vez de cortarse, y dos
     líneas de nombre más dos de pie necesitan lugar. */
  height: 80%;
  /* Canaletas laterales para los rótulos de "hay más": sin ellas los rótulos se
     montan encima del texto de los chips. Se reservan siempre, incluso en un
     carril que no desborda, para que los cuatro carriles queden alineados. */
  padding-inline: var(--canaleta);
}

.tareas {
  position: relative;
  display: flex;
  align-items: stretch;
  gap: clamp(0.4rem, 0.8vw, 0.9rem);
  /* Sin barra de desplazamiento: en un televisor no hay con qué agarrarla. Se
     desplaza por programa, desde navegacion.js.

     Desplazamiento instantáneo, no suave. Un scroll animado de una tira ancha es
     exactamente lo que trabuca el SoC de un televisor, y con el D-pad se
     encadenan varios pasos por segundo: la animación queda siempre atrás y se
     siente pegajosa. El anillo de foco ya dice dónde estás. */
  overflow: hidden;
  /* El anillo de foco mide 12px, más lo que crece el chip con scale(1.03), y no
     se puede recortar. El relleno le hace lugar en los extremos de la tira; en
     el medio se lo garantiza navegacion.js con su propio margen. El margen
     negativo vertical devuelve los chips a su posición visual, y el alto extra
     compensa el relleno. */
  height: calc(100% + var(--tira-aire) * 2);
  margin: calc(-1 * var(--tira-aire)) 0;
  padding: var(--tira-aire) 24px;
}

/* Los chips ya no se reparten el ancho disponible: cada uno mide lo suyo y la
   tira desborda. El ancho está en porcentaje del scrollport, así que entran
   siempre unos tres, tenga el carril tres tareas o diez. */
/* Cola de la tira: espacio muerto al final, del ancho justo para que la ÚLTIMA
   tarea también pueda quedar pegada al borde izquierdo.

   Sin esto, un carril que no desborda no se puede desplazar, y su tarea de ahora
   queda donde caiga —tercera, cuarta— mientras la de los demás está a la
   izquierda. Los cuatro carriles se leen entonces como cuatro cosas distintas.
   Con la cola, la tarea alumbrada cae siempre en la misma columna en los
   cuatro y el ojo baja por una sola línea vertical.

   El ancho lo calcula el JS al medir el carril. */
.tareas::after {
  content: '';
  flex: 0 0 var(--cola, 0px);
}

.tarea {
  /* Sin crecer: el ancho de un chip no puede depender de cuántas tareas tenga
     ese miembro, o los carriles dejan de parecerse entre sí. La cola se come el
     espacio sobrante. */
  flex: 0 0 clamp(17rem, 32%, 38rem);
  min-width: 0;
  position: relative;
  display: flex;
  align-items: center;
  gap: clamp(0.4rem, 0.8vw, 0.85rem);
  padding: 0 clamp(0.5rem, 1vw, 1rem);
  border-radius: var(--radio);
  border: 2px solid transparent;
  background: rgba(255, 255, 255, 0.03);
}

/* La tarea alumbrada es el centro de atención del carril. */

.tarea__icono {
  flex: 0 0 auto;
  font-size: calc(var(--t-tarea) * 1.35);
}

.tarea__cuerpo { flex: 1 1 auto; min-width: 0; }

/* La insignia se apoya sobre la esquina superior derecha del chip. Sin reservar
   ese lugar, la primera línea del nombre le pasa por debajo y queda tapada
   —"Cepillarse y lavarse" desaparecía atrás del reloj de arena—. Se reserva
   sólo en los estados que la muestran, para no desperdiciar ancho en el resto. */
.tarea[data-estado='esperando_aprobacion'] .tarea__cuerpo,
.tarea[data-estado='completada'] .tarea__cuerpo,
.tarea[data-estado='no_realizada'] .tarea__cuerpo,
.tarea[data-estado='omitida'] .tarea__cuerpo { padding-right: 1.7em; }

/* El texto BAJA de línea, no se corta con puntos suspensivos. "Esperando a
   pa..." no es información, es un acertijo. El max-height es una red de
   seguridad para un nombre disparatado: recorta limpio en lugar de empujar el
   alto del carril y romper la grilla de cuatro. */
.tarea__nombre {
  display: block;
  /* --t-nombre-chip lo redefinen los estados y los roles más abajo. El texto
     secundario del chip se calcula de esta misma variable, para que quede
     siempre 1px por debajo del título y no haya que mantener dos escalas. */
  font-size: var(--t-nombre-chip, var(--t-tarea));
  font-weight: 600;
  /* 1.2 y no menos: con 1.08 la caja de línea quedaba más chica que los glifos
     y, al recortar el sobrante, se afeitaban los descendentes — la "j" de
     "Dejar la cocina" perdía la cola. */
  line-height: 1.25;
  max-height: 2.5em;                 /* dos líneas */
  overflow: hidden;
  overflow-wrap: break-word;
}

.tarea__pie {
  display: block;
  margin-top: 0.3em;
  /* Un pixel menos que el título de ESE chip, no una escala aparte. */
  font-size: calc(var(--t-nombre-chip, var(--t-tarea)) - 3px);
  line-height: 1.2;
  color: var(--texto-suave);
  max-height: 2.5em;                 /* dos líneas */
  overflow: hidden;
  overflow-wrap: break-word;
}

/* --- Criterios de una tarea aprobada ------------------------------------- */
/* Una tarea vale la suma de sus criterios, así que cuando no se ganan todos hay
   que poder ver cuál no entró, sin abrir nada. Va siempre a la vista y no en un
   submenú: la especificación prohíbe los submenús y con razón.

   La marca es FORMA, no color: ✓ lleno contra ○ hueco. Y el hueco no lleva
   ninguna carga de reproche, porque "no ganaste el tercero" pesa distinto que
   "perdiste el tercero". */

.criterios {
  display: flex;
  flex-wrap: wrap;
  gap: 0.1em 0.65em;
  margin-top: 0.3em;
  /* El mismo cuerpo que el rótulo de estado y que el comentario: los tres son
     la línea secundaria del chip y ocupan el mismo lugar. Antes los criterios
     iban en --t-min, una escala aparte, y quedaban de otro tamaño. */
  font-size: calc(var(--t-nombre-chip, var(--t-tarea)) - 3px);
  line-height: 1.3;
  /* Tres criterios, que es el caso normal, entran siempre: incluso apilados de
     a uno por línea. Más allá de eso se recorta, en lugar de empujar el alto
     del carril y romper la grilla de cuatro. */
  max-height: 4.1em;
  overflow: hidden;
}

.criterios[hidden] { display: none; }

.criterio {
  display: inline-flex;
  align-items: baseline;
  gap: 0.3em;
  white-space: nowrap;
}

.criterio::before { font-weight: 900; }

.criterio[data-gano='si'] { color: var(--texto); }

.criterio[data-gano='no'] { color: var(--texto-suave); }
.criterio[data-gano='no']::before { content: '○'; }

/* El tilde ganado, en SVG para poder dibujarlo. */
.tilde {
  width: 1.15em;
  height: 1.15em;
  flex: 0 0 auto;
  align-self: center;
  overflow: visible;
}
.tilde path {
  fill: none;
  stroke: var(--miembro);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Los puntos ganados, como último elemento de la misma fila. */
.criterio-puntos {
  font-weight: 900;
  color: var(--miembro);
  white-space: nowrap;
}

/* La nota que escribió el adulto, cuando hay. Ocupa el lugar de los criterios,
   así que se le deja envolver: una frase corta importa más que los tildes. */
.criterio-nota {
  flex: 1 1 100%;
  color: var(--texto);
  font-style: italic;
  /* El mismo cuerpo que el rótulo de estado: los dos son la línea secundaria
     del chip y ocupan el mismo lugar. */
  font-size: calc(var(--t-nombre-chip, var(--t-tarea)) - 3px);
  line-height: 1.25;
  max-height: 2.6em;
  overflow: hidden;
  overflow-wrap: break-word;
}

/* Insignia de estado. Cada estado tiene la suya: el color solo no alcanza y
   hay un chico de 6 que todavía no lee bien. */
.tarea__insignia {
  position: absolute;
  top: -0.55em;
  right: -0.35em;
  min-width: 1.6em;
  height: 1.6em;
  padding: 0 0.25em;
  border-radius: 999px;
  display: none;
  align-items: center;
  justify-content: center;
  font-size: var(--t-min);
  background: var(--fondo);
  border: 2px solid rgba(242, 246, 250, 0.22);
  z-index: 4;
}

/* --- Botón de premios, al final del carrusel ------------------------------ */
/* Va acá y no en un botón global por tres razones: ◀ ▶ ya llega hasta él sin
   inventar navegación nueva, es del miembro —que es la unidad de los premios
   escalonados— y no ocupa nada en la pantalla principal.
   El escalón de premio NO se muestra fijo en el carril a propósito: si el chico
   puede ver cuánto le falta para el helado, va a quedarse calculando. */
.premio-boton {
  flex: 0 0 clamp(9rem, 15%, 14rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3em;
  border: 2px dashed rgba(143, 163, 184, 0.4);
  border-radius: var(--radio);
  text-align: center;
  color: var(--texto-suave);
  font-size: var(--t-min);
  line-height: 1.15;
  padding: 0 0.5em;
}

.premio-boton__icono { font-size: calc(var(--t-tarea) * 1.2); }
.premio-boton:focus { color: var(--texto); }

/* --- Cuenta regresiva ----------------------------------------------------- */
/* Sólo la tienen las tareas definidas con duración: "20 minutos de dibujitos".
   El número manda sobre el resto del chip — es la tarea, no un dato al costado. */
.cuenta {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.1em;
  border-radius: inherit;
  /* Opaco: con fondo translúcido el nombre de la tarea se leía POR DETRÁS de
     los dígitos y no se entendía ninguno de los dos. */
  background: var(--fondo-carril);
  pointer-events: none;
  z-index: 4;
}
.cuenta[hidden] { display: none; }

/* El nombre queda, chico, para saber de qué tarea es el reloj. */
.cuenta__que {
  font-size: var(--t-min);
  color: var(--texto-suave);
  max-width: 90%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cuenta__num {
  font-size: var(--t-crono);
  font-weight: 300;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--texto);
}

/* El último minuto, en el ámbar de "prestá atención". No es una alarma: no
   parpadea ni suena, sólo cambia de color. */
.cuenta[data-poco='si'] .cuenta__num { color: var(--luz); }

/* En pausa se atenúa SÓLO el número, nunca la capa entera: atenuar la capa
   también transparenta su fondo, y entonces se ve el chip por debajo —el ícono
   y el nombre otra vez— encimado con el reloj. */
.cuenta[data-pausa='si'] .cuenta__num { opacity: 0.45; }

.cuenta__pausa {
  font-size: var(--t-min);
  color: var(--luz);
  letter-spacing: 0.04em;
}
.cuenta:not([data-pausa='si']) .cuenta__pausa { display: none; }

.tarea[data-estado='en_curso'] {
  border-style: solid;
  border-color: var(--luz);
}

/* --- La semana en siete caritas ------------------------------------------ */
/* Debajo de la barra: el progreso de hoy y cómo viene la semana se leen juntos,
   que es la única forma de que "tres 😔 seguidos" salte a la vista. */
/* Ocupa todo el ancho de la identidad y reparte los siete días: así las caritas
   entran más grandes y la semana se lee de un barrido, no apretada a un rincón. */
.racha {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.2em;
  margin-top: 0.6vh;
  line-height: 1;
}
.racha[hidden] { display: none; }

.racha__dia {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.12em;
  opacity: 0.6;
}
.racha__cara { font-size: calc(var(--t-min) * 1.45); line-height: 1; }
.racha__letra {
  font-size: calc(var(--t-min) * 0.6);
  line-height: 1;
  color: var(--texto-suave);
}

/* Hoy va entero y con su inicial marcada; los días que todavía no llegaron,
   apenas insinuados: un miércoles que no pasó no es un día sin elegir. */
.racha__dia[data-hoy='si'] { opacity: 1; }
.racha__dia[data-hoy='si'] .racha__letra { color: var(--miembro); font-weight: 700; }
.racha__dia[data-pasado='no'] { opacity: 0.25; }

/* --- La carita del día --------------------------------------------------- */

.humor-boton {
  flex: 0 0 clamp(9rem, 15%, 14rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3em;
  border: 2px dashed rgba(143, 163, 184, 0.4);
  border-radius: var(--radio);
  text-align: center;
  color: var(--texto-suave);
  font-size: var(--t-min);
  line-height: 1.15;
  padding: 0 0.5em;
}
.humor-boton__cara { font-size: calc(var(--t-tarea) * 1.6); }
.humor-boton:focus { color: var(--texto); }

/* Ya elegida: borde sólido del color del miembro, sin celebrar nada. Contar
   cómo te sentiste no es un logro. */
.humor-boton[data-elegido='si'] {
  border-style: solid;
  border-color: var(--miembro);
  color: var(--texto);
}

.humor { background: rgba(12, 18, 27, 0.97); }

.humor__caja {
  width: min(88vw, 62rem);
  background: var(--fondo-carril);
  border-radius: calc(var(--radio) * 1.6);
  padding: clamp(1.4rem, 3.4vh, 2.6rem);
  border-top: 6px solid var(--miembro, var(--texto-suave));
}
.humor__quien { display: flex; align-items: center; gap: 1rem; }
.humor__avatar { font-size: var(--t-nombre); }
.humor__titulo { font-size: var(--t-nombre); font-weight: 700; margin: 0; }

.humor__caras {
  display: flex;
  justify-content: space-between;
  gap: clamp(0.5rem, 1.5vw, 1.4rem);
  margin: clamp(1.2rem, 3vh, 2.2rem) 0;
}

.cara {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35em;
  padding: 0.7em 0.3em;
  border-radius: var(--radio);
  border: 3px solid transparent;
  background: rgba(255, 255, 255, 0.04);
  text-align: center;
  color: var(--texto-suave);
  font-size: var(--t-min);
}
.cara__emoji { font-size: clamp(2.4rem, 7vh, 4.2rem); }
.cara:focus { color: var(--texto); }
.cara[data-elegido='si'] {
  border-color: var(--miembro);
  background: rgba(255, 255, 255, 0.08);
  color: var(--texto);
}

.humor__pie { display: flex; justify-content: center; }

/* ============================================================================
   El repaso de la noche
   ============================================================================
   Los cuatro juntos, antes de dormir. Nada acá celebra ni reprocha: es una
   foto del día. Por eso no hay verde de éxito ni coral de fallo en las
   tarjetas — el color es el de cada persona, y nada más.
   ========================================================================= */

.repaso-boton {
  flex: 0 0 clamp(9rem, 15%, 14rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3em;
  border: 2px dashed rgba(143, 163, 184, 0.4);
  border-radius: var(--radio);
  text-align: center;
  color: var(--texto-suave);
  font-size: var(--t-min);
  line-height: 1.15;
  padding: 0 0.5em;
}
.repaso-boton__icono { font-size: calc(var(--t-tarea) * 1.6); }
.repaso-boton:focus { color: var(--texto); }

.repaso { background: rgba(12, 18, 27, 0.97); }

.repaso__caja {
  width: min(94vw, 96rem);
  max-height: 92vh;
  overflow-y: auto;
  background: var(--fondo-carril);
  border-radius: calc(var(--radio) * 1.6);
  padding: clamp(1.2rem, 3vh, 2.4rem);
  border-top: 6px solid var(--luz);
}

.repaso__encabezado { text-align: center; }
.repaso__titulo { font-size: var(--t-nombre); font-weight: 700; margin: 0; }
.repaso__fecha { font-size: var(--t-min); color: var(--texto-suave); margin: 0.2em 0 0; }

/* Cuatro columnas en un televisor, y menos si la pantalla es angosta. Con
   auto-fit nadie queda cortado ni hay que contar cuántos son. */
.repaso__grilla {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: clamp(0.6rem, 1.4vw, 1.2rem);
  margin: clamp(1rem, 2.4vh, 1.8rem) 0;
}

.repaso__quien {
  background: rgba(255, 255, 255, 0.04);
  border-radius: var(--radio);
  border-top: 4px solid var(--miembro, var(--texto-suave));
  padding: clamp(0.7rem, 1.6vh, 1.1rem);
  display: flex;
  flex-direction: column;
  gap: 0.5em;
}

.repaso__cabeza { display: flex; align-items: center; gap: 0.5em; }
.repaso__avatar { font-size: calc(var(--t-tarea) * 1.3); line-height: 1; }
.repaso__nombre {
  font-size: var(--t-tarea);
  font-weight: 700;
  color: var(--miembro, var(--texto));
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.repaso__cara { font-size: calc(var(--t-tarea) * 1.2); line-height: 1; margin-left: auto; }
.repaso__plus {
  font-size: calc(var(--t-min));
  font-weight: 700;
  color: var(--exito);
  background: rgba(74, 222, 128, 0.16);
  border-radius: 999px;
  padding: 0.1em 0.5em;
}

.repaso__cifras { display: flex; align-items: baseline; gap: 0.4em; }
.repaso__puntos { font-size: calc(var(--t-tarea) * 1.5); font-weight: 700; }
.repaso__unidad { font-size: var(--t-min); color: var(--texto-suave); }
.repaso__tareas { font-size: var(--t-min); color: var(--texto-suave); margin-left: auto; }

.repaso__cualidades { display: flex; flex-wrap: wrap; gap: 0.3em; }
.repaso__cualidad {
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  font-size: var(--t-min);
  color: var(--texto-suave);
  background: rgba(255, 255, 255, 0.06);
  border-radius: 999px;
  padding: 0.15em 0.6em;
}

.repaso__nota {
  font-size: var(--t-min);
  font-style: italic;
  color: var(--texto-suave);
  margin: 0;
  line-height: 1.35;
}

/* El faro cierra la pantalla: lo último que se mira es lo que hicieron entre
   los cuatro, no lo que hizo cada uno. */
.repaso__faro {
  display: flex;
  align-items: center;
  gap: 0.8em;
  padding-top: clamp(0.6rem, 1.6vh, 1rem);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.repaso__faro-rotulo { font-size: var(--t-min); color: var(--texto-suave); }
.repaso__faro .barra { flex: 1 1 auto; }
.repaso__faro-cifra { font-size: var(--t-tarea); font-weight: 700; }

.repaso__pie {
  display: flex;
  justify-content: center;
  margin-top: clamp(0.8rem, 2vh, 1.4rem);
}

/* --- "Hay más para ese lado" --------------------------------------------- */
/* Sin barra de desplazamiento hay que decirlo de otra manera, y de paso el
   número contesta la pregunta obvia: cuántas tareas tiene esta persona. */

.tareas-marco::before,
.tareas-marco::after {
  content: '';
  position: absolute;
  /* Se estiran por fuera del marco tanto como la tira: si no, los chips que
     asoman por el borde quedan al descubierto en esa franja de aire. */
  top: calc(-1 * var(--tira-aire));
  bottom: calc(-1 * var(--tira-aire));
  width: calc(var(--canaleta) + clamp(2rem, 4vw, 4rem));
  pointer-events: none;
  opacity: 0;
  transition: opacity 260ms ease-out;
  z-index: 8;
}

/* La canaleta va OPACA, y recién después empieza el degradado. Con el degradado
   arrancando desde el borde, el pedazo de chip que asoma se veía por detrás del
   rótulo —insignia incluida— y el conjunto parecía un error de dibujo. */
.tareas-marco::before {
  left: 0;
  background: linear-gradient(
    90deg,
    var(--fondo-carril) 0,
    var(--fondo-carril) var(--canaleta),
    rgba(31, 44, 61, 0) 100%
  );
}

.tareas-marco::after {
  right: 0;
  background: linear-gradient(
    270deg,
    var(--fondo-carril) 0,
    var(--fondo-carril) var(--canaleta),
    rgba(31, 44, 61, 0) 100%
  );
}

.tareas-marco[data-hay-izq]::before { opacity: 1; }
.tareas-marco[data-hay-der]::after { opacity: 1; }

/* Pastilla con fondo propio, y el chevrón junto al número en una sola línea.
   Apilados y sin fondo se leían como dos números sueltos flotando en el carril,
   no como un control: la primera lectura de alguien parado a 3 metros fue
   "esto es un error". */
.mas {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 9;
  pointer-events: none;
  display: flex;
  align-items: center;
  gap: 0.1em;
  padding: 0.22em 0.5em;
  border-radius: 999px;
  background: rgba(143, 163, 184, 0.20);
  font-size: var(--t-min);
  font-weight: 700;
  line-height: 1.15;
  color: var(--texto-suave);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 260ms ease-out;
}

.mas--izq { left: 0.15rem; }
.mas--der { right: 0.15rem; }

.tareas-marco[data-hay-izq] .mas--izq { opacity: 1; }
.tareas-marco[data-hay-der] .mas--der { opacity: 1; }

/* --- El destello de marcar ------------------------------------------------ */
/* Acuse de recibo fuerte pero corto: el chip queda esperando aprobación, y la
   celebración de verdad va cuando un adulto aprueba. Sólo transform y opacity:
   el aro no repinta nada, se compone. */
/* inset 0, no negativo: una capa que sobresale agranda el scrollHeight del chip
   y simula un desbordamiento de contenido. El aro igual se ve salir, porque
   crece con transform, que no ocupa lugar. */
.destello {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 4px solid var(--espera);
  opacity: 0;
  pointer-events: none;
  z-index: 20;
}

.tarea.marcado { z-index: 25; }

/* Dos aros con distinto retraso: uno solo se lee como un parpadeo, dos se leen
   como una onda que sale del chip. */
.tarea.marcado .destello { animation: destello-aro 1000ms ease-out both; }
.tarea.marcado .destello::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 3px solid var(--espera);
  animation: destello-aro-ancho 1000ms ease-out 220ms both;
}

.tarea.marcado .tarea__icono {
  animation: icono-golpe 1000ms var(--rebote) both;
  display: inline-block;
}

.tarea.marcado .tarea__insignia {
  animation: exito-tilde 900ms var(--rebote) 220ms both;
}

/* esperando_aprobacion — borde neón que late. Sin celebración: eso va en la
   aprobación. */
.tarea[data-estado='esperando_aprobacion'] {
  border-style: solid;
  border-color: var(--espera);
  background: rgba(255, 234, 0, 0.06);
  /* Sólo escala: bajar la opacidad del chip apagaba también el texto. */
  animation: espera 1.8s ease-in-out infinite;
}

/* Halo en capa aparte animando sólo opacity: animar box-shadow obliga al
   televisor a repintar en cada cuadro. */
.tarea[data-estado='esperando_aprobacion']::after {
  content: '';
  position: absolute;
  /* inset 0, no negativo: una capa que sobresale agranda el scrollHeight. El
     resplandor sale igual, box-shadow no ocupa lugar. */
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  box-shadow:
    0 0 6px 1px rgba(255, 234, 0, 0.75),
    0 0 18px 3px rgba(255, 234, 0, 0.35);
  animation: espera-neon 1.8s ease-in-out infinite;
}

.tarea[data-estado='esperando_aprobacion'] .tarea__insignia { display: flex; }

/* completada — sólido y con tilde.
   El relleno es NEUTRO a propósito. Con un lavado del color del miembro, el
   carril de Fer (cuyo color de identidad es ámbar) quedaba indistinguible de la
   luz del faro: parecía alumbrado cuando la luz ya se había ido a otra tarea.
   La identidad vive en el borde, la insignia y los tildes, que alcanzan de
   sobra y no compiten con el único ámbar del sistema. */
.tarea[data-estado='completada'] {
  border-style: solid;
  border-color: var(--exito);
  background: rgba(255, 255, 255, 0.07);
  /* Resplandor ESTÁTICO. Quedarse encendido es gratis; animar una sombra no.
     Radio corto para que no se recorte contra el borde de la tira. */
  box-shadow: 0 0 13px rgba(74, 222, 128, 0.32);
}
.tarea[data-estado='completada'] .tarea__insignia {
  display: flex;
  background: var(--exito);
  color: #0B1A10;
  border-color: transparent;
  font-weight: 900;
}
.tarea[data-estado='completada'] .tarea__ganados { color: var(--exito); }
.tarea[data-estado='completada'] .criterio[data-gano='si']::before { color: var(--exito); }

/* --- Cómo salió, no sólo que se calificó -------------------------------- --
   Verde es "la hizo entera". Con la mitad de los puntos va ámbar y cara
   neutra; con cero, coral y cara triste. Pintarlo todo de verde y con tilde
   dice que da lo mismo hacerla bien, que es justo lo contrario de lo que la
   pantalla tiene que enseñar. No hay castigo: los puntos nunca se restan, sólo
   se ve con honestidad cómo salió. */

.tarea[data-logro='parte'] {
  border-color: var(--ambar);
  box-shadow: 0 0 13px rgba(245, 158, 11, 0.3);
}
.tarea[data-logro='parte'] .tarea__insignia { background: var(--ambar); color: #241703; }
.tarea[data-logro='parte'] .tarea__ganados { color: var(--ambar); }
.tarea[data-logro='parte']::before { background: var(--ambar); }

.tarea[data-logro='nada'] {
  border-color: var(--coral);
  box-shadow: 0 0 13px rgba(251, 113, 133, 0.3);
}
.tarea[data-logro='nada'] .tarea__insignia { background: var(--coral); color: #2A0A10; }
.tarea[data-logro='nada'] .tarea__ganados { color: var(--coral); }
.tarea[data-logro='nada']::before { background: var(--coral); }

/* Un permiso no se logra ni se falla: queda neutro, sin verde de éxito. */
.tarea[data-logro='permiso'] {
  border-color: rgba(143, 163, 184, 0.5);
  box-shadow: none;
}
.tarea[data-logro='permiso'] .tarea__insignia {
  background: rgba(143, 163, 184, 0.35);
  color: var(--texto);
}
.tarea[data-logro='permiso']::before { opacity: 0; }

/* La carita ocupa más que un tilde: se le baja el cuerpo para que entre. */
.tarea[data-logro='parte'] .tarea__insignia,
.tarea[data-logro='nada'] .tarea__insignia { font-size: 0.82em; }

/* El baño verde del fondo es un pseudo-elemento con opacity, no un cambio de
   background-color: así la transición es de opacidad pura, que el televisor
   compone sin repintar. z-index -1 lo deja por encima del fondo del chip y por
   debajo del texto (el chip crea contexto de apilamiento por su will-change). */
.tarea::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--exito);
  opacity: 0;
  transition: opacity 420ms ease-out;
  pointer-events: none;
}
.tarea[data-estado='completada']::before { opacity: 0.16; }

/* La clase festejo la pone tablero.js en el momento de la aprobación y la saca
   cuando termina. El estado verde queda; la animación es de una sola vez. */
.tarea.festejo {
  animation: exito-golpe 900ms var(--rebote);
  z-index: 25;                       /* la onda no queda debajo del chip vecino */
}

/* Dos ondas verdes desde el chip: una sale del borde y la otra la sigue más
   ancha. Es lo que convierte el aviso en una explosión. */
.tarea.festejo::after {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: var(--radio);
  border: 5px solid var(--exito);
  pointer-events: none;
  animation: exito-onda 1200ms ease-out;
}

.tarea.festejo .destello {
  border-color: var(--exito);
  border-width: 6px;
  animation: destello-aro 1300ms ease-out 100ms both;
}
.tarea.festejo .destello::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 4px solid var(--exito);
  animation: destello-aro-ancho 1300ms ease-out 320ms both;
}

.tarea.festejo .tarea__icono {
  animation: exito-icono 1150ms var(--rebote) both;
  display: inline-block;
}

.tarea.festejo .tarea__insignia {
  animation: exito-tilde 1000ms var(--rebote) 180ms both;
}

/* El escalonado sale de --i, que numera cada criterio desde el JS. */
.tarea.festejo .criterio {
  animation: exito-criterio 760ms var(--rebote) both;
  animation-delay: calc(420ms + var(--i, 0) * 200ms);
}

/* El trazo se dibuja mientras el criterio se acomoda: el tilde se ve NACER, no
   aparecer. Fuera del festejo queda dibujado y quieto. */
.tarea.festejo .tilde path {
  stroke-dasharray: 24;
  animation: tilde-dibujar 620ms ease-out both;
  animation-delay: calc(600ms + var(--i, 0) * 200ms);
}
/* Un chip aprobado carga más información que uno pendiente, así que se lleva un
   poco más de ancho, y el nombre cede protagonismo: la tarea ya es historia, la
   noticia son los criterios. */
.tarea[data-estado='completada'] { flex: 0 0 clamp(19rem, 36%, 42rem); }
.tarea[data-estado='completada'] { --t-nombre-chip: calc(var(--t-tarea) * 0.88); }
.carril[data-rol='adulto'] .tarea[data-estado='completada'] {
  --t-nombre-chip: calc(var(--t-tarea) * 0.82);
}

/* no_realizada — apagado, emoticón triste discreto, y nada más. Discreta y
   brevemente: no hay que hacer llorar a un chico de 6 con el televisor. */
.tarea[data-estado='no_realizada'] {
  border-color: transparent;
  background: rgba(255, 255, 255, 0.02);
  opacity: 0.42;
  filter: grayscale(1);
}
.tarea[data-estado='no_realizada'] .tarea__insignia { display: flex; }

/* omitida — gris neutro y rayado diagonal: la forma dice "esto no cuenta", sin
   ninguna carga emocional. No costó puntos. */
.tarea[data-estado='omitida'] {
  border-style: solid;
  border-color: rgba(143, 163, 184, 0.28);
  background-color: rgba(143, 163, 184, 0.07);
  background-image: repeating-linear-gradient(
    135deg,
    rgba(143, 163, 184, 0.13) 0 10px,
    rgba(143, 163, 184, 0) 10px 20px
  );
  color: var(--texto-suave);
}
.tarea[data-estado='omitida'] .tarea__insignia { display: flex; }
.tarea[data-estado='omitida'] .tarea__icono { opacity: 0.6; }

/* --- Densidad visual ----------------------------------------------------- */
/* Ya no hay ninguna. Existió una densidad "iconos" que le daba a Fer un ícono
   más grande, el nombre más chico y los criterios sin texto, con el argumento
   de que a los 6 años no lee. Se sacó entera: es un miembro más, la pantalla
   se mira en familia, y cada excepción trajo su propio defecto —el carril de
   Fer con chips de 62px contra 148, los comentarios que no aparecían—.

   La columna densidad sigue en la base y viaja en la API, pero ya no pinta
   nada. Se deja para no romper el esquema por una limpieza cosmética. */

/* Los criterios de Fer se leen igual que los de los demás.
   Antes quedaban sólo las marcas, con el argumento de que a los 6 años no lee
   los nombres. El repaso del día se hace en voz alta y en familia, así que lo
   que importa es que se pueda LEER, no quién lo lee. */

/* Los chicos pesan más que los adultos en la pantalla. */
.carril[data-rol='adulto'] .tarea__icono { font-size: calc(var(--t-tarea) * 1.1); }
.carril[data-rol='adulto'] .tarea { --t-nombre-chip: calc(var(--t-tarea) * 0.92); }
.carril[data-rol='adulto'] .avatar { font-size: var(--t-nombre); }

/* ============================================================================
   La luz — el único ámbar del sistema.

   El faro alumbra lo que toca ahora: la luz se posa sobre la tarea actual de
   cada carril y se corre cuando esa tarea se termina. No barre la pantalla con
   el reloj, porque para que la posición significara algo los chips tendrían que
   estar sobre un eje de tiempo, y no lo están; una luz que se desplaza sin
   señalar nada parece informar y no informa.

   Se mueve con transform (base de 100px + scaleX), nunca con left/width: así el
   deslizamiento sale por GPU y no provoca layout en cada frame.
   ========================================================================== */

.luz-carril {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 100px;
  border-radius: var(--radio);
  pointer-events: none;
  transform-origin: left center;
  transform: translateX(0) scaleX(1);
  transition: transform 620ms cubic-bezier(0.2, 0.7, 0.3, 1),
              opacity 500ms ease-out;
  will-change: transform;
  background: linear-gradient(
    90deg,
    rgba(255, 209, 102, 0) 0%,
    rgba(255, 209, 102, 0.09) 14%,
    rgba(255, 209, 102, 0.22) 50%,
    rgba(255, 209, 102, 0.09) 86%,
    rgba(255, 209, 102, 0) 100%
  );
}

/* Cuando la tarea actual está esperando aprobación no hay nada que hacer en ese
   carril: la luz se queda donde está pero baja. */
.luz-carril[data-espera='si'] { opacity: 0.28; }
.luz-carril[hidden] { display: none; }

/* Haz que baja del faro de la cabecera cuando la familia llega a la meta. */
.haz {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  pointer-events: none;
  z-index: 5;
  opacity: 0;
  transition: opacity 1.2s ease-out;
  background: radial-gradient(
    120% 90% at 50% -18%,
    rgba(255, 209, 102, 0.20) 0%,
    rgba(255, 209, 102, 0.07) 38%,
    rgba(255, 209, 102, 0) 70%
  );
}
.faro-encendido .haz { opacity: 1; animation: vaiven 9s ease-in-out infinite; }

/* ============================================================================
   Pista de teclas
   ========================================================================== */

.pista {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: clamp(0.75rem, 2vw, 2rem);
  padding: 0 clamp(0.5rem, 1vw, 1.25rem);
  font-size: var(--t-min);
  color: var(--texto-suave);
  white-space: nowrap;
  overflow: hidden;
}

.pista b { color: var(--texto); font-weight: 700; }
.pista__sep { opacity: 0.35; }

/* ============================================================================
   Overlays
   ========================================================================== */

.overlay {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--fondo);
}
.overlay[hidden] { display: none; }

/* --- Portada: desbloquea el audio. Es la primera pantalla que ve la familia
   y no hay forma de esquivarla, así que se la aprovecha. ------------------- */

.portada { flex-direction: column; gap: 3vh; text-align: center; }

/* En la portada el faro va encendido: es la pantalla de "encender el faro". */
.portada__faro {
  width: clamp(9rem, 30vh, 20rem);
  height: clamp(9rem, 30vh, 20rem);
  --haz-opacidad: 1;
  animation: respira 5s ease-in-out infinite;
}
.portada__titulo { font-size: var(--t-reloj); font-weight: 300; letter-spacing: 0.22em; text-transform: uppercase; margin: 0; }
.portada__bajada { font-size: var(--t-tarea); color: var(--texto-suave); max-width: 26em; margin: 0 auto; }
.portada__familia { font-size: clamp(2.5rem, 7vh, 4.5rem); letter-spacing: 0.3em; }

.boton-grande {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.7em 1.6em;
  border-radius: 999px;
  border: 3px solid rgba(242, 246, 250, 0.35);
  font-size: var(--t-nombre);
  font-weight: 700;
  background: rgba(255, 255, 255, 0.05);
}

/* --- Reposo: la luz del faro. Identidad de marca y protección real contra
   burn-in en un OLED. Cualquier tecla vuelve al tablero. ------------------- */

.reposo { background: #0C121B; overflow: hidden; }

.reposo__haz {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 260vmax;
  height: 260vmax;
  margin: -130vmax 0 0 -130vmax;
  background: conic-gradient(
    from 0deg,
    rgba(255, 209, 102, 0.16) 0deg,
    rgba(255, 209, 102, 0.02) 22deg,
    rgba(255, 209, 102, 0) 42deg,
    rgba(255, 209, 102, 0) 318deg,
    rgba(255, 209, 102, 0.05) 344deg,
    rgba(255, 209, 102, 0.16) 360deg
  );
  animation: girar 16s linear infinite;
  will-change: transform;
}

.reposo__momento {
  position: relative;
  z-index: 2;
  text-align: center;
  /* Se desplaza despacio: una interfaz estática encendida horas en un OLED
     deja marca permanente. */
  animation: deriva 97s ease-in-out infinite alternate;
  will-change: transform;
}

.reposo__fecha {
  margin-top: 0.5em;
  font-size: var(--t-nombre);
  font-weight: 300;
  color: rgba(143, 163, 184, 0.75);
}

/* La deriva la lleva .reposo__momento, que arrastra reloj y fecha juntos. */
.reposo__reloj {
  font-size: clamp(5rem, 22vh, 15rem);
  font-weight: 200;
  color: rgba(242, 246, 250, 0.72);
  letter-spacing: -0.03em;
  line-height: 0.95;
}

.reposo__pie {
  position: absolute;
  bottom: 8vh;
  font-size: var(--t-etiqueta);
  color: rgba(143, 163, 184, 0.7);
  z-index: 2;
}

/* --- Premios: los escalones de la semana --------------------------------- */
/* Es un submenú, y el punto 3.2 los prohíbe. Va igual porque hace falta: es
   para la revisión semanal de los adultos, no para la rutina diaria, que sigue
   resolviéndose con ▲ ▼ y OK sin abrir nada. */

.premios { background: rgba(12, 18, 27, 0.97); }

.premios__caja {
  width: min(90vw, 1000px);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  gap: 1.6vh;
}

.premios__quien {
  display: flex;
  align-items: center;
  gap: clamp(0.8rem, 1.6vw, 1.6rem);
}

.premios__avatar { font-size: calc(var(--t-nombre) * 1.5); }
.premios__nombre { font-size: var(--t-nombre); font-weight: 700; margin: 0; }
.premios__semana { font-size: var(--t-etiqueta); color: var(--texto-suave); margin: 0.2em 0 0; }
.premios__cifra { margin-left: auto; font-size: var(--t-nombre); font-weight: 700; }

.barra--premio { height: clamp(0.9rem, 2.2vh, 1.6rem); }

.escalones { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.9vh; }

.escalon {
  display: flex;
  align-items: center;
  gap: clamp(0.7rem, 1.4vw, 1.4rem);
  padding: 0.7vh clamp(0.7rem, 1.4vw, 1.4rem);
  border-radius: var(--radio);
  border: 2px solid transparent;
  background: rgba(255, 255, 255, 0.035);
  font-size: var(--t-etiqueta);
  color: var(--texto-suave);
}

.escalon__icono { font-size: calc(var(--t-tarea) * 1.15); }
.escalon__nombre { flex: 1 1 auto; min-width: 0; }
.escalon__desde { flex: 0 0 auto; font-variant-numeric: tabular-nums; }

/* El escalón alcanzado. Los de arriba quedan como algo a lo que llegar, nunca
   como algo que se perdió. */
.escalon[data-vigente] {
  border-color: var(--exito);
  background: rgba(74, 222, 128, 0.13);
  color: var(--texto);
  font-weight: 700;
}
.escalon[data-vigente] .escalon__nombre::after {
  content: ' — vas por acá';
  font-weight: 600;
  color: var(--exito);
}

.premios__falta {
  font-size: var(--t-tarea);
  margin: 0;
  text-align: center;
}

.premios__pie {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1vh;
  /* Aire extra respecto de la lista de escalones: el botón es una acción, no un
     renglón más de la enumeración, y pegado se leía como parte de ella. */
  margin-top: 2.4vh;
}
.premios__ayuda { font-size: var(--t-min); color: var(--texto-suave); }

/* --- Ayuda --------------------------------------------------------------- */

.ayuda { background: rgba(12, 18, 27, 0.97); }
.ayuda__caja { width: min(92vw, 1100px); max-height: 88vh; overflow: hidden; }
.ayuda__titulo { font-size: var(--t-nombre); font-weight: 700; margin: 0 0 2vh; letter-spacing: 0.06em; }
.ayuda__grilla {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6vh clamp(1rem, 3vw, 3rem);
  font-size: var(--t-min);
}
.ayuda__fila { display: flex; gap: 0.8em; align-items: baseline; }
.ayuda__tecla {
  flex: 0 0 auto;
  min-width: 6.5em;
  padding: 0.1em 0.5em;
  border: 2px solid rgba(242, 246, 250, 0.28);
  border-radius: 0.4em;
  font-weight: 700;
  text-align: center;
}
.ayuda__que { color: var(--texto-suave); }
.ayuda__cierre {
  margin-top: 2.5vh;
  display: flex;
  justify-content: center;
  gap: clamp(1rem, 2vw, 2rem);
  flex-wrap: wrap;
}

/* Segundo plano: está ahí por si hace falta, pero no es lo que uno viene a
   hacer al abrir la ayuda. */
.boton-grande--ojo {
  font-size: var(--t-etiqueta);
  border-color: rgba(242, 246, 250, 0.22);
  color: var(--texto-suave);
  background: transparent;
}
.boton-grande--ojo:focus { color: var(--texto); }

/* Salvo desvinculado: ahí es lo único que arregla la pantalla. */
.ayuda[data-desvinculado='si'] #ayuda-vincular {
  font-size: var(--t-nombre);
  border-color: var(--espera);
  color: var(--fondo);
  background: var(--espera);
}

.ayuda__nota {
  margin: 1.5vh 0 0;
  text-align: center;
  font-size: var(--t-min);
  color: var(--texto-suave);
}
.ayuda__nota b { color: var(--texto); }

/* ============================================================================
   Celebración
   ========================================================================== */

.confetti {
  position: fixed;
  inset: 0;
  z-index: 80;
  pointer-events: none;
}

/* El puntaje que vuela hacia el contador del carril. */
.vuelo {
  position: fixed;
  z-index: 85;
  pointer-events: none;
  font-size: var(--t-nombre);
  font-weight: 900;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.6);
  transform: translate(-50%, -50%);
  will-change: transform, opacity;
}

/* Cartel de feedback. Informa, nunca reta.
   Va abajo de todo, tapando la pista de teclas y no un carril: la pista es lo
   único de la pantalla que se puede perder de vista dos segundos. */
.aviso-flotante {
  position: fixed;
  left: 50%;
  bottom: 1.6vh;
  z-index: 86;
  transform: translateX(-50%);
  padding: 0.35em 1.1em;
  border-radius: 999px;
  background: rgba(31, 44, 61, 0.96);
  border: 2px solid rgba(242, 246, 250, 0.2);
  font-size: var(--t-etiqueta);
  font-weight: 600;
  pointer-events: none;
  opacity: 1;
  transition: opacity 300ms ease-out;
  will-change: transform, opacity;
}
.aviso-flotante[hidden] { display: none; }

/* ============================================================================
   Keyframes — solo transform y opacity
   ========================================================================== */

/* --- El momento de la aprobación ------------------------------------------
   Cuatro efectos que entran encadenados y terminan en 1,2 segundos. Todos son
   transform y opacity, que es lo único que el televisor compone por GPU sin
   repintar; con esas dos se llega más lejos de lo que parece.

   Corto a propósito: el premio está en el mundo real, así que la celebración
   tiene que soltar al chico, no retenerlo mirando la pantalla. */

/* 1. El golpe: el chip se infla y vuelve, con rebote. */
@keyframes exito-golpe {
  0%   { transform: scale(1); }
  28%  { transform: scale(1.16); }
  58%  { transform: scale(0.96); }
  80%  { transform: scale(1.04); }
  100% { transform: scale(1); }
}

/* El ícono de una tarea aprobada también festeja: gira y se pasa de tamaño. */
@keyframes exito-icono {
  0%   { transform: scale(1) rotate(0); }
  20%  { transform: scale(2.6) rotate(14deg); }
  42%  { transform: scale(1.7) rotate(-12deg); }
  60%  { transform: scale(2.1) rotate(8deg); }
  78%  { transform: scale(0.85) rotate(-4deg); }
  100% { transform: scale(1) rotate(0); }
}

/* 2. La onda: un aro verde que se expande desde el borde y se desvanece. */
@keyframes exito-onda {
  0%   { transform: scale(0.95); opacity: 1; }
  100% { transform: scale(2.4);  opacity: 0; }
}

/* 3. El tilde entra girando y pasándose de tamaño. */
@keyframes exito-tilde {
  0%   { transform: scale(0) rotate(-35deg); opacity: 0; }
  55%  { transform: scale(1.4) rotate(8deg); opacity: 1; }
  100% { transform: scale(1) rotate(0deg);   opacity: 1; }
}

/* 4. Los criterios aparecen de a uno. Es el efecto que más rinde de los cuatro,
      porque el movimiento CUENTA lo que ganaste en lugar de solo decorar.
      Entra GRANDE y se acomoda: se ve venir desde lejos. */
@keyframes exito-criterio {
  0%   { transform: scale(3.2) rotate(-8deg); opacity: 0; }
  30%  { transform: scale(1.9) rotate(4deg);  opacity: 1; }
  55%  { transform: scale(1.25) rotate(-2deg); }
  78%  { transform: scale(0.9) rotate(0); }
  100% { transform: scale(1) rotate(0); opacity: 1; }
}

/* El trazo del tilde se dibuja de punta a punta. */
@keyframes tilde-dibujar {
  from { stroke-dashoffset: 24; }
  to   { stroke-dashoffset: 0; }
}

/* El destello de marcar: un aro que se abre desde el chip y se desvanece. */
@keyframes destello-aro {
  0%   { transform: scale(0.9);  opacity: 0; }
  18%  { transform: scale(1);    opacity: 1; }
  100% { transform: scale(1.65); opacity: 0; }
}

/* El segundo aro llega más lejos: la onda se abre en dos tiempos. */
@keyframes destello-aro-ancho {
  0%   { transform: scale(0.95); opacity: 0; }
  22%  { transform: scale(1.1);  opacity: 0.85; }
  100% { transform: scale(2.1);  opacity: 0; }
}

/* El golpe de zoom del ícono al marcar. */
@keyframes icono-golpe {
  0%   { transform: scale(1) rotate(0); }
  22%  { transform: scale(2.2) rotate(-10deg); }
  45%  { transform: scale(1.5) rotate(8deg); }
  65%  { transform: scale(0.86) rotate(-4deg); }
  82%  { transform: scale(1.12) rotate(2deg); }
  100% { transform: scale(1) rotate(0); }
}

@keyframes respira {
  0%, 100% { opacity: 0.75; }
  50%      { opacity: 1; }
}

@keyframes espera {
  0%, 100% { transform: scale(1);     }
  50%      { transform: scale(1.012); }
}

/* No baja a cero: un parpadeo cansa y se termina ignorando. */
@keyframes espera-neon {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 1; }
}

@keyframes pulso-faro {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.28); }
  100% { transform: scale(1); }
}

@keyframes girar {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

@keyframes deriva {
  0%   { transform: translate(-16vw, -14vh); }
  25%  { transform: translate(14vw, 10vh); }
  50%  { transform: translate(17vw, -12vh); }
  75%  { transform: translate(-13vw, 13vh); }
  100% { transform: translate(-16vw, -14vh); }
}

@keyframes vaiven {
  0%, 100% { transform: translateX(-2.5%); }
  50%      { transform: translateX(2.5%); }
}

/* ============================================================================
   prefers-reduced-motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  /* La luz sigue alumbrando la tarea de ahora; deja de deslizarse hasta la
     siguiente y aparece directamente en su lugar. */
  .luz-carril { transition: none !important; }
  /* La protección de burn-in no es un adorno: el reloj del reposo se sigue
     moviendo, en saltos largos en lugar de un desplazamiento continuo. */
  .reposo__momento { animation: deriva 97s steps(4, jump-none) infinite alternate !important; }
  .reposo__haz { animation: none; opacity: 0.5; }
}

/* --- Estado de la conexión, en la barra de abajo -------------------------- */
/* Discreto a propósito: que no haya internet es un problema del adulto, no algo
   que un chico de 6 tenga que interpretar en medio de la rutina. El tablero
   sigue mostrando lo último que sabe y la vida sigue. */
.pista__red {
  color: var(--luz);
  font-weight: 700;
}
.pista__red[hidden] { display: none; }
.pista__red[hidden] + .pista__sep,
.pista__sep:has(+ .pista__red[hidden]) { display: none; }
