/* ICA Reminders · hoja única. Primero los tokens de §9.6, después los componentes.
   Ningún valor de color, radio, espacio ni tamaño se escribe fuera del bloque :root, salvo el
   filete de 1 px. Tema claro únicamente: no hay bloque prefers-color-scheme.
   Dirección visual de Apple (decisión 2026-09-24). En computadora, una ventana de macOS (revisión
   del 2026-09-25): lienzo blanco, secciones separadas por filetes con el título a la izquierda,
   tablas a sangre con la cabecera translúcida fija y el programa como la lista de requisiciones de la
   obra: una fila por equipo, en secciones por estado de «Cambió de mes» a «Terminó su periodo», con
   una barra por los meses que trabaja del color de su banda (decisiones 2026-09-25 y 2026-09-27).
   Bajo 900 px, las listas agrupadas de iOS: tarjetas blancas sobre el lienzo gris. */

:root {
  /* color: contraste sobre #FFFFFF / sobre #F5F5F7 */
  --pri: #0071E3;            /* 4.70 / 4.31: relleno de botones; el texto blanco encima da 4.70 */
  --pri-texto: #0066CC;      /* 5.57 / 5.10: enlaces y texto azul */
  --pri-fuerte: #0058B0;     /* 6.95 / 6.37: botón primario pulsado y texto de botón gris */
  --texto: #1D1D1F;          /* 16.83 / 15.46 */
  --texto-2: #6E6E73;        /* 5.07 / 4.65 */
  --app: #F5F5F7;            /* lienzo de la página y meses ya pasados del programa */
  --superficie: #FFFFFF;
  --relleno: #E8E8ED;        /* control segmentado y botón gris; --pri-fuerte encima da 5.69 */
  --relleno-hover: #DEDEE3;  /* botón gris bajo el puntero: 5.17 */
  --flotante: rgb(255 255 255 / 86%);   /* barras y cabeceras translúcidas, con desenfoque detrás */
  --app-flotante: rgb(245 245 247 / 86%);
  --sep: #E5E5EA;            /* filetes */
  --sep-fuerte: #D2D2D7;     /* cambio de año en la cabecera del programa */
  --ctl: #86868B;            /* 3.63 / 3.33: borde de campo, objeto no textual (WCAG 1.4.11) */
  --seleccion: #B3D7FF;
  --foco: #0071E3;
  --ideal: #1E7E34;          /* 5.14 / 4.71 */
  --cerca: #C93400;          /* 5.29 / 4.85 */
  --fuera: #D70015;          /* 5.39 / 4.94 */
  --vencida: #A30012;        /* 8.19 / 7.51 */
  --sombra: 0 1px 2px rgb(0 0 0 / 4%), 0 4px 16px rgb(0 0 0 / 4%);
  --sombra-control: 0 1px 1px rgb(0 0 0 / 4%), 0 2px 6px rgb(0 0 0 / 12%);
  --desenfoque: saturate(180%) blur(20px);
  --radio-xs: 6px; --radio-s: 8px; --radio-m: 12px; --radio-l: 16px; --radio-capsula: 980px;
  --e1: 4px; --e2: 8px; --e3: 12px; --e4: 16px; --e5: 20px; --e6: 24px; --e8: 32px; --e12: 48px;
  --control: 48px;           /* objetivo táctil del teléfono: campos y botones */
  --control-compacto: 36px;  /* botones en computadora, control segmentado, cabecera de tabla */
  --campo: 40px;             /* campos en computadora */
  --alto-barra: 52px;        /* barra superior, fija arriba */
  --tope-fijo: var(--alto-barra); /* dónde se quedan fijas las cabeceras al desplazar; 0 donde la barra no es fija */
  /* La SF de Apple donde existe; Inter, su equivalente abierto, en Windows y Android. */
  --fuente: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Inter", "Segoe UI Variable Text", "Segoe UI", Arial, sans-serif;
  --t10: 10px; --t11: 11px; --t12: 12px; --t13: 13px; --t14: 14px; --t15: 15px; --t17: 17px; --t20: 20px; --t22: 22px; --t28: 28px; --t34: 34px;
  --interletra-titulo: -0.022em;
  --interletra-texto: -0.01em;
  --curva: cubic-bezier(0.2, 0.8, 0.2, 1);
  --duracion: 200ms;
}

@font-face { font-family: "Inter"; font-style: normal; font-weight: 400; font-display: swap; src: url("fuentes/inter-400.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 500; font-display: swap; src: url("fuentes/inter-500.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 600; font-display: swap; src: url("fuentes/inter-600.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-style: normal; font-weight: 700; font-display: swap; src: url("fuentes/inter-700.woff2") format("woff2"); }

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scrollbar-color: var(--sep-fuerte) var(--superficie); scrollbar-gutter: stable; scroll-padding-top: calc(var(--tope-fijo) + var(--e1)); }

/* El foco no queda debajo de lo fijo (WCAG 2.2, 2.4.11): al desplazarse hasta un elemento, sea con
   el tabulador o con un enlace a un campo, el navegador deja libre arriba la barra (--tope-fijo, 0
   donde no es fija), la cabecera fija de la página y el contorno del foco (--e1). Las cuentas repiten
   las de cada cabecera: el alto de la fila de la tabla, o el relleno, el renglón y el filete de la
   cabecera de sección. En Por pedir se suma la subcabecera del mes; la nota de la sección va en su
   misma línea y no añade altura. */
html:has(table.historial, table.proyectos, table.disponibles, table.reporte) { scroll-padding-top: calc(var(--tope-fijo) + var(--control-compacto) + var(--e1)); }
html:has(table.alertas) { scroll-padding-top: calc(var(--tope-fijo) + var(--control-compacto) + var(--e6) + var(--t17) * 1.5 + var(--e2) + 1px + var(--control-compacto) + var(--e1)); }
html:has(.gantt-meses) { scroll-padding-top: calc(var(--tope-fijo) + var(--alto-barra) + 1px + var(--e1)); }
html:has(.gantt-seccion) { scroll-padding-top: calc(var(--tope-fijo) + var(--alto-barra) + var(--e6) + var(--t17) * 1.35 + var(--e2) + 1px + var(--e1)); }
/* Una sección no va dentro de una tabla: al llegar por su ancla (#ubicaciones, #versiones, #marcar) no
   necesita la reserva de la cabecera de columna, que dejaba asomar bajo la barra, cortada, la cabecera
   fija de la tabla anterior (revisión del 2026-09-29). Queda bajo la barra, con la holgura del foco. */
html:has(table.historial, table.proyectos, table.disponibles, table.reporte) section[id] { scroll-margin-top: calc(var(--control-compacto) * -1); }

/* Texto de trabajo de 15 px en computadora, con el interletrado que Apple da a la SF a ese tamaño. */
body {
  margin: 0;
  background: var(--superficie);
  color: var(--texto);
  font: 400 var(--t15)/1.5 var(--fuente);
  letter-spacing: var(--interletra-texto);
  -webkit-font-smoothing: antialiased;
  caret-color: var(--pri);
}

::selection { background: var(--seleccion); }

a { color: var(--pri-texto); text-underline-offset: 0.2em; }

/* La escala tiene seis estilos (ronda de auditorías del 2026-09-25, P2-17): título grande 28/700,
   título 17/600, texto 15/400, texto destacado 15/600, secundario 13/400 y rótulo 12/500. Bajo 640 px
   el texto sube a 17 y el secundario a 15. Aparte, con su razón en DESIGN.md: el calendario del
   programa y la cabecera de sección en el color de su estado (17/700). La barra inferior usa el
   rótulo, 12/500 (ajuste del 2026-09-25). */
b, strong { font-weight: 600; }

/* Foco visible (§9.10). outline: none no se usa en ninguna parte. */
:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

.saltar {
  position: absolute;
  left: var(--e5);
  top: var(--e2);
  z-index: 20;
  transform: translateY(-200%);
  padding: var(--e2) var(--e3);
  background: var(--superficie);
  color: var(--pri-texto);
  border-radius: var(--radio-s);
}
.saltar:focus { transform: none; }

/* El programa con 19 meses necesita el ancho de la pantalla; el resto de la página también
   vive en esa columna. */
.ancho {
  max-width: 1720px;
  margin: 0 auto;
  padding-inline: var(--e8);
}

/* Barra superior (§2.1): material translúcido fijo arriba, como la barra de una ventana de
   macOS; el contenido pasa por debajo desenfocado. Sus destinos van solo con texto: los iconos se
   quedan en la barra inferior del teléfono (decisión 2026-09-22). */
.barra-superior {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--flotante);
  -webkit-backdrop-filter: var(--desenfoque);
  backdrop-filter: var(--desenfoque);
  border-bottom: 1px solid var(--sep);
}
.barra-superior .ancho { display: flex; align-items: center; gap: var(--e8); height: var(--alto-barra); }
.barra-superior nav, .destinos li { display: flex; }
.marca { font-size: var(--t17); font-weight: 600; letter-spacing: var(--interletra-titulo); color: var(--texto); white-space: nowrap; }
.destinos { display: flex; gap: var(--e1); list-style: none; margin: 0; padding: 0; }
.destino {
  display: flex;
  align-items: center;
  gap: var(--e2);
  color: var(--texto-2);
  font-size: var(--t13);
  font-weight: 400;
  text-decoration: none;
  transition: background-color var(--duracion) var(--curva), color var(--duracion) var(--curva);
}
.destino[aria-current] { color: var(--pri-texto); }
/* En la barra el destino es una cápsula; el actual lleva el relleno del control segmentado. */
.barra-superior .destino { height: calc(var(--e8) - var(--e1)); padding: 0 var(--e3); border-radius: var(--radio-capsula); }
.barra-superior .destino:hover { color: var(--texto); }
.barra-superior .destino[aria-current] { color: var(--texto); background: var(--relleno); }
/* Con los colores forzados de Windows el navegador quita el fondo y el destino actual quedaba igual a
   los demás. Lleva un contorno del color de la cápsula, que no se ve fuera de ese modo y que el
   navegador pinta en el color del texto. Sin especificidad: el foco sigue ganando. */
:where(.barra-superior .destino[aria-current]) { outline: 2px solid var(--relleno); outline-offset: -2px; }
.usuario { margin: 0 0 0 auto; display: flex; align-items: center; gap: var(--e3); min-width: 0; font-size: var(--t13); color: var(--texto-2); white-space: nowrap; }
/* El nombre lo escribe la persona, hasta 60 caracteres (2026-09-29). Si no cabe, se corta con puntos
   suspensivos: los destinos y los enlaces de la cuenta no ceden y la barra no se desborda. */
.usuario .quien { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.usuario a, .barra-superior nav { flex: none; }
.usuario a, .pie-usuario a { text-decoration: none; }
.usuario a:hover { text-decoration: underline; }
/* En el teléfono «Cambiar de usuario» va al pie de cada página, sobre la barra inferior, y la cabecera
   se queda con la marca y el nombre (decisión 2026-09-25, fila 637 de CONTEXTO). Arriba de 900 px
   sigue en la barra superior y el pie no se dibuja. */
.pie-usuario { display: none; }
.pie-usuario a + a { margin-left: var(--e6); }

/* Barra inferior del teléfono (§9.8), como la barra de pestañas de iOS. Es la única con iconos.
   Arriba de 900 px no se dibuja. */
.barra-inferior { display: none; }
.barra-inferior .destino svg { width: var(--e6); height: var(--e6); }


/* El contenido mide su propio ancho: Alertas cambia de forma por él, no por la ventana. */
main { display: block; padding: var(--e8) 0 var(--e12); container: principal / inline-size; }

/* Migas, título grande y línea de contexto (§2.3) */
.migas { font-size: var(--t13); color: var(--texto-2); margin: 0 0 var(--e2); }
.migas a { text-decoration: none; }
.migas a:hover { text-decoration: underline; }
/* Título de 28 en 700, como el Title 1 de Apple. Sin interletrado negativo: los nombres del PUM
   llegan en mayúsculas y, apretados, se leen como un bloque; la SF a ese tamaño lo lleva positivo. */
h1 { font-size: var(--t28); font-weight: 700; line-height: 1.15; letter-spacing: 0; margin: 0; }
/* Un código con guion («WA-380») baja entero al renglón siguiente; el navegador lo partía en el guion.
   Si no cabe solo en un renglón, se parte dentro de su pieza. */
h1 .codigo { display: inline-block; max-width: 100%; }
h2 { font-size: var(--t17); font-weight: 600; line-height: 1.35; letter-spacing: var(--interletra-titulo); margin: var(--e8) 0 var(--e3); }
.contexto { color: var(--texto-2); font-size: var(--t15); margin: var(--e2) 0 0; }

/* Aviso de resultado (§9.9): un recuadro gris sobre el lienzo blanco, con el icono en azul y la
   acción a la derecha. Sin franja de color al costado. En el teléfono, blanco sobre el gris. */
.aviso {
  display: flex;
  align-items: center;
  gap: var(--e3);
  max-width: calc(var(--control) * 18);
  margin: var(--e5) 0 0;
  padding: var(--e3) var(--e4);
  background: var(--app);
  border-radius: var(--radio-m);
}
.aviso svg { width: var(--e5); height: var(--e5); flex: none; color: var(--pri); }
.aviso a { margin-left: auto; text-decoration: none; }
/* Con dos acciones, la primera lleva el margen que las empuja a la derecha y la segunda la sigue. */
.aviso a + a { margin-left: 0; }
/* El error de un campo rechazado: el icono en el rojo de «Fuera del mínimo» y el texto del error es
   el enlace al campo, subrayado dentro de la frase. */
.aviso.con-error svg { color: var(--fuera); }
.aviso.con-error a { margin-left: 0; text-decoration: underline; }
/* Con varios campos rechazados, la frase y la lista de enlaces; el icono, a la altura de la frase. */
.aviso.varios { align-items: flex-start; }
.aviso.varios svg { margin-top: calc((1lh - var(--e5)) / 2); }
.aviso .errores p { margin: 0; }
.aviso .errores ul { margin: var(--e1) 0 0; padding-left: var(--e5); }
/* El aviso que va dentro de una sección, encima de su tabla («Versiones del programa»), no se pega a ella:
   quedaba a 0 px y en el teléfono tocaba el filete del primer renglón (revisión del 2026-09-29). */
.caja > .aviso + table { margin-top: var(--e3); }

/* Sección de una página de detalle, como la página de la cuenta de Apple: separada de la anterior
   por un filete y al ancho de la página. Si abre con su título, el título va a la izquierda y el
   contenido a la derecha; el título abarca las filas que ocupe el contenido y las vacías miden
   cero. Bajo 900 px vuelve a ser la tarjeta blanca de Ajustes de iOS. */
.caja { padding: var(--e6) 0; border-top: 1px solid var(--sep); }
.caja:has(> h2:first-child) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 3fr);
  column-gap: var(--e8);
  align-items: start;
}
.caja:has(> h2:first-child) > * { grid-column: 2; }
.caja > h2:first-child { grid-column: 1; grid-row: 1 / span 40; margin: 0; font-size: var(--t17); line-height: 1.35; }
.caja.carga:has(> h2:first-child) { display: block; }
.caja.carga > h2:first-child { margin-bottom: var(--e3); }
.caja > h2:first-child + * { margin-top: 0; }
.caja > :last-child { margin-bottom: 0; }
/* Una retícula por pantalla (ronda de auditorías del 2026-09-25, P1-18). La tabla de una sección sale
   del margen lo que mide el relleno de sus celdas, como la de Por pedir: su texto arranca en la
   columna de contenido y no 12 px a la derecha. Una sección con formulario limita su contenido a
   576 px, salvo las tablas, que toman la columna entera. */
.caja table { width: calc(100% + var(--e6)); margin-inline: calc(var(--e3) * -1); }
.caja table > caption { padding-inline: var(--e3); }
.caja:not(.carga):has(> h2:first-child):has(form) > :not(h2, table, :has(table)) { max-width: calc(var(--control) * 12); }
.cabecera-pagina + .caja, .cabecera-pagina + .aviso + .caja { margin-top: var(--e6); }
/* Un formulario de varias secciones («Añadir pedido») las abre como si fueran de la página. */
.cabecera-pagina + form > .caja:first-child { margin-top: var(--e6); }
.aviso + form > .caja:first-child { margin-top: var(--e5); }
/* La confirmación es una hoja de macOS: flota sobre el blanco con su borde y su sombra. */
.caja.confirmacion { padding: var(--e6); border: 1px solid var(--sep); border-radius: var(--radio-l); box-shadow: var(--sombra); }
/* Los destinatarios en la confirmación del correo enviado: una dirección por renglón, con su filete. */
.lista-correos { margin: 0 0 var(--e3); padding: 0; list-style: none; }
.lista-correos li { padding: var(--e2) 0; border-top: 1px solid var(--sep); overflow-wrap: anywhere; }
.lista-correos li:first-child { border-top: 0; }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.hueco { stroke: var(--superficie); }

/* Estados (§9.7): palabra, icono y color de texto. Nunca pastilla ni fondo. */
/* La palabra da la línea base, así el texto que sigue queda alineado con ella; el icono se
   centra en la altura de la palabra. */
.estado { display: inline-flex; align-items: baseline; gap: var(--e1); font-weight: 600; }
.estado svg { align-self: center; width: var(--e4); height: var(--e4); flex: none; }
.e-vencida { color: var(--vencida); }
.e-fuera { color: var(--fuera); }
.e-cerca { color: var(--cerca); }
.e-ideal { color: var(--ideal); }
.e-resuelto { color: var(--texto); }
.e-sin-alerta { color: var(--texto-2); }
.e-sin-evidencia { color: var(--texto); }

/* Tablas (§9.9): sobre el blanco, con filetes horizontales y la cabecera de columna en gris sin
   mayúsculas. Los datos del PUM llegan en mayúsculas: en las celdas van sin interletrado negativo. */
