/* ── 00-orden.css ── */
/*
 * Consola CRUMIA. Reglas del sistema: .claude/rules/diseno/.
 * Se sirve concatenada como /css/app.css (services/css-bundle.js), en el orden
 * de este directorio. Lo de una capa posterior gana a lo de una anterior.
 */
@layer reset, tokens, base, componentes, shell, pantallas;

/* ── 01-tokens.css ── */
/*
 * Tokens: el ÚNICO sitio con valores de color (lo impone test/design-system).
 * Los semánticos se declaran una vez con light-dark(claro, oscuro): el tema lo
 * decide `color-scheme`, que sigue al sistema salvo que `data-theme` lo fije.
 */
@layer tokens {
  :root {
    color-scheme: light dark;

    /* ── Primitivos: no cambian con el tema ── */
    /* La base en el mapa: grafito fijo (el pin es blanco en los dos temas). El logotipo es imagen
       y su rojo no es color de interfaz: el rojo queda para peligro y prioridad. */
    --base-mapa: #3f3f46;
    /* Banderas del manual, con el nombre de FLAG_COLOR (api/services/enums.js). */
    --bandera-gris: #94a3b8;
    --bandera-verde: #16a34a;
    --bandera-rojo: #dc2626;
    --bandera-azul: #2563eb;
    --bandera-amarillo: #eab308;
    --bandera-blanco: #ffffff;
    --bandera-violeta: #7c3aed;
    /* Texto sobre cada bandera sólida, a 4.5:1. */
    --sobre-bandera-gris: #18181b;
    --sobre-bandera-verde: #052e16;
    --sobre-bandera-rojo: #ffffff;
    --sobre-bandera-azul: #ffffff;
    --sobre-bandera-amarillo: #18181b;
    --sobre-bandera-blanco: #18181b;
    --sobre-bandera-violeta: #ffffff;
    /* Blanco sobre un relleno saturado, en los dos temas. */
    --sobre-acento: #ffffff;
    /* Lo que pinta Google sobre blanco (popups del mapa): no cambia con el tema. */
    --sobre-blanco-fijo: #1f2937;
    --sobre-blanco-acento: #a81b21;
    /* Capas del mapa: sobre las teselas de Google, que son claras. */
    --geocerca-1: #4f6d7a;
    --geocerca-2: #7d5a6b;
    --geocerca-3: #5c6f52;
    --geocerca-4: #7a6248;
    --geocerca-5: #4a5c8a;
    --geocerca-6: #6b5b8f;
    --contorno-estado: #24466b;
    --marcador-borde: #d4d4d8;
    --ruta-trazo: #27272a;
    --ruta-inicio: #15803d;
    --ruta-fin: #1d4ed8;
    --ruta-parada: #b45309;

    /* ── Semánticos ── */
    --fondo: light-dark(#f4f4f5, #09090b);
    --superficie: light-dark(#ffffff, #18181b);
    --superficie-2: light-dark(#fafafa, #1f1f23);
    --superficie-hover: light-dark(#f4f4f5, #27272a);
    --superficie-activa: light-dark(#e4e4e7, #3f3f46);
    --borde: light-dark(#e4e4e7, #27272a);
    --borde-fuerte: light-dark(#d4d4d8, #3f3f46);
    --tinta: light-dark(#18181b, #fafafa);
    --tinta-media: light-dark(#52525b, #a1a1aa);
    --tinta-suave: light-dark(#71717a, #8b8b94);
    --primario: light-dark(#18181b, #fafafa);
    --primario-hover: light-dark(#3f3f46, #d4d4d8);
    --sobre-primario: light-dark(#fafafa, #18181b);
    --peligro: #d8232a;
    --peligro-hover: #b91c1c;
    --sobre-peligro: #ffffff;
    --mal-tinta: light-dark(#b91c1c, #f87171);
    --mal-fondo: light-dark(#fef2f2, #2a1215);
    --mal-borde: light-dark(#fecaca, #5c1d20);
    --ok-tinta: light-dark(#15803d, #4ade80);
    --ok-fondo: light-dark(#f0fdf4, #052e16);
    --ok-borde: light-dark(#bbf7d0, #14532d);
    --aviso-tinta: light-dark(#92400e, #fbbf24);
    --aviso-fondo: light-dark(#fffbeb, #2b1d05);
    --aviso-borde: light-dark(#fde68a, #78350f);
    --info-tinta: light-dark(#1d4ed8, #60a5fa);
    --info-fondo: light-dark(#eff6ff, #0c1a33);
    --info-borde: light-dark(#bfdbfe, #1e3a8a);
    --foco: light-dark(#18181b, #fafafa);
    --velo: light-dark(rgb(9 9 11 / 45%), rgb(0 0 0 / 60%));
    --grafica-serie: light-dark(#1f5fd0, #6c9bf0);
    --grafica-pista: light-dark(#eceff3, #27272a);
    --grafica-etiqueta: light-dark(#d4d4d8, #3f3f46);
    --sombra-panel:
      0 1px 2px light-dark(rgb(9 9 11 / 5%), rgb(0 0 0 / 30%)),
      0 2px 8px light-dark(rgb(9 9 11 / 4%), rgb(0 0 0 / 20%));
    --sombra-flotante:
      0 16px 40px light-dark(rgb(9 9 11 / 14%), rgb(0 0 0 / 55%)),
      0 2px 8px light-dark(rgb(9 9 11 / 8%), rgb(0 0 0 / 40%));

    /* ── Tipografía ── */
    --fuente: 'Inter', system-ui, 'Segoe UI', Roboto, sans-serif;
    --mono: ui-monospace, Consolas, monospace;
    --txt-2xs: 11px;
    --txt-xs: 12px;
    --txt-base: 13px;
    --txt-md: 14px;
    --txt-lg: 16px;
    --txt-xl: 18px;
    --txt-2xl: 22px;
    --txt-3xl: 28px;

    /* ── Espacio, forma y densidad compacta ── */
    --sp-1: 2px;
    --sp-2: 4px;
    --sp-3: 6px;
    --sp-4: 8px;
    --sp-5: 12px;
    --sp-6: 16px;
    --sp-7: 20px;
    --sp-8: 24px;
    --sp-9: 32px;
    --radio-sm: 6px;
    --radio: 8px;
    --radio-lg: 12px;
    --radio-xl: 16px;
    --radio-pill: 999px;
    --alto-control: 32px;
    --alto-control-sm: 28px;
    --alto-fila: 32px;
    --alto-cabecera: 44px;
    --riel-abierto: 240px;
    --riel-cerrado: 56px;
    --panel-lateral: 520px;
    --panel-lateral-ancho: 720px;
    --pad: var(--sp-5);
    --gap: var(--sp-5);

    /* ── Apilado (los modales van en la capa superior nativa) ── */
    --z-tabla: 1;
    --z-desplegable: 20;
    --z-panel-lateral: 40;
    --z-barra: 30;
    --z-cabecera: 31;
    --z-previo: 60;
    --z-menu-movil: 50;
  }

  /* 21" en adelante: el texto base sube a 14 px (cliente, 2026-09-25) y el panel lateral gana ancho. */
  @media (width >= 1920px) {
    :root {
      --txt-base: 14px;
      --txt-md: 15px;
      --panel-lateral: 600px;
      --panel-lateral-ancho: 840px;
    }
  }

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

/* ── 02-base.css ── */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }

  /* `[hidden]` gana a cualquier `display` propio: sin esto los botones que el
     menú de facultades ocultaba (`.boton` es inline-flex) se seguían viendo. */
  [hidden] { display: none !important; }
}

@layer base {
  body {
    margin: 0;
    font-family: var(--fuente);
    font-size: var(--txt-base);
    line-height: 1.5;
    color: var(--tinta);
    background: var(--fondo);
    font-optical-sizing: auto;
    -webkit-font-smoothing: antialiased;
  }

  h1, h2, h3 { line-height: 1.25; }
  img { max-width: 100%; }
  a { color: inherit; }

  /* Un solo anillo de foco, neutro y visible en los dos temas. */
  :where(a, button, input, select, textarea, [tabindex], summary, dialog):focus-visible {
    outline: 2px solid var(--foco);
    outline-offset: 2px;
  }

  /* ── Controles: por elemento, para que una pantalla nueva funcione sin reglas propias ── */
  input:not([type='checkbox'], [type='radio'], [type='file'], [type='range'], [type='color']),
  select,
  textarea {
    min-height: var(--alto-control);
    padding: 0 var(--sp-4);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio);
    font-family: inherit;
    font-size: var(--txt-base);
    font-weight: 400;
    line-height: 1.5;
    color: var(--tinta);
    background: var(--superficie);
    min-width: 0;
  }

  textarea { padding: var(--sp-3) var(--sp-4); resize: vertical; }
  input::placeholder, textarea::placeholder { color: var(--tinta-suave); }
  input:focus, select:focus, textarea:focus { border-color: var(--tinta); }
  input:disabled, select:disabled, textarea:disabled { background: var(--superficie-2); color: var(--tinta-suave); }
  input[type='checkbox'], input[type='radio'] { width: 16px; height: 16px; margin: 0; accent-color: var(--primario); }
  input[type='file'] { font: inherit; font-size: var(--txt-xs); }

  label {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    font-size: var(--txt-xs);
    font-weight: 500;
    color: var(--tinta-media);
  }

  fieldset {
    min-width: 0;
    margin: 0 var(--pad) var(--pad);
    padding: var(--sp-5) var(--pad) var(--pad);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
  }

  legend { padding: 0 var(--sp-3); font-size: var(--txt-base); font-weight: 600; color: var(--tinta); }

  kbd {
    padding: var(--sp-1) var(--sp-3);
    border: 1px solid var(--borde-fuerte);
    border-bottom-width: 2px;
    border-radius: var(--radio-sm);
    background: var(--superficie);
    color: var(--tinta-media);
    font: 500 var(--txt-2xs) / 1 var(--fuente);
  }

  code { font-family: var(--mono); font-size: var(--txt-xs); }

  /* ── Texto de apoyo y utilidades ── */
  .num { text-align: right; font-variant-numeric: tabular-nums; }
  .ancho-completo, .ancho-total { grid-column: 1 / -1; }
  .secundario { color: var(--tinta-suave); font-size: var(--txt-base); padding: 0 var(--pad); }
  .vacio { color: var(--tinta-suave); }

  .ayuda {
    display: block;
    margin-top: var(--sp-2);
    color: var(--tinta-suave);
    font-size: var(--txt-xs);
    font-weight: 400;
  }

  /* Botón que se ve como enlace: abre un modal, así que no es un <a href>. */
  .enlace {
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    color: var(--tinta);
    text-decoration: underline;
    text-decoration-color: var(--borde-fuerte);
    text-underline-offset: 2px;
    cursor: pointer;
  }

  .enlace:hover { text-decoration-color: currentColor; }

  .error {
    margin: 0 var(--pad);
    padding: var(--sp-4) var(--sp-5);
    border: 1px solid var(--mal-borde);
    border-radius: var(--radio);
    background: var(--mal-fondo);
    color: var(--mal-tinta);
    font-size: var(--txt-base);
  }

  .exito {
    margin: 0 var(--pad) var(--sp-5);
    padding: var(--sp-4) var(--sp-5);
    border: 1px solid var(--ok-borde);
    border-radius: var(--radio);
    background: var(--ok-fondo);
    color: var(--ok-tinta);
    font-size: var(--txt-base);
  }

  /* El margen del panel no se suma dentro de algo que ya tiene el suyo. */
  :is(.llamada-pendiente, .tarjeta, .ficha-tarjeta, .ficha-destacados, .vista-previa, .candidata,
    .stepper-resumen, .panel-interno, .tarjeta-acceso, .casilla, fieldset) .secundario {
    padding-inline: 0;
  }
}

/* ── 03-shell.css ── */
/* El shell: riel, cabecera global y barra de página (.claude/rules/diseno/distribucion.md). */
@layer shell {
  .app {
    --ancho-riel: var(--riel-abierto);
    display: grid;
    grid-template-columns: var(--ancho-riel) minmax(0, 1fr);
    min-height: 100vh;
    min-height: 100dvh;
  }

  :root[data-riel='cerrado'] .app { --ancho-riel: var(--riel-cerrado); }

  .saltar { position: absolute; left: var(--sp-4); top: -48px; z-index: 100; }
  .saltar:focus { top: var(--sp-4); }

  /* ── Riel ── */
  .riel {
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100dvh;
    display: flex;
    flex-direction: column;
    background: var(--superficie);
    border-right: 1px solid var(--borde);
    container: riel / inline-size;
  }

  .marca {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
    height: var(--alto-cabecera);
    padding: 0 18px;
    border-bottom: 1px solid var(--borde);
    color: var(--tinta);
    text-decoration: none;
    font-size: var(--txt-md);
    font-weight: 600;
    letter-spacing: 0.02em;
  }

  /* Abierto, la palabra; plegado, la «C» del mismo logotipo. */
  .logo-palabra { flex: none; width: auto; height: 18px; }
  .logo { display: none; flex: none; width: 22px; height: 22px; }

  .menu {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: var(--sp-5);
    padding: var(--sp-4);
  }

  /* No se enseña hasta saber qué puede ver cada quien (lo levanta app.js). */
  .menu[data-permisos='pendiente'] { visibility: hidden; }

  .menu-grupo ul { display: flex; flex-direction: column; gap: 1px; margin: 0; padding: 0; list-style: none; }

  .menu-grupo-titulo {
    display: block;
    padding: var(--sp-2) var(--sp-4) var(--sp-3);
    font-size: var(--txt-2xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    color: var(--tinta-suave);
  }

  .enlace-menu {
    display: flex;
    align-items: center;
    gap: 10px;
    height: var(--alto-control);
    padding: 0 var(--sp-4);
    overflow: hidden;
    border-radius: var(--radio);
    color: var(--tinta-media);
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
  }

  .enlace-menu i { --fa-width: 1.25em; flex: none; font-size: var(--txt-md); }
  .enlace-menu span { overflow: hidden; text-overflow: ellipsis; }
  .enlace-menu:hover { background: var(--superficie-hover); color: var(--tinta); }

  /* El activo es neutro: el rojo es marca o peligro. */
  .enlace-menu.activo { background: var(--superficie-activa); color: var(--tinta); font-weight: 600; }

  .pie-riel { padding: var(--sp-4); border-top: 1px solid var(--borde); }
  .pie-riel .boton { width: 100%; justify-content: flex-start; }
  :root[data-riel='cerrado'] #plegar-riel i { transform: scaleX(-1); }

  /* Plegado —por elección o por ancho—: solo iconos, con el nombre en `title`. */
  @container riel (width < 120px) {
    .marca { justify-content: center; padding: 0; }
    .logo-palabra, .enlace-menu span, .pie-riel .boton span { display: none; }
    .logo { display: block; }
    .menu-grupo-titulo { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
    .menu-grupo:not([hidden]) ~ .menu-grupo:not([hidden]) { padding-top: var(--sp-5); border-top: 1px solid var(--borde); }
    .enlace-menu, .pie-riel .boton { justify-content: center; padding: 0; }
  }

  /* ── Cabecera global ── */
  .contenido { display: flex; flex-direction: column; min-width: 0; }

  .cabecera {
    position: sticky;
    top: 0;
    z-index: var(--z-cabecera);
    display: flex;
    align-items: center;
    gap: var(--sp-5);
    height: var(--alto-cabecera);
    padding: 0 var(--sp-6);
    background: var(--superficie);
    border-bottom: 1px solid var(--borde);
  }

  .disparador-paleta {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    width: min(400px, 40vw);
    height: var(--alto-control);
    padding: 0 var(--sp-3) 0 10px;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--superficie-2);
    color: var(--tinta-suave);
    font: inherit;
    cursor: pointer;
  }

  .disparador-paleta:hover { border-color: var(--borde-fuerte); color: var(--tinta-media); }
  .disparador-paleta span { flex: 1; overflow: hidden; text-align: left; text-overflow: ellipsis; white-space: nowrap; }

  .identidad { display: flex; align-items: center; gap: var(--sp-4); margin-left: auto; }

  .ambito { flex-direction: row; align-items: center; gap: var(--sp-3); color: var(--tinta-media); }
  .ambito-etiqueta { font-size: var(--txt-2xs); letter-spacing: 0.04em; text-transform: uppercase; }
  .ambito-select { max-width: 220px; font-weight: 500; }

  /* Mirando otro estado: el selector también lo dice en rojo, como el aviso. */
  .ambito[data-otro-estado] { color: var(--mal-tinta); }
  .ambito[data-otro-estado] .ambito-select { border-color: var(--peligro); color: var(--mal-tinta); }

  .usuario {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    padding-left: var(--sp-4);
    border-left: 1px solid var(--borde);
  }

  .usuario > i { font-size: var(--txt-xl); color: var(--tinta-suave); }
  .usuario-texto { display: flex; flex-direction: column; line-height: 1.25; }
  .usuario .nombre { font-weight: 500; }
  .etiqueta-perfil { font-size: var(--txt-2xs); color: var(--tinta-suave); }

  /* ── Avisos de la sesión: pueden concurrir varios, se apilan ── */
  .aviso-guardia { border-bottom: 1px solid var(--borde); }

  .linea-aviso {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    margin: 0;
    padding: var(--sp-3) var(--sp-7);
    background: var(--info-fondo);
    color: var(--info-tinta);
  }

  .linea-aviso + .linea-aviso { border-top: 1px solid var(--borde); }
  .linea-aviso-aviso { background: var(--aviso-fondo); color: var(--aviso-tinta); }
  .linea-aviso-error { background: var(--mal-fondo); color: var(--mal-tinta); font-weight: 500; }

  /* ── Área principal y barra de página ── */
  .area-principal { display: flex; flex: 1; flex-direction: column; min-width: 0; }

  .barra-pagina {
    position: sticky;
    top: var(--alto-cabecera);
    z-index: var(--z-barra);
    padding: var(--sp-5) var(--sp-7) 0;
    background: var(--superficie);
    border-bottom: 1px solid var(--borde);
  }

  .barra-pagina.sin-pestanas { padding-bottom: var(--sp-5); }

  .ruta { display: flex; align-items: center; gap: var(--sp-3); font-size: var(--txt-2xs); color: var(--tinta-suave); }
  .ruta a { color: inherit; text-decoration: none; }
  .ruta a:hover { color: var(--tinta); text-decoration: underline; }
  .ruta i { font-size: var(--txt-2xs); }

  /* Con el panel lateral abierto la barra se estrecha: las acciones bajan de línea, no se salen. */
  .titulo-fila { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3) var(--sp-5); min-height: var(--alto-control); margin-top: var(--sp-1); }
  .titulo-fila h1 { margin: 0; font-size: var(--txt-xl); font-weight: 600; letter-spacing: -0.01em; }
  .acciones-pagina { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); margin-left: auto; }
  .acciones-pagina:empty { display: none; }
  /* Cada acción es de su pestaña (tabs.js): no se usa [hidden], que es de las facultades. */
  .acciones-pagina [data-otra-pestana] { display: none; }

  /* Puestos de trabajo: una línea, para no robar alto a sus columnas. */
  .barra-pagina.compacta { display: flex; align-items: center; gap: var(--sp-5); padding: var(--sp-3) var(--sp-6); }
  .barra-pagina.compacta .titulo-fila { flex: 1; margin: 0; }
  .barra-pagina.compacta h1 { font-size: var(--txt-md); }

  /* El puesto no desplaza: lo hacen sus columnas, y la cola y la flota siguen a la vista. */
  .contenido:has(.puesto) { height: 100vh; height: 100dvh; overflow: hidden; }
  .area-principal:has(.puesto) { min-height: 0; }
  .cuerpo-pagina:has(> .puesto) { display: flex; flex: 1; flex-direction: column; min-height: 0; padding: var(--gap); }
  .puesto { flex: 1; min-height: 0; }

  /* ── Pestañas del módulo (las declara services/menu.js) ── */
  .pestanas { display: flex; gap: var(--sp-2); margin-top: var(--sp-3); overflow-x: auto; }

  .pestana {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-3);
    height: 36px;
    margin-bottom: -1px;
    padding: 0 var(--sp-4);
    border: 0;
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--tinta-media);
    font: inherit;
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
  }

  .pestana:hover { color: var(--tinta); }
  .pestana.activa { color: var(--tinta); font-weight: 600; border-bottom-color: var(--tinta); }

  .cuenta {
    display: inline-flex;
    align-items: center;
    height: 18px;
    padding: 0 var(--sp-3);
    border-radius: var(--radio-pill);
    background: var(--superficie-activa);
    color: var(--tinta-media);
    font-size: var(--txt-2xs);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  .cuerpo-pagina { padding: var(--sp-6) var(--sp-7); }

  /* Hasta que Firebase confirma la sesión no se enseña el interior (tema.ejs). */
  :root[data-sesion='pendiente'] .cuerpo-pagina { visibility: hidden; }

  /* El botón del menú y su velo solo existen en móvil. */
  .abrir-menu, .velo-menu { display: none; }

  /* Por debajo de 1280 px el riel se pliega solo. */
  @media (width < 1280px) {
    .app { --ancho-riel: var(--riel-cerrado); }
    .pie-riel { display: none; }
    .disparador-paleta span { display: none; }
    .disparador-paleta { width: auto; }
  }

  /* Puestos por debajo de 1024 px: las columnas se apilan y la página vuelve a desplazar. */
  @media (width < 1024px) {
    .contenido:has(.puesto) { height: auto; overflow: visible; }
    .cuerpo-pagina:has(> .puesto) { display: block; }
    /* Su barra de una línea también se apila: ruta, título y acciones. */
    .barra-pagina.compacta { display: block; }
    .barra-pagina.compacta .titulo-fila { margin-top: var(--sp-1); }
  }

  /* Móvil (< 768 px): el riel sale como cajón sobre la página; la cabecera se queda con lo esencial. */
  @media (width < 768px) {
    .app { grid-template-columns: minmax(0, 1fr); }

    .riel {
      position: fixed;
      inset: 0 auto 0 0;
      z-index: var(--z-menu-movil);
      display: none;
      width: min(var(--riel-abierto), 85vw);
      box-shadow: var(--sombra-flotante);
    }

    .app[data-menu='abierto'] .riel { display: flex; }
    .app[data-menu='abierto'] .velo-menu { display: block; position: fixed; inset: 0; z-index: calc(var(--z-menu-movil) - 1); background: var(--velo); }
    .abrir-menu { display: inline-flex; }

    .cabecera { gap: var(--sp-3); padding: 0 var(--sp-4); }
    .disparador-paleta { flex: none; justify-content: center; width: var(--alto-control); padding: 0; }
    .disparador-paleta kbd, .usuario-texto, .ambito-etiqueta { display: none; }
    .ambito-select { max-width: 120px; }

    .barra-pagina { padding: var(--sp-4) var(--sp-5) 0; }
    .barra-pagina.sin-pestanas { padding-bottom: var(--sp-4); }
    .barra-pagina.compacta { padding: var(--sp-4) var(--sp-5); }
    .acciones-pagina { width: 100%; margin-left: 0; }
    .cuerpo-pagina { padding: var(--sp-5); }
    .linea-aviso { padding: var(--sp-3) var(--sp-5); }
  }

  /* 21" en adelante (≥ 1920 px): más aire, la misma densidad. */
  @media (width >= 1920px) {
    .cuerpo-pagina { padding: var(--sp-8) var(--sp-9); }
  }
}

/* ── componentes/avisos.css ── */
/* Avisos en línea. Los errores no se van solos: se quedan en su sitio. */
@layer componentes {
  .aviso {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-5);
    padding: var(--sp-4) var(--pad);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
  }

  .aviso > i { margin-top: 3px; }
  .aviso p { flex: 1; margin: 0; }
  .aviso > .boton { align-self: center; }
  .aviso-info { border-color: var(--info-borde); background: var(--info-fondo); }
  .aviso-info > i { color: var(--info-tinta); }
  .aviso-aviso { border-color: var(--aviso-borde); background: var(--aviso-fondo); }
  .aviso-aviso > i { color: var(--aviso-tinta); }
  .aviso-error { border-color: var(--mal-borde); background: var(--mal-fondo); }
  .aviso-error > i { color: var(--mal-tinta); }
  .aviso-ok { border-color: var(--ok-borde); background: var(--ok-fondo); }
  .aviso-ok > i { color: var(--ok-tinta); }

  /* Banda informativa de radio y la nota de pantalla-propuesta (Estadísticas). */
  .aviso-informativo, .nota-propuesta {
    margin: 0 0 var(--gap);
    padding: var(--sp-4) var(--pad);
    border: 1px solid var(--info-borde);
    border-radius: var(--radio);
    background: var(--info-fondo);
    color: var(--info-tinta);
  }

  .mensaje { margin: 0; }

  /* Un aviso suelto en el cuerpo de la página (Buzón de seguridad, «Traer del proveedor») respira contra lo de abajo. */
  .cuerpo-pagina > .aviso { margin-bottom: var(--gap); }

  /* notificar(): confirmaciones que se van a los 5 s. Capa superior (popover). */
  .avisos-flotantes {
    inset: calc(var(--alto-cabecera) + var(--sp-4)) var(--sp-6) auto auto;
    margin: 0;
    padding: 0;
    overflow: visible;
    border: 0;
    background: transparent;
    pointer-events: none;
  }

  .avisos-flotantes:popover-open { display: flex; flex-direction: column; gap: var(--sp-4); }

  .toast {
    display: flex;
    align-items: center;
    gap: var(--sp-5);
    width: 340px;
    padding: var(--sp-4) var(--sp-4) var(--sp-4) var(--pad);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    background: var(--superficie);
    color: var(--tinta);
    box-shadow: var(--sombra-flotante);
    pointer-events: auto;
  }

  .toast > i { font-size: var(--txt-lg); color: var(--ok-tinta); }
  .toast.info > i { color: var(--info-tinta); }
  .toast p { flex: 1; margin: 0; font-weight: 500; }
}

/* ── componentes/bitacora.css ── */
/* Comentarios e historial de un servicio (bitacora-servicio.js): cierre y Consola de radio. */
@layer componentes {
  .comentarios, .historial { margin: 0; padding: var(--sp-4) var(--pad); list-style: none; }
  .comentarios li, .historial li { padding: var(--sp-4) 0; border-bottom: 1px solid var(--borde); }
  .comentarios li:last-child, .historial li:last-child { border-bottom: 0; }
  .comentarios .autor { margin: 0; color: var(--tinta-suave); font-size: var(--txt-xs); }
  .comentarios .texto { margin: var(--sp-2) 0 0; color: var(--tinta); }
  .historial .evento { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--sp-6); }
  .historial .evento strong { color: var(--tinta); }

  /* El antes y el después de cada campo corregido. */
  .cambios { margin: var(--sp-3) 0 0; padding: 0 0 0 var(--sp-6); font-size: var(--txt-xs); list-style: none; }
  .cambios li { padding: var(--sp-1) 0; border: 0; }
  .cambios s { color: var(--tinta-suave); }
}

/* ── componentes/botones.css ── */
@layer componentes {
  .boton {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-3);
    height: var(--alto-control);
    padding: 0 var(--sp-5);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio);
    background: var(--superficie);
    color: var(--tinta);
    font-family: inherit;
    font-size: var(--txt-base);
    font-weight: 500;
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
  }

  .boton:hover:not(:disabled) { background: var(--superficie-hover); }
  .boton:disabled, .boton[aria-busy='true'] { opacity: 0.55; cursor: not-allowed; }
  .boton i { font-size: var(--txt-md); }

  /* Afirmar va en grafito; el rojo queda para marca y peligro. */
  .boton-primario { background: var(--primario); border-color: var(--primario); color: var(--sobre-primario); }

  .boton-primario:hover:not(:disabled) { background: var(--primario-hover); border-color: var(--primario-hover); }

  .boton-peligro { background: var(--peligro); border-color: var(--peligro); color: var(--sobre-peligro); font-weight: 600; }
  .boton-peligro:hover:not(:disabled) { background: var(--peligro-hover); border-color: var(--peligro-hover); }

  /* Sin fondo. Solo o sobre `.boton` (entonces conserva su alto). */
  .boton-texto {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-2) var(--sp-4);
    border: 1px solid transparent;
    border-radius: var(--radio);
    background: none;
    color: var(--tinta-media);
    font: inherit;
    cursor: pointer;
  }

  .boton.boton-texto { padding: 0 var(--sp-4); border-color: transparent; background: transparent; }
  .boton-texto:hover:not(:disabled) { background: var(--superficie-hover); color: var(--tinta); }
  .boton-texto:disabled { opacity: 0.4; cursor: default; }
  .boton-texto.peligro { color: var(--mal-tinta); }

  /* Solo icono: lleva `aria-label` y `title` con el texto literal. */
  .boton.boton-icono { width: var(--alto-control); padding: 0; }
  .boton-icono i { font-size: var(--txt-lg); }

  .boton.pequeno { height: var(--alto-control-sm); padding: 0 var(--sp-4); font-size: var(--txt-xs); }
  .boton.boton-icono.pequeno { width: var(--alto-control-sm); padding: 0; }
  .boton.pequeno i { font-size: var(--txt-xs); }
}

/* ── componentes/buscador.css ── */
/* Buscador con selección por id (autocomplete.js): para lo que no cabe en un <select>. */
@layer componentes {
  .buscador { position: relative; }
  .buscador-caja { width: 100%; }

  /* Posicionada: si empujara, elegir a alguien movería los campos de debajo. */
  .buscador-resultados {
    position: absolute;
    z-index: var(--z-desplegable);
    top: calc(100% + 4px);
    right: 0;
    left: 0;
    max-height: 280px;
    padding: var(--sp-2);
    overflow-y: auto;
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    background: var(--superficie);
    box-shadow: var(--sombra-flotante);
  }

  .buscador-opcion {
    display: block;
    width: 100%;
    padding: var(--sp-3) var(--sp-4);
    border: 0;
    border-radius: var(--radio-sm);
    background: none;
    color: var(--tinta);
    font: inherit;
    font-size: var(--txt-base);
    font-weight: 400;
    text-align: left;
    cursor: pointer;
  }

  .buscador-opcion:hover, .buscador-opcion.activa { background: var(--superficie-activa); }
  .buscador-opcion small { display: block; color: var(--tinta-suave); font-size: var(--txt-xs); }

  /* «Coinciden N y se muestran 20»: una lista corta que lo dice. */
  .buscador-aviso {
    margin: var(--sp-2) 0 0;
    padding: var(--sp-3) var(--sp-4);
    border-top: 1px solid var(--borde);
    color: var(--tinta-suave);
    font-size: var(--txt-xs);
    font-weight: 400;
  }

  .buscador-aviso.error { border-radius: var(--radio-sm); background: var(--mal-fondo); color: var(--mal-tinta); }
}

/* ── componentes/carrusel.css ── */
/* Carrusel de noticias (docs/01 §6-C): lo usan la Consola (inicio) y la ficha de Noticias, con el mismo marcado. */
@layer componentes {
  .carrusel { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--sp-5); padding: var(--pad); }

  .carrusel-flecha {
    display: inline-grid;
    place-items: center;
    width: var(--alto-control);
    height: var(--alto-control);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio-pill);
    background: var(--superficie);
    color: var(--tinta-media);
    cursor: pointer;
  }

  .carrusel-flecha:hover { background: var(--superficie-hover); color: var(--tinta); }
  .carrusel-contenido h3 { margin: 0 0 var(--sp-2); font-size: var(--txt-md); }
  .carrusel-contenido p { margin: 0 0 var(--sp-3); }
  .carrusel-contenido p:last-child { margin-bottom: 0; }
  .carrusel-indicador { margin: 0; padding: 0 var(--pad) var(--sp-5); color: var(--tinta-suave); font-size: var(--txt-xs); text-align: center; font-variant-numeric: tabular-nums; }
}

/* ── componentes/estatus.css ── */
/* Estatus con los tonos del manual: bandera, leyenda, distintivos y etiquetas. */
@layer componentes {
  /* La bandera cuadrada del original: 14 px de color del manual. */
  .bandera {
    display: inline-block;
    width: 14px;
    height: 14px;
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio-sm);
    vertical-align: middle;
    flex: none;
  }

  .bandera-gris { background: var(--bandera-gris); }
  .bandera-verde { background: var(--bandera-verde); }
  .bandera-rojo { background: var(--bandera-rojo); }
  .bandera-azul { background: var(--bandera-azul); }
  .bandera-amarillo { background: var(--bandera-amarillo); }
  .bandera-blanco { background: var(--bandera-blanco); }
  .bandera-violeta { background: var(--bandera-violeta); }

  .leyenda-banderas {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
    gap: var(--sp-4) var(--gap);
    margin: 0;
    padding: var(--pad);
    list-style: none;
  }

  .leyenda-banderas li { display: flex; align-items: center; gap: var(--sp-4); }

  /* La leyenda en una línea, al pie del mapa (Consola de inicio). */
  .leyenda-banderas.en-linea { display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-6); padding: var(--sp-4) var(--pad); border-top: 1px solid var(--borde); color: var(--tinta-media); font-size: var(--txt-xs); }
  .leyenda-banderas.en-linea li { gap: var(--sp-3); }

  /* La base en la leyenda: mismo color que su marcador en el mapa (--base-mapa). */
  .leyenda-base {
    display: inline-grid;
    place-items: center;
    width: 16px;
    height: 16px;
    border-radius: var(--radio-pill);
    background: var(--base-mapa);
    color: var(--sobre-acento);
    font-size: var(--txt-2xs);
  }

  /* Estado de un registro (no de una unidad): píldora con punto. */
  .distintivo {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-3);
    height: 22px;
    padding: 0 var(--sp-4);
    border: 1px solid var(--borde);
    border-radius: var(--radio-pill);
    background: var(--superficie-2);
    color: var(--tinta-media);
    font-size: var(--txt-xs);
    font-weight: 500;
    white-space: nowrap;
  }

  .distintivo::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
  .distintivo-activa { border-color: var(--ok-borde); background: var(--ok-fondo); color: var(--ok-tinta); }
  .distintivo-inactiva, .distintivo-vencido { border-color: var(--mal-borde); background: var(--mal-fondo); color: var(--mal-tinta); }
  .distintivo-neutro { background: var(--superficie-activa); color: var(--tinta-media); }
  /* Pide atención sin ser un error: Pendiente, Testigo encendido, Sin reportar, Solicitada. */
  .distintivo-aviso { border-color: var(--aviso-borde); background: var(--aviso-fondo); color: var(--aviso-tinta); }

  /* Estado de una extracción o de un evento de telemática. */
  .etiqueta {
    display: inline-flex;
    align-items: center;
    height: 22px;
    padding: 0 var(--sp-4);
    border-radius: var(--radio-pill);
    background: var(--superficie-activa);
    color: var(--tinta-media);
    font-size: var(--txt-xs);
    white-space: nowrap;
  }

  .etiqueta.solicitada, .etiqueta.pendiente { background: var(--aviso-fondo); color: var(--aviso-tinta); }
  .etiqueta.disponible, .etiqueta.revisado { background: var(--ok-fondo); color: var(--ok-tinta); }
  .etiqueta.fallida, .etiqueta.caducada { background: var(--mal-fondo); color: var(--mal-tinta); }
  .etiqueta.descartado { color: var(--tinta-suave); }

  /* Semáforo: icono más texto oculto, nunca solo color. */
  .semaforo-si { color: var(--ok-tinta); }
  .semaforo-no { color: var(--mal-tinta); }
}

/* ── componentes/ficha.css ── */
/* Ficha de solo lectura (fichaHtml): tarjetas por tema y los destacados arriba. */
@layer componentes {
  .ficha { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr)); gap: var(--gap); }

  .ficha-tarjeta {
    grid-column: 1 / -1;
    padding: var(--pad);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    background: var(--superficie);
  }

  .ficha-tarjeta.compacta { grid-column: auto; }

  /* Una tabla secundaria dentro de una tarjeta (el consolidado de SCI): sin
     esto, `.tabla` (min-width: max-content) ensancha la columna y se sale
     del panel. Desplaza por dentro con un tope, no con el alto del panel. */
  .ficha-tarjeta:has(> .tabla-contenedor) { min-width: 0; }
  .ficha-tarjeta > .tabla-controles { padding: 0 0 var(--sp-4); border-bottom: 0; }
  .ficha-tarjeta > .tabla-contenedor { max-height: 360px; border: 1px solid var(--borde); border-radius: var(--radio); }

  .ficha-tarjeta h3 {
    display: flex;
    align-items: baseline;
    gap: var(--sp-4);
    margin: 0 0 var(--sp-5);
    font-size: var(--txt-2xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tinta-suave);
  }

  /* Aclaración del bloque: en la cabecera, donde se lee. */
  .ficha-nota { margin-left: auto; font-weight: 400; letter-spacing: 0; text-transform: none; }

  /* La acción de una tarjeta, en su cabecera y junto a lo que modifica. */
  .ficha-tarjeta h3 .ficha-accion {
    margin: calc(var(--sp-2) * -1) 0 calc(var(--sp-2) * -1) auto;
    color: var(--tinta);
    font-size: var(--txt-xs);
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
  }

  /* Más de una acción en la cabecera de una tarjeta (p. ej. cámara: comprobar, foto, pedir). */
  .ficha-acciones { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-left: auto; }
  .ficha-tarjeta h3 .ficha-acciones .ficha-accion { margin: 0; }

  /* El hueco entre piezas de una tarjeta con más de un bloque propio (foto, resumen, tabla, mapa). */
  .ficha-tarjeta > :is(figure, .tabla-contenedor, .mapa-ruta, p, div):not(:last-child) { margin-bottom: var(--gap); }

  .ficha-destacados {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr));
    gap: var(--sp-4);
  }

  .ficha-destacado {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    min-width: 0;
    padding: var(--sp-4) 10px;
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--superficie-2);
  }

  .ficha-destacado-etiqueta { font-size: var(--txt-2xs); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--tinta-suave); }
  .ficha-destacado strong { font-size: var(--txt-md); font-weight: 600; overflow-wrap: anywhere; }
  .ficha-destacado strong .distintivo { font-size: var(--txt-xs); font-weight: 500; }

  .ficha-datos {
    display: grid;
    grid-template-columns: repeat(var(--columnas, 2), minmax(0, 1fr));
    gap: var(--sp-4) var(--gap);
    margin: 0;
  }

  .ficha-datos dt { margin-bottom: var(--sp-1); color: var(--tinta-suave); font-size: var(--txt-xs); }
  .ficha-datos dd { margin: 0; overflow-wrap: anywhere; }
  /* Un dato que ocupa la fila entera (un texto largo, como «Información extra del servicio»). */
  .ficha-datos > .ancho-total { grid-column: 1 / -1; }

  /* El minimapa debajo de los datos de su tarjeta (Buzón de seguridad, «Dónde»). */
  .ficha-datos + .minimapa { margin-top: var(--sp-5); }

  @media (width < 720px) {
    .ficha-datos { grid-template-columns: 1fr; }
  }

  /* Una credencial por línea en la tarjeta «Credencial CRUMIA» (Usuarios y
     Credenciales, pantallas.md §14): folio, estatus y fecha, con sus
     acciones a la derecha. */
  .linea-credencial { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-4); }
  .linea-credencial > small { color: var(--tinta-suave); font-size: var(--txt-xs); }
  .linea-credencial > .acciones-fila { gap: 0; margin-left: auto; }
}

/* ── componentes/filtros.css ── */
/* Filtros (filtros.js): principales a la vista, el resto plegado, lo aplicado como etiquetas. */
@layer componentes {
  .filtros-cabecera {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-4) var(--gap);
    padding: var(--sp-4) var(--pad);
    border-bottom: 1px solid var(--borde);
  }

  .filtros-rangos { display: flex; gap: var(--sp-3); }

  .chip-rango {
    display: inline-flex;
    align-items: center;
    height: 26px;
    padding: 0 var(--sp-4);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio-pill);
    background: var(--superficie);
    color: var(--tinta-media);
    font: inherit;
    font-size: var(--txt-xs);
    font-weight: 500;
    cursor: pointer;
  }

  .chip-rango:hover { background: var(--superficie-hover); color: var(--tinta); }
  .chip-rango[aria-pressed='true'] { border-color: var(--primario); background: var(--primario); color: var(--sobre-primario); }

  .filtros-activos { display: flex; flex: 1; flex-wrap: wrap; gap: var(--sp-3); min-width: 0; }

  .chip-filtro {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-3);
    max-width: 100%;
    height: 26px;
    padding: 0 var(--sp-2) 0 var(--sp-4);
    border-radius: var(--radio-pill);
    background: var(--superficie-activa);
    color: var(--tinta);
    font-size: var(--txt-xs);
  }

  .chip-filtro b { font-weight: 600; color: var(--tinta-media); }

  .chip-filtro button {
    display: inline-grid;
    place-items: center;
    width: 18px;
    height: 18px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: none;
    color: var(--tinta-media);
    cursor: pointer;
  }

  .chip-filtro button:hover { background: var(--borde-fuerte); color: var(--tinta); }
  .chip-filtro button i { font-size: var(--txt-2xs); }

  .filtros-acciones { display: flex; align-items: center; gap: var(--sp-4); margin-left: auto; }

  /* La rejilla del panel de filtros (4 columnas, como el original). */
  .rejilla-filtros {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
    gap: var(--gap);
    padding: var(--pad);
  }

  .rejilla-filtros .ancho-doble { grid-column: span 2; }

  /* Los principales primero: la plantilla conserva el orden del manual y aquí manda el uso. */
  .rejilla-filtros label[data-principal] { order: -1; }

  .acciones-filtros { display: flex; grid-column: 1 / -1; justify-content: flex-end; }
}

/* ── componentes/formularios.css ── */
/* Campos de un formulario de página (acceso, registro). Los de modal los arma modal.js. */
@layer componentes {
  /* Campo con etiqueta explícita (`for`): admite un botón dentro y el error debajo. */
  .campo { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
  .campo > label { display: block; }

  /* Obligatorio: asterisco en tinta suave; el control lleva `required`. */
  .obligatorio { color: var(--tinta-suave); font-weight: 400; }

  /* Error de UN campo, debajo de él: «Campo obligatorio» o `detalles[].mensaje` de la API. */
  .campo-error {
    display: flex;
    gap: var(--sp-3);
    margin: 0;
    color: var(--mal-tinta);
    font-size: var(--txt-xs);
  }

  .campo-error > i { margin-top: 3px; }
  :is(input, select, textarea)[aria-invalid='true'] { border-color: var(--mal-tinta); }

  /* Aviso bajo un campo que no impide guardar (operador no habilitado, colonia ya existente). */
  .campo-aviso { display: block; margin: var(--sp-2) 0 0; color: var(--aviso-tinta); font-size: var(--txt-xs); font-weight: 500; }

  /* Secciones de un formulario de página: título y rejilla, sin caja dentro de la tarjeta. */
  .grupo-campos { margin: 0; padding: 0; border: 0; }

  .grupo-campos > legend {
    padding: 0 0 var(--sp-4);
    color: var(--tinta-suave);
    font-size: var(--txt-2xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }

  .rejilla-campos {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr));
    gap: var(--sp-5) var(--gap);
  }

  /* Pie de un formulario de página: el botón principal a la derecha (Cierre). */
  .acciones-formulario { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-4); }

  /* Contraseña con «Mostrar» dentro del campo (docs/01 §5). */
  .campo-clave { position: relative; display: grid; }
  .campo-clave > input { padding-right: 76px; }

  .campo-clave > .boton-texto {
    position: absolute;
    inset: 3px 3px 3px auto;
    padding: 0 var(--sp-4);
    font-size: var(--txt-xs);
    font-weight: 500;
  }
}

/* ── componentes/graficas.css ── */
/* Gráficas: las comparten Estadísticas y Mi información. Colores de tokens (graficas.js/tokens.js). */
@layer componentes {
  .grafica { width: 100%; height: auto; }
  .grafica .serie { fill: none; stroke: var(--grafica-serie); stroke-width: 2; }
  .grafica .punto { fill: var(--grafica-serie); }
  .grafica .rejilla { stroke: var(--borde); stroke-width: 1; }
  .grafica .eje { font-size: var(--txt-2xs); fill: var(--tinta-suave); }
  .grafica .eje-x { text-anchor: middle; }
  .leyenda-serie { text-align: right; color: var(--grafica-serie); }

  /* Barras horizontales: etiqueta · pista · valor. Se recorta la etiqueta, no la barra. */
  .barras { container: barras / inline-size; margin: 0; padding: var(--pad); list-style: none; }
  .barras li { display: grid; grid-template-columns: minmax(90px, 30%) 1fr 52px; align-items: center; gap: var(--sp-5); padding: var(--sp-2) 0; }
  .barra-etiqueta { overflow: hidden; color: var(--tinta-media); text-overflow: ellipsis; white-space: nowrap; }
  .barra-pista { height: 14px; overflow: hidden; border-radius: var(--radio-sm); background: var(--grafica-pista); }
  .barra-relleno { display: block; height: 100%; border-radius: var(--radio-sm); background: var(--grafica-serie); }
  .barra-valor { text-align: right; font-variant-numeric: tabular-nums; }

  /* En un panel estrecho la etiqueta va entera, encima de su barra. */
  @container barras (width < 420px) {
    .barras li { grid-template-columns: minmax(0, 1fr) auto; row-gap: var(--sp-1); }
    .barras .barra-etiqueta { grid-column: 1 / -1; white-space: normal; }
  }

  /* Prioridad del paciente con los tonos de bandera; «Negra» no tiene bandera y lleva contorno. */
  .barras li[data-prioridad='roja'] .barra-relleno { background: var(--bandera-rojo); }
  .barras li[data-prioridad='amarilla'] .barra-relleno { background: var(--bandera-amarillo); }
  .barras li[data-prioridad='verde'] .barra-relleno { background: var(--bandera-verde); }
  .barras li[data-prioridad='negra'] .barra-relleno { background: var(--sobre-bandera-gris); box-shadow: inset 0 0 0 1px var(--borde-fuerte); }

  /* Lienzo de Chart.js: alto fijo, `maintainAspectRatio: false` en JS. */
  .grafica-lienzo { position: relative; height: 200px; margin: var(--pad); }
  .grafica-lienzo.baja { height: 140px; }
}

/* ── componentes/mapas.css ── */
/* Contenido de los popups de Google Maps: su ventana es blanca siempre, no sigue el tema. */
@layer componentes {
  .popup-mapa { max-width: 280px; color: var(--sobre-blanco-fijo); font-size: var(--txt-base); line-height: 1.5; }
  /* Título en neutro: el rojo es peligro, y esta ventana no lo es (Consola de inicio). */
  .popup-mapa h3 { margin: 0 0 var(--sp-3); color: var(--sobre-blanco-fijo); font-size: var(--txt-md); }
  .popup-mapa p { margin: 0 0 var(--sp-3); }
  .popup-mapa strong { font-weight: 600; }

  /* Una posición estimada no puede leerse como una lectura, pero tampoco es una alerta. */
  .popup-estimado { color: var(--sobre-blanco-fijo); font-weight: 600; }
  .popup-ruta { color: var(--sobre-blanco-fijo); font-size: var(--txt-base); line-height: 1.45; }

  /* Minimapa de un punto (mapaDePunto): discreto, dentro de su bloque. */
  .minimapa { display: grid; place-items: center; height: 180px; overflow: hidden; border: 1px solid var(--borde); border-radius: var(--radio); background: var(--superficie-2); }
  .minimapa > .secundario { text-align: center; }
}

/* ── componentes/modal.css ── */
/* Modales (modal.js): alta, edición, pasos, confirmaciones y PDF. Encima de la lista. */
@layer componentes {
  .modal {
    display: none;
    width: min(var(--modal-ancho, 680px), calc(100vw - 32px));
    max-height: calc(100vh - 48px);
    padding: 0;
    overflow: hidden;
    border: 1px solid var(--borde);
    border-radius: var(--radio-xl);
    background: var(--superficie);
    color: var(--tinta);
    box-shadow: var(--sombra-flotante);
  }

  .modal[open] { display: flex; flex-direction: column; }
  .modal::backdrop { background: var(--velo); }

  .modal-cabecera {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    padding: var(--sp-5) var(--sp-4) var(--sp-5) var(--sp-6);
    border-bottom: 1px solid var(--borde);
  }

  .modal-cabecera h2 { flex: 1; margin: 0; font-size: var(--txt-md); font-weight: 600; }

  .modal-cuerpo { flex: 1; min-height: 0; padding: var(--sp-6); overflow-y: auto; }
  .modal-cuerpo > .panel:last-child, .modal-cuerpo > .tarjetas:last-child { margin-bottom: 0; }
  .modal-texto { margin: 0 0 var(--sp-4); color: var(--tinta-media); }

  .modal-pie {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--sp-4);
    padding: var(--sp-5) var(--sp-6);
    border-top: 1px solid var(--borde);
    background: var(--superficie-2);
  }

  /* ── Formulario dentro del modal: dos columnas, lo largo ocupa la fila ── */
  .rejilla-modal { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: var(--gap); }
  .campo-modal.ancho-total { grid-column: 1 / -1; }
  .campo-modal small { color: var(--tinta-suave); font-size: var(--txt-xs); font-weight: 400; }
  .campo-modal .requerido { color: var(--tinta-suave); font-weight: 400; }
  .campo-modal.casilla { flex-flow: row wrap; align-items: center; gap: var(--sp-4); }
  /* La ayuda de una casilla («sin sección SCI») va en su propio renglón, bajo el texto. */
  .campo-modal.casilla small { flex-basis: 100%; margin-left: calc(var(--alto-control) - var(--sp-4)); }
  .formulario-modal .error { margin: var(--gap) 0 0; }

  /* Un formulario en GRUPOS (`openForm`/`openStepper` con `grupos`): fieldsets del manual, sin caja. */
  .formulario-modal .grupo-campos:not(:first-child) { margin-top: var(--sp-6); }

  /* ── Pasos: se ve dónde vas y cuánto falta; volver no borra lo escrito ── */
  .pasos {
    display: flex;
    gap: var(--sp-6);
    margin: 0 0 var(--gap);
    padding: 0 0 var(--sp-5);
    overflow-x: auto;
    border-bottom: 1px solid var(--borde);
    list-style: none;
  }

  .pasos li { display: flex; align-items: center; gap: var(--sp-4); color: var(--tinta-suave); font-weight: 500; white-space: nowrap; }

  .pasos-numero {
    display: inline-grid;
    place-items: center;
    flex: none;
    width: 22px;
    height: 22px;
    border: 1px solid var(--borde-fuerte);
    border-radius: 50%;
    font-size: var(--txt-2xs);
    font-weight: 600;
  }

  .pasos li.activo { color: var(--tinta); }
  .pasos li.activo .pasos-numero { border-color: var(--primario); background: var(--primario); color: var(--sobre-primario); }
  .pasos li.hecho { color: var(--tinta-media); }
  .pasos li.hecho .pasos-numero { border-color: transparent; background: var(--superficie-activa); color: var(--tinta); }

  /* Lo ya agregado en un paso repetible (las tripulaciones antes de almacenar). */
  .stepper-resumen {
    margin: var(--gap) 0 0;
    padding: var(--sp-5);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--superficie-2);
    color: var(--tinta-media);
  }

  .stepper-resumen ul { margin: 0; padding-left: var(--sp-7); }
  .stepper-resumen li { margin-bottom: var(--sp-2); }
  .stepper-resumen li:last-child { margin-bottom: 0; }
  .stepper-resumen strong { color: var(--tinta); font-weight: 600; }

  .visor-pdf {
    width: 100%;
    height: calc(100vh - 200px);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--superficie-2);
  }

  @media (width < 720px) {
    .modal { width: calc(100vw - 16px); }
  }
}

/* ── componentes/paleta.css ── */
/* Paleta de comandos (palette.js, Ctrl+K). */
@layer componentes {
  .paleta {
    top: 12vh;
    width: min(580px, calc(100vw - 32px));
    max-height: 70vh;
    margin: 0 auto;
    padding: 0;
    overflow: hidden;
    border: 1px solid var(--borde);
    border-radius: var(--radio-xl);
    background: var(--superficie);
    color: var(--tinta);
    box-shadow: var(--sombra-flotante);
  }

  .paleta[open] { display: flex; flex-direction: column; }
  .paleta::backdrop { background: var(--velo); }

  .paleta-entrada { display: flex; align-items: center; gap: var(--sp-4); padding: 0 var(--sp-6); border-bottom: 1px solid var(--borde); }
  .paleta-entrada > i { font-size: var(--txt-lg); color: var(--tinta-suave); }

  .paleta-entrada input {
    flex: 1;
    height: 48px;
    padding: 0;
    border: 0;
    background: none;
    font-size: var(--txt-md);
  }

  /* El anillo lo lleva la caja entera: el campo es toda la paleta. */
  .paleta-entrada:focus-within { box-shadow: inset 0 -2px 0 var(--foco); }
  .paleta-entrada input:focus-visible { outline-color: transparent; }

  .paleta-lista { flex: 1; margin: 0; padding: var(--sp-3); overflow-y: auto; list-style: none; }
  .paleta-grupo { padding: var(--sp-4) 10px var(--sp-2); font-size: var(--txt-2xs); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--tinta-suave); }

  .paleta-opcion {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    height: 36px;
    padding: 0 10px;
    border: 0;
    border-radius: var(--radio);
    background: none;
    color: var(--tinta);
    font: inherit;
    text-align: left;
    cursor: pointer;
  }

  .paleta-opcion i { --fa-width: 1.25em; color: var(--tinta-media); }
  .paleta-opcion[aria-selected='true'] { background: var(--superficie-activa); }
  .paleta-meta { margin-left: auto; color: var(--tinta-suave); font-size: var(--txt-xs); }
  .paleta-vacia { padding: var(--sp-6) 10px; color: var(--tinta-suave); }

  .paleta-pie {
    display: flex;
    gap: var(--sp-6);
    padding: var(--sp-4) var(--sp-6);
    border-top: 1px solid var(--borde);
    background: var(--superficie-2);
    color: var(--tinta-suave);
    font-size: var(--txt-xs);
  }
}

