/* public/styles.css — hoja única, sin frameworks.
   Dos capas, una encima de la otra:
   · la ESTRUCTURA es la de Frappe UI (repos5/frappe/frappe-ui): sus tokens de
     tipografía, radios, sombras y el juego de componentes.
   · la PALETA es la de Kiwa (kiwa.com/es-co/co), leída de sus CSS reales:
     --color-primary #0054C5, --color-primary-darkest #072643,
     --color-secondary (el verde menta del resaltado) #80FFCA, --color-subtle
     #F0F0E0, --color-supplementary #FFF672 y sus grises. Los hex se convirtieron
     a oklch para poder mezclarlos con los de Frappe sin romper el contraste. */

/* ---------- tipografía ----------
   Dos familias, como en Kiwa (que usa Azo Sans y cae a Work Sans):
   · Work Sans en la voz de marca — títulos, la marca, los números grandes;
   · Inter Variable en el texto de interfaz — tablas, formularios, botones.
   Work Sans es la fuente abierta que kiwa.com declara como respaldo de su Azo
   Sans (que es de Typekit y no se puede redistribuir). Solo el subconjunto latin:
   lo que no cubra cae a Inter, así no hay huecos en castellano. */
@font-face {
  font-family: 'WorkSansVar';
  font-weight: 100 900;
  font-display: swap;
  font-style: normal;
  src: url('/estatico/fonts/WorkSans.var.woff2') format('woff2');
}
@font-face {
  font-family: 'WorkSansVar';
  font-weight: 100 900;
  font-display: swap;
  font-style: italic;
  src: url('/estatico/fonts/WorkSans-Italic.var.woff2') format('woff2');
}

/* ---------- Inter Variable: el texto de interfaz de Frappe UI ---------- */
@font-face {
  font-family: 'InterVar';
  font-weight: 100 900;
  font-display: swap;
  font-style: normal;
  src: url('/estatico/fonts/Inter.var.woff2') format('woff2');
  unicode-range: U+0000-05FF, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}
@font-face {
  font-family: 'InterVar';
  font-weight: 100 900;
  font-display: swap;
  font-style: italic;
  src: url('/estatico/fonts/Inter-Italic.var.woff2') format('woff2');
  unicode-range: U+0000-05FF, U+2000-206F, U+20AC, U+2122;
}

:root {
  /* superficies: el blanco y los grises de Kiwa, apenas azulados */
  --surface-base: oklch(1 0 0);
  --surface-1: oklch(0.976 0.003 250);
  --surface-2: oklch(0.962 0.005 250);
  --surface-3: oklch(0.944 0.007 250);
  --surface-4: oklch(0.913 0.009 250);
  --surface-10: oklch(0.264 0.065 250.5);   /* #072643: el azul más oscuro de Kiwa */

  /* tinta: el texto de Kiwa es azul profundo, no negro */
  --ink-9: oklch(0.264 0.065 250.5);
  --ink-8: oklch(0.322 0.062 252);
  --ink-6: oklch(0.470 0.042 252);
  --ink-5: oklch(0.552 0.032 252);
  --ink-4: oklch(0.676 0.018 252);
  --ink-3: oklch(0.847 0.010 250);

  /* líneas (alfa sobre la tinta, como en Frappe) */
  --line-1: oklch(0.264 0.065 250.5 / 0.078);
  --line-2: oklch(0.264 0.065 250.5 / 0.14);
  --line-3: oklch(0.264 0.065 250.5 / 0.24);
  --line-4: oklch(0.264 0.065 250.5 / 0.42);

  /* acento: el azul Kiwa y, al lado, el menta que usan para resaltar */
  --accent: oklch(0.478 0.190 259.5);        /* #0054C5 */
  --accent-hover: oklch(0.325 0.176 265.5);  /* #09208C */
  --accent-soft: oklch(0.955 0.023 254.3);   /* #CBE2FF aclarado */
  --accent-ink: oklch(0.420 0.180 261);
  --mint: oklch(0.913 0.137 164.1);          /* #80FFCA */
  --mint-ink: oklch(0.445 0.108 160);        /* texto legible sobre menta */
  --navy: oklch(0.264 0.065 250.5);          /* #072643: paneles oscuros */
  --kiwa-orange: oklch(0.684 0.212 40.6);    /* #FF5C00: sólo franjas, nunca texto */

  /* estados: superficie tenue + tinta (así los arma Frappe) */
  --ok-soft: oklch(0.958 0.045 163);
  --ok-ink: oklch(0.445 0.105 160);
  --ok-line: oklch(0.868 0.090 161);
  --warn-soft: oklch(0.965 0.052 95.3);      /* #FEF4CD */
  --warn-ink: oklch(0.476 0.122 49.6);       /* #914308 */
  --warn-line: oklch(0.905 0.078 95);
  --bad-soft: oklch(0.971 0.013 17.4);       /* #FEF2F2 */
  --bad-ink: oklch(0.505 0.190 27.5);        /* #B91C1C */
  --bad-line: oklch(0.900 0.045 17);

  /* radios (radius 1..9 de Frappe) */
  --r-1: 4px;
  --r-2: 5px;
  --r-3: 6px;
  --r-4: 8px;
  --r-5: 10px;
  --r-6: 12px;
  --r-8: 20px;
  --r-full: 9999px;

  /* sombras (exactas de tokens/effects.js) */
  --shadow-sm: inset 0 0.25px 1.5px 0 #ffffff29, 0 0 1px 0 #00000033, 0 1px 3px 0 #00000024;
  --shadow-base: inset 0 0.25px 1.5px 0 #ffffff29, 0 0 1.5px 0 #00000029, 0 2px 5px 0 #00000024;
  --shadow-md: inset 0 0.25px 1.5px 0 #ffffff29, 0 0 1.5px 0 #00000026, 0 0 6px 2px #0000000a, 0 6px 12px -2px #00000014;
  --shadow-lg: inset 0 0.25px 1.5px 0 #ffffff29, 0 0 1.5px 0 #0000002e, 0 0 6px 3px #00000008, 0 18px 22px -6px #0000001a;

  /* anillo de foco (Frappe, teñido con el azul de Kiwa) */
  --ring: 2px solid oklch(0.478 0.190 259.5 / 0.6);

  /* iconos del botón de tema (máscara: se pintan con currentColor) */
  --icon-sun: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='1.8'%20stroke-linecap='round'%3E%3Ccircle%20cx='12'%20cy='12'%20r='4'/%3E%3Cpath%20d='M12%202v2M12%2020v2M2%2012h2M20%2012h2M4.9%204.9l1.4%201.4M17.7%2017.7l1.4%201.4M19.1%204.9l-1.4%201.4M6.3%2017.7l-1.4%201.4'/%3E%3C/svg%3E");
  --icon-moon: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='black'%20stroke-width='1.8'%20stroke-linejoin='round'%3E%3Cpath%20d='M20%2014.5A8.5%208.5%200%200%201%209.5%204a8.5%208.5%200%201%200%2010.5%2010.5z'/%3E%3C/svg%3E");
}

/* ---------- tema oscuro ------------------------------------------------
   Frappe UI cambia de esquema con `data-theme` en <html> y los mismos tokens
   semánticos. Acá: la base no es gris sino el azul profundo de Kiwa, y el acento
   sube de luminosidad para que siga leyéndose sobre el fondo oscuro. */
/* Los valores de referencia son darkMode en tailwind/tokens/colors.js (surface-base
   = el más oscuro, fondo de página; las tarjetas suben un escalón) y el anillo de
   tokens/effects.js (focus.dark.default = 3px #464646cc). */
:root[data-theme='dark'] {
  --surface-base: oklch(0.247 0.034 251);  /* tarjetas: un escalón sobre el fondo */
  --surface-1: oklch(0.205 0.032 251);     /* fondo de página */
  --surface-2: oklch(0.278 0.036 251);     /* campo/reposo */
  --surface-3: oklch(0.312 0.038 251);     /* hover */
  --surface-4: oklch(0.362 0.040 251);     /* pulsado */
  --surface-10: oklch(0.975 0.006 251);    /* invertido */

  --ink-9: oklch(0.968 0.008 251);
  --ink-8: oklch(0.902 0.012 251);
  --ink-6: oklch(0.766 0.022 251);
  --ink-5: oklch(0.694 0.026 251);
  --ink-4: oklch(0.590 0.028 251);
  --ink-3: oklch(0.462 0.030 251);

  --line-1: oklch(0.80 0.03 251 / 0.10);
  --line-2: oklch(0.80 0.03 251 / 0.17);
  --line-3: oklch(0.80 0.03 251 / 0.22);
  --line-4: oklch(0.80 0.03 251 / 0.32);

  --accent: oklch(0.680 0.155 256);
  --accent-hover: oklch(0.748 0.140 256);
  --accent-soft: oklch(0.292 0.072 256);
  --accent-ink: oklch(0.788 0.118 256);
  --mint: oklch(0.913 0.137 164.1);
  --mint-ink: oklch(0.850 0.140 163);
  --navy: oklch(0.205 0.032 251);
  --kiwa-orange: oklch(0.684 0.212 40.6);

  --ok-soft: oklch(0.272 0.055 163);
  --ok-ink: oklch(0.800 0.115 162);
  --ok-line: oklch(0.372 0.072 162);
  --warn-soft: oklch(0.272 0.050 95);
  --warn-ink: oklch(0.878 0.130 100);
  --warn-line: oklch(0.372 0.080 95);
  --bad-soft: oklch(0.268 0.060 22);
  --bad-ink: oklch(0.735 0.160 24);
  --bad-line: oklch(0.382 0.100 24);

  --shadow-sm: inset 0 0.5px 0.5px 0.5px #ffffff08, 0 0 14px 0 #0000002e, 0 1px 3px 0 #000000b2;
  --shadow-base: inset 0 0.5px 0.5px 0.5px #ffffff08, 0 0 14px 0 #0000002e, 0 2px 5px 0 #00000099;
  --shadow-md: inset 0 0.5px 0.5px 0.5px #ffffff08, 0 0 16px 2px #00000033, 0 6px 12px -2px #00000099;
  --shadow-lg: inset 0 0.5px 1.5px 0.5px #ffffff0a, 0 0 16px 0 #0000001a, 0 18px 22px -6px #000000b2;

  --ring: 2px solid oklch(0.680 0.155 256 / 0.8);
  color-scheme: dark;
}