table {
  width: 100%;
  background: none;
  border-collapse: collapse;
  border-spacing: 0;
}
caption { text-align: left; color: var(--texto-2); padding: 0 0 var(--e2); }
th, td { padding: calc(var(--e2) + 2px) var(--e3); text-align: left; vertical-align: top; }
tbody th, tbody td { letter-spacing: 0; }
thead th { font-size: var(--t12); font-weight: 500; color: var(--texto-2); letter-spacing: 0; }
tbody + tbody th[scope="colgroup"] { border-top: 1px solid var(--sep); }
th[scope="colgroup"] { background: var(--app); font-size: var(--t15); font-weight: 600; color: var(--texto); }
tbody tr + tr > * { border-top: 1px solid var(--sep); }
.num { font-variant-numeric: tabular-nums; }
tbody a:not(.boton) { text-decoration: none; }
tbody a:not(.boton):hover { text-decoration: underline; }
table.historial { border-collapse: separate; border-spacing: 0; }
table.historial thead th {
  position: sticky;
  top: var(--tope-fijo);
  z-index: 1;
  height: var(--control-compacto);
  padding-block: 0;
  vertical-align: middle;
  background: var(--flotante);
  -webkit-backdrop-filter: var(--desenfoque);
  backdrop-filter: var(--desenfoque);
  border-bottom: 1px solid var(--sep);
  white-space: nowrap;
}
/* Un desplegable dentro de una celda no lleva el margen de los de la página. */
td > details { margin: 0; }
/* Fechas y cantidades no se parten: el estado, que es texto, se queda con el ancho que sobra. */
table.historial td.num { white-space: nowrap; }

/* Alertas en computadora (decisión 2026-09-24), como una lista de Recordatorios de macOS: la
   cabecera de columna, translúcida, y la de cada sección se quedan fijas al desplazar; los
   renglones van sobre el blanco, de 44 px, con el filete desde el texto. La tabla sale del margen
   lo que mide su relleno, así el texto de la primera columna se alinea con el título.
   Las columnas son fijas (ronda de auditorías del 2026-09-25, P1-3): la tabla mide su contenedor y
   ninguna celda la ensancha. La descripción toma lo que sobra; lo largo se parte en su celda. Los
   anchos salen de los datos reales del 25 sep, más el relleno de la celda: la palabra de estado más
   ancha, «Cerca del mínimo» (107 px en Inter) con su icono (20 px), el proyecto más largo (171 px), la marca y
   el modelo usuales (136 y 144 px), el número económico (108 px) y «Marcar requisición» (140 px). La
   acción solo se ensancha si hay que marcar. */
table.alertas { width: calc(100% + var(--e6)); margin-inline: calc(var(--e3) * -1); background: none; border-collapse: separate; border-spacing: 0; table-layout: fixed; }
table.alertas col.k-estado { width: calc(var(--e8) * 5); }
table.alertas col.k-dias, table.alertas col.k-mes { width: 0; }
table.alertas col.k-proyecto { width: calc(var(--control) * 4 + var(--e2)); }
table.alertas col.k-grupo { width: calc(var(--e12) + var(--e4)); }
table.alertas col.k-marca, table.alertas col.k-modelo { width: calc(var(--e8) * 5); }
table.alertas col.k-num { width: calc(var(--e8) * 4 + var(--e1)); }
table.alertas col.k-accion { width: calc(var(--e8) + var(--e6)); }
table.alertas:has(.c-accion .boton.pri) col.k-accion { width: calc(var(--control) * 3 + var(--e6)); }
/* Días y mes los dice la subcabecera del mes (P1-13): en el renglón siguen para los lectores de
   pantalla y su columna mide cero. No se quitan con display: none: las
   celdas siguientes se correrían a la columna de la izquierda. */
table.alertas thead th:nth-child(2), table.alertas thead th:nth-child(3), table.alertas tr.renglon > td.c-dias, table.alertas tr.renglon > td.c-mes { padding: 0; font-size: 0; }
table.alertas thead th {
  position: sticky;
  top: var(--tope-fijo);
  z-index: 3;
  height: var(--control-compacto);
  padding: 0 var(--e3);
  background: var(--flotante);
  -webkit-backdrop-filter: var(--desenfoque);
  backdrop-filter: var(--desenfoque);
  vertical-align: middle;
  border-bottom: 1px solid var(--sep);
  white-space: nowrap;
}
/* La sección se queda fija debajo de la cabecera de columna mientras sus renglones pasan; la
   siguiente la tapa al llegar. Nombra el estado de sus renglones, que también lo dicen. */
table.alertas tr.seccion th {
  position: sticky;
  top: calc(var(--tope-fijo) + var(--control-compacto));
  z-index: 2;
  padding: var(--e6) var(--e3) var(--e2);
  background: var(--superficie);
  border: 0;
  border-bottom: 1px solid var(--sep);
  vertical-align: middle;
}
table.alertas tbody:first-of-type tr.seccion th { padding-top: var(--e4); }
table.alertas tr.seccion .estado { gap: var(--e2); font-size: var(--t17); font-weight: 700; letter-spacing: 0; }
table.alertas tr.seccion .estado svg { width: var(--e5); height: var(--e5); }
table.alertas tr.seccion .cuantos { margin-left: var(--e2); font-size: var(--t15); font-weight: 400; color: var(--texto-2); font-variant-numeric: tabular-nums; }
table.alertas tr.seccion .estado, table.alertas tr.seccion .cuantos, table.alertas tr.seccion .nota-seccion { vertical-align: middle; }
/* La nota de una sección dice qué significa o qué hacer con ella (P1-14); en gris y en la misma línea:
   las celdas fijas se quedan dentro de la tabla entera, no de su sección, así que todas las
   cabeceras de sección miden lo mismo y la subcabecera de un mes nunca asoma bajo la siguiente. */
table.alertas tr.seccion .nota-seccion { margin-left: var(--e4); font-size: var(--t13); font-weight: 400; color: var(--texto-2); }
table.alertas tbody + tbody tr.seccion > * { border-top: 0; }
/* La subcabecera del mes (P1-13), fija justo debajo de la de su sección: el mes, los días y cuántos
   renglones lleva. La primera sección abre con menos aire arriba y su subcabecera sube con ella. */
table.alertas tr.subseccion th {
  position: sticky;
  top: calc(var(--tope-fijo) + var(--control-compacto) + var(--e6) + var(--t17) * 1.5 + var(--e2) + 1px);
  z-index: 2;
  height: var(--control-compacto);
  padding: 0 var(--e3);
  background: var(--superficie);
  border: 0;
  border-bottom: 1px solid var(--sep);
  font-size: var(--t15);
  font-weight: 400;
  color: var(--texto-2);
  vertical-align: middle;
}
table.alertas tbody:first-of-type tr.subseccion th { top: calc(var(--tope-fijo) + var(--control-compacto) + var(--e4) + var(--t17) * 1.5 + var(--e2) + 1px); }
table.alertas tr.subseccion .mes-grupo { font-weight: 600; color: var(--texto); }
table.alertas tr.subseccion .cuantos { margin-left: var(--e2); font-size: var(--t13); font-weight: 400; font-variant-numeric: tabular-nums; }
table.alertas tr.renglon > td {
  height: calc(var(--e8) + var(--e3));
  padding: var(--e1) var(--e3);
  border-top: 1px solid var(--sep);
  line-height: 1.35;
  vertical-align: middle;
  overflow-wrap: break-word;
  transition: background-color var(--duracion) var(--curva);
}
table.alertas tr.subseccion + tr.renglon > td { border-top: 0; }
/* El filete arranca donde empieza el texto, como en las listas de Apple. */
table.alertas tr.renglon + tr.renglon > td:first-child { position: relative; border-top: 0; }
table.alertas tr.renglon + tr.renglon > td:first-child::before { content: ""; position: absolute; top: 0; left: var(--e3); right: 0; height: 1px; background: var(--sep); }
table.alertas tr.renglon > td:last-child { text-align: right; }
/* La descripción se parte en las líneas que necesite (P2-9): cortada con puntos suspensivos perdía
   texto con el espaciado de WCAG 1.4.12. */
table.alertas .c-desc a { display: block; }
/* El renglón entero abre el detalle (P1-19): el enlace de la descripción se estira sobre él, sin
   JavaScript. El proyecto y los botones quedan encima y se pulsan aparte; las cabeceras fijas, en
   el 2 y el 3, siguen por encima de todo. */
table.alertas tr.renglon { position: relative; }
table.alertas .c-desc a::after { content: ""; position: absolute; inset: 0; }
table.alertas .c-proyecto a, table.alertas .c-accion .boton { position: relative; z-index: 1; }
table.alertas tr.renglon:hover > td { background: var(--app); }
/* El renglón dice su estado con palabra, icono y color, como la fila del programa (decisión del
   2026-09-27, fila 665): 400 de 13 px, como el estado de un pedido en Disponibles. La cabecera de la
   sección lo sigue nombrando. Bajo 1100 px de contenido la palabra se parte en dos líneas dentro de
   los 44 px del renglón. */
table.alertas tr.renglon > td.c-estado { white-space: normal; }
table.alertas tr.renglon .estado { font-size: var(--t13); font-weight: 400; align-items: center; vertical-align: middle; }
table.alertas tr.renglon .estado svg { width: var(--e4); height: var(--e4); }
/* «Abrir» es el chevrón gris de una lista de Apple: el nombre accesible no cambia y la descripción
   también lleva al detalle. */
table.alertas .c-accion .boton.texto { width: var(--e8); height: var(--e8); padding: 0; justify-content: center; font-size: 0; color: var(--ctl); }
table.alertas .c-accion .boton.texto:hover { color: var(--pri-texto); text-decoration: none; }
/* «Marcar requisición» dentro de la lista es una cápsula gris con texto azul, como «Obtener» en
   la App Store: la acción se ve sin gritar entre 175 renglones. */
table.alertas .boton.pri { height: calc(var(--e8) - var(--e1)); padding: 0 var(--e3); background: var(--relleno); color: var(--pri-fuerte); font-size: var(--t13); }
table.alertas .boton.pri:hover { background: var(--relleno-hover); }
/* El renglón que se marca desde la lista no repite el chevrón junto a su botón: el renglón ya abre. */
table.alertas .c-accion .boton.pri + .boton.texto { display: none; }

/* Proyectos, la entrada (definición funcional del 2026-09-24, §7; rediseño del 2026-09-25, fila 647
   de CONTEXTO): contesta primero qué pedir y en qué obra. Arriba, los totales de todas las obras en
   el color de su estado, separados por filetes y sin tarjetas; debajo, la tabla de obras con la
   cabecera fija, lo que falta por pedir y un mini programa de sus meses en el color del semáforo. */
.totales-obras { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); margin: var(--e6) 0 0; padding: 0; list-style: none; border-top: 1px solid var(--sep); border-bottom: 1px solid var(--sep); }
.totales-obras > li + li { border-left: 1px solid var(--sep); }
.totales-obras a, .totales-obras .sin-enlace { display: flex; flex-direction: column; gap: var(--e1); height: 100%; padding: var(--e4) var(--e5); color: inherit; text-decoration: none; transition: background-color var(--duracion) var(--curva); }
.totales-obras a:hover { background: var(--app); }
.totales-obras .valor { display: flex; align-items: center; gap: var(--e2); font-size: var(--t28); font-weight: 600; line-height: 1.1; letter-spacing: var(--interletra-titulo); font-variant-numeric: tabular-nums; }
.totales-obras .valor svg { flex: none; width: var(--e5); height: var(--e5); }
.totales-obras .rotulo { font-size: var(--t13); color: var(--texto-2); }
.totales-obras a:hover .rotulo { color: var(--texto); text-decoration: underline; }
/* Un total en cero no es noticia: gris, sin enlace. */
.totales-obras > .cero { color: var(--texto-2); }
table.proyectos { width: calc(100% + var(--e6)); margin: var(--e5) calc(var(--e3) * -1) 0; background: none; border-collapse: separate; border-spacing: 0; }
table.proyectos thead th {
  position: sticky;
  top: var(--tope-fijo);
  z-index: 3;
  height: var(--control-compacto);
  padding: 0 var(--e3);
  background: var(--flotante);
  -webkit-backdrop-filter: var(--desenfoque);
  backdrop-filter: var(--desenfoque);
  vertical-align: middle;
  border-bottom: 1px solid var(--sep);
  white-space: nowrap;
}
table.proyectos thead th.num { width: 1%; padding-left: var(--e5); text-align: right; }
/* El mini programa toma casi la mitad de la tabla: sus meses son la lectura rápida de la obra. */
table.proyectos thead th.c-meses, table.proyectos td.c-meses { width: 44%; padding-inline: var(--e5); }
/* Un ritmo fijo (ronda de auditorías del 2026-09-25, P2-20): toda fila mide dos líneas, la cifra de
   17 px y la nota de 13 px debajo, tenga nota o no. Las celdas de texto se alinean por la línea base
   de su primera línea y el mini programa va al centro de la fila. Con todas al centro, las cifras de
   una línea quedaban 10 px por debajo del nombre y, en una fila con dos líneas de urgencia, la cifra
   por pedir 9 px por encima (revisión del 2026-09-26). */
table.proyectos tbody > tr > * { height: calc(var(--e3) * 2 + var(--t17) * 1.35 + var(--t13) * 1.35 + var(--e1)); padding: var(--e3); background: none; border-top: 0; line-height: 1.35; vertical-align: baseline; transition: background-color var(--duracion) var(--curva); }
table.proyectos tbody > tr > td.c-meses { vertical-align: middle; }
/* La fila entera abre el programa (P1-19): el enlace del nombre se estira sobre ella; la cifra por
   pedir, que lleva a Por pedir, queda encima. */