/* ── componentes/panel-lateral.css ── */
/* Panel lateral (openPanel): UNO para toda la consola. <dialog> NO modal y acoplado. */
@layer componentes {
  .panel-lateral {
    position: fixed;
    inset: var(--alto-cabecera) 0 0 auto;
    z-index: var(--z-panel-lateral);
    width: var(--panel-lateral);
    height: auto;
    max-height: none;
    margin: 0;
    padding: 0;
    border: 0;
    border-left: 1px solid var(--borde);
    background: var(--superficie);
    color: var(--tinta);
  }

  .panel-lateral.ancho { width: var(--panel-lateral-ancho); }
  .panel-lateral[open] { display: flex; flex-direction: column; }

  /* Acoplado: el área principal se estrecha y la búsqueda y la paginación siguen a la vista. */
  body:has(> .panel-lateral[open]) .area-principal { margin-right: var(--panel-lateral); }
  body:has(> .panel-lateral.ancho[open]) .area-principal { margin-right: var(--panel-lateral-ancho); }

  /* Por debajo de 1024 px no cabe al lado: flota sobre la lista, y en móvil la ocupa entera. */
  @media (width < 1024px) {
    body:has(> .panel-lateral[open]) .area-principal { margin-right: 0; }
    .panel-lateral, .panel-lateral.ancho { width: min(100%, var(--panel-lateral)); box-shadow: var(--sombra-flotante); }
  }

  @media (width < 768px) {
    .panel-lateral, .panel-lateral.ancho { width: 100%; }
  }

  .panel-lateral-cabecera {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-2);
    padding: var(--sp-5) var(--sp-4) var(--sp-5) var(--sp-7);
    border-bottom: 1px solid var(--borde);
  }

  .panel-lateral-titulos { display: flex; flex: 1; flex-direction: column; gap: var(--sp-3); min-width: 0; }
  .panel-lateral-titulos h2 { margin: 0; font-size: var(--txt-lg); font-weight: 600; overflow-wrap: anywhere; }
  .panel-lateral-subtitulo { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); color: var(--tinta-suave); font-size: var(--txt-xs); }

  .panel-lateral-cuerpo { flex: 1; min-height: 0; padding: var(--sp-6) var(--sp-7); overflow-y: auto; }

  .panel-lateral-pie {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: var(--sp-4);
    padding: var(--sp-5) var(--sp-7);
    border-top: 1px solid var(--borde);
    background: var(--superficie-2);
  }

  /* Lo destructivo va a la izquierda del pie, lejos de lo que afirma. */
  .panel-lateral-pie .boton-peligro { margin-right: auto; }

  /* 520 px no dan para dos tarjetas por fila; los destacados, en 2 × 2. La columna no crece con lo
     que lleva dentro: una tabla o unas fechas desplazan, no desbordan. */
  .panel-lateral .ficha { grid-template-columns: minmax(0, 1fr); }
  .panel-lateral .ficha-destacados { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ficha-tarjeta { min-width: 0; }

  /* Pestañas internas de la ficha (Datos · Conductor · Recorrido…), alineadas con sus tarjetas. */
  .panel-lateral .pestanas-trabajo { margin-bottom: var(--gap); padding-inline: 0; }

  /* En el panel ancho hay sitio de sobra: los destacados van en una sola fila. */
  .panel-lateral.ancho .ficha-destacados { grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr)); }
}

