/* ==========================================================================
   ITERA · DESIGN SYSTEM — COMPONENTES
   Capa 3 de 3. Depende de tokens.css y base.css.

   Referencias de oficio y qué se tomó de cada una:
   · Duolingo — botón primario con canto inferior que se hunde al presionar,
     progreso como protagonista, racha, celebración al cerrar una tarea.
   · Asana    — anatomía de la fila de trabajo (título · dueño · vencimiento ·
     estado), neutros contenidos, color reservado para significado.
   · Monday   — el estado como columna de primera clase: chip con nombre,
     franja de color a la izquierda y contador en el encabezado de grupo.
   ========================================================================== */

/* ==========================================================================
   1 · ARMAZÓN
   ========================================================================== */

.stage {
  min-height: 100dvh;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-5) var(--s-4) var(--s-8);
}

.frame {
  position: relative;                /* ancla del popover y de la barra flotante */
  width: 100%;
  max-width: var(--app-w);
  height: 812px;                     /* alto de teléfono: el scroll ocurre adentro */
  max-height: calc(100dvh - var(--s-12));
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-2xl);
  box-shadow: var(--sh-lg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.stage-foot {
  width: 100%;
  max-width: var(--app-w);
  text-align: center;
  color: var(--text-3);
}

/* El modo pantalla completa —teléfono y app instalada— vive en §18. */

/* ==========================================================================
   2 · BARRA SUPERIOR
   ========================================================================== */

/* La cabecera tiene dos pisos. Al bajar, el de marca se repliega y solo
   queda la identidad del usuario — que es la información que sí necesita
   estar siempre a la vista. Al subir, la marca vuelve. */
/* Chrome claro. La marca entra por acentos y botones, no tiñendo
   superficies: es la lectura más limpia y la que deja el contenido al
   frente. El precio es que el cian solo puede aparecer sobre petróleo —
   sobre blanco mide 1.31:1 — así que su único hogar aquí es el rótulo del
   botón primario. */
.topbar {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 30;
  background: var(--surface);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
  will-change: transform;
}
.topbar.is-stuck {
  border-bottom-color: var(--border);
  box-shadow: var(--sh-xs);
}

/* Altura fija: ya no se anima. Lo que se mueve es la cabecera entera, y
   solo la opacidad acompaña la salida. */
.brandbar {
  height: var(--brandbar-h);
  display: grid;
  place-items: center;
  will-change: opacity;
}
.brandbar[aria-hidden="true"] { pointer-events: none; }

/* El logo es el único acceso al conmutador de rol. Lleva chevron para que
   se lea como control y no como adorno. */
.brandbtn {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-full);
  transition: background var(--dur-1) var(--ease);
}
.brandbtn:hover { background: var(--surface-sunk); }
.brandbtn .chev {
  width: 17px;
  height: 17px;
  color: var(--text-3);
  transition: transform var(--dur-2) var(--ease);
}
.brandbtn[aria-expanded="true"] .chev { transform: rotate(180deg); }

/* El wordmark venía chico por una razón que no era el tamaño: el SVG de marca
   trae 75px de aire horneado en su viewBox por los cuatro lados, así que la
   tinta ocupa apenas el 51% del alto declarado. A `height: 30px` la palabra
   "itera" medía 15px reales — competía de igual a igual con el nombre del
   colegio, que es información y no identidad.
   
   La caja crece a 62px y el margen negativo recorta ese aire para que el
   bloque de layout sea la tinta y no el lienzo: 32px de logo visible, +56%
   lineal. El archivo de marca no se toca —el aire es del asset, no un error
   nuestro— y el botón vuelve a abrazar la palabra en vez del vacío. */
.wordmark {
  height: 62px;
  width: auto;
  margin: -15px;
}

.appbar {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-5) var(--s-3);
}

/* ---- Conmutador de rol: aparece solo al tocar el logo ---- */
.popscrim {
  position: absolute;
  inset: 0;
  z-index: 25;
  background: rgba(0, 58, 76, .18);
  animation: fade var(--dur-2) var(--ease);
}

.rolepop {
  position: absolute;
  top: 100%;
  left: var(--s-3);
  right: var(--s-3);
  z-index: 31;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-lg);
  padding: var(--s-3);
  transform-origin: top center;
  animation: dropin var(--dur-3) var(--ease);
}
@keyframes dropin {
  from { opacity: 0; transform: translateY(-8px) scale(.98); }
  to   { opacity: 1; transform: none; }
}

.rolepop .cap {
  color: var(--text-3);
  padding: var(--s-1) var(--s-2) var(--s-3);
}
.rolepop a {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: var(--tap);
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-md);
  color: var(--text);
  transition: background var(--dur-1) var(--ease);
}
.rolepop a:hover { background: var(--surface-sunk); }
.rolepop a[aria-current="page"] { background: var(--brand-50); }
.rolepop a .who { flex: 1; min-width: 0; }
.rolepop a .nm { display: block; font-size: var(--fs-h3); font-weight: 650; line-height: 1.3; }
.rolepop a .rl { display: block; font-size: var(--fs-xs); color: var(--text-3); margin-top: 2px; }
.rolepop a .tick { color: var(--brand-600); opacity: 0; }
.rolepop a[aria-current="page"] .tick { opacity: 1; }

.rolepop .foot {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  color: var(--text-3);
  padding: var(--s-3) var(--s-2) var(--s-1);
  margin-top: var(--s-2);
  border-top: 1px solid var(--border);
}
.rolepop .foot::before {            /* el punto de la "i", en su color */
  content: "";
  width: 7px; height: 7px;
  border-radius: var(--r-full);
  background: var(--cyan);
  outline: 1px solid var(--brand-300);
  flex: none;
}

/* El logo, tratado como app icon: teja de petróleo con el asta en blanco y
   el punto en cian. Es la aplicación que la marca ya trae resuelta —el
   archivo "on-dark" del kit— y la única en la que el cian rinde 9.36:1. */
.brandmark {
  width: 34px; height: 34px;
  border-radius: var(--r-sm);
  flex: none;
  background: var(--brand-800);
  display: grid;
  place-items: center;
}
.brandmark svg { height: 20px; width: auto; }
.brandmark .stem { fill: #FFFFFF; }
.brandmark .dot  { fill: var(--cyan); }

.appbar-id { flex: 1; min-width: 0; }
.appbar-id .org {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  letter-spacing: -.006em;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.appbar-id .sub { color: var(--text-3); margin-top: 3px; }

.iconbtn {
  position: relative;
  width: 36px; height: 36px;
  border-radius: var(--r-full);
  display: grid;
  place-items: center;
  color: var(--text-2);
  background: var(--surface);
  border: 1px solid var(--border);
  flex: none;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.iconbtn:hover { background: var(--surface-sunk); border-color: var(--border-strong); }

/* El círculo mide 36px por proporción con la cabecera, pero el área de toque
   debe ser 44. El pseudo-elemento la extiende sin agrandar el dibujo. */
.iconbtn::before,
.avatar::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: inherit;
}
.avatar { position: relative; }
.iconbtn .dot {
  position: absolute;
  top: 5px; right: 6px;
  width: 8px; height: 8px;
  border-radius: var(--r-full);
  background: var(--crit);
  border: 2px solid var(--surface);
}

.avatar {
  width: 36px; height: 36px;
  border-radius: var(--r-full);
  background: var(--brand-800);
  color: var(--n-0);
  display: grid;
  place-items: center;
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: .02em;
  flex: none;
}
.avatar-xs {
  width: 22px; height: 22px;
  border-radius: var(--r-full);
  background: var(--surface-mute);
  color: var(--text-2);
  display: grid;
  place-items: center;
  font-size: var(--fs-micro);
  font-weight: 700;
  flex: none;
}

/* ==========================================================================
   3 · REGIÓN DE CONTENIDO
   ========================================================================== */

.scroll {
  flex: 1;
  min-height: 0;                     /* sin esto, el flex item nunca scrollea */
  overflow-y: auto;
  overscroll-behavior: contain;
  /* El padding superior reserva el alto expandido de la cabecera. JS lo
     ajusta al valor medido; el 116px es la reserva por si JS no corre. */
  padding: calc(var(--topbar-h, 116px) + var(--s-4)) var(--s-4) var(--tabbar-gap);
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}
/* En un flex column los hijos se encogen antes de desbordar: sin esto el
   contenido se comprime para caber y las tarjetas quedan recortadas en vez
   de generar scroll. */
.scroll > * { flex: 0 0 auto; }

.greet {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s-3);
}
.greet .hi { color: var(--text-2); font-size: var(--fs-body); }
.greet .hi b { color: var(--text); font-weight: 700; }

.panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-4);
}

/* Encabezado de grupo con contador — patrón Monday. */
.grouphead {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) 2px 0;
}
.grouphead .gt { color: var(--text-3); }
.grouphead .gline { flex: 1; height: 1px; background: var(--border); }
.grouphead .gcount {
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-micro);
  font-weight: 600;
  color: var(--text-2);
  background: var(--surface-mute);
  padding: 3px 8px;
  border-radius: var(--r-full);
}

