/* Brújula · capa de animación estándar
   ─────────────────────────────────────────────────────────────────────────
   Objetivo: navegación moderna, fluida y con personalidad — entradas con
   cascada elegante, feedback táctil con un toque de rebote, y transiciones
   refinadas entre módulos. De forma ESTANDARIZADA y ÓPTIMA.
   Principios (no se rompe ningún proceso existente):
     · Solo se anima lo barato para el GPU: opacity y transform (compositor).
     · Todo el movimiento vive dentro de @media (prefers-reduced-motion: no-preference):
       si el sistema pide menos movimiento, NADA se anima.
     · Mejoras progresivas: lo que un navegador no soporta (p. ej. View Transitions
       en Safari iOS hoy) simplemente no ocurre, sin romper nada.
     · No se toca <body> con transform (rompería los topbars position:fixed);
       la entrada se anima en <main>, que es el contenido desplazable.
   Para subir/bajar la intensidad general, edita los tokens de MOVIMIENTO en
   assets/tokens.css (única fuente de verdad desde jul 2026 — antes estaban
   duplicados aquí con OTROS valores y ganaba el que cargara último, con 2
   páginas cargando al revés: mismo token, distinta velocidad). */

:root{
  /* Solo fallbacks de look (radios/glow) para páginas sin tokens.css.
     El movimiento (--amr-dur*, --amr-ease*, --amr-rise) vive en tokens.css. */
  --radius-sm:8px; --radius-md:12px; --radius-lg:24px;
  --glow-gold:rgba(193,154,75,.45);
}
[data-theme="dark"]{ --glow-gold:rgba(217,184,118,.40); }

/* ── Capa moderna compartida (todo el portal) ────────────────────────────
   Esquinas redondeadas en controles + resplandor dorado en el hover de los
   botones .btn. Solo cosmético (radio/sombra); no toca el layout. Las
   tarjetas y paneles a medida de cada módulo se redondean al migrarlos. */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]),
select, textarea, button, .btn{ border-radius: var(--radius-sm); }
/* El resplandor dorado del hover SE RETIRÓ el 23 sep 2026: con «plano con
   profundidad» el botón ya tiene su relieve, y este brillo lo SUSTITUÍA justo al
   pasar el cursor. Samuel lo había rechazado dos veces antes (tarjetas y widgets
   del Inicio: «el resplandor al hacer hover no me gusta»). */

/* ── Switches del portal · "Relieve sutil" ───────────────────────────────────
   Acabado moderno con algo de profundidad (no plano, no skeuo cargado): pista
   apagada con leve hundido, pista encendida en oro con degradado muy tenue, y
   perilla (bola) navy con sombra suave + brillo arriba. Geometría de cada módulo
   intacta; solo se redefine fondo/sombra/perilla con !important para unificar.
   Cubre: .switch (.switch-tr / .track), .notif-switch, .lp-switch, .venc-switch. */
/* Sus colores (--tgl-off, --tgl-knob) son del TEMA: viven en tokens.css (el núcleo)
   y en tema.css (el cliente) desde el 23 sep 2026; aquí estaban los de Amoramar
   escritos a mano, en el núcleo. */