table.proyectos tbody > tr { position: relative; }
table.proyectos .c-proyecto > a::after { content: ""; position: absolute; inset: 0; }
table.proyectos tbody > tr + tr > * { border-top: 1px solid var(--sep); }
table.proyectos tbody > tr:last-child > * { border-bottom: 1px solid var(--sep); }
table.proyectos tbody > tr:hover > * { background: var(--app); }
table.proyectos .c-proyecto { font-size: var(--t15); font-weight: 600; white-space: nowrap; }
table.proyectos .c-proyecto a { color: var(--texto); text-decoration: none; }
table.proyectos .c-proyecto a:hover { color: var(--pri-texto); }
table.proyectos td.num { padding-left: var(--e5); font-size: var(--t15); font-weight: 400; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Lo que falta por pedir es la cifra que se busca: 17/600, como un título de fila. */
table.proyectos td.c-por-pedir:not(.cero) { font-size: var(--t17); font-weight: 600; }
/* Un cero no es noticia: va en el gris secundario y deja ver las cifras que importan. */
table.proyectos td.cero { font-weight: 400; color: var(--texto-2); }
/* El resumen es del teléfono; en la computadora las cifras van en sus columnas. */
table.proyectos .resumen { display: none; }
/* La cifra mide al menos 24 px de ancho (WCAG 2.2, 2.5.8): con un dígito medía 11 y el renglón, que
   abre el programa, la rodea. Alineada a la derecha, como las demás cifras. */
table.proyectos td.num > a { color: var(--pri-texto); text-decoration: none; position: relative; z-index: 1; min-inline-size: var(--e6); text-align: end; }
table.proyectos td.num > a:hover { text-decoration: underline; }
/* El proyecto de Por pedir y la cifra de Proyectos quedan encima de un renglón que abre otra página:
   su objetivo mide 24 px de alto sin mover la línea (WCAG 2.2, 2.5.8; medían 19 y 20 px). Va antes de
   la lista del teléfono, que sube el proyecto a 48 px con la misma especificidad. */
table.alertas .c-proyecto a, table.proyectos td.num > a { display: inline-block; padding-block: calc((var(--e6) - 1lh) / 2); margin-block: calc((var(--e6) - 1lh) / -2); }
table.proyectos .urgencia { display: flex; justify-content: flex-end; margin-top: 2px; font-size: var(--t13); font-weight: 400; white-space: nowrap; }
/* Los equipos de la obra sin evidencia de llegada (decisión 2026-09-27): en su propia línea bajo el PUM,
   con la palabra, el icono y el color del estado, y por encima de la capa del nombre, que cubre la celda. */
table.proyectos .sin-evidencia-obra { position: relative; z-index: 1; display: flex; align-items: baseline; gap: var(--e1); width: fit-content; margin-top: 2px; font-size: var(--t13); font-weight: 600; text-decoration: none; }
table.proyectos .sin-evidencia-obra svg { flex: none; align-self: center; width: var(--e4); height: var(--e4); }
table.proyectos .sin-evidencia-obra:hover { text-decoration: underline; }
/* Lo que terminó su periodo y falta liberar: una línea más bajo el nombre, sin enlace propio (la fila
   abre el programa), con el icono y el color de texto de la sección. */
table.proyectos .termino-obra { display: flex; align-items: baseline; gap: var(--e1); width: fit-content; margin-top: 2px; font-size: var(--t13); font-weight: 600; }
table.proyectos .termino-obra svg { flex: none; align-self: center; width: var(--e4); height: var(--e4); }
/* Mide 17.5 px de alto dentro de un renglón que abre el programa sin filtrar: una capa centrada le da
   24 px sin mover la línea (WCAG 2.2, 2.5.8), 48 en el teléfono. */
table.proyectos .sin-evidencia-obra::before { content: ""; position: absolute; inset: calc((100% - var(--e6)) / 2) 0; }
table.proyectos .nota, .lista-cerrados .nota { display: block; margin-top: 2px; font-size: var(--t13); font-weight: 400; color: var(--texto-2); }
/* El mini programa: un mes por columna, de mínimo cero, como la línea de tiempo del programa. Cada
   mes dice cuántos equipos hay que pedir, en el color de la barra de su estado; sin nada por pedir,
   los programados en gris y lo pedido o ya en el proyecto en azul; un mes sin equipos queda como una
   casilla del lienzo. El cambio de año deja un respiro y el mes en curso lleva la raya de hoy. No es
   enlace: la fila abre el programa. */
.eje-obras, .mini { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); column-gap: 2px; container-type: inline-size; }
.eje-obras { font-size: var(--t12); font-weight: 500; color: var(--texto-2); text-align: center; }
.eje-obras > .actual { color: var(--texto); font-weight: 600; }
.eje-obras > .con-anio, .mini > .con-anio { margin-left: var(--e1); }
.mini > span { position: relative; display: flex; align-items: center; justify-content: center; min-width: 0; height: var(--e6); overflow: hidden; background: var(--app); border-radius: var(--radio-xs); color: var(--superficie); font-size: var(--t12); font-weight: 600; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
table.proyectos tbody > tr:hover .mini > span:not([class*="b-"]) { background: var(--relleno); }
.mini > .b-fuera { background: var(--fuera); }
.mini > .b-vencida { background: var(--vencida); }
.mini > .b-cerca { background: var(--cerca); }
.mini > .b-ideal { background: var(--ideal); }
.mini > .b-resuelto { background: var(--pri); }
.mini > .b-programada { background: var(--relleno); border: 1px solid var(--ctl); color: var(--texto); }
/* Con meses estrechos el número no cabe: la casilla queda en su color y el eje pasa a iniciales. */
@container (max-width: 520px) {
  .eje-obras .mes-largo { display: none; }
  .eje-obras .mes-corto { display: inline; }
  .mini > span { font-size: 0; }
}
/* El umbral de 520 px es para 19 meses. Una carga con otro horizonte alarga el eje común (a 24 meses
   con TCX): los rótulos se montaban y la cifra de tres dígitos se cortaba en casillas de 21 px. Con 20
   meses o más el cambio llega a 660 px: con 24 son los mismos 27 px por mes que 520 px con 19; con 20
   a 23 el corte llega antes, hasta 33 px por mes. Un eje de más de 24 meses pediría otro escalón. */
@container (max-width: 660px) {
  .eje-obras:has(> :nth-child(20)) .mes-largo { display: none; }
  .eje-obras:has(> :nth-child(20)) .mes-corto { display: inline; }
  .mini:has(> :nth-child(20)) > span { font-size: 0; }
}
.apartado { margin: var(--e12) 0 var(--e2); font-size: var(--t17); font-weight: 600; letter-spacing: var(--interletra-titulo); }
.lista-cerrados { margin: 0 calc(var(--e3) * -1); padding: 0; list-style: none; border-top: 1px solid var(--sep); border-bottom: 1px solid var(--sep); }
/* El renglón entero abre el programa del cerrado (P1-11), como en los activos. */
.lista-cerrados li { position: relative; padding: var(--e3); transition: background-color var(--duracion) var(--curva); }
.lista-cerrados li:hover { background: var(--app); }
.lista-cerrados li + li { border-top: 1px solid var(--sep); }
.lista-cerrados a { font-weight: 600; color: var(--texto); text-decoration: none; }
.lista-cerrados a::after { content: ""; position: absolute; inset: 0; }
.lista-cerrados a:hover { color: var(--pri-texto); }
.c-dias { font-variant-numeric: tabular-nums; }
.c-num { font-variant-numeric: tabular-nums; }
.c-desc a { color: var(--texto); font-weight: 600; text-decoration: none; }
.c-desc a:hover { text-decoration: underline; }
/* Marca, modelo y mes son datos, no notas: van en el color del texto. El grupo, en gris. El
   proyecto es una columna y enlaza al programa (decisión 2026-09-24). Su columna mide lo que el
   nombre más largo de los datos reales; uno más largo se parte en lugar de desbordar (P1-3). */
.c-grupo { color: var(--texto-2); font-size: var(--t13); font-variant-numeric: tabular-nums; }
.c-proyecto a { color: inherit; text-decoration: none; }
.c-proyecto a:hover { color: var(--pri-texto); text-decoration: underline; }

/* Pestañas (§9.9): enlaces, no tablist, dibujados como el control segmentado de Apple. El conteo
   va en gris al lado del rótulo, en cifras tabulares para que no baile. En computadora van a la
   izquierda y el filtro a la derecha, con los pies alineados. */
main:has(> .pestanas) { display: flex; flex-wrap: wrap; align-items: flex-end; }
main:has(> .pestanas) > * { flex: 1 1 100%; }
main:has(> .pestanas) > .pestanas { flex: 0 0 auto; margin: var(--e6) 0 var(--e4); }
main:has(> .pestanas) > .filtros { flex: 0 0 auto; margin: var(--e6) 0 var(--e4) auto; }
main:has(> .pestanas) > .filtros > .filtro { margin: 0; }
.pestanas {
  display: flex;
  gap: 0;
  align-items: stretch;
  width: fit-content;
  height: var(--control-compacto);
  padding: 2px;
  margin: var(--e6) 0 var(--e4);
  background: var(--relleno);
  border-radius: var(--radio-s);
}
.pestana {
  display: inline-flex;
  align-items: center;
  gap: var(--e2);
  padding: 0 var(--e4);
  border-radius: var(--radio-xs);
  font-size: var(--t13);
  color: var(--texto);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--duracion) var(--curva);
}
.pestana:hover { background: var(--relleno-hover); }
.pestana[aria-current] { background: var(--superficie); box-shadow: var(--sombra-control); }
/* Con los colores forzados también se va la sombra: la pestaña elegida lleva el contorno del color de
   su fondo, como el destino actual de la barra superior. */
:where(.pestana[aria-current]) { outline: 2px solid var(--superficie); outline-offset: -2px; }
.conteo { color: var(--texto-2); font-variant-numeric: tabular-nums; }
/* Sobre el gris del segmento no elegido, el gris secundario da 4.15: el conteo va en el texto, más ligero. */
.pestana:not([aria-current]) .conteo { color: var(--texto); }
.pestanas-telefono { display: none; }

/* Campos (§9.9). El alto y el ancho son del campo de texto y del select: un campo de
   opción o una casilla estirados a 100% ocupaban el ancho de la página entera. La regla va sin
   especificidad (:where): con sus dos :not() ganaba a «.campo input» del teléfono, y los campos de
   texto se quedaban en 40 px con letra de 15 (ronda de auditorías del 2026-09-25, P1-9). */
.campo { max-width: calc(var(--control) * 8); margin: var(--e4) 0; }
label { display: block; font-size: var(--t12); font-weight: 500; margin-bottom: var(--e1); }
:where(input:not([type="radio"]):not([type="checkbox"])), select, textarea {
  width: 100%;
  height: var(--campo);
  padding: 0 var(--e3);
  font: 400 var(--t15)/1.5 var(--fuente);
  letter-spacing: var(--interletra-texto);
  color: var(--texto);
  background: var(--superficie);
  border: 1px solid var(--ctl);
  border-radius: var(--radio-s);
  transition: border-color var(--duracion) var(--curva);
}
/* El select es un botón emergente de Apple: sin la flecha del sistema, con las dos puntas. */
select {
  appearance: none;
  padding-right: var(--e8);
  background: var(--superficie) url("selector.svg") no-repeat right var(--e3) center;
  cursor: pointer;
}
input:not([type="radio"]):not([type="checkbox"]):focus-visible, select:focus-visible, textarea:focus-visible { border-color: var(--pri); }
/* El campo rechazado lleva el borde en el rojo de su error, también con el foco dentro: el contorno
   del foco ya lo marca en azul. */
input[aria-invalid="true"]:not([type="radio"]):not([type="checkbox"]), select[aria-invalid="true"], textarea[aria-invalid="true"] { border-color: var(--fuera); }
/* El área de texto crece con lo escrito: dos renglones de campo de alto, y el usuario la estira. */
textarea { height: auto; min-height: calc(var(--campo) * 2); padding: var(--e2) var(--e3); resize: vertical; }
.opcional { color: var(--texto-2); }
.ayuda { font-size: var(--t13); color: var(--texto-2); margin: var(--e1) 0 0; }

/* Campo de opción y casilla. El control conserva su tamaño; lo que cumple el objetivo
   táctil de 48 px (§9.11) es la fila entera, que es la etiqueta y se puede pulsar. */
fieldset { margin: var(--e4) 0; padding: 0; border: 0; }
legend { padding: 0; font-size: var(--t12); font-weight: 500; }
/* El campo numérico no lleva las flechas del navegador: el teclado numérico basta. */
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
input[type="radio"], input[type="checkbox"] {
  flex: none;
  width: var(--e6);
  height: var(--e6);
  margin: 0;
  accent-color: var(--pri);
}
label:has(> input[type="radio"]), label:has(> input[type="checkbox"]) {
  display: flex;
  align-items: center;
  gap: var(--e2);
  width: fit-content;
  min-height: var(--control);
  margin-bottom: 0;
  font-size: var(--t15);
  font-weight: 400;
}

/* Botones (§9.9): cápsulas, como en la web de Apple. No hay botón deshabilitado: la acción que
   no aplica no se dibuja. */
.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--e1);
  height: var(--control-compacto);
  padding: 0 var(--e5);
  font: 400 var(--t15)/1.5 var(--fuente);
  letter-spacing: var(--interletra-texto);
  border: 0;
  border-radius: var(--radio-capsula);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--duracion) var(--curva), color var(--duracion) var(--curva);
}
.boton.texto { padding: 0 var(--e1); background: none; color: var(--pri-texto); }
.boton.texto:hover { text-decoration: underline; }
/* La flecha es dibujo: `chevron.svg` como máscara, en el color del texto. Sin contenido no entra
   en el nombre accesible. */
.boton.texto::after {
  content: "";
  flex: none;
  width: var(--e2);
  height: var(--e3);
  background: currentColor;
  -webkit-mask: url("chevron.svg") center / contain no-repeat;
  mask: url("chevron.svg") center / contain no-repeat;
}
.boton.texto.sin-flecha::after { content: none; }
/* Un botón de texto solo en su párrafo (la vuelta de la página de error, «Ver en el programa» de la
   confirmación de cierre) alinea su texto con el margen. */
main > p > .boton.texto:only-child, .caja > p > .boton.texto:only-child { margin-left: calc(var(--e1) * -1); }
.pri { background: var(--pri); color: var(--superficie); }
.pri:hover { background: var(--pri-texto); }
.pri:active { background: var(--pri-fuerte); }
.sec { background: var(--relleno); color: var(--pri-fuerte); }
.sec:hover { background: var(--relleno-hover); }

/* Sección plegada (§9.9): details y summary nativos. En lugar del triángulo del navegador, el
   chevrón de despliegue de Apple, dibujado con dos filetes, que gira al abrir. Un summary que es un
   botón no lo lleva. */
details { margin: var(--e4) 0; }
summary { cursor: pointer; }
summary:not(.boton) { display: flex; align-items: center; gap: var(--e2); list-style: none; }
summary::-webkit-details-marker { display: none; }
summary:not(.boton)::before {
  content: "";
  flex: none;
  width: calc(var(--e2) - 1px);
  height: calc(var(--e2) - 1px);
  margin: 0 var(--e1) 0 2px;
  border-right: 2px solid var(--texto-2);
  border-bottom: 2px solid var(--texto-2);
  transform: rotate(-45deg);
  transition: transform var(--duracion) var(--curva);
}
details[open] > summary:not(.boton)::before { transform: rotate(45deg) translate(-2px, -2px); }
summary .detalle { color: var(--texto-2); font-weight: 400; }

/* Estado vacío: un bloque gris con el texto centrado, sin icono decorativo; blanco en el teléfono. */
.vacio { color: var(--texto-2); }
main > .vacio {
  margin: var(--e6) 0 0;
  padding: var(--e12) var(--e6);
  background: var(--app);
  border-radius: var(--radio-m);
  font-size: var(--t17);
  text-align: center;
}

/* Texto solo para lectores de pantalla: la caption de la tabla y el encabezado de la acción (§13) */
.solo-lector {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Filtros plegables de Por pedir y Disponibles (ronda de auditorías del 2026-09-25, P1-20). En el
   teléfono el resumen dice lo elegido y el formulario se abre con él; en la computadora el contenido
   de un details cerrado se muestra siempre (::details-content) y el resumen no se dibuja. Donde el
   navegador no sabe mostrarlo, el resumen se queda y el filtro se abre con un toque. */
.filtros { margin: 0; }
/* La leyenda del programa se pliega igual en el teléfono, donde empujaba la primera fila fuera de la
   primera pantalla (verificación del 2026-09-25, iPhone: la fila empezaba en y=542 con la barra en
   y=613); en la computadora se lee siempre, sin el resumen. */
.leyenda-plegable { margin: 0; }
@supports selector(::details-content) {
  .filtros > summary { display: none; }
  .filtros::details-content { content-visibility: visible; }
  .leyenda-plegable > summary { display: none; }
  .leyenda-plegable::details-content { content-visibility: visible; }
}

/* Filtro de Alertas (§3.3): lista de proyecto y «Ver» en una fila */
.filtro { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--e2); margin: 0 0 var(--e5); }
.filtro .campo { margin: 0; min-width: calc(var(--control) * 6); }
.filtro label { font-size: var(--t12); color: var(--texto-2); }
.filtro select { height: var(--control-compacto); }
.filtro .boton { height: var(--control-compacto); }
/* Detalle de un ingreso (§4): línea de estado grande, aviso de reprogramación, datos como filas
   de Ajustes y error de campo. */
.linea-estado { margin: var(--e3) 0 var(--e2); }
.reprogramado { color: var(--texto-2); margin: 0 0 var(--e4); }
.aviso + .caja, .reprogramado + .caja, .linea-estado + .caja { margin-top: var(--e5); }
.datos { display: grid; grid-template-columns: max-content 1fr; gap: 0; margin: 0; }
.datos dt { color: var(--texto-2); padding: var(--e3) var(--e8) var(--e3) 0; border-top: 1px solid var(--sep); }
.datos dd { margin: 0; padding: var(--e3) 0; border-top: 1px solid var(--sep); font-variant-numeric: tabular-nums; }
.datos dt:first-of-type, .datos dd:first-of-type { padding-top: 0; border-top: 0; }
/* Los demás pedidos de la línea, en el detalle (ajuste del 2026-09-25): uno por renglón, el mes como
   enlace y el estado con su palabra, su icono y su color, en el peso del texto. Cada enlace mide 24 px de
   alto (WCAG 2.2, 2.5.8: medían 19 px con los centros a 22.5). Con inline-block: un flex quitaría los
   espacios alrededor del punto. */
.otros-pedidos { margin: 0; padding: 0; list-style: none; }
.otros-pedidos a { display: inline-block; min-height: var(--e6); text-decoration: none; }
.otros-pedidos a:hover .mes-pedido { text-decoration: underline; }
.otros-pedidos .estado { font-weight: 400; }
/* El rótulo del número en el renglón apilado de Por pedir; en la tabla lo da la cabecera. */
.rotulo-apilado { display: none; }
/* Bajo los datos del pedido, para el administrador, la última edición a mano y dónde revertirla. */
.caja > .ultima-edicion { margin: var(--e3) 0 0; color: var(--texto-2); }
.historial + .historial { margin-top: var(--e5); }
/* «Anular» es una acción que deshace: va en rojo, como las acciones destructivas de iOS. */
.c-accion-marca .boton.texto { color: var(--fuera); }
/* Confirmación sin JavaScript (§10.2), como una alerta de iOS: la frase arriba y los dos botones
   abajo, el primario a la derecha. */
.confirmacion { max-width: calc(var(--control) * 12); margin-top: var(--e5); }
.frase { font-size: var(--t17); font-weight: 600; letter-spacing: var(--interletra-titulo); margin: 0 0 var(--e2); }
.acciones { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e3); margin-top: var(--e5); }
.error { color: var(--fuera); font-size: var(--t13); margin: var(--e1) 0 0; }

/* Cambiar el pedido (definición §6), en el detalle: una lista agrupada de iOS dentro de la
   tarjeta. Cada fila es un enlace de 48 px con la flecha a la derecha y el filete empieza donde
   empieza el texto. Cancelar va en rojo, como las acciones destructivas de iOS. El foco se
   dibuja hacia dentro: la tarjeta recorta lo que sale de ella. */
.caja.cambiar > p { margin: 0 0 var(--e3); color: var(--texto-2); font-size: var(--t13); }
.lista-acciones { max-width: calc(var(--control) * 12); list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--sep); border-bottom: 1px solid var(--sep); }
.lista-acciones li + li { border-top: 1px solid var(--sep); }
.lista-acciones a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e3);
  min-height: calc(var(--e8) + var(--e3));
  padding: 0;
  color: var(--pri-texto);
  text-decoration: none;
  transition: background-color var(--duracion) var(--curva);
}
.lista-acciones a:hover { text-decoration: underline; }
.lista-acciones a:focus-visible { outline-offset: calc(var(--e1) * -1 + 1px); }
.lista-acciones a::after {
  content: "";
  flex: none;
  width: var(--e2);
  height: var(--e3);
  background: var(--ctl);
  -webkit-mask: url("chevron.svg") center / contain no-repeat;
  mask: url("chevron.svg") center / contain no-repeat;
}
.lista-acciones a.destructiva { color: var(--fuera); }

/* Página de la edición: dos tarjetas angostas, como una hoja de iOS. Arriba el formulario; abajo
   lo que va a pasar, una línea por efecto con su filete, y la confirmación. Lo que hay que hacer
   fuera del sistema (cancelar con el proveedor) lleva icono y texto en naranja. */
.caja.edicion > :not(h2), .caja.efecto > :not(h2) { max-width: calc(var(--control) * 12); }
/* Con el efecto a la vista, los datos del cambio se leen como filas y el enlace para cambiarlos va
   debajo, con su texto alineado con el de las filas (el botón de texto lleva --e1 de relleno). Una
   cápsula («Volver al proyecto») ya arranca en el borde de las filas y no se corre. */
.caja.edicion > .datos + .acciones { margin-top: var(--e3); }
.caja.edicion > .datos + .acciones:has(> .boton.texto) { margin-left: calc(var(--e1) * -1); }
/* Dentro del formulario de la tarjeta, el campo toma el ancho de la tarjeta. Un campo hijo directo de la
   sección («Añadir pedido», cuyo formulario abarca dos secciones) se queda en los 576 px de arriba. */