/* ── componentes/paneles.css ── */
@layer componentes {
  .panel, .tarjeta, .tarjeta-acceso {
    background: var(--superficie);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    box-shadow: var(--sombra-panel);
  }

  .panel { margin-bottom: var(--gap); overflow: hidden; }

  .panel > h2 {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    min-height: 44px;
    margin: 0;
    padding: var(--sp-3) var(--pad);
    border-bottom: 1px solid var(--borde);
    font-size: var(--txt-md);
    font-weight: 600;
  }

  .panel > h2 > .boton-texto,
  .panel > h2 > .solo-lectura { margin-left: auto; font-size: var(--txt-xs); font-weight: 400; }

  /* Cuántos hay: píldora junto al título que cuenta. */
  .contador {
    display: inline-flex;
    align-items: center;
    height: 20px;
    padding: 0 var(--sp-3);
    border-radius: var(--radio-pill);
    background: var(--superficie-activa);
    color: var(--tinta-media);
    font-size: var(--txt-2xs);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  .panel-interno { padding: var(--sp-5) var(--pad); }

  /* Rótulo de bloque: versalitas pequeñas, no un aviso. */
  .panel-interno h3,
  .tarjeta h3 {
    margin: 0 0 var(--sp-5);
    font-size: var(--txt-2xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--tinta-suave);
  }

  .titulo-seccion {
    margin: var(--sp-8) 0 var(--sp-4);
    font-size: var(--txt-xs);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--tinta-suave);
  }

  .titulo-seccion:first-of-type { margin-top: var(--sp-2); }

  .tarjetas { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); gap: var(--gap); margin-bottom: var(--gap); }
  .tarjeta { padding: var(--pad); }
  .tarjeta h3 { margin: 0; }
  .tarjeta .dato { margin: var(--sp-3) 0 var(--sp-1); font-size: var(--txt-3xl); font-weight: 600; font-variant-numeric: tabular-nums; }
  .tarjeta small { color: var(--tinta-suave); font-size: var(--txt-xs); }

  /* Franja de indicadores de una lista: solo cifras que la API ya da. Pulsar aplica su filtro. */
  .franja-indicadores { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr)); gap: var(--gap); margin-bottom: var(--gap); }

  @media (width < 768px) {
    .franja-indicadores { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  }

  /* `.llena` reparte el ancho entre sus 3 a 5 tarjetas (Estadísticas): sin huecos sueltos. */
  @media (width >= 768px) {
    .franja-indicadores.llena { grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr)); }
  }

  .indicador {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
    padding: var(--sp-4) var(--pad);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    background: var(--superficie);
    box-shadow: var(--sombra-panel);
    color: inherit;
    font: inherit;
    text-align: left;
  }

  button.indicador { cursor: pointer; }
  button.indicador:hover { border-color: var(--borde-fuerte); }
  button.indicador[aria-pressed='true'] { border-color: var(--tinta); box-shadow: inset 0 0 0 1px var(--tinta); }

  /* El indicador que lleva a donde está lo que cuenta (Consola de inicio). */
  a.indicador { text-decoration: none; }
  a.indicador:hover { border-color: var(--borde-fuerte); }
  .indicador-rotulo { font-size: var(--txt-2xs); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--tinta-suave); }
  .indicador-cifra { font-size: var(--txt-2xl); font-weight: 600; line-height: 1.2; font-variant-numeric: tabular-nums; }
  .indicador-nota { font-size: var(--txt-xs); color: var(--tinta-suave); }

  /* ── Rejillas y bloques de datos ── */
  .rejilla { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr)); gap: var(--gap); }

  .datos { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: var(--gap); margin: 0; padding: var(--pad); }
  .datos dt { font-size: var(--txt-xs); color: var(--tinta-suave); }
  .datos dd { margin: var(--sp-1) 0 0; overflow-wrap: anywhere; }

  .lista { margin: 0; padding: var(--sp-2) var(--pad) var(--sp-5); list-style: none; }
  .lista li { padding: var(--sp-3) 0; border-bottom: 1px solid var(--borde); }
  .lista li:last-child { border-bottom: none; }

  /* ── Formularios en panel ── */
  .filtro, .casilla { flex-direction: row; align-items: center; gap: var(--sp-4); }
  .casilla { font-size: var(--txt-base); font-weight: 400; color: var(--tinta); }

  .acciones, .linea-accion { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); padding: var(--pad); }
  .acciones { justify-content: flex-end; }

  /* La clave TOTP se teclea a mano cuando no se puede escanear. */
  .clave-totp {
    padding: var(--sp-4) var(--sp-5);
    border-radius: var(--radio);
    background: var(--superficie-activa);
    font-family: var(--mono);
    font-size: var(--txt-md);
    letter-spacing: 0.08em;
    overflow-wrap: anywhere;
    user-select: all;
  }

  /* Vacío o error dentro de un panel, con su porqué (Consola de inicio y afines). */
  .vacio-panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--sp-4);
    margin: 0;
    padding: var(--sp-8) var(--pad);
    color: var(--tinta-suave);
    text-align: center;
  }
}