/* ==========================================================================
   4 · MONITOR  ·  los tres datos que el rol vigila SIEMPRE

   Un solo bloque responde "¿qué debo mirar?". Tres columnas, tres rótulos
   de una palabra que no cambian nunca — esa constancia es lo que acorta la
   curva: el usuario aprende tres palabras una vez y ya sabe leer su app.

   Rector      PLAN · EQUIPO · COMUNIDAD   (y en ese orden causal: si cae el
                                            equipo, cae el plan, y después la
                                            comunidad)
   Coordinador AL DÍA · EN RIESGO · DETENIDOS  (los tres estados del tablero,
                                            suman el total: lectura Monday)
   Docente     PRÁCTICA · RACHA · OBSERVACIÓN

   No hay figura hero compitiendo: son tres pesos iguales, porque son tres
   hábitos iguales. Un número gigante y dos chicos entrena a ignorar dos.
   ========================================================================== */

.monitor {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-sm);
  overflow: hidden;
}

.monitor-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4) 0;
  color: var(--text-3);
}

.monitor-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  padding: var(--s-3) 0 var(--s-4);
}

.mtile {
  padding: var(--s-1) var(--s-4);
  min-width: 0;
}
.mtile + .mtile { border-left: 1px solid var(--border); }

.mtile .k {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-3);
}
.mtile .v {
  font-family: var(--font-display);
  font-size: var(--fs-kpi);
  font-weight: 800;
  letter-spacing: var(--ls-kpi);
  line-height: 1.05;
  margin-top: 7px;
  font-variant-numeric: proportional-nums;
}
.mtile .v .u { font-size: var(--fs-h3); font-weight: 700; letter-spacing: 0; }

/* La línea de estado siempre trae palabra, no solo color. */
.mtile .s {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  margin-top: var(--s-15);
  font-size: var(--fs-xs);
  line-height: 1.3;
  color: var(--text-3);
}
.mtile .s.ok   { color: var(--ok-ink); }
.mtile .s.warn { color: var(--warn-ink); }
.mtile .s.crit { color: var(--crit-ink); }

.mtile .bar {
  height: 5px;
  border-radius: var(--r-full);
  background: var(--brand-50);
  margin-top: 9px;
  overflow: hidden;
}
.mtile .bar > i { display: block; height: 100%; border-radius: var(--r-full); background: var(--brand-500); }
.mtile .bar.warn { background: var(--warn-soft); }
.mtile .bar.warn > i { background: var(--warn); }

/* Cuando el monitor encabeza una práctica —el caso del docente— lleva
   título y nota antes de las tres columnas. Misma tarjeta blanca que en los
   otros dos roles: un solo componente para los tres, que es lo que hace que
   aprender uno sea aprender los tres. */
.monitor .subject {
  font-family: var(--font-display);
  text-wrap: balance;
  font-size: var(--fs-h1);
  font-weight: 800;
  line-height: 1.16;
  letter-spacing: var(--ls-h1);
  padding: var(--s-2) var(--s-4) 0;
}
.monitor .note {
  text-wrap: pretty;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--text-2);
  padding: var(--s-3) var(--s-4) 0;
}
.monitor .subject + .note + .monitor-grid,
.monitor .note + .monitor-grid {
  border-top: 1px solid var(--border);
  margin-top: var(--s-4);
}

/* ==========================================================================
   5 · AVISO  ·  una sola frase que une el dato con la acción
   ========================================================================== */

.alert {
  text-wrap: pretty;
  display: flex;
  gap: var(--s-2);
  align-items: flex-start;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  line-height: 1.45;
  color: var(--text-2);
  background: var(--crit-soft);
  border: 1px solid var(--crit-line);
}
.alert .i-sm { color: var(--crit); margin-top: 1px; }
.alert b { color: var(--text); font-weight: 700; }
.alert.is-net { background: var(--net-soft); border-color: var(--net-line); }
.alert.is-net .i-sm { color: var(--net); }

/* ==========================================================================
   6 · ACCIONES  ·  qué puedo hacer, con nombre de verbo

   Suben sobre el pliegue. Antes el único botón vivía al final del scroll:
   la acción principal no puede estar donde hay que buscarla. El patrón es
   el panel de NotebookLM — un puñado corto de salidas con nombre propio,
   no un lienzo abierto.
   ========================================================================== */

.actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-2);
}
.action {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: var(--tap);
  padding: var(--s-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  transition: border-color var(--dur-1) var(--ease),
              background var(--dur-1) var(--ease),
              transform var(--dur-1) var(--ease);
}
.action:hover { border-color: var(--border-strong); background: var(--surface-sunk); }
.action:active { transform: scale(.985); }
.action .ic {
  width: 32px; height: 32px;
  border-radius: var(--r-full);
  display: grid;
  place-items: center;
  flex: none;
  background: var(--brand-50);
  color: var(--brand-600);
}
.action .ic.crit { background: var(--crit-soft); color: var(--crit-ink); }
.action .ic.warn { background: var(--warn-soft); color: var(--warn-ink); }
.action .nm {
  font-size: var(--fs-sm);
  font-weight: 650;
  line-height: 1.3;
  letter-spacing: -.005em;
}

/* ==========================================================================
   4b · PANEL DE MANDO  ·  la vista de portafolio de HQ

   HQ no ejecuta: supervisa. Su pantalla es un overview de misiones, no un
   tablero de tareas. Todo aquí está diseñado para responder "¿dónde está
   el problema?" en un barrido, sin abrir nada.
   ========================================================================== */

/* Dos medidores en vez de tres: adopción de la herramienta y cumplimiento
   de misiones. Reusa el monitor con dos columnas. */
.monitor-grid.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* ---- Líderes de operaciones ---- */
.leaders {
  display: flex;
  gap: var(--s-3);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scroll-padding-inline: var(--s-4);   /* si no, el snap se come el padding */
  padding: 2px 2px var(--s-2);
  margin: 0 calc(-1 * var(--s-4));
  padding-inline: var(--s-4);
  scrollbar-width: none;
}
.leaders::-webkit-scrollbar { display: none; }

.leader {
  flex: none;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-15);
  width: 62px;
}
.leader .av {
  position: relative;
  width: 46px; height: 46px;
  border-radius: var(--r-full);
  background: var(--brand-800);
  color: var(--n-0);
  display: grid;
  place-items: center;
  font-size: var(--fs-sm);
  font-weight: 700;
  transition: transform var(--dur-1) var(--ease);
}
.leader:hover .av { transform: scale(1.06); }
.leader.is-more .av {
  background: var(--surface-mute);
  color: var(--text-2);
  font-family: var(--font-display);
  font-weight: 800;
}

.leader .nm {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--text-2);
  text-align: center;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* El punto marca al líder con un frente bloqueado: HQ sabe con quién
   hablar antes de leer una sola tarjeta. */
.leader .flag {
  position: absolute;
  right: -1px; bottom: -1px;
  width: 15px; height: 15px;
  border-radius: var(--r-full);
  background: var(--crit);
  border: 2.5px solid var(--surface);
}

/* ---- Pila de operadores, con el Master Chief destacado ---- */
.stack { display: flex; align-items: center; padding: 4px; }
/* 28px es el mínimo para que dos iniciales a 10.5px quepan sin recortarse.
   El solape de 6px deja ver la inicial del avatar de atrás. */
.stack .av {
  position: relative;
  width: 28px; height: 28px;
  border-radius: var(--r-full);
  border: 2px solid var(--surface);
  margin-left: -6px;
  background: var(--surface-mute);
  color: var(--text-2);
  display: grid;
  place-items: center;
  font-size: var(--fs-micro);
  font-weight: 700;
}
.stack .av:first-child { margin-left: 0; }
.stack .av.more {
  width: auto;
  min-width: 28px;
  padding: 0 var(--s-15);
  background: var(--surface-sunk);
  color: var(--text-3);
  font-size: var(--fs-micro);
}

/* El Master Chief va en petróleo y con estrella: en una pila de iniciales
   grises, el responsable de campo se lee sin leer. */
/* Se probó una estrella de 10px como distintivo y a ese tamaño se lee como
   un borrón. El anillo funciona a cualquier escala y nunca se deforma: el
   Master Chief va relleno en petróleo, primero en la pila, y con anillo. */
.stack .av.chief {
  background: var(--brand-800);
  color: var(--n-0);
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--brand-400);
  margin-right: var(--s-3);          /* libra el anillo y el solape siguiente */
  z-index: 1;
}
.stack .av.chief + .av { margin-left: 0; }

/* ---- Misión estratégica ---- */
.mission {
  width: 100%;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-4);
  box-shadow: var(--sh-sm);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
.mission.is-ready { border-color: var(--ok-line); }
.mission.is-blocked { border-color: var(--crit-line); }

.mission-top { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }

/* El tag organiza por reto. Deliberadamente sin color propio: un matiz por
   categoría colisionaría con el semáforo y rompería la regla de que el
   color solo comunica estado. La etiqueta organiza; el color, no. */
.tag {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-2);
  background: var(--surface-mute);
  padding: 4px 9px;
  border-radius: var(--r-sm);
  white-space: nowrap;
}
.mission-top .count { font-size: var(--fs-xs); color: var(--text-3); white-space: nowrap; }

.mission-title {
  font-family: var(--font-display);
  text-wrap: balance;
  font-size: var(--fs-h2);
  font-weight: 800;
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-h2);
}