.caja.edicion form .campo, .caja.efecto form .campo, .caja.edicion .campos-en-linea .campo { max-width: none; }
/* El aviso de un rechazo se alinea con las tarjetas angostas de la página. */
main:has(.caja.edicion, .caja.efecto) > .aviso { max-width: calc(var(--control) * 12); }

/* Página del proyecto: «Ver el programa» bajo el encabezado y la tabla de versiones, con el autor y
   la razón en gris bajo su dato. La reversión repite la forma de la página de una edición. */
/* Cabecera de página: título y contexto a la izquierda, acciones a la derecha y al pie, como la
   barra de herramientas de una ventana de Apple. En angosto las acciones bajan. */
.cabecera-pagina { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--e4) var(--e6); }
.cabecera-texto { min-width: 0; flex: 1 1 calc(var(--control) * 8); }
.acciones-cabecera { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e2); margin: 0; }
/* Las acciones de la cabecera son botones de barra de herramientas: la misma cápsula gris para
   todas, sin la flecha de los enlaces; la primaria, en azul. */
.acciones-cabecera .boton { height: var(--e8); padding: 0 var(--e4); font-size: var(--t13); background: var(--relleno); color: var(--pri-fuerte); }
.acciones-cabecera .boton:hover { background: var(--relleno-hover); text-decoration: none; }
.acciones-cabecera .boton.pri { background: var(--pri); color: var(--superficie); }
.acciones-cabecera .boton.pri:hover { background: var(--pri-texto); }
.acciones-cabecera .boton.texto::after { content: none; }
.caja > .nota { margin: 0 0 var(--e3); color: var(--texto-2); font-size: var(--t13); }
table.versiones .secundario { display: block; color: var(--texto-2); font-size: var(--t13); }
.autor { color: var(--texto-2); margin: var(--e3) 0 0; }
.autor + .caja { margin-top: var(--e5); }
/* Cargas del PUM (especificación de pantallas §5). Tarjetas anchas para las tablas de la vista
   previa; lo que está pendiente, en naranja con icono; y la carga entera solo en computadora
   (§5.10): por debajo de 900 px la sustituye una línea. */
.ejercicio-fijo { margin-top: var(--e4); padding-top: var(--e3); border-top: 1px solid var(--sep); }
.solo-telefono { display: none; }
.nota-telefono { color: var(--texto-2); margin: var(--e5) 0 0; }
.caja > .nota + .datos { margin-top: var(--e3); }
.nota-pendiente, p.por-hacer, .nota.por-hacer { display: flex; align-items: flex-start; gap: var(--e2); color: var(--cerca); font-weight: 600; }
.nota-pendiente { max-width: calc(var(--control) * 18); margin: var(--e4) 0 0; }
.nota-pendiente svg, p.por-hacer svg { flex: none; width: var(--e4); height: var(--e4); margin-top: calc((1lh - var(--e4)) / 2); }
.nota-pendiente + .nota { margin-top: var(--e3); }
.proyecto-de { font-weight: 600; }
/* Elegir el archivo (ronda de auditorías del 2026-09-25, P2-22): el botón del navegador decía «Choose
   File» en un Chrome en inglés. No se dibuja: lo sustituye una etiqueta con la forma de los botones
   grises, «Elegir archivo», a la derecha del campo, que muestra el nombre del archivo elegido o, sin
   archivo, «Ningún archivo elegido». El campo sigue siendo el control: recibe el foco, lleva su
   contorno y el teclado lo abre. Sin archivo es inválido (required) y su propio texto no se ve. */
.elegir-archivo { position: relative; display: flex; align-items: center; gap: var(--e3); }
/* El control de archivo pone su texto arriba: el relleno lo centra en el alto del campo. */
.elegir-archivo > input[type="file"] { flex: 1 1 auto; min-width: 0; padding-block: calc((var(--campo) - 1lh) / 2 - 1px); cursor: pointer; }
.elegir-archivo input[type="file"]::file-selector-button { display: none; }
.elegir-archivo > input:invalid { color: var(--superficie); }
.elegir-archivo > .sin-archivo { position: absolute; top: 50%; left: calc(var(--e3) + 1px); color: var(--texto-2); pointer-events: none; transform: translateY(-50%); }
.elegir-archivo:has(> input:valid) > .sin-archivo { display: none; }
.elegir-archivo > .boton { flex: none; margin: 0; }
/* «Proyectos de este archivo»: un renglón por nombre, el nombre a la izquierda y su proyecto a la derecha. */
.lista-asociar { list-style: none; margin: 0; padding: 0; }
.lista-asociar li { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--e4); align-items: center; padding: var(--e3) 0; border-top: 1px solid var(--sep); }
.lista-asociar li:first-child { border-top: 0; }
.lista-asociar .campo { margin: 0; max-width: none; }
.nombre-archivo { display: flex; flex-direction: column; }
.nombre-archivo .nombre { font-weight: 600; }
.nombre-archivo .secundario, .asociado { color: var(--texto-2); font-size: var(--t13); }
.asociado { margin: 0; }
.campos-en-linea { display: flex; flex-wrap: wrap; gap: var(--e4); }
.campos-en-linea .campo { margin: var(--e2) 0 0; min-width: calc(var(--control) * 4); }
/* En la tarjeta de edición, los campos de una fila comparten el ancho por igual y bajan juntos. */
.caja.edicion .campos-en-linea { display: grid; grid-template-columns: repeat(auto-fit, minmax(calc(var(--control) * 3), 1fr)); }
.caja.edicion .campos-en-linea .campo { min-width: 0; }
/* Decisiones: cada grupo de propuestas es una elección; lo sugerido lo dice en verde, con texto. */
fieldset.propuesta { margin: var(--e5) 0 0; }
fieldset.propuesta legend { font-size: var(--t15); font-weight: 600; margin-bottom: var(--e1); }
fieldset.propuesta label, .caja.carga > label { align-items: flex-start; padding: var(--e2) 0; }
.sugerida { color: var(--ideal); font-size: var(--t13); }
.secundario-bloque { display: block; color: var(--texto-2); font-size: var(--t13); }
/* Página del proyecto: «Cerrar» es una acción destructiva, en rojo sobre gris; los alias en una lista
   con «Quitar» plegado a su lado. */
.boton.rojo { color: var(--vencida); }
.lista-alias { list-style: none; margin: var(--e2) 0 0; padding: 0; }
.lista-alias li { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--e2) var(--e4); padding: var(--e3) 0; border-top: 1px solid var(--sep); }
.lista-alias li:first-child { border-top: 0; }
.lista-alias .alias { font-weight: 600; }
.lista-alias .alias .secundario-bloque { font-weight: 400; }
.lista-alias details { margin: 0; }
details.plegada-accion { margin: var(--e2) 0 var(--e4); }
details.plegada-accion summary { color: var(--pri-texto); }
.lista-alias details.plegada-accion summary { color: var(--fuera); }
table.equipos .secundario { display: block; color: var(--texto-2); font-size: var(--t13); }
table.equipos tbody a { color: var(--texto); font-weight: 600; }
/* El renglón de un equipo con pedido abre su detalle entero (P1-11): el enlace se estira sobre él. */
table.equipos tbody tr { position: relative; }
table.equipos tbody a::after { content: ""; position: absolute; inset: 0; }
table.equipos tbody tr:has(a:hover) > td { background: var(--app); }
/* Lo informativo, plegado: un desplegable por asunto con su conteo, separados por filetes. */
.informativo details { margin: 0; padding: var(--e3) 0; border-top: 1px solid var(--sep); }
.informativo h2 + details { border-top: 0; }
.informativo summary { font-size: var(--t15); }
/* Un asunto sin nada que mostrar no se despliega: su renglón dice el cero. Tiene la forma del summary
   sin su chevrón: el texto arranca donde el de las plegables (el margen de 2 px, el chevrón, su
   margen y el hueco) y el conteo va tras el mismo hueco. */
.informativo .asunto-vacio { display: flex; gap: var(--e2); margin: 0; padding: var(--e3) 0 var(--e3) calc(2px + var(--e2) - 1px + var(--e1) + var(--e2)); border-top: 1px solid var(--sep); color: var(--texto-2); font-size: var(--t15); }
.informativo h2 + .asunto-vacio { border-top: 0; }
table.compacta { width: auto; min-width: calc(var(--control) * 8); }
.informativo details > .nota, .informativo details > table, .informativo details > .resumen-carga { margin-top: var(--e3); }
/* El aviso guarda un piso de ancho: un detalle de miles de caracteres (los números en dos proyectos,
   las celdas de una columna MESES que no coincide) se llevaba el ancho y dejaba cada aviso en seis o
   siete renglones (ronda de auditorías del 2026-09-26). Las vistas previas son solo de computadora. */
.informativo td[data-rotulo="Aviso"] { min-width: calc(var(--control) * 6); }
.resumen-carga { margin: var(--e2) 0 0; padding-left: var(--e5); }
details.caja.carga.descartar summary, details.plegada summary { color: var(--fuera); }
.efectos { list-style: none; margin: 0; padding: 0; }
.efectos li { display: flex; align-items: baseline; gap: var(--e2); padding: var(--e3) 0; border-top: 1px solid var(--sep); }
.efectos li:first-child { padding-top: 0; border-top: 0; }
/* El icono va a la altura de la primera línea, aunque el texto ocupe varias. */
.efectos svg { align-self: flex-start; width: var(--e4); height: var(--e4); margin-top: calc((1lh - var(--e4)) / 2); flex: none; }
.efectos .por-hacer { color: var(--cerca); font-weight: 600; }
.boton.destructivo { background: var(--fuera); }
.boton.destructivo:hover, .boton.destructivo:active { background: var(--vencida); }

/* Estado, días, mes y acción son cortos: partidos en dos líneas duplican el alto del renglón */
.c-estado, .c-dias, .c-mes, .c-accion { white-space: nowrap; }

/* Programa del proyecto (§7.10; decisión de Raul del 2026-09-25, filas 640 a 643 de CONTEXTO): la
   lista de requisiciones de la obra. Cada fila es un equipo con cuatro columnas (equipo, periodo,
   requisición y el botón) y, a la derecha, una barra por los meses que trabaja, del color de su
   banda del semáforo. La hoja no cambia con el número de meses: el servidor da las clases de
   tramo, de largo, de trimestre y de día. El diagrama no es enlace: el único botón está en la fila. */

/* Resumen: cuántos equipos hay en cada estado; cada cifra filtra la lista. Es texto con su icono y
   su color, sin pastillas; el elegido lleva un subrayado de 2 px. Los demás guardan ese alto en el
   relleno: un borde del color del fondo se veía en el teléfono, donde el lienzo es gris. */
.resumen-programa { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e2) var(--e6); margin: var(--e4) 0 0; padding: var(--e2) 0; border-top: 1px solid var(--sep); border-bottom: 1px solid var(--sep); font-size: var(--t13); }
.resumen-programa a { display: inline-flex; align-items: center; gap: var(--e1); padding: var(--e1) 0 calc(var(--e1) + 2px); text-decoration: none; }
.resumen-programa a b { font-size: var(--t17); font-weight: 600; color: inherit; font-variant-numeric: tabular-nums; letter-spacing: var(--interletra-titulo); }
.resumen-programa a svg { width: var(--e4); height: var(--e4); flex: none; }
.resumen-programa a:hover { text-decoration: underline; }
.resumen-programa .res-todos { color: var(--texto-2); }
.resumen-programa a.activo { padding-bottom: var(--e1); border-bottom: 2px solid currentColor; }
.resumen-programa .res-todos.activo { color: var(--texto); }

/* La leyenda explica cada color con sus días. En la computadora va siempre abierta; bajo 900 px se
   pliega en «Leyenda». Si no cabe en una línea, la lista sigue junto a la introducción, alineada con su
   primer renglón, y se parte ella: con nueve muestras, a 1280 px la lista entera bajaba y «hoy» quedaba
   sola en una tercera línea. Entre muestras van 12 px, más que los 8 entre la muestra y su texto: con 20
   no cabía en una línea a 1440 px. A 1366 px «hoy» queda sola en la segunda línea. */
.programa-leyenda { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--e2) var(--e4); margin: var(--e3) 0 var(--e4); font-size: var(--t13); line-height: 1.4; color: var(--texto-2); }
.leyenda-intro { margin: 0; font-weight: 600; color: var(--texto); }
.leyenda-lista { display: flex; flex: 1 1 calc(var(--control) * 8); flex-wrap: wrap; gap: var(--e2) var(--e3); margin: 0; padding: 0; list-style: none; }
.leyenda { display: inline-flex; align-items: center; gap: var(--e2); }
.leyenda b { font-weight: 600; color: var(--texto); }
.muestra { display: inline-flex; flex: none; align-items: center; justify-content: center; width: var(--e8); height: var(--e4); border-radius: var(--radio-xs); color: var(--superficie); }
.muestra-hoy { flex: none; width: 2px; height: var(--e4); background: var(--texto); }

/* El color de la barra: el de la banda de la fila. La muestra de la leyenda repite cada color. El
   texto blanco encima da 5.39:1 sobre el rojo, 5.29 sobre el naranja, 5.14 sobre el verde y 4.70
   sobre el azul; la barra gris lleva el texto oscuro. */
.b-fuera .celda.trabaja, .muestra.b-fuera { background: var(--fuera); }
.b-vencida .celda.trabaja, .muestra.b-vencida { background: var(--vencida); }
.b-cerca .celda.trabaja, .muestra.b-cerca { background: var(--cerca); }
.b-ideal .celda.trabaja, .muestra.b-ideal { background: var(--ideal); }
.b-programada .celda.trabaja, .muestra.b-programada { background: var(--relleno); color: var(--texto); }
/* La barra gris solo da 1.2:1 contra el blanco: lleva un contorno de 1 px en --ctl, 3.63:1 sobre el
   blanco y 3.33 sobre el gris del trimestre (WCAG 1.4.11), como la cápsula de la fila 539 de
   CONTEXTO. Va arriba y abajo de cada mes y cierra en los extremos; con border-box la celda no crece. */
.b-programada .celda.trabaja, .b-cerrado .celda.trabaja, .b-termino .celda.trabaja { border-block: 1px solid var(--ctl); }
.b-programada .celda.inicio, .b-cerrado .celda.inicio, .b-termino .celda.inicio { border-left: 1px solid var(--ctl); }
.b-programada .celda.fin, .b-cerrado .celda.fin, .b-termino .celda.fin { border-right: 1px solid var(--ctl); }
.muestra.b-programada { border: 1px solid var(--ctl); }
.b-resuelto .celda.trabaja, .muestra.b-resuelto { background: var(--pri); }
.b-cerrado .celda.trabaja { background: var(--relleno-hover); }
/* «Terminó su periodo» va hueca: solo el contorno gris de «Con tiempo», sin relleno, sin texto y sin
   iconos. Con el relleno del cerrado daba 1.10:1 contra el de «Con tiempo» y la leyenda enseñaba dos
   grises iguales. */
.muestra.b-termino { border: 1px solid var(--ctl); background: none; }
/* «Sin evidencia de llegada» (decisión 2026-09-27): la barra no toma color de banda ni el azul de lo
   resuelto. Sin relleno y con un contorno discontinuo de 1 px en --texto (16.83:1 sobre el blanco y
   15.46 sobre el gris del trimestre), dice «no confirmado». */
.b-sin-evidencia .celda.trabaja, .muestra.b-sin-evidencia { background: var(--superficie); color: var(--texto); }
.b-sin-evidencia .celda.trabaja { border-block: 1px dashed var(--texto); }
.b-sin-evidencia .celda.inicio { border-left: 1px dashed var(--texto); }
.b-sin-evidencia .celda.fin { border-right: 1px dashed var(--texto); }
.muestra.b-sin-evidencia { border: 1px dashed var(--texto); }
/* Con los colores forzados de Windows el navegador quita los fondos: la barra quedaba en blanco sobre
   blanco y, con el periodo oculto, no quedaba rastro de él. La barra, la casilla del mini programa y
   la muestra de la leyenda conservan su color y su texto; fuera de ese modo no cambia nada. */
.celda.trabaja, .mini > [class*="b-"], .muestra { forced-color-adjust: none; }

/* Sobre el blanco el programa va a sangre, como la cuadrícula de Calendario: sin tarjeta y con un
   filete al pie. Sale del margen lo que mide el relleno del panel, así su texto se alinea con el
   título. Bajo 900 px vuelve a ser la tarjeta blanca. */
.gantt { margin-inline: calc(var(--e5) * -1); border-bottom: 1px solid var(--sep); }
/* Panel de 11/20 y línea de tiempo de 9/20: las cuatro columnas del panel pesan más que la barra,
   que con 19 meses de 40 px sigue leyéndose. El panel no baja de 672 px. */
.gantt-meses, .gantt-fila { container: fila / inline-size; display: grid; grid-template-columns: minmax(calc(var(--control) * 14), 11fr) minmax(0, 9fr); column-gap: 0; }
/* La fila de los meses se queda fija bajo la barra al desplazar, translúcida como ella: los
   renglones pasan por debajo desenfocados. Ningún ancestro recorta, así que sticky funciona. */
.gantt-meses {
  position: sticky;
  top: var(--tope-fijo);
  z-index: 3;
  background: var(--flotante);
  -webkit-backdrop-filter: var(--desenfoque);
  backdrop-filter: var(--desenfoque);
  border-bottom: 1px solid var(--sep);
}
.gantt-eje, .gantt-linea { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); padding-right: var(--e4); }
.gantt-eje { container-type: inline-size; }
/* Cada mes lleva fondo opaco: sobre el material, las barras rojas que pasan por debajo teñían el
   fondo y el gris del mes bajaba a 4.31:1. Los rótulos del panel siguen sobre el material. */