/* ── componentes/puesto.css ── */
/* Puesto de trabajo (Radio, Telefonista): la tarjeta de trabajo y lo que desplaza por dentro. */
@layer componentes {
  .desplaza { flex: 1; min-height: 0; overflow-y: auto; }

  /* La tarjeta del centro: su barra, sus pestañas y sus bloques. */
  .barra-trabajo {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    margin: 0;
    padding: var(--sp-4) var(--pad);
    border-bottom: 1px solid var(--borde);
    background: var(--superficie-2);
    font-size: var(--txt-md);
    font-weight: 600;
  }

  .barra-trabajo .bandera { width: 16px; height: 16px; }
  .barra-trabajo .boton { margin-left: auto; }

  .pestanas-trabajo { display: flex; gap: var(--sp-2); padding: 0 var(--pad); border-bottom: 1px solid var(--borde); overflow-x: auto; }

  .pestanas-trabajo button {
    flex: none;
    height: var(--alto-control);
    margin-bottom: -1px;
    padding: 0 var(--sp-5);
    border: 0;
    border-bottom: 2px solid transparent;
    background: transparent;
    color: var(--tinta-media);
    font: inherit;
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
  }

  .pestanas-trabajo button:hover { color: var(--tinta); }
  .pestanas-trabajo button[aria-selected='true'] { border-bottom-color: var(--tinta); color: var(--tinta); font-weight: 600; }

  .cuerpo-trabajo { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); align-content: start; gap: var(--gap); padding: var(--pad); }
  .cuerpo-trabajo[hidden] { display: none; }
  .cuerpo-trabajo > .ancho-total, .cuerpo-trabajo > .aviso { grid-column: 1 / -1; }

  .bloque {
    display: flex;
    flex-direction: column;
    gap: var(--sp-5);
    min-width: 0;
    padding: var(--pad);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
  }

  .bloque > h3 { margin: 0; color: var(--tinta-suave); font-size: var(--txt-2xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; }
  .bloque .rejilla-campos { grid-template-columns: repeat(auto-fill, minmax(min(130px, 100%), 1fr)); }
  .bloque .acciones { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-4); }
  .bloque .acciones.inicio { justify-content: flex-start; }
  .bloque .error { margin: 0; }
  .bloque .comentarios, .bloque .historial { padding: 0; }
}