.mission-goal { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.mission-goal .goal { font-size: var(--fs-sm); color: var(--text-2); }
.mission-goal .goal b { font-family: var(--font-display); color: var(--text); font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.mission-goal .goal .to { color: var(--text-3); margin: 0 3px; }
.mission > .bar {
  height: 6px;
  border-radius: var(--r-full);
  background: var(--brand-50);
  overflow: hidden;
}
.mission > .bar > i {
  display: block;
  height: 100%;
  border-radius: var(--r-full);
  background: var(--brand-500);
}
.mission.is-ready > .bar { background: var(--ok-soft); }
.mission.is-ready > .bar > i { background: var(--ok); }

.mission-goal .av {
  width: 28px; height: 28px;
  border-radius: var(--r-full);
  background: var(--brand-50);
  color: var(--brand-700);
  display: grid;
  place-items: center;
  font-size: var(--fs-micro);
  font-weight: 700;
  flex: none;
}

/* ---- Tácticas dentro de la misión ---- */
.tactics {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--border);
  margin-top: 2px;
}
.tactic {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--border);
  text-align: left;
}
.tactic:last-child { border-bottom: 0; padding-bottom: 0; }
.tactic .dot {
  width: 8px; height: 8px;
  border-radius: var(--r-full);
  flex: none;
  background: var(--border-strong);
}
.tactic.is-ok .dot   { background: var(--ok); }
.tactic.is-warn .dot { background: var(--warn); }
.tactic.is-crit .dot { background: var(--crit); }
.tactic .bd { flex: 1; min-width: 0; }
.tactic .t { display: block; font-size: var(--fs-sm); font-weight: 600; line-height: 1.35; }
.tactic .s { display: block; font-size: var(--fs-xs); color: var(--text-3); margin-top: 3px; line-height: 1.35; }
.tactic.is-crit .s { color: var(--crit-ink); font-weight: 600; }
/* Se alinea con los títulos de táctica, no con el borde: el punto de
   estado ocupa 8px más 12 de gap. */
.tactics .more {
  font-size: var(--fs-xs);
  color: var(--text-3);
  padding: var(--s-3) 0 0;
  padding-left: calc(8px + var(--s-3));
}

/* ---- Cierre de misión ---- */
.mission .close-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  width: 100%;
  min-height: var(--tap);
  border-radius: var(--r-md);
  background: var(--brand-800);
  color: var(--cyan);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: 800;
  letter-spacing: -.006em;
  transition: background var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.mission .close-cta:hover { background: var(--brand-700); }
.mission .close-cta:active { transform: scale(.99); }

/* ==========================================================================
   4c · SUPERFICIES DEL LÍDER DE OPERACIONES

   Ops es el único rol que mira hacia afuera. HQ mira su portafolio y el
   operador mira su aula; Ops es quien trae inteligencia de la red. Por eso
   su pantalla termina en dos superficies de descubrimiento —recursos y
   pares— que en los otros dos roles no existirían.
   ========================================================================== */

/* ---- Tarjeta de misión táctica ----
   Más liviana que la estratégica de HQ: aquí no hay objetivo numérico ni
   tácticas anidadas, porque esta YA es la unidad de ejecución. */
.tmission {
  width: 100%;
  text-align: left;
  /* Dos puntos de luminosidad entre el borde superior y el inferior. No se
     ve; se siente. Es lo que separa una tarjeta plana de una fabricada. */
  background: linear-gradient(180deg, var(--surface) 0%, var(--n-25) 100%);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-4);
  box-shadow: var(--sh-sm);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.tmission:hover { border-color: var(--border-strong); box-shadow: var(--sh-md); }
.tmission:active { transform: scale(.992); }
.tmission.is-crit { border-color: var(--crit-line); }
.tmission.is-warn { border-color: var(--warn-line); }

.tmission-top { display: flex; align-items: center; justify-content: space-between; gap: var(--s-2); }
.tmission-title {
  font-family: var(--font-display);
  text-wrap: balance;
  font-size: var(--fs-h2);
  font-weight: 800;
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-h2);
}
.tmission-note { font-size: var(--fs-sm); color: var(--text-3); line-height: 1.45; }
.tmission.is-crit .tmission-note { color: var(--crit-ink); font-weight: 600; }
.tmission-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid var(--border);
}
.tmission-foot .who { font-size: var(--fs-xs); color: var(--text-3); }

/* ---- Feed de recursos ----
   La línea de contexto no es adorno: es lo que separa un estante de
   contenido de un feed que engancha. Netflix dice "porque viste X"; aquí
   dice por qué ESTE recurso es para ESTE líder ESTA semana. Sin esa línea,
   un recurso sugerido es ruido con buena tipografía. */
.res {
  width: 100%;
  text-align: left;
  display: flex;
  gap: var(--s-3);
  align-items: flex-start;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--s-3);
  transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.res:hover { border-color: var(--border-strong); background: var(--surface-sunk); }
.res:active { transform: scale(.99); }

.res .ic {
  width: 40px; height: 40px;
  border-radius: var(--r-sm);
  display: grid;
  place-items: center;
  flex: none;
  background: var(--brand-50);
  color: var(--brand-600);
}
.res .bd { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.res .bd > * { display: block; }
.res .kind {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-3);
}
.res .t {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 700;
  line-height: 1.32;
  letter-spacing: -.006em;
  margin-top: var(--s-1);
}
/* La razón por la que este recurso aparece. Va en color de marca porque es
   la parte que hace que se toque. */
.res .why {
  font-size: var(--fs-xs);
  color: var(--brand-600);
  font-weight: 600;
  line-height: 1.4;
  margin-top: var(--s-15);
}
.res .meta { font-size: var(--fs-xs); color: var(--text-3); margin-top: var(--s-15); line-height: 1.4; }

/* El destacado: mismo componente, más peso. Un feed sin jerarquía obliga a
   leerlo entero. */
.res.is-lead { padding: var(--s-4); border-radius: var(--r-lg); box-shadow: var(--sh-sm); background: linear-gradient(180deg, var(--surface) 0%, var(--n-25) 100%); }
.res.is-lead .ic { width: 46px; height: 46px; background: var(--brand-800); color: var(--cyan); border-radius: var(--r-md); }
.res.is-lead .t { font-size: var(--fs-h2); letter-spacing: var(--ls-h2); font-weight: 800; }

/* Bloque de fecha para el evento: se lee como una hoja de calendario. */
.res .cal {
  width: 40px; height: 40px;
  border-radius: var(--r-sm);
  flex: none;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  display: grid;
  place-items: center;
  align-content: center;
  line-height: 1.05;
  text-align: center;
}
.res .cal .d { font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 800; line-height: 1.2; color: var(--text); }
.res .cal .m { font-size: 9px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-3); }

/* Barra fina de avance para los cursos empezados. */
.res .prog { height: 4px; border-radius: var(--r-full); background: var(--brand-50); margin-top: var(--s-2); overflow: hidden; }
.res .prog > i { display: block; height: 100%; border-radius: var(--r-full); background: var(--brand-500); }

/* ---- Pares de la red ----
   Carrusel horizontal a propósito: es superficie de descubrimiento, no de
   tarea. Esconder parte tras el scroll aquí no cuesta nada; en la lista de
   frentes costaría una decisión. */
.peers {
  display: flex;
  gap: var(--s-3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--s-4);   /* si no, el snap se come el padding */
  padding: 2px 2px var(--s-2);
  margin: 0 calc(-1 * var(--s-4));
  padding-inline: var(--s-4);
  scrollbar-width: none;
}
.peers::-webkit-scrollbar { display: none; }