/* Pista apagada: leve hundido. */
.switch-tr, .switch .track, .notif-switch-track, .lp-switch span, .venc-switch-slider{
  background: var(--tgl-off) !important; border-color: transparent !important;
  box-shadow: var(--hundido) !important;
}
/* Pista encendida: oro con degradado tenue. */
.switch input:checked + .switch-tr,
.switch input:checked + .track,
.notif-switch input:checked + .notif-switch-track,
.lp-switch input:checked + span,
.venc-switch input:checked + .venc-switch-slider{
  background: linear-gradient(180deg, var(--gold-soft,#e8cc8e), var(--gold,#c19a4b)) !important;
  border-color: transparent !important;
  box-shadow: none !important;
}
/* Perilla: bola navy con sombra suave y brillo superior. */
.switch-tr::after, .switch .track::after, .notif-switch-track::after,
.lp-switch span::before, .venc-switch-slider::before{
  background: var(--tgl-knob) !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.2), var(--relieve-tarjeta) !important;
}

/* ── Botón trabajando (lo inserta amrOcupado, en theme.js) ─────────────────
   El anillo va DENTRO del botón, pegado a su texto: quien pulsó mira ahí, no a
   una esquina de la pantalla. Hereda `currentColor`, así que sirve igual en el
   botón dorado, en el fantasma y en el de peligro sin una regla por cada uno.

   El DIBUJO va fuera del @media de movimiento a propósito: es información de
   estado —«esto está trabajando»—, no adorno, y quien pide menos movimiento
   también necesita verlo. Lo único que se reserva al @media es el giro.

   `flex` en el botón evita el salto de layout típico de meterle un spinner. */
.amr-spin{
  display:inline-block; width:.85em; height:.85em; flex:none;
  margin-right:.5em; vertical-align:-.1em;
  border:2px solid currentColor; border-top-color:transparent;
  border-radius:var(--radius-pill,999px);
}
button:has(.amr-spin), .btn:has(.amr-spin){ display:inline-flex; align-items:center; justify-content:center; }
@keyframes amr-giro{ to{ transform: rotate(360deg) } }

/* ── Marca de «hecho» (la inserta amrHecho, en theme.js) ───────────────────
   Aparece centrada, dice que la operación terminó y se va sola. NO bloquea:
   `pointer-events:none` para que quien ya está en lo siguiente ni la note.

   Igual que el anillo, el DIBUJO vive fuera del @media de movimiento: para
   quien pidió menos movimiento la marca aparece ya trazada, pero aparece. */
.amr-hecho{
  position:fixed; left:50%; top:38%; transform:translate(-50%,-50%);
  z-index:var(--z-toast,9999); pointer-events:none;
  display:flex; flex-direction:column; align-items:center; gap:10px;
  padding:22px 26px; border-radius:var(--radius-md,12px);
  background:var(--glass-float-solid,var(--surface-raised,#fff));
  border:1px solid var(--border-2); box-shadow:var(--elev-2);
  color:var(--ink); font-family:var(--font-sans,inherit);
  font-size:var(--text-base,14px); font-weight:var(--weight-semibold,600);
  text-align:center; max-width:min(var(--maxw-dialogo,520px), calc(100vw - 48px));
}
.amr-hecho svg{ width:44px; height:44px; display:block; overflow:visible }
.amr-hecho circle{ fill:none; stroke:var(--ok,#2f7d4f); stroke-width:2; opacity:.35 }
.amr-hecho path{
  fill:none; stroke:var(--ok,#2f7d4f); stroke-width:3;
  stroke-linecap:round; stroke-linejoin:round;
}
.amr-hecho.yendose{ opacity:0; transition:opacity 160ms var(--amr-ease,ease) }

/* Fila que se va: solo se anima el alto que ya se fijó en píxeles. */
.amr-colapsa{
  transition:height 200ms var(--amr-ease,ease), opacity 160ms var(--amr-ease,ease);
  opacity:0;
}

/* ── Esqueleto de carga · UNO para todo el portal ──────────────────────────
   Vivía en `ui.css`, donde solo lo veían 26 de las 43 páginas: las otras 17
   seguían enseñando «Cargando…» de texto porque no cargan el kit. Bajó aquí
   —anim.css está en las 42 páginas operativas— para que el estado de carga sea
   el MISMO en todas partes, que es lo que se pidió.

   Conserva el nombre `.ui-skel` a propósito: renombrarlo habría roto las cuatro
   pantallas que ya lo usaban sin darle nada a nadie.

   El brillo anima SOLO `transform` (lo barato para el GPU) y se apaga con
   reduced-motion — la silueta se queda, que es la información; lo que sobra es
   el barrido. */
.ui-skel{
  position:relative;overflow:hidden;
  background:var(--surface,#fbf6e8);
  border:1px solid var(--hairline,var(--border-2,rgba(10,31,51,.12)));
  border-radius:var(--radius-md,12px);
}
.ui-skel::after{
  content:"";position:absolute;inset:0;transform:translateX(-100%);
  background:linear-gradient(100deg,transparent 30%,var(--row-stripe,rgba(10,31,51,.06)) 50%,transparent 70%);
  /* Barrido pausado (1.6s) con gradiente angosto: el brillo "pasa" en vez de
     "parpadear". Sigue siendo solo transform. */
  animation:ui-skel-shine 1.6s cubic-bezier(.4,0,.2,1) infinite;
}
.ui-skel-line{height:11px;border-radius:var(--radius-pill,999px);background:var(--row-stripe,rgba(10,31,51,.07))}
@keyframes ui-skel-shine{to{transform:translateX(100%)}}
@media(prefers-reduced-motion:reduce){.ui-skel::after{animation:none}}

/* ── Estado VACÍO (y el de error) · UNO para todo el portal ────────────────
   La forma canónica de §15.3: icono de trazo + título editorial + una frase que
   diga QUÉ HACER — nunca «Sin datos», que informa de que no hay nada y deja a
   quien mira sin saber si se rompió, si le falta permiso o si le toca crear el
   primero.

   Vivía en `ui.css`, donde solo lo veían 33 de las 50 páginas, y por eso las
   otras seguían escribiendo el suyo: cuarenta clases distintas (`.cli-empty`,
   `.tj-vacio`, `.lpm-sec-empty`…) para el mismo momento. Baja aquí por el mismo
   motivo y con el mismo criterio que el esqueleto de carga de arriba, y conserva
   el nombre `.ui-state` para no romper las cinco pantallas que ya lo usaban.

   El error NO grita: sin caja roja, misma superficie calma, el icono en `--danger`
   y un botón de reintento. Un error es un estado de la pantalla, no una alarma.

   Se pone con `amrVacio(el, {...})` (theme.js) — escribir el markup a mano es
   como se llegó a tener cinco copias del mismo SVG inline. */
/* Todo con tokens y SIN valores de reserva: las 50 páginas que cargan `anim.css`
   cargan también `tokens.css` (la única que no lo hace, `offline.html`, tampoco
   carga este archivo). Los `var(--x, #hex)` que traía de `ui.css` solo eran
   deuda arrastrada. */
.ui-state{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--space-1);text-align:center;padding:var(--space-10) var(--space-7);
  background:var(--surface);border:var(--stroke) solid var(--hairline);
  border-radius:var(--radius-md);color:var(--muted);
}
/* Dentro de una celda de tabla la caja no repite fondo ni marco: ya los pone la
   fila, y una tarjeta dentro de otra se lee como un error de maquetación. */
td > .ui-state, th > .ui-state{background:transparent;border:0;padding:var(--space-8) var(--space-6)}
/* Y lo mismo dentro del MARCO de una lista (`.panel`, la zona que se desplaza):
   el marco ya es la tarjeta. */
.panel .ui-state, [data-fija-scroll] .ui-state{background:transparent;border:0}
/* EL DISEÑO DE LOS CUATRO ESTADOS (22 sep 2026, aprobado por Samuel sobre la
   maqueta: «una pantalla amable con el usuario y limpia»). El icono va dentro
   de un círculo suave —dorado si informa, rojo tenue si algo falló—, el título
   en la serif de la casa, UNA frase que dice qué hacer y un solo botón
   principal. Lo técnico no se enseña: va plegado en «Ver detalle para
   soporte». */
.ui-state-ic{width:52px;height:52px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  color:var(--gold);background:color-mix(in srgb,var(--gold) 14%,transparent);margin-bottom:var(--space-2)}
.ui-state-ic svg{width:26px;height:26px;display:block}
.ui-state-title{font-family:var(--font-serif);font-size:var(--text-xl);font-weight:var(--weight-semibold);color:var(--ink);line-height:1.2}
.ui-state-sub{font-size:var(--text-sm);line-height:1.6;max-width:36ch;color:var(--muted)}
/* El botón principal es el dorado de la casa; el secundario —«Quitar filtros»,
   que no crea nada— va en contorno. En frase, no en versalitas: es una acción
   que se lee, no un rótulo. */
.ui-state-cta{
  margin-top:var(--space-3);font-family:inherit;font-size:var(--text-sm);font-weight:var(--weight-semibold);
  padding:0 var(--space-4);min-height:var(--alto-control);display:inline-flex;align-items:center;justify-content:center;
  border-radius:var(--radius-sm);border:var(--stroke) solid var(--gold);
  background:var(--gold);color:var(--on-gold);cursor:pointer;text-decoration:none;
  transition:background-color var(--amr-dur-fast),border-color var(--amr-dur-fast),color var(--amr-dur-fast);box-shadow:var(--relieve)}
@media (hover:hover){.ui-state-cta:hover{background:var(--gold-soft);border-color:var(--gold-soft)}}
.ui-state-cta.sec{background:transparent;border-color:var(--hairline);color:var(--ink)}
@media (hover:hover){.ui-state-cta.sec:hover{background:var(--chip);border-color:var(--gold)}}
@media (pointer:coarse){.ui-state-cta{min-height:var(--tap-min)}}
.ui-state.is-error .ui-state-ic{color:var(--danger);background:var(--danger-bg)}
/* «Sin resultados» dice CON QUÉ se está filtrando: sin eso, una lista vacía se
   lee como «se borraron mis datos». */
.ui-state-filtros{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--space-1);max-width:40ch;margin-top:var(--space-1)}
.ui-state-chip{font-size:var(--text-xs);padding:3px 9px;border-radius:var(--radius-pill);background:var(--chip);color:var(--ink)}
/* El detalle técnico, plegado y en voz baja: sirve a soporte, no a quien mira. */
.ui-state-det{margin-top:var(--space-2);font-size:var(--text-xs);color:var(--muted);max-width:40ch}
.ui-state-det summary{cursor:pointer;text-decoration:underline;text-underline-offset:3px;list-style:none}
.ui-state-det summary::-webkit-details-marker{display:none}
.ui-state-det code{display:block;margin-top:var(--space-1);font-family:var(--font-mono);word-break:break-word;text-align:left}
/* La acción que llega escrita como HTML (`amrVacio.html({accionHTML})`). */
.ui-state-act{margin-top:var(--space-3)}

/* Filas del esqueleto: la separación y el alto los pone la utilidad
   `amrCargando` (theme.js), para que no haya dos maneras de escribirlo. */
.amr-cargando{display:flex;flex-direction:column;gap:8px;
  /* Sin parpadeo: si la respuesta llega antes de 300 ms, el esqueleto ni se ve. */
  animation:amr-cargando-entra var(--amr-dur-view) var(--amr-ease-out) .3s both}
@keyframes amr-cargando-entra{from{opacity:0}to{opacity:1}}
/* La silueta tiene la FORMA de una fila —el dato de la izquierda, el nombre, la
   cifra a la derecha— y la lista se desvanece hacia abajo: se lee como «esto
   se está llenando» y no como un bloque gris. */
.amr-cargando .ui-skel{padding:0 16px;display:flex;align-items:center;gap:var(--space-3)}
.amr-cargando .ui-skel-line{flex:none;height:9px;background:color-mix(in srgb,var(--gold) 16%,transparent)}
.amr-cargando .ui-skel-line.fin{margin-left:auto}
.amr-cargando .ui-skel:nth-child(2){opacity:.8}
.amr-cargando .ui-skel:nth-child(3){opacity:.6}
.amr-cargando .ui-skel:nth-child(n+4){opacity:.42}
/* Y si tarda, se dice — con calma y sin alarma. Va por retardo de CSS, que el
   portal respeta también con «movimiento reducido» (ahí solo acorta duraciones). */
.amr-cargando-lento{font-size:var(--text-xs);color:var(--muted);text-align:center;margin-top:var(--space-1);
  animation:amr-cargando-entra var(--amr-dur-view) var(--amr-ease-out) 4s both}
/* EL BARRIDO BAJA POR LA LISTA, no destella en bloque. Cada `.ui-skel` corría su
   brillo con el mismo reloj, así que tres o cinco filas se encendían y apagaban
   a la vez: se leía como un parpadeo del panel entero y no como algo cargando.
   Con un desfase por fila el brillo RECORRE la lista, que es lo que el ojo
   interpreta como trabajo en curso.
   Va con `animation-delay` NEGATIVO: así la primera pintada ya sale con cada
   fila en un punto distinto de su ciclo, en vez de arrancar todas en cero y
   tardar 1,6 s en separarse. Diez filas y se repite, igual que la escalera de
   las listas — quien espera la fila 40 no espera por una animación. */
.amr-cargando .ui-skel:nth-child(10n+1)::after{animation-delay:0ms}
.amr-cargando .ui-skel:nth-child(10n+2)::after{animation-delay:-160ms}
.amr-cargando .ui-skel:nth-child(10n+3)::after{animation-delay:-320ms}
.amr-cargando .ui-skel:nth-child(10n+4)::after{animation-delay:-480ms}
.amr-cargando .ui-skel:nth-child(10n+5)::after{animation-delay:-640ms}
.amr-cargando .ui-skel:nth-child(10n+6)::after{animation-delay:-800ms}
.amr-cargando .ui-skel:nth-child(10n+7)::after{animation-delay:-960ms}
.amr-cargando .ui-skel:nth-child(10n+8)::after{animation-delay:-1120ms}
.amr-cargando .ui-skel:nth-child(10n+9)::after{animation-delay:-1280ms}
.amr-cargando .ui-skel:nth-child(10n)::after{animation-delay:-1440ms}
/* En una tabla el esqueleto va dentro de una celda: sin fondo ni borde propios,
   que ya los pone la fila. */
td > .amr-cargando .ui-skel{border-radius:var(--radius-sm,8px)}

/* ── La superficie que reacciona: tarjetas, filas y casillas ────────────────
   Va FUERA del bloque de movimiento a propósito: encender un marco y acercar
   una sombra no es movimiento, es estado. Quien pide `reduced-motion` está
   pidiendo que no se muevan las cosas, no quedarse sin saber dónde está el
   puntero.

   LA REGLA: la superficie NO se mueve al pasar por encima.

   Antes saltaba —`translateY(-3px) scale(1.012)`, con `!important`, en las
   cuarenta pantallas— y eso rompía tres cosas:
     · Al rozar el borde inferior la tarjeta se apartaba del puntero: el hover
       se apagaba, bajaba, volvía… en bucle. Con ese parpadeo, un clic sobre un
       botón de dentro caía en el hueco y no pasaba nada.
     · El `scale` movía todo el contenido bajo el cursor: se apuntaba a un botón,
       la tarjeta crecía, el botón se desplazaba y el clic aterrizaba en otro
       sitio. Es la causa de «no responden los botones de su interior».
     · Tres píxeles y un 1,2 % son mucho para media pantalla: se leía como un
       brinco, no como un realce.

   Un BOTÓN sí puede saltar: se apunta a su centro, es pequeño y no contiene
   nada. Una superficie grande que contiene controles, no.

   Lo que la sustituye: el marco se enciende entero en dorado y la sombra del
   sistema (`--elev-1`, con su extensión negativa) se acerca. Siete pantallas
   tenían su propia versión de esto y hacían cinco cosas distintas. */
.card, .kpi, .hub-card, .kpi-card, .route-card, .m-card, .archived-route,
.order, .order-compact, .psl-item, .notif-item{
  transition: box-shadow var(--amr-dur,.2s) var(--amr-ease-out, ease),
              border-color var(--amr-dur,.2s) var(--amr-ease-out, ease),
              background-color var(--amr-dur,.2s) var(--amr-ease-out, ease);
}
.card:focus-within,.kpi:focus-within,.hub-card:focus-within,.kpi-card:focus-within,.route-card:focus-within,.m-card:focus-within,.order:focus-within,.order-compact:focus-within,.psl-item:focus-within,.notif-item:focus-within{
  border-color: var(--gold, #c19a4b);
  box-shadow: var(--elev-1, 0 1px 2px rgba(56,44,20,.05), 0 10px 28px -14px rgba(10,31,51,.18));
}
@media (hover:hover){.card:hover,.kpi:hover,.hub-card:hover,.kpi-card:hover,.route-card:hover,.m-card:hover,.archived-route:hover,.order:hover,.order-compact:hover,.psl-item:hover,.notif-item:hover{
  border-color: var(--gold, #c19a4b);
  box-shadow: var(--relieve-tarjeta);
}}

/* Un panel que scrollea recorta lo que sobresale de sus tarjetas.
   `overflow-y:auto` NO deja el otro eje en `visible` —la norma obliga a ponerlo
   en `auto` también—, así que la sombra se cortaba por los lados y el marco
   parecía «cortarse con límites invisibles». La solución no es quitar el scroll,
   es darle el aire que la sombra necesita; la página le resta ese mismo aire a
   su propio padding y el contenido no se mueve un píxel. */
[data-tarjetas-scroll]{
  padding-inline: var(--tarjeta-aire, 14px);
  padding-block: 2px var(--tarjeta-aire, 14px);
}

@media (prefers-reduced-motion: no-preference){

  /* ── 1. Transición fluida entre módulos (navegación MPA) ─────────────────
     Mejora progresiva: cross-fade nativo del navegador al pasar de una página
     a otra. La página entrante asciende y se asienta con un leve scale para un
     gesto más moderno; la saliente se desvanece subiendo apenas. En navegadores
     sin soporte no ocurre nada. */
  @view-transition { navigation: auto; }
  /* Transición entre páginas: cross-fade RÁPIDO y fluido (sin morph ni overlay).
     La saliente se desvanece en un instante; la entrante hace un fade con un
     ascenso mínimo. Navegación ligera y amena. En navegadores sin soporte, nada. */
  ::view-transition-old(root){ animation: amr-vt-out var(--amr-dur-fast) var(--amr-ease) both; }
  ::view-transition-new(root){ animation: amr-vt-in  var(--amr-dur,200ms) var(--amr-ease-fun) both; }
  /* Topbar persistente (nombrado por theme.js): pieza propia que se mantiene
     estable entre páginas — marco fijo de app. */
  ::view-transition-group(amr-topbar){ animation-duration: var(--amr-dur,200ms); }
  /* SIN doble movimiento: si la View Transition ya anima la página entrante,
     la entrada propia de <main> no se repite encima (la marca theme.js). */
  html[data-amr-vt] main{ animation: none; }
  /* …y las entradas de contenedores internos (tabs/gráficas) tampoco se
     duplican encima de la View Transition. */
  html[data-amr-vt] .tabs-wrap, html[data-amr-vt] .chart-wrap{ animation: none; }
  /* Dirección "volver": al regresar al inicio la página entra BAJANDO y la
     saliente se aparta hacia abajo — regresar se siente como regresar. */
  html[data-amr-nav="back"]::view-transition-new(root){ animation-name: amr-vt-in-back; }
  html[data-amr-nav="back"]::view-transition-old(root){ animation-name: amr-vt-out-back; }

  /* ── 2. Entrada del contenido en cada carga ──────────────────────────────
     El "feel" que sí perciben en móvil/iOS: cada navegación asienta el contenido
     con un ascenso + un scale casi imperceptible (.992 → 1) usando una curva de
     desaceleración elegante. CLAVE: NO se usa opacity → el contenido está visible
     desde el primer frame (nunca hay pantalla en blanco mientras carga). Solo se
     desliza/escala con transform. Se anima <main> (no <body>) para no afectar los
     topbars fijos; fill-mode `both` termina en transform:none → sin efecto
     colateral sobre position:sticky tras la animación. */
  main{ animation: amr-enter var(--amr-dur-enter) var(--amr-ease-fun) both; }

  /* ── 3. Micro-interacción: feedback al tocar/clicar en todo el portal ─────
     transform:scale no afecta el layout. La transición de regreso usa la curva
     con rebote (spring): al soltar, el elemento "rebota" levemente a su tamaño
     → tacto vivo y divertido, pero sutil. */
  button, .btn, [role="button"], .card{
    /* Al soltar, vuelve a su tamaño con un rebote MÍNIMO (press curve): se
       percibe "asentado y refinado", no un salto. v2: también transiciona la
       sombra (para el resplandor del hover — un estado, no una animación). */
    transition: transform var(--amr-dur-fast) var(--amr-ease-press),
                box-shadow var(--amr-dur,200ms) var(--amr-ease-out,ease);
  }
  /* Realce al pasar el mouse en cualquier botón: pequeño salto con rebote. El
     RESPLANDOR que lo acompañaba se retiró el 23 sep 2026 (plano con
     profundidad): pisaba el relieve de cada botón al pasar el cursor, y cada
     uno conserva ahora su propia sombra. */
  @media (hover:hover){button:hover,.btn:hover,[role="button"]:hover{
    transform: translateY(-2px);
  }}
  /* Filas DENTRO de menús/listas (hamburguesa, popovers, resúmenes): el salto
     con resplandor de los botones se ve raro en una fila — solo debe cambiar su
     fondo (regla propia de cada lista). `.amr-row` es la clase OPT-OUT reutilizable
     para cualquier fila con role="button" (4º caso del mismo patrón: ham-item,
     lote-toggle, vt-route-head, stats-row → las nuevas solo añaden la clase). */
  .amr-row:active{
    transform: none;
    box-shadow: none;
  }
@media (hover:hover){[role="menuitem"]:hover,.ham-item:hover,.amr-row:hover{
    transform: none;
    box-shadow: none;
  }}
  /* El press gana al hover (va después): baja y escala con rebote. */
  button:active, .btn:active, [role="button"]:active, .card:active{
    transform: scale(.94);
  }

  /* ── 3a-bis (v2). FOCO VISIBLE con aire — universal ──────────────────────
     Anillo dorado a 2px del contorno (en vez del outline pegado que definía
     cada módulo). Solo con :focus-visible (teclado / asistencia): el mouse no
     lo dispara. !important para ganarle a los outline inline de los módulos —
     es exactamente la capa de piel que debe unificar este gesto.

     ESTA regla es la que hace que los 82 `outline:none` que los módulos
     escribieron sobre `:focus` NO dejen a nadie sin señal de teclado. La
     auditoría concluyó lo contrario razonando solo sobre la especificidad
     contra la regla base de `tokens.css` (que usa `:where()`, especificidad 0)
     y sin ver este `!important`. Comprobado con Tab real: el anillo aparece.

     `summary` y `[tabindex]` se añadieron en ago 2026 para cerrar el único
     hueco que quedaba: la lista va por TIPO de elemento, así que un
     `<div tabindex="0">` con `outline:none` propio sí se quedaba fuera. Hoy el
     portal tiene un solo div enfocable (`.paste-zone` de Ajuste de pesos) y da
     la casualidad de que dibuja una alternativa — pero era suerte, no garantía.

     Lo fija `tests/foco-visible.test.mjs`. */
  button:focus-visible, .btn:focus-visible, [role="button"]:focus-visible,
  a:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible,
  summary:focus-visible, [tabindex]:focus-visible{
    outline: 2px solid var(--gold, #c19a4b) !important;
    outline-offset: 2px !important;
  }

  /* ── 3b. El PRESS de una tarjeta ───────────────────────────────────────────
     El realce del hover vive arriba, fuera de este bloque: un marco y una
     sombra no son movimiento. Aquí queda solo lo que SÍ lo es.
     Al pulsar se hunde un poco: es un gesto momentáneo —no hay parpadeo
     posible— y sin él no se distingue una tarjeta que abre algo de una que
     solo se mira. Un 0,6 %, no un 2 %: lo justo para que se sienta el dedo. */
  .card:active, .kpi:active, .hub-card:active, .kpi-card:active, .route-card:active,
  .m-card:active, .archived-route:active, .order:active, .order-compact:active,
  .psl-item:active, .notif-item:active{
    transform: scale(.994);
    transition: transform 90ms var(--amr-ease-press, ease);
  }

  /* ── 3c. Botones con icono: el icono reacciona al hover ───────────────────
     Cualquier botón/enlace-botón cuyo hijo directo es un <svg> (icono): al
     pasar el mouse el icono hace un "pop" con rebote suave (transición spring).
     Se excluyen los toggles de tema, que ya tienen su crossfade sol/luna. */
  button:not([data-theme-toggle]):not([data-anim]) > svg:not([data-icono]),
  a.btn:not([data-anim]) > svg:not([data-icono]), .btn:not([data-anim]) > svg:not([data-icono]),
  [role="button"]:not([data-theme-toggle]):not([data-anim]) > svg:not([data-icono]){
    transition: transform var(--amr-dur) var(--amr-ease-spring);
    transform-origin: center;
  }
  @media (hover:hover){button:not([data-theme-toggle]):not([data-anim]):hover > svg:not([data-icono]),a.btn:not([data-anim]):hover > svg:not([data-icono]),.btn:not([data-anim]):hover > svg:not([data-icono]),[role="button"]:not([data-theme-toggle]):not([data-anim]):hover > svg:not([data-icono]){
    transform: scale(1.18);
  }}
  button:not([data-theme-toggle]):not([data-anim]):active > svg:not([data-icono]),
  .btn:not([data-anim]):active > svg:not([data-icono]), [role="button"]:not([data-theme-toggle]):not([data-anim]):active > svg:not([data-icono]){
    transform: scale(1.05);   /* al pulsar, el icono cede un poco */
  }

  /* ── 3d. Animación CONTEXTUAL de iconos según lo que representan ───────────
     Pon data-anim="bell|box|bob|wiggle|pulse|advance" en el botón (o, dentro de
     una tarjeta, en el <svg> del icono) y al hover el icono cobra vida de forma
     acorde: la campana suena, la caja abre su tapa, la moto avanza, etc.
     Disparador: el :hover del propio botón, o el :hover de la tarjeta que lo
     contiene. */
  @media (hover:hover){[data-anim]:hover > svg,.card:hover  .card-icon[data-anim],.hub-card:hover .hub-card-icon[data-anim]{ transform: none; }}   /* base */

  @media (hover:hover){[data-anim="bell"]:hover > svg{ animation: amr-bell .8s ease; transform-origin: 50% 12%; }}
  @media (hover:hover){.card:hover .card-icon[data-anim="rewind"],.hub-card:hover .hub-card-icon[data-anim="rewind"]{ animation: amr-rewind .6s ease; transform-origin: center; }}
  @media (hover:hover){[data-anim="advance"]:hover > svg{ animation: amr-advance .6s ease; }}

  @media (hover:hover){.card:hover .card-icon[data-anim="bob"],.hub-card:hover .hub-card-icon[data-anim="bob"]{ animation: amr-bob .6s ease; }}
  @media (hover:hover){.card:hover .card-icon[data-anim="wiggle"],.hub-card:hover .hub-card-icon[data-anim="wiggle"]{ animation: amr-wiggle .55s ease; transform-origin: 50% 60%; }}
  @media (hover:hover){.card:hover .card-icon[data-anim="pulse"],.hub-card:hover .hub-card-icon[data-anim="pulse"]{ animation: amr-pulse .5s ease; transform-origin: center; }}
  @media (hover:hover){.card:hover .card-icon[data-anim="advance"],.hub-card:hover .hub-card-icon[data-anim="advance"]{ animation: amr-advance .6s ease; }}
  /* "El timón da una vuelta": una rueda de barco gira sobre su eje, como cuando
     se le da un golpe con la mano. `transform-origin:center` sobre el <svg> es
     el centro de SU caja, que es donde está el cubo del timón — sin declararlo
     giraría alrededor de la esquina y se saldría de la ficha. Gerencia. */
  @media (hover:hover){.card:hover .card-icon[data-anim="timon"],.hub-card:hover .hub-card-icon[data-anim="timon"]{ animation: amr-timon .8s ease-in-out; transform-origin: center; }}

  /* LOS GESTOS DEL MANUAL DE MARCA (30 sep 2026, §6 «Movimiento»). Los módulos
     que solo daban un saltito genérico —o nada— estrenan el suyo, y se mueve la
     pieza que significa: la moto hace un pique sobre su rueda trasera, el rayo
     destella, la llave se inclina, la balanza se mece, el carrito avanza y las
     teclas del POS se hunden una tras otra. Los que ya tenían su gesto afinado
     aquí —la tapa, la base de datos, las cajas, las columnas, la campana y el
     timón— se quedan: son los que el manual tomó de este archivo. */
  .card-icon[data-anim="pique"] .moto,.hub-card-icon[data-anim="pique"] .moto{ transform-box: view-box; transform-origin: 12px 35px; }
  .card-icon[data-anim="llave"] > g > path,.hub-card-icon[data-anim="llave"] > g > path{ transform-box: view-box; transform-origin: 24px 24px; }
  .card-icon[data-anim="balanza"] > :nth-child(n+4),.hub-card-icon[data-anim="balanza"] > :nth-child(n+4){ transform-box: view-box; transform-origin: 24px 14.4px; }
  @media (hover:hover){.card:hover .card-icon[data-anim="pique"] .moto,.hub-card:hover .hub-card-icon[data-anim="pique"] .moto{ animation: amr-pique calc(var(--amr-dur-lento) * 1.82) cubic-bezier(.3,.7,.4,1); }}
  @media (hover:hover){.card:hover .card-icon[data-anim="destello"] > path,.hub-card:hover .hub-card-icon[data-anim="destello"] > path{ animation: amr-destello var(--amr-dur-lento) linear; }}
  @media (hover:hover){.card:hover .card-icon[data-anim="llave"] > g > path,.hub-card:hover .hub-card-icon[data-anim="llave"] > g > path{ animation: amr-inclina var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1); }}
  @media (hover:hover){.card:hover .card-icon[data-anim="balanza"] > :nth-child(n+4),.hub-card:hover .hub-card-icon[data-anim="balanza"] > :nth-child(n+4){ animation: amr-mece calc(var(--amr-dur-lento) * 1.3) ease-out; }}
  @media (hover:hover){.card:hover .card-icon[data-anim="carrito"] > *,.hub-card:hover .hub-card-icon[data-anim="carrito"] > *{ animation: amr-avanza var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1); }}
  @media (hover:hover){.card:hover .card-icon[data-anim="teclas"] > circle,.hub-card:hover .hub-card-icon[data-anim="teclas"] > circle{ animation: amr-tecla calc(var(--amr-dur-lento) * .7) cubic-bezier(.3,.7,.4,1) both; }}
  .card-icon[data-anim="teclas"] > circle:nth-of-type(2),.hub-card-icon[data-anim="teclas"] > circle:nth-of-type(2){ animation-delay: 70ms; }
  .card-icon[data-anim="teclas"] > circle:nth-of-type(3),.hub-card-icon[data-anim="teclas"] > circle:nth-of-type(3){ animation-delay: 140ms; }
  .card-icon[data-anim="teclas"] > circle:nth-of-type(4),.hub-card-icon[data-anim="teclas"] > circle:nth-of-type(4){ animation-delay: 210ms; }

  /* "El visor se abre": al hover se desvanece el visor cerrado (.i-visor, la lente)
     y aparece levantándose hacia la frente la curva del visor abierto (.i-visor-open)
     — una sola línea del mismo grosor, sin óvalo. Se mantiene mientras hay hover.
     Solo opacidad/transform → fiable en todo navegador. Mis entregas (casco). */
  .card-icon[data-anim="visor"] .i-visor,
  .hub-card-icon[data-anim="visor"] .i-visor{ transition: opacity .3s var(--amr-ease-out); }
  .card-icon[data-anim="visor"] .i-visor-open,
  .hub-card-icon[data-anim="visor"] .i-visor-open{
    opacity: 0; transform-box: fill-box; transform-origin: center;
    transform: translateY(3px);
    transition: opacity .3s var(--amr-ease-out), transform var(--amr-dur-lento,.34s) var(--amr-ease-out);
  }
  @media (hover:hover){.card:hover .card-icon[data-anim="visor"] .i-visor,.hub-card:hover .hub-card-icon[data-anim="visor"] .i-visor{ opacity: 0; }}
  @media (hover:hover){.card:hover .card-icon[data-anim="visor"] .i-visor-open,.hub-card:hover .hub-card-icon[data-anim="visor"] .i-visor-open{ opacity: 1; transform: translateY(0); }}

  /* "La caja se abre": la tapa (.i-lid) se eleva recta como una plancha y deja
     la caja abierta (el borde de la abertura queda visible debajo). El rebote
     lo da la curva spring. Sirve igual en botón o dentro de una tarjeta. */
  .i-lid{ transition: transform var(--amr-dur-lento,.34s) var(--amr-ease-spring); }
  @media (hover:hover){[data-anim="box"]:hover > svg .i-lid,.card:hover .card-icon[data-anim="box"] .i-lid,.hub-card:hover .hub-card-icon[data-anim="box"] .i-lid{ transform: translateY(-11px); }}

  /* "Suena la campana": al pasar el cursor el pomo se hunde como cuando se le da
     con la palma, la cúpula acusa el golpe achatándose un pelo y salen dos ondas
     a los costados. Restaurantes.

     SE PULSA, NO SE BALANCEA. Es una campana de mostrador de hotel: está apoyada
     en su bandeja y se golpea el pomo. El vaivén amortiguado —el de `amr-bell`,
     la campanita de notificaciones— es de las campanas que CUELGAN, y aquí
     quedaría como si la mesa temblara.

     Es de UN DISPARO y no sostenida, al revés que los otros hover del Inicio: un
     timbre es un suceso, suena y se apaga. Sostenerlo sería un pomo hundido para
     siempre.

     La cúpula se achata desde su BASE (24,28) y no desde el centro: apoyada en
     la bandeja, lo que cede es la parte de arriba; achatándola por el centro se
     despegaría de la bandeja. Las ondas entran cuando el pomo ya tocó fondo. */
  /* Las ondas son ARCOS CONCÉNTRICOS con la cúpula (28 ago 2026), así que su
     centro de escala es el centro de la cúpula —24,28— y no un punto a ojo:
     al crecer se separan de ella en paralelo, que es como se propaga una onda.
     Con el origen anterior (24,22) el arco derecho se abría un poco más que el
     izquierdo. */
  .card-icon[data-anim="campana"] .i-ondas,
  .hub-card-icon[data-anim="campana"] .i-ondas{ transform-box: view-box; transform-origin: 24px 33.6px; }
  @media (hover:hover){
    .card:hover .card-icon[data-anim="campana"] .i-pomo,
    .hub-card:hover .hub-card-icon[data-anim="campana"] .i-pomo{
      transform-box: view-box;
      animation: amr-campana-pomo .5s var(--amr-ease-out);
    }
    .card:hover .card-icon[data-anim="campana"] .i-cupula,
    .hub-card:hover .hub-card-icon[data-anim="campana"] .i-cupula{
      transform-box: view-box; transform-origin: 24px 33.6px;
      animation: amr-campana-cupula .5s var(--amr-ease-out);
    }
    .card:hover .card-icon[data-anim="campana"] .i-ondas,
    .hub-card:hover .hub-card-icon[data-anim="campana"] .i-ondas{
      animation: amr-campana-ondas .55s var(--amr-ease-out) .14s;
    }
  }

  /* "Se acomoda la bodega": al pasar el cursor cada caja se corre por su
     entrepaño, escalonada, y SE QUEDA puesta mientras el cursor siga encima; al
     salir vuelven todas. El mueble no se mueve: si se moviera el conjunto no se
     leería que lo que se acomoda es la carga.

     Es una TRANSICIÓN y no una animación de un disparo, por lo mismo que el
     resto de los hover que se sostienen: una que va y vuelve se acaba con la
     mano todavía encima y parece que el icono se cansó.

     Los recorridos son cortos y CADA UNO TIENE SU TOPE: el entrepaño mide de 8 a
     40 y la caja 9 de ancho, así que la de arriba y la de abajo (x=12,5) pueden
     correrse hasta +17 y la del medio (x=26,5) solo +3 antes de salirse por el
     canto. Se usan 6 / -6 / 3,5, que se ve y no roza.

     Van por `nth-child` DENTRO de `.i-cajas`, y no por `rect:nth-of-type` sobre
     el <svg>: ahí el primer `rect` es el marco del mueble, y mover el marco es
     justo lo contrario de lo que se busca. Planta. */
  .card-icon[data-anim="bodega"] .i-cajas > rect,
  .hub-card-icon[data-anim="bodega"] .i-cajas > rect{
    transition: transform .34s var(--amr-ease-spring, cubic-bezier(.34,1.56,.64,1));
  }
  @media (hover:hover){
    .card:hover .card-icon[data-anim="bodega"] .i-cajas > rect:nth-child(1),
    .hub-card:hover .hub-card-icon[data-anim="bodega"] .i-cajas > rect:nth-child(1){ transform: translateX(6px); }
    .card:hover .card-icon[data-anim="bodega"] .i-cajas > rect:nth-child(2),
    .hub-card:hover .hub-card-icon[data-anim="bodega"] .i-cajas > rect:nth-child(2){ transform: translateX(-6px); transition-delay: 60ms; }
    .card:hover .card-icon[data-anim="bodega"] .i-cajas > rect:nth-child(3),
    .hub-card:hover .hub-card-icon[data-anim="bodega"] .i-cajas > rect:nth-child(3){ transform: translateX(3.5px); transition-delay: 120ms; }
  }

  /* "La pila se abre en capas": los tres discos de Base de datos se separan al
     pasar por encima, de arriba abajo y con retardo, como un fichero que se
     abanica. El nombre del icono es `capas` y hasta hoy NO TENÍA REGLA: el
     atributo estaba puesto desde que se dibujó la tarjeta y no animaba nada.

     Se mueve cada disco en sentidos distintos —la tapa sube, el de abajo baja—
     porque moverlos todos igual sería desplazar el icono entero, que no dice
     nada. La tapa es el <ellipse>; los dos cuerpos, los <path> en su orden de
     dibujo (de arriba abajo), así que `nth-of-type` basta y no hace falta
     ensuciar el SVG con clases.

     Solo `transform`, y dentro del bloque de `prefers-reduced-motion:
     no-preference` como todo lo de este archivo: con el movimiento apagado la
     pila se queda quieta, que es lo que tiene que pasar. */
  .card-icon[data-anim="capas"] > ellipse,
  .card-icon[data-anim="capas"] > path,
  .hub-card-icon[data-anim="capas"] > ellipse,
  .hub-card-icon[data-anim="capas"] > path{
    transition: transform .34s var(--amr-ease-spring, cubic-bezier(.34,1.56,.64,1));
  }
  @media (hover:hover){
    .card:hover .card-icon[data-anim="capas"] > ellipse,
    .hub-card:hover .hub-card-icon[data-anim="capas"] > ellipse{ transform: translateY(-2.5px); }
    .card:hover .card-icon[data-anim="capas"] > path:nth-of-type(1),
    .hub-card:hover .hub-card-icon[data-anim="capas"] > path:nth-of-type(1){ transform: translateY(-.5px); transition-delay: 60ms; }
    .card:hover .card-icon[data-anim="capas"] > path:nth-of-type(2),
    .hub-card:hover .hub-card-icon[data-anim="capas"] > path:nth-of-type(2){ transform: translateY(2.5px); transition-delay: 120ms; }
  }

  /* La rejilla que «se armaba pieza por pieza» se retiró el 23 sep 2026: la
     tarjeta de Herramientas es ahora la LLAVE del plan, que es una sola pieza,
     y se mece (`bob`) como las demás de una pieza. */

  /* "La punta se desdobla y se vuelve a doblar": el dog-ear (.i-corner) se refleja
     sobre su pliegue (a 45°) y regresa. Reflexión 2D (rotate+scaleY+rotate) → se ve
     como un plegado pero es fiable en todos los navegadores (incl. Safari/iOS),
     sin transformaciones 3D. Etiquetas. */
  .card-icon[data-anim="unfold"] .i-corner,
  .hub-card-icon[data-anim="unfold"] .i-corner{
    transform-box: fill-box; transform-origin: center;
    transform: rotate(45deg) scaleY(1) rotate(-45deg);   /* doblada (reposo) */
    transition: transform var(--amr-dur-lento,.34s) ease-in-out;
  }
  /* Mientras el mouse está en la tarjeta, la hoja se mantiene desdoblada; al salir
     se vuelve a doblar. */
  @media (hover:hover){.card:hover .card-icon[data-anim="unfold"] .i-corner,.hub-card:hover .hub-card-icon[data-anim="unfold"] .i-corner{
    transform: rotate(45deg) scaleY(-1) rotate(-45deg);  /* desdoblada (reflejada) */
  }}
  /* La diagonal del pliegue: visible doblada, oculta desdoblada. El retardo (media
     duración) la mantiene mientras la hoja se aplana y solo la oculta cuando el
     flap ya cubre la esquina → sin hueco, en ambos sentidos. */
  .card-icon[data-anim="unfold"] .i-crease,
  .hub-card-icon[data-anim="unfold"] .i-crease{ transition: opacity .25s ease-in-out .25s; }
  @media (hover:hover){.card:hover .card-icon[data-anim="unfold"] .i-crease,.hub-card:hover .hub-card-icon[data-anim="unfold"] .i-crease{ opacity: 0; }}

  /* "Se toma el maletín": el asa rebota hacia arriba. Asesoría. */
  .i-handle{ transition: transform .4s var(--amr-ease-spring); transform-origin: center bottom; }
  @media (hover:hover){.card:hover .card-icon[data-anim="case"] .i-handle,.hub-card:hover .hub-card-icon[data-anim="case"] .i-handle{ animation: amr-handle .6s var(--amr-ease-spring); }}

  /* "Las columnas suben en secuencia": cada columna del banco (.i-cols > path)
     crece desde su base, escalonada. Bancos. */
  @media (hover:hover){.card:hover .card-icon[data-anim="bank"] .i-cols > path,.hub-card:hover .hub-card-icon[data-anim="bank"] .i-cols > path{
    transform-box: fill-box; transform-origin: center bottom;
    animation: amr-rise-col .5s var(--amr-ease-out) both;
  }}
  @media (hover:hover){.card:hover .card-icon[data-anim="bank"] .i-cols > path:nth-child(1){ animation-delay: 0ms; }}
  @media (hover:hover){.card:hover .card-icon[data-anim="bank"] .i-cols > path:nth-child(2){ animation-delay: 70ms; }}
  @media (hover:hover){.card:hover .card-icon[data-anim="bank"] .i-cols > path:nth-child(3){ animation-delay: 140ms; }}
  @media (hover:hover){.card:hover .card-icon[data-anim="bank"] .i-cols > path:nth-child(4){ animation-delay: 210ms; }}

  /* ── 4. Cascada de entrada (reutilizable) ─────────────────────────────────
     Pon data-amr-stagger en un contenedor y sus hijos directos entran en
     cascada (fade + ascenso + leve pop). Ideal para grillas de tarjetas y
     listas. Aquí SÍ se usa opacity porque son elementos DENTRO de una página ya
     visible (no el <main> completo), así que no hay riesgo de pantalla en blanco
     al navegar. */
  /* fill: backwards (no `both`): mantiene el estado inicial DURANTE el retraso
     (la tarjeta espera invisible), pero al terminar NO retiene el transform —
     así no bloquea el hover/press de la tarjeta. El estado final coincide con el
     base (opacity:1, sin transform), así que es visualmente idéntico. */
  /* Entrada de los hijos: fade + ascenso suave con desaceleración. */
  [data-amr-stagger] > *{ animation: amr-cascade var(--amr-dur-enter) var(--amr-ease-out) backwards; }

  /* ── EL AVISO DE VACÍO LLEGA, no aparece ──────────────────────────────────
     Hasta el 13 sep 2026 `.ui-state` no tenía ninguna entrada: la pantalla
     cambiaba de esqueleto a aviso con un corte seco, y ese corte es justo el
     momento en que quien mira necesita entender que la búsqueda TERMINÓ y no
     que se rompió. Sube 8 px y aparece, con la duración de entrada de la casa.

     Y el icono hace una cosa sola: entra un poco pequeño y se asienta con el
     muelle. Es el único guiño —el aviso es una mala noticia pequeña («aquí no
     hay nada»), así que se le pone gracia, no fiesta—. Sin `!important` y con
     `backwards`, que suelta el transform al acabar: si lo retuviera, el icono
     se quedaría con su capa propia para siempre.

     Todo dentro del bloque de movimiento: con `reduced-motion` el aviso sale
     ya puesto y el icono en su tamaño final. Lo que se apaga es el viaje, no la
     información. */
  .ui-state{ animation: amr-vacio-entra var(--amr-dur-enter) var(--amr-ease-out) backwards; }
  .ui-state-ic{ animation: amr-vacio-icono var(--amr-dur-enter) var(--amr-ease-spring, cubic-bezier(.34,1.56,.64,1)) 70ms backwards; }

  /* ESCALERA BREVE en las diez primeras (guion de jul 2026).
     Antes entraban todos JUNTOS, en bloque; era una decisión deliberada —
     «combina con la apertura de la ventana, una sola pieza que se asienta»— y
     se revierte a propósito, no por descuido: el guion pide que una lista se
     lea como lista, con las filas llegando uña detrás de otra.

     22 ms de paso, dentro del 20–30 pedido. Solo diez: la fila 10 arranca a los
     198 ms y termina cerca de medio segundo, que es lo máximo que se puede
     hacer esperar a alguien que ya tiene los datos delante. De la 11 en
     adelante entran a la vez — quien busca la fila 40 no espera un segundo por
     una animación.

     Va con `:nth-child` y no con JS a propósito: una lista que se repinta cada
     pocos segundos no puede depender de que alguien acuerde de re-asignar
     retrasos. Si el contenedor no tiene `data-amr-stagger`, nada de esto ocurre. */
  [data-amr-stagger] > *:nth-child(1){ animation-delay:0ms }
  [data-amr-stagger] > *:nth-child(2){ animation-delay:22ms }
  [data-amr-stagger] > *:nth-child(3){ animation-delay:44ms }
  [data-amr-stagger] > *:nth-child(4){ animation-delay:66ms }
  [data-amr-stagger] > *:nth-child(5){ animation-delay:88ms }
  [data-amr-stagger] > *:nth-child(6){ animation-delay:110ms }
  [data-amr-stagger] > *:nth-child(7){ animation-delay:132ms }
  [data-amr-stagger] > *:nth-child(8){ animation-delay:154ms }
  [data-amr-stagger] > *:nth-child(9){ animation-delay:176ms }
  [data-amr-stagger] > *:nth-child(10){ animation-delay:198ms }

  /* El anillo del botón ocupado SOLO gira aquí; su dibujo vive fuera de este
     @media, porque un indicador de estado tiene que verse también para quien
     pidió menos movimiento. Gira `transform` y nada más. */
  .amr-spin{ animation: amr-giro .7s linear infinite; }

  /* La marca de «hecho» se dibuja: la caja entra con un rebote medido y el
     trazo se pinta solo. `stroke-dashoffset` no es de las baratas, pero aquí
     corre sobre UN path de nueve píxeles y una sola vez, no en bucle. */
  .amr-hecho{ animation: amr-hecho-entra 260ms var(--amr-ease-fun,cubic-bezier(.34,1.5,.55,1)) backwards; }
  .amr-hecho path{ stroke-dasharray:22; animation: amr-hecho-traza 320ms var(--amr-ease-out,ease-out) 120ms backwards; }
  .amr-hecho circle{ animation: amr-hecho-aro 400ms var(--amr-ease-out,ease-out) backwards; }

  /* ── 5. Realce al pasar el cursor (opt-in) ────────────────────────────────
     Añade la clase .amr-lift a una tarjeta/mosaico para un realce elegante:
     sube levemente con desaceleración suave. No se aplica en bloque para no
     chocar con los hover propios de cada módulo. */
  .amr-lift{ transition: transform var(--amr-dur) var(--amr-ease-out); }
  @media (hover:hover){.amr-lift:hover{ transform: translateY(-3px); }}

  /* ── 6. Micro-pulido global ────────────────────────────────────────────────
     Campos: el foco/hover transiciona suave (borde/sombra) en vez de saltar.
     Los módulos que definen su propia transition ganan por cascada. */
  input, select, textarea{
    transition: border-color var(--amr-dur-fast) ease, box-shadow var(--amr-dur-fast) ease,
                background-color var(--amr-dur-fast) ease;
  }
  /* CTA de tarjeta ("Abrir"): se asoma hacia la acción al pasar el mouse. */
  .card .card-cta{ transition: transform var(--amr-dur-fast) var(--amr-ease-out); }
  @media (hover:hover){.card:hover .card-cta{ transform: translateX(3px); }}
}

@keyframes amr-enter{
  from{ transform: translateY(var(--amr-rise)) scale(.986); }
  to  { transform: none; }
}
/* Los dos del aviso de vacío. Solo opacity y transform, y el fotograma final es
   el estado en reposo: así la versión sin movimiento se ve idéntica al final. */
@keyframes amr-vacio-entra{
  from{ opacity:0; transform:translateY(8px) }
  to  { opacity:1; transform:none }
}
@keyframes amr-vacio-icono{
  from{ transform:scale(.86) }
  to  { transform:none }
}
@keyframes amr-cascade{
  from{ opacity:0; transform: translateY(12px) scale(.98); }
  to  { opacity:1; transform: none; }
}
@keyframes amr-vt-out{
  from{ opacity:1; transform: none; }
  to  { opacity:0; transform: translateY(-8px) scale(.985); }
}
@keyframes amr-vt-in-back{
  from{ opacity:0; transform: translateY(-12px) scale(.985); }
  to  { opacity:1; transform: none; }
}
@keyframes amr-vt-out-back{
  from{ opacity:1; transform: none; }
  to  { opacity:0; transform: translateY(10px) scale(.99); }
}
@keyframes amr-vt-in {
  from{ opacity:0; transform: translateY(14px) scale(.97); }
  to  { opacity:1; transform: none; }
}
/* Animaciones contextuales de icono (ver §3d). */
@keyframes amr-rewind{
  0%{ transform: rotate(0); } 45%{ transform: rotate(-16deg); }
  75%{ transform: rotate(4deg); } 100%{ transform: rotate(0); }
}
@keyframes amr-campana-pomo{
  0%,100%{ transform: translateY(0); }
  20%    { transform: translateY(2.4px); }   /* la palma lo hunde */
  55%    { transform: translateY(-.7px); }   /* y el muelle lo devuelve */
}
@keyframes amr-campana-cupula{
  0%,100%{ transform: scaleY(1); }
  20%    { transform: scaleY(.955); }
  55%    { transform: scaleY(1.015); }
}
@keyframes amr-campana-ondas{
  0%  { opacity:0; transform: scale(.55); }
  35% { opacity:1; transform: scale(1); }
  100%{ opacity:0; transform: scale(1.3); }
}
@keyframes amr-bell{
  0%,100%{ transform: rotate(0); }
  10%{ transform: rotate(16deg); } 25%{ transform: rotate(-13deg); }
  40%{ transform: rotate(9deg); }  55%{ transform: rotate(-6deg); }
  70%{ transform: rotate(3deg); }  85%{ transform: rotate(-1deg); }
}
/* Los gestos de módulo del manual de marca (ver 3d). */
@keyframes amr-pique{ 0%,100%{ transform: none; } 18%{ transform: translateX(-1.6px); } 42%{ transform: translateX(6px) rotate(-8deg); } 62%{ transform: translateX(4.5px) rotate(0); } 80%{ transform: translateX(-.8px); } }
@keyframes amr-destello{ 0%,100%{ opacity: 1; } 20%{ opacity: .25; } 40%{ opacity: 1; } 60%{ opacity: .45; } }
@keyframes amr-inclina{ 0%,100%{ transform: none; } 45%{ transform: rotate(-18deg); } 75%{ transform: rotate(4deg); } }
@keyframes amr-mece{ 0%,100%{ transform: none; } 25%{ transform: rotate(9deg); } 50%{ transform: rotate(-6deg); } 75%{ transform: rotate(3deg); } }
@keyframes amr-avanza{ 0%,100%{ transform: none; } 40%{ transform: translateX(4px); } 70%{ transform: translateX(-.8px); } }
@keyframes amr-tecla{ 0%,100%{ transform: none; } 40%{ transform: translateY(1.8px); } }
@keyframes amr-bob{
  0%,100%{ transform: translateY(0); }
  40%{ transform: translateY(-4px); } 70%{ transform: translateY(-1px); }
}
@keyframes amr-wiggle{
  0%,100%{ transform: rotate(0); }
  25%{ transform: rotate(-8deg); } 60%{ transform: rotate(8deg); } 85%{ transform: rotate(-3deg); }
}
@keyframes amr-pulse{
  0%,100%{ transform: scale(1); }
  45%{ transform: scale(1.14); } 70%{ transform: scale(.98); }
}
@keyframes amr-advance{
  0%{ transform: translateX(0); } 45%{ transform: translateX(5px); }
  70%{ transform: translateX(-1px); } 100%{ transform: translateX(0); }
}
/* Vuelta ENTERA, no un vaivén: el timón gira sobre su eje y para donde estaba.
   Acaba en 360 y no en 0 a propósito — «hasta 0» no daría vuelta ninguna.
   La curva es `ease-in-out` y no la del resto del catálogo: una rueda arranca y
   para, no aparece a toda velocidad. Medido en el preview, reparte la vuelta en
   14 / 58 / 89 / 96 / 100 % — empuja, corre y se posa. Con `--amr-ease-out` del
   portal daba 260° en los primeros 120 ms y el resto se arrastraba: parecía que
   se hubiera trabado, no que estuviera girando. */
@keyframes amr-timon{
  0%{ transform: rotate(0); }
  100%{ transform: rotate(360deg); }
}
@keyframes amr-poprect{
  0%{ transform: scale(.35); opacity:.35; }
  60%{ transform: scale(1.12); opacity:1; }
  100%{ transform: scale(1); }
}
@keyframes amr-handle{
  0%,100%{ transform: translateY(0); }
  40%{ transform: translateY(-3px); } 70%{ transform: translateY(-1px); }
}
@keyframes amr-rise-col{
  0%{ transform: scaleY(0); }
  65%{ transform: scaleY(1.06); }
  100%{ transform: scaleY(1); }
}

/* ── Evitar el zoom automático de iOS al enfocar campos de texto ──
   iOS Safari hace zoom si el control tiene font-size < 16px, y quien lo sufre
   tiene que volver a alejar la página a dos dedos para seguir escribiendo.

   El disparador ya NO es el ancho: es que la pantalla sea TÁCTIL. Con
   `max-width:520px` a secas la regla no llegaba ni al iPad ni al iPhone en
   APAISADO —los dos miden más de 520— y ahí el zoom seguía intacto. Medido a
   834px (iPad vertical): 111 de 112 campos visibles por debajo de 16px, o sea
   que la protección no cubría prácticamente nada fuera del teléfono de pie.

   `pointer:coarse` es la pregunta correcta —¿se usa con el dedo?— y cubre las
   tres a la vez. Se conserva la cláusula de ancho para no quitarle la regla a
   nadie que la tuviera: es un superconjunto, no un cambio.

   Quedan 144 reglas de campo con tamaño propio por debajo de 16px repartidas en
   44 archivos; esta capa las nivela sin tocarlas una a una. */
@media (pointer:coarse), (max-width:520px){
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="button"]):not([type="submit"]),
  textarea,
  select{ font-size:16px !important; }
}

/* ── Header estandarizado en todos los módulos ───────────────────────────
   Una sola capa que unifica el encabezado (la marca "Brújula | <módulo>",
   el enlace de retorno y los botones de utilidad) en las dos familias de
   clases que existen en el portal: la estándar (.topbar / .brand-*) y la de
   etiquetas (.brujula-topbar / .bt-*). Se carga en las 15 páginas, así que
   cualquier deriva entre copias inline queda nivelada. Solo afecta al
   encabezado; no toca el contenido ni la impresión. */

/* IMPORTANTE: todo se acota DENTRO de los topbars de módulo (.topbar /
   .brujula-topbar). El encabezado del menú de inicio (.header) reusa la clase
   .brand-name para el wordmark grande y NO debe verse afectado por estas reglas. */

/* Wordmark uniforme: "Brújula" en EB Garamond (serif), IGUAL que el wordmark del
   menú de inicio (.header .brand-name), para estandarizar todos los headers. */
.topbar .brand-name, .brujula-topbar .bt-brand{
  font-family:var(--font-serif);
}
/* Separador dorado coherente entre marca y nombre del módulo. */
.topbar .brand-sep, .brujula-topbar .bt-sep{ background:var(--gold,#c9a24b) !important; opacity:.7; }

/* ── LA BARRA DE MARCA, UNA SOLA (22 sep 2026, estandarización del portal) ──
   Estaba copiada en 33 pantallas con 14 variantes de `.topbar` —y 7 del botón
   de tema, 7 del «← Inicio», 7 de la marca—: alturas de 63 a 68 px, huecos de
   16 y 20, botón de 34 y de 36, separador de 16 y de 18, la marca a 17, 18 y
   20 px y un título en dorado. Nadie había decidido esas diferencias: eran la
   misma barra escrita en momentos distintos. Aquí vive la de todas; la pantalla
   solo pone lo que es SUYO (sus botones, o un `flex` si su <body> es columna).
   El vidrio es la regla de más abajo (`--glass-blur-chrome`), y el teléfono, el
   bloque «Móvil: UN encabezado». Lo cuida `tests/una-sola-barra.test.mjs`.

   `:where(.topbar)` deja la especificidad en la de una clase (0,1,0): lo que
   una pantalla ajusta a propósito —su relleno móvil, un botón más grande—
   sigue ganando, y la `.brand` de la etiqueta impresa no es de aquí. */
.topbar{position:sticky;top:0;z-index:var(--z-topbar,1000);background:var(--topbar);border-bottom:1px solid var(--border-2);
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:var(--space-5,20px);
  padding:calc(14px + env(safe-area-inset-top,0px)) var(--pad-x) 14px}
:where(.topbar) .brand{display:flex;align-items:center;justify-self:start}
:where(.topbar) > .brand-back{justify-self:start}
:where(.topbar) .brand-back{font-size:var(--text-mini);letter-spacing:var(--track-widest);text-transform:uppercase;color:var(--muted);
  text-decoration:none;font-weight:var(--weight-semibold,600);transition:color var(--amr-dur-fast,.15s)}
:where(.topbar) .brand-center{display:flex;align-items:center;gap:10px;justify-self:center}
:where(.topbar) .brand-name{font-size:var(--text-cuerpo);letter-spacing:var(--track-widest);color:var(--ink);text-transform:uppercase;
  font-weight:var(--weight-semibold,600);padding-left:.18em;text-decoration:none;transition:color var(--amr-dur-fast,.15s)}
:where(.topbar) .brand-sep{width:1px;height:18px;background:var(--gold);opacity:.7}
:where(.topbar) .brand-sub{font-size:var(--text-micro);letter-spacing:var(--track-widest);color:var(--muted);text-transform:uppercase;font-weight:var(--weight-semibold,600);margin:0}
:where(.topbar) .topbar-actions{display:flex;gap:var(--space-2,8px);align-items:center;justify-self:end}
:where(.topbar) > .theme-toggle{justify-self:end}
:where(.topbar) .theme-toggle{background:transparent;border:1px solid var(--border-2);color:var(--muted);width:36px;height:36px;
  border-radius:var(--radius-sm,8px);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
  padding:0;position:relative;
  transition:background-color var(--amr-dur-fast,.15s),color var(--amr-dur-fast,.15s),border-color var(--amr-dur-fast,.15s)}
:where(.topbar) .theme-toggle .icon-sun,:where(.topbar) .theme-toggle .icon-moon{position:absolute;top:50%;left:50%;width:18px;height:18px;margin:-9px 0 0 -9px;
  transition:opacity var(--amr-dur-view,.28s) ease,transform var(--amr-dur-lento,.34s) var(--amr-ease-spring,cubic-bezier(.34,1.56,.64,1))}
:where(.topbar) .theme-toggle .icon-sun{opacity:1;transform:rotate(0) scale(1)}
:where(.topbar) .theme-toggle .icon-moon{opacity:0;transform:rotate(-180deg) scale(.4);pointer-events:none}
[data-theme="dark"] :where(.topbar) .theme-toggle .icon-sun{opacity:0;transform:rotate(180deg) scale(.4);pointer-events:none}
[data-theme="dark"] :where(.topbar) .theme-toggle .icon-moon{opacity:1;transform:none;pointer-events:auto}
@media (hover:hover){
  :where(.topbar) .brand-back:hover{color:var(--ink)}
  :where(.topbar) a.brand-name:hover{color:var(--gold)}
  :where(.topbar) .theme-toggle:hover{background:var(--ink);color:var(--bg);border-color:var(--ink)}
}

/* PWA instalada (standalone): el topbar sticky respeta el notch/barra de estado.
   Las páginas usan viewport-fit=cover, así que sin esto el contenido queda bajo
   la hora/batería en iPhones con notch. env() vale 0 donde no aplica; max()
   conserva el padding normal en pantallas sin notch. */
@media (display-mode:standalone){
  .topbar, .brujula-topbar, .ui-topbar{
    padding-top:calc(env(safe-area-inset-top, 0px) + 14px) !important;
  }
}

/* Móvil: UN encabezado para todo el portal — «← Inicio · MÓDULO · acciones»,
   con el nombre del módulo CENTRADO a la pantalla y a un solo tamaño (el del
   estándar de docs/ARQUETIPOS.md). Medido el 22 sep 2026 a 375 px: había tres
   tamaños de título (9, 13 y 18 px) y el centro se iba de −41 a +58 px, porque
   cada pantalla traía su copia —unas en rejilla, otras en flex con lados de
   distinto ancho— y la de la capa móvil solo alcanzaba a las que eran rejilla.
   Aquí se fuerza la rejilla con los dos lados IGUALES: el centro cae en el
   centro diga lo que diga cada copia. Son `1fr` y no `minmax(0,1fr)` a
   propósito: con tres botones a la derecha (Rutas, Gestión: 148 px contra 131
   de lado) el lado crece y el título se corre unos píxeles; con suelo cero los
   botones se montarían ENCIMA del título. Y el centro es `minmax(0,auto)`:
   si el título no cabe entre los dos lados, se recorta con puntos suspensivos
   en vez de pisar el retorno (Simulador de tarifas, 9 px encima). El wordmark «Brújula» no cabe junto
   al módulo y se va, como en la capa móvil.

   `screen` NO ES DECORACIÓN (23 sep 2026): una etiqueta de 100 mm son ~378 px,
   así que al IMPRIMIR esta consulta también casaba, y su `display:grid
   !important` —con clase, que pesa más que `body > *`— le ganaba al
   `body>*{display:none!important}` de la hoja de impresión. La barra salía
   encima de la etiqueta de los pedidos flash y la empujaba hasta cortarla. */
/* EL RELLENO DEL TELÉFONO, UNO SOLO (tanda de la barra, 23 sep 2026): 29
   pantallas se lo escribían en su propio `@media` —8, 10 o 12 px, con o sin la
   zona segura, a 520, 600, 640, 720 o 760 px— y la misma barra medía distinto
   según el módulo. Ahora es este: 8 px más la zona segura arriba, la zona segura
   a los lados y 46 px de alto mínimo. Sin `!important` a propósito: una
   pantalla que de verdad necesite otra cosa (las etiquetas) la pisa con la suya. */
@media screen and (max-width:760px){
  .topbar{
    padding:calc(env(safe-area-inset-top,0px) + 8px) max(var(--pad-x-movil),env(safe-area-inset-right)) 8px max(var(--pad-x-movil),env(safe-area-inset-left));
    min-height:46px;
  }
}
@media (display-mode:standalone) and (min-width:761px){
  .topbar{padding-left:max(var(--pad-x),env(safe-area-inset-left));padding-right:max(var(--pad-x),env(safe-area-inset-right))}
}
@media screen and (max-width:760px){
  .topbar, .brujula-topbar, .ui-topbar{
    display:grid !important;
    grid-template-columns:1fr minmax(0,auto) 1fr !important;
    align-items:center !important;
    gap:8px !important;
  }
  :is(.topbar, .ui-topbar, .brujula-topbar) > :first-child{ justify-self:start !important; }
  :is(.topbar, .ui-topbar, .brujula-topbar) > :last-child{ justify-self:end !important; }
  .topbar .brand-center, .ui-topbar .ui-brand-center, .brujula-topbar .bt-center{
    justify-self:center !important; min-width:0 !important; max-width:62vw; margin:0 !important;
  }
  .topbar .brand-name, .topbar .brand-sep,
  .ui-topbar .ui-brand-name, .ui-topbar .ui-brand-sep,
  .brujula-topbar .bt-brand, .brujula-topbar .bt-sep{ display:none !important; }
  .topbar .brand-sub, .ui-topbar .ui-brand-sub, .brujula-topbar .bt-sub{
    display:block !important; opacity:1 !important; margin:0 !important;
    font-size:18px !important; font-weight:700 !important; letter-spacing:0 !important;
    padding-left:0 !important; text-transform:none !important; color:var(--ink) !important;
    white-space:nowrap !important; overflow:hidden; text-overflow:ellipsis; max-width:62vw;
  }
  .topbar .brand-back, .ui-topbar .ui-brand-back, .brujula-topbar .bt-back{ white-space:nowrap !important; }
  .topbar .topbar-actions, .ui-topbar .ui-topbar-actions, .brujula-topbar .bt-right{ gap:8px !important; }
  /* Botones de utilidad superior: 42×42 accesibles y parejos. */
  .topbar .theme-toggle, .brujula-topbar .bt-toggle, .topbar .topbar-icon, .topbar .topbar-upload, .topbar .refresh-btn, .topbar .reveal-toggle{
    width:42px !important; height:42px !important;
  }
}

/* ── Toque fluido en todo el portal (móvil/PWA) ──────────────────────────
   touch-action:manipulation quita el retardo de ~300 ms y la interferencia
   del doble-tap-zoom en elementos interactivos, sin afectar el scroll. Hace
   que botones, enlaces y controles respondan al primer toque. */
button, .btn, [role="button"], a, summary, label, select{ touch-action: manipulation; }

/* ── Sin "sticky hover" en dispositivos táctiles (móvil/PWA) ──────────────
   En pantallas sin hover real, iOS deja "pegado" el último :hover tocado →
   el elemento queda elevado/escalado hasta tocar otra cosa. Aquí anulamos SOLO
   los realces de :hover (transform) en táctil; el feedback de :active (press)
   y las entradas se conservan.

   REDUNDANTE DESDE AGO 2026, y se conserva a propósito. El comentario original
   decía que las reglas de escritorio «siguen intactas bajo (hover:hover)»: era
   la intención, no el hecho —solo dos archivos del portal tenían esa guarda—.
   Ahora sí lo están las 967, así que en táctil ningún :hover llega a aplicar y
   estos `!important` ya no anulan nada.
   No se retiran porque son la red por si alguien escribe un `:hover` nuevo sin
   guarda antes de que `npm run tokens:verificar` se lo diga. Si algún día el
   portal comprueba eso en las pruebas, este bloque se puede borrar entero. */
@media (hover: none), (pointer: coarse){
  button:hover, .btn:hover, [role="button"]:hover,
  .card:hover, .hub-card:hover, .kpi-card:hover, .route-card:hover, .m-card:hover,
  .archived-route:hover, .order:hover, .order-compact:hover, .psl-item:hover,
  .notif-item:hover{ transform: none !important; }
  .card:hover .card-cta{ transform: none !important; }   /* sin CTA "pegado" tras el toque */
  button:not([data-theme-toggle]):hover > svg,
  a.btn:hover > svg, .btn:hover > svg, [role="button"]:not([data-theme-toggle]):hover > svg{
    transform: none !important;
  }
}

/* ── Fondo de los módulos: PLANO (decisión de Samuel, jul 2026) ─────────────
   Solo el menú principal (html[data-amr-bg]) lleva textura: su oleaje animado.
   Los módulos van en color sólido — el patrón de ondas concéntricas estáticas
   que vivía aquí se retiró. */

/* ══ Modo mar: luz superior en las tarjetas ══════════════════════════════
   Sobre fondo navy, las tarjetas navy pierden relieve (dependen de un borde
   tenue). Un hairline de LUZ en el borde superior — "luz desde arriba" — las
   despega del fondo sin gradientes ni sombras nuevas. Solo cambia el COLOR
   del borde superior existente; los estados con más especificidad (hover
   dorado, selección) le ganan naturalmente. */
html[data-theme="dark"] .card,
html[data-theme="dark"] .hub-card, html[data-theme="dark"] .kpi-card,
html[data-theme="dark"] .route-card, html[data-theme="dark"] .m-card,
html[data-theme="dark"] .panel-card, html[data-theme="dark"] .order,
html[data-theme="dark"] .order-compact, html[data-theme="dark"] .rsm-tile,
html[data-theme="dark"] .active-route,
html[data-theme="dark"] .scard, html[data-theme="dark"] .art,
html[data-theme="dark"] .bank-card, html[data-theme="dark"] .ui-state,
html[data-theme="dark"] .ui-skel{
  border-top-color:rgba(243,235,216,.16);
}
@media (prefers-color-scheme:dark){
  html:not([data-theme="light"]) .card,
  html:not([data-theme="light"]) .hub-card, html:not([data-theme="light"]) .kpi-card,
  html:not([data-theme="light"]) .route-card, html:not([data-theme="light"]) .m-card,
  html:not([data-theme="light"]) .panel-card, html:not([data-theme="light"]) .order,
  html:not([data-theme="light"]) .order-compact, html:not([data-theme="light"]) .rsm-tile,
  html:not([data-theme="light"]) .active-route,
  html:not([data-theme="light"]) .scard, html:not([data-theme="light"]) .art,
  html:not([data-theme="light"]) .bank-card, html:not([data-theme="light"]) .ui-state,
  html:not([data-theme="light"]) .ui-skel{
    border-top-color:rgba(243,235,216,.16);
  }
}
/* Al resaltar en hover (marco dorado), el borde SUPERIOR también toma el acento.
   El hairline de "luz desde arriba" de arriba tiene más especificidad que
   `.card:hover`, así que sin esto el borde superior se quedaba crema y el marco
   dorado NO CERRABA: quedaba abierto justo por arriba.

   Esta corrección existía pero solo nombraba tres tarjetas (.card, .hub-card,
   .rsm-tile) mientras el hairline se aplica a catorce. Al resto —.route-card,
   .m-card, .kpi-card, los pedidos…— el marco les seguía faltando el lado de
   arriba; se vio en la ventana de una ruta, que es una .route-card grande y ahí
   el hueco canta. La lista de abajo es la MISMA del hover y la del focus, que
   es lo que impide que se vuelvan a desincronizar.

   Va también en :focus-within: quien navega con el teclado ve el mismo marco. */
@media (hover:hover){
  html[data-theme="dark"] .card:hover, html[data-theme="dark"] .kpi:hover,
  html[data-theme="dark"] .hub-card:hover, html[data-theme="dark"] .kpi-card:hover,
  html[data-theme="dark"] .route-card:hover, html[data-theme="dark"] .m-card:hover,
  html[data-theme="dark"] .archived-route:hover, html[data-theme="dark"] .order:hover,
  html[data-theme="dark"] .order-compact:hover, html[data-theme="dark"] .psl-item:hover,
  html[data-theme="dark"] .notif-item:hover, html[data-theme="dark"] .rsm-tile:hover{
    border-top-color:var(--gold);
  }
}
html[data-theme="dark"] .card:focus-within, html[data-theme="dark"] .kpi:focus-within,
html[data-theme="dark"] .hub-card:focus-within, html[data-theme="dark"] .kpi-card:focus-within,
html[data-theme="dark"] .route-card:focus-within, html[data-theme="dark"] .m-card:focus-within,
html[data-theme="dark"] .order:focus-within, html[data-theme="dark"] .order-compact:focus-within,
html[data-theme="dark"] .psl-item:focus-within, html[data-theme="dark"] .notif-item:focus-within{
  border-top-color:var(--gold);
}
@media (prefers-color-scheme:dark){
  @media (hover:hover){
    html:not([data-theme="light"]) .card:hover, html:not([data-theme="light"]) .kpi:hover,
    html:not([data-theme="light"]) .hub-card:hover, html:not([data-theme="light"]) .kpi-card:hover,
    html:not([data-theme="light"]) .route-card:hover, html:not([data-theme="light"]) .m-card:hover,
    html:not([data-theme="light"]) .archived-route:hover, html:not([data-theme="light"]) .order:hover,
    html:not([data-theme="light"]) .order-compact:hover, html:not([data-theme="light"]) .psl-item:hover,
    html:not([data-theme="light"]) .notif-item:hover, html:not([data-theme="light"]) .rsm-tile:hover{
      border-top-color:var(--gold);
    }
  }
  html:not([data-theme="light"]) .card:focus-within, html:not([data-theme="light"]) .kpi:focus-within,
  html:not([data-theme="light"]) .hub-card:focus-within, html:not([data-theme="light"]) .kpi-card:focus-within,
  html:not([data-theme="light"]) .route-card:focus-within, html:not([data-theme="light"]) .m-card:focus-within,
  html:not([data-theme="light"]) .order:focus-within, html:not([data-theme="light"]) .order-compact:focus-within,
  html:not([data-theme="light"]) .psl-item:focus-within, html:not([data-theme="light"]) .notif-item:focus-within{
    border-top-color:var(--gold);
  }
}

/* ── Kill-switch GLOBAL de reduced-motion (afinación jul 2026) ─────────────
   anim.css carga en TODAS las páginas → este bloque garantiza la preferencia
   en el CSS local de cada módulo (9 páginas animaban sin guard propio y 4
   loops escapaban de guards dirigidos: aiScan/aiPulse/aiBlink, spin,
   rt-marquee-scroll, pulse-strong, ios-ptr-spin). Las animaciones corren una
   sola vez en .01ms → las entradas quedan en su estado final visible y los
   pulsos/spinners quedan quietos. Cubre también lo futuro. */
/* Toque nativo canónico: los ELEMENTOS interactivos no parpadean con el
   highlight del sistema (cada módulo definía exclusiones distintas y un label
   parpadeaba dorado en unas páginas y en otras no). El feedback lo dan nuestros
   :active/:hover. Gana a los `*{...}` de página por especificidad. */
a, button, input, select, textarea, label, summary, [role="button"], [role="menuitem"]{
  -webkit-tap-highlight-color: transparent;
}

@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
    scroll-behavior:auto !important;
  }
  /* ACUSE DE TOQUE sin movimiento. Todo el feedback de :active del portal es
     `transform: scale(...)` y vive dentro de @media(no-preference), así que
     quien activa "reducir movimiento" —gente mayor, quien se marea— tocaba un
     botón y la pantalla NO acusaba recibo. La regla de la casa es que se apaga
     el movimiento, no la información: aquí el press se comunica atenuando, que
     no desplaza ni escala nada. */
  button:active, .btn:active, [role="button"]:active, a.card:active, .card:active{
    opacity:.7;
  }
}

/* ══ 7. PIEL MODERNA (v3, jul 2026) — misma base náutica, acabado 2025 ══════
   Central y aditiva: lavado de profundidad en tarjetas, glass real en topbars
   y scrollbars finos cálidos. Nada anima; cero costo en gestos. */
/* El «lavado de luz» que iba aquí —un degradado claro en la mitad de arriba
   de 16 tipos de tarjeta, con !important— se retiró el 23 sep 2026 (decisión
   de Samuel, viendo las dos versiones lado a lado): «plano con profundidad» es
   color sólido, y la profundidad de una tarjeta la da --relieve-tarjeta. Lo
   cuida tests/sin-degradados-en-las-tarjetas.test.mjs. */
/* Glass de verdad en las barras superiores (los módulos traían blur(6px); el
   token --topbar bajó su opacidad para dejarlo respirar). !important: es la
   capa de piel que unifica, igual que el gesto de hover. */
.topbar, .ui-topbar, .brujula-topbar{
  /* Por token: este es el ÚNICO sitio donde se decide el vidrio de las barras
     del portal, así que es el único que hay que cambiar para moverlo. Los
     valores del token se pusieron en 16/1.5 justamente para que estrenarlo
     no repinte nada. */
  -webkit-backdrop-filter: blur(var(--glass-blur-chrome, 16px)) saturate(var(--glass-sat, 1.5)) !important;
  backdrop-filter: blur(var(--glass-blur-chrome, 16px)) saturate(var(--glass-sat, 1.5)) !important;
}
/* ── EL TOAST, uno solo para todo el portal ──────────────────────────────────
   Vive aquí y no en `ui.css` por el mismo motivo que el esqueleto de carga y el
   estado vacío se mudaron: `ui.css` lo cargan 35 archivos y `anim.css` los 52.
   Un aviso que falta en 17 pantallas no es un aviso del portal.

   Estaba copiado en 36 sitios. No eran 36 decisiones: 30 eran el MISMO bloque
   con la diferencia de escribir `12px` o `var(--text-nota)`, y las que de verdad
   divergían eran dos (una en `--surface-2` con borde tenue, otra en píldora) más
   los `bottom` que esquivan una barra fija. Los `bottom` se quedan como override
   de una línea en su página, que es lo que los hace visibles; el resto converge.

   QUÉ AÑADE respecto al de antes (rediseño 1 sep 2026, decisión de Samuel):
   · UN ICONO por tipo, que sale del `.err` que las páginas ya alternan — así
     ninguna tiene que cambiar su JS para ganarlo. Va con `mask` y no con un
     `<img>` porque el dibujo es de TRAZO y hereda el color de la caja.
   · SE PUEDE DESCARTAR. Antes era `pointer-events:none` siempre: el aviso te
     tapaba el botón de abajo y no había forma de quitarlo, solo esperar. Ahora
     acepta el toque MIENTRAS se ve, y lo cierra `theme.js`.
   · Se ANUNCIA. 15 de las 40 páginas no tenían `role`/`aria-live` en su `#toast`
     y ahí «Guardado» y «No se pudo guardar» sonaban igual: a nada. Lo pone
     `theme.js` al arrancar, en las que falten.
   La `margin-bottom` de safe-area sigue viniendo de la capa de piel de abajo. */
/* EL DISEÑO APROBADO (22 sep 2026): tinta, abajo al centro, el icono en un
   CÍRCULO —dorado si informa, rojo si falló— con el trazo del color del fondo
   (se lee igual en los dos modos: en Modo mar la tinta es crema), el texto en
   frase y, si la hay, UNA acción a la derecha. El error ya no es un bloque
   rojo: es el mismo aviso con el círculo rojo, que avisa sin gritar. Lo pinta
   `window.toast` (theme.js). */
.toast, .ui-toast, .amr-toast{
  position:fixed; bottom:24px; left:50%;
  transform:translateX(-50%) translateY(20px);
  display:inline-flex; align-items:center; gap:10px;
  max-width:min(440px, calc(100vw - 32px));
  padding:var(--space-2) var(--space-4) var(--space-2) var(--space-2);
  background:var(--ink); color:var(--bg);
  border:0; border-radius:var(--radius-md);
  box-shadow:var(--elev-toast);
  font-family:inherit; font-size:var(--text-sm); font-weight:var(--weight-medium,500);
  letter-spacing:0; line-height:1.4; text-align:left;
  opacity:0; pointer-events:none;
  z-index:var(--z-toast, 9999);
  transition:opacity var(--amr-dur-fast) ease,
             transform var(--amr-dur) var(--amr-ease-spring);
}
.amr-toast-ic{flex:0 0 auto;width:24px;height:24px;border-radius:50%;background:var(--gold);position:relative}
.amr-toast-ic::after{content:"";position:absolute;inset:0;background:var(--ink);
  -webkit-mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%222.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M20%206L9%2017l-5-5%22%2F%3E%3C%2Fsvg%3E") center/14px 14px no-repeat; mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%222.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M20%206L9%2017l-5-5%22%2F%3E%3C%2Fsvg%3E") center/14px 14px no-repeat}
.err .amr-toast-ic{background:var(--danger)}
.err .amr-toast-ic::after{-webkit-mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%222.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M12%207v6M12%2017.5h.01%22%2F%3E%3C%2Fsvg%3E") center/14px 14px no-repeat; mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%222.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M12%207v6M12%2017.5h.01%22%2F%3E%3C%2Fsvg%3E") center/14px 14px no-repeat}
.amr-toast-tx{min-width:0}
.amr-toast-acc{margin-left:var(--space-2);flex:none;background:transparent;border:0;padding:var(--space-1) 2px;cursor:pointer;
  font:inherit;font-weight:var(--weight-semibold);color:inherit;text-decoration:underline;text-underline-offset:3px}
.toast.show, .ui-toast.show, .amr-toast.show{
  opacity:1; transform:translateX(-50%) translateY(0);
  pointer-events:auto; cursor:pointer;   /* solo mientras se ve: fuera no estorba */
}
.toast.show:active, .ui-toast.show:active, .amr-toast.show:active{ transform:translateX(-50%) scale(.985) }

/* ══ LA VENTANA, UNA SOLA (22 sep 2026, diseño aprobado por Samuel) ═════════
   El portal abría ventanas de NUEVE maneras: `.modal-back > .modal` (POS),
   `.pk-back > .pk-card` (Compras), `.ui-modal` (kit), `.modal > .modal-card`
   (Biblioteca, Catálogo), `.mback > .modal` (Artículos), `.modal-bd > .modal`
   (Seguimiento), `.modal-overlay` (Simulador), `.overlay > .panel` (Inventario
   de planta), `.sheet-bg` (Particulares) y la de `amrConfirmar`. Cada una con su
   velo, su tarjeta, su título y su «×».

   Aquí se iguala LO DE FUERA —velo, superficie, cabecera, título, cerrar, pie y,
   en el teléfono, la hoja desde abajo— sin tocar lo que cada ventana lleva
   dentro ni cómo entra. Los selectores van por CONTEXTO porque `.modal` es el
   fondo en Biblioteca y la tarjeta en Clientes. Y sin `!important`: `:is()` se
   queda con la especificidad de su argumento más alto, que ya pasa la de las
   copias de cada página. */
:is(.modal-back, .pk-back, .ui-modal-backdrop, .mback, .modal-bd, .modal-overlay, .sheet-bg,
    .modal:has(> .modal-card), .overlay:has(> .panel[role="dialog"])){background:var(--velo)}
:is(.modal-back > .modal, .pk-back .pk-card, .ui-modal-backdrop .ui-modal, .mback > .modal, .modal-bd > .modal,
    .modal > .modal-card, .modal-overlay > .modal-card, .sheet-panel, .overlay > .panel[role="dialog"]){
  background:var(--surface);border:var(--stroke) solid var(--hairline);box-shadow:var(--elev-3)}
@media (min-width:641px){
  :is(.modal-back > .modal, .pk-back .pk-card, .ui-modal-backdrop .ui-modal, .mback > .modal, .modal-bd > .modal,
      .modal > .modal-card, .modal-overlay > .modal-card, .overlay > .panel[role="dialog"]){border-radius:var(--radius-lg)}
}
/* El TÍTULO en la serif de la casa; debajo, una línea de contexto en voz baja. */
:is(.modal-back .modal-head h2, .pk-head strong, .ui-modal__title, .modal-card .modal-title, .modal-card .modal-head h2,
    .mback .mhead h2, .overlay .p-tit, .modal-bd .m-val){
  font-family:var(--font-serif);font-size:var(--text-xl);font-weight:var(--weight-semibold);color:var(--ink);
  letter-spacing:0;text-transform:none;line-height:1.15}
:is(.modal-back .mh-sub, .pk-head .pk-day, .modal-card .modal-sub, .mback .mhead .sub, .modal-bd .m-sub){
  font-size:var(--text-nota);color:var(--muted);letter-spacing:0;text-transform:none;font-weight:var(--weight-regular,400);margin-top:2px}
/* El «×»: el mismo cuadrito en todas, arriba a la derecha. */
:is(.modal-back .modal-x, .pk-head .pk-x, .ui-modal-backdrop .ui-modal__close, .modal-card .modal-close, .modal-bd .modal-close,
    .sheet-panel .sheet-close, .overlay .p-cerrar, .mback .mx){
  width:var(--alto-control);height:var(--alto-control);flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  padding:0;border:var(--stroke) solid var(--hairline);border-radius:var(--radius-sm);background:transparent;
  color:var(--muted);font-size:var(--text-titulo3);line-height:1;cursor:pointer;
  transition:background-color var(--amr-dur-fast),color var(--amr-dur-fast)}
@media (hover:hover){
  :is(.modal-back .modal-x, .pk-head .pk-x, .ui-modal-backdrop .ui-modal__close, .modal-card .modal-close, .modal-bd .modal-close,
      .sheet-panel .sheet-close, .overlay .p-cerrar, .mback .mx):hover{background:var(--chip);color:var(--ink)}
}
/* El PIE: las acciones abajo a la derecha, separadas por un filete. */
:is(.modal-back .modal-actions, .ui-modal-backdrop .ui-modal__foot, .mback .mfoot, .overlay .p-pie){
  display:flex;justify-content:flex-end;align-items:center;gap:var(--space-2);border-top:var(--stroke) solid var(--hairline)}

/* EN EL TELÉFONO, LA HOJA DESDE ABAJO: a lo ancho, pegada al borde de abajo,
   con asa, las esquinas de arriba redondeadas y los botones apilados a lo
   ancho —el principal (el último en el HTML) arriba—. */
@media (max-width:640px){
  :is(.modal-back, .pk-back, .ui-modal-backdrop, .mback, .modal-bd, .modal-overlay,
      .modal:has(> .modal-card), .overlay:has(> .panel[role="dialog"])){align-items:flex-end;padding:0}
  :is(.modal-back > .modal, .pk-back:not(.as-drop) .pk-card, .ui-modal-backdrop .ui-modal, .mback > .modal, .modal-bd > .modal,
      .modal > .modal-card, .modal-overlay > .modal-card, .overlay > .panel[role="dialog"]){
    width:100%;max-width:none;margin:0;max-height:92dvh;
    border-radius:var(--radius-lg) var(--radius-lg) 0 0;border-bottom:0;
    padding-bottom:env(safe-area-inset-bottom,0px)}
  :is(.modal-back > .modal, .pk-back:not(.as-drop) .pk-card, .ui-modal-backdrop .ui-modal, .mback > .modal, .modal-bd > .modal,
      .modal > .modal-card, .modal-overlay > .modal-card, .overlay > .panel[role="dialog"])::before{
    content:"";display:block;flex:none;width:36px;height:4px;margin:var(--space-2) auto 0;border-radius:var(--radius-pill);background:var(--hairline)}
  :is(.modal-back .modal-actions, .ui-modal-backdrop .ui-modal__foot, .mback .mfoot, .overlay .p-pie){flex-direction:column-reverse;align-items:stretch}
  :is(.modal-back .modal-actions, .ui-modal-backdrop .ui-modal__foot, .mback .mfoot, .overlay .p-pie) > :is(button, a){width:100%;margin:0;flex:none}
}

/* ══ EL BOTÓN, UNO SOLO (22 sep 2026, diseño aprobado por Samuel) ═══════════
   `.btn` estaba escrito en 17 pantallas con cuatro alturas, tres grosores de
   letra y DOS colores de acción principal: dorado en el POS y azul tinta en
   Compras, Restaurantes y siete más. Ahora vive aquí y la pantalla solo pone lo
   que es SUYO (un `flex:1` dentro de su pie, un margen).

     .btn                 secundario: contorno visible sobre la superficie
     .btn.primary/.main   principal, dorado — uno por pantalla (y `.btn-primary`)
     .btn.ghost           secundario (mismo aspecto: hubo pantallas que lo
                          llamaban así y otras que no)
     .btn.danger/.warn    peligro en contorno; `.peligro` es el relleno de la
                          confirmación, que ya pidió el «¿seguro?»
     .btn.sm              compacto, para filas y barras
     .btn.ico             solo icono, cuadrado

   El contorno es `--borde-control` y no `--hairline`: en Modo playa la línea
   del divisor casi no se ve alrededor de un botón (lo dijo Samuel al aprobar).

   Y DESDE EL 23 SEP 2026, PLANO CON PROFUNDIDAD (decisión de Samuel, viendo la
   propuesta en los dos temas):
   · SUBE: color sólido con el `--relieve` de tokens.css —canto de luz arriba,
     labio abajo y sombra corta—. Al apretarlo baja 1 px y se queda solo con el
     canto; antes encogía (`scale(.97)`), que se lee como goma y no como botón.
     Los que no tienen relleno —fantasma y peligro en contorno— siguen planos:
     un canto de luz sobre nada es un filete suelto.
   · HABLA EN FRASE: «Guardar pedido», no «GUARDAR PEDIDO». Revoca las
     mayúsculas espaciadas que puso el estándar el 22 sep; es lo que más acerca a
     la referencia por menos, y se lee más rápido. Los textos ya estaban escritos
     en minúscula en el HTML —comprobado—: las mayúsculas las ponía solo esta
     regla, así que ninguna pantalla hay que tocarla. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-2);
  min-height:var(--alto-control);padding:0 var(--space-4);box-sizing:border-box;
  border-radius:var(--radius-sm);border:var(--stroke,1px) solid var(--borde-control);
  background:var(--surface);color:var(--ink);font-family:inherit;font-size:var(--text-apoyo);
  font-weight:var(--weight-semibold);letter-spacing:0;text-transform:none;line-height:1.1;box-shadow:var(--relieve);
  text-decoration:none;white-space:nowrap;cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:background var(--amr-dur-fast) var(--amr-ease),color var(--amr-dur-fast) var(--amr-ease),
    border-color var(--amr-dur-fast) var(--amr-ease),box-shadow var(--amr-dur) var(--amr-ease-out),
    transform var(--amr-dur-fast) var(--amr-ease-out)}
.btn svg{flex:none;width:16px;height:16px}
.btn:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.btn:active:not(:disabled,[disabled]){transform:translateY(1px);box-shadow:var(--relieve-pulsado)}
.btn:disabled,.btn[disabled]{opacity:.5;cursor:default;box-shadow:none;transform:none}
.btn.ghost,.btn.btn-ghost{background:transparent;box-shadow:none}
.btn.primary,.btn.main,.btn.btn-primary{background:var(--gold);border-color:color-mix(in srgb,var(--gold) 82%,#000);color:var(--on-gold)}
.btn.danger,.btn.warn{background:transparent;border-color:color-mix(in srgb,var(--danger) 55%,transparent);color:var(--danger);box-shadow:none}
.btn.peligro,.btn.danger.armed{background:var(--danger);border-color:color-mix(in srgb,var(--danger) 82%,#000);color:var(--on-danger);box-shadow:var(--relieve)}
.btn.sm{min-height:28px;padding:0 var(--space-3)}
.btn.ico{width:var(--alto-control);padding:0}
.btn.sm.ico{width:28px}
@media (hover:hover){
  .btn:hover:not(:disabled,[disabled]){border-color:var(--ink);background:var(--chip);color:var(--ink)}
  .btn.primary:hover:not(:disabled,[disabled]),.btn.main:hover:not(:disabled,[disabled]),.btn.btn-primary:hover:not(:disabled,[disabled]){background:var(--gold);border-color:var(--gold);color:var(--on-gold);
    filter:brightness(1.05);box-shadow:var(--relieve)}
  .btn.danger:hover:not(:disabled,[disabled]),.btn.warn:hover:not(:disabled,[disabled]),
  .btn.peligro:hover:not(:disabled,[disabled]){background:var(--danger);border-color:var(--danger);color:var(--on-danger)}
}
@media (max-width:760px){ .btn{min-height:var(--alto-control-movil)} .btn.ico{width:var(--alto-control-movil)} }

/* ══ LA PESTAÑA, UNA SOLA (22 sep 2026, diseño aprobado por Samuel) ═════════
   Pestañas de sección y selectores de formulario eran 22 familias en 20
   pantallas, en dos estilos que se contradecían: la opción activa ELEVADA en
   blanco dentro de un cajón, o RELLENA de dorado (y en Compras, Restaurantes y
   Particulares, además, en mayúsculas y en píldora). Ahora es una sola pieza:
   `.amr-seg` en el contenedor y sus botones (o enlaces) como hijos directos; la
   activa se marca como cada pantalla ya la marcaba (`.on`, `.active`,
   `aria-selected`, `aria-pressed`).

   La activa la señala UNA PIEZA que viaja (`.amr-seg-pieza`, la pone theme.js).
   Samuel pidió que las esquinas «coincidan en radio»: son CONCÉNTRICAS — el
   cajón es `--radius-md` (16) y la pieza `--radius-sm` (12) con 4 px de relleno
   entre los dos, así las dos curvas corren paralelas.

   Sin JavaScript, la activa se pinta ella misma (mismo aspecto, sin viaje).

   El botón pesa UNA clase (`.amr-seg > :where(button,a)`): le gana a un
   `button{}` suelto y cede ante `.rtab{flex:1}`, que es como cada pantalla
   reparte el ancho de sus pestañas. */
.amr-seg{position:relative;display:inline-flex;align-items:center;gap:2px;padding:var(--space-1);box-sizing:border-box;
  border-radius:var(--radius-md);background:var(--surface-2);box-shadow:var(--hundido),inset 0 0 0 1px var(--hairline);
  max-width:100%;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;vertical-align:middle}
.amr-seg::-webkit-scrollbar{display:none}
.amr-seg[hidden]{display:none}
.amr-seg > :where(button,a){position:relative;z-index:1;flex:none;display:inline-flex;align-items:center;justify-content:center;gap:var(--space-2);
  min-height:32px;padding:0 var(--space-3);box-sizing:border-box;border:0;border-radius:var(--radius-sm);background:transparent;box-shadow:none;
  color:var(--muted);font-family:inherit;font-size:var(--text-nota);font-weight:var(--weight-bold);letter-spacing:.02em;text-transform:none;
  line-height:1.1;white-space:nowrap;text-decoration:none;cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:color var(--amr-dur-fast) var(--amr-ease)}
.amr-seg > :where(button,a)[hidden]{display:none}
.amr-seg > :where(button,a):focus-visible{outline:2px solid var(--gold);outline-offset:-2px}
.amr-seg > :is(.on,.active,.is-on,.is-active,[aria-selected="true"],[aria-pressed="true"]){color:var(--ink)}
.amr-seg:not(.amr-seg-lista) > :is(.on,.active,.is-on,.is-active,[aria-selected="true"],[aria-pressed="true"]){background:var(--surface-raised);box-shadow:var(--elev-seg)}
/* Una pestaña NO salta ni brilla al pasar el cursor —anim.css le da a todo
   `button` un `translateY(-2px)` y un resplandor dorado—: solo se aclara su
   texto. Lo notó Samuel el mismo día («la veo muy drástica»). */
.amr-seg > :where(button,a):is(:hover,:active){transform:none;box-shadow:none;filter:none}
@media (hover:hover){ .amr-seg > :where(button,a):hover{color:var(--ink)} }
/* La pieza. Anima su ANCHO además de su posición —cada pestaña mide distinto—:
   es la única transición de tamaño que se añade, y es de un elemento absoluto,
   fuera del flujo, que no mueve nada a su alrededor. */
.amr-seg-pieza{position:absolute;top:0;left:0;z-index:0;border-radius:var(--radius-sm);background:var(--surface-raised);
  box-shadow:var(--elev-seg);pointer-events:none;opacity:0;
  transition:transform var(--amr-dur-view) var(--amr-ease-out),width var(--amr-dur-view) var(--amr-ease-out),opacity var(--amr-dur-fast) var(--amr-ease)}
/* Un contador dentro de la pestaña (`.amr-seg-n`): gris, y dorado en la activa. */
.amr-seg .amr-seg-n{min-width:20px;height:18px;padding:0 6px;border-radius:var(--radius-pill);display:inline-flex;align-items:center;justify-content:center;
  background:var(--chip);color:inherit;font-size:var(--text-micro);font-weight:var(--weight-bold);font-variant-numeric:tabular-nums}
.amr-seg > :is(.on,.active,.is-on,.is-active,[aria-selected="true"],[aria-pressed="true"]) .amr-seg-n{background:var(--gold);color:var(--on-gold)}
@media (max-width:760px){ .amr-seg > :where(button,a){min-height:var(--alto-control)} }

/* ── LAS DIMENSIONES, ESTANDARIZADAS (23 sep 2026) ──────────────────────────
   Samuel: «revisa las pestañas en todo el sistema para que estandarices
   dimensiones y que no pasen los sobrebordamientos». Censo medido en las 38
   pantallas: las `.amr-seg` llevaban rellenos de 10 a 16 px según la pantalla,
   dos tamaños de letra, y en el resumen de productos las tres palabras se
   cortaban o se salían del cajón: 182–193 px de texto con 96 de relleno en 238
   de sitio. Y cuatro conmutadores ni siquiera eran `.amr-seg`.

   AHORA HAY DOS TAMAÑOS Y NINGUNO CORTA:
   · el NORMAL —el de arriba—: 32 px de alto, letra de 12, relleno de 12. Es el
     que ya pedían las barras de Seguimiento para caber a 1.440 (con 16 se
     partían en dos líneas), así que su excepción desaparece;
   · el COMPACTO (`.amr-seg-compacta`), para columnas estrechas: 28 px, letra de
     11 y relleno de 8. Con él las tres opciones del resumen ocupan ~228 px de
     238.
   Y un reparto: `.amr-seg-llena` ocupa todo el ancho de su sitio y reparte el
   sobrante entre las opciones, pero ninguna baja de su texto (`min-width` de
   contenido): si no cabe, se desplaza — nunca se corta con puntos suspensivos,
   que es esconder la opción que se viene a tocar. */
.amr-seg.amr-seg-llena{display:flex;width:100%}
.amr-seg.amr-seg-llena > :where(button,a){flex:1 1 auto;min-width:max-content}
.amr-seg.amr-seg-compacta > :where(button,a){min-height:28px;padding:0 var(--space-2);font-size:var(--text-mini);letter-spacing:0}
@media (max-width:760px){ .amr-seg.amr-seg-compacta > :where(button,a){min-height:var(--alto-control)} }

/* ══ EL CHIP, UNO SOLO — de FILTRO y de ESTADO (22 sep 2026, diseño aprobado) ══
   Había unas cien familias de chip, con dos ideas mezcladas: el chip que se TOCA
   para filtrar y el que solo DICE un estado. Ahora son dos piezas:

     .amr-chip     filtro. Píldora con contorno; el activo (`.on`, `.is-active`,
                   `aria-pressed`) se TIÑE —fondo dorado claro, texto dorado— y
                   solo su conteo (`.n`) va relleno. Es el de las píldoras de
                   Actividad, que Samuel eligió como el de todo el portal: el
                   dorado macizo queda para el botón principal.
     .amr-estado   estado. No se toca: píldora teñida de su color con su punto.
                   El color es `--tono` y cada pantalla dice el suyo con su
                   propio vocabulario (`.pill.ok{--tono:var(--ok)}`), porque las
                   palabras de estado son de cada módulo y el aspecto no.

   Las de las listas con el formato de Actividad (`.chip`, `.act-tipo`) están
   aquí mismo: eran esta pieza con otro nombre. */
.amr-chip,.lista-trabajo :is(.chip,.act-tipo){display:inline-flex;align-items:center;justify-content:center;gap:var(--space-1);
  height:32px;padding:0 var(--space-3);box-sizing:border-box;border-radius:var(--radius-pill);border:1px solid var(--border-2);
  background:var(--surface-2);color:var(--muted);font-family:inherit;font-size:var(--text-nota);font-weight:var(--weight-semibold);
  letter-spacing:normal;text-transform:none;white-space:nowrap;cursor:pointer;-webkit-tap-highlight-color:transparent;
  transition:background-color var(--amr-dur-fast),color var(--amr-dur-fast),border-color var(--amr-dur-fast)}
.amr-chip svg,.lista-trabajo .act-tipo svg{stroke-width:1.75;width:15px;height:15px;flex:0 0 auto;stroke:currentColor;fill:none;stroke-linecap:round;stroke-linejoin:round}
.amr-chip :is(.n,.amr-chip-n),.lista-trabajo .act-tipo .n{font-size:var(--text-micro);font-weight:var(--weight-bold);font-variant-numeric:tabular-nums;
  min-width:18px;text-align:center;padding:1px var(--space-1);border-radius:var(--radius-pill);background:var(--chip);color:var(--muted);border:1px solid var(--border-2)}
.amr-chip:is(.on,.is-on,.is-active,[aria-pressed="true"]),.lista-trabajo :is(.chip,.act-tipo).on{background:var(--chip);border-color:color-mix(in srgb,var(--gold) 45%,transparent);color:var(--gold-text)}
.amr-chip:is(.on,.is-on,.is-active,[aria-pressed="true"]) :is(.n,.amr-chip-n),.lista-trabajo .act-tipo.on .n{background:var(--gold);color:var(--on-gold);border-color:transparent}
.amr-chip:is(:disabled,[disabled]){opacity:.45;cursor:not-allowed}
/* Tampoco salta al pasar el cursor (anim.css le da `translateY(-2px)` a todo
   botón): un filtro que se mueve bajo el dedo parece que se escapa. Las
   píldoras de tipo de Actividad conservan su medio píxel, que es suyo. */
.amr-chip:is(:hover,:active),.lista-trabajo .chip:is(:hover,:active){transform:none;box-shadow:none}
@media (hover:hover){ .amr-chip:not(.on,.is-on,.is-active,[aria-pressed="true"]):hover,.lista-trabajo :is(.chip,.act-tipo):not(.on):hover{color:var(--ink)} }
@media (max-width:760px){ .amr-chip{height:var(--alto-control)} }

.amr-estado{--tono:var(--muted);display:inline-flex;align-items:center;gap:var(--space-1);height:22px;padding:0 var(--space-2);box-sizing:border-box;
  border:0;border-radius:var(--radius-pill);background:color-mix(in srgb,var(--tono) 13%,transparent);color:var(--tono);
  font-size:var(--text-micro);font-weight:var(--weight-semibold);letter-spacing:.01em;text-transform:none;line-height:1;white-space:nowrap;vertical-align:middle}
.amr-estado::before{content:"";flex:none;width:6px;height:6px;border-radius:50%;background:currentColor}

/* ══ EL CAMPO, UNO SOLO (22 sep 2026, diseño aprobado por Samuel) ═══════════
   Los campos de formulario vivían en 13 envoltorios distintos (`.fld`, `.ff`,
   `.field`, `.pk-fld`, `.campo`…) repartidos por 30 pantallas, con fondos
   `--bg`, `--surface` y `--surface-2`, alturas de 32 a 46 px y el foco escrito
   de cuatro maneras. Aquí se dice una vez: 36 px, contorno de control, anillo
   dorado al escribir y rojo cuando `aria-invalid`. Va con `:is()` para ganarle
   a `.fld input` de la pantalla sin `!important`.

   Lo que NO entra, a propósito: los campos DENTRO de una tabla o de una fila de
   edición (Registro de Seguimiento, tarifas del Simulador, líneas de un pedido),
   que son compactos porque viven en una celda.

   En el teléfono todo campo de texto va a 16 px: con menos, el iPhone amplía la
   pantalla al tocarlo y hay que alejarla a mano. */
:is(.fld,.ff,.field,.pk-fld,.campo,.am-field,.mfld,.tb-fld,.asf-field,.es-f,.cfg-field,.msg-campo,.re-grid,.ui-field) :is(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden]),select,textarea){
  box-sizing:border-box;min-height:var(--alto-control);
  border:var(--stroke,1px) solid var(--borde-control);border-radius:var(--radius-sm);
  background-color:var(--surface);color:var(--ink);font-family:inherit;font-size:var(--text-guia);line-height:1.2;
  box-shadow:var(--hundido);   /* lo que se llena se hunde (23 sep 2026) */
  transition:border-color var(--amr-dur-fast) var(--amr-ease),box-shadow var(--amr-dur-fast) var(--amr-ease)}