/* ── componentes/reporte-ciudadano.css ── */
/* El reporte ciudadano y sus evidencias (report-evidence.js): en Radio y en el cierre. */
@layer componentes {
  /* De dónde salió la llamada: sobrio, sin color propio (el de la tarjeta es la prioridad). */
  .origen-reporte {
    margin: var(--sp-2) 0 0;
    padding-top: var(--sp-2);
    border-top: 1px solid var(--borde);
    color: var(--tinta-suave);
    font-size: var(--txt-2xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }

  .reporte-origen { display: block; margin-bottom: var(--sp-6); }

  /* Retractación: aquí el rojo SÍ es lo que significa, algo crítico que decidir. */
  .reporte-retractado {
    margin: var(--sp-2) 0 0;
    padding: var(--sp-3) var(--sp-4);
    border: 1px solid var(--mal-borde);
    border-radius: var(--radio-sm);
    background: var(--mal-fondo);
    color: var(--mal-tinta);
    font-size: var(--txt-2xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }

  .reporte-retractado p { margin: 0 0 var(--sp-2); }
  .reporte-retractado p:last-child { margin-bottom: 0; }
  .reporte-retractado.sin-acusar { border-left-width: 3px; }

  .reporte-origen .reporte-retractado {
    margin: 0 0 var(--sp-5);
    padding: var(--sp-4) var(--pad);
    font-size: var(--txt-base);
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
  }

  .reporte-origen .reporte-retractado .boton { margin-top: var(--sp-4); }

  /* El punto no cayó en ninguna geocerca: se revisa antes de despachar. */
  .reporte-aviso-cercania {
    display: block;
    padding: var(--sp-3) var(--sp-4);
    border-radius: var(--radio-sm);
    background: var(--aviso-fondo);
    color: var(--aviso-tinta);
  }

  /* Miniaturas: se envuelven, para comparar ángulos de la misma escena. */
  .reporte-evidencias { display: flex; flex-wrap: wrap; gap: var(--sp-5); margin-top: var(--sp-5); }

  .evidencia-miniatura {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    width: 160px;
    padding: var(--sp-2);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--superficie);
    color: var(--tinta-suave);
    font-size: var(--txt-2xs);
    text-align: left;
    cursor: pointer;
  }

  .evidencia-miniatura:hover { border-color: var(--borde-fuerte); background: var(--superficie-hover); }

  .evidencia-miniatura img {
    display: block;
    max-width: 100%;
    height: 110px;
    object-fit: cover;
    border-radius: var(--radio-sm);
    background: var(--superficie-activa);
  }

  .evidencia-miniatura span { overflow-wrap: anywhere; }

  .evidencia-completa img {
    display: block;
    max-width: 100%;
    max-height: calc(100vh - 220px);
    height: auto;
    margin: 0 auto;
    border-radius: var(--radio);
    background: var(--superficie-2);
  }

  .evidencia-completa .secundario { margin-top: var(--sp-5); padding: 0; text-align: center; }
}

/* ── componentes/tabla.css ── */
/* Tablas (tabla.js + widgets/tabla-controles.ejs). Filas de 32 px, cabecera fija. */
@layer componentes {
  /* Desplaza por dentro: así la cabecera queda fija y la página nunca desplaza en horizontal. */
  .tabla-contenedor { overflow: auto; max-height: max(320px, calc(100dvh - 260px)); }
  .modal .tabla-contenedor { max-height: none; }

  /* `max-content`: se prefiere desplazar a partir un nombre en tres renglones. */
  .tabla { width: 100%; min-width: max-content; border-collapse: separate; border-spacing: 0; }

  /* Sin filas: la tabla ya no necesita el ancho de sus cabeceras y cabe en pantallas angostas. */
  .tabla:has(> tbody > tr.vacio:only-child) { min-width: 0; }

  .tabla th {
    position: sticky;
    top: 0;
    z-index: var(--z-tabla);
    height: var(--alto-fila);
    padding: 0 10px;
    border-bottom: 1px solid var(--borde);
    background: var(--superficie-2);
    color: var(--tinta-suave);
    font-size: var(--txt-2xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-align: left;
    text-transform: uppercase;
    white-space: nowrap;
  }

  .tabla th.num { text-align: right; }

  .tabla td {
    height: var(--alto-fila);
    padding: var(--sp-1) 10px;
    border-bottom: 1px solid var(--borde);
    white-space: nowrap;
  }

  .tabla tbody tr:last-child td { border-bottom: none; }
  .tabla tbody tr:hover td { background: var(--superficie-hover); }

  /* La fila entera abre el detalle; la abierta en el panel lateral queda marcada. */
  .tabla tbody tr.fila-abrible { cursor: pointer; }
  .tabla tbody tr.fila-abrible:focus-visible { outline-offset: -2px; }

  .tabla tbody tr[aria-current='true'] td { background: var(--superficie-activa); }

  /* El dato que identifica la fila: peso, no color. */
  .tabla td.principal { font-weight: 500; color: var(--tinta); }

  /* Segunda línea de la celda: la base bajo la unidad, el tipo bajo el folio. */
  .tabla td > small { display: block; color: var(--tinta-suave); font-size: var(--txt-2xs); font-weight: 400; }

  /* Un texto largo en una sola línea (Buzón de seguridad, «Dónde»): el completo va en `title` y en la ficha. */
  .tabla td > .recortada { display: block; max-width: 28ch; overflow: hidden; text-overflow: ellipsis; }

  /*
   * Sin resultados o con error: el porqué y, si se puede, cómo seguir.
   * `.tabla-mensaje` queda FIJO a la izquierda (como la primera columna) y
   * a lo ancho del contenedor visible: si la tabla desplaza en horizontal
   * (columnas de más para caber en móvil), el mensaje se sigue leyendo
   * entero en vez de centrarse sobre el ancho total y cortarse.
   */
  .tabla-contenedor { container-type: inline-size; }
  .tabla .vacio td { padding: 0; text-align: center; color: var(--tinta-suave); white-space: normal; }
  .tabla-mensaje { position: sticky; left: 0; width: 100cqi; padding: var(--sp-9) var(--pad); }
  .tabla-mensaje > i { margin-right: var(--sp-3); }
  .tabla-mensaje > .boton { margin-left: var(--sp-5); }

  /* Primera columna fija: con el panel lateral abierto la tabla se estrecha y ella sigue diciendo qué fila es. */
  .tabla-fija th:first-child,
  .tabla-fija td:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--superficie);
    box-shadow: inset -1px 0 0 var(--borde);
  }

  .tabla-fija th:first-child { z-index: 2; background: var(--superficie-2); }
  .tabla-fija tbody tr:hover td:first-child { background: var(--superficie-hover); }

  .tabla tbody tr[aria-current='true'] td:first-child {
    background: var(--superficie-activa);
    box-shadow: inset 2px 0 0 var(--tinta), inset -1px 0 0 var(--borde);
  }

  th.ordenable { cursor: pointer; user-select: none; }
  th.ordenable:hover { color: var(--tinta); }
  th.ordenable i { margin-left: var(--sp-2); font-size: var(--txt-2xs); opacity: 0.6; }
  th.ordenable[aria-sort] i { opacity: 1; }

  .acciones-fila { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }

  /* Acciones de fila con SOLO icono (Marcas, Modelos): la columna se ciñe a
     sus botones y queda al final. 0 y no 1%: un porcentaje infla el
     `max-content` de la tabla (vehiculos.md, pantallas.md §7). En tinta
     suave; pasan a tinta al pasar por la fila (distribucion.md, «Tablas»).
     Acotado a `.boton-icono`: las demás listas usan botones de texto
     («Editar», «Borrar») que no llevan esta variante. */
  .tabla td:has(> .acciones-fila .boton-icono) { width: 0; }
  .tabla td > .acciones-fila { flex-wrap: nowrap; }
  .tabla td > .acciones-fila .boton-icono.boton-texto { color: var(--tinta-suave); }
  .tabla tbody tr:hover td > .acciones-fila .boton-icono.boton-texto { color: var(--tinta); }

  /* Cargando: silueta estática, sin brillo animado. */
  .esqueleto { display: block; height: 10px; border-radius: var(--radio-sm); background: var(--superficie-activa); }

  /* ── Controles del patrón de tabla del manual ── */
  .tabla-controles, .tabla-pie {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-3) var(--pad);
  }

  .tabla-controles { border-bottom: 1px solid var(--borde); }
  .tabla-pie { border-top: 1px solid var(--borde); background: var(--superficie-2); color: var(--tinta-media); font-size: var(--txt-xs); font-variant-numeric: tabular-nums; }

  .control-busqueda, .control-pagina { flex-direction: row; align-items: center; gap: var(--sp-4); }
  .control-pagina select { width: auto; }
  .tabla-controles .menu-exportar { margin-right: auto; }

  .caja-buscar { position: relative; display: flex; align-items: center; }
  .caja-buscar > i { position: absolute; left: 10px; color: var(--tinta-suave); font-size: var(--txt-xs); pointer-events: none; }
  .caja-buscar input { width: 220px; padding-left: 30px; }

  .paginacion { display: flex; align-items: center; gap: var(--sp-2); }
  .paginacion [data-pagina='indicador'] { padding: 0 var(--sp-4); }

  /* ── Menú de exportación: un <details>, pegado a la tabla de la que sale ── */
  .menu-exportar { position: relative; }

  .menu-exportar summary {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-3);
    height: var(--alto-control);
    padding: 0 var(--sp-5);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio);
    background: var(--superficie);
    color: var(--tinta);
    font-weight: 500;
    list-style: none;
    cursor: pointer;
    user-select: none;
  }

  .menu-exportar summary::-webkit-details-marker { display: none; }
  .menu-exportar summary:hover, .menu-exportar[open] summary { background: var(--superficie-hover); }

  .menu-exportar-lista {
    position: absolute;
    z-index: var(--z-desplegable);
    top: calc(100% + 4px);
    left: 0;
    min-width: 250px;
    padding: var(--sp-2);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    background: var(--superficie);
    box-shadow: var(--sombra-flotante);
  }

  .menu-exportar-lista button {
    display: block;
    width: 100%;
    padding: var(--sp-3) var(--sp-4);
    border: none;
    border-radius: var(--radio-sm);
    background: none;
    color: var(--tinta);
    font: inherit;
    text-align: left;
    cursor: pointer;
  }

  .menu-exportar-lista button:hover { background: var(--superficie-hover); }
  .menu-exportar-lista button:disabled { opacity: 0.5; cursor: default; }

  /* El menú también vive en la barra de página (Cierre, §27.2): se abre hacia dentro. */
  .acciones-pagina .menu-exportar-lista { right: 0; left: auto; width: max-content; max-width: 360px; }
  .menu-exportar-nota { margin: 0 0 var(--sp-2); padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--borde); color: var(--tinta-suave); font-size: var(--txt-xs); }
  .menu-exportar-lista > .aviso { margin-bottom: var(--sp-2); }

  @media (width < 768px) {
    .acciones-pagina .menu-exportar-lista { right: auto; left: 0; }
    /* Sin filas y en angosto, la cabecera (que fija el ancho de las columnas) sobra: solo queda el aviso. */
    .tabla:has(> tbody > tr.vacio:only-child) thead { display: none; }
  }
}