/* El botón primario es el azul Kiwa: en oscuro el acento se aclara, así que la
   tinta pasa a azul profundo para no perder contraste. */
:root[data-theme='dark'] .btn-primary { color: oklch(0.205 0.032 251); }
:root[data-theme='dark'] .btn-primary:hover { background: oklch(0.748 0.140 256); border-color: oklch(0.748 0.140 256); }
:root[data-theme='dark'] .btn-primary:active { background: oklch(0.680 0.155 256); }
:root[data-theme='dark'] .chip-check input:checked + span { color: oklch(0.205 0.032 251); }

* { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  background: var(--surface-1);
  color: var(--ink-8);
  font-family: 'InterVar', 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 14px;
  /* Densidad de Frappe UI: su `text-*` (todo lo que es UI: etiqueta, celda, botón,
     nav) va con line-height 1.35, y 1.5 se reserva para párrafos que corren varios
     renglones (`text-p-*`, que en Kiwaya es .material/.prosa). Con 1.5 en todo, cada
     línea de interfaz pedía ~11% más de alto y la pantalla se leía suelta. */
  line-height: 1.35;
  letter-spacing: 0.02em;
  font-weight: 420;
  font-variation-settings: 'opsz' 16;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a { color: var(--accent-ink); text-decoration: none; }
a:hover { text-decoration: underline; }

/* títulos: la voz de Kiwa (Work Sans), 24/18/13, line-height 1.35 */
h1, h2, h3, h4 {
  margin: 0 0 12px; line-height: 1.35; font-weight: 560;
  font-family: 'WorkSansVar', 'InterVar', -apple-system, BlinkMacSystemFont, sans-serif;
  letter-spacing: -0.012em;
}
h1 { font-size: 26px; letter-spacing: -0.022em; color: var(--ink-9); font-weight: 500; }
h2 { font-size: 18px; color: var(--ink-9); font-weight: 520; }
h3 {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-5); font-family: 'InterVar', sans-serif;
}
p { margin: 0 0 12px; }

code {
  background: var(--surface-3);
  padding: 1px 5px;
  border-radius: var(--r-1);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.92em;
}

hr { border: 0; border-top: 1px solid var(--line-1); margin: 20px 0; }

/* ---------- barra superior: la finura de Frappe, el filo de menta de Kiwa ---------- */
.topbar {
  background: color-mix(in oklab, var(--surface-base) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(8px);
  border-bottom: 1px solid var(--line-1);
  border-top: 2px solid var(--mint);
  position: sticky;
  top: 0;
  z-index: 20;
}
.topbar-inner {
  max-width: 1180px; margin: 0 auto; padding: 10px 24px;
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
}
/* La marca: el logotipo de Kiwa es la palabra en minúscula y fina. La marca
   geométrica es un cuadrado azul profundo con la mitad en menta. */
.brand {
  font-weight: 300; letter-spacing: -0.03em; color: var(--ink-9); font-size: 18px;
  display: inline-flex; align-items: center; gap: 8px; text-decoration: none;
  text-transform: lowercase;
  font-family: 'WorkSansVar', sans-serif;
}
.brand:hover { text-decoration: none; color: var(--accent); }
.brand::before {
  content: ''; width: 20px; height: 20px; border-radius: var(--r-3); flex: none;
  background:
    linear-gradient(135deg, var(--mint) 0 50%, transparent 50%),
    var(--navy);
  box-shadow: inset 0 0 0 1px oklch(0.264 0.065 250.5 / 0.35);
}
.brand span { color: var(--ink-5); font-weight: 420; letter-spacing: 0; font-size: 13px; }
.brand b { font-weight: 500; }

/* Módulos: dos pestañas arriba, con el aspecto de «tabs» de Frappe UI. */
.modules {
  display: flex; gap: 2px; align-items: center;
  margin-left: 14px; padding-left: 14px;
  border-left: 1px solid var(--surface-4);
}
.mod {
  color: var(--ink-6); font-size: 13px; font-weight: 500;
  padding: 6px 10px; border-radius: var(--r-3); text-decoration: none;
  white-space: nowrap; transition: background-color 120ms ease, color 120ms ease;
}
.mod:hover { background: var(--surface-3); color: var(--ink-9); text-decoration: none; }
.mod.active {
  background: var(--accent-soft); color: var(--accent-ink); font-weight: 560;
  box-shadow: inset 0 -2px 0 var(--accent);
}

/* Selección en lote: la barra sólo existe cuando hay algo marcado, y se queda
   pegada arriba de la tabla mientras se recorre (Frappe: list_view actions). */
.sel-barra {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  padding: 10px 14px; margin-bottom: 10px;
  background: var(--accent-tint); border: 1px solid var(--accent-soft);
  border-radius: var(--r-md); font-size: 13px;
  position: sticky; top: 8px; z-index: 3;
}
.sel-barra[hidden] { display: none; }
.sel-barra strong { font-variant-numeric: tabular-nums; }
.sel-barra .btn { margin-left: 0; }
.sel-col { width: 34px; padding-right: 0 !important; }
.sel-col input[type='checkbox'] {
  width: 17px; height: 17px; accent-color: var(--accent); cursor: pointer;
}
.sel-col input[type='checkbox']:disabled { cursor: not-allowed; opacity: 0.4; }

/* Lo que se va a construir: cartel centrado con ícono. */
.empty-state { padding: 44px 24px; }
/* El estado vacío de una lista terminada no es «no hay nada»: dice la causa y deja
   el botón que la resuelve (Frappe: empty_state.js:96-140). */
.empty-state h3 { font-size: 15px; font-weight: 600; margin-bottom: 6px; }
.empty-state .sub { max-width: 46ch; margin: 0 auto 16px; }
.empty-state .btn { margin-top: 2px; }
.card > .empty-state, .empty-state { text-align: center; }
.empty-icon {
  display: inline-flex; width: 46px; height: 46px; align-items: center; justify-content: center;
  border-radius: var(--r-4); background: var(--surface-3); color: var(--ink-6); margin-bottom: 14px;
}
.empty-icon svg { width: 22px; height: 22px; }
.eyebrow {
  margin: 0 0 6px; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ink-5); font-weight: 600;
}
.hint { color: var(--ink-5); font-size: 13px; margin: 14px 0 0; }

.nav { display: flex; gap: 2px; flex-wrap: wrap; margin-left: auto; align-items: center; }
.nav a {
  color: var(--ink-6); padding: 6px 10px; border-radius: var(--r-3); font-size: 13px;
  text-decoration: none; transition: background-color 120ms ease, color 120ms ease;
  white-space: nowrap;
}
.nav a:hover { background: var(--surface-3); color: var(--ink-9); text-decoration: none; }
.nav a.active { background: var(--surface-3); color: var(--ink-9); font-weight: 560; }
.nav .count {
  display: inline-block; min-width: 17px; padding: 0 5px; margin-left: 5px;
  background: var(--bad-soft); color: var(--bad-ink);
  border-radius: var(--r-full); font-size: 11px; font-weight: 600; text-align: center;
  line-height: 17px;
}
.nav a.icon-btn { padding: 0; position: relative; text-decoration: none; }
/* El número del campanita: va pegado arriba a la derecha del icono, con el borde
   del color de la barra para que se despegue del icono de abajo. */
.nav a.icon-btn .dot {
  position: absolute; top: -2px; right: -3px;
  min-width: 15px; height: 15px; padding: 0 4px;
  display: grid; place-items: center;
  background: var(--bad-ink); color: var(--surface-base);
  border: 2px solid var(--surface-base); border-radius: var(--r-full);
  font-size: 10px; font-weight: 650; line-height: 1; letter-spacing: -0.01em;
}