.peer {
  flex: none;
  width: 208px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-4);
  box-shadow: var(--sh-sm);
}
.peer .av {
  width: 44px; height: 44px;
  border-radius: var(--r-full);
  background: var(--brand-800);
  color: var(--n-0);
  display: grid;
  place-items: center;
  font-size: var(--fs-sm);
  font-weight: 700;
}
.peer .nm { font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 700; line-height: 1.28; letter-spacing: -.006em; }
.peer .org { font-size: var(--fs-xs); color: var(--text-3); line-height: 1.35; }
/* El motivo de la sugerencia. Sin él, "personas que quizá conozcas". */
.peer .why {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--brand-700);
  background: var(--brand-50);
  border-radius: var(--r-sm);
  padding: var(--s-15) var(--s-2);
  line-height: 1.35;
}
.peer .follow {
  margin-top: auto;
  min-height: var(--tap);
  border: 1.5px solid var(--brand-600);
  border-radius: var(--r-md);
  color: var(--brand-700);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: -.006em;
  display: grid;
  place-items: center;
  transition: background var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.peer .follow:hover { background: var(--brand-50); }
.peer .follow:active { transform: scale(.98); }

/* ==========================================================================
   6b · RANGO Y DESIGNACIÓN

   Dos cosas distintas que conviene no confundir:

   · El RANGO es permanente y se gana. Es la progresión, y su moneda son los
     ciclos cerrados con evidencia — la misma métrica norte del producto, no
     puntos de vanidad.
   · MASTER CHIEF es rotativo: se designa por misión y responde por la
     ejecución en campo. Solo se puede designar desde Chief.

   Esa separación le da propósito a la escalera: se sube para poder liderar.
   ========================================================================== */

.rank {
  display: inline-flex;
  align-items: center;
  gap: var(--s-15);
  padding: 3px 9px 3px 7px;
  border-radius: var(--r-full);
  background: var(--brand-50);
  color: var(--brand-700);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* La designación de misión no tiene banda propia: vive al pie de la tarjeta
   de rango (§6c, `.rankcard .desig`). Suelta, competía con el rango por la
   misma atención; cosida abajo dice lo que de verdad significa —liderar en
   campo es el uso del rango, no un adorno aparte. */

/* ==========================================================================
   6c · SUPERFICIES DEL OPERADOR

   El operador es el rol con menos tiempo y más desgaste: da clase. Su
   pantalla no informa, motiva — y la motivación aquí no es decorativa, es
   la condición de que el dato exista. Si él no cierra el ciclo, HQ y Ops
   miran tableros vacíos.

   Tres decisiones gobiernan estas superficies:

   1. El RANGO va primero y completo. Duolingo no esconde la racha en una
      pestaña: es lo primero que ves. Aquí el rango, lo que falta para el
      siguiente y los requisitos exactos viven en una sola tarjeta, con la
      designación de Master Chief cosida abajo. Identidad, progreso y
      encargo son un solo objeto, no tres tarjetas sueltas.

   2. La TAREA se marca desde la pantalla principal. El micro-momento de
      tachar es el refuerzo más barato y más potente que tiene el producto;
      esconderlo tras un detalle lo desperdicia.

   3. El bloque de MASTER CHIEF vive DENTRO de la misión que lidera, no en
      un panel aparte. Un panel de supervisión propio lo convertiría en un
      líder de operaciones en miniatura y borraría la frontera entre los dos
      roles. Manda en su frente; los demás frentes no son asunto suyo.
   ========================================================================== */

/* ---- Tarjeta de rango: el ancla motivacional de la pantalla ---- */
.rankcard {
  background: linear-gradient(180deg, var(--surface) 0%, var(--n-25) 100%);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-sm);
  overflow: hidden;
}

.rankcard-top {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  padding: var(--s-5) var(--s-4);
}

/* Anillo de avance con la insignia adentro. La insignia dice quién eres;
   el anillo, cuánto falta. Separarlos en dos gráficos distintos obligaría
   a leer dos veces lo que es una sola idea. */
.rankcard .dial {
  position: relative;
  flex: none;
  width: 82px;
  height: 82px;
  border-radius: var(--r-full);
  background: conic-gradient(var(--brand-500) calc(var(--p, 0) * 1%), var(--brand-100) 0);
  display: grid;
  place-items: center;
}
.rankcard .dial::before {
  content: "";
  position: absolute;
  inset: 6px;
  border-radius: inherit;
  background: var(--brand-50);
}
/* Galones: tres para Chief. Es el vocabulario de la metáfora y se lee como
   nivel sin necesidad de rótulo. */
.rankcard .dial .insignia {
  position: relative;
  width: 34px;
  height: 34px;
  stroke: var(--brand-700);
  fill: none;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.rankcard .who { flex: 1; min-width: 0; }
.rankcard .who .k { color: var(--text-3); }
.rankcard .who .lvl {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 800;
  line-height: 1.16;
  letter-spacing: var(--ls-h1);
  margin-top: 2px;
}
.rankcard .who .next {
  font-size: var(--fs-sm);
  color: var(--text-2);
  line-height: 1.4;
  margin-top: var(--s-15);
}
.rankcard .who .next b {
  font-family: var(--font-display);
  font-weight: 800;
  color: var(--brand-600);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}

/* ---- Escalera de rango ----
   Un número suelto ("8 de 16") no dice si vas adelante o atrás. La escalera
   sí: se ve de dónde vienes, dónde estás y que hay techo. */
.ladder {
  display: flex;
  align-items: flex-end;
  gap: var(--s-1);
  padding: 0 var(--s-4) var(--s-4);
}
.ladder .st { flex: 1; min-width: 0; text-align: center; }
.ladder .st .pip {
  display: block;                  /* es un <i>: en línea no toma alto */
  height: 6px;
  border-radius: var(--r-full);
  background: var(--surface-mute);
}
.ladder .st.done .pip { background: var(--brand-300); }
.ladder .st.now  .pip { background: var(--brand-600); height: 10px; }
.ladder .st .lb {
  display: block;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: .005em;
  color: var(--text-3);
  margin-top: var(--s-15);
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ladder .st.now .lb { color: var(--brand-700); font-weight: 750; }

/* ---- Requisitos del siguiente rango ----
   El "qué me falta" tiene que ser accionable. Un contador de ciclos a ocho
   semanas de distancia desmotiva; tres requisitos, uno ya cumplido, leen
   como algo que se puede terminar. */
.needs {
  border-top: 1px solid var(--border);
  padding: var(--s-3) var(--s-4);
  display: flex;
  flex-direction: column;
  gap: var(--s-15);
}
.needs .cap { color: var(--text-3); margin-bottom: var(--s-1); }
.need {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 26px;
}
.need .box {
  flex: none;
  width: 19px;
  height: 19px;
  border-radius: var(--r-full);
  border: 2px solid var(--border-strong);
  display: grid;
  place-items: center;
  color: transparent;
}
.need.is-done .box { background: var(--ok); border-color: var(--ok); color: var(--n-0); }
.need .lb { flex: 1; min-width: 0; font-size: var(--fs-sm); line-height: 1.35; }
.need.is-done .lb { color: var(--text-3); }
.need .val {
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.need.is-done .val { color: var(--ok-ink); }

/* ---- Designación, cosida al pie de la tarjeta ----
   Antes era una banda suelta encima del monitor. Como pie del rango dice lo
   que de verdad significa: liderar en campo es el uso del rango, no un
   adorno aparte. */
.rankcard .desig {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: var(--brand-50);
  border-top: 1px solid var(--brand-100);
}
.rankcard .desig .star { color: var(--brand-600); }
.rankcard .desig .tx { flex: 1; min-width: 0; font-size: var(--fs-xs); color: var(--brand-700); line-height: 1.35; }
.rankcard .desig .tx b { display: block; font-size: var(--fs-sm); font-weight: 750; color: var(--brand-800); }

/* ---- Lista de tareas ----
   Orden: primero por fecha (los grupos), luego por prioridad dentro del
   grupo. La franja da la prioridad de un vistazo y la palabra la confirma
   —nunca solo color, por daltonismo. */
.tasks { display: flex; flex-direction: column; gap: var(--s-2); }

.task {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--s-3) var(--s-3) var(--s-3) calc(var(--s-4) + 2px);
  overflow: hidden;
  transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.task:hover { border-color: var(--border-strong); }
.task > .bar {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 4px;
  background: var(--deemph);
}
.task.is-crit > .bar { background: var(--crit); }
.task.is-warn > .bar { background: var(--warn); }

/* La casilla mide 22px por proporción con la fila; el área de toque se
   extiende a 44px con el pseudo, como en los íconos de la cabecera. */
.task .check {
  flex: none;
  position: relative;
  width: 22px;
  height: 22px;
  margin-top: 1px;
  border-radius: var(--r-full);
  border: 2px solid var(--border-strong);
  background: var(--surface);
  display: grid;
  place-items: center;
  color: transparent;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease-spring);
}
.task .check::before { content: ""; position: absolute; inset: -11px; border-radius: inherit; }
.task .check:hover { border-color: var(--brand-500); }
.task .check:active { transform: scale(.86); }

.task .bd {
  flex: 1;
  min-width: 0;
  min-height: var(--tap);          /* el cuerpo ES el objetivo de toque */
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  background: none;
}
.task .bd > * { display: block; width: 100%; }
.task .t { font-size: var(--fs-h3); font-weight: 600; line-height: 1.35; }
.task .m { font-size: var(--fs-xs); color: var(--text-3); margin-top: 3px; line-height: 1.35; }
.task .m b { font-weight: 700; color: var(--text-2); }
.task.is-crit .m b { color: var(--crit-ink); }
.task.is-warn .m b { color: var(--warn-ink); }

.task .due {
  flex: none;
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  margin-top: 2px;
}
.task.is-crit .due { color: var(--crit-ink); }

/* Marcada: el refuerzo. El tachado y el verde llegan juntos y la fila se
   apaga sin desaparecer —ver lo hecho es parte del premio. */
.task.is-done { background: var(--surface-sunk); border-color: var(--border); }
.task.is-done > .bar { background: var(--ok); }
.task.is-done .check { background: var(--ok); border-color: var(--ok); color: var(--n-0); }
.task.is-done .t { text-decoration: line-through; color: var(--text-3); font-weight: 500; }
.task.is-done .due { color: var(--ok-ink); }

.taskmore {
  align-self: center;
  padding: var(--s-2) var(--s-3);
  min-height: var(--tap);
  font-size: var(--fs-sm);
  font-weight: 650;
  color: var(--brand-600);
}
.taskmore:hover { color: var(--brand-800); }

/* ---- Misión donde el operador es Master Chief ----
   Mismo componente que en la cabina de Ops, con un borde de marca y el
   mando anidado. No es una tarjeta oscura: el peso lo dan el borde y la
   sombra, no un fondo de color. */
.tmission.is-chief {
  border-color: var(--brand-300);
  box-shadow: var(--sh-md);
  cursor: default;
}
.tmission.is-chief:hover { border-color: var(--brand-300); box-shadow: var(--sh-md); }
.tmission.is-chief:active { transform: none; }

/* ---- Mando de campo del Master Chief ---- */
.command {
  border-top: 1px solid var(--border);
  padding-top: var(--s-3);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
.command .cap { color: var(--text-3); }

.cgrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
.cstat {
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: var(--s-3);
}
.cstat .k { color: var(--text-3); }
.cstat .v {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 800;
  letter-spacing: var(--ls-h1);
  line-height: 1.25;               /* 1.1 recortaba el trazo inferior de Manrope */
  margin-top: 2px;
}
.cstat .v .u { font-size: var(--fs-sm); font-weight: 700; letter-spacing: 0; color: var(--text-2); }
.cstat .s { font-size: var(--fs-xs); color: var(--text-3); margin-top: var(--s-1); line-height: 1.3; }
.cstat.is-crit { background: var(--crit-soft); border-color: var(--crit-line); }
.cstat.is-crit .v, .cstat.is-crit .s { color: var(--crit-ink); }
.cstat.is-crit .k { color: var(--crit-ink); opacity: .85; }

/* "A quién darle una mano", no "quién va peor".
   El dato es el mismo; el encuadre decide si el equipo adopta la
   herramienta o la sabotea. Un ranking público de incumplimiento dentro de
   una sala de profesores se paga caro, y la acción que ofrece la fila
   —escribirle— es la que de verdad mueve el número. */
.lag { display: flex; flex-direction: column; gap: var(--s-2); }
.lagrow { display: flex; align-items: center; gap: var(--s-3); }
.lagrow .av {
  flex: none;
  width: 32px; height: 32px;
  border-radius: var(--r-full);
  background: var(--surface-mute);
  color: var(--text-2);
  display: grid; place-items: center;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .02em;
}
.lagrow .bd { flex: 1; min-width: 0; }
.lagrow .bd > * { display: block; }
.lagrow .nm { font-size: var(--fs-sm); font-weight: 650; line-height: 1.25; }
.lagrow .mini {
  height: 4px;
  border-radius: var(--r-full);
  background: var(--surface-mute);
  overflow: hidden;
  margin-top: var(--s-15);
}
.lagrow .mini > i { display: block; height: 100%; border-radius: var(--r-full); background: var(--warn); }
.lagrow .mini.crit > i { background: var(--crit); }
.lagrow .s { font-size: var(--fs-xs); color: var(--text-3); margin-top: 3px; line-height: 1.3; }
.lagrow .act {
  flex: none;
  min-height: var(--tap);
  padding: 0 var(--s-3);
  border-radius: var(--r-sm);
  border: 1.5px solid var(--border-strong);
  color: var(--brand-700);
  font-size: var(--fs-xs);
  font-weight: 700;
  display: grid;
  place-items: center;
}
.lagrow .act:hover { border-color: var(--brand-500); background: var(--brand-50); }
.lagrow .act:active { transform: scale(.97); }

/* ==========================================================================
   7 · FILA DE TRABAJO  (Asana × Monday)
   ========================================================================== */

.row {
  display: flex;
  align-items: stretch;
  gap: var(--s-3);
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--s-3) var(--s-3) var(--s-3) var(--s-2);
  transition: border-color var(--dur-1) var(--ease),
              box-shadow var(--dur-1) var(--ease),
              transform var(--dur-1) var(--ease);
}
.row:hover { border-color: var(--border-strong); box-shadow: var(--sh-sm); }
.row:active { transform: scale(.988); }

/* Franja de estado a la izquierda — nunca es el único canal: la fila
   siempre trae además un chip con ícono y nombre. */
.row .bar {
  width: 4px;
  border-radius: var(--r-full);
  flex: none;
  background: var(--border-strong);
}
.row.is-crit .bar { background: var(--crit); }
.row.is-warn .bar { background: var(--warn); }
.row.is-ok   .bar { background: var(--ok); }
.row.is-net  .bar { background: var(--net); }

.row-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.row-body > * { display: block; width: 100%; }

.row-top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--s-2);
}
.row-title {
  text-wrap: pretty;
  font-size: var(--fs-h3);
  font-weight: 650;
  line-height: var(--lh-snug);
  letter-spacing: -.008em;
  color: var(--text);
}
.row-sub {
  font-size: var(--fs-xs);
  color: var(--text-3);
  line-height: 1.45;
  margin-top: 5px;
}

.row-meta {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-2);
  width: auto;
}
.row-meta .who {
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-micro);
  color: var(--text-3);
  letter-spacing: .01em;
}