/* ── componentes/vista-previa.css ── */
/* Vista previa de una fila (preview.js): responde «¿es este?» sin abrir la ficha. */
@layer componentes {
  .vista-previa {
    position: fixed;
    z-index: var(--z-previo);
    width: 320px;
    max-width: calc(100vw - 24px);
    padding: var(--pad);
    border: 1px solid var(--borde);
    border-radius: var(--radio-lg);
    background: var(--superficie);
    box-shadow: var(--sombra-flotante);
    /* Ayuda a la lectura, no objetivo: si capturara el ratón, la fila dejaría de poder pulsarse. */
    pointer-events: none;
  }

  .vista-previa-titulo { margin: 0; font-size: var(--txt-md); font-weight: 600; overflow-wrap: anywhere; }
  .vista-previa-sub { margin: var(--sp-2) 0 0; color: var(--tinta-suave); font-size: var(--txt-xs); }
  .vista-previa-distintivos { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: var(--sp-4) 0 0; }

  .vista-previa-datos { display: grid; gap: var(--sp-3); margin: var(--sp-4) 0 0; padding-top: var(--sp-4); border-top: 1px solid var(--borde); }
  .vista-previa-datos > div { display: grid; grid-template-columns: 40% 1fr; gap: var(--sp-4); }
  .vista-previa-datos dt { color: var(--tinta-suave); font-size: var(--txt-xs); }
  .vista-previa-datos dd { margin: 0; overflow-wrap: anywhere; }
}

/* ── pantallas/acceso.css ── */
/* Pantallas sin sesión: acceso, registro y error (docs de diseño, pantalla 1). */
@layer pantallas {
  .pantalla-acceso {
    display: grid;
    place-items: center;
    min-height: 100vh;
    min-height: 100dvh;
    padding: var(--sp-7) var(--sp-6);
  }

  .tarjeta-acceso {
    display: grid;
    gap: var(--sp-7);
    width: 100%;
    max-width: 360px;
    padding: var(--sp-8);
    border-radius: var(--radio-xl);
  }

  .cabecera-acceso { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-5); }

  .marca-acceso img { display: block; width: min(260px, 100%); height: auto; }

  /* El subtítulo del logotipo es negro: en oscuro va su versión en blanco. */
  .marca-acceso .logo-oscuro { display: none; }
  :root[data-theme='dark'] .marca-acceso {
    .logo-claro { display: none; }
    .logo-oscuro { display: block; }
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme='light']) .marca-acceso {
      .logo-claro { display: none; }
      .logo-oscuro { display: block; }
    }
  }

  .titulo-acceso { display: grid; gap: var(--sp-2); }
  .titulo-acceso h1 { margin: 0; font-size: var(--txt-xl); font-weight: 600; text-wrap: balance; }
  .titulo-acceso p { margin: 0; color: var(--tinta-media); }

  /* «Entrando como …»: sustituye a los campos de solo lectura del segundo paso. */
  .cuenta-en-curso { overflow-wrap: anywhere; }
  .cuenta-en-curso strong { color: var(--tinta); font-weight: 600; }

  .form-acceso { display: grid; gap: var(--sp-6); }
  .form-acceso .boton-primario { width: 100%; }

  .codigo-verificacion {
    font-size: var(--txt-lg);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.3em;
  }

  .otra-cuenta { justify-self: center; }

  .tarjeta-error { max-width: 400px; }
  .tarjeta-error .boton-primario { justify-self: start; }
}

/* ── pantallas/cierre.css ── */
/* Cierre de los servicios (docs/02 §26-§28) e Histórico de expedientes (§29). Maqueta 6. */
@layer pantallas {
  /* La pantalla del cierre es un puesto: el cierre manda y la bitácora va al lado. */
  .cierre { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: var(--gap); }
  .cierre > .panel { display: flex; flex-direction: column; min-height: 0; margin: 0; }

  /* Expedientes, comentarios e historial: cada panel desplaza por dentro. */
  .cierre-bitacora { display: flex; flex-direction: column; gap: var(--gap); min-height: 0; }
  .cierre-bitacora > .panel { display: flex; flex-direction: column; min-height: 0; margin: 0; }
  .cierre-bitacora > .panel:not(:first-child) { flex: 1; }

  /* «Cerrar el servicio» (§26.1): el orden del manual; cada fecha con su hora. */
  .formulario-cierre .rejilla-campos { grid-template-columns: repeat(auto-fill, minmax(min(250px, 100%), 1fr)); }
  .fecha-hora { display: flex; gap: var(--sp-3); }
  .fecha-hora input[type='date'] { flex: 1 1 128px; }
  .fecha-hora input[type='time'] { flex: 0 0 96px; }

  /* Comentar (§26.2): el campo y su botón, al pie de la lista. */
  .formulario-comentario { display: flex; gap: var(--sp-4); padding: var(--pad); border-top: 1px solid var(--borde); }
  .formulario-comentario input { flex: 1; }

  /* Por debajo de 1024 px las columnas se apilan y la página vuelve a desplazar. */
  @media (width < 1024px) {
    .cierre { grid-template-columns: minmax(0, 1fr); }
    .cierre-bitacora > .panel:not(:first-child) { flex: none; }
  }

  @media (width < 768px) {
    .formulario-comentario { flex-wrap: wrap; }
  }
}

/* ── pantallas/combustibles.css ── */
/* Combustibles (docs/01 §20-B a §23, docs/02 §31; maqueta 11). */
@layer pantallas {
  /* Un prepago en rojo es información, no un error (combustibles.md): ámbar y con texto. */
  .saldo-en-rojo { color: var(--aviso-tinta); }
}