/* Barra de filtros: un solo renglón de campos chicos, y abajo los guardados. */
.filters {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: end;
  padding: 12px 14px; margin-bottom: 14px;
  background: var(--surface-2); border: 1px solid var(--line-1); border-radius: var(--r-4);
}
.filters .f-field { display: grid; gap: 4px; }
.filters .f-field > span { font-size: 11px; font-weight: 600; color: var(--ink-5); }
.filters input[type='search'], .filters input[type='text'], .filters select {
  min-width: 132px; padding: 6px 9px; font-size: 13px;
}
/* El campo de búsqueda crece, pero no se come la barra: sin tope, empujaba los
   botones a un segundo renglón a 1180px de ancho. */
.filters .grow-2 { flex: 1 1 160px; min-width: 140px; max-width: 260px; }
.filters .f-actions { display: flex; gap: 6px; margin-left: auto; }
.saved-filters { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 14px; }
.saved-filters .s-label { font-size: 11px; font-weight: 600; color: var(--ink-4); margin-right: 2px; }
.saved-filters .saved { display: inline-flex; align-items: center; gap: 0; }
.saved-filters .saved a {
  padding: 4px 8px; font-size: 12px; color: var(--ink-6); text-decoration: none;
  border: 1px solid var(--line-2); border-right: 0;
  border-radius: var(--r-3) 0 0 var(--r-3); background: var(--surface-base);
}
.saved-filters .saved a:hover { background: var(--surface-3); color: var(--ink-9); }
.saved-filters .saved.on a { border-color: var(--accent); color: var(--accent-ink); font-weight: 560; }
.saved-filters .saved button {
  padding: 4px 6px; font-size: 12px; line-height: 1; color: var(--ink-4);
  border: 1px solid var(--line-2); border-radius: 0 var(--r-3) var(--r-3) 0;
  background: var(--surface-base); cursor: pointer;
}
.saved-filters .saved button:hover { background: var(--bad-soft); color: var(--bad-ink); border-color: var(--bad-line); }

/* La estrella: deja la vista como predeterminada (se aplica sola al entrar).
   Ocupa el mismo lugar en las dos posiciones para que el nombre no se mueva al
   marcar; el ☆/★ es el estado, no un adorno. */
.saved-filters .saved .star {
  border-radius: var(--r-sm) 0 0 var(--r-sm);
  width: 24px; padding: 0; font-size: 13px; line-height: 1; color: var(--ink-4);
}
.saved-filters .saved .star:hover { background: var(--warn-soft); color: var(--warn-ink); border-color: var(--warn-line); }
.saved-filters .saved .star.on { color: var(--warn-ink); background: var(--warn-soft); border-color: var(--warn-line); }
.saved-filters .saved.predeterminada a { font-weight: 600; }

/* Aviso de que lo que se ve no es «todo», sino una vista guardada. */
.vista-chip {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-bottom: 12px; padding: 8px 12px;
  background: var(--surface-2); border: 1px dashed var(--line); border-radius: var(--r-md);
  font-size: 13px; color: var(--ink-7);
}
.vista-chip strong { color: var(--ink-9); }
.vista-chip a { font-weight: 560; }

/* Centro de avisos */
.aviso-row {
  display: flex; gap: 12px; align-items: start;
  padding: 12px 0; border-bottom: 1px solid var(--line-1);
}
.aviso-row:last-child { border-bottom: 0; }
.aviso-row .ico {
  width: 28px; height: 28px; flex: 0 0 28px; display: grid; place-items: center;
  border-radius: var(--r-full); background: var(--surface-3); color: var(--ink-6);
  font-size: 13px;
}
.aviso-row.atencion .ico { background: var(--warn-soft); color: var(--warn-ink); }
.aviso-row .txt { min-width: 0; }
.aviso-row .txt a { font-weight: 560; }
.aviso-row .when { font-size: 11px; color: var(--ink-4); white-space: nowrap; }


.wrap { max-width: 1180px; margin: 0 auto; padding: 28px 24px 64px; }
.wrap.narrow { max-width: 760px; }
/* Páginas sin cabecera ni márgenes (login): ocupan la ventana entera. */
.bare-main { min-height: 100vh; min-height: 100dvh; }

.page-head { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; margin-bottom: 22px; }
.page-head h1 { margin-bottom: 4px; }
.page-head .grow { flex: 1 1 320px; }
.page-head .actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.sub { color: var(--ink-5); font-size: 13px; margin: 0; }

/* ---------- tarjetas: blancas, borde hairline, sombra suave ---------- */
.card {
  background: var(--surface-base);
  border: 1px solid var(--line-1);
  border-radius: var(--r-5);
  padding: 20px 22px;
  margin-bottom: 16px;
  box-shadow: var(--shadow-sm);
}
.card.tight { padding: 14px 16px; }
.card > h2:first-child, .card > h1:first-child, .card > h3:first-child { margin-top: 0; }
.card > h3:first-child { margin-bottom: 14px; }

.grid { display: grid; gap: 14px; margin-bottom: 16px; }
.grid.cols-4 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.grid.cols-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }

.stat {
  background: var(--surface-base); border: 1px solid var(--line-1);
  border-radius: var(--r-5); padding: 16px 18px; box-shadow: var(--shadow-sm);
}
.stat .label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-5); font-weight: 520;
}
.stat .value {
  font-size: 30px; font-weight: 480; letter-spacing: -0.03em;
  margin-top: 6px; color: var(--ink-9); line-height: 1.1;
  font-variant-numeric: tabular-nums;
  font-family: 'WorkSansVar', sans-serif;
}
.stat .hint { font-size: 12px; color: var(--ink-5); margin-top: 2px; }
.stat.bad .value { color: var(--bad-ink); }
.stat.ok .value { color: var(--ok-ink); }

/* La tarjeta es un enlace: tocarla filtra la pantalla. (Frappe: el indicador de un
   listado ya viene con su `onclick` — sales_invoice_list.js:16-44.) */
a.stat {
  position: relative; display: block; text-decoration: none; color: inherit;
  transition: box-shadow 120ms ease, border-color 120ms ease, transform 120ms ease;
}
a.stat:hover { border-color: var(--accent-soft); box-shadow: var(--shadow-md); }
a.stat:active { transform: translateY(1px); }
a.stat:focus-visible { outline: var(--ring); outline-offset: 2px; }
/* Cuál está puesto: no basta con el color, va un borde y el texto del hint. */
a.stat[aria-current='true'] { box-shadow: inset 0 0 0 2px var(--accent); border-color: var(--accent); }
.stat-go {
  position: absolute; top: 12px; right: 14px; font-size: 15px; color: var(--ink-4);
  opacity: 0; transform: translateX(-3px); transition: opacity 120ms ease, transform 120ms ease;
}
a.stat:hover .stat-go, a.stat:focus-visible .stat-go, a.stat[aria-current='true'] .stat-go {
  opacity: 1; transform: translateX(0);
}
/* En un teléfono no hay hover: la flecha se queda, si no nadie adivina que se toca. */
@media (hover: none) {
  .stat-go { opacity: 0.55; transform: none; }
}

/* ---------- etiquetas de estado: fondo tenue, tinta del mismo tono ---------- */
.badge {
  display: inline-block; padding: 2px 8px; border-radius: var(--r-full);
  font-size: 11.5px; font-weight: 520; white-space: nowrap; line-height: 18px;
  letter-spacing: 0.01em;
}
.b-ok { background: var(--ok-soft); color: var(--ok-ink); }
.b-warn { background: var(--warn-soft); color: var(--warn-ink); }
.b-bad { background: var(--bad-soft); color: var(--bad-ink); }
.b-info { background: var(--accent-soft); color: var(--accent-ink); }
.b-muted { background: var(--surface-2); color: var(--ink-6); }

.pill {
  display: inline-block; padding: 1px 8px; border: 1px solid var(--line-2);
  border-radius: var(--r-full); font-size: 11.5px; color: var(--ink-6);
  line-height: 18px; white-space: nowrap;
}
.pill.ok { border-color: var(--ok-line); background: var(--ok-soft); color: var(--ok-ink); }
.pill.warn { border-color: var(--warn-line); background: var(--warn-soft); color: var(--warn-ink); }
.pill.bad { border-color: var(--bad-line); background: var(--bad-soft); color: var(--bad-ink); }

/* «Quién asigna»: la etiqueta con el área que envía el material. Tiene que leerse
   como un dato (de dónde viene esto), no como un estado, así que va con borde y un
   punto a la izquierda en vez de un fondo de color de estado. */
.tag-origen {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 1px 8px 1px 6px; border: 1px solid var(--line-2); border-radius: var(--r-full);
  background: var(--surface-2); color: var(--ink-6);
  font-size: 11.5px; font-weight: 520; line-height: 18px; white-space: nowrap;
  vertical-align: 1px;
}
.tag-origen::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); flex: none;
}

/* ---------- tablas: sin rejilla, encabezado chico y filas que se aclaran ---------- */
.table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.table th, .table td {
  /* 44px de fila con texto de 13.5px: 18 + 22 de padding + 1 de borde. La banda que
     usa Frappe en sus listas es 40–60px; antes quedaba en 39. */
  text-align: left; padding: 11px 10px; border-bottom: 1px solid var(--line-1);
  vertical-align: middle;
}
.table thead th {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-5); font-weight: 520; border-bottom-color: var(--line-2);
  padding-top: 6px; padding-bottom: 8px;
}
.table tbody tr { transition: background-color 100ms ease; }
.table tbody tr:hover { background: var(--surface-1); }
.table tbody tr:last-child td { border-bottom: 0; }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.table-wrap { overflow-x: auto; border-radius: var(--r-4); }