.row .go {
  align-self: center;
  flex: none;
  color: var(--text-3);
  transition: transform var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.row:hover .go { transform: translateX(2px); color: var(--brand-600); }

/* ==========================================================================
   8 · CHIP DE ESTADO  (Monday: el estado tiene nombre)
   ========================================================================== */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex: none;
  width: auto;
  padding: 4px 9px 4px 7px;
  border-radius: var(--r-full);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.chip.crit { background: var(--crit-soft); color: var(--crit-ink); }
.chip.warn { background: var(--warn-soft); color: var(--warn-ink); }
.chip.ok   { background: var(--ok-soft);   color: var(--ok-ink); }
.chip.net  { background: var(--net-soft);  color: var(--net-ink); }
.chip.mute { background: var(--surface-mute); color: var(--text-2); }

/* ==========================================================================
   9 · BOTONES  (Duolingo: el primario tiene canto y se hunde)
   ========================================================================== */

.btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--tap);
  padding: 13px var(--s-4);
  border-radius: var(--r-md);
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 800;
  letter-spacing: -.008em;
  text-align: center;
}

/* El botón repite la lógica del logo: cuerpo en petróleo, señal en cian.
   Se probó el relleno en cian y dominaba la pantalla — un slab de neón le
   robaba la atención a los tres datos, que es justo lo contrario de lo que
   la jerarquía necesita. A escala de texto el cian señala sin gritar. */
/* El cian del rótulo lleva halo propio. Sobre petróleo el cian mide 9.36:1,
   así que el halo no compra legibilidad —la tiene— sino presencia: es el
   punto de la "i" encendido. */
.btn-primary {
  background: var(--brand-800);
  color: var(--cyan);
  box-shadow: 0 4px 0 var(--brand-950);
  transform: translateY(0);
  transition: transform var(--dur-1) var(--ease),
              box-shadow var(--dur-1) var(--ease),
              background var(--dur-1) var(--ease);
}
.btn-primary:hover { background: var(--brand-700); }
.btn-primary { text-shadow: 0 0 22px rgba(0, 249, 255, .40); }
.btn-primary .hint { text-shadow: none; }
.btn-primary:active {
  transform: translateY(4px);
  box-shadow: 0 0 0 var(--brand-950);
}
.btn-primary .hint {
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--brand-200);
  margin-top: 4px;
}

.btn-ghost {
  background: var(--surface);
  color: var(--text-2);
  border: 1.5px solid var(--border);
  transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.btn-ghost:hover { border-color: var(--border-strong); color: var(--text); }

.endnote { text-align: center; color: var(--text-3); padding-top: 2px; }

/* ==========================================================================
   12 · PULSO SEMANAL
   ========================================================================== */

.pulse {
  background: var(--surface);
  border: 1.5px solid var(--brand-300);
  border-radius: var(--r-lg);
  padding: var(--s-4);
}
.pulse .q { font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 700; line-height: var(--lh-snug); letter-spacing: -.006em; }
.pulse .opts { display: flex; gap: var(--s-2); margin-top: var(--s-3); }
.pulse .opts button {
  flex: 1;
  min-height: var(--tap);
  background: var(--surface-sunk);
  border: 1.5px solid var(--border);
  border-radius: var(--r-sm);
  font-size: var(--fs-h1);
  line-height: 1;
  text-align: center;
  transition: transform var(--dur-1) var(--ease-spring),
              border-color var(--dur-1) var(--ease),
              background var(--dur-1) var(--ease);
}
.pulse .opts button:hover { border-color: var(--brand-300); background: var(--brand-50); }
.pulse .opts button:active { transform: scale(.9); }
.pulse .opts button[aria-pressed="true"] {
  border-color: var(--brand-500);
  background: var(--brand-50);
  transform: scale(1.06);
}
.pulse .ack {
  display: none;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-3);
  font-size: var(--fs-sm);
  font-weight: 650;
  color: var(--ok-ink);
}
.pulse.is-done .ack { display: flex; animation: pop var(--dur-3) var(--ease-spring); }
.pulse .note { color: var(--text-3); margin-top: var(--s-3); line-height: 1.5; }

@keyframes pop {
  from { opacity: 0; transform: translateY(5px) scale(.94); }
  to   { opacity: 1; transform: none; }
}

/* ==========================================================================
   13 · NAVEGACIÓN INFERIOR
   ========================================================================== */

/* Barra flotante de vidrio, al modo del UI nuevo de Instagram: no se apoya
   en el borde inferior, flota sobre el contenido y lo deja pasar por debajo
   desenfocado. El velo es opaco a propósito — sobre blanco, un vidrio
   más transparente deja leer el texto que scrollea detrás y los rótulos de la
   barra pierden contraste. */
.tabbar {
  position: absolute;
  left: var(--s-3);
  right: var(--s-3);
  bottom: max(var(--s-3), env(safe-area-inset-bottom));
  z-index: 20;
  display: flex;
  gap: var(--s-1);
  padding: 6px;
  border-radius: var(--r-xl);
  background: var(--glass);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-shadow);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  /* El filo blanco de un píxel arriba es lo que hace que el vidrio se lea
     como vidrio y no como una lámina gris translúcida. */
  box-shadow: var(--glass-shadow), inset 0 1px 0 rgba(255, 255, 255, .85);
}