/* ── pantallas/consola.css ── */
/* Consola (inicio), maqueta 5: indicadores arriba; el mapa y, a su lado, guardias, mi servicio y noticias. */
@layer pantallas {
  /* Telemática ▸ Estado sigue usando esta rejilla de dos columnas (mudada aquí, sin pantalla propia). */
  .indicadores { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap); margin: 0; padding: var(--pad); }
  .indicadores a { display: block; color: inherit; text-decoration: none; }
  .indicadores a:hover { text-decoration: underline; text-underline-offset: 3px; }
  .indicadores dt { color: var(--tinta-suave); font-size: var(--txt-xs); line-height: 1.3; }
  .indicadores dd { margin: var(--sp-1) 0 0; font-size: var(--txt-2xl); font-weight: 600; line-height: 1.1; font-variant-numeric: tabular-nums; }
  .indicadores small { color: var(--tinta-suave); font-size: var(--txt-2xs); }

  @media (width < 1240px) {
    .indicadores { grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr)); }
  }

  /* El tablero mide su propio ancho: con el panel lateral abierto también pasa a una columna. */
  .tablero { container: consola / inline-size; display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: var(--gap); }
  .tablero .panel { margin-bottom: 0; }
  .tablero-lateral { display: flex; flex-direction: column; gap: var(--gap); }

  /* ── Ubicación de las unidades ── */
  .panel-mapa { display: flex; flex-direction: column; }
  .panel-mapa > h2 { flex-wrap: wrap; }
  .conmutador-flota { display: flex; gap: var(--sp-3); margin-left: auto; font-weight: 400; }
  .panel-mapa > .aviso { margin: var(--sp-4) var(--pad) 0; }

  /* Más específico que `.mapa` de radio.css, que va después en la hoja. */
  .panel-mapa > .mapa-consola { position: relative; flex: 1; min-height: 460px; overflow: hidden; }
  .panel-mapa > .mapa-consola:has(> .aviso) { display: grid; place-items: center; padding: var(--pad); }
  .mapa-consola > .aviso { max-width: 460px; }

  /* ── Guardias activas: la fila abre su ficha en el panel lateral ── */
  .lista-guardias { max-height: 320px; margin: 0; padding: 0; overflow-y: auto; list-style: none; }
  .lista-guardias li + li { border-top: 1px solid var(--borde); }

  .guardia {
    display: grid;
    gap: var(--sp-1);
    width: 100%;
    padding: var(--sp-4) var(--pad);
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
  }

  .guardia:hover { background: var(--superficie-hover); }
  .guardia[aria-current='true'] { background: var(--superficie-activa); box-shadow: inset 2px 0 0 var(--tinta); }
  .guardia-sede { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); font-weight: 600; }
  .guardia small { color: var(--tinta-suave); font-size: var(--txt-xs); font-weight: 400; }

  /* La ficha de la guardia: una tripulación por fila, con su gente debajo. */
  .lista-tripulaciones { margin: 0; padding: 0; list-style: none; }
  .lista-tripulaciones li { display: grid; gap: var(--sp-1); padding: var(--sp-4) 0; border-bottom: 1px solid var(--borde); }
  .lista-tripulaciones li:first-child { padding-top: 0; }
  .lista-tripulaciones li:last-child { padding-bottom: 0; border-bottom: 0; }
  .lista-tripulaciones p { margin: 0; }
  .tripulacion-unidad { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-4); }
  .tripulacion-unidad .distintivo { margin-left: auto; }

  /* ── Mi servicio (docs/01 §6-A): las tres cifras propias ── */
  .cifras-propias { display: grid; gap: var(--sp-4); margin: 0; padding: var(--sp-5) var(--pad); }
  .cifras-propias div { display: flex; align-items: baseline; justify-content: space-between; gap: var(--gap); }
  .cifras-propias dt { color: var(--tinta-media); }
  .cifras-propias dd { margin: 0; font-size: var(--txt-lg); font-weight: 600; font-variant-numeric: tabular-nums; }

  /* ── Historial (docs/01 §6-D): la fila abre el cierre del servicio ── */
  .panel-historial { margin-top: var(--gap); }
  .lista-historial { max-height: 320px; margin: 0; padding: 0; overflow-y: auto; list-style: none; }
  .lista-historial li + li { border-top: 1px solid var(--borde); }

  .movimiento-historial {
    display: flex;
    align-items: baseline;
    gap: var(--sp-4);
    width: 100%;
    padding: var(--sp-4) var(--pad);
    color: inherit;
    text-decoration: none;
  }

  a.movimiento-historial:hover { background: var(--superficie-hover); }
  .movimiento-historial strong { color: var(--info-tinta); font-weight: 600; }
  .movimiento-historial .secundario { flex: 1; margin-left: auto; padding: 0; text-align: right; }
  .movimiento-historial .fa-chevron-right { color: var(--tinta-suave); font-size: var(--txt-xs); }

  /* El carrusel de noticias (docs/01 §6-C) es un componente: `componentes/carrusel.css` (también en Noticias). */

  /* ── Sin shifts.view: Mi servicio y noticias, lado a lado ── */
  .consola-personal { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); gap: var(--gap); align-items: start; }
  .consola-personal .panel { margin-bottom: 0; }

  /* Una columna (panel lateral abierto, tableta, móvil): las guardias —lo que se pulsa— antes que el mapa. */
  @container consola (width < 760px) {
    .tablero { grid-template-columns: minmax(0, 1fr); }
    .tablero-lateral { display: contents; }
    .panel-guardias { order: -1; }
    .panel-mapa > .mapa-consola { flex: none; min-height: 0; max-height: 440px; aspect-ratio: 1; }
  }

  @media (width >= 1920px) {
    .tablero { grid-template-columns: minmax(0, 1fr) 380px; }
    .panel-mapa > .mapa-consola { min-height: 600px; }
  }
}

/* ── pantallas/estadisticas.css ── */
/*
 * Estadísticas (propuesta, sin captura en los manuales): un bloque por facultad
 * —operación, expedientes, personal—, cada uno con su franja y su rejilla.
 */
@layer pantallas {
  .bloque-estadisticas { margin-top: var(--sp-6); }
  .bloque-estadisticas + .bloque-estadisticas { margin-top: var(--sp-8); }

  /* Título del bloque y, en Personal, lo que no depende del periodo. */
  .cabecera-bloque { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2) var(--sp-5); margin-bottom: var(--sp-4); }
  .cabecera-bloque .titulo-seccion { margin: 0; }
  .cabecera-bloque p { margin: 0; color: var(--tinta-suave); font-size: var(--txt-xs); }

  /* Paneles del bloque: una columna; dos desde 1024 px, emparejados por alto. */
  .rejilla-graficas { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gap); margin-bottom: var(--gap); }
  .rejilla-graficas > .panel { margin-bottom: 0; }

  @media (width >= 1024px) {
    .rejilla-graficas { grid-template-columns: repeat(2, minmax(0, 1fr)); }

    /* El panel que se queda solo en su fila la ocupa entera. */
    .rejilla-graficas > .ancho-total:first-child ~ .panel:last-child:nth-child(even),
    .rejilla-graficas > .panel:first-child:not(.ancho-total) ~ .panel:last-child:nth-child(odd) { grid-column: 1 / -1; }
  }

  /* Una lista larga en un panel ancho: dos columnas, leídas de arriba abajo. */
  .rejilla-graficas > .ancho-total .barras:has(> li:nth-child(7)) { columns: 2 360px; column-gap: var(--sp-8); }
  .rejilla-graficas > .ancho-total .barras li { break-inside: avoid; }

  /* Causa y prioridad en un panel: lado a lado si caben. */
  .grafica-doble { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr)); }

  .grafica-doble h3 {
    margin: 0;
    padding: var(--sp-5) var(--pad) 0;
    color: var(--tinta-suave);
    font-size: var(--txt-2xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }

  /* A la derecha del título: la lista viene cortada por la API («Los 12 más frecuentes»). */
  .panel > h2 > .nota-grafica { margin-left: auto; color: var(--tinta-suave); font-size: var(--txt-xs); font-weight: 400; }

  /* Tablas secundarias: la cabecera y 12 filas. */
  .rejilla-graficas .tabla-contenedor { max-height: calc(var(--alto-fila) * 13); }

  /* Nada en el periodo: un aviso por bloque, no uno por gráfica. */
  .sin-datos { margin: 0; padding: var(--sp-9) var(--pad); color: var(--tinta-suave); text-align: center; }
  .sin-datos > i { margin-right: var(--sp-3); }
}

/* ── pantallas/guardias.css ── */
/* Guardias (docs/02 §2-§5; diseño en pantallas.md §10). Lista con la guardia en el panel lateral. */
@layer pantallas {
  /* Tripulaciones de la guardia, dentro de su tarjeta: una por unidad, separadas por un filete. */
  .tripulaciones-guardia { display: grid; margin: 0; padding: 0; list-style: none; }
  .tripulaciones-guardia > li { display: grid; gap: var(--sp-4); padding: var(--sp-5) 0; border-top: 1px solid var(--borde); }
  .tripulaciones-guardia > li:first-child { padding-top: 0; border-top: 0; }
  .tripulaciones-guardia > li:last-child { padding-bottom: 0; }

  /* Unidad, tipo y base; el estatus de la tripulación a la derecha. */
  .tripulacion-cabecera { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-4); }
  .tripulacion-cabecera strong { font-weight: 600; }
  .tripulacion-cabecera span:not(.distintivo) { color: var(--tinta-media); font-size: var(--txt-xs); }
  .tripulacion-cabecera .distintivo { margin-left: auto; }

  /* «Voluntario» junto al nombre, y las lecturas del turno en una línea de apoyo. */
  .tripulaciones-guardia dd small { color: var(--tinta-suave); font-size: var(--txt-xs); }
  .tripulacion-lecturas { margin: 0; color: var(--tinta-suave); font-size: var(--txt-xs); font-variant-numeric: tabular-nums; }

  /* Un aviso dentro de una tarjeta de la ficha va antes de lo que explica. */
  .ficha-tarjeta > .aviso { margin-bottom: var(--sp-5); }
}

/* ── pantallas/lugares.css ── */
/* Lugares (pantalla 9): Bases · Colonias · Hospitales · Delegaciones. Casi todo es de componentes. */
@layer pantallas {
  /* El filtro de la lista va junto a «Buscar:»; «Registros mostrados:» se queda a la derecha. */
  .tabla-controles .filtro { margin-right: auto; }
  .tabla-controles .filtro select { width: auto; max-width: 220px; }

  /* «Solo lectura» (ficha del hospital para quien no es Soporte): icono más texto, en el subtítulo del panel. */
  .solo-lectura { display: inline-flex; align-items: center; gap: var(--sp-2); color: var(--tinta-suave); font-size: var(--txt-xs); }
}

/* ── pantallas/mi-informacion.css ── */
/* Mi información (docs/01 §7-B y §8-A): la ficha propia, su estadística y sus avisos. */
@layer pantallas {
  /* Rótulo de sección con lo suyo a la derecha: el año de la estadística, el tope de los avisos. */
  .cabecera-seccion {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-3) var(--sp-5);
    margin: var(--sp-8) 0 var(--sp-4);
  }

  .cabecera-seccion .titulo-seccion { margin: 0; }
  .cabecera-seccion > :not(.titulo-seccion) { margin-left: auto; }
  .cabecera-seccion small { color: var(--tinta-suave); font-size: var(--txt-xs); }

  /* Contraseña y 2FA: el estado y lo que implica en una línea; la acción, en la cabecera de la tarjeta. */
  .estado-acceso { display: grid; justify-items: start; gap: var(--sp-5); }
  .estado-acceso p { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3) var(--sp-4); margin: 0; color: var(--tinta-media); }

  /* Estadística: horas por puesto · mapa de calor · horas por mes. Apila en móvil; en 21", una fila. */
  .estadistica { display: grid; grid-template-columns: minmax(0, 1fr); align-items: start; gap: var(--gap); }

  @media (width >= 1024px) {
    .estadistica { grid-template-columns: minmax(min(200px, 100%), 16rem) minmax(0, 1fr); }
    .estadistica > .horas-mes { grid-column: 1 / -1; }
  }

  @media (width >= 1920px) {
    .estadistica { grid-template-columns: minmax(min(200px, 100%), 16rem) auto minmax(0, 1fr); }
    .estadistica > .horas-mes { grid-column: auto; }
  }

  .horas-puesto tfoot td { border-top: 1px solid var(--borde); border-bottom: 0; font-weight: 600; }

  /* Chart.js pide un contenedor con alto propio (maintainAspectRatio: false). */
  .grafica-lienzo { position: relative; height: 13rem; }

  /* El detalle de un aviso fallido parte línea en vez de ensanchar la tabla. */
  .tabla-avisos td > small { max-width: 40ch; white-space: normal; }

  /* ── Variantes de componentes compartidos: cada bloque va a su archivo (ver la nota) ── */

  /* → componentes/ficha.css: varias acciones en la cabecera, juntas a la derecha; bajan de línea si no caben. */
  .ficha-tarjeta h3 { flex-wrap: wrap; }
  .ficha-tarjeta h3 .ficha-accion + .ficha-accion { margin-left: 0; }
  .ficha-tarjeta h3 .ficha-accion.peligro { color: var(--mal-tinta); }
  /* Dos bloques en una tarjeta (Credencial Nacional · Seguro de vida Institucional) y el texto de vacío. */
  .ficha-tarjeta .ficha-datos + h3 { margin-top: var(--sp-6); }
  .ficha-tarjeta > p { margin: 0; }

  /* → componentes/paneles.css: la clave de la 2FA con su «Copiar». */
  .clave-copiar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-4); }
  .clave-copiar .clave-totp { flex: 1; margin: 0; }

  /* El QR de la clave (alta y cambio de dispositivo): el SVG ya pinta su propio fondo blanco. */
  .qr-dos-pasos { display: block; margin: 0 0 var(--sp-4); border: 1px solid var(--borde); border-radius: var(--radio); }

  /* → componentes/graficas.css, en lugar de .heatmap-*: celdas de 10 px a escala real; si no cabe, desplaza y arranca en la semana actual. */
  .mapa-calor-desplaza { display: flex; flex-direction: row-reverse; overflow-x: auto; }
  .mapa-calor-desplaza svg { flex: none; }
  .mapa-calor [data-nivel='0'] { --nivel: var(--grafica-pista); }
  .mapa-calor [data-nivel='1'] { --nivel: color-mix(in oklch, var(--grafica-serie) 35%, var(--grafica-pista)); }
  .mapa-calor [data-nivel='2'] { --nivel: color-mix(in oklch, var(--grafica-serie) 58%, var(--grafica-pista)); }
  .mapa-calor [data-nivel='3'] { --nivel: color-mix(in oklch, var(--grafica-serie) 80%, var(--grafica-pista)); }
  .mapa-calor [data-nivel='4'] { --nivel: var(--grafica-serie); }
  .mapa-calor rect { fill: var(--nivel); }
  .mapa-calor .eje { fill: var(--tinta-suave); font-size: var(--txt-2xs); }
  .mapa-calor .anio { fill: var(--tinta-media); font-size: var(--txt-md); font-weight: 600; }
  .mapa-calor-leyenda { display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-2); margin-top: var(--sp-4); color: var(--tinta-suave); font-size: var(--txt-2xs); }
  .mapa-calor-leyenda [data-nivel] { width: 10px; height: 10px; border-radius: 20%; background: var(--nivel); }
}