/* ---------- botones: 4 variantes de Frappe (solid, subtle, outline, ghost) ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  cursor: pointer; font: inherit; font-size: 13px; font-weight: 520; letter-spacing: 0.01em;
  height: 32px; padding: 0 11px; border-radius: var(--r-4);
  border: 1px solid var(--line-2); background: var(--surface-base); color: var(--ink-8);
  text-decoration: none; white-space: nowrap;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
  box-shadow: inset 0 0.5px 0 #ffffff;
}
.btn:hover {
  text-decoration: none; border-color: var(--line-3); background: var(--surface-1);
}
.btn:active { background: var(--surface-4); border-color: var(--line-3); }
.btn:focus-visible { outline: var(--ring); outline-offset: 1px; }

/* primario: el azul de Kiwa; el hover baja al azul profundo (#09208C), que es
   exactamente el par que usa kiwa.com en sus botones. */
.btn-primary {
  background: var(--accent); border-color: var(--accent); color: #fff;
  box-shadow: inset 0 0.5px 0 #ffffff26;
}
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-primary:active { background: var(--navy); border-color: var(--navy); }

.btn-dark {
  background: var(--accent); border-color: var(--accent); color: #fff;
  box-shadow: inset 0 0.5px 0 #ffffff26;
}
.btn-dark:hover { background: var(--accent-hover); border-color: var(--accent-hover); }

.btn-danger {
  background: var(--surface-base); border-color: var(--bad-line); color: var(--bad-ink);
}
.btn-danger:hover { background: var(--bad-soft); border-color: var(--bad-line); }

.btn-sm { height: 26px; padding: 0 9px; font-size: 12px; border-radius: var(--r-3); }
.btn[disabled], .btn[aria-disabled='true'] {
  opacity: 0.55; cursor: not-allowed; background: var(--surface-2); color: var(--ink-4);
  border-color: var(--line-1);
}

button.link {
  background: none; border: 0; color: var(--accent-ink); cursor: pointer;
  font: inherit; font-size: 13px; padding: 0;
}
button.link:hover { text-decoration: underline; }
/* «Salir» vive dentro del nav: se ve como un ítem más, no como un enlace azul */
.nav form button.link {
  color: var(--ink-6); padding: 6px 10px; border-radius: var(--r-3); font-size: 13px;
  transition: background-color 120ms ease, color 120ms ease;
}
.nav form button.link:hover {
  background: var(--surface-3); color: var(--ink-9); text-decoration: none;
}

/* ---------- formularios ---------- */
.field { margin-bottom: 16px; }
.field > label, .field label.lbl {
  display: block; font-size: 12.5px; font-weight: 520; margin-bottom: 6px; color: var(--ink-8);
  letter-spacing: 0.01em;
}
.field .help { font-size: 12px; color: var(--ink-5); margin-top: 5px; }

input[type='text'], input[type='email'], input[type='password'], input[type='number'],
input[type='date'], input[type='datetime-local'], input[type='search'], input[type='file'],
select, textarea {
  width: 100%; padding: 0 9px; height: 32px; font: inherit; font-size: 13.5px;
  color: var(--ink-8); background: var(--surface-2); border: 1px solid var(--surface-2);
  border-radius: var(--r-4); transition: background-color 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
}
input[type='file'] { padding: 5px 8px; height: auto; }
textarea { height: auto; min-height: 170px; padding: 9px 10px; resize: vertical;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; line-height: 1.55; }
input::placeholder, textarea::placeholder { color: var(--ink-5); }
input:hover, select:hover, textarea:hover { background: var(--surface-3); border-color: var(--line-2); }
input:focus, select:focus, textarea:focus {
  outline: none; background: var(--surface-base); border-color: var(--line-4);
  box-shadow: var(--shadow-sm);
}
input[type='checkbox'], input[type='radio'] { accent-color: var(--surface-10); }
select { cursor: pointer; }

.row { display: flex; gap: 16px; flex-wrap: wrap; }
.row > * { flex: 1 1 180px; }
.check { display: flex; gap: 9px; align-items: flex-start; font-size: 13.5px; }
.check input { margin-top: 2px; accent-color: var(--surface-10); }

/* Varias áreas por persona: casillas en forma de chip. */
.areas-pick { display: flex; flex-wrap: wrap; gap: 6px; }
.chip-check { display: inline-flex; }
.chip-check input { position: absolute; opacity: 0; width: 0; height: 0; }
.chip-check span {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 12.5px; color: var(--ink-6); background: var(--surface-2);
  border: 1px solid var(--line-1); border-radius: 999px; padding: 4px 10px;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
.chip-check span:hover { background: var(--surface-3); color: var(--ink-8); }
.chip-check input:checked + span {
  background: var(--surface-10); color: #fff; border-color: transparent; font-weight: 560;
}
.chip-check input:focus-visible + span { outline: var(--ring); outline-offset: 2px; }
/* ---------- tabla que se apila en el teléfono ----------

   CUIDADO con reusar `.stack` como utilidad genérica. Antes acá vivía
   `.stack { display: flex; flex-direction: column }`, y las tablas apilables se escriben
   `class="table stack"`: esa utilidad ganaba en especificidad de orden y convertía el
   <table> en un **flex** —el <thead> y el <tbody> pasaban a ser dos filas flex
   independientes—, así que el encabezado dejaba de compartir columnas con el cuerpo.
   En escritorio se veía como que «la tabla está mal dimensionada»: los títulos
   ocupaban 377 px a la izquierda y las celdas se repartían 1.086 px.
   El apilado real es del breakpoint de abajo (`.table.stack { display: block }`),
   y no necesita ninguna utilidad: la clase sola no hace nada en escritorio. */
.table.stack { display: table; }

fieldset {
  border: 1px solid var(--line-1); border-radius: var(--r-5);
  padding: 16px 18px; margin: 0 0 16px; background: var(--surface-1);
}
legend {
  font-size: 11px; font-weight: 560; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-5); padding: 0 6px;
}

/* ---------- avisos ---------- */
.flash {
  border-radius: var(--r-4); padding: 11px 14px; margin-bottom: 16px;
  font-size: 13.5px; border: 1px solid; box-shadow: var(--shadow-sm);
}
.flash.ok { background: var(--ok-soft); border-color: var(--ok-line); color: var(--ok-ink); }
.flash.err { background: var(--bad-soft); border-color: var(--bad-line); color: var(--bad-ink); }
.flash.info { background: var(--accent-soft); border-color: var(--accent-soft); color: var(--accent-ink); }

/* ---------- avisos flotantes (antes eran un cartel arriba de todo) ----------
   Frappe los pone abajo a la derecha y que se vayan solos (Toast.md:47,70).
   Acá el cartel lo sigue renderizando el servidor: si fallara el JS, se ve
   igual (sin JS simplemente se queda quieto arriba). */
.avisos {
  position: fixed; right: 16px; bottom: 16px; z-index: 60;
  display: flex; flex-direction: column; gap: 8px;
  max-width: min(420px, calc(100vw - 32px));
}
.avisos .flash {
  margin: 0; display: flex; align-items: flex-start; gap: 10px;
  box-shadow: var(--shadow-lg); animation: entrar-aviso 160ms ease-out;
}
.flash-x {
  flex: 0 0 auto; margin: -4px -6px -4px 0; padding: 0 6px;
  border: 0; background: transparent; color: inherit; cursor: pointer;
  font-size: 18px; line-height: 1.1; opacity: 0.55; border-radius: 6px;
}
.flash-x:hover { opacity: 1; }
.flash-x:focus-visible { outline: var(--ring); outline-offset: 1px; }
@keyframes entrar-aviso { from { opacity: 0; transform: translateY(6px); } }

@media (max-width: 560px) {
  .avisos { left: 12px; right: 12px; bottom: 12px; max-width: none; }
}

/* ---------- diálogo de confirmación ----------
   El <dialog> nativo ya da foco atrapado, Esc y el fondo oscurecido; acá solo se
   le da la cara del sitio. */