/* El relleno, en cambio, cede ante la pantalla (una clase y nada más: le gana
   a un `input{padding:0}` suelto y pierde contra `.fld input.con-icono`): un
   campo con icono dentro o un contador estrecho ya dice el suyo, y pisarlo
   metería el texto debajo del icono. */
:is(.fld,.ff,.field,.pk-fld,.campo,.am-field,.mfld,.tb-fld,.asf-field,.es-f,.cfg-field,.msg-campo,.re-grid,.ui-field) :where(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden]),select,textarea){padding:var(--space-2) var(--space-3)}
:is(.fld,.ff,.field,.pk-fld,.campo,.am-field,.mfld,.tb-fld,.asf-field,.es-f,.cfg-field,.msg-campo,.re-grid,.ui-field) textarea{min-height:calc(var(--alto-control) * 2);resize:vertical;line-height:1.45}
:is(.fld,.ff,.field,.pk-fld,.campo,.am-field,.mfld,.tb-fld,.asf-field,.es-f,.cfg-field,.msg-campo,.re-grid,.ui-field) select{appearance:none;-webkit-appearance:none;padding-right:var(--space-8);
  background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),linear-gradient(135deg,var(--muted) 50%,transparent 50%);
  background-position:calc(100% - 16px) calc(50% + 1px),calc(100% - 11px) calc(50% + 1px);
  background-size:5px 5px,5px 5px;background-repeat:no-repeat}