/* ── pantallas/noticias.css ── */
/* Noticias (ADMINISTRACIÓN ▸ Noticias): lista de publicadas y borradores; la ficha enseña la noticia como la pinta el carrusel de la consola. */
@layer pantallas {
  /* El título identifica la fila y va fijo: recortado, con el completo en `title`, para que no tape la tabla. */
  .titulo-noticia { display: block; max-width: 48ch; overflow: hidden; text-overflow: ellipsis; }

  @media (width < 768px) {
    .titulo-noticia { max-width: 22ch; }
  }
}

/* ── pantallas/radio.css ── */
/* Consola de radio (docs/02 §6; diseño en pantallas.md §3). Puesto de trabajo. */
@layer pantallas {
  /* Unidades · trabajo · llamadas. Laterales fijas, el centro se queda con el resto. */
  .consola-radio { display: grid; grid-template-columns: 280px minmax(0, 1fr) 300px; gap: var(--gap); }

  .columna-unidades, .columna-informacion, .columna-trabajo { display: flex; flex-direction: column; gap: var(--gap); min-height: 0; }
  .consola-radio .panel { display: flex; flex-direction: column; min-height: 0; margin: 0; }
  .columna-unidades > .panel:first-child, .columna-informacion > .panel:first-child, .columna-trabajo > .panel { flex: 1; }
  .consola-radio .panel > h2 .contador { margin-left: auto; }

  /* Operativos: número con su base debajo, bandera sólida y estado. */
  .tabla-radio { min-width: 0; }
  .tabla-radio th, .tabla-radio td { padding: var(--sp-2) var(--sp-4); }
  .tabla-radio td { white-space: normal; }
  .tabla-radio .economico { font-weight: 600; white-space: nowrap; }

  .rejilla-pendientes { display: grid; grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); gap: var(--sp-3); padding: var(--sp-4) var(--pad); }
  .rejilla-pendientes > .secundario { grid-column: 1 / -1; padding-inline: 0; }

  .celda-pendiente {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: var(--sp-3);
    border: 1px dashed var(--borde-fuerte);
    border-radius: var(--radio);
    background: var(--superficie);
    color: inherit;
    font: 500 var(--txt-xs) / 1.2 var(--fuente);
    white-space: nowrap;
    cursor: pointer;
  }

  .celda-pendiente:hover { background: var(--superficie-hover); }
  .celda-pendiente[aria-current='true'] { border-style: solid; border-color: var(--tinta); }

  .sin-seleccion { display: grid; flex: 1; place-items: center; color: var(--tinta-suave); text-align: center; }
  .sin-seleccion i { font-size: var(--txt-2xl); }

  /* ── Llamadas por asignar: el borde izquierdo es la prioridad ── */
  .lista-llamadas { display: flex; flex-direction: column; gap: var(--sp-4); padding: var(--sp-4); }
  .lista-llamadas > .secundario { padding: var(--sp-4) 0; }

  .llamada-pendiente {
    display: grid;
    gap: var(--sp-1);
    padding: var(--sp-4) var(--sp-5);
    border: 1px solid var(--borde);
    border-left-width: 4px;
    border-radius: var(--radio);
    background: var(--superficie);
    color: inherit;
    font: inherit;
    font-size: var(--txt-xs);
    text-align: left;
    cursor: pointer;
  }

  .llamada-pendiente:hover { background: var(--superficie-hover); }
  .llamada-pendiente[aria-current='true'] { border-color: var(--tinta); box-shadow: inset 0 0 0 1px var(--tinta); }
  .llamada-pendiente > span { display: block; }
  .llamada-pendiente .folio { display: flex; align-items: center; gap: var(--sp-3); color: var(--tinta-media); }
  .llamada-pendiente .espera { margin-left: auto; font-variant-numeric: tabular-nums; }
  .llamada-pendiente .espera.tarde { color: var(--mal-tinta); font-weight: 600; }
  .llamada-pendiente .motivo { color: var(--tinta); font-size: var(--txt-base); font-weight: 600; }
  .llamada-pendiente .motivo small { color: var(--tinta-suave); font-weight: 400; }
  .llamada-pendiente .detalle { color: var(--tinta-suave); }
  .llamada-pendiente.en-curso { background: var(--superficie-2); }

  .prioridad-roja { border-left-color: var(--bandera-rojo); }
  .prioridad-amarilla { border-left-color: var(--bandera-amarillo); }
  .prioridad-verde { border-left-color: var(--bandera-verde); }
  .prioridad-sin { border-left-color: var(--borde-fuerte); }

  /* Información de la unidad seleccionada (docs/02 §9.2) y datos de la llamada. */
  .datos-unidad, .datos-llamada { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-2) var(--sp-5); margin: 0; }
  .datos-unidad { padding: var(--sp-4) var(--pad) var(--pad); }
  .datos-unidad dt, .datos-llamada dt { color: var(--tinta-suave); }
  .datos-unidad dd, .datos-llamada dd { margin: 0; font-weight: 500; overflow-wrap: anywhere; }

  /* ── Despacho: todos los TEA a la vista, un clic despacha ── */
  .tabla-asignacion { min-width: 0; font-size: var(--txt-xs); }
  .tabla-asignacion td { white-space: normal; }
  .estado-asignacion { color: var(--info-tinta); }
  .bloque-despacho { display: grid; gap: var(--sp-5); padding-top: var(--sp-5); border-top: 1px solid var(--borde); }
  .bloque-despacho > h3 { margin: 0; color: var(--tinta-suave); font-size: var(--txt-2xs); font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; }
  .candidatas { display: flex; flex-direction: column; gap: var(--sp-3); }

  .candidata {
    display: grid;
    grid-template-columns: 1fr auto auto;
    align-items: center;
    gap: var(--sp-5);
    width: 100%;
    padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-5);
    border: 1px solid var(--borde);
    border-radius: var(--radio);
    background: var(--superficie);
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
  }

  .candidata:hover:not(:disabled) { background: var(--superficie-hover); }
  .candidata:disabled { opacity: 0.45; cursor: default; }
  .candidata.sugerida { border-color: var(--tinta); }
  .candidata-unidad, .candidata-tea { display: flex; flex-direction: column; line-height: 1.25; }
  .candidata-tea { align-items: flex-end; font-variant-numeric: tabular-nums; }
  .candidata-unidad small, .candidata-tea small { color: var(--tinta-suave); font-size: var(--txt-2xs); }
  .candidata-accion { padding: var(--sp-3) var(--sp-5); border-radius: var(--radio-sm); background: var(--superficie-activa); font-size: var(--txt-xs); font-weight: 600; white-space: nowrap; }
  .candidata.sugerida .candidata-accion, .candidata:hover:not(:disabled) .candidata-accion { background: var(--primario); color: var(--sobre-primario); }

  /* ── Fases: cronología; «Actualizar emergencia» registra la siguiente ── */
  .fases { display: grid; gap: var(--sp-1); margin: 0; padding: 0; list-style: none; }
  .fases li { display: flex; align-items: center; gap: var(--sp-4); padding: var(--sp-3) var(--sp-4); border-radius: var(--radio); color: var(--tinta-suave); }
  .fases li.cumplida { color: var(--tinta); }
  .fases li.cumplida > i { color: var(--ok-tinta); }
  .fases li.siguiente { background: var(--superficie-activa); color: var(--tinta); font-weight: 600; }
  .fases .hora { margin-left: auto; font-variant-numeric: tabular-nums; }
  .fases .hospital { display: block; color: var(--tinta-media); font-size: var(--txt-xs); font-weight: 400; }

  .confirmacion-emergencia { margin: 0; padding: var(--pad); border: 0; border-radius: var(--radio); background: var(--superficie-2); }
  .confirmacion-emergencia legend { float: left; width: 100%; padding: 0 0 var(--sp-4); font-size: var(--txt-xs); font-weight: 600; }

  .campo-rol .casilla { flex-direction: row; align-items: center; gap: var(--sp-3); color: var(--tinta-suave); font-size: var(--txt-xs); }

  .mapa { flex: 1; min-height: 0; background: var(--superficie-2); }

  @media (width < 1280px) {
    .consola-radio { grid-template-columns: 240px minmax(0, 1fr) 260px; }
  }

  /* Apilada: lo que se está trabajando va primero. */
  @media (width < 1024px) {
    .consola-radio { grid-template-columns: minmax(0, 1fr); }
    .consola-radio .columna-trabajo { order: -1; }
  }

  @media (width >= 1920px) {
    .consola-radio { grid-template-columns: 340px minmax(0, 1fr) 380px; }
  }
}

/* ── pantallas/telefonista.css ── */
/* Telefonista (docs/02 §13-§18; diseño en pantallas.md §4). Puesto de trabajo. */
@layer pantallas {
  /* Captura · histórico. La captura manda: es donde está quien atiende. */
  .telefonista { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); gap: var(--gap); }
  .telefonista > .panel { display: flex; flex-direction: column; min-height: 0; margin: 0; }

  /* Paso 1: el tipo ES el botón. Un clic levanta la llamada. */
  .tipos-llamada { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-4); }

  .tipo-llamada {
    display: grid;
    gap: var(--sp-1);
    padding: var(--sp-5) var(--pad);
    border: 1px solid var(--borde-fuerte);
    border-radius: var(--radio-lg);
    background: var(--superficie);
    color: var(--tinta);
    font: inherit;
    text-align: left;
    cursor: pointer;
  }

  .tipo-llamada strong { font-size: var(--txt-md); font-weight: 600; }
  .tipo-llamada span { color: var(--tinta-suave); font-size: var(--txt-xs); }
  .tipo-llamada:hover { background: var(--superficie-hover); }
  .tipo-llamada.principal { border-color: var(--primario); background: var(--primario); color: var(--sobre-primario); }
  .tipo-llamada.principal span { color: color-mix(in oklch, var(--sobre-primario) 75%, transparent); }
  .tipo-llamada.principal:hover { background: var(--primario-hover); }

  /* Folio y tipo; debajo, estatus y quién la registró (los «Detalles del servicio», §15.1). */
  .cabecera-llamada { display: grid; gap: var(--sp-1); }
  .cabecera-llamada small { color: var(--tinta-suave); font-size: var(--txt-xs); font-weight: 400; }

  /* Apilado: la captura arriba, el histórico debajo. */
  @media (width < 1024px) {
    .telefonista { grid-template-columns: minmax(0, 1fr); }
  }

  @media (width < 768px) {
    .tipos-llamada { grid-template-columns: minmax(0, 1fr); }
  }
}

/* ── pantallas/telematica.css ── */
/* Operaciones ▸ Telemática y la ficha de telemática de la unidad (maqueta 8). */
@layer pantallas {
  /* Estado: conexión, cierre diario, permisos y webhook, de dos en dos desde 1024 px. */
  .estado-telematica { display: grid; gap: var(--gap); }
  .estado-telematica > .panel { margin-bottom: 0; }

  @media (width >= 1024px) {
    .estado-telematica { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  }

  /* La ruta cabe en el panel sin empujar los viajes fuera de la vista. */
  .mapa-ruta { height: 16rem; overflow: hidden; border: 1px solid var(--borde); border-radius: var(--radio); background: var(--superficie-2); }
  .mapa-ruta img { display: block; width: 100%; height: 100%; object-fit: cover; }

  /* La foto de la unidad es un fotograma con fecha, no un retrato. */
  .ficha-foto { margin: 0 0 var(--gap); overflow: hidden; border: 1px solid var(--borde); border-radius: var(--radio); background: var(--superficie-2); }
  .ficha-foto img { display: block; width: 100%; max-height: 12rem; object-fit: cover; }
  .ficha-foto figcaption { padding: var(--sp-3) var(--sp-5); color: var(--tinta-suave); font-size: var(--txt-xs); }
  .material-extraido { display: block; width: 100%; max-height: 70vh; object-fit: contain; border-radius: var(--radio); background: var(--superficie-2); }

  /* Marcha y, dentro, el ralentí: el ralentí es parte de la marcha, no otra cosa. */
  .barra-actividad { width: var(--ancho, 0%); min-width: 2px; height: 10px; overflow: hidden; border-radius: var(--radio-sm); background: var(--ok-tinta); }
  .barra-actividad span { display: block; width: var(--dentro, 0%); height: 100%; background: var(--aviso-tinta); }

  /* Ventana de fechas en la cabecera de su tarjeta (Recorrido, Conductor). */
  .ficha-tarjeta h3:has(.ficha-ventana, .ficha-acciones) { flex-wrap: wrap; align-items: center; }

  .ficha-ventana {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-3);
    margin-left: auto;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
  }

  .ficha-ventana input { flex: 1 1 11rem; min-width: 0; height: var(--alto-control-sm); }

  /* Un aviso suelto dentro de un panel respira contra lo que tiene al lado. */
  [data-panel] .panel > .error, [data-panel] .panel > div > .error { margin: var(--sp-5) var(--pad); }
  [data-panel] .datos dd { overflow-wrap: anywhere; }
}