.dlg {
  border: 0; padding: 0; border-radius: var(--r-4, 14px);
  max-width: min(440px, calc(100vw - 32px));
  background: var(--surface-base); color: var(--ink-9); box-shadow: var(--shadow-lg);
}
.dlg::backdrop { background: oklch(0.264 0.065 250.5 / 0.44); }
.dlg-caja { display: grid; gap: 10px; padding: 20px; }
.dlg-titulo { margin: 0; font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
.dlg-texto { margin: 0; font-size: 14px; line-height: 1.5; color: var(--ink-6); }
.dlg-acciones { display: flex; gap: 8px; justify-content: flex-end; margin-top: 6px; }

/* ---------- error por campo ----------
   Frappe marca el campo y escribe el motivo debajo (TextInput.vue:43-45). Antes
   había un solo cartel global que no decía CUÁL campo estaba mal. */
.field-err {
  display: flex; align-items: flex-start; gap: 5px;
  margin: 5px 0 0; font-size: 12.5px; line-height: 1.4;
  color: var(--bad-ink, oklch(0.52 0.19 25)); font-weight: 500;
}
input[aria-invalid='true'], textarea[aria-invalid='true'], select[aria-invalid='true'] {
  border-color: var(--bad-line, oklch(0.55 0.19 25 / 0.6));
}
.area-box[aria-invalid='true'], .quiz-box[aria-invalid='true'] {
  border: 1px solid var(--bad-line, oklch(0.55 0.19 25 / 0.6)); border-radius: var(--r-3, 10px); padding: 8px;
}

/* ---------- botón trabajando ----------
   Frappe lo deja con un giro y sin responder al segundo toque (Button.vue:291-302). */
.btn[aria-busy='true'] { pointer-events: none; opacity: 0.85; }
.btn[aria-busy='true']::before {
  content: ''; display: inline-block; vertical-align: -2px; margin-right: 6px;
  width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent;
  animation: girar 0.7s linear infinite;
}
@keyframes girar { to { transform: rotate(360deg); } }

/* ---------- material (el contenido que la persona lee) ---------- */
.material { font-size: 14.5px; line-height: 1.62; max-width: 68ch; }
/* Prosa que corre varios renglones: el único lugar donde 1.5 manda (en Frappe es
   `text-p-*`). Para todo lo demás rige el 1.35 del body. */
.prosa { line-height: 1.5; }
.material h3, .material h4, .material h5 {
  text-transform: none; letter-spacing: 0; color: var(--ink-9); margin: 22px 0 8px;
  font-weight: 560;
}
.material h3 { font-size: 18px; }
.material h4 { font-size: 15.5px; }
.material h5 { font-size: 14px; }
.material ul, .material ol { margin: 0 0 14px; padding-left: 22px; }
.material li { margin-bottom: 6px; }
.material blockquote {
  margin: 0 0 14px; padding: 10px 14px; border-left: 3px solid var(--mint);
  background: var(--surface-1); color: var(--ink-6); border-radius: 0 var(--r-3) var(--r-3) 0;
}
.material code { background: var(--surface-2); }

/* ---------- progreso ---------- */
.progress { height: 6px; background: var(--surface-3); border-radius: var(--r-full); overflow: hidden; }
.progress > span {
  display: block; height: 100%; background: var(--accent); border-radius: var(--r-full);
  transition: width 300ms ease;
}
.bar-row {
  display: grid; grid-template-columns: 1fr 84px; gap: 12px; align-items: center;
  margin-bottom: 10px; font-size: 13px;
}
.bar-row .pct { text-align: right; color: var(--ink-6); font-variant-numeric: tabular-nums; }

/* ---------- botón de icono y cambio de tema ---------- */
.icon-btn {
  width: 30px; height: 30px; padding: 0; display: inline-grid; place-items: center;
  background: transparent; border: 1px solid transparent; border-radius: var(--r-3);
  color: var(--ink-5); cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}
.icon-btn:hover { background: var(--surface-3); color: var(--ink-8); }
.icon-btn:focus-visible { outline: var(--ring); outline-offset: 1px; }

/* Un solo botón que muestra el icono de lo que va a pasar: sol en oscuro. */
.theme-toggle::before {
  content: ''; width: 16px; height: 16px; background-color: currentColor;
  -webkit-mask: var(--icon-moon) center / 16px 16px no-repeat;
  mask: var(--icon-moon) center / 16px 16px no-repeat;
}
:root[data-theme='dark'] .theme-toggle::before {
  -webkit-mask-image: var(--icon-sun);
  mask-image: var(--icon-sun);
}

/* ---------- login ----------
/* Ocupa la ventana entera y deja la tarjeta en el centro exacto; si la
   pantalla es baja, se centra igual y deja scrollear.
   Fondo claro: el papel gris de la app, un halo de menta que baja desde arriba y
   la franja de marca pegada al borde superior (menta → azul → naranja: la paleta
   de Kiwa). El navy queda solo para el tema oscuro. */
.login-shell {
  min-height: 100vh; min-height: 100dvh;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  position: relative;
  background:
    radial-gradient(110% 65% at 50% -25%, oklch(0.913 0.137 164.1 / 0.34) 0%, transparent 62%),
    radial-gradient(90% 60% at 105% 108%, oklch(0.684 0.212 40.6 / 0.10) 0%, transparent 60%),
    var(--surface-1);
}
.login-shell::before {
  content: ''; position: fixed; top: 0; left: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, var(--mint) 0%, var(--accent) 58%, var(--kiwa-orange) 100%);
}
:root[data-theme='dark'] .login-shell {
  background:
    radial-gradient(110% 65% at 50% -25%, oklch(0.913 0.137 164.1 / 0.12) 0%, transparent 62%),
    radial-gradient(90% 60% at 105% 108%, oklch(0.684 0.212 40.6 / 0.14) 0%, transparent 60%),
    var(--surface-1);
}
:root[data-theme='dark'] .login-shell::before { opacity: 0.85; }
.login-card {
  width: 100%; max-width: 392px; margin: 0 auto;
  background: var(--surface-base);
  border: 1px solid var(--line-1); border-radius: var(--r-6); padding: 30px 28px;
  box-shadow: var(--shadow-md);
}
.login-card .brandmark {
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-5); margin: 0; font-weight: 520;
}
.login-card h1 { font-size: 24px; margin-bottom: 6px; font-weight: 300; letter-spacing: -0.03em; }
.login-card h1 b { font-weight: 560; }
.login-card h1 em { font-style: italic; color: var(--accent); }
.login-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 16px; }
.login-card h1 { font-size: 20px; margin-bottom: 6px; }
.login-card .sub { color: var(--ink-5); margin-bottom: 18px; }
.login-card form { margin: 0; }
.login-card .btn-primary { margin-top: 4px; }
.login-card .foot-note {
  margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--line-1);
  font-size: 12px; color: var(--ink-5); text-align: center; line-height: 1.45;
}

/* ---------- lector ---------- */
.timer {
  display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 520;
  background: var(--warn-soft); color: var(--warn-ink);
  padding: 3px 10px; border-radius: var(--r-full);
  font-variant-numeric: tabular-nums;
}
.timer.ready { background: var(--ok-soft); color: var(--ok-ink); }

.quiz-q { border-top: 1px solid var(--line-1); padding-top: 16px; margin-top: 16px; }
.quiz-q .qtext { font-weight: 520; margin-bottom: 10px; color: var(--ink-9); }
.quiz-q label {
  display: block; padding: 9px 12px; border: 1px solid var(--line-2);
  border-radius: var(--r-4); margin-bottom: 8px; cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease;
}
.quiz-q label:hover { background: var(--surface-1); border-color: var(--line-3); }
.quiz-q label:has(input:checked) { background: var(--accent-soft); border-color: var(--accent); }
.quiz-q input { margin-right: 9px; }

/* ---------- revisión de respuestas abiertas ---------- */
.respuesta { border-top: 1px solid var(--line-1); padding-top: 14px; margin-top: 14px; }
.respuesta .qtext { font-weight: 520; color: var(--ink-9); margin-bottom: 8px; }
.respuesta blockquote {
  margin: 0; padding: 10px 14px; border-left: 3px solid var(--accent);
  background: var(--surface-1); border-radius: 0 var(--r-4) var(--r-4) 0;
  color: var(--ink-7); white-space: pre-wrap; overflow-wrap: anywhere;
}
.revision-form {
  display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end;
  border-top: 1px solid var(--line-1); padding-top: 14px; margin-top: 16px;
}
.revision-form .field { margin-bottom: 0; min-width: 240px; }
.revision-form .actions { flex-wrap: wrap; }

/* ---------- constancia ---------- */
.cert {
  background: var(--surface-base); border: 1px solid var(--line-2);
  border-top: 3px solid var(--accent);
  border-radius: var(--r-5); padding: 38px 40px; max-width: 780px; margin: 0 auto;
  box-shadow: var(--shadow-md);
}
.cert .kicker {
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-5); font-weight: 520;
}
.cert .big {
  font-size: 30px; font-weight: 460; margin: 12px 0 20px;
  letter-spacing: -0.03em; color: var(--ink-9); line-height: 1.2;
  font-family: 'WorkSansVar', sans-serif;
}
/* El nombre del colaborador, resaltado con el menta de Kiwa: es la marca de la
   casa — un trazo de color detrás del dato que importa. */