.gantt-eje .col {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  min-height: var(--alto-barra);
  padding-bottom: var(--e2);
  background: var(--superficie);
  font-size: var(--t12);
  font-weight: 500;
  color: var(--texto-2);
}
/* El mes en curso, en negro y en negrita: es donde cae la raya de hoy. */
.gantt-eje .col.actual { color: var(--texto); font-weight: 700; }
/* El año puede pasar sobre los meses siguientes: por encima de su fondo. */
.anio { position: absolute; top: 0; left: 0; z-index: 1; padding: var(--e2) 0 0 var(--e2); font-size: var(--t13); font-weight: 700; color: var(--texto); white-space: nowrap; }
.mes-corto { display: none; }
/* El eje mide su propio ancho: con menos de 500 px para 19 meses las tres letras se montan, así
   que pasa a las iniciales y la pastilla a solo «hoy». Es una consulta de contenedor, no un
   punto de corte de página. Con meses tan estrechos el texto de la barra no cabe y se quita. */
@container (max-width: 500px) {
  .mes-largo { display: none; }
  .mes-corto { display: inline; }
  .hoy-fecha { display: none; }
  .texto-barra { display: none; }
}
.gantt-lineas { list-style: none; margin: 0; padding: 0; }
/* Sin relleno en la fila: las rayas de los meses y la de hoy van a todo el alto del renglón. */
.gantt-fila { align-items: stretch; transition: background-color var(--duracion) var(--curva); }
.gantt-fila + .gantt-fila { border-top: 1px solid var(--sep); }
.gantt-fila:hover { background: var(--app); }
/* Los trimestres alternan el fondo del lienzo, en la cabecera y en las filas; bajo el puntero el
   trimestre alterno oscurece un paso para que la fila siga viéndose entera. */
.gantt-linea .col.alterno, .gantt-eje .col.alterno { background: var(--app); }
.gantt-fila:hover .gantt-linea .col.alterno { background: var(--relleno); }
/* Panel con cuatro columnas: el equipo toma lo que sobra; periodo y requisición miden en em para
   que sus dos líneas quepan sin cortarse; el botón, lo suyo. Un renglón, una altura (44 px): cada
   celda va en dos líneas de una sola línea y lo que no cabe termina en puntos suspensivos; el
   detalle del pedido lo trae completo. */
.gantt-rotulo {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 10em) minmax(0, 14em) calc(var(--control) * 3);
  column-gap: var(--e4);
  align-items: center;
  min-height: calc(var(--e8) + var(--e3));
  min-width: 0;
  padding: var(--e1) var(--e4) var(--e1) var(--e5);
  border-right: 1px solid var(--sep);
}
.gantt-meses .gantt-rotulo { align-items: end; }
/* Cada fila mide su propio ancho: con 1600 px o menos (un panel de 880 o menos), el periodo se va
   (la barra ya lo dibuja) y el equipo recupera su espacio. Es una consulta de contenedor, no un
   punto de corte de página. */
@container fila (max-width: 1600px) {
  .gantt-rotulo { grid-template-columns: minmax(0, 1fr) minmax(0, 14em) calc(var(--control) * 3); }
  .gantt-rotulo > .g-periodo, .gantt-rotulo > .rotulo-panel:nth-child(2) { display: none; }
}
.rotulo-panel { padding-bottom: var(--e2); font-size: var(--t12); font-weight: 500; color: var(--texto-2); white-space: nowrap; }
.g-equipo, .g-periodo, .g-estado { display: flex; flex-direction: column; min-width: 0; }
/* El nombre del equipo abre el detalle del pedido: es el único enlace del panel además del botón. */
/* Una fila sin pedido (un equipo que ya trabajaba) no enlaza: su nombre va igual, sin enlace. */
.g-equipo > a, .g-equipo > .nombre { overflow: hidden; color: var(--texto); font-size: var(--t14); font-weight: 600; line-height: 1.3; letter-spacing: 0.01em; text-decoration: none; text-overflow: ellipsis; white-space: nowrap; }
.g-equipo > a:hover { color: var(--pri-texto); text-decoration: underline; }
.equipo, .duracion, .detalle-estado { overflow: hidden; font-size: var(--t12); line-height: 1.35; letter-spacing: 0.01em; color: var(--texto-2); text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* La razón de «Sin evidencia de llegada» y de «Terminó su periodo» no se corta: se parte en dos
   líneas y ese renglón crece; los demás siguen en 44 px. */
.detalle-estado.razon { overflow: visible; white-space: normal; }
/* La unidad que el PUM ya no trae no tiene duración: su periodo usa las dos líneas y no se corta. */
.periodo.sin-meses { overflow: visible; white-space: normal; }
.periodo { overflow: hidden; font-size: var(--t13); line-height: 1.3; color: var(--texto); text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums; }
.g-estado .estado { overflow: hidden; font-size: var(--t13); font-weight: 600; line-height: 1.3; text-overflow: ellipsis; white-space: nowrap; }
.g-estado .estado svg { flex: none; width: var(--e4); height: var(--e4); }
/* El toque de la fila (decisión 2026-09-25): la cápsula gris con texto azul de Por pedir, en su
   columna, y «Anular» sobre la fila ya pedida, en rojo, como en el detalle. La columna mide lo que
   mide el botón para que las filas sin botón no muevan a las demás. */
.g-accion { display: flex; justify-content: flex-end; }
.g-accion > .gantt-marcar, .g-accion > .gantt-anular, .g-accion > .gantt-ver { height: calc(var(--e6) + var(--e1)); padding: 0 var(--e3); font-size: var(--t12); font-weight: 600; line-height: 1; }
.g-accion > .gantt-marcar { background: var(--relleno); color: var(--pri-fuerte); }
.g-accion > .gantt-marcar:hover { background: var(--relleno-hover); }
.g-accion > .gantt-anular { background: none; color: var(--fuera); }
.g-accion > .gantt-anular:hover { text-decoration: underline; }
/* «Ver el pedido» que aparta el equipo liberado: lleva a otra página, como un enlace (§9.1 del plan de
   «Terminó su periodo»). */
.g-accion > .gantt-ver { background: none; color: var(--pri-texto); }
.g-accion > .gantt-ver:hover { text-decoration: underline; }
/* Secciones por estado, como en Por pedir (decisión 2026-09-25): la cabecera nombra el estado con
   su icono y su color y cuenta sus equipos. Se queda fija bajo la fila de los meses mientras pasan
   sus renglones y la siguiente la empuja al llegar. La fila de los meses mide el alto de la barra
   más su filete: la cabecera mete ese píxel por debajo de ella y no deja hueco. */
.gantt-seccion {
  position: sticky;
  top: calc(var(--tope-fijo) + var(--alto-barra));
  z-index: 2;
  display: flex;
  align-items: center;
  margin: 0;
  padding: var(--e6) var(--e4) var(--e2) var(--e5);
  background: var(--superficie);
  border-bottom: 1px solid var(--sep);
  font-size: var(--t17);
  line-height: 1.35;
  letter-spacing: 0;
}
.gantt-meses + .gantt-grupo > .gantt-seccion { padding-top: var(--e4); }
.gantt-seccion .estado { gap: var(--e2); font-weight: 700; }
.gantt-seccion .estado svg { width: var(--e5); height: var(--e5); }
.gantt-seccion .cuantos { margin-left: var(--e2); font-size: var(--t15); font-weight: 400; color: var(--texto-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* La nota de «Cambió de mes» dice qué hacer, como en Por pedir, en gris. Va bajo la cabecera y no
   dentro: fija, en el teléfono sus tres renglones taparían los que pasan por debajo. */
.gantt-grupo > .nota-seccion { margin: 0; padding: var(--e2) var(--e4) var(--e2) var(--e5); border-bottom: 1px solid var(--sep); font-size: var(--t13); line-height: 1.35; color: var(--texto-2); }
.gantt-linea { isolation: isolate; container-type: inline-size; }
.gantt-linea .col { position: relative; display: flex; align-items: center; padding: var(--e2) 0; }
/* Un filete por mes, como la cuadrícula de Calendario; el primer mes de cada trimestre, más
   oscuro, y el cambio de año, el más oscuro, solo en la cabecera. */
.gantt-linea .col::before, .gantt-eje .col::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 1px;
  background: var(--sep);
}
.gantt-eje .col.trimestre::before { background: var(--sep-fuerte); }
.gantt-eje .col.con-anio::before { background: var(--ctl); }
/* La barra: cada mes que trabaja es una celda del color de la banda, y las celdas seguidas forman
   una sola barra de 28 px con las puntas redondeadas. Las columnas miden fracciones de píxel: sin
   solaparse, entre dos meses se ve una costura clara. */
.celda {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  height: calc(var(--e6) + var(--e1));
  color: var(--superficie);
  font-size: var(--t12);
  font-weight: 600;
  letter-spacing: 0;
}
.celda.trabaja:not(.fin) { margin-right: -1px; }
.celda.inicio { margin-left: 2px; border-radius: var(--radio-xs) 0 0 var(--radio-xs); }
.celda.fin { margin-right: 2px; border-radius: 0 var(--radio-xs) var(--radio-xs) 0; }
.celda.inicio.fin { border-radius: var(--radio-xs); }
/* El texto de la barra arranca en su primer mes y mide lo que mide la barra (una clase de largo
   por número de meses) hasta el mes anterior al pedido siguiente; lo que no cabe termina en puntos
   suspensivos. Va sobre la raya de hoy: debajo, la raya lo partía. */
.texto-barra { position: absolute; top: 0; bottom: 0; left: 0; z-index: 3; padding: 0 var(--e2); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; line-height: calc(var(--e6) + var(--e1)); }
/* El mes del ingreso lleva el icono de su estado al principio de la celda; el texto se corre. Va sobre la
   raya de hoy, como el texto: con una línea de tiempo de 500 px o menos es la única marca de la barra. */
.icono-mes { position: absolute; top: 50%; left: var(--e2); z-index: 3; width: var(--e3); height: var(--e3); transform: translateY(-50%); }
.celda.ingreso > .texto-barra { padding-left: calc(var(--e3) + var(--e2) + var(--e1)); }
.celda.ingreso:not(.trabaja) { color: var(--texto-2); }
.largo-1 { width: 100%; }
.largo-2 { width: 200%; }
.largo-3 { width: 300%; }
.largo-4 { width: 400%; }
.largo-5 { width: 500%; }
.largo-6 { width: 600%; }
.largo-7 { width: 700%; }
.largo-8 { width: 800%; }
.largo-9 { width: 900%; }
.largo-10 { width: 1000%; }
.largo-11 { width: 1100%; }
.largo-12 { width: 1200%; }
.largo-13 { width: 1300%; }
.largo-14 { width: 1400%; }
.largo-15 { width: 1500%; }
.largo-16 { width: 1600%; }
.largo-17 { width: 1700%; }
.largo-18 { width: 1800%; }
.largo-19 { width: 1900%; }
.largo-20 { width: 2000%; }
.largo-21 { width: 2100%; }
.largo-22 { width: 2200%; }
.largo-23 { width: 2300%; }
.largo-24 { width: 2400%; }
.largo-25 { width: 2500%; }
.largo-26 { width: 2600%; }
.largo-27 { width: 2700%; }
.largo-28 { width: 2800%; }
.largo-29 { width: 2900%; }
.largo-30 { width: 3000%; }
.largo-31 { width: 3100%; }
.largo-32 { width: 3200%; }
.largo-33 { width: 3300%; }
.largo-34 { width: 3400%; }
.largo-35 { width: 3500%; }
.largo-36 { width: 3600%; }
/* La raya de hoy cruza el programa entero en el color del texto, sin halo: sobre la barra de
   color se lee igual. */
.hoy { position: absolute; top: 0; bottom: 0; z-index: 2; width: 2px; margin-left: -1px; background: var(--texto); }
/* La frase del renglón es para el lector. Si el teclado entra en uno de sus enlaces, la frase sigue
   oculta y el renglón lleva el contorno del foco: mostrarla hacía crecer el renglón y movía los de
   abajo (ronda de auditorías del 2026-09-25, P2-18). El contorno va en una capa del renglón, por
   encima de la línea de tiempo. El renglón aislado no sube sobre las cabeceras fijas. */
.gantt-fila:has(.frase-pedidos :focus-visible) { position: relative; isolation: isolate; }
.gantt-fila:has(.frase-pedidos :focus-visible)::after { content: ""; position: absolute; inset: 0; z-index: 3; border: 2px solid var(--foco); pointer-events: none; }
/* La frase va al tope de su renglón y sin margen: a media altura, con Mayús+Tab el navegador llevaba
   ese punto al borde de lo fijo y el tope del renglón, con su contorno, quedaba 11 px bajo la
   cabecera de sección. */
.gantt-fila > .gantt-rotulo { position: relative; }
.frase-pedidos { top: 0; left: 0; margin: 0; }
/* Tras una acción desde una fila (marcar, anular, liberar), el aviso va dentro de ella, encima de su
   contenido y a todo el ancho: la vuelta a la fila lo deja a la vista (decisión 2026-09-28). */
.gantt-fila > .aviso { grid-column: 1 / -1; margin: var(--e3) var(--e4) 0 var(--e5); }
/* Bajo el puntero la fila toma el gris del aviso: el aviso pasa al blanco para seguir viéndose. */
.gantt-fila:hover > .aviso { background: var(--superficie); }
/* En la fila de los meses la raya se queda en la línea de los años: bajando, tacharía el mes.
   Cuelga de ella la pastilla «hoy · 24 sep» y, si el mes lleva el año, el año detrás de la
   pastilla. Cuelga a la derecha de la raya salvo con la clase izq, que el servidor pone en el
   último mes del horizonte y en oct, nov y dic, antes de un año (decisiones 2026-09-24 y 2026-09-28). */
.gantt-eje .hoy { top: var(--e1); bottom: auto; height: var(--e5); display: flex; gap: var(--e2); white-space: nowrap; background: none; }
.hoy.izq { justify-content: flex-end; }
.hoy-texto {
  height: var(--e5);
  line-height: var(--e5);
  padding: 0 var(--e2);
  font-size: var(--t12);
  font-weight: 500;
  color: var(--superficie);
  background: var(--texto);
  border-radius: var(--radio-capsula);
  white-space: nowrap;
}
.hoy .anio { position: static; padding: 0; line-height: var(--e5); }
/* Posición del día dentro del mes: 31 clases fijas, (día − 1) / días del mes, que elige el servidor. */
.dia-1 { left: 0%; }
.dia-2 { left: 3.226%; }
.dia-3 { left: 6.452%; }
.dia-4 { left: 9.677%; }
.dia-5 { left: 12.903%; }
.dia-6 { left: 16.129%; }
.dia-7 { left: 19.355%; }
.dia-8 { left: 22.581%; }
.dia-9 { left: 25.806%; }
.dia-10 { left: 29.032%; }
.dia-11 { left: 32.258%; }
.dia-12 { left: 35.484%; }
.dia-13 { left: 38.71%; }
.dia-14 { left: 41.935%; }
.dia-15 { left: 45.161%; }
.dia-16 { left: 48.387%; }
.dia-17 { left: 51.613%; }
.dia-18 { left: 54.839%; }
.dia-19 { left: 58.065%; }
.dia-20 { left: 61.29%; }
.dia-21 { left: 64.516%; }
.dia-22 { left: 67.742%; }
.dia-23 { left: 70.968%; }
.dia-24 { left: 74.194%; }
.dia-25 { left: 77.419%; }
.dia-26 { left: 80.645%; }
.dia-27 { left: 83.871%; }
.dia-28 { left: 87.097%; }
.dia-29 { left: 90.323%; }
.dia-30 { left: 93.548%; }
.dia-31 { left: 96.774%; }

/* Acceso (2026-09-25). Referencia: la página de acceso de la Cuenta de Apple, medida con
   getComputedStyle: columna blanca de 460 px, título de 28 px en 600, campo de 56 px con radio 12 y
   rótulo flotante de 12 px, botón al ancho de la columna. Sin barras: no hay adónde ir todavía. */
body.acceso { background: var(--superficie); }
body.acceso main { max-width: calc(var(--control) * 10 + var(--e8) * 2); padding: calc(var(--e12) * 2) var(--e8) var(--e12); }
.acceso-marca { margin: 0 0 var(--e12); text-align: center; font-size: var(--t17); font-weight: 600; letter-spacing: var(--interletra-titulo); color: var(--texto); }
.acceso-marca a { color: inherit; text-decoration: none; }
/* El título, en 700 como el de las demás pantallas (decisión 2026-09-23), no en el 600 medido. */
.acceso h1 { font-size: var(--t28); font-weight: 700; line-height: 1.15; text-align: center; }
.acceso .contexto { margin-top: var(--e3); text-align: center; font-size: var(--t17); }
.acceso .aviso { max-width: none; margin-top: var(--e8); background: var(--app); box-shadow: none; }
.acceso-formulario { display: grid; gap: var(--e6); margin-top: var(--e8); }
.acceso-formulario fieldset, .acceso-formulario .campo { max-width: none; margin: 0; }
.segmentado legend { margin-bottom: var(--e2); }
/* El perfil, en el control segmentado de las pestañas: la opción elegida es la pieza blanca. El
   campo de opción queda encima de su pieza, invisible, y el foco se dibuja en la pieza. */
.segmentos {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  height: var(--campo);
  padding: 2px;
  background: var(--relleno);
  border-radius: var(--radio-s);
}
.segmentos label:has(> input[type="radio"]) {
  position: relative;
  justify-content: center;
  width: auto;
  min-height: 0;
  border-radius: var(--radio-xs);
  color: var(--texto);
  cursor: pointer;
  transition: background-color var(--duracion) var(--curva);
}
.segmentos label:has(> input[type="radio"]):hover { background: var(--relleno-hover); }
.segmentos label:has(> input[type="radio"]:checked) { background: var(--superficie); box-shadow: var(--sombra-control); font-weight: 600; }
.segmentos label:has(> input[type="radio"]:focus-visible) { outline: 2px solid var(--foco); outline-offset: 2px; }
/* El campo cubre también los 2 px de pista de arriba y de abajo: en el teléfono la pieza mide 44 px y
   el toque responde en los 48 de la pista (§9.11; el recorrido lo medía en 44 desde el 2026-09-25). */
.segmentos input[type="radio"] { position: absolute; inset: -2px 0; width: 100%; height: calc(100% + 4px); opacity: 0; cursor: pointer; }
/* Campo con rótulo flotante: vacío y sin foco, el rótulo ocupa el campo; al escribir sube. */
.acceso .flotante { position: relative; }
.acceso .flotante input:not([type="radio"]) {
  height: calc(var(--control) + var(--e2));
  padding: var(--e5) var(--e4) 0;
  font-size: var(--t17);
  border-radius: var(--radio-m);
}
.acceso .flotante input:not([type="radio"]):focus-visible { outline-offset: -1px; }
.acceso .flotante label {
  position: absolute;
  top: var(--e2);
  left: calc(var(--e4) + 1px);
  margin: 0;
  font-size: var(--t12);
  font-weight: 400;
  line-height: 1.3;
  color: var(--texto-2);
  pointer-events: none;
  transition: top var(--duracion) var(--curva), font-size var(--duracion) var(--curva), transform var(--duracion) var(--curva);
}
.acceso .flotante input:placeholder-shown:not(:focus) + label { top: 50%; transform: translateY(-50%); font-size: var(--t17); }
.acceso .boton.pri { width: 100%; height: var(--control); font-size: var(--t17); }
/* Bajo el formulario del acceso real (2026-09-29): qué hacer si se olvida la contraseña, o la vuelta
   («Salir», «Volver a Proyectos»). */
.acceso-nota { margin: var(--e6) 0 0; text-align: center; font-size: var(--t15); color: var(--texto-2); }
.acceso-nota a { text-decoration: none; }
.acceso-nota a:hover { text-decoration: underline; }

/* La contraseña temporal recién emitida en Usuarios, en el 17/600 de la escala: de un clic se
   selecciona entera para copiarla. */
.temporal { margin: 0 0 var(--e3); font-size: var(--t17); font-weight: 600; font-variant-numeric: tabular-nums; user-select: all; overflow-wrap: anywhere; }

/* Reporte del proyecto (tarea 24): la tabla por mes con el aspecto de la de Proyectos. El mes en
   curso va en negrita; un cero, en gris; lo pedido fuera del mínimo, en el rojo de su estado. */
.reporte-tabla { margin-top: var(--e6); }
/* Columnas regulares (ronda de auditorías del 2026-09-25, P2-24): el mes y la renta miden lo que su
   dato más largo; las ocho cifras de equipos reparten el resto por igual y su cabecera se parte en
   las líneas que necesite. */
table.reporte { width: calc(100% + var(--e6)); margin-inline: calc(var(--e3) * -1); border-collapse: separate; border-spacing: 0; font-variant-numeric: tabular-nums; table-layout: fixed; }
table.reporte col.k-mes { width: calc(var(--e12) * 2); }
table.reporte col.k-renta { width: calc(var(--e6) * 6); }
table.reporte th, table.reporte td { padding: calc(var(--e2) + 2px) var(--e3); text-align: left; white-space: nowrap; }
table.reporte thead th {
  position: sticky;
  top: var(--tope-fijo);
  z-index: 3;
  height: var(--control-compacto);
  white-space: normal;
  vertical-align: bottom;
  background: var(--flotante);
  -webkit-backdrop-filter: var(--desenfoque);
  backdrop-filter: var(--desenfoque);
  border-bottom: 1px solid var(--sep);
  font-size: var(--t12);
  font-weight: 500;
  color: var(--texto-2);
}
table.reporte .num { text-align: right; }
table.reporte tbody > tr > * { line-height: 1.35; }
table.reporte tbody > tr + tr > * { border-top: 1px solid var(--sep); }
table.reporte tbody > tr:last-child > * { border-bottom: 1px solid var(--sep); }
table.reporte tbody th { font-size: var(--t15); font-weight: 400; }
table.reporte tfoot th { font-size: var(--t15); }
table.reporte td { font-size: var(--t15); }
table.reporte td.cero { color: var(--texto-2); }
table.reporte tr.actual > * { font-weight: 600; }
table.reporte tr.actual > td.cero { font-weight: 400; }
table.reporte tfoot > tr > * { padding-top: var(--e3); font-weight: 600; }
.nota-reporte { margin: var(--e3) 0 0; font-size: var(--t13); color: var(--texto-2); }
.cambios h2 { margin-top: var(--e8); }
.cambios-a-mano { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--sep); border-bottom: 1px solid var(--sep); }
.cambios-a-mano li { padding: var(--e3) 0; }
.cambios-a-mano li + li { border-top: 1px solid var(--sep); }

/* Disponibles (tarea 26): la fecha del inventario bajo el contexto, los cuatro filtros en una fila
   y cada bloque con su título y su conteo. En la tabla, cada equipo es un grupo: sus datos a la
   izquierda, a lo alto de sus pedidos, y un renglón por pedido que podría cubrir. */
.fecha-inventario { margin: var(--e3) 0 0; font-size: var(--t13); color: var(--texto-2); }
.filtro-disponibles { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--e3); margin: var(--e6) 0 0; }
.filtro-disponibles .campo { flex: 1 1 calc(var(--control) * 4); max-width: calc(var(--control) * 6); margin: 0; }
.bloque-disponibles { margin: var(--e8) 0 0; }
/* La cifra sigue al título en la misma línea de texto: si el título se parte, la cifra va tras su
   última palabra y no se va al margen derecho. */