/* Sin backdrop-filter el vidrio sería una lámina translúcida sobre texto:
   ahí la barra se vuelve sólida. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .tabbar { background: var(--surface); border-color: var(--border); }
}
.tabbar button {
  flex: 1;
  min-height: var(--tap);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-1);
  padding: 5px 0 4px;
  color: var(--text-3);
  border-radius: var(--r-md);
  transition: color var(--dur-2) var(--ease);
}
.tabbar button .ico {
  display: grid;
  place-items: center;
  width: 46px; height: 26px;
  border-radius: var(--r-full);
  transition: background var(--dur-2) var(--ease);
}
.tabbar button span { font-size: var(--fs-micro); font-weight: 650; letter-spacing: .01em; }
.tabbar button:hover { color: var(--text-2); }
.tabbar button[aria-current="page"] { color: var(--brand-600); }
.tabbar button[aria-current="page"] .ico { background: var(--brand-50); }
[data-theme="dark"] .tabbar button[aria-current="page"] .ico { background: var(--net-soft); }

/* ==========================================================================
   14 · HOJA INFERIOR
   ========================================================================== */

.scrim {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;
  align-items: flex-end;
  justify-content: center;
  padding: var(--s-4);
  background: rgba(19, 25, 23, .44);
  backdrop-filter: blur(2px);
}
.scrim.is-open { display: flex; animation: fade var(--dur-2) var(--ease); }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

.sheet {
  width: 100%;
  max-width: var(--app-w);
  background: var(--surface);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-sheet);
  padding: var(--s-3) var(--s-5) var(--s-5);
  max-height: 88dvh;
  overflow-y: auto;
  animation: rise var(--dur-3) var(--ease);
}
@keyframes rise { from { transform: translateY(26px); opacity: .4; } to { transform: none; opacity: 1; } }

.sheet .grab {
  width: 40px; height: 4px;
  border-radius: var(--r-full);
  background: var(--border-strong);
  margin: 0 auto var(--s-4);
}
.sheet-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-3);
}
.sheet-head .st { font-family: var(--font-display); font-size: var(--fs-h2); font-weight: 800; letter-spacing: var(--ls-h2); }

/* El cronómetro es una promesa de producto hecha visible: 90 segundos. */
.timer {
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--brand-600);
  background: var(--brand-50);
  padding: 5px 10px;
  border-radius: var(--r-full);
  letter-spacing: .04em;
  flex: none;
  font-variant-numeric: tabular-nums;
}

.steps { display: flex; gap: 5px; margin-top: var(--s-4); }
.steps i {
  height: 4px;
  flex: 1;
  border-radius: var(--r-full);
  background: var(--surface-mute);
  transition: background var(--dur-2) var(--ease);
}
.steps i.on { background: var(--brand-500); }

.sheet-q { font-size: var(--fs-body); color: var(--text-2); margin-top: var(--s-4); line-height: 1.5; }

.choices { display: flex; flex-direction: column; gap: var(--s-2); margin-top: var(--s-4); }
.choices button {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  min-height: var(--tap);
  padding: var(--s-3) var(--s-4);
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--r-md);
  transition: border-color var(--dur-1) var(--ease),
              background var(--dur-1) var(--ease),
              transform var(--dur-1) var(--ease);
}
.choices button:hover { border-color: var(--brand-300); background: var(--brand-50); }
.choices button:active { transform: scale(.99); }
.choices .lead { width: 10px; height: 10px; border-radius: var(--r-full); flex: none; }
.choices .lab { flex: 1; min-width: 0; }
.choices .lab .a { display: block; font-size: var(--fs-h3); font-weight: 650; line-height: var(--lh-snug); }
.choices .lab .b { display: block; font-size: var(--fs-xs); color: var(--text-3); margin-top: 3px; line-height: 1.4; }

.picks { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-4); }
.picks button {
  min-height: var(--tap);
  padding: 0 var(--s-5);
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--r-full);
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-h3);
  font-weight: 600;
  transition: border-color var(--dur-1) var(--ease),
              background var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease);
}
.picks button:hover { border-color: var(--brand-500); background: var(--brand-50); color: var(--brand-700); }

.finish { text-align: center; padding: var(--s-4) 0 0; }
.finish .seal {
  width: 60px; height: 60px;
  border-radius: var(--r-full);
  background: var(--brand-50);
  color: var(--brand-600);
  display: grid;
  place-items: center;
  margin: 0 auto var(--s-4);
  animation: pop var(--dur-3) var(--ease-spring);
}
.finish .seal .i { width: 28px; height: 28px; stroke-width: 2.6; }
.finish .a { font-family: var(--font-display); font-size: var(--fs-h1); font-weight: 800; letter-spacing: var(--ls-h1); }
.finish .b {
  font-size: var(--fs-sm);
  color: var(--text-2);
  margin-top: var(--s-3);
  line-height: 1.5;
  max-width: 34ch;
  margin-inline: auto;
}
.finish .c {
  color: var(--text-3);
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--border);
}

.sheet .btn { margin-top: var(--s-5); }

/* ==========================================================================
   15 · AVISO EFÍMERO
   ========================================================================== */

.toast {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translate(-50%, 16px);
  z-index: 80;
  max-width: min(88vw, 380px);
  padding: 12px 18px;
  border-radius: var(--r-full);
  background: var(--n-900);
  color: var(--n-0);
  font-size: var(--fs-sm);
  font-weight: 500;
  text-align: center;
  box-shadow: var(--sh-lg);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
.toast.is-on { opacity: 1; transform: translate(-50%, 0); }
[data-theme="dark"] .toast { background: var(--n-100); color: var(--n-900); }

/* ==========================================================================
   16 · INSTRUMENTO  ·  la capa oscura de medición

   Una regla de sistema, no un adorno: **la superficie de medición primaria de
   cada rol es un instrumento oscuro.** HQ mide adopción y cumplimiento; el
   líder de operaciones mide su escuadra; el operador mide su rango. Esas tres
   y ninguna más. Todo lo demás sigue siendo tarjeta blanca.

   Por qué esto y no una app oscura entera: el producto vive en salones con
   sol, en gama media y en manos de docentes de cincuenta años. Una interfaz
   oscura completa se paga en legibilidad real. Un panel de instrumentos
   dentro de una interfaz clara, no — y es además la única forma de que el
   cian de la marca haga su trabajo, porque mide 1.31:1 contra blanco y
   9.36:1 sobre petróleo. Hasta ahora el color de señal de Itera no tenía
   dónde vivir salvo el rótulo de un botón.

   Tablero de avión, no consola de videojuego. Esa es la línea.
   ========================================================================== */

.instrument {
  position: relative;
  isolation: isolate;
  background: var(--mesh-ink);
  border: 1px solid rgba(125, 244, 250, .10);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-ink), var(--edge-hi);
  color: var(--ink-text);
  overflow: hidden;
}
/* Fuente puntual arriba, como la tiene cualquier panel físico. Sin ella el
   bloque oscuro es una mancha plana. */
.instrument::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background: var(--mesh-cyan);
  pointer-events: none;
}
/* Grano. Un degradado oscuro sin grano hace bandas en pantallas de 6 bits
   —justo las de gama media que este producto va a encontrar. */
.instrument::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: var(--grain);
  opacity: .38;
  mix-blend-mode: overlay;
  pointer-events: none;
}

/* ---- El monitor, en versión instrumento (HQ y Operaciones) ---- */
.monitor.instrument { border-color: rgba(125, 244, 250, .10); }
.monitor.instrument .monitor-head { color: var(--ink-text-3); }
.monitor.instrument .mtile + .mtile { border-left-color: var(--ink-line-2); }
.monitor.instrument .mtile .k { color: var(--ink-text-3); }
.monitor.instrument .mtile .v { color: var(--ink-text); }
.monitor.instrument .mtile .v .u { color: var(--cyan-600); }
.monitor.instrument .mtile .s { color: var(--ink-text-2); }
.monitor.instrument .mtile .s.ok   { color: var(--ink-ok); }
.monitor.instrument .mtile .s.warn { color: var(--ink-warn); }
.monitor.instrument .mtile .s.crit { color: var(--ink-crit); }
.monitor.instrument .subject { color: var(--ink-text); }
.monitor.instrument .note { color: var(--ink-text-2); }
.monitor.instrument .note + .monitor-grid { border-top-color: var(--ink-line-2); }