.cert .big mark {
  background: linear-gradient(180deg, transparent 58%, var(--mint) 58%);
  color: inherit; padding: 0 2px;
}
.cert table { width: 100%; font-size: 13.5px; border-collapse: collapse; margin-top: 16px; }
.cert table td { padding: 9px 0; border-bottom: 1px solid var(--line-1); }
.cert table td:first-child { color: var(--ink-5); width: 40%; }
.cert table tr:last-child td { border-bottom: 0; }
/* El texto de la plantilla: párrafo corrido, legible, con aire arriba y abajo. */
.cert .cuerpo {
  margin: 18px 0 0;
  font-size: 14px;
  line-height: 1.62;
  color: var(--ink-2);
  text-wrap: pretty;
}
.cert .sign {
  margin-top: 30px; border-top: 1px solid var(--line-4); padding-top: 9px;
  width: 300px; font-style: italic; color: var(--ink-6); font-size: 13px;
  font-family: 'WorkSansVar', sans-serif;
}
/* Con firma dibujada no hace falta la raya: el nombre va debajo de la imagen. */
.cert .sign.sin-linea { border-top: 0; padding-top: 4px; margin-top: 4px; }
/* La firma dibujada: tinta sobre papel, así que va sobre blanco también en
   modo oscuro (una firma en negativo no es una firma). */
.cert .firma-img {
  display: block; max-width: 300px; height: auto; margin: 26px 0 0;
  background: #fff; border-bottom: 1px solid var(--line-4); padding: 2px 4px 4px;
  border-radius: var(--r-4) var(--r-4) 0 0;
}

/* ---------- firma dibujada (lector) ---------- */
.pad-wrap { position: relative; max-width: 620px; }
.pad {
  display: block; width: 100%; height: 180px;
  background: #fff;
  border: 1px dashed var(--line-4); border-radius: var(--r-4);
  cursor: crosshair; touch-action: none;
}
.pad:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pad-hint {
  position: absolute; inset: 0; display: grid; place-items: center;
  color: #8a8f98; font-size: 13px; pointer-events: none;
  transition: opacity 0.15s ease;
}
.pad-wrap:not(.pad-vacio) .pad-hint { opacity: 0; }
.pad-tools { display: flex; align-items: center; gap: 10px; margin-top: 8px; flex-wrap: wrap; }

/* ---------- utilidades ---------- */
.muted { color: var(--ink-5); }
.small { font-size: 12.5px; }
.right { text-align: right; }
.center { text-align: center; }
.mt0 { margin-top: 0; }
.mb0 { margin-bottom: 0; }
.nowrap { white-space: nowrap; }
.grow { flex: 1 1 auto; }

/* ---------- teléfono: una columna, nada cortado -------------------------
   La app se usa en el celular del colaborador (abrir el material, leer, firmar),
   así que a 720px o menos: una sola columna, la barra de arriba se desplaza en
   horizontal en vez de ocupar tres renglones, los filtros se apilan y las tablas
   largas se leen como fichas en lugar de obligar a arrastrar de costado. */
@media (max-width: 720px) {
  .topbar-inner { padding: 8px 14px; gap: 10px; }
  /* la marca queda en el cuadro; el texto «capacitaciones y comunicados» sobra */
  .brand span { display: none; }
  .modules { margin-left: 0; padding-left: 0; border-left: 0; order: -1; }
  /* El menú en una tira que se desplaza: en 390px no entra en un renglón y
     envolverlo empujaba el contenido dos renglones hacia abajo. */
  .nav {
    margin-left: 0; width: 100%; flex-wrap: nowrap; gap: 4px;
    overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
    padding-bottom: 2px;
  }
  .nav::-webkit-scrollbar { display: none; }
  .nav > * { flex: 0 0 auto; }

  .wrap { padding: 16px 14px 44px; }
  h1 { font-size: 22px; }
  .page-head { flex-direction: column; align-items: stretch; gap: 10px; margin-bottom: 16px; }
  .page-head .actions { width: 100%; }
  .page-head .actions > * { flex: 1 1 auto; justify-content: center; }

  /* grids: siempre una columna (auto-fit ya casi lo hace; esto cierra el resto) */
  .grid.cols-2, .grid.cols-3, .grid.cols-4 { grid-template-columns: 1fr; }

  /* filtros: campos a lo ancho y los botones en su propio renglón */
  .filters { flex-direction: column; align-items: stretch; gap: 10px; }
  .filters .f-field, .filters .grow-2 { flex: 1 1 auto; width: 100%; min-width: 0; max-width: none; }
  .filters input[type='search'], .filters input[type='text'], .filters select { width: 100%; min-height: 40px; }
  .filters .f-actions { margin-left: 0; }
  .filters .f-actions > * { flex: 1 1 0; justify-content: center; }

  /* dedo, no puntero: 40px de alto mínimo */
  .btn { min-height: 40px; }
  /* también los campos: el de la firma venía en 32px. Las casillas y radios no se
     tocan: van dentro de su <label>, así que el renglón entero ya es el blanco. */
  .wrap input[type='text'], .wrap input[type='email'], .wrap input[type='password'],
  .wrap input[type='search'], .wrap input[type='date'], .wrap input[type='number'],
  .wrap select { min-height: 40px; }

  /* tablas: el contenedor desplaza (y no corta) cuando no hay versión en fichas */
  .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .table th, .table td { padding: 9px 8px; font-size: 13px; }

  /* la constancia y el certificado, a lo ancho de la pantalla */
  .cert { padding: 20px 16px; }
  .cert .big { font-size: 26px; }
}

/* ---------- «esto se desliza de costado» ----------
   Un contenedor horizontal que se corta sin avisar se lee como si estuviera
   completo: en un teléfono, la última columna de una tabla o el último botón de
   una barra «no existen». Acá hay DOS señales, y las dos se encienden solas:

   1. El borde se desvanece sólo del lado donde queda contenido
      (`data-hay-der` / `data-hay-izq`, que pone `app.js`). Es una máscara, no un
      degradado blanco pegado encima: así funciona igual en tema claro y oscuro.
   2. La barra de desplazamiento se ve siempre, fina y del color del texto
      apagado — es lo único que dice, mientras arrastrás, cuánto llevás y cuánto
      falta. En iOS las barras se esconden hasta que tocás; estilizarlas las deja
      a la vista.

   No hace falta marcar nada a mano: `app.js` busca todo lo que desborda. */
[data-desliza] {
  overscroll-behavior-x: contain; /* el arrastre no arrastra la página entera */
  scrollbar-width: thin;
  scrollbar-color: var(--line-3) transparent;
}
[data-desliza]::-webkit-scrollbar { height: 8px; }
[data-desliza]::-webkit-scrollbar-track { background: transparent; }
[data-desliza]::-webkit-scrollbar-thumb {
  background: var(--line-3); border-radius: 99px;
  border: 2px solid var(--surface-base); /* el pulgar se ve «suelto», no pegado */
}