:is(.fld,.ff,.field,.pk-fld,.campo,.am-field,.mfld,.tb-fld,.asf-field,.es-f,.cfg-field,.msg-campo,.re-grid,.ui-field) :is(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden]),select,textarea)::placeholder{color:var(--muted);opacity:.8}
:is(.fld,.ff,.field,.pk-fld,.campo,.am-field,.mfld,.tb-fld,.asf-field,.es-f,.cfg-field,.msg-campo,.re-grid,.ui-field) :is(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden]),select,textarea):focus{outline:none;border-color:var(--gold);box-shadow:var(--hundido),var(--ring)}
:is(.fld,.ff,.field,.pk-fld,.campo,.am-field,.mfld,.tb-fld,.asf-field,.es-f,.cfg-field,.msg-campo,.re-grid,.ui-field) :is(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden]),select,textarea):disabled{opacity:.55;cursor:default;background-color:var(--surface-sunken)}
:is(.fld,.ff,.field,.pk-fld,.campo,.am-field,.mfld,.tb-fld,.asf-field,.es-f,.cfg-field,.msg-campo,.re-grid,.ui-field) :is(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden]),select,textarea)[aria-invalid="true"]{border-color:var(--danger);background-color:var(--danger-bg)}
:is(.fld,.ff,.field,.pk-fld,.campo,.am-field,.mfld,.tb-fld,.asf-field,.es-f,.cfg-field,.msg-campo,.re-grid,.ui-field) :is(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden]),select,textarea)[aria-invalid="true"]:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--danger) 18%,transparent)}
@media (max-width:760px){
  :is(.fld,.ff,.field,.pk-fld,.campo,.am-field,.mfld,.tb-fld,.asf-field,.es-f,.cfg-field,.msg-campo,.re-grid,.ui-field) :is(input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden]),select,textarea){min-height:var(--alto-control-movil)}
  input:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=hidden],[type=button],[type=submit]),select,textarea{font-size:16px !important}
}