.bloque-disponibles h2 { margin: 0 0 var(--e1); }
.bloque-disponibles h2 .cuantos { margin-left: var(--e1); font-size: var(--t17); font-weight: 400; color: var(--texto-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
.bloque-disponibles > .nota { margin: 0 0 var(--e3); font-size: var(--t13); color: var(--texto-2); }
.plegada-bloque > summary h2 { margin: 0; font-size: var(--t17); }
.plegada-bloque > summary::before { border-color: var(--texto); }
.plegada-bloque[open] > summary { margin-bottom: var(--e3); }
table.disponibles { width: calc(100% + var(--e6)); margin-inline: calc(var(--e3) * -1); border-collapse: separate; border-spacing: 0; border-bottom: 1px solid var(--sep); font-variant-numeric: tabular-nums; }
table.disponibles thead th {
  position: sticky;
  top: var(--tope-fijo);
  z-index: 3;
  height: var(--control-compacto);
  padding: 0 var(--e3);
  background: var(--flotante);
  -webkit-backdrop-filter: var(--desenfoque);
  backdrop-filter: var(--desenfoque);
  border-bottom: 1px solid var(--sep);
  font-size: var(--t12);
  font-weight: 500;
  color: var(--texto-2);
  text-align: left;
  vertical-align: middle;
  white-space: nowrap;
}
table.disponibles tbody > tr > * { padding: calc(var(--e2) + 2px) var(--e3); text-align: left; vertical-align: top; line-height: 1.35; }
table.disponibles tbody > tr + tr > td { border-top: 1px solid var(--sep); }
table.disponibles tbody + tbody > tr:first-child > * { border-top: 1px solid var(--sep-fuerte); }
table.disponibles .c-equipo { font-weight: 400; min-width: calc(var(--control) * 5); }
table.disponibles .c-equipo .nombre { font-weight: 600; }
table.disponibles .secundario-bloque { display: block; margin-top: 2px; font-size: var(--t13); color: var(--texto-2); }
/* El pedido arriba, en 600, y su obra debajo en gris (ronda de auditorías del 2026-09-25, P2-23). El
   renglón del pedido lo abre entero (P1-11): el enlace se estira sobre el renglón y los datos del
   equipo, que ocupan varios renglones, quedan encima sin abrir nada. */
table.disponibles .c-pedido a { font-weight: 600; color: var(--texto); text-decoration: none; }
table.disponibles .c-pedido a:hover { color: var(--pri-texto); text-decoration: underline; }
table.disponibles tbody > tr { position: relative; }
table.disponibles .c-pedido a::after { content: ""; position: absolute; inset: 0; }
table.disponibles td[rowspan], table.disponibles th[rowspan] { position: relative; z-index: 1; }
table.disponibles tbody > tr:has(.c-pedido a:hover) > :not([rowspan]) { background: var(--app); }
table.disponibles .c-coincidencia { font-size: var(--t13); color: var(--texto-2); }
/* Equipo propio en el detalle (§4.4): una tabla por grupo, con su título arriba y el botón en el renglón. */
table.candidatos { margin-top: var(--e4); }
table.candidatos caption { padding: 0 var(--e3) var(--e2); text-align: left; font-size: var(--t15); font-weight: 600; color: var(--texto); }
/* Las ocho columnas de los candidatos (§13): la cabecera puede partirse en dos líneas y una palabra
   larga se parte antes que desbordar la página. */
table.candidatos thead th { white-space: normal; }
table.candidatos td { overflow-wrap: anywhere; }
.plegada-candidatos { margin: var(--e4) 0 0; }
table.disponibles .c-estado-pedido { white-space: nowrap; }
table.disponibles .c-estado-pedido .estado { font-size: var(--t13); font-weight: 400; }

/* Correo semanal (decisión 2026-09-25). La vista previa con las tablas de la página: un título por
   proyecto con cuántos faltan en gris, como la cabecera de sección de Por pedir, y una tabla por
   estado con su palabra, su icono y su color arriba. */
.correo-vista { margin-top: var(--e5); }
.correo-vista > p { margin: var(--e5) 0 0; }
.correo-vista > p:first-child { margin-top: 0; }
.correo-vista > .nota { color: var(--texto-2); font-size: var(--t13); }
.correo-proyecto { margin: var(--e8) 0 0; font-size: var(--t17); font-weight: 600; letter-spacing: 0; }
.correo-proyecto .cuantos { margin-left: var(--e2); font-weight: 400; color: var(--texto-2); font-variant-numeric: tabular-nums; }
/* La tabla sale del margen lo que mide su relleno, como la de Por pedir: el texto de la primera
   columna y la palabra del estado quedan alineados con el título del proyecto. */
/* Las tablas de estado de un proyecto y las de los demás comparten columnas (ronda de auditorías del
   2026-09-25, P2-19): cada dato mide lo que su valor más largo y el equipo toma lo que sobra. */
table.correo { width: calc(100% + var(--e6)); margin: var(--e4) calc(var(--e3) * -1) 0; table-layout: fixed; }
table.correo col.k-grupo { width: calc(var(--e12) + var(--e4)); }
table.correo col.k-cual { width: calc(var(--e8) * 4 + var(--e1)); }
table.correo col.k-mes { width: calc(var(--e8) * 2 + var(--e6)); }
table.correo col.k-dias { width: calc(var(--e8) * 5 + var(--e6)); }
table.correo caption { padding: 0 var(--e3) var(--e2); font-size: var(--t15); }
/* El aviso del correo que no ha salido: el icono de «pendiente» en el color de cerca del mínimo. */
.aviso.pendiente svg { color: var(--cerca); }

/* Sin movimiento para quien lo pide al sistema: los cambios de estado son instantáneos. La regla
   universal no tiene especificidad: sin !important, cada regla de clase que declara su transición le
   ganaba y no se apagaba nada (ronda de auditorías del 2026-09-25, P2-8). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; }
}

/* Sin desenfoque en el navegador, las barras translúcidas se vuelven opacas. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .barra-superior, .gantt-meses, .barra-inferior { background: var(--superficie); }
  table.alertas thead th, table.proyectos thead th, table.disponibles thead th, table.reporte thead th { background: var(--superficie); }
}

/* Punto de corte 900 px: la barra superior pasa a barra inferior (§2.1) y los controles
   crecen al objetivo táctil del teléfono (§9.5 y §9.11). */
@media (max-width: 900px) {
  .barra-superior nav { display: none; }
  .barra-superior { position: static; }
  /* «Cambiar de usuario» deja la cabecera y va al pie (fila 637 de CONTEXTO). El pie es lo último de
     la página: reserva abajo lo que tapa la barra inferior, como antes lo reservaba main. */
  .usuario a { display: none; }
  .pie-usuario { display: block; padding-bottom: calc(var(--control) + var(--e12)); }
  :root { --tope-fijo: 0px; }
  /* Las listas agrupadas de iOS: tarjetas blancas sobre el lienzo gris, como estaba antes de la
     revisión de la computadora. */
  html { scrollbar-color: var(--sep-fuerte) var(--app); }
  body { background: var(--app); }
  .aviso { background: var(--superficie); box-shadow: var(--sombra); }
  /* El aviso que va dentro de una tarjeta (junto a la fila o a la sección que cambió) vuelve al gris del
     lienzo y sin sombra, como en la computadora: blanco con sombra sobre el blanco flotaba. */
  .caja > .aviso, .gantt-fila > .aviso { background: var(--app); box-shadow: none; }
  /* En la fila, el aviso se alinea con su contenido, que lleva 16 px a cada lado bajo 900 px. */
  .gantt-fila > .aviso { margin-inline: var(--e4); }
  .caja, .caja:has(> h2:first-child) { display: block; padding: var(--e5) var(--e6); background: var(--superficie); border-top: 0; border-radius: var(--radio-m); box-shadow: var(--sombra); }
  .caja > h2:first-child { margin: 0 0 var(--e3); }
  .caja + .caja { margin-top: var(--e5); }
  .caja.confirmacion { border: 0; border-radius: var(--radio-m); }
  main > .vacio { background: var(--superficie); box-shadow: var(--sombra); }
  .caja.cambiar { padding-bottom: 0; overflow: hidden; }
  .lista-acciones { max-width: none; margin: 0 calc(var(--e6) * -1); border-bottom: 0; }
  .lista-acciones li + li { margin-left: var(--e6); }
  .lista-acciones li + li a { margin-left: calc(var(--e6) * -1); }
  .lista-acciones a { min-height: var(--control); padding: 0 var(--e6); }
  .lista-acciones a:hover { background: var(--app); text-decoration: none; }
  /* Acciones de la cabecera (ronda de auditorías del 2026-09-25, P1-20): un solo botón y las demás
     como enlaces de texto en una línea, sin flecha y alineados con el margen (P2-28). */
  .acciones-cabecera { column-gap: var(--e5); }
  .acciones-cabecera .boton { height: var(--control); font-size: var(--t17); }
  .acciones-cabecera .boton.texto { padding: 0; font-size: var(--t15); background: none; color: var(--pri-texto); }
  /* Los enlaces de navegación sueltos miden 48 px de alto sin mover su línea: el relleno crece lo
     que el margen negativo devuelve (ronda de auditorías del 2026-09-25, P2-14; medían 41, 43.5 y
     25.5 px). La marca de «Entrar como» es la única vuelta de esa pantalla, que el pie abre en el
     teléfono (medía 20 px). */
  .pie-usuario a, .aviso a, .acceso-marca a, .acceso-nota a { display: inline-block; padding-block: calc((var(--control) - 1lh) / 2); margin-block: calc((var(--control) - 1lh) / -2); }
  /* Las migas pueden ir en dos renglones: cada uno mide el toque entero, sin margen negativo, para que
     el segundo no tape al primero (verificación del 2026-09-25 en el Pixel y el iPhone). */
  .migas { line-height: var(--e8); margin-bottom: 0; }
  .migas a { display: inline-block; padding-block: var(--e2); }
  /* La miga responde en sus 48 px: el título, que va después, tapaba los 6 de abajo (verificación del
     2026-09-25: se tocaban 42). Por encima del título; las cabeceras fijas siguen por encima de ella. */
  .migas a { position: relative; z-index: 1; }
  /* Sin «Descargar el correo» en el teléfono, el enlace que queda en el aviso sigue a la derecha. */
  .aviso .solo-computadora + a { margin-left: auto; }
  /* Los demás pedidos de la línea: cada uno es un renglón de 48 px para el dedo. La celda no lleva su
     relleno: el primer mes queda a la altura de su rótulo. */
  .datos dd:has(> .otros-pedidos) { padding-block: 0; }
  .otros-pedidos a { display: flex; flex-wrap: wrap; align-items: center; column-gap: var(--e1); min-height: var(--control); }
  summary:not(.boton) { min-height: var(--control); }
  .lista-cerrados, .cambios-a-mano { margin-inline: 0; background: var(--superficie); border: 0; border-radius: var(--radio-m); }
  .lista-cerrados li, .cambios-a-mano li { padding: var(--e3) var(--e4); }
  /* Un cerrado se abre desde el renglón entero, con el chevrón gris de iOS (P1-11). */
  .lista-cerrados li { padding-right: var(--e8); }
  .lista-cerrados li:hover { background: none; }
  .lista-cerrados li::after {
    content: "";
    position: absolute;
    top: 50%;
    right: var(--e4);
    width: var(--e2);
    height: var(--e4);
    margin-top: calc(var(--e4) / -2);
    background: var(--ctl);
    -webkit-mask: url("chevron.svg") center / contain no-repeat;
    mask: url("chevron.svg") center / contain no-repeat;
  }
  table.alertas tr.seccion th { background: var(--app); border-bottom: 0; }
  table.disponibles thead th, table.reporte thead th { background: var(--app-flotante); }
  table.disponibles tbody > tr > *, table.reporte tbody > tr > *, table.reporte tfoot > tr > * { background: var(--superficie); }
  .gantt { margin-inline: 0; padding: 0 0 var(--e2); background: var(--superficie); border-bottom: 0; border-radius: var(--radio-m); box-shadow: var(--sombra); }
  .gantt-meses { border-radius: var(--radio-m) var(--radio-m) 0 0; }
  .gantt-linea .col { padding: var(--e2) 0; }
  .g-equipo > a, .equipo { overflow: visible; white-space: normal; }
  .ancho { padding-inline: var(--e5); }
  .barra-inferior {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 10;
    display: flex;
    padding-bottom: env(safe-area-inset-bottom);
    background: var(--flotante);
    -webkit-backdrop-filter: var(--desenfoque);
    backdrop-filter: var(--desenfoque);
    border-top: 1px solid var(--sep);
  }
  .barra-inferior .destino {
    flex: 1;
    flex-direction: column;
    justify-content: center;
    gap: 2px;
    min-height: var(--control);
    padding: var(--e1) var(--e1) var(--e1);
    /* 12 px, el mínimo de §10.6 (ajuste del 2026-09-25; medía 11). Con el renglón a 1.25 la barra mide
       lo mismo que con 11 px a 1.5 y cabe en la reserva de abajo. */
    font-size: var(--t12);
    font-weight: 500;
    line-height: 1.25;
  }
  /* El destino actual se distingue por el color y por el peso (decisión 2026-09-22; P2-15). */
  .barra-inferior .destino[aria-current] { color: var(--pri); font-weight: 600; }
  .boton { height: var(--control); font: 400 var(--t17)/1.5 var(--fuente); }
  .campo input, .campo select, .pestanas-telefono select { height: var(--control); font-size: var(--t17); }
  .campo textarea { font-size: var(--t17); }
  /* El foco no queda debajo de la barra inferior al avanzar con el tabulador (WCAG 2.2, 2.4.11;
     ronda de auditorías del 2026-09-25, P1-4): el navegador deja libre abajo la barra, que mide su
     icono, su rótulo, su relleno y su filete (menos que --alto-barra), su margen seguro y el contorno
     del foco. Más --e4: en un campo de texto WebKit lleva a la vista el cursor, no el campo, y el borde
     de abajo quedaba 9 px bajo la barra (verificación del 2026-09-25, iPhone de Playwright); ahí
     scroll-margin no tiene efecto. --e4 cubre lo que va del cursor al borde de un campo de 48 px. */
  html { scroll-padding-bottom: calc(var(--alto-barra) + env(safe-area-inset-bottom) + var(--e1) + var(--e4)); }
  /* Con un área de texto, la reserva cubre su alto entero: el Pixel deja la mitad bajo la barra si solo
     revela el cursor (verificación del 2026-09-25). */
  html:has(textarea) { scroll-padding-bottom: calc(var(--alto-barra) + env(safe-area-inset-bottom) + var(--e1) + var(--campo) * 2 + var(--e2) * 2); }
  /* Las cargas solo se hacen desde la computadora (decisión 2026-09-22). Con !important: una sección
     que abre con su título tenía más especificidad y «Subir Excel» se dibujaba en el teléfono (P1-10). */
  .solo-computadora { display: none !important; }
  .solo-telefono { display: block; }
  /* Los filtros de Por pedir y Disponibles van plegados y el resumen dice lo elegido (P1-20). */
  .filtros > summary { display: flex; }
  .filtros:not([open])::details-content { content-visibility: hidden; }
  /* La leyenda del programa, plegada en una línea «Leyenda» (ajuste del 2026-09-25). */
  .leyenda-plegable { margin: var(--e2) 0 var(--e3); }
  .leyenda-plegable > summary { display: flex; }
  .leyenda-plegable:not([open])::details-content { content-visibility: hidden; }
  .leyenda-plegable > .programa-leyenda { margin-top: 0; }
  /* Programa (§7.10.6): las cuatro columnas del panel se apilan encima de la línea de tiempo, que
     toma todo el ancho; el botón va a ancho completo. El nombre sigue abriendo el detalle; la fila
     no es enlace y el diagrama tampoco (decisión 2026-09-25). */
  .gantt-meses, .gantt-fila { grid-template-columns: minmax(0, 1fr); }
  .gantt-meses .gantt-rotulo { display: none; }
  .gantt-rotulo { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: var(--e1); min-height: 0; padding: var(--e3) var(--e4) 0; border-right: 0; }
  .g-equipo > a, .g-equipo > .nombre { font-size: var(--t17); }
  /* El nombre es el único acceso al detalle desde el programa: responde en 48 px y queda encima de la
     línea del equipo, que va después (respondía en 22 px). El área crece con una capa y no con relleno:
     la caja, y con ella el contorno de foco, sigue ciñendo el nombre (con relleno, el contorno cruzaba
     las letras de la línea del equipo). */
  .g-equipo > a { position: relative; z-index: 1; }
  .g-equipo > a::before { content: ""; position: absolute; inset: calc((100% - var(--control)) / 2) 0; }
  .g-periodo, .g-estado { flex-direction: row; flex-wrap: wrap; align-items: baseline; column-gap: var(--e2); }
  /* El contenedor de la fila oculta el periodo con menos de 1600 px; en el teléfono vuelve. */
  .gantt-rotulo > .g-periodo { display: flex; }
  .equipo, .periodo, .duracion, .detalle-estado, .g-estado .estado { overflow: visible; font-size: var(--t15); white-space: normal; }
  .g-accion { min-width: 0; }
  .g-accion > .gantt-marcar, .g-accion > .gantt-anular, .g-accion > .gantt-ver { flex: 1; height: var(--control); margin: var(--e2) 0 0; font-size: var(--t17); }
  /* Sobre el gris, «Anular» va en el rojo oscuro: con el de «Fuera del mínimo» daba 4.41:1. «Ver el
     pedido», en el azul fuerte de «Marcar requisición» (5.69:1). */
  .g-accion > .gantt-anular { background: var(--relleno); color: var(--vencida); }
  .g-accion > .gantt-ver { background: var(--relleno); color: var(--pri-fuerte); }
  .gantt-eje, .gantt-linea { padding-inline: var(--e4); }
  /* El fondo alterno de los trimestres se queda en la fila de meses: en cada renglón sería una caja
     suelta bajo el texto. La raya de hoy sigue marcándolo. */
  .gantt-linea .col.alterno, .gantt-fila:hover .gantt-linea .col.alterno { background: none; }
  /* La cabecera de sección y su nota se alinean con el texto de la tarjeta; el tope fijo ya vale 0. */
  .gantt-seccion, .gantt-grupo > .nota-seccion { padding-inline: var(--e4); }
  /* Cada filtro del resumen responde en 48 px de alto (medían 35.5) con una capa centrada en el
     enlace: el texto y el subrayado del elegido no se mueven. Con el texto al pie de un enlace de 48 px,
     un toque 6 px bajo la cifra filtraba por el renglón siguiente. A 12 px entre renglones, las capas de
     dos renglones se encuentran a medio camino entre sus textos. */
  .resumen-programa { gap: var(--e3) var(--e4); font-size: var(--t15); }
  .resumen-programa a { position: relative; }
  .resumen-programa a::before { content: ""; position: absolute; inset: calc((100% - var(--control)) / 2) 0; }
}

/* Punto de corte 640 px: texto de 17 como en iOS, cada renglón se apila en una lista agrupada
   (§3.6) y las pestañas pasan a select */
@media (max-width: 640px) {
  body { font-size: var(--t17); }
  .ancho { padding-inline: var(--e4); }
  /* Un nombre largo no cabe en una línea junto a la marca: se parte, alineado a la derecha, dentro de
     la altura de la barra. */
  .barra-superior .ancho { gap: var(--e3); }
  .usuario { white-space: normal; text-align: right; line-height: 1.3; }
  /* Dos renglones como máximo dentro de la barra; un nombre de 60 caracteres ocupaba cuatro y se salía. */
  .usuario .quien { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
  main { padding-top: var(--e5); }
  /* «Saltar al contenido» medía 42 px de alto: sube a los 48 de un control. */
  .saltar { padding-block: calc((var(--control) - 1lh) / 2); }
  /* El error bajo el campo, a 15 px: a 13 se perdía junto al texto de trabajo de 17. */
  .error { font-size: var(--t15); }
  /* El texto secundario sube a 15 px, como el de iOS junto a un texto de 17 (P2-17). Cada selector
     repite la especificidad de la regla que lo pone en 13. */
  .migas, .nota, .ayuda, .secundario, .secundario-bloque, .fecha-inventario, .nota-reporte, .asociado, .sugerida, .c-grupo, .urgencia, .caja > .nota, .caja.cambiar > p, .correo-vista > .nota, .bloque-disponibles > .nota, .nombre-archivo .secundario, table.versiones .secundario, table.equipos .secundario, table.disponibles .secundario-bloque, table.disponibles .c-coincidencia, table.proyectos .nota, table.proyectos .sin-evidencia-obra, table.proyectos .termino-obra, .lista-cerrados .nota, table.alertas tr.seccion .nota-seccion, .gantt-grupo > .nota-seccion, table.disponibles .c-estado-pedido .estado { font-size: var(--t15); }
  /* En el teléfono cada campo del formulario ocupa su renglón: tres en dos columnas dejan uno a media anchura. */
  .caja.edicion .campos-en-linea { grid-template-columns: 1fr; }
  /* Disponibles en el teléfono: cada equipo, un bloque; sus pedidos, renglones dentro. */
  .filtro-disponibles .campo { max-width: none; flex-basis: 100%; }
  table.disponibles { width: auto; margin-inline: 0; border-bottom: 0; }
  table.disponibles thead { display: none; }
  table.disponibles tbody { display: block; margin-bottom: var(--e3); border-radius: var(--radio-m); overflow: hidden; background: var(--superficie); }
  table.disponibles tbody > tr > * { display: block; padding: var(--e2) var(--e4); border-radius: 0; }
  table.disponibles td[data-rotulo] { font-size: var(--t15); color: var(--texto-2); padding-top: 0; }
  /* «Sin pedido pendiente»: el destino y su fecha llevan su rótulo. Sin él, bajo el liberado, la fecha se
     leía como la de la liberación. */
  table.disponibles.simple td[data-rotulo="Destino"]::before, table.disponibles.simple td[data-rotulo="En su destino desde"]::before { content: attr(data-rotulo) " "; }
  /* El pedido lleva el chevrón de iOS en su primera línea, como la fecha de un correo en Mail. */
  table.disponibles .c-pedido { padding-right: var(--e8); }
  table.disponibles .c-pedido a::before {
    content: "";
    float: right;
    width: var(--e2);
    height: var(--e4);
    margin: calc((1lh - var(--e4)) / 2) calc(var(--e4) * -1) 0 0;
    background: var(--ctl);
    -webkit-mask: url("chevron.svg") center / contain no-repeat;
    mask: url("chevron.svg") center / contain no-repeat;
  }
  table.disponibles tbody > tr { padding: 0; }
  table.disponibles tbody > tr:first-child { border-top: 0; }
  table.disponibles tbody > tr + tr > td, table.disponibles tbody + tbody > tr:first-child > * { border-top: 0; }
  /* El reporte en el teléfono: un bloque por mes, como el historial (ronda de auditorías del
     2026-09-25, P2-24; la tabla se deslizaba dentro de su caja y se veían 5 de sus 10 columnas sin
     indicio de las demás). El mes titula su bloque y cada cifra lleva delante el nombre de su
     columna; el total va aparte, con la misma forma. */
  table.reporte { width: auto; margin-inline: 0; }
  table.reporte thead, table.reporte colgroup { display: none; }
  table.reporte tbody, table.reporte tfoot { overflow: hidden; background: var(--superficie); border-radius: var(--radio-m); }
  /* El apilado de abajo no alcanza al tfoot: como grupo de tabla medía lo que su contenido, sin radio
     ni margen. En bloque mide lo que los meses. */
  table.reporte tfoot { display: block; margin-top: var(--e3); }
  table.reporte tr { padding: var(--e3) var(--e4); }
  table.reporte tbody > tr + tr { border-top: 1px solid var(--sep); }
  table.reporte tbody > tr + tr > *, table.reporte tbody > tr:last-child > * { border: 0; }
  /* Cada cifra en su línea, como una fila de Ajustes: el nombre de la columna a la izquierda y la cifra
     a la derecha, en tabulares. Así cabe en una línea también a 320 px. */
  table.reporte th { padding: 0 0 var(--e1); font-weight: 600; }
  table.reporte td { display: flex; justify-content: space-between; align-items: baseline; gap: var(--e3); padding: var(--e1) 0 0; }
  table.reporte tfoot > tr > * { padding-top: 0; }
  table.reporte td::before { content: attr(data-rotulo); color: var(--texto-2); font-weight: 400; text-align: left; }
  /* El acceso en el teléfono: menos aire arriba y el control segmentado al alto táctil. */
  body.acceso main { padding-top: var(--e12); padding-inline: var(--e4); }
  .acceso-marca { margin-bottom: var(--e8); }
  .segmentos { height: var(--control); }
  main:has(> .pestanas) { display: block; }
  .pestanas { display: none; }
  .pestanas-telefono { display: block; margin: var(--e5) 0 var(--e3); }
  table, tbody, tr, th, td { display: block; }
  thead { display: none; }
  tbody tr { background: var(--superficie); border-top: 1px solid var(--sep); padding: var(--e3) var(--e4); }
  tbody tr + tr > * { border-top: 0; }
  /* Dentro de una tarjeta, el renglón apilado arranca donde arranca el título: la tarjeta ya pone el margen. */
  .caja table tbody tr { padding-inline: 0; }
  td, th { padding: 0; }
  /* El historial apila cada solicitud: sin el thead, cada dato lleva delante el nombre de
     su columna. La especificación no fija esta forma: es un supuesto. */
  table.historial caption { display: block; }
  table.historial td { overflow-wrap: anywhere; }
  table.historial td { position: relative; padding-left: calc(var(--e6) * 6 + var(--e3)); }
  /* Apilada, una fecha o una cantidad larga se parte en lugar de desbordar la página (ronda de
     auditorías del 2026-09-25, P1-5: a 320 px el historial y el correo se desplazaban a lo ancho). */
  table.historial td.num { white-space: normal; }
  /* Las tablas apiladas no salen del margen: su texto arranca donde el de la tarjeta (P1-18). */
  .caja table { width: auto; margin-inline: 0; }
  .caja table > caption { padding-inline: 0; }
  /* Las filas de datos llevan el rótulo del ancho del de las tablas apiladas: los valores de las
     tarjetas de una pantalla se alinean (P2-27; con max-content cada tarjeta ponía su columna). */
  .datos { grid-template-columns: calc(var(--e6) * 6 + var(--e3)) minmax(0, 1fr); }
  .datos dt { padding-right: var(--e3); }
  table.historial td::before { content: attr(data-rotulo); position: absolute; top: 0; left: 0; width: calc(var(--e6) * 6); color: var(--texto-2); }
  table.historial td:empty { display: none; }
  table.historial td.c-accion-marca { display: block; margin-top: var(--e2); padding-left: 0; }
  table.historial td.c-accion-marca::before { content: none; }
  /* El gris es de los botones secundarios y de texto de la celda. El primario rojo de la confirmación
     plegada («Quitar …») conserva su relleno: con el gris quedaba blanco sobre gris, 1.22:1. Su ancho
     lo da la fila de acciones. */
  table.historial td.c-accion-marca .boton:not(.pri) { width: 100%; background: var(--relleno); }
  /* «Anular» y «Revertir» sobre el gris: el rojo de «Fuera del mínimo» da 4.41:1 y el más oscuro, 6.70,
     como «Cerrar el proyecto». «Cubrir con este equipo», el botón gris de la misma celda, sigue azul. */
  table.historial td.c-accion-marca .boton.texto { color: var(--vencida); }
  /* Equipos del proyecto: una fila de iOS, sin rótulos; clase y pedidos en gris en una línea. */
  table.equipos td { position: static; display: block; padding-left: 0; }
  table.equipos td::before { content: none; }
  table.equipos td[data-rotulo="Equipo"] { margin-top: var(--e1); }
  table.equipos td[data-rotulo="Clase"], table.equipos td[data-rotulo="Pedidos"] { display: inline; color: var(--texto-2); font-size: var(--t15); }
  table.equipos td[data-rotulo="Clase"]::after { content: " · "; }
  /* El renglón con pedido se abre entero y lleva el chevrón gris de iOS (P1-11). */
  table.equipos tbody tr:has(a) { padding-right: var(--e6); }
  table.equipos tbody tr:has(a)::after {
    content: "";
    position: absolute;
    top: 50%;
    right: 0;
    width: var(--e2);
    height: var(--e4);
    margin-top: calc(var(--e4) / -2);
    background: var(--ctl);
    -webkit-mask: url("chevron.svg") center / contain no-repeat;
    mask: url("chevron.svg") center / contain no-repeat;
  }
  /* Vista previa del correo: una fila sin rótulos, como el renglón de la versión en texto; el equipo
     arriba y grupo, cantidad, mes y días en gris en una línea. La tabla vuelve al margen. */
  table.correo { width: 100%; margin-inline: 0; }
  table.correo colgroup { display: none; }
  table.correo caption { padding-inline: 0; }
  table.correo td { display: inline; padding-left: 0; color: var(--texto-2); font-size: var(--t15); }
  table.correo td::before { content: none; }
  table.correo td[data-rotulo="Equipo"] { display: block; color: var(--texto); }
  table.correo td[data-rotulo="Grupo"]::after, table.correo td[data-rotulo="Número o cantidad"]::after, table.correo td[data-rotulo="Mes"]::after { content: " · "; }
  /* Destinatarios: la dirección entera en su renglón, sin rótulo que la parta; quién y cuándo, en gris. */
  table.destinatarios td { padding-left: 0; }
  table.destinatarios td::before { content: none; }
  table.destinatarios td[data-rotulo="Agregado"] { color: var(--texto-2); font-size: var(--t15); }
  /* El aviso del correo: la acción baja a su renglón, alineada con el texto. */
  .aviso.pendiente { flex-wrap: wrap; row-gap: var(--e2); }
  .aviso.pendiente span { flex: 1 1 0; }
  .aviso.pendiente a { flex-basis: 100%; margin-left: calc(var(--e5) + var(--e3)); }
  .caja { padding: var(--e4); }
  .caja.cambiar { padding-bottom: 0; }
  .lista-acciones { margin-inline: calc(var(--e4) * -1); }
  .lista-acciones li + li { margin-left: var(--e4); }
  .lista-acciones li + li a { margin-left: calc(var(--e4) * -1); }
  .lista-acciones a { padding-inline: var(--e4); }
  .filtro .campo { min-width: 0; max-width: none; flex: 1 1 100%; }
  .filtro select, .filtro .boton { height: var(--control); }
  .filtro .boton { flex: 1 1 100%; }
  .caja.marcar .boton, .acciones .boton { width: 100%; }
  .acciones { flex-direction: column; align-items: stretch; }
  /* Un enlace de texto no es un botón al ancho: va a la izquierda, con su texto en el margen de la
     tarjeta, como los enlaces de la cabecera (verificación del 2026-09-25: «Cambiar estos datos» iba
     centrado en 372 px). */
  .acciones > .boton.texto { align-self: flex-start; width: auto; padding-inline: 0; }
  /* Sin relleno no hay nada que compensar: con el corrimiento de la computadora, «Cambiar estos datos»
     arrancaba 4 px antes que los rótulos de las filas (revisión del 2026-09-26). */
  .caja.edicion > .datos + .acciones:has(> .boton.texto) { margin-left: 0; }
  /* El botón de la cabecera ocupa el ancho, como los demás botones de acción; los enlaces van debajo,
     en una línea. */
  .acciones-cabecera { flex: 1 1 100%; }
  .acciones-cabecera .boton:not(.texto) { flex-basis: 100%; }
  /* Programa (§7.10.6): meses por su inicial, solo «hoy» en la pastilla y la tarjeta con el
     relleno del teléfono. La leyenda va en una columna y el texto de las barras no cabe. */
  .programa-leyenda { font-size: var(--t15); }
  .leyenda-lista { flex-direction: column; gap: var(--e2); }
  .gantt { padding: 0 0 var(--e2); }
  .mes-largo { display: none; }
  .mes-corto { display: inline; }
  .hoy-fecha { display: none; }
  /* Con meses de 13 a 20 px, 19 filetes parecen un código de barras. */
  .gantt-linea .col::before, .gantt-eje .col::before { content: none; }
  .gantt-linea .celda { height: var(--e4); }
  .texto-barra { display: none; }
  .icono-mes { left: 2px; }
  .celda.inicio { margin-left: 1px; }
  .celda.fin { margin-right: 1px; }
}

/* Alertas mide el ancho de su contenido, no el de la ventana (§3.5 y §3.6; corrige el desborde
   heredado de la decisión 438). Bajo 1280 px la tabla se compacta: sin la columna de grupo y con
   menos relleno; la palabra del estado sigue en una línea. */
@container principal (max-width: 1280px) {
  /* La columna del grupo se queda en cero, como días y mes: quitarla correría las celdas. */
  table.alertas col.k-grupo { width: 0; }
  table.alertas thead th:nth-child(6), table.alertas tr.renglon > td.c-grupo { padding: 0; font-size: 0; visibility: hidden; }
  table.alertas col.k-proyecto { width: calc(var(--e8) * 5); }
  table.alertas col.k-marca { width: calc(var(--control) * 3 + var(--e2)); }
  table.alertas col.k-estado { width: calc(var(--e8) * 4 + var(--e6)); }
  table.alertas col.k-modelo { width: calc(var(--e8) * 4 + var(--e2)); }
  table.alertas col.k-num { width: calc(var(--e8) * 4 - var(--e1)); }
  table.alertas:has(.c-accion .boton.pri) col.k-accion { width: calc(var(--control) * 3 + var(--e4)); }
  /* Proyectos: con menos ancho, el mini programa cede espacio a las cifras. */
  table.proyectos thead th.c-meses, table.proyectos td.c-meses { width: 36%; padding-inline: var(--e3); }
  table.proyectos thead th.num, table.proyectos td.num { padding-left: var(--e3); }
  table.alertas tr.renglon > td { padding-inline: var(--e2); }
  table.alertas thead th { padding-inline: var(--e2); }
}

/* Bajo 960 px Alertas es una lista agrupada de iOS: cada sección, un grupo blanco de esquinas
   redondeadas con su cabecera fija sobre el lienzo; cuatro líneas por renglón (§3.6 y decisión
   2026-09-24): estado y días; descripción, marca y modelo; el proyecto; número y mes. El renglón
   entero abre el detalle y lleva el chevrón gris a la derecha; el de «Marcar solicitada» lleva su
   botón al ancho. El grupo no se muestra. */
@container principal (max-width: 960px) {
  /* Un renglón por proyecto: el nombre, lo que falta por pedir y lo demás en el resumen. El
     renglón entero abre el programa, con el chevrón gris de iOS. */
  table.proyectos, table.proyectos tbody, table.proyectos tr, table.proyectos th { display: block; }
  table.proyectos thead, table.proyectos td { display: none; }
  table.proyectos { width: auto; margin-inline: 0; }
  table.proyectos tbody > tr:last-child > * { border-bottom: 0; }
  /* El grupo es el tbody, blanco y redondeado: el renglón no pinta un fondo cuadrado encima. */
  table.proyectos tbody > tr { background: none; }
  table.proyectos tbody > tr:first-child { border-top: 0; }
  table.proyectos tbody { background: var(--superficie); border-radius: var(--radio-m); }
  table.proyectos tbody > tr { position: relative; padding: var(--e3) var(--e8) var(--e3) var(--e4); }
  table.proyectos tbody > tr + tr { border-top: 1px solid var(--sep); }
  table.proyectos tbody > tr > *, table.proyectos tbody > tr + tr > * { height: auto; padding: 0; background: none; border: 0; border-radius: 0; }
  table.proyectos tbody > tr:hover > * { background: none; }
  table.proyectos .c-proyecto { order: 0; font-size: var(--t17); font-weight: 600; color: var(--texto); white-space: normal; }
  table.proyectos tbody > tr::after {
    content: "";
    position: absolute;
    top: 50%;
    right: var(--e4);
    width: var(--e2);
    height: var(--e4);
    margin-top: calc(var(--e4) / -2);
    background: var(--ctl);
    -webkit-mask: url("chevron.svg") center / contain no-repeat;
    mask: url("chevron.svg") center / contain no-repeat;
  }
  table.proyectos .resumen { display: block; margin-top: 2px; font-size: var(--t15); font-weight: 400; }
  table.proyectos .resumen > .estado, table.proyectos .resumen > .linea { display: flex; margin-top: 2px; }
  table.proyectos .resumen > .estado { gap: var(--e1); align-items: baseline; font-weight: 400; }
  table.proyectos .resumen > .estado svg { flex: none; align-self: center; }
  table.proyectos .resumen > .nota { font-size: var(--t15); }
  /* El enlace de la obra sin evidencia responde en 48 px, como los filtros del resumen del programa: un
     toque 3 px por encima o por debajo del texto abría el programa sin filtrar. */
  table.proyectos .sin-evidencia-obra::before { inset: calc((100% - var(--control)) / 2) 0; }
  /* Lo que sobresale arriba y abajo queda en su propio margen, igual en los dos lados: sobre la nota del
     PUM, sobre «N terminaron su periodo sin liberar» o sobre el resumen, un toque abría el programa
     filtrado por la evidencia; con margen solo abajo, el hueco quedaba desigual. */
  table.proyectos .sin-evidencia-obra { margin-block: calc((var(--control) - 1lh) / 2); }
  table.proyectos td.c-meses { display: block; width: auto; margin-top: var(--e2); padding: 0; }
  table.proyectos .mini > span { height: var(--e4); font-size: 0; }
  .totales-obras { grid-auto-flow: row; grid-template-columns: 1fr 1fr 1fr; margin-inline: 0; background: var(--superficie); border: 0; border-radius: var(--radio-m); }
  .totales-obras > li + li { border-left: 0; }
  .totales-obras > li:nth-child(n + 4) { border-top: 1px solid var(--sep); }
  .totales-obras > li:not(:nth-child(3n + 1)) { border-left: 1px solid var(--sep); }
  .totales-obras a, .totales-obras .sin-enlace { padding: var(--e3) var(--e4); }
  table.alertas, table.alertas tbody, table.alertas tr, table.alertas th, table.alertas td { display: block; }
  table.alertas thead, table.alertas colgroup { display: none; }
  table.alertas { width: auto; margin-inline: 0; border-spacing: 0; background: none; }
  /* Aquí la fija es la fila de sección: su celda es un bloque de la misma altura que la fila y
     no tendría recorrido. La sección siguiente empuja a la anterior. */
  table.alertas tr.seccion { position: sticky; top: var(--tope-fijo); z-index: 2; background: none; padding: 0; border-top: 0; }
  /* La cabecera de la sección y el título del mes arrancan en el margen, como el título de la página
     (verificación del 2026-09-25: iban 4 px más adentro). */
  table.alertas tr.seccion th { position: static; padding: var(--e5) 0 var(--e2); }
  table.alertas tr.seccion .nota-seccion { display: block; margin: var(--e1) 0 0; }
  /* El mes es el título de su grupo, sin quedarse fijo: cada renglón del teléfono ya dice su mes y
     sus días (decisión 2026-09-22 del renglón apilado). */
  table.alertas tr.subseccion { padding: 0; background: none; border-top: 0; }
  table.alertas tr.subseccion th { position: static; height: auto; padding: var(--e1) 0 var(--e2); background: none; border: 0; }
  table.alertas tr.renglon + tr.subseccion th { padding-top: var(--e5); }
  /* Sin sitio junto al control segmentado, el filtro baja a su propia línea, al ancho. */
  main:has(> .pestanas) > .pestanas { margin-bottom: 0; }
  main:has(> .pestanas) > .filtros { flex-basis: 100%; margin-left: 0; }
  table.alertas tbody tr.renglon {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: var(--e2);
    row-gap: 2px;
    padding: var(--e3) var(--e8) var(--e3) var(--e4);
    background: var(--superficie);
    border-top: 1px solid var(--sep);
  }
  table.alertas tr.renglon::before, table.alertas tr.renglon::after { content: ""; flex-basis: 100%; order: 3; }
  table.alertas tr.renglon::after { order: 8; }
  .c-estado { order: 1; }
  .c-dias { order: 2; }
  .c-desc { order: 4; }
  .c-marca { order: 5; }
  .c-modelo { order: 6; }
  .c-proyecto { order: 7; flex-basis: 100%; color: var(--texto-2); font-size: var(--t15); }
  /* El enlace del proyecto mide 48 px de alto para el dedo sin mover la línea: el relleno crece lo que
     el margen negativo devuelve (verificación del 2026-09-25: medía 136 × 18 px). Crece solo hacia
     abajo: centrado tapaba la mitad de abajo de la descripción, y tocar el nombre del pedido abría el
     programa (2026-09-29). Abajo cubre la línea del número en el ancho del nombre. */
  table.alertas .c-proyecto a { display: inline-block; padding-block: 0 calc(var(--control) - 1lh); margin-block: 0 calc(1lh - var(--control)); }
  /* Sin la cabecera de su columna, el número de una unidad lleva su rótulo (ajuste del 2026-09-25). */
  table.alertas .rotulo-apilado { display: inline; color: var(--texto-2); }
  table.alertas tr.renglon > td.c-grupo { display: none; }
  .c-num { order: 9; }
  .c-mes { order: 10; }
  .c-accion { order: 11; }
  /* Cada mes es un grupo con sus esquinas. */
  table.alertas tr.subseccion + tr.renglon { border-top: 0; border-radius: var(--radio-m) var(--radio-m) 0 0; }
  table.alertas tr.renglon:has(+ tr.subseccion), table.alertas tr.renglon:last-child { border-radius: 0 0 var(--radio-m) var(--radio-m); }
  table.alertas tr.subseccion + tr.renglon:has(+ tr.subseccion), table.alertas tr.subseccion + tr.renglon:last-child { border-radius: var(--radio-m); }
  table.alertas tr.renglon > td, table.alertas tr.renglon > td:first-child, table.alertas tr.renglon > td:last-child { height: auto; padding: 0; border-top: 0; border-radius: 0; background: none; text-align: left; }
  table.alertas tr.renglon + tr.renglon > td:first-child::before { content: none; }
  table.alertas tr.renglon:hover > td { background: none; }
  table.alertas tr.renglon .estado { font-size: var(--t15); }
  table.alertas .c-desc a { display: inline; }
  .c-desc a { font-size: var(--t17); }
  .c-dias { margin-left: auto; color: var(--texto-2); font-size: var(--t15); }
  table.alertas tr.renglon > td.c-dias, table.alertas tr.renglon > td.c-mes { font-size: var(--t15); }
  .c-marca, .c-modelo, .c-num, .c-mes { font-size: var(--t15); }
  .c-marca, .c-modelo, .c-mes { color: var(--texto-2); }
  .c-marca:empty, .c-modelo:empty { display: none; }
  /* El renglón entero abre por el enlace de la descripción. «Abrir» es el chevrón gris de iOS, en la
     franja derecha que todos los renglones reservan: no tapa el proyecto ni el botón (P2-7), y
     también va en el renglón que se marca (P1-11). Su nombre accesible no cambia. */
  table.alertas .c-accion .boton.pri + .boton.texto { display: inline-flex; }
  table.alertas .c-accion .boton.texto { position: absolute; inset: 0 0 0 auto; z-index: 1; justify-content: flex-end; width: var(--e8); height: auto; padding-right: var(--e3); font-size: 0; color: var(--ctl); }
  /* Con «Marcar requisición», la franja se detiene sobre el botón, que ocupa el ancho de la tarjeta
     como antes, y el chevrón se centra en el texto. */
  table.alertas tr.renglon:has(.boton.pri) .c-accion .boton.texto { bottom: calc(var(--control) + var(--e3)); }
  table.alertas .c-accion .boton.texto::after { width: var(--e2); height: var(--e4); }
  table.alertas .c-accion .boton.texto:hover { text-decoration: none; }
  .c-accion:has(.boton.pri) { flex-basis: calc(100% + var(--e4)); margin: var(--e3) calc(var(--e4) * -1) 0 0; }
  .c-accion .boton.pri { width: 100%; }
  table.alertas .boton.pri { height: var(--control); font-size: var(--t17); }
}

/* Candidatos del detalle (§4.4 y §13): las ocho columnas piden unos 1,050 px de página. Con menos,
   cada equipo se apila con el nombre de cada dato delante, en su propia columna, y el botón al pie.
   Mide el ancho de la página, no el de la ventana. En el teléfono la columna del nombre se estrecha
   y «En su destino desde» ocupa dos líneas sin montarse sobre el dato siguiente. */
@container principal (max-width: 1100px) {
  /* Por pedir: la palabra del estado se parte en dos líneas, también «Cubierto con equipo propio», y la
     descripción conserva 128 px con 961 de contenido (fila 665). */
  table.alertas col.k-estado { width: calc(var(--e12) * 2 + var(--e6) + var(--e1)); }
  table.candidatos, table.candidatos caption, table.candidatos tbody, table.candidatos tr { display: block; }
  /* Apilados, los candidatos no llevan el relleno de las celdas: no salen del margen (P1-18). */
  table.candidatos { width: auto; margin-inline: 0; }
  table.candidatos caption { padding-inline: 0; }
  table.candidatos thead { display: none; }
  table.candidatos tbody tr { padding: var(--e3) 0; background: none; border-top: 0; }
  table.candidatos tbody tr + tr { border-top: 1px solid var(--sep); }
  table.candidatos tbody tr > *, table.candidatos tbody tr + tr > * { border-top: 0; }
  table.candidatos td { display: grid; grid-template-columns: calc(var(--e6) * 7) minmax(0, 1fr); column-gap: var(--e3); padding: 0; }
  table.candidatos td::before { content: attr(data-rotulo); position: static; width: auto; color: var(--texto-2); white-space: normal; }
  table.candidatos td:empty { display: none; }
  table.candidatos td.c-accion-marca { display: block; margin-top: var(--e2); }
  table.candidatos td.c-accion-marca::before { content: none; }
}
@container principal (max-width: 600px) {
  /* El rótulo mide lo que el de las tablas apiladas y las filas de datos: los valores de la pantalla
     arrancan en la misma línea (ronda de auditorías del 2026-09-25, P2-27). */
  table.candidatos td { grid-template-columns: calc(var(--e6) * 6) minmax(0, 1fr); }
}

/* Con menos de 368 px de contenido (una ventana de menos de 400 px), el rótulo de 144 px dejaba unos
   80 px al valor y la página se desplazaba a lo ancho (WCAG 1.4.10; ronda de auditorías del
   2026-09-25, P1-5). El rótulo va encima de su valor, en las tablas apiladas, en los candidatos y en
   las filas de datos. El reporte no lo necesita: cada cifra ya va en su línea, con la cifra a la derecha. */
@container principal (width < 368px) {
  table.historial td { padding-left: 0; }
  table.historial td::before { position: static; display: block; width: auto; }
  table.historial td + td { margin-top: var(--e2); }
  table.candidatos td { grid-template-columns: minmax(0, 1fr); }
  .datos { grid-template-columns: minmax(0, 1fr); }
  .datos dt { padding: var(--e3) 0 0; }
  .datos dd { padding-top: 0; border-top: 0; }
  .datos dt:first-of-type { padding-top: 0; }
}

/* Impresión del reporte (tarea 24): papel blanco y horizontal, sin barras, migas ni botones; la
   cabecera de la tabla deja de flotar y la tabla se imprime entera. */
@page { size: landscape; margin: 12mm; }
@media print {
  .barra-superior, .barra-inferior, .pie-usuario, .migas, .acciones-cabecera, .saltar { display: none; }
  body { background: var(--superficie); }
  main { padding: 0; }
  .ancho { max-width: none; padding-inline: 0; }
  .reporte-tabla { overflow: visible; }
  table.reporte { width: 100%; margin-inline: 0; }
  table.reporte thead th { position: static; background: var(--superficie); -webkit-backdrop-filter: none; backdrop-filter: none; }
  table.reporte th, table.reporte td { padding: var(--e1) var(--e2); }
  table.reporte tbody > tr:first-child > * { border-top: 1px solid var(--sep); }
}