/* ---- Barras dentro del instrumento ---- */
.instrument .bar { background: rgba(255, 255, 255, .09); }
.instrument .bar > i {
  background: linear-gradient(90deg, var(--cyan-700), var(--cyan));
  box-shadow: var(--glow-tight);
}
.instrument .bar.warn { background: rgba(242, 210, 135, .14); }
.instrument .bar.warn > i {
  background: linear-gradient(90deg, #C99A1E, var(--ink-warn));
  box-shadow: 0 0 16px -2px rgba(242, 210, 135, .5);
}

/* ---- Llenado en la entrada ----
   La barra sube desde cero cuando la tarjeta entra. Es la única animación
   decorativa del sistema que además significa algo: es la medición
   ocurriendo. Y termina — no hay brillos en bucle: un destello perpetuo en
   un tablero se convierte en ruido a los dos días. */
.bar > i,
.prog > i,
.mini > i { width: var(--w, 0%); }

html.motion .reveal .bar > i,
html.motion .reveal .prog > i,
html.motion .reveal .mini > i { width: 0; }

html.motion .reveal.is-in .bar > i,
html.motion .reveal.is-in .prog > i,
html.motion .reveal.is-in .mini > i {
  width: var(--w, 0%);
  transition: width var(--dur-5) var(--ease-expo) 140ms;
}

/* ==========================================================================
   17 · PROGRESIÓN DEL OPERADOR

   El operador es el único rol con mecánica de juego, y es a propósito: HQ y
   Operaciones ya tienen incentivo estructural —les pagan por esto—. El
   docente no. Su moneda sigue siendo el ciclo cerrado con evidencia, que es
   la métrica norte del producto: aquí no se inventa un XP paralelo que se
   pueda subir sin que pase nada en un salón.
   ========================================================================== */

/* ---- La tarjeta de rango, ahora instrumento ---- */
.rankcard.instrument .rankcard-top { padding: var(--s-5) var(--s-4) var(--s-4); }

.rankcard.instrument .dial::before { background: var(--ink-850); }
.rankcard.instrument .dial .insignia { stroke: var(--cyan); filter: drop-shadow(0 0 8px rgba(0, 249, 255, .45)); }
.rankcard.instrument .who .k { color: var(--ink-text-3); }
.rankcard.instrument .who .lvl { color: var(--ink-text); }
.rankcard.instrument .who .next { color: var(--ink-text-2); }
.rankcard.instrument .who .next b { color: var(--cyan); }

/* El anillo. `--pt` trae el objetivo y `--p` lo recorre: con @property el
   navegador puede interpolar una variable numérica, así que el arco se
   dibuja en vez de aparecer. */
@property --p {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
.rankcard .dial {
  background: conic-gradient(var(--cyan) calc(var(--p, 0) * 1%), rgba(255, 255, 255, .10) 0);
}
.rankcard.instrument .dial { box-shadow: 0 0 28px -6px rgba(0, 249, 255, .45); }

/* El estado por defecto es el ARCO COMPLETO, no el vacío: sin JS o con
   movimiento reducido el anillo tiene que llegar dibujado. Solo cuando la
   capa de movimiento está activa se parte de cero para recorrerlo. */
.rankcard .dial { --p: var(--pt, 0); }
html.motion .reveal .dial {
  --p: 0;
  transition: --p var(--dur-5) var(--ease-expo) 200ms;
}
html.motion .reveal.is-in .dial { --p: var(--pt, 0); }

/* ---- Escalera, en tinta oscura ---- */
.instrument .ladder .st .pip { background: rgba(255, 255, 255, .10); }
.instrument .ladder .st.done .pip { background: rgba(0, 249, 255, .42); }
.instrument .ladder .st.now  .pip { background: var(--cyan); box-shadow: var(--glow-tight); }
.instrument .ladder .st .lb { color: var(--ink-text-3); }
.instrument .ladder .st.now .lb { color: var(--cyan); font-weight: 750; }

/* ---- Requisitos ---- */
.instrument .needs { border-top-color: var(--ink-line-2); }
.instrument .needs .cap { color: var(--ink-text-3); }
.instrument .need .box { border-color: rgba(255, 255, 255, .22); }
.instrument .need .lb { color: var(--ink-text); }
.instrument .need .val { color: var(--ink-text-2); }
.instrument .need.is-done .box { background: var(--cyan); border-color: var(--cyan); color: var(--ink-900); box-shadow: var(--glow-tight); }
.instrument .need.is-done .lb { color: var(--ink-text-3); }
.instrument .need.is-done .val { color: var(--cyan-600); }

/* ---- Designación ---- */
.rankcard.instrument .desig {
  background: rgba(0, 249, 255, .07);
  border-top: 1px solid var(--ink-line-2);
}
.rankcard.instrument .desig .star { color: var(--cyan); filter: drop-shadow(0 0 6px rgba(0, 249, 255, .5)); }
.rankcard.instrument .desig .tx { color: var(--ink-text-2); }
.rankcard.instrument .desig .tx b { color: var(--ink-text); }

/* ---- Racha ----
   La mecánica de retención más eficaz que se ha construido, y aquí no es
   prestada: la consistencia semanal ES lo que el producto necesita medir.
   Siete semanas seguidas cerrando ciclo dicen más de una institución que
   cualquier encuesta de satisfacción. */
.streakbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-top: 1px solid var(--ink-line-2);
}
.streak {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-15);
  color: var(--cyan);
}
.streak .n {
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: 800;
  letter-spacing: var(--ls-h2);
  text-shadow: 0 0 18px rgba(0, 249, 255, .45);
}
.streak .lb {
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--ink-text-2);
  letter-spacing: 0;
}

.weeks { display: flex; gap: 4px; align-items: center; }
.weeks i {
  display: block;
  width: 8px; height: 14px;
  border-radius: 3px;
  background: rgba(255, 255, 255, .10);
}
.weeks i.on { background: var(--cyan); box-shadow: 0 0 10px -1px rgba(0, 249, 255, .7); }
/* La semana en curso no está ganada: va hueca y respira. Es el único
   elemento del sistema que se mueve en bucle, y por eso funciona. */
.weeks i.now {
  background: transparent;
  border: 1.5px solid var(--cyan);
  box-shadow: 0 0 10px -2px rgba(0, 249, 255, .6);
}
html.motion .weeks i.now { animation: breathe 2.6s var(--ease) infinite; }
@keyframes breathe {
  0%, 100% { opacity: .45; }
  50%      { opacity: 1; }
}

/* ---- Condecoraciones ----
   Insignias atadas a hechos verificables, no a horas de uso. Una medalla que
   se gana por abrir la app enseña a abrir la app. */
.badges {
  display: flex;
  gap: var(--s-3);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scroll-padding-inline: var(--s-4);
  margin: 0 calc(-1 * var(--s-4));
  padding: 2px var(--s-4);
  scrollbar-width: none;
}
.badges::-webkit-scrollbar { display: none; }

.badge {
  flex: none;
  width: 104px;
  text-align: center;
  scroll-snap-align: start;
  background: none;
}
.badge > * { display: block; width: 100%; }
.badge .medal {
  width: 62px; height: 62px;
  margin: 0 auto var(--s-2);
  border-radius: var(--r-lg);
  display: grid;
  place-items: center;
  background: linear-gradient(158deg, var(--brand-100), var(--brand-50));
  border: 1px solid var(--brand-200);
  color: var(--brand-700);
  transition: transform var(--dur-2) var(--ease-spring);
}
.badge:hover .medal { transform: translateY(-2px) scale(1.03); }
.badge .medal .i { width: 24px; height: 24px; stroke-width: 1.9; }
/* Altura fija en las dos líneas de texto: sin esto, una insignia de nombre
   corto y otra de nombre largo desalinean toda la fila y el carrusel se ve
   armado a mano. */
.badge .nm { font-size: var(--fs-xs); font-weight: 650; line-height: 1.25; min-height: 30px; }
.badge .st {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 27px;
  font-size: var(--fs-micro);
  color: var(--text-3);
  margin-top: 2px;
  line-height: 1.3;
}

.badge.is-locked .medal {
  background: var(--surface-sunk);
  border-color: var(--border);
  color: var(--n-300);
}
.badge.is-locked .nm { color: var(--text-3); font-weight: 600; }

/* La recién ganada trae el instrumento adentro: es el único lugar de la
   pantalla clara donde vuelve a aparecer el cian, y por eso se ve. */
.badge.is-new .medal {
  background: var(--mesh-ink);
  border-color: rgba(0, 249, 255, .34);
  color: var(--cyan);
  box-shadow: var(--glow-cyan), var(--edge-hi);
}
.badge.is-new .medal .i { filter: drop-shadow(0 0 6px rgba(0, 249, 255, .55)); }
.badge.is-new .st { color: var(--brand-600); font-weight: 700; }

/* ---- Objetivo del escuadrón ----
   Colectivo, nunca individual. Una tabla de posiciones entre docentes de un
   mismo colegio es la forma más rápida de que la sala de profesores decida
   que la herramienta es un instrumento de vigilancia. La meta compartida
   produce el efecto contrario: se empujan entre ellos. */
.squadgoal {
  background: linear-gradient(180deg, var(--surface), var(--n-25));
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-4);
  box-shadow: var(--sh-sm);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