/* ── Lo que flota abajo, POR ENCIMA de la barra de gestos ────────────────────
   Medido (ago 2026): 37 elementos con `position:fixed` y un `bottom:Npx` sin
   safe-area, y 32 de ellos son el mismo `.toast` copiado página a página con
   `bottom:24px`. En un iPhone con gesto el indicador ocupa los 34px de abajo,
   así que un aviso a 24px sale DENTRO de esa franja: medio tapado y justo en la
   zona donde un deslizamiento hacia arriba cierra la app.

   Se arregla con `margin-bottom` y no tocando `bottom`, porque así no hace falta
   saber qué `bottom` eligió cada página: el margen se SUMA al que ya tenga. Y en
   un teléfono sin notch `env()` vale 0, o sea que aquí no se mueve nada.

   `!important` porque es la capa de piel que unifica, igual que el vidrio de las
   barras y el gesto de hover: estas 32 clases están definidas DENTRO de cada
   página y ganarían por orden de documento. */
.toast, .ui-toast, .amr-toast, .reorder-bar, .btn-ayuda, .conex{
  margin-bottom:var(--safe-bottom, env(safe-area-inset-bottom, 0px)) !important;
}

/* Scrollbars finos y cálidos en todo el portal. */
*{ scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--gold, #c19a4b) 38%, transparent) transparent; }
*::-webkit-scrollbar{ width: 8px; height: 8px; }
*::-webkit-scrollbar-track{ background: transparent; }
*::-webkit-scrollbar-thumb{
  background: color-mix(in srgb, var(--gold, #c19a4b) 32%, transparent);
  border-radius: 999px; border: 2px solid transparent; background-clip: padding-box;
}
@media (hover:hover){*::-webkit-scrollbar-thumb:hover{ background: color-mix(in srgb, var(--gold, #c19a4b) 55%, transparent); border: 2px solid transparent; background-clip: padding-box; }}

/* ── EL BOTÓN, con un SUELO de dedo ──────────────────────────────────────────
   Medido (26 ago 2026): `.btn` está definida DESDE CERO en 21 páginas, con 20
   cuerpos distintos, y **ninguna de las 17 que derivan su alto del padding
   llega a 44px**: van de 29 a 42. Solo `articulos` declaraba `--tap-min`.

   No es que unas midan bien y otras mal: es que el botón NO TIENE ALTO. Su
   altura es lo que sobre del padding, y como hay 24 paddings distintos para la
   misma clase, hay una altura distinta por pantalla. Un botón de 29px se falla
   con el pulgar en una moto parada.

   El suelo va aquí y no en cada página por lo mismo que el vidrio de las barras:
   una regla, veintiuna pantallas, y ninguna oportunidad de que la siguiente
   nazca sin él. `min-height` solo SUBE —nunca encoge—, así que las cuatro que ya
   declaraban 44 no se mueven.

   `pointer:coarse` y no un ancho: el iPad y el iPhone tumbado miden más de
   520px y se quedaban fuera de cualquier regla que dispare por tamaño de
   pantalla. Es la tercera vez hoy que esa es la pregunta correcta.

   Los `<a class="btn">` necesitan además el `inline-flex`: un elemento en línea
   ignora `min-height`, así que sin esto el suelo no les aplicaría — y son los
   que más se usan de enlace-acción en las pantallas vacías. */
@media (pointer:coarse){
  .btn, .ui-btn{ min-height:var(--tap-min, 44px); }
  a.btn, a.ui-btn{ display:inline-flex; align-items:center; justify-content:center; }
}

/* ── EL BOTÓN DE VOLVER, a tamaño de dedo en TODAS partes ────────────────────
   Medido (ago 2026): el enlace de retorno mide 12–13,5px de alto. Es el control
   MÁS USADO del portal —está en las 50 pantallas y es por donde se sale de cada
   una— y era de los más pequeños.

   La capa móvil ya lo arreglaba… en las 23 pantallas que la cargan. En las otras
   27 nadie lo agrandaba, y ahí es donde más falta hace: son las que se abren en
   un iPad o en un teléfono tumbado sin que ninguna otra regla las alcance.

   Se pregunta por el DEDO (`pointer:coarse`) y no por el ancho, por lo mismo que
   el anti-zoom de más abajo: el iPad y el iPhone apaisado miden más de 520px y
   se quedaban fuera de cualquier regla que dispare por tamaño de pantalla.

   `inline-flex` + `min-height` y no un `padding`: el padding movería la línea de
   base del texto dentro de la topbar y descuadraría el título centrado. Esto
   crece el área táctil sin mover un píxel de lo que se ve. */
@media (pointer:coarse){
  .brand-back, .ui-brand-back, .bt-back{
    display:inline-flex; align-items:center;
    min-height:var(--tap-min, 44px);
  }
}

/* Área táctil mínima (v3): botones-icono y cierres de modal que median <42px
   reciben un halo INVISIBLE de +9px por lado (inset:-9px) — el dedo acierta sin
   cambiar el diseño. Lista curada de la auditoría móvil; para uno nuevo, añade
   su clase aquí o usa .amr-tap. */
.amr-tap, .im-del, .dfx, .line-del, .modal-close, .card-icon-btn,
.hist-delete, .hist-close, .mn-btn, .ns-btn, .tbtn, .calib-close,
.pk-x, .ctrl-x, .osheet-close, .cfs-x, .rowdel{ position:relative; }
.amr-tap::before, .im-del::before, .dfx::before, .line-del::before,
.modal-close::before, .card-icon-btn::before, .hist-delete::before,
.hist-close::before, .mn-btn::before, .ns-btn::before, .tbtn::before,
.calib-close::before,
/* Cierres de sheet y borrados de fila: 22-28px de alto, muy por debajo del
   mínimo táctil. El halo agranda el área SIN agrandar el ícono. */
.pk-x::before, .ctrl-x::before, .osheet-close::before, .cfs-x::before,
.rowdel::before{ content:""; position:absolute; inset:-9px; }

/* Controles que van EN FILA: el área crece SOLO a lo alto ──────────────────
   El halo de arriba (`inset:-9px`) crece por los cuatro lados, y eso solo vale
   para un botón suelto. En una fila de pastillas pegadas —los selectores de
   sede («Ambas · Medellín · Bogotá»), las pestañas, los chips de filtro— dos
   halos contiguos se solapan, y en el solape gana el que va después en el DOM:
   se toca el borde derecho de «Particulares» y se activa «Restaurantes». Eso es
   peor que el objetivo pequeño que venía a arreglar.

   La forma correcta la tiene escrita el sistema de diseño (§14.3, «el área
   frente al dibujo»): una banda invisible centrada que crece a lo ALTO y nunca
   a lo ancho (`inset:50% 0 auto`). El control se sigue viendo de 28–38 px y
   mide 44; los vecinos de su fila no se tocan.

   La condición es `pointer:coarse`, no un ancho: una tableta con ratón no
   necesita 44 px y un celular apaisado sí.

   Medidos en la auditoría móvil (390 px): pastillas de sede 35, pestañas 38,
   chips de rango 41, exportar 31, capturar 36.

   OJO — esto solo funciona si NINGÚN ancestro recorta. `.rt-sede-opt` y
   `.rt-tab` de Rutas activas quedan fuera a propósito: sus pistas llevan
   `overflow:hidden` (lo necesita el plegado del encabezado al hacer scroll), así
   que la banda se recorta y la regla no haría nada. Esos dos piden decisión de
   diseño —subir el alto dibujado a 44— y no un parche que aparenta arreglarlos. */
@media (pointer:coarse){
  .pf-sede-opt, .rtab, .dr-chip,
  .btn-xls, .btn-export, .capture-trigger{ position:relative; }
  .pf-sede-opt::after, .rtab::after,
  .dr-chip::after, .btn-xls::after, .btn-export::after, .capture-trigger::after{
    content:""; position:absolute; inset:50% 0 auto;
    height:var(--tap-min,44px); transform:translateY(-50%);
  }
}

/* Keyframes de la marca de «hecho» (ver .amr-hecho arriba). */
@keyframes amr-hecho-entra{
  from{ opacity:0; transform:translate(-50%,-50%) scale(.9) }
  to  { opacity:1; transform:translate(-50%,-50%) scale(1) }
}
@keyframes amr-hecho-traza{ from{ stroke-dashoffset:22 } to{ stroke-dashoffset:0 } }
@keyframes amr-hecho-aro{ from{ opacity:0; transform:scale(.6) } to{ opacity:.35; transform:scale(1) } }

/* ══ LOS ICONOS DE MÓDULO: UN GROSOR Y DUOTONO (23 sep 2026) ═════════════════
   Tanda 2 de «plano con profundidad». El dibujo vive en `iconos-modulo.js`.

   El grosor es el del manual —2 sobre 24, o sea 4 en este lienzo de 48—, que
   Samuel eligió el 30 ago 2026. Antes cada copia lo compensaba a mano —1,5 · 3,8
   · 3— y de ahí salían seis grosores en el portal.

   `.ico-duo` es el relleno del duotono: el color del icono a un 20 % (el del
   plan; se aplicó al 18 % y se corrigió en el censo del 23 sep), en la pieza
   principal. Plano —sin degradado— y del mismo color que el trazo, así que sigue
   al tema y al hover sin reglas propias. */
.ico-duo{fill:currentColor;fill-opacity:.2}

/* ══ LA FAMILIA DE ICONOS: UN SOLO GROSOR PARA TODOS (23 sep 2026) ══════════
   Los iconos restantes de la remodernización. Medido en el repo: 755 iconos de
   trazo, 346 dibujos distintos y NUEVE grosores (2 · 1,5 · 2,2 · 1,8 · 1,9 · 2,4 ·
   1,6 · 1,7 · 1,75), además de 23 ajustes sueltos por componente. Por eso no se
   leían como familia.

   AHORA TODOS LLEVAN EL GROSOR DEL PLAN: 1,75 sobre la rejilla de 24, el de la
   propuesta que Samuel aprobó. Revoca el 2 sobre 24 del 30 ago 2026: el 23 sep,
   comparando el plan con el resultado, pidió el del plan («el grosor de los
   iconos y el detalle, mira que no son lo mismo»). Es PROPORCIONAL —crece con el
   dibujo—, así que en cada rejilla vale lo mismo: 3,5 sobre 48, 1,46 sobre 20,
   1,17 sobre 16, 1,02 sobre 14, 0,88 sobre 12.

   La regla sigue la convención del manual —un icono es `fill="none"` +
   `stroke="currentColor"`—, así que no alcanza a los gráficos ni a los logos. Va
   dentro de `:where()` (pesa cero): cualquier regla de una pantalla que diga su
   grosor le gana, y las que lo dicen es A PROPÓSITO —la marca de «hecho» que se
   dibuja, la pestaña activa de la barra, los botones del modo foco de Rutas
   activas, que se miran conduciendo—. Y quien necesite su propio trazo lo declara:
   `data-trazo="propio"`.

   El duotono de los objetos es `.ico-duo` (más arriba): la forma cerrada más
   grande de cada dibujo lleva el color del icono al 18 %. Los gestos —flechas,
   «×», «+», el visto— no tienen cuerpo que rellenar y se quedan en línea. */
:where(svg[fill="none"][stroke="currentColor"]:not([data-trazo="propio"])){stroke-width:1.75}
:where(svg[fill="none"][stroke="currentColor"][viewBox$=" 48 48"]:not([data-trazo="propio"])){stroke-width:3.5}
:where(svg[fill="none"][stroke="currentColor"][viewBox$=" 20 20"]:not([data-trazo="propio"])){stroke-width:1.46}
:where(svg[fill="none"][stroke="currentColor"][viewBox$=" 16 16"]:not([data-trazo="propio"])){stroke-width:1.17}
:where(svg[fill="none"][stroke="currentColor"][viewBox$=" 14 14"]:not([data-trazo="propio"])){stroke-width:1.02}
:where(svg[fill="none"][stroke="currentColor"][viewBox$=" 12 12"]:not([data-trazo="propio"])){stroke-width:.88}

/* ══ LOS GESTOS DE LOS ICONOS · GENERADO por docs/marca/fuente/llevar-iconos.py — no se edita a mano ══
   Cada icono de la biblioteca (`data-icono`) hace SU gesto al apuntar o enfocar el botón o el enlace del
   que es hijo directo: se mueve la pieza que significa (manual de marca §6, iconos/gestos.py). Los que
   tienen gesto dejan el «crecer al 1,18» general de los iconos en botones y, al pulsar, se hunden 1 px. */
[data-icono] > *{transform-box:view-box;transform-origin:var(--o,12px 12px)}
[data-icono="agregar"]{--v:90}
[data-icono="agregar-circulo"]{--v:90}
[data-icono="ajustes"] > :nth-child(2){--dx:-3px;--dy:0px}
[data-icono="ajustes"] > :nth-child(3){--i:1;--dx:3px;--dy:0px}
[data-icono="alto"]{--v:1.12}
[data-icono="archivar"]{--o:3.5px 8.5px}
[data-icono="arrastrar"] > :nth-child(2){--i:1}
[data-icono="arrastrar"] > :nth-child(3){--i:2}
[data-icono="arrastrar"] > :nth-child(4){--i:3}
[data-icono="arrastrar"] > :nth-child(5){--i:4}
[data-icono="arrastrar"] > :nth-child(6){--i:5}
[data-icono="aviso"] > :nth-child(3){--i:1}
[data-icono="balanza"]{--o:12px 7.5px}
[data-icono="balanza"] > :nth-child(3){--i:1}
[data-icono="balanza"] > :nth-child(4){--i:2}
[data-icono="bandera"]{--o:5px 9px}
[data-icono="bloquear"]{--v:1.2}
[data-icono="borrar"]{--o:4px 6.5px}
[data-icono="borrar"] > :nth-child(2){--i:1}
[data-icono="buscar"]{--o:11px 11px}
[data-icono="campana"]{--o:12px 3px}
[data-icono="campana-apagada"]{--o:12px 3px}
[data-icono="campana-apagada"] > :nth-child(2){--i:1}
[data-icono="campana-apagada"] > :nth-child(3){--i:2}
[data-icono="cerrar"]{--v:90}
[data-icono="compartir"] > :nth-child(1){--dx:1.2px;--dy:-1.2px}
[data-icono="compartir"] > :nth-child(3){--i:1;--dx:1.2px;--dy:1.2px}
[data-icono="compartir"] > :nth-child(2){--i:2;--dx:-1.2px;--dy:0px}
[data-icono="configuracion"]{--v:45}
[data-icono="contraer"]{--v:0.88}
[data-icono="copiar"] > :nth-child(1){--dx:1.5px;--dy:1.5px}
[data-icono="corregir"]{--o:9.5px 15px}
[data-icono="cuadricula"] > :nth-child(2){--i:1}
[data-icono="cuadricula"] > :nth-child(4){--i:2}
[data-icono="cuadricula"] > :nth-child(3){--i:3}
[data-icono="cuchillo"]{--o:6px 18px}
[data-icono="desbloquear"]{--v:-2}
[data-icono="descargar"] > :nth-child(2){--i:1}
[data-icono="destello"]{--o:10px 12.2px;--v:90}
[data-icono="detener"]{--o:12px 21px}
[data-icono="documento-nuevo"]{--o:12px 14.5px;--v:90}
[data-icono="editar"]{--o:5px 19.5px}
[data-icono="enlace-externo"] > :nth-child(2){--i:1}
[data-icono="enlazar"] > :nth-child(1){--dx:-1.2px;--dy:1.2px}
[data-icono="enlazar"] > :nth-child(2){--i:1;--dx:1.2px;--dy:-1.2px}
[data-icono="error"] > :nth-child(3){--i:1}
[data-icono="escribir"]{--o:5px 19.5px}
[data-icono="estrella"]{--o:12px 12.3px;--v:72}
[data-icono="etiqueta"]{--o:8px 8px}
[data-icono="expandir"]{--v:1.12}
[data-icono="historial"]{--v:-360}
[data-icono="info"] > :nth-child(3){--i:1}
[data-icono="intercambiar"] > :nth-child(1){--dx:2.2px;--dy:0px}
[data-icono="intercambiar"] > :nth-child(2){--i:1;--dx:-2.2px;--dy:0px}
[data-icono="libro"]{--o:12px 20px}
[data-icono="llave"]{--o:16px 8px}
[data-icono="mas-opciones"] > :nth-child(2){--i:1}
[data-icono="mas-opciones"] > :nth-child(3){--i:2}
[data-icono="moto"]{--o:6px 16.25px}
[data-icono="mudo"]{--o:18.5px 12px;--v:90}
[data-icono="objetivo"] > :nth-child(3){--i:1}
[data-icono="obligatorio"]{--v:60}
[data-icono="ocultar"] > :nth-child(2){--i:1}
[data-icono="ocultar"] > :nth-child(3){--i:2}
[data-icono="olas"] > :nth-child(2){--i:1}
[data-icono="olas"] > :nth-child(3){--i:2}
[data-icono="ordenar"] > :nth-child(3){--i:1}
[data-icono="panel-lateral"] > :nth-child(2){--dx:2px;--dy:0px}
[data-icono="pantalla-completa"]{--v:1.12}
[data-icono="personas"] > :nth-child(3){--i:1}
[data-icono="pez"]{--o:14px 12px}
[data-icono="porcentaje"] > :nth-child(3){--i:1}
[data-icono="quitar-filtro"]{--o:18px 17.5px;--v:90}
[data-icono="refrescar"]{--v:360}
[data-icono="reiniciar"]{--v:-360}
[data-icono="reloj"]{--v:360}
[data-icono="sin-conexion"] > :nth-child(3){--i:1}
[data-icono="sin-conexion"] > :nth-child(4){--i:2}
[data-icono="sin-conexion"] > :nth-child(5){--i:3}
[data-icono="sin-conexion"] > :nth-child(6){--i:4}
[data-icono="sol"]{--v:45}
[data-icono="subir"] > :nth-child(2){--i:1}
[data-icono="ver"] > :nth-child(2){--i:1}
@media (prefers-reduced-motion:no-preference){
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="abrir"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="bandeja"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="descargar"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="descargar"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="documento-bajar"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="fijar"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="filtrar"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="flecha-abajo"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="guardar"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="imprimir"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ordenar"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ordenar"] > :nth-child(3){animation:amr-ic-bajar var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="actividad"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="barras"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="bifurcar"] > :nth-child(4),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="campo"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="documento-texto"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="escalon"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="escudo-hecho"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="formulario"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="grafico"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="hecho"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="hecho-circulo"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="lista"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="lista-hecha"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="mapa"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="menu"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="pantalla"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="quitar"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="quitar-persona"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="recibo"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ruta"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="tarea"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="texto"] > :nth-child(1){animation:amr-ic-redibujar calc(var(--amr-dur-lento) * 1.24) cubic-bezier(.4,0,.2,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="adjuntar"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="buscar"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="corregir"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="cuchillo"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="editar"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="escribir"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="libro"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="llave"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="regla"] > *{animation:amr-ic-inclinar var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="agregar"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="agregar-circulo"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="cerrar"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="configuracion"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="destello"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="documento-nuevo"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="estrella"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="mudo"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="obligatorio"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="quitar-filtro"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="sol"] > *{animation:amr-ic-girar var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ajustes"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ajustes"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="compartir"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="compartir"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="compartir"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="copiar"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="enlazar"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="enlazar"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="intercambiar"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="intercambiar"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="panel-lateral"] > :nth-child(2){animation:amr-ic-separar var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="alto"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="contraer"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="expandir"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="pantalla-completa"] > *{animation:amr-ic-expandir var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="archivar"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="borrar"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="borrar"] > :nth-child(2){animation:amr-ic-tapa var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="arrastrar"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="arrastrar"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="arrastrar"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="arrastrar"] > :nth-child(4),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="arrastrar"] > :nth-child(5),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="arrastrar"] > :nth-child(6),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="cuadricula"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="cuadricula"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="cuadricula"] > :nth-child(4),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="cuadricula"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="mas-opciones"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="mas-opciones"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="mas-opciones"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="personas"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="personas"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="porcentaje"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="porcentaje"] > :nth-child(3){animation:amr-ic-saltar var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="atras"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="deshacer"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="flecha-izquierda"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="nota-credito"] > :nth-child(2){animation:amr-ic-volver var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="avion"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="enlace-externo"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="enlace-externo"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="enviar"] > *{animation:amr-ic-despegar var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="aviso"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="aviso"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="base-datos"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="bolsa"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="caja"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="calendario"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="camara-apagada"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="capas"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="dinero"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="documento"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="error"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="error"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="escudo"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="factura"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="imagen"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="imagen-nueva"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="info"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="info"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="inicio"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="mensaje"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="persona"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="portapapeles"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="termometro"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="tienda"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ubicacion"] > *{animation:amr-ic-saltar var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="balanza"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="balanza"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="balanza"] > :nth-child(4),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="bandera"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="brujula"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="campana"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="campana-apagada"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="campana-apagada"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="campana-apagada"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="detener"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="etiqueta"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="luna"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="pez"] > *{animation:amr-ic-mecer calc(var(--amr-dur-lento) * 1.41) ease-out both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="billete"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="camion"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="carrito"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="flecha-derecha"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="rehacer"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="reproducir"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="salir"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="siguiente"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="tarjeta"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="terrestre"] > *{animation:amr-ic-avanzar var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="bloquear"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="desbloquear"] > :nth-child(2){animation:amr-ic-grillete var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="camara"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="rayo"] > *{animation:amr-ic-destello calc(var(--amr-dur-lento) * 1.24) linear both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="cobro"] > *{animation:amr-ic-moneda calc(var(--amr-dur-lento) * 1.41) ease-in-out both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="documento-subir"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="flecha-arriba"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="plegar"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="subir"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="subir"] > :nth-child(2){animation:amr-ic-subir var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="edificio"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="objetivo"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="objetivo"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="sin-conexion"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="sin-conexion"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="sin-conexion"] > :nth-child(4),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="sin-conexion"] > :nth-child(5),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="sin-conexion"] > :nth-child(6),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="sonido"] > :nth-child(2){animation:amr-ic-latir calc(var(--amr-dur-lento) * 1.24) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="historial"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="refrescar"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="reiniciar"] > *,
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="reloj"] > :nth-child(2){animation:amr-ic-vuelta calc(var(--amr-dur-lento) * 1.41) cubic-bezier(.22,1,.36,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="moto"] > *{animation:amr-ic-pique calc(var(--amr-dur-lento) * 1.82) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ocultar"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ocultar"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ocultar"] > :nth-child(3),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ver"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="ver"] > :nth-child(2){animation:amr-ic-parpadear calc(var(--amr-dur-lento) * 0.765) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="olas"] > :nth-child(1),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="olas"] > :nth-child(2),
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="olas"] > :nth-child(3){animation:amr-ic-ola-x var(--amr-dur-lento) cubic-bezier(.3,.7,.4,1) both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):is(:hover,:focus-visible) > [data-icono="telefono"] > *{animation:amr-ic-timbre calc(var(--amr-dur-lento) * 1.24) linear both;animation-delay:calc(var(--i,0) * 55ms)}
:is(button,a,[role="button"]):not([data-anim],[data-theme-toggle]):active > [data-icono]{transform:translateY(1px)}
}
@keyframes amr-ic-bajar{0%,100%{transform:none}40%{transform:translateY(2.4px)}70%{transform:translateY(-.4px)}}
@keyframes amr-ic-subir{0%,100%{transform:none}40%{transform:translateY(-2.4px)}70%{transform:translateY(.4px)}}
@keyframes amr-ic-avanzar{0%,100%{transform:none}40%{transform:translateX(2.4px)}70%{transform:translateX(-.4px)}}
@keyframes amr-ic-volver{0%,100%{transform:none}40%{transform:translateX(-2.4px)}70%{transform:translateX(.4px)}}
@keyframes amr-ic-pique{0%,100%{transform:none}18%{transform:translateX(-.8px)}42%{transform:translateX(3px) rotate(-8deg)}62%{transform:translateX(2.2px) rotate(0)}80%{transform:translateX(-.4px)}}
@keyframes amr-ic-despegar{0%,100%{transform:none}40%{transform:translate(2px,-2px)}70%{transform:translate(-.3px,.3px)}}
@keyframes amr-ic-girar{0%{transform:rotate(0)}70%{transform:rotate(calc(var(--v,90) * 1.08deg))}100%{transform:rotate(calc(var(--v,90) * 1deg))}}
@keyframes amr-ic-vuelta{from{transform:rotate(0)}to{transform:rotate(calc(var(--v,360) * 1deg))}}
@keyframes amr-ic-moneda{0%,50%,100%{transform:scaleX(1)}25%,75%{transform:scaleX(.08)}}
@keyframes amr-ic-mecer{0%,100%{transform:none}20%{transform:rotate(14deg)}45%{transform:rotate(-10deg)}70%{transform:rotate(5deg)}88%{transform:rotate(-2deg)}}
@keyframes amr-ic-inclinar{0%,100%{transform:none}45%{transform:rotate(-14deg)}75%{transform:rotate(3deg)}}
@keyframes amr-ic-timbre{0%,100%{transform:none}12%{transform:rotate(-12deg)}25%{transform:rotate(12deg)}38%{transform:rotate(-10deg)}52%{transform:rotate(10deg)}66%{transform:rotate(-5deg)}80%{transform:rotate(4deg)}}
@keyframes amr-ic-tapa{0%,100%{transform:none}45%{transform:translateY(-2.2px) rotate(-12deg)}75%{transform:translateY(.2px) rotate(1deg)}}
@keyframes amr-ic-grillete{0%,100%{transform:none}45%{transform:translateY(calc(var(--v,-2) * 1px))}75%{transform:translateY(calc(var(--v,-2) * -.15px))}}
@keyframes amr-ic-separar{0%,100%{transform:none}45%{transform:translate(var(--dx),var(--dy))}75%{transform:translate(calc(var(--dx) * -.15),calc(var(--dy) * -.15))}}
@keyframes amr-ic-expandir{0%,100%{transform:none}45%{transform:scale(var(--v,1.12))}75%{transform:scale(calc(1 - (var(--v,1.12) - 1) * .2))}}
@keyframes amr-ic-redibujar{0%{stroke-dasharray:1;stroke-dashoffset:1;opacity:0}10%{opacity:1}100%{stroke-dasharray:1;stroke-dashoffset:0;opacity:1}}
@keyframes amr-ic-saltar{0%,100%{transform:none}35%{transform:translateY(-2.2px)}65%{transform:translateY(.4px)}}
@keyframes amr-ic-ola-x{0%,100%{transform:none}40%{transform:translateX(1.8px)}70%{transform:translateX(-.3px)}}
@keyframes amr-ic-latir{0%,100%{opacity:1}45%{opacity:.2}}
@keyframes amr-ic-destello{0%,100%{opacity:1}20%{opacity:.25}40%{opacity:1}60%{opacity:.45}}
@keyframes amr-ic-parpadear{0%,100%{transform:none}50%{transform:scaleY(.1)}}
/* ══ fin de los gestos de los iconos ══ */