[data-hay-der='1'] {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 30px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 30px), transparent);
}
[data-hay-izq='1'] {
  -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 30px), transparent);
  mask-image: linear-gradient(to left, #000 calc(100% - 30px), transparent);
}
[data-hay-izq='1'][data-hay-der='1'] {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 30px, #000 calc(100% - 30px), transparent);
  mask-image: linear-gradient(to right, transparent, #000 30px, #000 calc(100% - 30px), transparent);
}

/* Enganche: las tiras de pestañas y el menú se acomodan de a un ítem en vez de
   quedar a mitad de camino. `proximity` y no `mandatory`: si el dedo quiere
   frenar entre dos, lo deja. */
.nav, .form-tabs { scroll-snap-type: x proximity; scroll-padding-inline: 4px; }
.nav > *, .form-tabs > * { scroll-snap-align: start; }

/* Tablas que en el teléfono se leen como fichas: cada fila es una tarjeta y cada
   celda se rotula con el encabezado (data-label). La usan las listas donde el
   botón de acción vive en la última columna: arrastrando de costado, en un
   teléfono, ese botón queda fuera de la vista. */
@media (max-width: 720px) {
  .table.stack { display: block; }
  .table.stack thead { display: none; }
  .table.stack tbody { display: block; }
  .table.stack tbody tr {
    display: block; padding: 12px 0;
    border-bottom: 1px solid var(--line-1);
  }
  .table.stack tbody tr:last-child { border-bottom: 0; }
  .table.stack tbody tr:hover { background: none; }
  .table.stack td {
    display: block; border: 0; padding: 2px 0;
    text-align: left; font-size: 13px;
  }
  .table.stack td:empty { display: none; }
  /* La etiqueta va en una columna fija a la izquierda y el valor se indenta a su
     lado (no encima): así cada ficha mide ~190 px en vez de ~320, porque el
     rótulo deja de gastar una línea por campo. El valor conserva la sangría
     cuando envuelve, que es lo que lo hace legible. */
  .table.stack td[data-label] { position: relative; padding-left: 92px; }
  .table.stack td[data-label]::before {
    content: attr(data-label); position: absolute; left: 0; top: 3px;
    width: 84px;
    font-size: 10.5px; font-weight: 600; text-transform: uppercase;
    letter-spacing: 0.06em; color: var(--ink-5);
  }
  .table.stack td[data-label] > .small { margin-top: 1px; }
  .table.stack td.right { text-align: left; }
  .table.stack td .btn { width: 100%; justify-content: center; margin-top: 6px; }
}

/* ---------- visor del material adjunto ---------------------------------
   El módulo existe para que la información se entienda, y un PDF encerrado en
   «descargar» no se lee. Acá el PDF se abre dentro de la página, la imagen se
   amplía con un clic y el video se mira sin salir del material. */
.visor { display: grid; gap: 16px; }
.visor-item {
  margin: 0;
  border: 1px solid var(--line-1);
  border-radius: var(--r-5);
  overflow: hidden;
  background: var(--surface-1);
}
.visor-marco { display: block; position: relative; background: var(--surface-3); border: 0; }
.visor-marco iframe {
  display: block; width: 100%; height: 72vh; min-height: 420px;
  border: 0; background: #fff;
}
.visor-zoom { cursor: zoom-in; }
.visor-zoom img {
  display: block; width: 100%; max-height: 72vh; object-fit: contain;
  background: var(--surface-3);
}
.visor-zoom-hint {
  position: absolute; right: 10px; bottom: 10px;
  padding: 4px 10px; border-radius: 999px;
  background: oklch(0.264 0.065 250.5 / 0.82); color: #fff;
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.02em;
  pointer-events: none;
}
.visor-media { display: block; width: 100%; max-height: 72vh; background: #000; }
.visor-audio { display: block; width: 100%; padding: 18px; }
.visor-ficha {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 34px 18px; text-align: center;
  text-decoration: none;
}
.visor-ficha:hover { background: var(--surface-2); text-decoration: none; }
.visor-ficha-tipo {
  font-size: 12px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--accent);
}
.visor-ficha-nota { font-size: 12.5px; color: var(--ink-5); line-height: 1.5; }
.visor-pie {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 14px; border-top: 1px solid var(--line-1); background: var(--surface-base);
}
.visor-nombre { font-weight: 550; overflow-wrap: anywhere; }
.visor-meta { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }

/* Una imagen dentro del texto del material (sintaxis `![alt](/archivo/12)`) */
.inline-img {
  display: block; max-width: 100%; height: auto; margin: 14px 0;
  border: 1px solid var(--line-1); border-radius: var(--r-4);
}

/* ---------- imagen ampliada a pantalla completa ------------------------ */
.lightbox {
  position: fixed; inset: 0; z-index: 90;
  display: flex; flex-direction: column;
  background: oklch(0.16 0.02 250 / 0.94);
}
.lightbox-barra { display: flex; align-items: center; gap: 10px; padding: 10px 14px; }
.lightbox-nombre {
  flex: 1 1 auto; min-width: 0;
  color: #fff; font-size: 13px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lightbox-barra .btn {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.28);
  color: #fff;
}
.lightbox-barra .btn:hover { background: rgba(255, 255, 255, 0.22); }
.lightbox-img {
  flex: 1 1 auto; min-height: 0; width: 100%;
  object-fit: contain; padding: 0 14px 14px;
}

@media (max-width: 720px) {
  /* en el teléfono el PDF ocupa lo que hay: se lee y se desplaza dentro */
  .visor-marco iframe { height: 62vh; min-height: 300px; }
  .visor-pie { flex-direction: column; align-items: flex-start; gap: 6px; }
  .visor-meta { flex-wrap: wrap; }
  .lightbox-barra { flex-wrap: wrap; }
  .lightbox-nombre { flex: 1 0 100%; }
}

@media print {
  .topbar, .nav, .no-print, .flash, .btn, .page-head .actions { display: none !important; }
  body { background: #fff; font-size: 12pt; }
  .wrap { padding: 0; max-width: none; }
  .card, .cert { border: 1px solid #ccc; box-shadow: none; }
  .cert { border-top-width: 3px; padding: 24px; }
  .cert table td { border-color: #e5e5e5; }
  /* el resaltado de menta también sale en papel (si no, el navegador lo descarta) */
  .cert .big mark { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  /* el contenedor que en pantalla desplaza no puede recortar el papel */
  .table-wrap { overflow: visible !important; }
  a[href]::after { content: ''; }
}

/* ---------- paleta de comandos (⌘K) -------------------------------------
   Sólo usa los tokens de arriba, así que el tema oscuro la hereda sin reglas
   propias. La caja se pega arriba (no centrada) para que el ojo no salte cuando
   los resultados cambian de alto mientras uno escribe. */
body.con-paleta { overflow: hidden; }
.paleta[hidden] { display: none; }
.paleta {
  position: fixed; inset: 0; z-index: 90;
  display: flex; align-items: flex-start; justify-content: center;
  padding: min(14vh, 120px) 16px 16px;
  background: oklch(0.264 0.065 250.5 / 0.36);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.paleta-caja {
  width: min(640px, 100%); overflow: hidden;
  background: var(--surface-base); border: 1px solid var(--line-2);
  border-radius: var(--r-6); box-shadow: var(--shadow-lg);
}
.paleta-input {
  width: 100%; padding: 14px 16px; border: 0; border-bottom: 1px solid var(--line-1);
  background: transparent; color: var(--ink-9); outline: none;
  font: inherit; font-size: 15px; line-height: 1.35;
}
.paleta-input::placeholder { color: var(--ink-4); }
.paleta-res { max-height: min(52vh, 420px); overflow-y: auto; padding: 6px; }
.paleta-grupo {
  padding: 10px 10px 4px; font-size: 11px; font-weight: 520;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-5);
}
.paleta-item {
  display: flex; flex-direction: column; gap: 1px; width: 100%;
  padding: 7px 10px; border: 0; border-radius: var(--r-4);
  background: transparent; color: var(--ink-8); cursor: pointer; text-align: left;
}
.paleta-item.activo { background: var(--accent-soft); }
.paleta-item.activo .paleta-titulo { color: var(--accent-ink); }
.paleta-titulo { font-size: 13.5px; font-weight: 520; color: var(--ink-9); }
.paleta-sub { font-size: 12px; color: var(--ink-5); }
.paleta-vacio { padding: 22px 12px; text-align: center; font-size: 13px; color: var(--ink-5); }
.paleta-pie {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 12px; border-top: 1px solid var(--line-1);
  font-size: 11.5px; color: var(--ink-5);
}
.paleta-pie .der { color: var(--ink-4); }
.paleta-pie kbd {
  margin-right: 2px; padding: 1px 5px; border: 1px solid var(--line-2); border-bottom-width: 2px;
  border-radius: var(--r-2); background: var(--surface-1);
  font: inherit; font-size: 10.5px; color: var(--ink-6);
}

/* ---------- lecciones (capítulos) ---------- */
/* Marcadores de la plantilla de constancia: chips de solo lectura. */
.marcadores { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin: 4px 0 18px; }
.marcadores .chip {
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 11.5px;
  padding: 2px 7px;
  border-radius: var(--r-1, 6px);
  background: var(--surface-3);
  color: var(--ink-7);
  border: 1px solid var(--line-1);
}

.acciones { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin: 0; }
.acciones > * { flex: 0 0 auto; }

.lecciones { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.lecciones > li {
  border: 1px solid var(--line-1);
  border-radius: var(--r-3);
  background: var(--surface-1);
}
.lecciones.indice > li > a {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 14px; color: inherit; text-decoration: none;
}
.lecciones.indice > li > a:hover { background: var(--surface-2); }
.lecciones > li.leida .leccion-titulo { color: var(--ink-4); }
.leccion-titulo { flex: 1 1 auto; }
.leccion-num {
  flex: 0 0 26px; height: 26px; border-radius: var(--r-full);
  background: var(--navy); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 600;
}
.lecciones details { padding: 10px 14px; }
.lecciones summary { display: flex; align-items: center; gap: 12px; cursor: pointer; list-style: none; }
.lecciones summary::-webkit-details-marker { display: none; }
.leccion-form { margin-top: 14px; }
.leccion-acciones { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.leccion-acciones form { margin: 0; }
.help-bad { color: var(--bad-ink); }

/* ---------- editor del material ----------
   Lo que se escribe se ve igual que en la pantalla del colaborador: mismos
   títulos, mismas listas, misma cita. La barra no ofrece nada que el servidor
   vaya a tirar (ver `sanitizeHtml` en lib/view.js). */

.editor { border: 1px solid var(--line-1); border-radius: var(--r-3); background: var(--surface-0); }
.editor:focus-within { outline: var(--ring); outline-offset: 1px; border-radius: 10px; }

.editor-barra {
  display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
  padding: 6px 8px; border-bottom: 1px solid var(--line-1);
  background: var(--surface-1); border-radius: var(--r-3) var(--r-3) 0 0;
  position: sticky; top: 0; z-index: 2;
}
.eb {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; height: 32px; padding: 0 8px;
  font: inherit; font-size: 13px; color: var(--ink-7);
  background: var(--surface-0); border: 1px solid var(--line-1);
  border-radius: var(--r-2); cursor: pointer;
}
.eb:hover { background: var(--surface-2); color: var(--ink-9); }
.eb:active, .eb[aria-pressed='true'] { background: var(--surface-3); color: var(--ink-9); }
.eb strong, .eb em, .eb u, .eb s { font-size: 14px; }
.eb-sep { width: 1px; height: 22px; background: var(--line-1); margin: 0 2px; }
.eb-colores { display: inline-flex; gap: 4px; }
.eb-color {
  width: 22px; height: 22px; padding: 0; border-radius: var(--r-full);
  border: 1px solid var(--line-2); cursor: pointer; background: currentColor;
}
.eb-color:hover { transform: scale(1.12); }
.eb-color:focus-visible { outline: var(--ring); outline-offset: 2px; }

.editor-area {
  min-height: 180px; padding: 14px 16px;
  font-size: 14.5px; line-height: 1.62; max-width: 72ch;
  outline: none; overflow-wrap: anywhere;
}
.editor-area:empty::before {
  content: attr(data-placeholder); color: var(--ink-4); pointer-events: none;
}
.editor-area p, .editor-area div { margin: 0 0 10px; }
.editor-area h3 { font-size: 18px; margin: 18px 0 8px; color: var(--ink-9); font-weight: 560; }
.editor-area h4 { font-size: 15.5px; margin: 16px 0 6px; color: var(--ink-9); font-weight: 560; }
.editor-area ul, .editor-area ol { margin: 0 0 12px; padding-left: 22px; }
.editor-area li { margin-bottom: 5px; }
.editor-area blockquote {
  margin: 0 0 12px; padding: 10px 14px; border-left: 3px solid var(--mint);
  background: var(--surface-1); color: var(--ink-6); border-radius: 0 var(--r-3) var(--r-3) 0;
}
.editor-area img { max-width: 100%; height: auto; border-radius: var(--r-2); }
.editor-area a { color: var(--accent-ink); }

/* Colores del texto: los cinco del editor. Se usan tanto en la barra (como
   muestra) como en el material publicado, así que el tono tiene que leerse
   sobre papel y sobre oscuro (los de arriba pasan AA en ambos). */
.tx-rojo { color: oklch(0.500 0.170 25); }
.tx-ambar { color: oklch(0.520 0.130 65); }
.tx-verde { color: oklch(0.500 0.110 155); }
.tx-azul { color: oklch(0.480 0.140 256); }
.tx-gris { color: var(--ink-5); }
:root[data-theme='dark'] .tx-rojo { color: oklch(0.760 0.140 25); }
:root[data-theme='dark'] .tx-ambar { color: oklch(0.800 0.120 75); }
:root[data-theme='dark'] .tx-verde { color: oklch(0.800 0.120 155); }
:root[data-theme='dark'] .tx-azul { color: oklch(0.780 0.110 256); }
:root[data-theme='dark'] .tx-gris { color: var(--ink-4); }

@media (max-width: 560px) {
  /* La barra no cabe: se arrastra, y los botones quedan cómodos al dedo. */
  .editor-barra { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .eb { min-width: 38px; height: 38px; flex: 0 0 auto; }
  .eb-sep, .eb-colores { flex: 0 0 auto; }
  .editor-area { padding: 12px 12px; min-height: 160px; }
}

/* ---------- menos movimiento, si el sistema lo pide ---------------------
   Quien configuró «reducir movimiento» en su Mac o su teléfono no tiene por qué
   comerse las transiciones de los botones ni el deslizamiento de los avisos. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Publicar desde el celular ----------
   El formulario de publicar es largo (contenido, plazos, preguntas) y en un
   teléfono «Guardar» quedaba dos pantallas más abajo. Acá: secciones de a una y
   la barra de guardar pegada abajo. En escritorio no cambia nada — las tres
   tarjetas se ven seguidas, como siempre. */
.form-tabs { display: none; }

@media (max-width: 720px) {
  .form-tabs {
    display: flex; gap: 4px; overflow-x: auto; margin: 0 0 12px;
    padding: 4px; background: var(--surface-2);
    border: 1px solid var(--line); border-radius: var(--r-md);
  }
  .form-tabs [data-tab] {
    flex: 1 0 auto; padding: 8px 12px; border: 0; background: none;
    font: inherit; font-size: 13px; font-weight: 560; color: var(--ink-5);
    border-radius: var(--r-sm); cursor: pointer; white-space: nowrap;
  }
  .form-tabs [data-tab][aria-selected="true"] {
    background: var(--surface); color: var(--ink-9);
    box-shadow: 0 1px 2px rgb(10 20 40 / 0.10);
  }
  /* Sin JS no hay `data-active` ni `data-tabs-on`: las tres secciones se ven
     seguidas. El CSS no esconde nada por su cuenta — si el JS falla, el formulario
     queda entero y visible en vez de vacío. */
  form[data-tabs-on] [data-step] { display: none; }
  form[data-tabs-on] [data-step][data-active="1"] { display: block; }

  .acciones-form {
    position: sticky; bottom: 0; z-index: 5;
    margin: 10px 0 0; padding: 10px 0;
    background: var(--surface); border-top: 1px solid var(--line);
  }
  .acciones-form .actions { width: 100%; }
  .acciones-form .actions .btn { flex: 1 1 auto; justify-content: center; }
}

/* ---------- Adjuntos: zona para arrastrar ----------
   El input de archivos sigue estando adentro y sigue siendo el que viaja al
   servidor: esto sólo agranda el blanco para no tener que apuntarle a un
   botón de 12px. */
.drop-zone {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  padding: 10px; border: 1px dashed var(--line-2); border-radius: var(--r-md);
  background: var(--surface-2); transition: border-color 0.12s, background 0.12s;
}
.drop-zone.sobre { border-color: var(--accent); background: var(--accent-soft); }
.drop-zone input[type="file"] { flex: 1 1 220px; }
.drop-zone .drop-hint { margin: 0; flex: 1 1 200px; font-size: 12px; color: var(--ink-5); }

/* ── Utilidad de accesibilidad ──────────────────────────────────────────────
   Texto que existe para el lector de pantalla y no para el ojo: el `<caption>` de
   una tabla, la etiqueta de una columna de acciones. Antes se resolvía con
   `aria-label` repetido en cada fila («Rol», «Rol», «Rol»…), que no dice de quién
   es cada uno. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* La tarjeta «nunca entraron»: ni buena ni mala, es una señal de adopción. */
.stat.warn .value { color: var(--warn-ink); }

/* ── La clave temporal ──────────────────────────────────────────────────────
   Se muestra una sola vez y en grande: se copia o se lee en voz alta, no se
   busca con los ojos en una línea de texto corrido. */
.flash-clave { border-color: var(--warn-line); background: var(--warn-soft); }
.clave-suelta { margin: 10px 0 12px; }
.clave-suelta code {
  display: inline-block; padding: 10px 14px; border-radius: var(--r-3);
  background: var(--surface-base); border: 1px solid var(--line-1);
  font-size: 19px; letter-spacing: 0.04em; user-select: all;
  font-family: 'JetBrainsMonoVar', ui-monospace, monospace;
}

/* En el teléfono la fila de la lista se apila y el botón queda solo en su renglón:
   ahí sí conviene que sea un blanco cómodo, no los 26 px del botón chico. */
@media (max-width: 720px) {
  .table.stack td .btn-fila { height: 40px; }
}

/* ==========================================================================
   Control de tiempos — la vida del material en una línea de tiempo
   --------------------------------------------------------------------------
   Sólo tokens: si el tema cambia, esto cambia. La línea vertical la dibuja
   el ::before de cada hito (excepto el último), así no hay un elemento extra
   que se desalinee cuando una nota ocupa dos renglones.
   ========================================================================== */
.tiempos-card { display: grid; gap: 14px; }
.tiempos-cab {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
}
.tiempos-cab h2 { margin: 0; }
.tiempos-pie {
  margin: 0; padding-top: 12px;
  border-top: 1px solid var(--line-1);
  font-size: 12.5px; color: var(--ink-5);
}

.hitos { list-style: none; margin: 0; padding: 0; }
.hito {
  position: relative;
  display: grid; grid-template-columns: 11px 1fr auto;
  gap: 12px; align-items: start;
  padding-bottom: 14px;
}
.hito:last-child { padding-bottom: 0; }
/* el tramo entre un hito y el siguiente: 1px arrancando en 4 para que su centro
   caiga exacto en el centro del punto (0..9 → 4.5) */
.hito::before {
  content: ''; position: absolute; left: 4px; top: 15px; bottom: 0;
  width: 1px; background: var(--line-2);
}
.hito:last-child::before { content: none; }

.hito-punto {
  width: 9px; height: 9px; margin-top: 4px; border-radius: 50%;
  background: var(--line-4);
  box-shadow: 0 0 0 3px var(--surface-base); /* tapa la línea detrás del punto */
}
.hito.hecho  .hito-punto { background: var(--accent); }
.hito.plazo  .hito-punto { background: var(--warn-line); }
.hito.vencido .hito-punto { background: var(--bad-ink); }

.hito-nombre { font-size: 13px; font-weight: 550; line-height: 1.35; }
.hito-nota { font-size: 12px; color: var(--ink-5); margin-top: 1px; }
.hito:not(.hecho):not(.plazo):not(.vencido) .hito-nombre { color: var(--ink-4); }
.hito-cuando {
  font-size: 12.5px; color: var(--ink-5);
  font-variant-numeric: tabular-nums;
  white-space: nowrap; align-self: center;
}

@media (max-width: 720px) {
  /* En el teléfono la fecha deja de competir con el nombre: baja a su renglón,
     alineada con el texto, no con el punto. */
  .hito { grid-template-columns: 11px 1fr; }
  .hito-cuando { grid-column: 2; margin-top: -2px; }
}