.squadgoal-top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3); }
.squadgoal .ttl { font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 750; letter-spacing: -.006em; }
.squadgoal .cnt { font-family: var(--font-display); font-size: var(--fs-h3); font-weight: 800; color: var(--brand-600); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Segmentada y no continua: cada segmento es una persona, y eso hace que
   "faltan cuatro" sea una cara y no un porcentaje. */
.segs { display: flex; gap: 3px; }
.segs i {
  flex: 1;
  height: 12px;
  border-radius: 3px;
  background: var(--surface-mute);
  transition: background var(--dur-2) var(--ease);
}
.segs i.on { background: var(--brand-500); }
.segs i.me { background: var(--brand-800); box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.5px var(--brand-400); }
.squadgoal .note { font-size: var(--fs-xs); color: var(--text-2); line-height: 1.4; }
.squadgoal .note b { color: var(--text); font-weight: 700; }

/* ---- Subida de rango ----
   El momento de mayor estatus del producto. Va en la hoja, ocupando todo el
   ancho, y es la única vez que el instrumento aparece a página completa. */
.levelup {
  position: relative;
  isolation: isolate;
  margin-top: var(--s-4);
  padding: var(--s-6) var(--s-4) var(--s-5);
  border-radius: var(--r-xl);
  background: var(--mesh-ink);
  border: 1px solid rgba(0, 249, 255, .22);
  box-shadow: var(--sh-ink), var(--edge-hi);
  text-align: center;
  overflow: hidden;
}
.levelup::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--mesh-cyan);
}
.levelup .medal {
  width: 84px; height: 84px;
  margin: 0 auto var(--s-4);
  border-radius: var(--r-full);
  display: grid;
  place-items: center;
  background: rgba(0, 249, 255, .10);
  border: 1.5px solid rgba(0, 249, 255, .45);
  color: var(--cyan);
  box-shadow: 0 0 40px -8px rgba(0, 249, 255, .6), var(--edge-hi);
}
.levelup .medal svg { width: 40px; height: 40px; stroke: var(--cyan); fill: none; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
html.motion .levelup .medal { animation: rankpop var(--dur-4) var(--ease-spring) both; }
@keyframes rankpop {
  from { transform: scale(.6); opacity: 0; }
  to   { transform: none; opacity: 1; }
}
.levelup .k { font-size: var(--fs-micro); font-weight: 700; letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--cyan-600); }
.levelup .a {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 800;
  letter-spacing: var(--ls-h1);
  color: var(--ink-text);
  margin-top: var(--s-1);
}
.levelup .b { font-size: var(--fs-sm); color: var(--ink-text-2); line-height: 1.5; margin-top: var(--s-2); text-wrap: pretty; }
.levelup .earned {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-4);
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-full);
  background: rgba(0, 249, 255, .10);
  border: 1px solid rgba(0, 249, 255, .26);
  color: var(--cyan);
  font-size: var(--fs-xs);
  font-weight: 700;
}

/* ==========================================================================
   18 · MODO APLICACIÓN

   Instalada desde "Añadir a pantalla de inicio" (iOS) o "Instalar app"
   (Android), Itera deja de ser una página: no hay barra de direcciones, no
   hay pestañas y el sistema la trata como una app más. Este bloque se ocupa
   de que se comporte como tal.

   Lo que aquí NO hay, a propósito: `user-scalable=no`. Bloquear el zoom es
   el atajo clásico para que una web "se sienta nativa" y es una violación
   directa de WCAG 1.4.4 — en un producto para docentes de cincuenta años,
   quitarles el zoom es indefendible. Safari lo ignora desde hace años de
   todas formas.
   ========================================================================== */

/* Pantalla completa: sin marco ni escenario. Dos disparadores, un solo
   bloque — el teléfono en el navegador y la app instalada quieren lo mismo. */
@media (max-width: 520px),
       (display-mode: standalone),
       (display-mode: minimal-ui),
       (display-mode: fullscreen) {
  .stage {
    padding: 0;
    gap: 0;
    height: 100dvh;
    min-height: 0;
    /* El notch en horizontal. Arriba y abajo los resuelven la cabecera y la
       barra flotante, que ya leen sus propios insets. */
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
  }
  .frame {
    max-width: none;
    height: auto;
    max-height: none;
    flex: 1;
    min-height: 0;
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }
  .stage-foot { display: none; }
}

/* La cabecera reserva la barra de estado. Con `status-bar-style: default`
   el inset es 0 y esto no hace nada; queda declarado para que el día que se
   pase a pantalla completa no haya que acordarse. */
.topbar { padding-top: env(safe-area-inset-top); }

/* ---- Gestos y tacto ----
   Cada una de estas cuatro líneas quita un delator de "esto es una web". */
html, body {
  /* Mata el rebote elástico de la página y el "deslizar para recargar" de
     Chrome en Android, que en una app instalada se siente como un error. */
  overscroll-behavior: none;
}
body {
  -webkit-tap-highlight-color: transparent;
  /* Sin esto, el doble toque hace zoom y el navegador retrasa 300ms cada
     toque por si acaso. */
  touch-action: manipulation;
}
/* El menú de contexto al dejar el dedo sobre un control, y la selección de
   texto de una etiqueta, son el delator número uno. Los controles se
   comportan como controles; el texto de contenido se sigue pudiendo copiar. */
button,
a,
nav,
.topbar,
.tabbar,
.t-label,
.avatar,
.leader,
.badge,
.weeks,
.segs,
.ladder {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}
img { -webkit-touch-callout: none; }

/* ---- Aviso de instalación ----
   Android tiene API para pedir la instalación; iOS no tiene ninguna y hay
   que explicar el gesto. Se muestra una vez, se descarta para siempre y
   desaparece sola cuando la app ya está instalada. */
.installbar {
  position: absolute;
  left: var(--s-3);
  right: var(--s-3);
  bottom: calc(max(var(--s-3), env(safe-area-inset-bottom)) + 76px);
  z-index: 25;
  display: none;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-3) var(--s-3) var(--s-4);
  border-radius: var(--r-lg);
  background: var(--mesh-ink);
  border: 1px solid rgba(0, 249, 255, .20);
  box-shadow: var(--sh-ink), var(--edge-hi);
  color: var(--ink-text);
}
.installbar.is-on { display: flex; }
html.motion .installbar.is-on { animation: rise var(--dur-3) var(--ease-spring); }
.installbar .tx { flex: 1; min-width: 0; font-size: var(--fs-xs); line-height: 1.4; color: var(--ink-text-2); }
.installbar .tx b { display: block; font-size: var(--fs-sm); font-weight: 700; color: var(--ink-text); }
.installbar .go {
  flex: none;
  min-height: var(--tap);
  padding: 0 var(--s-4);
  border-radius: var(--r-sm);
  background: var(--cyan);
  color: var(--ink-900);
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: 800;
  display: grid;
  place-items: center;
}
.installbar .go:active { transform: scale(.97); }
/* `display: grid` le gana a [hidden] si no se dice lo contrario. */
.installbar .go[hidden] { display: none; }
.installbar .x {
  flex: none;
  width: var(--tap);
  height: var(--tap);
  display: grid;
  place-items: center;
  color: var(--ink-text-3);
  border-radius: var(--r-sm);
}
.installbar .x:hover { color: var(--ink-text); }

/* ==========================================================================
   19 · ARRANQUE

   La pantalla que ve el ícono al abrirse por primera vez. Es la única del
   producto que va oscura de borde a borde, y es el lugar donde eso
   corresponde: no hay dato que leer, solo marca e identidad.

   En los arranques siguientes no se ve. Una app no pregunta quién eres cada
   vez que la abres — el rol se recuerda y la redirección ocurre antes del
   primer pixel.
   ========================================================================== */

.launch-body {
  background: var(--ink-900);
  min-height: 100dvh;
}

.launch {
  position: relative;
  isolation: isolate;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--s-10);
  padding: calc(var(--s-10) + env(safe-area-inset-top))
           var(--s-5)
           calc(var(--s-8) + env(safe-area-inset-bottom));
  background: var(--mesh-ink);
  color: var(--ink-text);
  overflow: hidden;
}
.launch::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background: var(--mesh-cyan);
}
.launch::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: var(--grain);
  opacity: .38;
  mix-blend-mode: overlay;
}

.launch-head { text-align: center; }
/* El mismo recorte del aire horneado que en el riel superior. */
.launch-mark { height: 96px; width: auto; margin: -23px auto; }
.launch-kicker { color: var(--ink-text-3); margin-top: var(--s-6); }

.launch-body-wrap {
  width: 100%;
  max-width: 420px;
  margin: 0 auto;
}
.launch-q {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: 800;
  letter-spacing: var(--ls-h1);
  line-height: var(--lh-tight);
  text-align: center;
  margin-bottom: var(--s-5);
}

.rolelist { display: flex; flex-direction: column; gap: var(--s-3); }
.rolelist a {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 68px;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-lg);
  background: rgba(255, 255, 255, .05);
  border: 1px solid var(--ink-line-2);
  box-shadow: var(--edge-hi-soft);
  color: var(--ink-text);
  transition: border-color var(--dur-2) var(--ease), background var(--dur-2) var(--ease), transform var(--dur-1) var(--ease);
}
.rolelist a:hover { background: rgba(0, 249, 255, .08); border-color: rgba(0, 249, 255, .30); }
.rolelist a:active { transform: scale(.99); }
.rolelist .av {
  flex: none;
  width: 44px; height: 44px;
  border-radius: var(--r-full);
  display: grid; place-items: center;
  background: rgba(0, 249, 255, .12);
  border: 1px solid rgba(0, 249, 255, .26);
  color: var(--cyan);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: .02em;
}
.rolelist .who { flex: 1; min-width: 0; }
.rolelist .nm {
  display: block;
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: 750;
  line-height: 1.3;
  letter-spacing: -.006em;
}
.rolelist .rl { display: block; font-size: var(--fs-xs); color: var(--ink-text-2); margin-top: 2px; line-height: 1.35; }
.rolelist .go { color: var(--ink-text-3); }
.rolelist a:hover .go { color: var(--cyan); }

.launch-foot {
  margin-top: var(--s-6);
  text-align: center;
  font-size: var(--fs-xs);
  line-height: 1.55;
  color: var(--ink-text-3);
}
.launch-foot b { color: var(--ink-text-2); font-weight: 700; }
